00001 /* 00002 * table_container.c 00003 * $Id: table__container_8c-source.html 14005 2005-12-30 19:14:23Z alex_b $ 00004 */ 00005 00006 #include <net-snmp/net-snmp-config.h> 00007 00008 #if HAVE_STRING_H 00009 #include <string.h> 00010 #else 00011 #include <strings.h> 00012 #endif 00013 00014 #include <net-snmp/net-snmp-includes.h> 00015 #include <net-snmp/agent/net-snmp-agent-includes.h> 00016 00017 #include <net-snmp/agent/table.h> 00018 #include <net-snmp/agent/table_container.h> 00019 #include <net-snmp/library/container.h> 00020 #include <net-snmp/library/snmp_assert.h> 00021 00022 /* 00023 * snmp.h:#define SNMP_MSG_INTERNAL_SET_BEGIN -1 00024 * snmp.h:#define SNMP_MSG_INTERNAL_SET_RESERVE1 0 00025 * snmp.h:#define SNMP_MSG_INTERNAL_SET_RESERVE2 1 00026 * snmp.h:#define SNMP_MSG_INTERNAL_SET_ACTION 2 00027 * snmp.h:#define SNMP_MSG_INTERNAL_SET_COMMIT 3 00028 * snmp.h:#define SNMP_MSG_INTERNAL_SET_FREE 4 00029 * snmp.h:#define SNMP_MSG_INTERNAL_SET_UNDO 5 00030 */ 00031 00032 /* 00033 * PRIVATE structure for holding important info for each table. 00034 */ 00035 typedef struct container_table_data_s { 00036 00038 netsnmp_table_registration_info *tblreg_info; 00039 00041 netsnmp_container *table; 00042 00043 /* 00044 * mutex_type lock; 00045 */ 00046 00047 /* what type of key do we want? */ 00048 char key_type; 00049 00050 } container_table_data; 00051 00134 static int 00135 _container_table_handler(netsnmp_mib_handler *handler, 00136 netsnmp_handler_registration *reginfo, 00137 netsnmp_agent_request_info *agtreq_info, 00138 netsnmp_request_info *requests); 00139 00140 static void * 00141 _find_next_row(netsnmp_container *c, 00142 netsnmp_table_request_info *tblreq, 00143 void * key); 00144 00145 /********************************************************************** 00146 ********************************************************************** 00147 * * 00148 * * 00149 * PUBLIC Registration functions * 00150 * * 00151 * * 00152 ********************************************************************** 00153 **********************************************************************/ 00154 00155 /* ================================== 00156 * 00157 * Container Table API: Table maintenance 00158 * 00159 * ================================== */ 00160 00161 container_table_data * 00162 netsnmp_tcontainer_create_table( const char *name, 00163 netsnmp_container *container, long flags ) 00164 { 00165 container_table_data *table; 00166 00167 table = SNMP_MALLOC_TYPEDEF(container_table_data); 00168 if (!table) 00169 return NULL; 00170 if (container) 00171 table->table = container; 00172 else { 00173 table->table = netsnmp_container_find("table_container"); 00174 if (!table->table) { 00175 SNMP_FREE(table); 00176 return NULL; 00177 } 00178 } 00179 00180 if (flags) 00181 table->key_type = flags & 0x03; /* Use lowest two bits */ 00182 else 00183 table->key_type = TABLE_CONTAINER_KEY_NETSNMP_INDEX; 00184 00185 if (!table->table->compare) 00186 table->table->compare = netsnmp_compare_netsnmp_index; 00187 if (!table->table->ncompare) 00188 table->table->ncompare = netsnmp_ncompare_netsnmp_index; 00189 00190 return table; 00191 } 00192 00193 void 00194 netsnmp_tcontainer_delete_table( container_table_data *table ) 00195 { 00196 if (!table) 00197 return; 00198 00199 if (table->table) 00200 CONTAINER_FREE(table->table); 00201 00202 SNMP_FREE(table); 00203 return; 00204 } 00205 00206 /* 00207 * The various standalone row operation routines 00208 * (create/clone/copy/delete) 00209 * will be specific to a particular table, 00210 * so can't be implemented here. 00211 */ 00212 00213 int 00214 netsnmp_tcontainer_add_row( container_table_data *table, netsnmp_index *row ) 00215 { 00216 if (!table || !table->table || !row) 00217 return -1; 00218 CONTAINER_INSERT( table->table, row ); 00219 return 0; 00220 } 00221 00222 netsnmp_index * 00223 netsnmp_tcontainer_remove_row( container_table_data *table, netsnmp_index *row ) 00224 { 00225 if (!table || !table->table || !row) 00226 return NULL; 00227 CONTAINER_REMOVE( table->table, row ); 00228 return NULL; 00229 } 00230 00231 int 00232 netsnmp_tcontainer_replace_row( container_table_data *table, 00233 netsnmp_index *old_row, netsnmp_index *new_row ) 00234 { 00235 if (!table || !table->table || !old_row || !new_row) 00236 return -1; 00237 netsnmp_tcontainer_remove_row( table, old_row ); 00238 netsnmp_tcontainer_add_row( table, new_row ); 00239 return 0; 00240 } 00241 00242 /* netsnmp_tcontainer_remove_delete_row() will be table-specific too */ 00243 00244 00245 /* ================================== 00246 * 00247 * Container Table API: MIB maintenance 00248 * 00249 * ================================== */ 00250 00252 netsnmp_mib_handler * 00253 netsnmp_container_table_handler_get(netsnmp_table_registration_info *tabreg, 00254 netsnmp_container *container, char key_type) 00255 { 00256 container_table_data *tad; 00257 netsnmp_mib_handler *handler; 00258 00259 if (NULL == tabreg) { 00260 snmp_log(LOG_ERR, "bad param in netsnmp_container_table_register\n"); 00261 return NULL; 00262 } 00263 00264 tad = SNMP_MALLOC_TYPEDEF(container_table_data); 00265 handler = netsnmp_create_handler("table_container", 00266 _container_table_handler); 00267 if((NULL == tad) || (NULL == handler)) { 00268 if(tad) free(tad); /* SNMP_FREE wasted on locals */ 00269 if(handler) free(handler); /* SNMP_FREE wasted on locals */ 00270 snmp_log(LOG_ERR, 00271 "malloc failure in netsnmp_container_table_register\n"); 00272 return NULL; 00273 } 00274 00275 tad->tblreg_info = tabreg; /* we need it too, but it really is not ours */ 00276 if(key_type) 00277 tad->key_type = key_type; 00278 else 00279 tad->key_type = TABLE_CONTAINER_KEY_NETSNMP_INDEX; 00280 00281 if(NULL == container) 00282 container = netsnmp_container_find("table_container"); 00283 tad->table = container; 00284 00285 if (NULL==container->compare) 00286 container->compare = netsnmp_compare_netsnmp_index; 00287 if (NULL==container->ncompare) 00288 container->ncompare = netsnmp_ncompare_netsnmp_index; 00289 00290 handler->myvoid = (void*)tad; 00291 handler->flags |= MIB_HANDLER_AUTO_NEXT; 00292 00293 return handler; 00294 } 00295 00296 int 00297 netsnmp_container_table_register(netsnmp_handler_registration *reginfo, 00298 netsnmp_table_registration_info *tabreg, 00299 netsnmp_container *container, char key_type ) 00300 { 00301 netsnmp_mib_handler *handler; 00302 00303 if ((NULL == reginfo) || (NULL == reginfo->handler) || (NULL == tabreg)) { 00304 snmp_log(LOG_ERR, "bad param in netsnmp_container_table_register\n"); 00305 return SNMPERR_GENERR; 00306 } 00307 00308 if (NULL==container) 00309 container = netsnmp_container_find(reginfo->handlerName); 00310 00311 handler = netsnmp_container_table_handler_get(tabreg, container, key_type); 00312 netsnmp_inject_handler(reginfo, handler ); 00313 00314 return netsnmp_register_table(reginfo, tabreg); 00315 } 00316 00318 netsnmp_container* 00319 netsnmp_container_table_container_extract(netsnmp_request_info *request) 00320 { 00321 return (netsnmp_container *) 00322 netsnmp_request_get_list_data(request, TABLE_CONTAINER_CONTAINER); 00323 } 00324 00325 #ifndef NETSNMP_USE_INLINE 00326 00327 void * 00328 netsnmp_container_table_row_extract(netsnmp_request_info *request) 00329 { 00330 /* 00331 * NOTE: this function must match in table_container.c and table_container.h. 00332 * if you change one, change them both! 00333 */ 00334 return netsnmp_request_get_list_data(request, TABLE_CONTAINER_ROW); 00335 } 00337 void * 00338 netsnmp_container_table_extract_context(netsnmp_request_info *request) 00339 { 00340 /* 00341 * NOTE: this function must match in table_container.c and table_container.h. 00342 * if you change one, change them both! 00343 */ 00344 return netsnmp_request_get_list_data(request, TABLE_CONTAINER_ROW); 00345 } 00346 #endif /* inline */ 00347 00349 void 00350 netsnmp_container_table_row_insert(netsnmp_request_info *request, 00351 netsnmp_index *row) 00352 { 00353 netsnmp_request_info *req; 00354 netsnmp_table_request_info *table_info = NULL; 00355 netsnmp_variable_list *this_index = NULL; 00356 netsnmp_variable_list *that_index = NULL; 00357 oid base_oid[] = {0, 0}; /* Make sure index OIDs are legal! */ 00358 oid this_oid[MAX_OID_LEN]; 00359 oid that_oid[MAX_OID_LEN]; 00360 size_t this_oid_len, that_oid_len; 00361 00362 if (!request) 00363 return; 00364 00365 /* 00366 * We'll add the new row information to any request 00367 * structure with the same index values as the request 00368 * passed in (which includes that one!). 00369 * 00370 * So construct an OID based on these index values. 00371 */ 00372 00373 table_info = netsnmp_extract_table_info(request); 00374 this_index = table_info->indexes; 00375 build_oid_noalloc(this_oid, MAX_OID_LEN, &this_oid_len, 00376 base_oid, 2, this_index); 00377 00378 /* 00379 * We need to look through the whole of the request list 00380 * (as received by the current handler), as there's no 00381 * guarantee that this routine will be called by the first 00382 * varbind that refers to this row. 00383 * In particular, a RowStatus controlled row creation 00384 * may easily occur later in the variable list. 00385 * 00386 * So first, we rewind to the head of the list.... 00387 */ 00388 for (req=request; req->prev; req=req->prev) 00389 ; 00390 00391 /* 00392 * ... and then start looking for matching indexes 00393 * (by constructing OIDs from these index values) 00394 */ 00395 for (; req; req=req->next) { 00396 if (req->processed) 00397 continue; 00398 00399 table_info = netsnmp_extract_table_info(req); 00400 that_index = table_info->indexes; 00401 build_oid_noalloc(that_oid, MAX_OID_LEN, &that_oid_len, 00402 base_oid, 2, that_index); 00403 00404 /* 00405 * This request has the same index values, 00406 * so add the newly-created row information. 00407 */ 00408 if (snmp_oid_compare(this_oid, this_oid_len, 00409 that_oid, that_oid_len) == 0) { 00410 netsnmp_request_add_list_data(req, 00411 netsnmp_create_data_list(TABLE_CONTAINER_ROW, row, NULL)); 00412 } 00413 } 00414 } 00415 00416 #ifndef DOXYGEN_SHOULD_SKIP_THIS 00417 /********************************************************************** 00418 ********************************************************************** 00419 * * 00420 * * 00421 * DATA LOOKUP functions * 00422 * * 00423 * * 00424 ********************************************************************** 00425 **********************************************************************/ 00426 NETSNMP_STATIC_INLINE void 00427 _set_key( container_table_data * tad, netsnmp_request_info *request, 00428 netsnmp_table_request_info *tblreq_info, 00429 void **key, netsnmp_index *index ) 00430 { 00431 if (TABLE_CONTAINER_KEY_NETSNMP_INDEX == tad->key_type) { 00432 index->oids = tblreq_info->index_oid; 00433 index->len = tblreq_info->index_oid_len; 00434 *key = index; 00435 } 00436 else if (TABLE_CONTAINER_KEY_VARBIND_INDEX == tad->key_type) { 00437 *key = tblreq_info->indexes; 00438 } 00439 #if 0 00440 else if (TABLE_CONTAINER_KEY_VARBIND_RAW == tad->key_type) { 00441 *key = request->requestvb; 00442 } 00443 #endif 00444 else 00445 *key = NULL; 00446 } 00447 00448 00449 NETSNMP_STATIC_INLINE void 00450 _data_lookup(netsnmp_handler_registration *reginfo, 00451 netsnmp_agent_request_info *agtreq_info, 00452 netsnmp_request_info *request, container_table_data * tad) 00453 { 00454 netsnmp_index *row = NULL; 00455 netsnmp_table_request_info *tblreq_info; 00456 netsnmp_variable_list *var; 00457 netsnmp_index index; 00458 void *key; 00459 00460 var = request->requestvb; 00461 00462 DEBUGIF("table_container") { 00463 DEBUGMSGTL(("table_container", " data_lookup oid:")); 00464 DEBUGMSGOID(("table_container", var->name, var->name_length)); 00465 DEBUGMSG(("table_container", "\n")); 00466 } 00467 00468 /* 00469 * Get pointer to the table information for this request. This 00470 * information was saved by table_helper_handler. 00471 */ 00472 tblreq_info = netsnmp_extract_table_info(request); 00474 netsnmp_assert((NULL != tblreq_info) && 00475 (tblreq_info->colnum <= tad->tblreg_info->max_column)); 00476 00477 if ((agtreq_info->mode == MODE_GETNEXT) || 00478 (agtreq_info->mode == MODE_GETBULK)) { 00479 /* 00480 * find the row. This will automatically move to the next 00481 * column, if necessary. 00482 */ 00483 _set_key( tad, request, tblreq_info, &key, &index ); 00484 row = _find_next_row(tad->table, tblreq_info, key); 00485 if (row) { 00486 /* 00487 * update indexes in tblreq_info (index & varbind), 00488 * then update request varbind oid 00489 */ 00490 if(TABLE_CONTAINER_KEY_NETSNMP_INDEX == tad->key_type) { 00491 tblreq_info->index_oid_len = row->len; 00492 memcpy(tblreq_info->index_oid, row->oids, 00493 row->len * sizeof(oid)); 00494 netsnmp_update_variable_list_from_index(tblreq_info); 00495 } 00496 else if (TABLE_CONTAINER_KEY_VARBIND_INDEX == tad->key_type) { 00499 netsnmp_update_indexes_from_variable_list(tblreq_info); 00500 } 00501 00502 if (TABLE_CONTAINER_KEY_VARBIND_RAW != tad->key_type) { 00503 netsnmp_table_build_oid_from_index(reginfo, request, 00504 tblreq_info); 00505 } 00506 } 00507 else { 00508 /* 00509 * no results found. Flag the request so lower handlers will 00510 * ignore it, but it is not an error - getnext will move 00511 * on to another handler to process this request. 00512 */ 00513 netsnmp_set_request_error(agtreq_info, request, SNMP_ENDOFMIBVIEW); 00514 DEBUGMSGTL(("table_container", "no row found\n")); 00515 } 00516 } 00517 else { 00518 00519 _set_key( tad, request, tblreq_info, &key, &index ); 00520 row = CONTAINER_FIND(tad->table, key); 00521 if (NULL == row) { 00522 /* 00523 * not results found. For a get, that is an error 00524 */ 00525 DEBUGMSGTL(("table_container", "no row found\n")); 00526 if((agtreq_info->mode != MODE_SET_RESERVE1) || /* get */ 00527 (reginfo->modes & HANDLER_CAN_NOT_CREATE)) { /* no create */ 00528 netsnmp_set_request_error(agtreq_info, request, 00529 SNMP_NOSUCHINSTANCE); 00530 } 00531 } 00532 } 00534 /* 00535 * save the data and table in the request. 00536 */ 00537 if (SNMP_ENDOFMIBVIEW != request->requestvb->type) { 00538 if (NULL != row) 00539 netsnmp_request_add_list_data(request, 00540 netsnmp_create_data_list 00541 (TABLE_CONTAINER_ROW, 00542 row, NULL)); 00543 netsnmp_request_add_list_data(request, 00544 netsnmp_create_data_list 00545 (TABLE_CONTAINER_CONTAINER, 00546 tad->table, NULL)); 00547 } 00548 } 00549 00550 /********************************************************************** 00551 ********************************************************************** 00552 * * 00553 * * 00554 * netsnmp_table_container_helper_handler() * 00555 * * 00556 * * 00557 ********************************************************************** 00558 **********************************************************************/ 00559 static int 00560 _container_table_handler(netsnmp_mib_handler *handler, 00561 netsnmp_handler_registration *reginfo, 00562 netsnmp_agent_request_info *agtreq_info, 00563 netsnmp_request_info *requests) 00564 { 00565 int rc = SNMP_ERR_NOERROR; 00566 int oldmode, need_processing = 0; 00567 container_table_data *tad; 00568 00570 netsnmp_assert((NULL != handler) && (NULL != handler->myvoid)); 00571 netsnmp_assert((NULL != reginfo) && (NULL != agtreq_info)); 00572 00573 DEBUGMSGTL(("table_container", "Mode %s, Got request:\n", 00574 se_find_label_in_slist("agent_mode",agtreq_info->mode))); 00575 00576 /* 00577 * First off, get our pointer from the handler. This 00578 * lets us get to the table registration information we 00579 * saved in get_table_container_handler(), as well as the 00580 * container where the actual table data is stored. 00581 */ 00582 tad = (container_table_data *)handler->myvoid; 00583 00584 /* 00585 * only do data lookup for first pass 00586 * 00587 * xxx-rks: this should really be handled up one level. we should 00588 * be able to say what modes we want to be called for during table 00589 * registration. 00590 */ 00591 oldmode = agtreq_info->mode; 00592 if(MODE_IS_GET(oldmode) || (MODE_SET_RESERVE1 == oldmode)) { 00593 netsnmp_request_info *curr_request; 00594 /* 00595 * Loop through each of the requests, and 00596 * try to find the appropriate row from the container. 00597 */ 00598 for (curr_request = requests; curr_request; curr_request = curr_request->next) { 00599 /* 00600 * skip anything that doesn't need processing. 00601 */ 00602 if (curr_request->processed != 0) { 00603 DEBUGMSGTL(("table_container", "already processed\n")); 00604 continue; 00605 } 00606 00607 /* 00608 * find data for this request 00609 */ 00610 _data_lookup(reginfo, agtreq_info, curr_request, tad); 00611 00612 if(curr_request->processed) 00613 continue; 00614 00615 ++need_processing; 00616 } 00617 } 00618 00619 /* 00620 * send GET instead of GETNEXT to sub-handlers 00621 * xxx-rks: again, this should be handled further up. 00622 */ 00623 if ((oldmode == MODE_GETNEXT) && (handler->next)) { 00624 /* 00625 * tell agent handlder not to auto call next handler 00626 */ 00627 handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE; 00628 00629 /* 00630 * if we found rows to process, pretend to be a get request 00631 * and call handler below us. 00632 */ 00633 if(need_processing > 0) { 00634 agtreq_info->mode = MODE_GET; 00635 rc = netsnmp_call_next_handler(handler, reginfo, agtreq_info, 00636 requests); 00637 if (rc != SNMP_ERR_NOERROR) { 00638 DEBUGMSGTL(("table_container", 00639 "next handler returned %d\n", rc)); 00640 } 00641 00642 agtreq_info->mode = oldmode; /* restore saved mode */ 00643 } 00644 } 00645 00646 return rc; 00647 } 00648 #endif 00651 /* ================================== 00652 * 00653 * Container Table API: Row operations 00654 * 00655 * ================================== */ 00656 00657 static void * 00658 _find_next_row(netsnmp_container *c, 00659 netsnmp_table_request_info *tblreq, 00660 void * key) 00661 { 00662 void *row = NULL; 00663 00664 if (!c || !tblreq || !tblreq->reg_info ) { 00665 snmp_log(LOG_ERR,"_find_next_row param error\n"); 00666 return NULL; 00667 } 00668 00669 /* 00670 * table helper should have made sure we aren't below our minimum column 00671 */ 00672 netsnmp_assert(tblreq->colnum >= tblreq->reg_info->min_column); 00673 00674 /* 00675 * if no indexes then use first row. 00676 */ 00677 if(tblreq->number_indexes == 0) { 00678 row = CONTAINER_FIRST(c); 00679 } else { 00680 00681 if(NULL == key) { 00682 netsnmp_index index; 00683 index.oids = tblreq->index_oid; 00684 index.len = tblreq->index_oid_len; 00685 row = CONTAINER_NEXT(c, &index); 00686 } 00687 else 00688 row = CONTAINER_NEXT(c, key); 00689 00690 /* 00691 * we don't have a row, but we might be at the end of a 00692 * column, so try the next column. 00693 */ 00694 if (NULL == row) { 00695 /* 00696 * don't set tblreq next_col unless we know there is one, 00697 * so we don't mess up table handler sparse table processing. 00698 */ 00699 oid next_col = netsnmp_table_next_column(tblreq); 00700 if (0 != next_col) { 00701 tblreq->colnum = next_col; 00702 row = CONTAINER_FIRST(c); 00703 } 00704 } 00705 } 00706 00707 return row; 00708 } 00709 00719 netsnmp_index * 00720 netsnmp_table_index_find_next_row(netsnmp_container *c, 00721 netsnmp_table_request_info *tblreq) 00722 { 00723 return _find_next_row(c, tblreq, NULL ); 00724 } 00725 00726 /* ================================== 00727 * 00728 * Container Table API: Index operations 00729 * 00730 * ================================== */ 00731
1.3.9.1
Last modified: Thursday, 01-Mar-2007 16:20:01 PST
For questions regarding web content and site functionality, please write to the net-snmp-users mail list.