/* * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * * This file is part of Kamailio, a free SIP server. * * Kamailio is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * Kamailio is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA * * Note: this file originally auto-generated by mib2c using * mib2c.array-user.conf * * This file implements the kamailioSIPRegUserLookupTable. For a full * description of the table, please see the KAMAILIO-SIP-SERVER-MIB. * * This file is much larger and more complicated than the files for other * tables. This is because the table is settable, bringing a lot of SNMP * overhead. Most of the file consists of the original auto-generated * code (aside from white space and comment changes). * * The functions that have been modified to implement this table are the * following: * * 1) kamailioSIPRegUserLookupTable_extract_index() * * - Modified to fail if the index is invalid. The index is invalid if it * does not match up with the global userLookupCounter. * * 2) kamailioSIPRegUserLookupTable_can_[activate|deactivate|delete]() * * - Simplified to always allow activation/deactivation/deletion. * * 3) kamailioSIPRegUserLookupTable_set_reserve1() * * - The reserve1 phase passes if the row is new, and the rowStatus column * is being set to 'createAndGo' * - The reserve1 phase passes if the row is not new, and the rowStatus * column is being set to 'destroy' * * 4) kamailioSIPRegUserLookupTable_set_action() * * - The function was modified to populate the row with the userIndex of the * supplied URI if that URI was found on the system, and set the rowStatus * to 'active'. If the URI was not found, the rowStatus is set to * 'notInService' * * You can safely ignore the other functions. */ #include #include #include #include #include "snmpSIPRegUserLookupTable.h" #include "snmpstats_globals.h" #include "hashTable.h" #include "interprocess_buffer.h" static netsnmp_handler_registration *my_handler = NULL; static netsnmp_table_array_callbacks cb; oid kamailioSIPRegUserLookupTable_oid[] = { kamailioSIPRegUserLookupTable_TABLE_OID}; size_t kamailioSIPRegUserLookupTable_oid_len = OID_LENGTH(kamailioSIPRegUserLookupTable_oid); /* * Initializes the kamailioSIPRegUserLookupTable table. This step is easier * than in the other tables because there is no table population. All table * population takes place during run time. */ void init_kamailioSIPRegUserLookupTable(void) { initialize_table_kamailioSIPRegUserLookupTable(); } /* the *_row_copy routine */ static int kamailioSIPRegUserLookupTable_row_copy( kamailioSIPRegUserLookupTable_context *dst, kamailioSIPRegUserLookupTable_context *src) { if(!dst || !src) { return 1; } /* copy index, if provided */ if(dst->index.oids) { free(dst->index.oids); } if(snmp_clone_mem((void *)&dst->index.oids, src->index.oids, src->index.len * sizeof(oid))) { dst->index.oids = NULL; return 1; } dst->index.len = src->index.len; /* Copy out almost all components of the structure. We don't copy out * the kamailioSIPRegUSerLookupURI (or its length). */ dst->kamailioSIPRegUserLookupIndex = src->kamailioSIPRegUserLookupIndex; dst->kamailioSIPRegUserIndex = src->kamailioSIPRegUserIndex; dst->kamailioSIPRegUserLookupRowStatus = src->kamailioSIPRegUserLookupRowStatus; return 0; } /* * the *_extract_index routine. (Mostly auto-generated) * * This routine is called when a set request is received for an index * that was not found in the table container. Here, we parse the oid * in the individual index components and copy those indexes to the * context. Then we make sure the indexes for the new row are valid. * * It has been modified from its original form in that if the indexes are * invalid, then they aren't returned. An index is invalid if: * * 1) It is < 1 * 2) It doesn't match the global userLookupIndex. (As per MIB specs) * */ int kamailioSIPRegUserLookupTable_extract_index( kamailioSIPRegUserLookupTable_context *ctx, netsnmp_index *hdr) { /* * temporary local storage for extracting oid index * * extract index uses varbinds (netsnmp_variable_list) to parse * the index OID into the individual components for each index part. */ netsnmp_variable_list var_kamailioSIPRegUserLookupIndex; int err; /* copy index, if provided */ if(hdr) { netsnmp_assert(ctx->index.oids == NULL); if((hdr->len > MAX_OID_LEN) || snmp_clone_mem((void *)&ctx->index.oids, hdr->oids, hdr->len * sizeof(oid))) { return -1; } ctx->index.len = hdr->len; } /* Set up the index */ memset(&var_kamailioSIPRegUserLookupIndex, 0x00, sizeof(var_kamailioSIPRegUserLookupIndex)); var_kamailioSIPRegUserLookupIndex.type = ASN_UNSIGNED; var_kamailioSIPRegUserLookupIndex.next_variable = NULL; if(hdr) { /* parse the oid into the individual index components */ err = parse_oid_indexes( hdr->oids, hdr->len, &var_kamailioSIPRegUserLookupIndex); if(err == SNMP_ERR_NOERROR) { /* copy index components into the context structure */ ctx->kamailioSIPRegUserLookupIndex = *var_kamailioSIPRegUserLookupIndex.val.integer; /* * Check to make sure that the index corresponds to the * global_userLookupCounter, as per the MIB specifications. */ if(*var_kamailioSIPRegUserLookupIndex.val.integer != global_UserLookupCounter || *var_kamailioSIPRegUserLookupIndex.val.integer < 1) { err = -1; } } /* parsing may have allocated memory. free it. */ snmp_reset_var_buffers(&var_kamailioSIPRegUserLookupIndex); return err; } return -1; } /* * This is an auto-generated function. In general the *_can_activate routine * is called when a row is changed to determine if all the values set are * consistent with the row's rules for a row status of ACTIVE. If not, then 0 * can be returned to prevent the row status from becomming final. * * For our purposes, we have no need for this check, so we always return 1. */ int kamailioSIPRegUserLookupTable_can_activate( kamailioSIPRegUserLookupTable_context *undo_ctx, kamailioSIPRegUserLookupTable_context *row_ctx, netsnmp_request_group *rg) { return 1; } /* * This is an auto-generated function. In general the *_can_deactivate routine * is called when a row that is currently ACTIVE is set to a state other than * ACTIVE. If there are conditions in which a row should not be allowed to * transition out of the ACTIVE state (such as the row being referred to by * another row or table), check for them here. * * Since this table has no reason why this shouldn't be allowed, we always * return 1; */ int kamailioSIPRegUserLookupTable_can_deactivate( kamailioSIPRegUserLookupTable_context *undo_ctx, kamailioSIPRegUserLookupTable_context *row_ctx, netsnmp_request_group *rg) { return 1; } /* * This is an auto-generated function. In general the *_can_delete routine is * called to determine if a row can be deleted. This usually involved checking * if it can be deactivated, and if it can be, then checking for other * conditions. * * Since this table ha no reason why row deletion shouldn't be allowed, we * always return 1, unless we can't deactivate. */ int kamailioSIPRegUserLookupTable_can_delete( kamailioSIPRegUserLookupTable_context *undo_ctx, kamailioSIPRegUserLookupTable_context *row_ctx, netsnmp_request_group *rg) { if(kamailioSIPRegUserLookupTable_can_deactivate(undo_ctx, row_ctx, rg) != 1) return 0; return 1; } /* * This is an auto-generated function. * * The *_create_row routine is called by the table handler to create a new row * for a given index. This is the first stage of the row creation process. The * *_set_reserve_* functions can be used to prevent the row from being inserted * into the table even if the row passes any preliminary checks set here. * * Returns a newly allocated kamailioSIPRegUserLookupTable_context structure (a * row in the table) if the indexes are legal. NULL will be returned otherwise. */ kamailioSIPRegUserLookupTable_context *kamailioSIPRegUserLookupTable_create_row( netsnmp_index *hdr) { kamailioSIPRegUserLookupTable_context *ctx = SNMP_MALLOC_TYPEDEF(kamailioSIPRegUserLookupTable_context); if(!ctx) { return NULL; } /* * Extract the index. The function has been modified from its original * auto-generated version in that the function will fail if index is * somehow invalid. */ if(kamailioSIPRegUserLookupTable_extract_index(ctx, hdr)) { if(NULL != ctx->index.oids) { free(ctx->index.oids); } free(ctx); return NULL; } ctx->kamailioSIPRegUserLookupURI = NULL; ctx->kamailioSIPRegUserLookupURI_len = 0; ctx->kamailioSIPRegUserIndex = 0; ctx->kamailioSIPRegUserLookupRowStatus = 0; return ctx; } /* * Auto-generated function. The *_duplicate row routine */ kamailioSIPRegUserLookupTable_context * kamailioSIPRegUserLookupTable_duplicate_row( kamailioSIPRegUserLookupTable_context *row_ctx) { kamailioSIPRegUserLookupTable_context *dup; if(!row_ctx) return NULL; dup = SNMP_MALLOC_TYPEDEF(kamailioSIPRegUserLookupTable_context); if(!dup) return NULL; if(kamailioSIPRegUserLookupTable_row_copy(dup, row_ctx)) { free(dup); dup = NULL; } return dup; } /* * The *_delete_row method is auto-generated, and is called to delete a row. * * This will not be called if earlier checks said that this row can't be * deleted. However, in our implementation there is never a reason why this * function can't be called. */ netsnmp_index *kamailioSIPRegUserLookupTable_delete_row( kamailioSIPRegUserLookupTable_context *ctx) { if(ctx->index.oids) { free(ctx->index.oids); } if(ctx->kamailioSIPRegUserLookupURI != NULL) { pkg_free(ctx->kamailioSIPRegUserLookupURI); } free(ctx); return NULL; } /* * Large parts of this function have been auto-generated. The functions purpose * is to check to make sure all SNMP set values for the given row, have been * valid. If not, then the process is supposed to be aborted. Otherwise, we * pass on to the *_reserve2 function. * * For our purposes, our only check is to make sure that either of the following * conditions are true: * * 1) If this row already exists, then the SET request is setting the rowStatus * column to 'destroy'. * * 2) If this row does not already exist, then the SET request is setting the * rowStatus to 'createAndGo'. * * Since the MIB specified there are to be no other modifications to the row, * any other condition is considered illegal, and will result in an SNMP error * being returned. */ void kamailioSIPRegUserLookupTable_set_reserve1(netsnmp_request_group *rg) { kamailioSIPRegUserLookupTable_context *row_ctx = (kamailioSIPRegUserLookupTable_context *)rg->existing_row; netsnmp_variable_list *var; netsnmp_request_group_item *current; int rc; for(current = rg->list; current; current = current->next) { var = current->ri->requestvb; rc = SNMP_ERR_NOERROR; switch(current->tri->colnum) { case COLUMN_KAMAILIOSIPREGUSERLOOKUPURI: if(row_ctx->kamailioSIPRegUserLookupRowStatus == 0 || row_ctx->kamailioSIPRegUserLookupRowStatus == TC_ROWSTATUS_NOTREADY) { } else { rc = SNMP_ERR_BADVALUE; } break; case COLUMN_KAMAILIOSIPREGUSERLOOKUPROWSTATUS: /** RowStatus = ASN_INTEGER */ rc = netsnmp_check_vb_type_and_size(var, ASN_INTEGER, sizeof(row_ctx->kamailioSIPRegUserLookupRowStatus)); /* Want to make sure that if it already exists that it * is setting it to 'destroy', or if it doesn't exist, * that it is setting it to 'createAndGo' */ if(row_ctx->kamailioSIPRegUserLookupRowStatus == 0 && *var->val.integer != TC_ROWSTATUS_CREATEANDGO) { rc = SNMP_ERR_BADVALUE; } else if(row_ctx->kamailioSIPRegUserLookupRowStatus == TC_ROWSTATUS_ACTIVE && *var->val.integer != TC_ROWSTATUS_DESTROY) { rc = SNMP_ERR_BADVALUE; } break; default: /** We shouldn't get here */ rc = SNMP_ERR_GENERR; snmp_log(LOG_ERR, "unknown column in kamailioSIPReg" "UserLookupTable_set_reserve1\n"); } if(rc) { netsnmp_set_mode_request_error(MODE_SET_BEGIN, current->ri, rc); } rg->status = SNMP_MAX(rg->status, current->ri->status); } } /* * Auto-generated function. The function is supposed to check for any * last-minute conditions not being met. However, we don't have any such * conditions, so we leave the default function as is. */ void kamailioSIPRegUserLookupTable_set_reserve2(netsnmp_request_group *rg) { kamailioSIPRegUserLookupTable_context *undo_ctx = (kamailioSIPRegUserLookupTable_context *)rg->undo_info; netsnmp_request_group_item *current; int rc; rg->rg_void = rg->list->ri; for(current = rg->list; current; current = current->next) { rc = SNMP_ERR_NOERROR; switch(current->tri->colnum) { case COLUMN_KAMAILIOSIPREGUSERLOOKUPURI: break; case COLUMN_KAMAILIOSIPREGUSERLOOKUPROWSTATUS: /** RowStatus = ASN_INTEGER */ rc = netsnmp_check_vb_rowstatus(current->ri->requestvb, undo_ctx ? undo_ctx->kamailioSIPRegUserLookupRowStatus : 0); rg->rg_void = current->ri; break; default: /** We shouldn't get here */ netsnmp_assert(0); /** why wasn't this caught in reserve1? */ } if(rc) { netsnmp_set_mode_request_error(MODE_SET_BEGIN, current->ri, rc); } } } /* * This function is called only when all the *_reserve[1|2] functions were * succeful. Its purpose is to make any changes to the row before it is * inserted into the table. * * In the case of this table, this involves looking up the index of the * requested user in the URI to userIndex mapping hash table. If the result is * found, the index will be copied to the row, and the rowStatus set to * 'active'. Otherwise, the row status will be set to 'notInService' * * All other handling is auto-generated. */ void kamailioSIPRegUserLookupTable_set_action(netsnmp_request_group *rg) { /* First things first, we need to consume the interprocess buffer, in * case something has changed. We want to return the freshest data. */ consumeInterprocessBuffer(); aorToIndexStruct_t *hashRecord; netsnmp_variable_list *var; kamailioSIPRegUserLookupTable_context *row_ctx = (kamailioSIPRegUserLookupTable_context *)rg->existing_row; kamailioSIPRegUserLookupTable_context *undo_ctx = (kamailioSIPRegUserLookupTable_context *)rg->undo_info; netsnmp_request_group_item *current; int row_err = 0; /* Copy the actual data to the row. */ for(current = rg->list; current; current = current->next) { var = current->ri->requestvb; switch(current->tri->colnum) { case COLUMN_KAMAILIOSIPREGUSERLOOKUPURI: row_ctx->kamailioSIPRegUserLookupURI = pkg_malloc(sizeof(char) * (var->val_len + 1)); memcpy(row_ctx->kamailioSIPRegUserLookupURI, var->val.string, var->val_len); /* Usually NetSNMP won't terminate strings with '\0'. * The hash function expect them to be terminated * though, so we have to add this on to the end. The +1 * in the malloc makes sure of the extra space for us. */ row_ctx->kamailioSIPRegUserLookupURI[var->val_len] = '\0'; row_ctx->kamailioSIPRegUserLookupURI_len = var->val_len; /* Do the lookup. If we could find the record, then set * the index and the row status to active. Otherwise, * set the row to notInService */ hashRecord = findHashRecord(hashTable, (char *)row_ctx->kamailioSIPRegUserLookupURI, HASH_SIZE); if(hashRecord == NULL) { row_ctx->kamailioSIPRegUserIndex = 0; row_ctx->kamailioSIPRegUserLookupRowStatus = TC_ROWSTATUS_NOTINSERVICE; } else { row_ctx->kamailioSIPRegUserIndex = hashRecord->userIndex; row_ctx->kamailioSIPRegUserLookupRowStatus = TC_ROWSTATUS_ACTIVE; } break; case COLUMN_KAMAILIOSIPREGUSERLOOKUPROWSTATUS: row_ctx->kamailioSIPRegUserLookupRowStatus = *var->val.integer; if(*var->val.integer == TC_ROWSTATUS_CREATEANDGO) { rg->row_created = 1; /* Set to NOT READY until the lookup URI has * been supplied. */ row_ctx->kamailioSIPRegUserLookupRowStatus = TC_ROWSTATUS_NOTREADY; } else if(*var->val.integer == TC_ROWSTATUS_DESTROY) { rg->row_deleted = 1; } else { /* We should never be here, because the RESERVE * functions should have taken care of all other * values. */ LM_ERR("invalid RowStatus in " "kamailioSIPStatusCodesTable\n"); } break; default: /** We shouldn't get here */ netsnmp_assert(0); /** why wasn't this caught in reserve1? */ } } /* * done with all the columns. Could check row related * requirements here. */ #ifndef kamailioSIPRegUserLookupTable_CAN_MODIFY_ACTIVE_ROW if(undo_ctx && RS_IS_ACTIVE(undo_ctx->kamailioSIPRegUserLookupRowStatus) && row_ctx && RS_IS_ACTIVE(row_ctx->kamailioSIPRegUserLookupRowStatus)) { row_err = 1; } #endif LM_DBG("stage row_err = %d\n", row_err); /* * check activation/deactivation */ row_err = netsnmp_table_array_check_row_status(&cb, rg, row_ctx ? &row_ctx->kamailioSIPRegUserLookupRowStatus : NULL, undo_ctx ? &undo_ctx->kamailioSIPRegUserLookupRowStatus : NULL); if(row_err) { netsnmp_set_mode_request_error( MODE_SET_BEGIN, (netsnmp_request_info *)rg->rg_void, row_err); return; } } /* * The COMMIT phase is used to do any extra processing after the ACTION phase. * In our table, there is nothing to do, so the function body is empty. */ void kamailioSIPRegUserLookupTable_set_commit(netsnmp_request_group *rg) { } /* * This function is called if the *_reserve[1|2] calls failed. Its supposed to * free up any resources allocated earlier. However, we already take care of * all these resources in earlier functions. So for our purposes, the function * body is empty. */ void kamailioSIPRegUserLookupTable_set_free(netsnmp_request_group *rg) { } /* * This function is called if an ACTION phase fails, to do extra clean-up work. * We don't have anything complicated enough to warrant putting anything in this * function. Therefore, its just left with an empty function body. */ void kamailioSIPRegUserLookupTable_set_undo(netsnmp_request_group *rg) { } /* * Initialize the kamailioSIPRegUserLookupTable table by defining how it is * structured. * * This function is mostly auto-generated. */ void initialize_table_kamailioSIPRegUserLookupTable(void) { netsnmp_table_registration_info *table_info; if(my_handler) { snmp_log(LOG_ERR, "initialize_table_kamailioSIPRegUserLookup" "Table_handler called again\n"); return; } memset(&cb, 0x00, sizeof(cb)); /** create the table structure itself */ table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info); if(table_info==NULL) { snmp_log(LOG_ERR, "failed to allocate table_info\n"); return; } my_handler = netsnmp_create_handler_registration( "kamailioSIPRegUserLookupTable", netsnmp_table_array_helper_handler, kamailioSIPRegUserLookupTable_oid, kamailioSIPRegUserLookupTable_oid_len, HANDLER_CAN_RWRITE); if(!my_handler) { SNMP_FREE(table_info); snmp_log(LOG_ERR, "malloc failed in " "initialize_table_kamailioSIPRegUserLookup" "Table_handler\n"); return; /** mallocs failed */ } /* * Setting up the table's definition */ netsnmp_table_helper_add_index(table_info, ASN_UNSIGNED); table_info->min_column = kamailioSIPRegUserLookupTable_COL_MIN; table_info->max_column = kamailioSIPRegUserLookupTable_COL_MAX; /* * registering the table with the master agent */ cb.get_value = kamailioSIPRegUserLookupTable_get_value; cb.container = netsnmp_container_find("kamailioSIPRegUserLookupTable_primary:" "kamailioSIPRegUserLookupTable:" "table_container"); cb.can_set = 1; cb.create_row = (UserRowMethod *)kamailioSIPRegUserLookupTable_create_row; cb.duplicate_row = (UserRowMethod *)kamailioSIPRegUserLookupTable_duplicate_row; cb.delete_row = (UserRowMethod *)kamailioSIPRegUserLookupTable_delete_row; cb.row_copy = (Netsnmp_User_Row_Operation *) kamailioSIPRegUserLookupTable_row_copy; cb.can_activate = (Netsnmp_User_Row_Action *) kamailioSIPRegUserLookupTable_can_activate; cb.can_deactivate = (Netsnmp_User_Row_Action *) kamailioSIPRegUserLookupTable_can_deactivate; cb.can_delete = (Netsnmp_User_Row_Action *)kamailioSIPRegUserLookupTable_can_delete; cb.set_reserve1 = kamailioSIPRegUserLookupTable_set_reserve1; cb.set_reserve2 = kamailioSIPRegUserLookupTable_set_reserve2; cb.set_action = kamailioSIPRegUserLookupTable_set_action; cb.set_commit = kamailioSIPRegUserLookupTable_set_commit; cb.set_free = kamailioSIPRegUserLookupTable_set_free; cb.set_undo = kamailioSIPRegUserLookupTable_set_undo; DEBUGMSGTL(("initialize_table_kamailioSIPRegUserLookupTable", "Registering table kamailioSIPRegUserLookupTable " "as a table array\n")); netsnmp_table_container_register( my_handler, table_info, &cb, cb.container, 1); } /* * This function was auto-generated and didn't need modifications from its * auto-generation. It is called to handle an SNMP GET request. */ int kamailioSIPRegUserLookupTable_get_value(netsnmp_request_info *request, netsnmp_index *item, netsnmp_table_request_info *table_info) { netsnmp_variable_list *var = request->requestvb; kamailioSIPRegUserLookupTable_context *context = (kamailioSIPRegUserLookupTable_context *)item; switch(table_info->colnum) { case COLUMN_KAMAILIOSIPREGUSERLOOKUPURI: /** SnmpAdminString = ASN_OCTET_STR */ snmp_set_var_typed_value(var, ASN_OCTET_STR, (unsigned char *)context->kamailioSIPRegUserLookupURI, context->kamailioSIPRegUserLookupURI_len); break; case COLUMN_KAMAILIOSIPREGUSERINDEX: /** UNSIGNED32 = ASN_UNSIGNED */ snmp_set_var_typed_value(var, ASN_UNSIGNED, (unsigned char *)&context->kamailioSIPRegUserIndex, sizeof(context->kamailioSIPRegUserIndex)); break; case COLUMN_KAMAILIOSIPREGUSERLOOKUPROWSTATUS: /** RowStatus = ASN_INTEGER */ snmp_set_var_typed_value(var, ASN_INTEGER, (unsigned char *)&context ->kamailioSIPRegUserLookupRowStatus, sizeof(context->kamailioSIPRegUserLookupRowStatus)); break; default: /** We shouldn't get here */ snmp_log(LOG_ERR, "unknown column in " "kamailioSIPRegUserLookupTable_get_value\n"); return SNMP_ERR_GENERR; } return SNMP_ERR_NOERROR; } /* * kamailioSIPRegUserLookupTable_get_by_idx */ const kamailioSIPRegUserLookupTable_context * kamailioSIPRegUserLookupTable_get_by_idx(netsnmp_index *hdr) { return (const kamailioSIPRegUserLookupTable_context *)CONTAINER_FIND( cb.container, hdr); }