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