"Fossies" - the Fresh Open Source Software Archive 
Member "npadmin-0.14/session.C~" (19 Apr 2001, 9404 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 <sys/types.h>
22 #include <sys/socket.h>
23 #include <sys/time.h>
24 #include <sys/stat.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <assert.h>
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #include <netdb.h>
34 #include <unistd.h>
35 #include <errno.h>
36
37 #include "compat.h"
38 #include "ber.h"
39 #include "session.h"
40 #include "argflags.h"
41
42 char SNMP_session::need_newline;
43 SNMP_session *SNMP_session::lastprint;
44 pthread_mutex_t SNMP_session::lastprint_m;
45
46 #define MAXPACKSIZE 10240
47
48 void cpy_hostent(hostent *first,hostent *second){
49 first->h_name=strdup(second->h_name);
50 first->h_addrtype=second->h_addrtype;
51 first->h_length=second->h_length;
52 int i;
53 for(i=0;second->h_aliases[i]!=NULL;i++);
54 first->h_aliases=new char*[i+1];
55 first->h_aliases[i]=NULL;
56 for(;second->h_aliases[i] && i>=0;i--)
57 first->h_aliases[i]=strdup(second->h_aliases[i]);
58
59 for(i=0;second->h_addr_list[i]!=NULL;i++);
60 first->h_addr_list=new char*[i+1];
61 first->h_addr_list[i]=NULL;
62 for(--i;i>=0;i--){
63 first->h_addr_list[i]=new char[second->h_length];
64 memcpy(first->h_addr_list[i],second->h_addr_list[i],first->h_length);
65 }
66 }
67
68 void del_hostent(hostent *dead){
69 int i;
70 for(i=0;dead->h_aliases[i]!=NULL;i++)
71 delete dead->h_aliases[i];
72 for(i=0;dead->h_addr_list[i]!=NULL;i++)
73 delete dead->h_addr_list[i];
74 }
75
76 SNMP_error_oid::SNMP_error_oid(const char* str){
77 oidstr=strdup(str);
78 }
79
80 SNMP_error_oid::~SNMP_error_oid(){
81 free(oidstr);
82 }
83
84 int SNMP_error_oid::operator==(CONST char* otherstr){
85 return !strcmp(otherstr,oidstr);
86 }
87
88 OidSeq *SNMP_session::do_req(Tags tag, OidSeq *oids){
89 if(flags&SESSION_DISABLED_FLAG)
90 return NULL;
91 /* ------- Construct the packet ------- */
92 BerSequence *opacket,*request;
93 long int seqno=random(),seq2;
94 request=new BerSequence(tag,4,new BerInt(seqno),new BerInt(0L),
95 new BerInt(0L),oids->Seq());
96 opacket=new BerSequence(SEQUENCE_TAG,3,new BerInt(0L),
97 new BerString(community,strlen(community)),
98 request);
99
100 BerEncodedData *opackdat=opacket->encode();
101
102 if(flags&SESSION_DEBUGSNMP_FLAG){
103 write_debug("Sent", opacket);
104 write_debug_bin(opackdat->Data(),opackdat->Length());
105 }
106
107 /* ------- Send the packet ------- */
108 unsigned char *inbuf;
109
110 BerSequence *top,*cur;
111 do{
112 int buflen=opackdat->Length();
113 // fprintf(stderr,"debug: Going to do call to %s\n",he->h_name);
114 while((inbuf=sock->call(he->h_length,he->h_addrtype,he->h_addr_list[ipidx],
115 (char*)opackdat->Data(),buflen))==NULL){
116 // fprintf(stderr,"Warning: dropping IP addr %u.%u.%u.%u for %s.\n",
117 // he->h_addr_list[ipidx][0]&0xff,he->h_addr_list[ipidx][1]&0xff,
118 // he->h_addr_list[ipidx][2]&0xff,he->h_addr_list[ipidx][3]&0xff,
119 // hostname);
120 ipidx++;
121 if(he->h_addr_list[ipidx]==NULL){
122 // fprintf(stderr,"Warning: no more IP addrs for %s.\n",hostname);
123 flags|=SESSION_DISABLED_FLAG;
124 return NULL;
125 }
126 }
127
128 // inbuf=sock->call(he->h_length,he->h_addrtype,he->h_addr_list[ipidx],
129 // (char*)opackdat->Data(),buflen);
130 // assert(inbuf);
131 top=new BerSequence(inbuf);
132 if(flags&SESSION_DEBUGSNMP_FLAG){
133 write_debug("Received", top);
134 write_debug_bin(inbuf,buflen);
135 }
136
137 // make sure that this is a response
138 cur=(BerSequence*)top->extract(2);
139 assert(cur->type()==GET_RESP_TAG);
140
141 /* make sure that this is a response to this request not some
142 previous request. What was happening with slow was that I would
143 send a packet then it would time out and then I would assume that
144 the packet was lost and then I would send another copy. Right
145 after that, the reply to the first packet would arrive and so I
146 would move on and send another packet. Then the second reply to
147 the first packet would arrive and the program would get all
148 confused. This could also fix the problem where table lines are
149 sometimes repeated over slow links. */
150 assert((cur->peek(0)->edatacache->Data())[0]==INT_TAG);
151 seq2=((BerInt*)cur->peek(0))->value();
152 }while(seq2!=seqno);
153 // printf("Outside the loop.\n");
154
155 // make sure that no errors came back
156 unsigned char *dat=cur->peek(1)->edatacache->Data();
157 assert(dat[0]==INT_TAG && dat[1]==1); /* if this fails then the device is not
158 sending back a properly constructed
159 packet */
160 if(dat[2]!=0){
161 dat=cur->peek(2)->edatacache->Data();
162 assert(dat[0]==INT_TAG && dat[1]==1); /* if this fails something more
163 sophisticated will have to be
164 written -- hopefully this will
165 never fail. */
166 delete top;
167 top=cur;
168 /*cur should now point to the problem oid */
169 top=(BerSequence*)top->peek(3);
170 top=(BerSequence*)top->peek(dat[2]-1);
171 cur=(BerSequence*)top->peek(0);
172 char buf[256];
173 cur->print(buf,256);
174 throw new SNMP_error_oid(buf);
175 }
176 delete top;
177 top=cur;
178 cur=(BerSequence*)top->extract(3);
179 delete top;
180 // printf("leaving doreq\n");
181 return new OidSeq(cur);
182 }
183
184 SNMP_session::SNMP_session(SNMP_socket *sockp, char *host,
185 const char *comm):
186 sock(sockp),ipidx(0),flags(0){
187 if(comm)
188 community=strdup(comm);
189 else
190 community=strdup("public");
191 hostname=strdup(host);
192
193 hostent *tmp;
194 if((tmp=gethostbyname(host))==NULL){
195 fprintf(stderr,"SNMP: cannot resolve hostname \"%s\".\n",host);
196 exit(-4);
197 }
198 he=new hostent;
199 cpy_hostent(he,tmp);
200 }
201
202 SNMP_session::~SNMP_session(){
203 delete community;
204 del_hostent(he);
205 delete he;
206 delete hostname;
207 }
208
209 void SNMP_session::setDebug(){
210 flags|=SESSION_DEBUGSNMP_FLAG;
211 int filenum=0;
212 char namebuf[20];
213 struct stat dummy;
214 int retval;
215
216 snprintf(namebuf,19,"snmplog.%d",filenum);
217 while((retval=stat(namebuf,&dummy))!=-1){
218 filenum++;
219 snprintf(namebuf,19,"snmplog.%d",filenum);
220 }
221 //stat returned a different error than we were expecting.
222 assert(errno=ENOENT);
223
224 assert(debugfile=open(namebuf,O_WRONLY|O_CREAT|O_TRUNC,
225 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH));
226 char buf[256];
227 int buflen=snprintf(buf,256,"Contacting %u.%u.%u.%u\n",
228 ((unsigned)he->h_addr_list[ipidx][0] & 0xff),
229 ((unsigned)he->h_addr_list[ipidx][1] & 0xff),
230 ((unsigned)he->h_addr_list[ipidx][2] & 0xff),
231 ((unsigned)he->h_addr_list[ipidx][3] & 0xff));
232 write(debugfile,buf,buflen);
233 }
234
235 void SNMP_session::write_debug(CONST char *dirstr, BerSequence *packet){
236 unsigned int sizeleft=MAXPACKSIZE;
237 char prntbuf[MAXPACKSIZE];
238 char *curpos=prntbuf;
239 int lenused;
240
241 lenused=sprintf(prntbuf,"%s\n",dirstr);
242 sizeleft-=lenused+1;
243 curpos+=lenused;
244
245 // overflowed the buffer
246 assert((lenused=packet->print(curpos,sizeleft))!=-1);
247 curpos+=lenused;
248 sizeleft-=lenused;
249
250 assert((lenused=snprintf(curpos,sizeleft,"\n"))!=-1);
251 sizeleft-=lenused;
252 curpos+=lenused;
253
254 sizeleft=curpos-prntbuf; // reusing a variable
255 assert(static_cast<ssize_t>(sizeleft)==write(debugfile,prntbuf,sizeleft));
256
257 }
258
259 // write the binary version of the packet
260 void SNMP_session::write_debug_bin(unsigned char *data, unsigned len){
261 unsigned int sizeleft=MAXPACKSIZE;
262 char prntbuf[MAXPACKSIZE];
263 char *curpos=prntbuf;
264 int lenused;
265
266 for( unsigned idx=0; idx<len; idx++){
267 lenused=snprintf(curpos,sizeleft,"%02x ",data[idx]);
268 assert(lenused!=-1);
269 sizeleft-=lenused;
270 curpos+=lenused;
271 if(idx>0 && (idx+1)%16==0){
272 lenused=snprintf(curpos,sizeleft,"\n");
273 assert(lenused!=-1);
274 sizeleft-=lenused;
275 curpos+=lenused;
276 }
277 }
278 lenused=snprintf(curpos,sizeleft,"\n");
279 assert(lenused!=-1);
280 sizeleft-=lenused;
281 curpos+=lenused;
282
283 sizeleft=curpos-prntbuf; // reusing a variable
284 static_cast<ssize_t>(sizeleft)=write(debugfile,prntbuf,sizeleft);
285 assert(sizeleft);
286 }
287
288 void SNMP_session::printstr(unsigned long *argflags,char neednl,
289 const char *str){
290 static const char *basestr[]={"%s%s","\n%s%s","hostname=\"%s\";%s",
291 "\nhostname=\"%s\";%s"};
292 const char *hn="";
293 char idx=0;
294 pthread_mutex_lock(&lastprint_m);
295 if(lastprint!=this){
296 if(need_newline)
297 idx=1;
298 if(CK_NAME_FLAG){
299 idx|=2;
300 hn=hostname;
301 }
302 }else{
303 if(!neednl && CK_NAME_FLAG){
304 idx|=2;
305 hn=hostname;
306 }
307 if(need_newline && !neednl){
308 idx=1;
309 }
310 }
311 need_newline=neednl;
312 lastprint=this;
313 pthread_mutex_unlock(&lastprint_m);
314
315 printf(basestr[idx],hn,str);
316 }
317
318 void SNMP_session::end(){
319 pthread_mutex_lock(&lastprint_m);
320 if(need_newline)
321 printf("\n");
322 pthread_mutex_unlock(&lastprint_m);
323 }