"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 }