diff options
Diffstat (limited to 'README.thread')
-rw-r--r-- | README.thread | 343 |
1 files changed, 343 insertions, 0 deletions
diff --git a/README.thread b/README.thread new file mode 100644 index 0000000..aa1304a --- /dev/null +++ b/README.thread @@ -0,0 +1,343 @@ +Improved Error Reporting and Thread-Safe Use of the SNMP Library + +There is a need in some environments to support multiple threads +in a single application. The SNMP Library provides the Single Session +functions which support thread-safe operation when certain precautions +are taken. This document describes the operation of the SNMP Library +with a focus on its session management functions. The Traditional API +and the Single API functions are compared and contrasted. +A working understanding of the CMU or UCD SNMP Library +API is recommended to fully appreciate the concepts discussed. +The document ends with a list of restrictions for using the Single API +in a multi-threaded application. + +Unfortunately, the SNMPv3 support was added about the same time as +the thread support and since they occurred in parallel the SNMPv3 +support was never checked for multi-threading correctness. It is +most likely that it is not thread-safe at this time. + + ***** IMPORTANT ANNOUNCEMENT ***** + To the point, no resource locks are applied within the SNMP Library. + The APDU encoding and some session management functions can be used + in thread-safe manners. The MIB file parsing is not thread-safe. + The Single Session API was made available in November 1998. + Existing applications use the Traditional API, which is not thread-safe. + The thread-safe considerations are discussed throughout this document. + +The research and development of the Single Session API that I've completed +was wholly funded by my employer, Internet Security Systems, Inc. +and is distributed freely to the Internet community. + +-Mike Slifcak, 23 April 1999 + +09 July 1999 Removed references to snmp_synch_setup and snmp_synch_reset + + +Availability + +The Single Session API is integrated into the currently available +versions of the CMU SNMP library and the UC-Davis SNMP package. + + ftp://ftp.net.cmu.edu/pub/snmp/cmu-snmp-V1.13.tar.gz and later + Read : snmp_sess_api.3, Changes.SingleSession + + ftp://ucd-snmp.ucdavis.edu/ucd-snmp-3.6.tar.gz and later + Read : snmp_sess_api.3, README.thread (after version 3.6.1) + +Both libraries work equally well in Windows NT and various +UNIX platforms. Please read this document and refer to +the snmp_sess_api section 3 manual page. + +Glossary of Terms + +APDU Application Protocol Data Unit +API Application Programming Interface +CMU Carnegie-Mellon University, Pittsburgh, PA. +Library The SNMP library; Both CMU and UCD versions are applicable. +Session Concept embodying the management of transacting SNMP APDUS. +SNMP Simple Network Management Protocol +UCD University of California at Davis, CA. + +Introduction + +The Library extends the UNIX file concept (open, close, read, write) to a Session. +Opening a Session binds a local socket to a well-known port and creates internal +structures to help with controlling the transaction of SNMP APDUs. Closing a +Session releases the memory and system resources used for these purposes. + +Since the mid-1980s, many SNMP applications have used the Traditional Session +API to transact SNMP APDUs between the local host and SNMP-enabled devices. + + The Traditional Session API does not support multi-threaded applications: + + 1) There are no resource locks to prevent exposing the Library's + global data resources to corruption in a multi-threaded application; + + 2) The Traditional API functions that receive SNMP APDUs + do not provide an interface for one of many sessions; + + 3) Errors discovered by the Library are communicated through global + data structures and are not associated with the session + in which the error occurred. + + The Single Session API provides these capabilities: + + 1) Manage a single SNMP session safely, in multi-threaded or + non-threaded applications, by avoiding access to data structures + that the Traditional Session API may share between Sessions; + + 2) Associate errors with the session context for threaded + and non-threaded applications. + + +Contrasting and Comparing Traditional API and Single API + +The Traditional API uses the struct snmp_session pointer returned +from snmp_open() to identify one SNMP session. The Single API uses +the opaque pointer returned from snmp_sess_open() to identify one +SNMP session. + + Helpful Hint : The Library copies the contents of the + structure which is input to snmp_open() and snmp_sess_open(). + Once copied, changing that input structure's data + has no effect on the opened SNMP Session. + +The Traditional API uses the snmp_error() function to identify any +library and system errors that occurred during the processing for +one SNMP session. The Single API uses snmp_sess_error() for the +same purpose. + +The Traditional API manages the private Sessions list structure; +adding to the list during snmp_open(), removing during snmp_close. + +With few exceptions, the Traditional API calls the Single API +for each session that appears on the Sessions list. + +The Traditional API reads from all Sessions on the Sessions list; +The Single API does not use the Sessions list. +The Single API can read from only one Session. + + Helpful Hint : + This is the basis for thread-safe-ness of the Library. + There are no resource locks applied. + + +Using the Single API + +A multi-threaded application that deploys the SNMP Library should +should complete all MIB file parsing before additional threads +are activated. Drawing from the parsed contents of the MIB does +not incur any data corruption exposure once the internal MIB structures +are initialised. + +The application may create threads such that a single thread may manage +a single SNMP session. The thread should call snmp_sess_init() +to prepare a struct snmp_session structure. The thread can adjust +session parameters such as the remote UDP port or the local UDP port, +which must be set prior to invoking snmp_sess_open(). + +The first call to snmp_sess_init() initialises the SNMP Library, +including the MIB parse trees, before any SNMP sessions are created. +Applications that call snmp_sess_init() do not need to read MIBs +nor setup environment variables to utilize the Library. + +After the struct snmp_session is setup, the thread must call +snmp_sess_open() to create an SNMP session. If at any time +the thread must change the Session configuration, +snmp_sess_session() returns the pointer to the internal configuration +structure (a struct snmp_session, copied from snmp_sess_open). +The thread can adjust parameters such as the session timeout +or the community string with this returned struct snmp_session pointer. +Changes to the remote or local port values have no effect on an opened Session. + +The thread can build PDUs and bind variables to PDUs, as it performs its duties. +The thread then calls snmp_sess_send() or snmp_sess_async_send() to build and send +an SNMP APDU to the remote device. If a Get-Response-PDU is expected, the thread +should call snmp_sess_synch_response() instead. + +When the thread is finished using the session, it must free the resources +that the Library used to manage the session. +Finally, the thread must call snmp_sess_close() to end the Session. + +Snmp_sess_init(), snmp_open(), and snmp_sess_open() +must use the same calling parameter for a given Session. +Other methods should use only the returned parameter from +snmp_open() and snmp_sess_open() to access the opened SNMP Session. + + +Error Processing + +Two calls were added : snmp_error() and snmp_sess_error() return the +"errno" and "snmp_errno" values from the per session data, and a string +that describes the errors that they represent. The string must be freed +by the caller. + +Use snmp_error() to process failures after Traditional API calls, +or snmp_sess_error() to process failure after Single API calls. +In the case where an SNMP session could not be opened, +call snmp_error() using the struct snmp_session supplied to either snmp_open() +or snmp_sess_open(). + + +The following variables and functions are obsolete and may create problems +in a multi-threaded application : + + int snmp_errno + char * snmp_detail + snmp_set_detail() + snmp_api_errstring() + + +Function Summary + +The functions in the following table are functionally equivalent, +with the exception of these behaviors: +- The Traditional API manages many sessions +- The Traditional API passes a struct snmp_session pointer, + and touches the Sessions list +- The Single API manages only one session +- The Single API passes an opaque pointer, and does not use Sessions list + + Traditional Single Comment + =========== ============== ======= + snmp_sess_init snmp_sess_init Call before either open + snmp_open snmp_sess_open Single not on Sessions list + snmp_sess_session Exposes snmp_session pointer + snmp_send snmp_sess_send Send one APDU + snmp_async_send snmp_sess_async_send Send one APDU with callback + snmp_select_info snmp_sess_select_info Which session(s) have input + snmp_read snmp_sess_read Read APDUs + snmp_timeout snmp_sess_timeout Check for timeout + snmp_close snmp_sess_close Single not on Sessions list + snmp_synch_response snmp_sess_synch_response Send/receive one APDU + snmp_error snmp_sess_error Get library,system errno + + +Example 1 : Traditional API use. + + #include "snmp_api.h" + ... + int liberr, syserr; + char *errstr; + struct snmp_session Session, *sptr; + ... + snmp_sess_init(&Session); + Session.peername = "foo.bar.net"; + sptr = snmp_open(&Session); + if (sptr == NULL) { + /* Error codes found in open calling argument */ + snmp_error(&Session, &liberr, &syserr, &errstr); + printf("SNMP create error %s.\n", errstr); + free(errstr); + return 0; + } + /* Pass sptr to snmp_error from here forward */ + ... + /* Change the community name */ + free(sptr->community); + sptr->community = strdup("public"); + sptr->community_len = strlen("public"); + ... + if (0 == snmp_send(sptr, pdu)) { + snmp_error(sptr, &liberr, &syserr, &errstr); + printf("SNMP write error %s.\n", errstr); + free(errstr); + return 0; + } + snmp_close(sptr); + + +Example 2 : Single API use. + + #include "snmp_api.h" + ... + int liberr, syserr; + char *errstr; + void *sessp; /* <-- an opaque pointer, not a struct pointer */ + struct snmp_session Session, *sptr; + ... + snmp_sess_init(&Session); + Session.peername = "foo.bar.net"; + sessp = snmp_sess_open(&Session); + if (sessp == NULL) { + /* Error codes found in open calling argument */ + snmp_error(&Session, &liberr, &syserr, &errstr); + printf("SNMP create error %s.\n", errstr); + free(errstr); + return 0; + } + sptr = snmp_sess_session(sessp); /* <-- get the snmp_session pointer */ + + /* Pass sptr to snmp_sess_error from here forward */ + ... + /* Change the community name */ + free(sptr->community); + sptr->community = strdup("public"); + sptr->community_len = strlen("public"); + ... + if (0 == snmp_sess_send(sessp, pdu)) { + snmp_sess_error(sessp, &liberr, &syserr, &errstr); + printf("SNMP write error %s.\n", errstr); + free(errstr); + return 0; + } + snmp_sess_close(sessp); + +Example 3. Differences Between Traditional API and Single API Usage +5a6 +> void *sessp; /* <-- an opaque pointer, not a struct pointer */ +11,13c12,14 +< sptr = snmp_open(&Session); +< if (sptr == NULL) { +--- +> sessp = snmp_sess_open(&Session); +> if (sessp == NULL) { +19c20,22 +< /* Pass sptr to snmp_error from here forward */ +--- +> sptr = snmp_sess_session(sessp); /* <-- get the snmp_session pointer */ +> +> /* Pass sptr to snmp_sess_error from here forward */ +26,27c29,30 +< if (0 == snmp_send(sptr, pdu)) { +< snmp_error(sptr, &liberr, &syserr, &errstr); +--- +> if (0 == snmp_sess_send(sessp, pdu)) { +> snmp_sess_error(sessp, &liberr, &syserr, &errstr); +33c36 +< snmp_close(sptr); +--- +> snmp_sess_close(sessp); + + +Restrictions on Multi-threaded Use of the SNMP Library + + 1. Invoke SOCK_STARTUP or SOCK_CLEANUP from the main thread only. + + 2. The MIB parsing functions use global shared data and are not + multi-thread safe when the MIB tree is under construction. + Once the tree is built, the data can be safely referenced from + any thread. There is no provision for freeing the MIB tree. + Suggestion: Read the MIB files before an SNMP session is created. + This can be accomplished by invoking snmp_sess_init from the main + thread and discarding the buffer which is initialised. + + 3. Invoke the SNMPv2p initialisation before an SNMP session is created, + for reasons similar to reading the MIB file. + The SNMPv2p structures should be available to all SNMP sessions. + CAUTION: These structures have not been tested in a multi-threaded + application. + + 4. Sessions created using the Single API do not interact with other + SNMP sessions. If you choose to use Traditional API calls, call + them from a single thread. The Library cannot reference an SNMP + session using both Traditional and Single API calls. + + 5. Using the callback mechanism for asynchronous response PDUs + requires additional caution in a multi-threaded application. + This means a callback function probably should probably not use + Single API calls to further process the session. + + 6. Each call to snmp_sess_open() creates an IDS. Only a call to + snmp_sess_close() releases the resources used by the IDS. + |