Blame README.thread

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