Logo
Home page Net-SNMP

Archive Search:

Require all words?

Site Search:
Google
Main Page | Modules | Data Structures | File List | Data Fields | Related Pages | Examples

row_merge.c

00001 #include <net-snmp/net-snmp-config.h>
00002 
00003 #if HAVE_STRING_H
00004 #include <string.h>
00005 #else
00006 #include <strings.h>
00007 #endif
00008 
00009 #include <net-snmp/net-snmp-includes.h>
00010 #include <net-snmp/agent/net-snmp-agent-includes.h>
00011 
00012 #include <net-snmp/agent/row_merge.h>
00013 
00026 netsnmp_mib_handler *
00027 netsnmp_get_row_merge_handler(int prefix_len)
00028 {
00029     netsnmp_mib_handler *ret = NULL;
00030     ret = netsnmp_create_handler("row_merge",
00031                                   netsnmp_row_merge_helper_handler);
00032     if (ret) {
00033         ret->myvoid = (void *) prefix_len;
00034     }
00035     return ret;
00036 }
00037 
00040 int
00041 netsnmp_register_row_merge(netsnmp_handler_registration *reginfo)
00042 {
00043     netsnmp_inject_handler(reginfo,
00044                     netsnmp_get_row_merge_handler(reginfo->rootoid_len+1));
00045     return netsnmp_register_handler(reginfo);
00046 }
00047 
00048 static void
00049 _rm_status_free(void *mem)
00050 {
00051     netsnmp_row_merge_status *rm_status = (netsnmp_row_merge_status*)mem;
00052 
00053     if (NULL != rm_status->saved_requests)
00054         free(rm_status->saved_requests);
00055 
00056     if (NULL != rm_status->saved_status)
00057         free(rm_status->saved_status);
00058 
00059     free(mem);
00060 }
00061 
00062 
00065 netsnmp_row_merge_status *
00066 netsnmp_row_merge_status_get(netsnmp_handler_registration *reginfo,
00067                              netsnmp_agent_request_info *reqinfo,
00068                              int create_missing)
00069 {
00070     netsnmp_row_merge_status *rm_status;
00071     char buf[64];
00072     int rc;
00073 
00074     /*
00075      * see if we've already been here
00076      */
00077     rc = snprintf(buf, sizeof(buf), "row_merge:%p", reginfo);
00078     if ((-1 == rc) || (rc >= sizeof(buf))) {
00079         snmp_log(LOG_ERR,"error creating key\n");
00080         return NULL;
00081     }
00082     
00083     rm_status = netsnmp_agent_get_list_data(reqinfo, buf);
00084     if ((NULL == rm_status) && create_missing) {
00085         void *data_list;
00086         
00087         rm_status = SNMP_MALLOC_TYPEDEF(netsnmp_row_merge_status);
00088         if (NULL == rm_status) {
00089             snmp_log(LOG_ERR,"error allocating memory\n");
00090             return NULL;
00091         }
00092         data_list = netsnmp_create_data_list(buf, rm_status,
00093                                              _rm_status_free);
00094         if (NULL == data_list) {
00095             free(rm_status);
00096             return NULL;
00097         }
00098         netsnmp_agent_add_list_data(reqinfo, data_list);
00099     }
00100     
00101     return rm_status;
00102 }
00103 
00108 int
00109 netsnmp_row_merge_status_first(netsnmp_handler_registration *reginfo,
00110                                netsnmp_agent_request_info *reqinfo)
00111 {
00112     netsnmp_row_merge_status *rm_status;
00113 
00114     /*
00115      * find status
00116      */
00117     rm_status = netsnmp_row_merge_status_get(reginfo, reqinfo, 0);
00118     if (NULL == rm_status)
00119         return 0;
00120 
00121     return (rm_status->count == 1) ? 1 : (rm_status->current == 1);
00122 }
00123 
00128 int
00129 netsnmp_row_merge_status_last(netsnmp_handler_registration *reginfo,
00130                               netsnmp_agent_request_info *reqinfo)
00131 {
00132     netsnmp_row_merge_status *rm_status;
00133 
00134     /*
00135      * find status
00136      */
00137     rm_status = netsnmp_row_merge_status_get(reginfo, reqinfo, 0);
00138     if (NULL == rm_status)
00139         return 0;
00140 
00141     return (rm_status->count == 1) ? 1 :
00142         (rm_status->current == rm_status->rows);
00143 }
00144 
00145 
00146 #define ROW_MERGE_WAITING 0
00147 #define ROW_MERGE_ACTIVE  1
00148 #define ROW_MERGE_DONE    2
00149 #define ROW_MERGE_HEAD    3
00150 
00152 int
00153 netsnmp_row_merge_helper_handler(netsnmp_mib_handler *handler,
00154                                  netsnmp_handler_registration *reginfo,
00155                                  netsnmp_agent_request_info *reqinfo,
00156                                  netsnmp_request_info *requests)
00157 {
00158     netsnmp_request_info *request, **saved_requests;
00159     char *saved_status;
00160     netsnmp_row_merge_status *rm_status;
00161     int i, j, ret, tail, count, final_rc = SNMP_ERR_NOERROR;
00162 
00163     /*
00164      * Use the prefix length as supplied during registration, rather
00165      *  than trying to second-guess what the MIB implementer wanted.
00166      */
00167     int SKIP_OID = (int)handler->myvoid;
00168 
00169     DEBUGMSGTL(("helper:row_merge", "Got request (%d): ", SKIP_OID));
00170     DEBUGMSGOID(("helper:row_merge", reginfo->rootoid, reginfo->rootoid_len));
00171     DEBUGMSG(("helper:row_merge", "\n"));
00172 
00173     /*
00174      * find or create status
00175      */
00176     rm_status = netsnmp_row_merge_status_get(reginfo, reqinfo, 1);
00177 
00178     /*
00179      * Count the requests, and set up an array to keep
00180      *  track of the original order.
00181      */
00182     for (count = 0, request = requests; request; request = request->next) {
00183         DEBUGIF("helper:row_merge") {
00184             DEBUGMSGTL(("helper:row_merge", "  got varbind: "));
00185             DEBUGMSGOID(("helper:row_merge", request->requestvb->name,
00186                          request->requestvb->name_length));
00187             DEBUGMSG(("helper:row_merge", "\n"));
00188         }
00189         count++;
00190     }
00191 
00192     /*
00193      * Optimization: skip all this if there is just one request
00194      */
00195     if(count == 1) {
00196         rm_status->count = count;
00197         return netsnmp_call_next_handler(handler, reginfo, reqinfo, requests);
00198     }
00199 
00200     /*
00201      * we really should only have to do this once, instead of every pass.
00202      * as a precaution, we'll do it every time, but put in some asserts
00203      * to see if we have to.
00204      */
00205     /*
00206      * if the count changed, re-do everything
00207      */
00208     if ((0 != rm_status->count) && (rm_status->count != count)) {
00209         /*
00210          * ok, i know next/bulk can cause this condition. Probably
00211          * GET, too. need to rethink this mode counting. maybe
00212          * add the mode to the rm_status structure? xxx-rks
00213          */
00214         if ((reqinfo->mode != MODE_GET) &&
00215             (reqinfo->mode != MODE_GETNEXT) &&
00216             (reqinfo->mode != MODE_GETBULK)) {
00217             netsnmp_assert((NULL != rm_status->saved_requests) &&
00218                            (NULL != rm_status->saved_status));
00219         }
00220         DEBUGMSGTL(("helper:row_merge", "count changed! do over...\n"));
00221 
00222         SNMP_FREE(rm_status->saved_requests);
00223         SNMP_FREE(rm_status->saved_status);
00224         
00225         rm_status->count = 0;
00226         rm_status->rows = 0;
00227     }
00228 
00229     if (0 == rm_status->count) {
00230         /*
00231          * allocate memory for saved structure
00232          */
00233         rm_status->saved_requests =
00234             (netsnmp_request_info**)calloc(count+1,
00235                                            sizeof(netsnmp_request_info*));
00236         rm_status->saved_status = (char*)calloc(count,sizeof(char));
00237     }
00238 
00239     saved_status = rm_status->saved_status;
00240     saved_requests = rm_status->saved_requests;
00241 
00242     /*
00243      * set up saved requests, and set any processed requests to done
00244      */
00245     i = 0;
00246     for (request = requests; request; request = request->next, i++) {
00247         if (request->processed) {
00248             saved_status[i] = ROW_MERGE_DONE;
00249             DEBUGMSGTL(("helper:row_merge", "  skipping processed oid: "));
00250             DEBUGMSGOID(("helper:row_merge", request->requestvb->name,
00251                          request->requestvb->name_length));
00252             DEBUGMSG(("helper:row_merge", "\n"));
00253         }
00254         else
00255             saved_status[i] = ROW_MERGE_WAITING;
00256         if (0 != rm_status->count)
00257             netsnmp_assert(saved_requests[i] == request);
00258         saved_requests[i] = request;
00259     }
00260     saved_requests[i] = NULL;
00261 
00262     /*
00263      * Note that saved_requests[count] is valid
00264      *    (because of the 'count+1' in the calloc above),
00265      * but NULL (since it's past the end of the list).
00266      * This simplifies the re-linking later.
00267      */
00268 
00269     /*
00270      * Work through the (unprocessed) requests in order.
00271      * For each of these, search the rest of the list for any
00272      *   matching indexes, and link them into a new list.
00273      */
00274     for (i=0; i<count; i++) {
00275         if (saved_status[i] != ROW_MERGE_WAITING)
00276             continue;
00277 
00278         if (0 == rm_status->count)
00279             rm_status->rows++;
00280         DEBUGMSGTL(("helper:row_merge", " row %d oid[%d]: ", rm_status->rows, i));
00281         DEBUGMSGOID(("helper:row_merge", saved_requests[i]->requestvb->name,
00282                      saved_requests[i]->requestvb->name_length));
00283         DEBUGMSG(("helper:row_merge", "\n"));
00284 
00285         saved_requests[i]->next = NULL;
00286         saved_status[i] = ROW_MERGE_HEAD;
00287         tail = i;
00288         for (j=i+1; j<count; j++) {
00289             if (saved_status[j] != ROW_MERGE_WAITING)
00290                 continue;
00291 
00292             DEBUGMSGTL(("helper:row_merge", "? oid[%d]: ", j));
00293             DEBUGMSGOID(("helper:row_merge",
00294                          saved_requests[j]->requestvb->name,
00295                          saved_requests[j]->requestvb->name_length));
00296             if (!snmp_oid_compare(
00297                     saved_requests[i]->requestvb->name+SKIP_OID,
00298                     saved_requests[i]->requestvb->name_length-SKIP_OID,
00299                     saved_requests[j]->requestvb->name+SKIP_OID,
00300                     saved_requests[j]->requestvb->name_length-SKIP_OID)) {
00301                 DEBUGMSG(("helper:row_merge", " match\n"));
00302                 saved_requests[tail]->next = saved_requests[j];
00303                 saved_requests[j]->next    = NULL;
00304                 saved_status[j] = ROW_MERGE_ACTIVE;
00305                 tail = j;
00306             }
00307             else
00308                 DEBUGMSG(("helper:row_merge", " no match\n"));
00309         }
00310     }
00311 
00312     /*
00313      * not that we have a list for each row, call next handler...
00314      */
00315     if (0 == rm_status->count)
00316         rm_status->count = count;
00317     rm_status->current = 0;
00318     for (i=0; i<count; i++) {
00319         if (saved_status[i] != ROW_MERGE_HEAD)
00320             continue;
00321 
00322         /*
00323          * found the head of a new row,
00324          * call the next handler with this list
00325          */
00326         rm_status->current++;
00327         ret = netsnmp_call_next_handler(handler, reginfo, reqinfo,
00328                                         saved_requests[i]);
00329         if (ret != SNMP_ERR_NOERROR) {
00330             snmp_log(LOG_WARNING,
00331                      "bad rc (%d) from next handler in row_merge\n", ret);
00332             if (SNMP_ERR_NOERROR == final_rc)
00333                 final_rc = ret;
00334         }
00335     }
00336 
00337     /*
00338      * restore original linked list
00339      */
00340     for (i=0; i<count; i++)
00341         saved_requests[i]->next = saved_requests[i+1];
00342 
00343     return final_rc;
00344 }
00345 
00351 void
00352 netsnmp_init_row_merge(void)
00353 {
00354     netsnmp_register_handler_by_name("row_merge",
00355                                      netsnmp_get_row_merge_handler(-1));
00356 }

Generated on Fri Dec 30 13:47:46 2005 for net-snmp by  doxygen 1.3.9.1

Valid CSS!


Last modified: Thursday, 01-Mar-2007 16:20:14 PST
For questions regarding web content and site functionality, please write to the net-snmp-users mail list.