1 Improved Error Reporting and Thread-Safe Use of the SNMP Library
3 There is a need in some environments to support multiple threads
4 in a single application. The SNMP Library provides the Single Session
5 functions which support thread-safe operation when certain precautions
6 are taken. This document describes the operation of the SNMP Library
7 with a focus on its session management functions. The Traditional API
8 and the Single API functions are compared and contrasted.
9 A working understanding of the CMU or UCD SNMP Library
10 API is recommended to fully appreciate the concepts discussed.
11 The document ends with a list of restrictions for using the Single API
12 in a multi-threaded application.
14 ***** IMPORTANT ANNOUNCEMENT *****
15 To the point, no resource locks are applied within the SNMP Library.
16 The APDU encoding and some session management functions can be used
17 in thread-safe manners. The MIB file parsing is not thread-safe.
18 The Single Session API was made available in November 1998.
19 Existing applications use the Traditional API, which is not thread-safe.
20 The thread-safe considerations are discussed throughout this document.
22 The research and development of the Single Session API that I've completed
23 was wholly funded by my employer, Internet Security Systems, Inc.
24 and is distributed freely to the Internet community.
26 -Mike Slifcak, 23 April 1999
28 09 July 1999 Removed references to snmp_synch_setup and snmp_synch_reset
33 The Single Session API is integrated into the currently available
34 versions of the CMU SNMP library and the UC-Davis SNMP package.
36 ftp://ftp.net.cmu.edu/pub/snmp/cmu-snmp-V1.13.tar.gz and later
37 Read : snmp_sess_api.3, Changes.SingleSession
39 ftp://ucd-snmp.ucdavis.edu/ucd-snmp-3.6.tar.gz and later
40 Read : snmp_sess_api.3, README.thread (after version 3.6.1)
42 Both libraries work equally well in Windows NT and various
43 UNIX platforms. Please read this document and refer to
44 the snmp_sess_api section 3 manual page.
48 APDU Application Protocol Data Unit
49 API Application Programming Interface
50 CMU Carnegie-Mellon University, Pittsburgh, PA.
51 Library The SNMP library; Both CMU and UCD versions are applicable.
52 Session Concept embodying the management of transacting SNMP APDUS.
53 SNMP Simple Network Management Protocol
54 UCD University of California at Davis, CA.
58 The Library extends the UNIX file concept (open, close, read, write) to a Session.
59 Opening a Session binds a local socket to a well-known port and creates internal
60 structures to help with controlling the transaction of SNMP APDUs. Closing a
61 Session releases the memory and system resources used for these purposes.
63 Since the mid-1980s, many SNMP applications have used the Traditional Session
64 API to transact SNMP APDUs between the local host and SNMP-enabled devices.
66 The Traditional Session API does not support multi-threaded applications:
68 1) There are no resource locks to prevent exposing the Library's
69 global data resources to corruption in a multi-threaded application;
71 2) The Traditional API functions that receive SNMP APDUs
72 do not provide an interface for one of many sessions;
74 3) Errors discovered by the Library are communicated through global
75 data structures and are not associated with the session
76 in which the error occurred.
78 The Single Session API provides these capabilities:
80 1) Manage a single SNMP session safely, in multi-threaded or
81 non-threaded applications, by avoiding access to data structures
82 that the Traditional Session API may share between Sessions;
84 2) Associate errors with the session context for threaded
85 and non-threaded applications.
88 Contrasting and Comparing Traditional API and Single API
90 The Traditional API uses the struct snmp_session pointer returned
91 from snmp_open() to identify one SNMP session. The Single API uses
92 the opaque pointer returned from snmp_sess_open() to identify one
95 Helpful Hint : The Library copies the contents of the
96 structure which is input to snmp_open() and snmp_sess_open().
97 Once copied, changing that input structure's data
98 has no effect on the opened SNMP Session.
100 The Traditional API uses the snmp_error() function to identify any
101 library and system errors that occurred during the processing for
102 one SNMP session. The Single API uses snmp_sess_error() for the
105 The Traditional API manages the private Sessions list structure;
106 adding to the list during snmp_open(), removing during snmp_close.
108 With few exceptions, the Traditional API calls the Single API
109 for each session that appears on the Sessions list.
111 The Traditional API reads from all Sessions on the Sessions list;
112 The Single API does not use the Sessions list.
113 The Single API can read from only one Session.
116 This is the basis for thread-safe-ness of the Library.
117 There are no resource locks applied.
122 A multi-threaded application that deploys the SNMP Library should
123 should complete all MIB file parsing before additional threads
124 are activated. Drawing from the parsed contents of the MIB does
125 not incur any data corruption exposure once the internal MIB structures
128 The application may create threads such that a single thread may manage
129 a single SNMP session. The thread should call snmp_sess_init()
130 to prepare a struct snmp_session structure. The thread can adjust
131 session parameters such as the remote UDP port or the local UDP port,
132 which must be set prior to invoking snmp_sess_open().
134 The first call to snmp_sess_init() initialises the SNMP Library,
135 including the MIB parse trees, before any SNMP sessions are created.
136 Applications that call snmp_sess_init() do not need to read MIBs
137 nor setup environment variables to utilize the Library.
139 After the struct snmp_session is setup, the thread must call
140 snmp_sess_open() to create an SNMP session. If at any time
141 the thread must change the Session configuration,
142 snmp_sess_session() returns the pointer to the internal configuration
143 structure (a struct snmp_session, copied from snmp_sess_open).
144 The thread can adjust parameters such as the session timeout
145 or the community string with this returned struct snmp_session pointer.
146 Changes to the remote or local port values have no effect on an opened Session.
148 The thread can build PDUs and bind variables to PDUs, as it performs its duties.
149 The thread then calls snmp_sess_send() or snmp_sess_async_send() to build and send
150 an SNMP APDU to the remote device. If a Get-Response-PDU is expected, the thread
151 should call snmp_sess_synch_response() instead.
153 When the thread is finished using the session, it must free the resources
154 that the Library used to manage the session.
155 Finally, the thread must call snmp_sess_close() to end the Session.
157 Snmp_sess_init(), snmp_open(), and snmp_sess_open()
158 must use the same calling parameter for a given Session.
159 Other methods should use only the returned parameter from
160 snmp_open() and snmp_sess_open() to access the opened SNMP Session.
165 Two calls were added : snmp_error() and snmp_sess_error() return the
166 "errno" and "snmp_errno" values from the per session data, and a string
167 that describes the errors that they represent. The string must be freed
170 Use snmp_error() to process failures after Traditional API calls,
171 or snmp_sess_error() to process failure after Single API calls.
172 In the case where an SNMP session could not be opened,
173 call snmp_error() using the struct snmp_session supplied to either snmp_open()
177 The following variables and functions are obsolete and may create problems
178 in a multi-threaded application :
188 The functions in the following table are functionally equivalent,
189 with the exception of these behaviors:
190 - The Traditional API manages many sessions
191 - The Traditional API passes a struct snmp_session pointer,
192 and touches the Sessions list
193 - The Single API manages only one session
194 - The Single API passes an opaque pointer, and does not use Sessions list
196 Traditional Single Comment
197 =========== ============== =======
198 snmp_sess_init snmp_sess_init Call before either open
199 snmp_open snmp_sess_open Single not on Sessions list
200 snmp_sess_session Exposes snmp_session pointer
201 snmp_send snmp_sess_send Send one APDU
202 snmp_async_send snmp_sess_async_send Send one APDU with callback
203 snmp_select_info snmp_sess_select_info Which session(s) have input
204 snmp_read snmp_sess_read Read APDUs
205 snmp_timeout snmp_sess_timeout Check for timeout
206 snmp_close snmp_sess_close Single not on Sessions list
207 snmp_synch_response snmp_sess_synch_response Send/receive one APDU
208 snmp_error snmp_sess_error Get library,system errno
211 Example 1 : Traditional API use.
213 #include "snmp_api.h"
217 struct snmp_session Session, *sptr;
219 snmp_sess_init(&Session);
220 Session.peername = "foo.bar.net";
221 sptr = snmp_open(&Session);
223 /* Error codes found in open calling argument */
224 snmp_error(&Session, &liberr, &syserr, &errstr);
225 printf("SNMP create error %s.\n", errstr);
229 /* Pass sptr to snmp_error from here forward */
231 /* Change the community name */
232 free(sptr->community);
233 sptr->community = strdup("public");
234 sptr->community_len = strlen("public");
236 if (0 == snmp_send(sptr, pdu)) {
237 snmp_error(sptr, &liberr, &syserr, &errstr);
238 printf("SNMP write error %s.\n", errstr);
245 Example 2 : Single API use.
247 #include "snmp_api.h"
251 void *sessp; /* <-- an opaque pointer, not a struct pointer */
252 struct snmp_session Session, *sptr;
254 snmp_sess_init(&Session);
255 Session.peername = "foo.bar.net";
256 sessp = snmp_sess_open(&Session);
258 /* Error codes found in open calling argument */
259 snmp_error(&Session, &liberr, &syserr, &errstr);
260 printf("SNMP create error %s.\n", errstr);
264 sptr = snmp_sess_session(sessp); /* <-- get the snmp_session pointer */
266 /* Pass sptr to snmp_sess_error from here forward */
268 /* Change the community name */
269 free(sptr->community);
270 sptr->community = strdup("public");
271 sptr->community_len = strlen("public");
273 if (0 == snmp_sess_send(sessp, pdu)) {
274 snmp_sess_error(sessp, &liberr, &syserr, &errstr);
275 printf("SNMP write error %s.\n", errstr);
279 snmp_sess_close(sessp);
281 Example 3. Differences Between Traditional API and Single API Usage
283 > void *sessp; /* <-- an opaque pointer, not a struct pointer */
285 < sptr = snmp_open(&Session);
286 < if (sptr == NULL) {
288 > sessp = snmp_sess_open(&Session);
289 > if (sessp == NULL) {
291 < /* Pass sptr to snmp_error from here forward */
293 > sptr = snmp_sess_session(sessp); /* <-- get the snmp_session pointer */
295 > /* Pass sptr to snmp_sess_error from here forward */
297 < if (0 == snmp_send(sptr, pdu)) {
298 < snmp_error(sptr, &liberr, &syserr, &errstr);
300 > if (0 == snmp_sess_send(sessp, pdu)) {
301 > snmp_sess_error(sessp, &liberr, &syserr, &errstr);
305 > snmp_sess_close(sessp);
308 Restrictions on Multi-threaded Use of the SNMP Library
310 1. Invoke SOCK_STARTUP or SOCK_CLEANUP from the main thread only.
312 2. The MIB parsing functions use global shared data and are not
313 multi-thread safe when the MIB tree is under construction.
314 Once the tree is built, the data can be safely referenced from
315 any thread. There is no provision for freeing the MIB tree.
316 Suggestion: Read the MIB files before an SNMP session is created.
317 This can be accomplished by invoking snmp_sess_init from the main
318 thread and discarding the buffer which is initialised.
320 3. Invoke the SNMPv2p initialisation before an SNMP session is created,
321 for reasons similar to reading the MIB file.
322 The SNMPv2p structures should be available to all SNMP sessions.
323 CAUTION: These structures have not been tested in a multi-threaded
326 4. Sessions created using the Single API do not interact with other
327 SNMP sessions. If you choose to use Traditional API calls, call
328 them from a single thread. The Library cannot reference an SNMP
329 session using both Traditional and Single API calls.
331 5. Using the callback mechanism for asynchronous response PDUs
332 requires additional caution in a multi-threaded application.
333 This means a callback function probably should probably not use
334 Single API calls to further process the session.
336 6. Each call to snmp_sess_open() creates an IDS. Only a call to
337 snmp_sess_close() releases the resources used by the IDS.