1 /*
2  * GNET-SNMP -- glib-based SNMP library
3  *
4  * Copyright (c) 2003 Juergen Schoenwaelder
5  * Copyright (c) 1998 Gregory McLean & Jochen Friedrich
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  * $Id: session.c 1992 2006-08-22 12:48:31Z schoenw $
22  */
23 
24 #include "gsnmp.h"
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <sys/socket.h>
29 #include <sys/time.h>
30 #include <time.h>
31 
32 static GSList  *request_queue = NULL;   /* queue of active requests */
33 static int initialized = 0;
34 
35 guint           gnet_snmp_retries = GNET_SNMP_DEFAULT_RETRIES;
36 guint           gnet_snmp_timeout = GNET_SNMP_DEFAULT_TIMEOUT;
37 GNetSnmpVersion gnet_snmp_version = GNET_SNMP_V2C;
38 
39 static int g_snmp_timeout_cb(gpointer data);
40 
41 GQuark
gnet_snmp_error_quark(void)42 gnet_snmp_error_quark(void)
43 {
44     static GQuark quark = 0;
45     if (quark == 0) {
46 	quark = g_quark_from_static_string("gnet-snmp-error-quark");
47     }
48     return quark;
49 }
50 
51 /*
52  * Allocate a new session data structure.
53  */
54 
55 GNetSnmp*
gnet_snmp_new()56 gnet_snmp_new()
57 {
58     GNetSnmp *session;
59 
60     if (! initialized) {
61 	g_timeout_add(100, g_snmp_timeout_cb, NULL);
62     }
63 
64     session = g_malloc0(sizeof(GNetSnmp));
65     session->tdomain = GNET_SNMP_TDOMAIN_NONE;
66     session->taddress = NULL;
67     session->retries = gnet_snmp_retries;
68     session->timeout = gnet_snmp_timeout;
69     session->version = gnet_snmp_version;
70     session->sec_level = GNET_SNMP_SECLEVEL_NANP;
71     session->sec_model = GNET_SNMP_SECMODEL_ANY;
72     session->sec_name = g_string_new(NULL);
73     session->ctxt_name = g_string_new(NULL);
74 
75     if (gnet_snmp_debug_flags & GNET_SNMP_DEBUG_SESSION) {
76 	g_printerr("session %p: new\n", session);
77     }
78     return session;
79 }
80 
81 /**
82  * gnet_snmp_new_uri:
83  * @uri: the snmp: uri
84  *
85  * Allocate and initialize a new GNetSnmp session.
86  *
87  * Returns: a pointer to a new GNetSnmp session.
88  */
89 
90 /* XXX must use the glib error handling mechanism here (and in other
91    XXX session related functions) */
92 
93 /* XXX what about TCP/UDP selection? probing? should we pass some flags? */
94 
95 GNetSnmp*
gnet_snmp_new_uri(const GURI * uri)96 gnet_snmp_new_uri(const GURI *uri)
97 {
98     GNetSnmp *snmp = NULL;
99     GInetAddr *taddress = NULL;
100     GNetSnmpTDomain tdomain = GNET_SNMP_TDOMAIN_NONE;
101     int ipv6;
102 
103     g_return_val_if_fail(uri, NULL);
104 
105     taddress = gnet_inetaddr_new(uri->hostname, uri->port);
106     if (taddress) {
107 	ipv6 = gnet_inetaddr_is_ipv6(taddress);
108 	tdomain =
109 	    ipv6 ? GNET_SNMP_TDOMAIN_UDP_IPV6 : GNET_SNMP_TDOMAIN_UDP_IPV4;
110 
111 	snmp = gnet_snmp_new();
112 	if (snmp) {
113 	    GString *s = g_string_new(uri->userinfo);
114 	    gnet_snmp_set_transport(snmp, tdomain, taddress);
115 	    gnet_snmp_set_sec_name(snmp, s);
116 	    g_string_free(s, 1);
117 
118 	    if (uri->path && uri->path[0] == '/' && uri->path[1]) {
119 		char *end = strchr(uri->path+1, '/');
120 		GString *s;
121 		if (end) {
122 		    s = g_string_new_len(uri->path+1, end - uri->path - 1);
123 		} else {
124 		    s = g_string_new(uri->path+1);
125 		}
126 		gnet_snmp_set_ctxt_name(snmp, s);
127 		g_string_free(s, 1);
128 	    }
129 
130 	}
131 	gnet_inetaddr_delete(taddress);
132     }
133 
134     return snmp;
135 }
136 
137 GNetSnmp*
gnet_snmp_new_string(const gchar * string,GError ** error)138 gnet_snmp_new_string(const gchar *string, GError **error)
139 {
140     GURI *uri;
141     GNetSnmp *s;
142 
143     uri = gnet_snmp_parse_uri(string);
144     if (! uri) {
145 	if (error) {
146 	    g_set_error(error,
147 			GNET_SNMP_ERROR,
148 			GNET_SNMP_ERROR_BADURI,
149 			"invalid snmp uri");
150 	}
151 	return NULL;
152     }
153 
154     s = gnet_snmp_new_uri(uri);
155     if (! s) {
156 	gnet_uri_delete(uri);
157 	if (error) {
158 	    g_set_error(error,
159 			GNET_SNMP_ERROR,
160 			GNET_SNMP_ERROR_NEWFAIL,
161 			"unable to create snmp session");
162 	}
163 	return NULL;
164     }
165     gnet_uri_delete(uri);
166     return s;
167 }
168 
169 /*
170  * Clone a session data structure.
171  */
172 
173 GNetSnmp*
gnet_snmp_clone(GNetSnmp * session)174 gnet_snmp_clone(GNetSnmp *session)
175 {
176     GNetSnmp *clone;
177 
178     g_return_val_if_fail(session, NULL);
179 
180     clone = gnet_snmp_new();
181     gnet_snmp_set_transport(clone, session->tdomain, session->taddress);
182     gnet_snmp_set_timeout(clone, session->timeout);
183     gnet_snmp_set_retries(clone, session->retries);
184     gnet_snmp_set_version(clone, session->version);
185     gnet_snmp_set_sec_model(clone, session->sec_model);
186     gnet_snmp_set_sec_level(clone, session->sec_level);
187     gnet_snmp_set_sec_name(clone, session->sec_name);
188     gnet_snmp_set_ctxt_name(clone, session->ctxt_name);
189 
190     return clone;
191 }
192 
193 /*
194  * Destroy a session data structure.
195  */
196 
197 void
gnet_snmp_delete(GNetSnmp * snmp)198 gnet_snmp_delete(GNetSnmp *snmp)
199 {
200     g_return_if_fail(snmp);
201 
202     /* XXX delete all requests that refer to this session first */
203 
204     if (snmp->taddress) gnet_inetaddr_delete(snmp->taddress);
205     if (snmp->uri) gnet_uri_delete(snmp->uri);
206     if (snmp->sec_name) g_string_free(snmp->sec_name, 1);
207     if (snmp->ctxt_name) g_string_free(snmp->ctxt_name, 1);
208     g_free(snmp);
209 
210     if (gnet_snmp_debug_flags & GNET_SNMP_DEBUG_SESSION) {
211 	g_printerr("session %p: deleted\n", snmp);
212     }
213 }
214 
215 void
gnet_snmp_set_transport(GNetSnmp * snmp,GNetSnmpTDomain tdomain,GInetAddr * taddress)216 gnet_snmp_set_transport(GNetSnmp *snmp,
217 			GNetSnmpTDomain tdomain, GInetAddr *taddress)
218 {
219     g_return_if_fail(snmp);
220 
221     if (snmp->taddress) gnet_inetaddr_delete(snmp->taddress);
222     snmp->tdomain = GNET_SNMP_TDOMAIN_NONE;
223     snmp->taddress = NULL;
224     if (taddress) {
225 	snmp->tdomain = tdomain;
226 	snmp->taddress = gnet_inetaddr_clone(taddress);
227     }
228     (void) gnet_snmp_get_uri(snmp);
229 }
230 
231 /* decrecated interface */
232 
233 void
gnet_snmp_set_community(GNetSnmp * snmp,gchar * community)234 gnet_snmp_set_community(GNetSnmp *snmp, gchar *community)
235 {
236     GString *s;
237 
238     g_return_if_fail(snmp);
239 
240     s = g_string_new(community);
241     gnet_snmp_set_sec_name(snmp, s);
242     g_string_free(s, 1);
243     (void) gnet_snmp_get_uri(snmp);	/* update the uri */
244 }
245 
246 /* deprecated interface */
247 
248 const gchar*
gnet_snmp_get_community(const GNetSnmp * snmp)249 gnet_snmp_get_community(const GNetSnmp *snmp)
250 {
251     g_return_val_if_fail(snmp, NULL);
252 
253     return snmp->sec_name->str;
254 }
255 
256 void
gnet_snmp_set_timeout(GNetSnmp * snmp,guint timeout)257 gnet_snmp_set_timeout(GNetSnmp *snmp, guint timeout)
258 {
259     g_return_if_fail(snmp);
260 
261     snmp->timeout = timeout;
262 }
263 
264 guint
gnet_snmp_get_timeout(const GNetSnmp * snmp)265 gnet_snmp_get_timeout(const GNetSnmp *snmp)
266 {
267     g_return_val_if_fail(snmp, 0);
268 
269     return snmp->timeout;
270 }
271 
272 void
gnet_snmp_set_retries(GNetSnmp * snmp,guint retries)273 gnet_snmp_set_retries(GNetSnmp *snmp, guint retries)
274 {
275     g_return_if_fail(snmp);
276 
277     snmp->retries = retries;
278 }
279 
280 guint
gnet_snmp_get_retries(const GNetSnmp * snmp)281 gnet_snmp_get_retries(const GNetSnmp *snmp)
282 {
283     g_return_val_if_fail(snmp, 0);
284 
285     return snmp->retries;
286 }
287 
288 void
gnet_snmp_set_version(GNetSnmp * snmp,GNetSnmpVersion version)289 gnet_snmp_set_version(GNetSnmp *snmp, GNetSnmpVersion version)
290 {
291     g_return_if_fail(snmp);
292 
293     snmp->version = version;
294 }
295 
296 GNetSnmpVersion
gnet_snmp_get_version(const GNetSnmp * snmp)297 gnet_snmp_get_version(const GNetSnmp *snmp)
298 {
299     g_return_val_if_fail(snmp, 0);
300 
301     return snmp->version;
302 }
303 
304 void
gnet_snmp_set_sec_name(GNetSnmp * snmp,GString * name)305 gnet_snmp_set_sec_name(GNetSnmp *snmp, GString *name)
306 {
307     g_return_if_fail(snmp);
308 
309     g_string_assign(snmp->sec_name, name->str);
310     (void) gnet_snmp_get_uri(snmp);	/* update the uri */
311 }
312 
313 GString*
gnet_snmp_get_sec_name(const GNetSnmp * snmp)314 gnet_snmp_get_sec_name(const GNetSnmp *snmp)
315 {
316     g_return_val_if_fail(snmp, NULL);
317 
318     return snmp->sec_name;
319 }
320 
321 void
gnet_snmp_set_sec_model(GNetSnmp * snmp,GNetSnmpSecModel model)322 gnet_snmp_set_sec_model(GNetSnmp *snmp, GNetSnmpSecModel model)
323 {
324     g_return_if_fail(snmp);
325 
326     snmp->sec_model = model;
327 }
328 
gnet_snmp_get_sec_model(const GNetSnmp * snmp)329 GNetSnmpSecModel gnet_snmp_get_sec_model(const GNetSnmp *snmp)
330 {
331     g_return_val_if_fail(snmp, 0);
332 
333     return snmp->sec_model;
334 }
335 
336 void
gnet_snmp_set_sec_level(GNetSnmp * snmp,GNetSnmpSecLevel level)337 gnet_snmp_set_sec_level(GNetSnmp *snmp, GNetSnmpSecLevel level)
338 {
339     g_return_if_fail(snmp);
340 
341     snmp->sec_level = level;
342 }
343 
gnet_snmp_get_sec_level(const GNetSnmp * snmp)344 GNetSnmpSecLevel gnet_snmp_get_sec_level(const GNetSnmp *snmp)
345 {
346     g_return_val_if_fail(snmp, 0);
347 
348     return snmp->sec_level;
349 }
350 
351 void
gnet_snmp_set_ctxt_name(GNetSnmp * snmp,GString * name)352 gnet_snmp_set_ctxt_name(GNetSnmp *snmp, GString *name)
353 {
354     g_return_if_fail(snmp);
355 
356     g_string_assign(snmp->ctxt_name, name->str);
357     (void) gnet_snmp_get_uri(snmp);	/* update the uri */
358 }
359 
360 GString*
gnet_snmp_get_ctxt_name(const GNetSnmp * snmp)361 gnet_snmp_get_ctxt_name(const GNetSnmp *snmp)
362 {
363     g_return_val_if_fail(snmp, NULL);
364 
365     return snmp->ctxt_name;
366 }
367 
368 /*
369  * Allocate a new request data structure.
370  */
371 
372 GNetSnmpRequest*
gnet_snmp_request_new()373 gnet_snmp_request_new()
374 {
375     GNetSnmpRequest *request;
376 
377     request = g_malloc0(sizeof(GNetSnmpRequest));
378     request->sec_name = g_string_new(NULL);
379 
380     if (gnet_snmp_debug_flags & GNET_SNMP_DEBUG_REQUESTS) {
381 	g_printerr("request %p: new\n", request);
382     }
383 
384     return request;
385 }
386 
387 /*
388  * Destroy a request data structure.
389  */
390 
391 void
gnet_snmp_request_delete(GNetSnmpRequest * request)392 gnet_snmp_request_delete(GNetSnmpRequest *request)
393 {
394     g_return_if_fail(request);
395 
396     if (request->sec_name) {
397 	g_string_free(request->sec_name, 1);
398     }
399     g_free(request);
400 
401     if (gnet_snmp_debug_flags & GNET_SNMP_DEBUG_REQUESTS) {
402 	g_printerr("request %p: deleted\n", request);
403     }
404 }
405 
406 /*
407  * Add a request to the global queue of outstanding requests.
408  * XXX This is not thread-safe.
409  */
410 
411 void
gnet_snmp_request_queue(GNetSnmpRequest * request)412 gnet_snmp_request_queue(GNetSnmpRequest *request)
413 {
414     g_return_if_fail(request);
415 
416     request_queue = g_slist_append(request_queue, request);
417     if (gnet_snmp_debug_flags & GNET_SNMP_DEBUG_REQUESTS) {
418 	g_printerr("request %p: queued\n", request);
419     }
420 }
421 
422 /*
423  * Remove a request from the global queue of outstanding requests.
424  * XXX This is not thread-safe.
425  */
426 
427 void
gnet_snmp_request_dequeue(GNetSnmpRequest * request)428 gnet_snmp_request_dequeue(GNetSnmpRequest *request)
429 {
430     g_return_if_fail(request);
431 
432     request_queue = g_slist_remove(request_queue, request);
433     if (gnet_snmp_debug_flags & GNET_SNMP_DEBUG_REQUESTS) {
434 	g_printerr("request %p: dequeued\n", request);
435     }
436 }
437 
438 /*
439  * Find the request with a given request id in the global queue of
440  * outstanding requests.
441  * XXX This is not thread-safe.
442  */
443 
444 GNetSnmpRequest*
gnet_snmp_request_find(gint32 id)445 gnet_snmp_request_find(gint32 id)
446 {
447     GSList *elem;
448 
449     for (elem = request_queue; elem; elem = g_slist_next(elem)) {
450 	GNetSnmpRequest *request = (GNetSnmpRequest *) elem->data;
451 	if (request->pdu.request_id == id) {
452 	    if (gnet_snmp_debug_flags & GNET_SNMP_DEBUG_REQUESTS) {
453 		g_printerr("request %p: found\n", request);
454 	    }
455 	    return request;
456 	}
457     }
458 
459     return NULL;
460 }
461 
462 /*
463  *
464  */
465 
466 void
gnet_snmp_request_timeout(GNetSnmpRequest * request)467 gnet_snmp_request_timeout(GNetSnmpRequest *request)
468 {
469     if (request->timeout) {
470 	if (gnet_snmp_debug_flags & GNET_SNMP_DEBUG_REQUESTS) {
471 	    g_printerr("request %p: timeout callback invoked\n", request);
472 	}
473 	request->timeout(request->session, request->magic);
474     }
475 }
476 
477 
478 /*
479  * query/set one mib from a snmp host
480  *
481  * host    -- Host info in question
482  * callback-- Pointer to function that will handle the reply
483  *
484  */
485 
486 /* Asynchronous SNMP functions */
487 
488 static gpointer
g_async_send(GNetSnmp * session,GNetSnmpPduType type,GList * vbl,guint32 arg1,guint32 arg2)489 g_async_send(GNetSnmp *session, GNetSnmpPduType type,
490 	     GList *vbl, guint32 arg1, guint32 arg2)
491 {
492     GError *error = NULL;
493     GNetSnmpRequest *request;
494     GTimeVal	  now;
495     static gint32 id = -1;
496 
497     if (id < 0) {
498 	id = random();
499     }
500 
501     g_get_current_time(&now);
502 
503     session->error_status = GNET_SNMP_PDU_ERR_NOERROR;
504     session->error_index = 0;
505 
506     request = gnet_snmp_request_new();
507     request->callback = session->done_callback;
508     request->timeout  = session->time_callback;
509     request->pdu.request_id   = id++;
510     request->pdu.error_status = arg1;
511     request->pdu.error_index  = arg2;
512     request->pdu.varbind_list = vbl;
513     request->pdu.context_name = (guchar *) session->ctxt_name->str;
514     request->pdu.context_name_len = session->ctxt_name->len;
515     request->sec_name         = g_string_append(request->sec_name,
516 						session->sec_name->str);
517     request->sec_model	      = session->sec_model;
518     request->sec_level	      = session->sec_level;
519     request->pdu.type	      = type;
520     request->retries          = session->retries;
521     request->timeoutval       = session->timeout;
522     request->magic            = session->magic;
523     request->version          = session->version;
524     request->tdomain          = session->tdomain;
525     request->taddress         = session->taddress;
526     request->session          = session;
527     request->timer            = now;
528     request->timer.tv_sec    += request->timeoutval / 1000;
529     request->timer.tv_usec   += (request->timeoutval % 1000) * 1000;
530 
531     gnet_snmp_dispatcher_send_pdu(request->tdomain, request->taddress,
532 				  request->version,
533 				  request->sec_model,
534 				  request->sec_name,
535 				  request->sec_level,
536 				  &request->pdu, TRUE, &error);
537 
538     if (error) {
539 	gnet_snmp_request_timeout(request);
540 	gnet_snmp_request_delete(request);
541 	g_error_free(error);
542 	return NULL;
543     }
544 
545     gnet_snmp_request_queue(request);
546 
547     return request;
548 }
549 
550 gpointer
gnet_snmp_async_set(GNetSnmp * snmp,GList * vbl)551 gnet_snmp_async_set(GNetSnmp *snmp, GList *vbl)
552 {
553     if (gnet_snmp_debug_flags & GNET_SNMP_DEBUG_SESSION) {
554 	g_printerr("session %p: g_async_set pdu %p\n", snmp, vbl);
555     }
556     return g_async_send(snmp, GNET_SNMP_PDU_SET, vbl, 0, 0);
557 }
558 
559 gpointer
gnet_snmp_async_get(GNetSnmp * snmp,GList * vbl)560 gnet_snmp_async_get(GNetSnmp *snmp, GList *vbl)
561 {
562     if (gnet_snmp_debug_flags & GNET_SNMP_DEBUG_SESSION) {
563 	g_printerr("session %p: g_async_get pdu %p\n", snmp, vbl);
564     }
565     return g_async_send(snmp, GNET_SNMP_PDU_GET, vbl, 0, 0);
566 }
567 
568 gpointer
gnet_snmp_async_getnext(GNetSnmp * snmp,GList * vbl)569 gnet_snmp_async_getnext(GNetSnmp *snmp, GList *vbl)
570 {
571     if (gnet_snmp_debug_flags & GNET_SNMP_DEBUG_SESSION) {
572 	g_printerr("session %p: g_async_getnext pdu %p\n", snmp, vbl);
573     }
574     return g_async_send(snmp, GNET_SNMP_PDU_NEXT, vbl, 0, 0);
575 }
576 
577 gpointer
gnet_snmp_async_getbulk(GNetSnmp * snmp,GList * vbl,guint32 nonrep,guint32 maxrep)578 gnet_snmp_async_getbulk(GNetSnmp *snmp, GList *vbl,
579 			guint32 nonrep, guint32 maxrep)
580 {
581     if (gnet_snmp_debug_flags & GNET_SNMP_DEBUG_SESSION) {
582 	g_printerr("session %p: g_async_getbulk pdu %p\n", snmp, vbl);
583     }
584     return g_async_send(snmp, GNET_SNMP_PDU_BULK, vbl, nonrep, maxrep);
585 }
586 
587 /* Synchronous SNMP functions */
588 
589 struct inputcb {
590   int sock_nr;
591   void (*receiveMessage)();
592 };
593 
594 struct syncmagic {
595     GMainLoop *loop;
596     GList *result;
597 };
598 
599 static void
cb_time(GNetSnmp * session,void * magic)600 cb_time(GNetSnmp *session, void *magic)
601 {
602     struct syncmagic *sm = (struct syncmagic *) magic;
603     sm->result = NULL;
604     session->error_index = 0;
605     session->error_status = GNET_SNMP_PDU_ERR_NORESPONSE;
606 
607     g_main_quit(sm->loop);
608 }
609 
610 static gboolean
cb_done(GNetSnmp * session,GNetSnmpPdu * spdu,GList * objs,gpointer magic)611 cb_done(GNetSnmp *session, GNetSnmpPdu *spdu, GList *objs, gpointer magic)
612 {
613     struct syncmagic *sm = (struct syncmagic *) magic;
614     sm->result = objs;
615     if (gnet_snmp_debug_flags & GNET_SNMP_DEBUG_SESSION) {
616 	g_printerr("session %p: error-status = %d, error-index = %d\n",
617 		   session, session->error_status, session->error_index);
618     }
619     g_main_quit(sm->loop);
620     return FALSE;
621 }
622 
623 static GList *
g_sync_send(GNetSnmp * session,GNetSnmpPduType type,GList * objs,guint32 arg1,guint32 arg2)624 g_sync_send(GNetSnmp *session, GNetSnmpPduType type,
625 	    GList *objs, guint32 arg1, guint32 arg2)
626 {
627     struct syncmagic * magic;
628     GList *result;
629 
630     magic = (struct syncmagic *) g_malloc(sizeof(struct syncmagic));
631     magic->loop = g_main_new(TRUE);
632 
633     session->done_callback = cb_done;
634     session->time_callback = cb_time;
635     session->magic = magic;
636     if (! g_async_send(session, type, objs, arg1, arg2)) {
637 	if (gnet_snmp_debug_flags & GNET_SNMP_DEBUG_SESSION) {
638 	    g_printerr("session %p: g_sync_send failed to send PDU\n", session);
639 	}
640 	g_main_destroy(magic->loop);
641 	g_free(magic);
642 	return NULL;
643     }
644 
645     while(g_main_is_running(magic->loop)) {
646 	g_main_run(magic->loop);
647     }
648     g_main_destroy(magic->loop);
649     result = magic->result;
650     g_free(magic);
651     return result;
652 }
653 
654 GList *
gnet_snmp_sync_set(GNetSnmp * snmp,GList * pdu)655 gnet_snmp_sync_set(GNetSnmp *snmp, GList *pdu)
656 {
657     if (gnet_snmp_debug_flags & GNET_SNMP_DEBUG_SESSION) {
658 	g_printerr("session %p: g_sync_set pdu %p\n", snmp, pdu);
659     }
660     return g_sync_send(snmp, GNET_SNMP_PDU_SET, pdu, 0, 0);
661 }
662 
663 GList *
gnet_snmp_sync_get(GNetSnmp * snmp,GList * pdu)664 gnet_snmp_sync_get(GNetSnmp *snmp, GList *pdu)
665 {
666     if (gnet_snmp_debug_flags & GNET_SNMP_DEBUG_SESSION) {
667 	g_printerr("session %p: g_sync_get pdu %p\n", snmp, pdu);
668     }
669     return g_sync_send(snmp, GNET_SNMP_PDU_GET, pdu, 0, 0);
670 }
671 
672 GList *
gnet_snmp_sync_getnext(GNetSnmp * snmp,GList * pdu)673 gnet_snmp_sync_getnext(GNetSnmp *snmp, GList *pdu)
674 {
675     if (gnet_snmp_debug_flags & GNET_SNMP_DEBUG_SESSION) {
676 	g_printerr("session %p: g_sync_getnext pdu %p\n", snmp, pdu);
677     }
678     return g_sync_send(snmp, GNET_SNMP_PDU_NEXT, pdu, 0, 0);
679 }
680 
681 GList *
gnet_snmp_sync_getbulk(GNetSnmp * snmp,GList * pdu,guint32 nonrep,guint32 maxrep)682 gnet_snmp_sync_getbulk(GNetSnmp *snmp, GList *pdu,
683 		       guint32 nonrep, guint32 maxrep)
684 {
685     if (gnet_snmp_debug_flags & GNET_SNMP_DEBUG_SESSION) {
686 	g_printerr("session %p: g_sync_getbulk pdu %p\n", snmp, pdu);
687     }
688     return g_sync_send(snmp, GNET_SNMP_PDU_BULK, pdu, nonrep, maxrep);
689 }
690 
691 #if 0
692 gboolean
693 g_pdu_add_oid(GList **pdu, guint32 *myoid, guint mylength,
694 	      GSnmpVarBindType type, gpointer value)
695 {
696   GSnmpVarBind *obj;
697 
698   obj = g_snmp_varbind_new(myoid, mylength, type, value, -1);
699   if (! obj) {
700       return FALSE;
701   }
702   *pdu = g_list_append(*pdu, obj);
703   return TRUE;
704 }
705 #endif
706 
707 #if 0
708 /* This should be nuked once the new parser and mib module are available.
709    For now, either use this or the print function in struct tree          */
710 
711 void
712 g_snmp_printf(char *buf, int buflen, GSnmpVarBind *obj)
713 {
714   int i;
715   /*
716    * Changed all the sprintf's to snprintf, paranoid I know but
717    * I'd rather not get caught with any buffer overflows..
718    */
719   switch(obj->type)
720     {
721       case G_SNMP_INTEGER32:
722         g_snprintf(buf, buflen, "%d", obj->syntax.i32[0]);
723         break;
724       case G_SNMP_COUNTER32:
725       case G_SNMP_UNSIGNED32:
726         g_snprintf(buf, buflen, "%u", obj->syntax.ui32[0]);
727         break;
728       case G_SNMP_TIMETICKS:
729 	/* replaced this duplicated code with a call to existing code */
730 	/* timetick_string (obj->syntax.ul[0], buf); */
731         g_snprintf(buf, buflen, "%u", obj->syntax.ui32[0]);
732         break;
733       case G_SNMP_OCTET_STRING:
734       case G_SNMP_OPAQUE:
735         /* xxx fix this (data is not necessarily printable) */
736         memcpy(buf, obj->syntax.uc,
737 	       obj->syntax_len > buflen ? buflen: obj->syntax_len);
738 	buf[obj->syntax_len > buflen ? buflen: obj->syntax_len] = '\0';
739         break;
740       case G_SNMP_IPADDRESS:
741         if (obj->syntax_len == 4) /* IPv4 */
742           g_snprintf(buf, buflen, "%d.%d.%d.%d", obj->syntax.uc[0],
743                                                obj->syntax.uc[1],
744                                                obj->syntax.uc[2],
745                                                obj->syntax.uc[3]);
746         break;
747       case G_SNMP_OBJECT_ID:
748         g_snprintf(buf, buflen, "%u", obj->syntax.ui32[0]);
749         i=1;
750         while(i < obj->syntax_len / sizeof(guint32))
751           g_snprintf(buf+strlen(buf), buflen-strlen(buf), ".%u",
752                    obj->syntax.ui32[i++]);
753         break;
754       case G_SNMP_COUNTER64:
755         g_snprintf(buf, buflen, "%llu", obj->syntax.ui64[0]);
756 	break;
757       case G_SNMP_NULL:
758         g_snprintf(buf, buflen, "<null>");
759         break;
760       case G_SNMP_NOSUCHOBJECT:
761         g_snprintf(buf, buflen, "<nosuchobject>");
762         break;
763       case G_SNMP_NOSUCHINSTANCE:
764         g_snprintf(buf, buflen, "<nosuchinstance>");
765         break;
766       case G_SNMP_ENDOFMIBVIEW:
767         g_snprintf(buf, buflen, "<endofmibview>");
768         break;
769     }
770 }
771 #endif
772 
773 /*
774  * The low level callbacks
775  */
776 
777 static int
g_snmp_timeout_cb(gpointer data)778 g_snmp_timeout_cb(gpointer data)
779 {
780     GSList *mylist;
781     GTimeVal now;
782     GNetSnmpRequest *request;
783 
784   again:
785     g_get_current_time(&now);
786     mylist = request_queue;
787 
788     while (mylist) {
789 	request = (GNetSnmpRequest *) mylist->data;
790 	mylist = mylist->next;
791 	if (request->timer.tv_sec < now.tv_sec
792 	    || (request->timer.tv_sec == now.tv_sec
793 		&& request->timer.tv_usec <= now.tv_usec)) {
794 	    if (request->retries) {
795 		request->retries--;
796 
797 		request->timer = now;
798 		request->timer.tv_sec  += request->timeoutval / 1000;
799 		request->timer.tv_usec += (request->timeoutval % 1000) * 1000;
800 
801 		if (gnet_snmp_debug_flags & GNET_SNMP_DEBUG_REQUESTS) {
802 		    g_printerr("request %p: timeout ...\n", request);
803 		}
804 
805 		{
806 		    GError *error = NULL;
807 
808 		    gnet_snmp_dispatcher_send_pdu(request->tdomain,
809 						  request->taddress,
810 						  request->version,
811 						  request->sec_model,
812 						  request->sec_name,
813 						  request->sec_level,
814 						  &request->pdu, TRUE, &error);
815 
816 		    if (error) {
817 			g_error_free(error);
818 			gnet_snmp_request_timeout(request);
819 			gnet_snmp_request_dequeue(request);
820 			gnet_snmp_request_delete(request);
821 			goto again;
822 		    }
823 		}
824 #if 0
825 		if (gnet_snmp_debug_flags & GNET_SNMP_DEBUG_REQUESTS) {
826 		    g_warning("request %p: timeout, retry shipped", request);
827 		}
828 #endif
829 	    } else {
830 		if (gnet_snmp_debug_flags & GNET_SNMP_DEBUG_REQUESTS) {
831 		    g_printerr("request %p: final timeout ...\n", request);
832 		}
833 
834 		gnet_snmp_request_timeout(request);
835 		gnet_snmp_request_dequeue(request);
836 		gnet_snmp_request_delete(request);
837 		goto again;
838 	    }
839 	}
840     }
841     return TRUE;
842 }
843 
844 void
g_session_response_pdu(GNetSnmpMsg * msg)845 g_session_response_pdu(GNetSnmpMsg *msg)
846 {
847     GNetSnmpPdu     *pdu;
848     GList           *vbl;
849     GNetSnmpRequest *request;
850 
851     g_assert(msg);
852 
853     if (! msg->data) return;
854 
855     pdu = (GNetSnmpPdu *) msg->data;
856     vbl = pdu->varbind_list;
857 
858     request = gnet_snmp_request_find(pdu->request_id);
859     if (! request) {
860 	g_list_foreach(vbl, (GFunc) gnet_snmp_varbind_delete, NULL);
861 	g_list_free(vbl);
862 	return;
863     }
864 
865 #if 0
866     /* XXX this needs to be generalized I think */
867 
868     if (memcmp(securityName->str, request->sec_name->str, securityName->len)) {
869 	g_list_foreach(vbl, (GFunc) gnet_snmp_varbind_delete, NULL);
870 	g_list_free(vbl);
871 	return;
872     }
873 #endif
874 
875     gnet_snmp_request_dequeue(request);
876     request->session->error_status = pdu->error_status;
877     request->session->error_index = pdu->error_index;
878     if (! request->callback) {
879 	g_list_foreach(vbl, (GFunc) gnet_snmp_varbind_delete, NULL);
880 	g_list_free(vbl);
881 	gnet_snmp_request_delete(request);
882 	return;
883     }
884 
885     if (request->callback(request->session, pdu, vbl, request->magic)) {
886 	if (gnet_snmp_debug_flags & GNET_SNMP_DEBUG_REQUESTS) {
887 	    g_printerr("request %p: callback invoked\n", request);
888 	}
889 	/* g_snmp_vbl_free(vbl); */
890     }
891     gnet_snmp_request_delete(request);
892 }
893 
894 GURI*
gnet_snmp_get_uri(GNetSnmp * snmp)895 gnet_snmp_get_uri(GNetSnmp *snmp)
896 {
897     gchar *host, *name, *path = NULL;
898     gint port;
899 
900     g_return_val_if_fail(snmp, NULL);
901 
902     if (snmp->uri) gnet_uri_delete(snmp->uri);
903 
904     host = gnet_inetaddr_get_canonical_name(snmp->taddress);
905     port = gnet_inetaddr_get_port(snmp->taddress);
906     name = snmp->sec_name ? snmp->sec_name->str : NULL;
907     if (snmp->ctxt_name) {
908 	path = g_strdup_printf("/%s/", snmp->ctxt_name->str);
909     }
910 
911     snmp->uri = gnet_uri_new_fields_all("snmp", name, host, port,
912 					path, NULL, NULL);
913 
914     if (path) g_free(path);
915 
916     return snmp->uri;
917 }
918