"Fossies" - the Fresh Open Source Software Archive

Member "npadmin-0.14/snmpsock.C" (22 Nov 2002, 6542 Bytes) of package /linux/misc/old/npadmin-0.14.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /* Copyright (c) 2000 Ben Woodard
    2  * All rights reserved.
    3  *
    4  * This program is free software; you can redistribute it and/or
    5  * modify it under the terms of the GNU General Public Licence
    6  * as published by the Free Software Foundation; either version 2
    7  * of the Licence, or (at your option) any later version.
    8  *
    9  * This program is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRENTY; without even the implied warrenty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   12  * GNU General Public Licence in the COPYING file for more
   13  * details.
   14  *
   15  * You should have received a copy of the GNU Library General 
   16  * Public License along with the GNU C Library; see the file 
   17  * COPYING.LIB.  If not, write to the Free Software Foundation, 
   18  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
   19  */
   20 
   21 #include "snmpsock.h"
   22 #include <assert.h>
   23 #include <sys/types.h>
   24 #include <sys/socket.h>
   25 #include <string.h>
   26 #include <stdio.h>
   27 #include <stdlib.h>
   28 #include <unistd.h>
   29 #include <sys/time.h>
   30 #include <netinet/in.h>
   31 #include <netdb.h>
   32 #include <ctype.h>
   33 #include <errno.h>
   34 
   35 #define MAXPACKSIZE 10240
   36 
   37 unsigned int maxaddrlen=sizeof(sockaddr);
   38 
   39 struct request_t{
   40 //   int magic1;
   41   int len;
   42   char *addr;
   43   pthread_cond_t req_cv;
   44   request_t *next;
   45   request_t *prev;
   46 
   47   request_t(int length, char *address):len(length),addr(address),
   48     next(NULL),prev(NULL),buf(NULL){ //,magic1(0xbadcab88),magic2(0xdeadbeef){
   49     assert(addr!=NULL || addr!=(char*)1);
   50     pthread_cond_init(&req_cv,NULL);
   51   }
   52 
   53   //filled in on the return
   54   unsigned char *buf;
   55   int buflen;
   56   int errnum;
   57 //   char padding[200];
   58 //   int magic2;
   59 };
   60 
   61 void unlink(request_t **head,request_t *cur){
   62   if(cur->prev)
   63     cur->prev->next=cur->next;
   64   if(cur->next)
   65     cur->next->prev=cur->prev;
   66   if(cur==*head)
   67     *head=cur->next;
   68 }
   69 
   70 pthread_mutex_t pending_m=PTHREAD_MUTEX_INITIALIZER;
   71 request_t *pending=NULL;
   72 
   73 // void check_plist(char *file,unsigned int line){
   74 //   fprintf(stderr,"debug: thread: %lu checking at %s %u ",pthread_self(),file,
   75 //    line);
   76 //   pthread_mutex_lock(&pending_m);
   77 //   for(request_t *cur=pending;cur!=NULL;cur=cur->next){
   78 //     fprintf(stderr,"0x%x",cur);
   79 //     assert(cur->magic1==0xbadcab88);
   80 //     fputs("->",stderr);
   81 //   }
   82 //   fputc('\n',stderr);
   83 //   pthread_mutex_unlock(&pending_m);
   84 // }
   85 
   86 void *receiver(void *sockp){
   87   int sock=*(int*)sockp;
   88   int readcnt;
   89   unsigned int fromlen;
   90   for(;;){
   91     sockaddr_in from;
   92     memset(&from,0,sizeof(from));
   93     fromlen=sizeof(sockaddr_in);
   94     unsigned char *buf=new unsigned char[MAXPACKSIZE];
   95     assert(buf);
   96     fd_set rfds;
   97     timeval tv;
   98     int retval;
   99     FD_ZERO(&rfds);
  100     FD_SET(sock,&rfds);
  101     tv.tv_sec=5;
  102     tv.tv_usec=0;
  103     retval=select(sock+1,&rfds,NULL,NULL,&tv);
  104     assert(retval!=-1);
  105     pthread_testcancel();
  106 
  107     // check every 5 seconds to see if we were cancelled
  108     if(retval!=1 || !FD_ISSET(sock,&rfds))
  109       continue;
  110 
  111     // actually got some data
  112     readcnt=recvfrom(sock,buf,MAXPACKSIZE,0,(sockaddr*)&from,&fromlen);
  113     if(readcnt==-1){
  114       if(errno==ECONNREFUSED)
  115     continue; // just ignore those pesky icmp unreachable errors
  116       perror("bad read in reciever thread");
  117       exit(5);
  118     }
  119 
  120     pthread_mutex_lock(&pending_m);
  121     request_t *cur;
  122     for(cur=pending;cur!=NULL;cur=cur->next){
  123 //       assert(cur->magic1==0xbadcab88);
  124 //       assert(cur->magic2==0xdeadbeef);
  125       if(!memcmp(&from.sin_addr,cur->addr,cur->len))
  126     break;
  127     }
  128     // now cur equals either null i.e. not found or the correct element
  129     if(cur==NULL){
  130       fprintf(stderr,"Warning: stray packet recieved from %u.%u.%u.%u\n",
  131           ((char*)&from.sin_addr)[0]&0xff,((char*)&from.sin_addr)[1]&0xff,
  132           ((char*)&from.sin_addr)[2]&0xff,((char*)&from.sin_addr)[3]&0xff);
  133           
  134       pthread_mutex_unlock(&pending_m);
  135       continue;
  136     }
  137     cur->buf=buf;
  138     cur->buflen=readcnt;
  139     cur->errnum=errno;
  140 
  141     //unlink everything
  142     unlink(&pending,cur);
  143       
  144     pthread_cond_signal(&cur->req_cv);
  145       
  146     pthread_mutex_unlock(&pending_m);
  147   }
  148 }
  149 
  150 SNMP_socket::SNMP_socket(int tmo, int rt, int pt):timeout(tmo),retries(rt),
  151   port(pt){
  152   // create socket
  153   struct protoent *pe;
  154   struct servent *se;
  155   
  156   pe=getprotobyname("udp");
  157   assert(pe);
  158   sock=socket(AF_INET,SOCK_DGRAM,pe->p_proto);
  159   assert(sock!=-1);
  160 
  161   if(port==0){
  162     se = getservbyname("snmp","udp");
  163     if (NULL != se){
  164       port=se->s_port;
  165       endservent();
  166     } else
  167       port = 161; /* Fall back to hardcoded value */
  168   }  else 
  169     port=htons(port);
  170 
  171   // create listening thread
  172   int rv=pthread_create(&listening_thr,NULL,receiver,&sock);
  173   assert(rv==0);
  174 }
  175 
  176 SNMP_socket::~SNMP_socket(){
  177   // zap listening thread 
  178   pthread_cancel(listening_thr);
  179   pthread_join(listening_thr,NULL);
  180   // close socket
  181   close(sock);
  182 }
  183 
  184 unsigned char *SNMP_socket::call(int len,int type,char *addr,
  185                  char *data,int &buflen){
  186   request_t curreq(len,addr);
  187   if(static_cast<unsigned int>(len)>maxaddrlen)
  188     maxaddrlen=len;
  189 
  190   // send packet
  191   struct sockaddr_in sain;
  192   memset((caddr_t)&sain,0,sizeof(sain));
  193   sain.sin_family=type,
  194   sain.sin_port=port;
  195   memcpy((caddr_t)&sain.sin_addr,addr,len);
  196   
  197   // insert it on the list
  198   pthread_mutex_lock(&pending_m);
  199   curreq.next=pending;
  200   if(pending)
  201     pending->prev=&curreq;
  202   pending=&curreq;
  203 
  204   //while there are still retries
  205   int rt;
  206   for(rt=retries;rt>=0;rt--){
  207   retry:
  208     int sendcnt=sendto(sock,data,buflen,0,(sockaddr*)&sain,
  209                sizeof(sockaddr_in));
  210     /* work around potential problem where ICMP port unreachable 
  211        propegates up IP stack and can appear on socket even 
  212        though problem is not with this particular packet. */
  213     if(sendcnt==-1 && errno==ECONNREFUSED)
  214       goto retry;
  215     assert(sendcnt==-1 || sendcnt==buflen);
  216     if(sendcnt==-1){
  217       perror("Error sending packet");
  218       // remove from list and return error
  219       buflen=errno;
  220       pthread_mutex_lock(&pending_m);
  221       unlink(&pending,&curreq);
  222       pthread_mutex_unlock(&pending_m);
  223       return NULL;
  224     }
  225     // wait on condition variable
  226     timespec tv;
  227     tv.tv_sec=time(NULL)+timeout;
  228     tv.tv_nsec=0;
  229     
  230     int waitret=pthread_cond_timedwait(&curreq.req_cv,&pending_m,&tv);
  231     if(waitret!=ETIMEDOUT)
  232       break;
  233   }
  234   if(rt<0)
  235     unlink(&pending,&curreq);
  236   pthread_mutex_unlock(&pending_m);
  237 
  238   // kick out bad data
  239   if(curreq.buflen==-1){
  240     delete curreq.buf;
  241     buflen=curreq.errnum;
  242     return NULL;
  243   }
  244   
  245   buflen=curreq.buflen;
  246   return curreq.buf;
  247 }