openserSIPRegUserTable.c

Go to the documentation of this file.
00001 /*
00002  * $Id: openserSIPRegUserTable.c 4518 2008-07-28 15:39:28Z henningw $
00003  *
00004  * SNMPStats Module 
00005  * Copyright (C) 2006 SOMA Networks, INC.
00006  * Written by: Jeffrey Magder (jmagder@somanetworks.com)
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify it
00011  * under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00023  * USA
00024  *
00025  * History:
00026  * --------
00027  * 2006-11-23 initial version (jmagder)
00028  *
00029  * Note: this file originally auto-generated by mib2c using
00030  * mib2c.array-user.conf
00031  *
00032  * This file implements the openserSIPRegUserTable.  For a full description of
00033  * the table, please see the OPENSER-SIP-SERVER-MIB.
00034  *
00035  * Understanding this code will be much simpler with the following information:
00036  *
00037  * 1) All rows are indexed by an integer user index.  This is different from the
00038  *    usrloc module, which indexes by strings.  This less natural indexing
00039  *    scheme was required due to SNMP String index limitations.  (for example,
00040  *    SNMP has maximum index lengths.)
00041  *
00042  * 2) We need a quick way of mapping usrloc indices to our integer indices.  For
00043  *    this reason a string indexed Hash Table was created, with each entry mapping
00044  *    to an integer user index. 
00045  *
00046  *    This hash table is used by the openserSIPContactTable (the hash table also
00047  *    maps a user to its contacts), as well as the openserSIPRegUserLookupTable.
00048  *    The hash table is also used for quick lookups when a user expires. (i.e, it
00049  *    gives us a more direct reference, instead of having to search the whole
00050  *    table).
00051  *
00052  * 3) We are informed about new/expired users via a callback mechanism from the
00053  *    usrloc module.  Because of NetSNMP inefficiencies, we had to abstract this
00054  *    process.  Specifically:
00055  *
00056  *    - It can take a long time for the NetSNMP code base to populate a table with
00057  *      a large number of records. 
00058  *
00059  *    - We rely on callbacks for updated user information. 
00060  *
00061  *    Clearly, using the SNMPStats module in this situation could lead to some
00062  *    big performance loses if we don't find another way to deal with this.  The
00063  *    solution was to use an interprocess communications buffer.  
00064  *
00065  *    Instead of adding the record directly to the table, the callback functions
00066  *    now adds either an add/delete command to the interprocessBuffer.  When an
00067  *    snmp request is recieved by the SNMPStats sub-process, it will consume
00068  *    this interprocess buffer, adding and deleting users.  When it is finished,
00069  *    it can service the SNMP request.  
00070  *
00071  *    This doesn't remove the NetSNMP inefficiency, but instead moves it to a
00072  *    non-critical path.  Such an approach allows SNMP support with almost no
00073  *    overhead to the rest of OpenSER.
00074  */
00075 
00076 #include <net-snmp/net-snmp-config.h>
00077 #include <net-snmp/net-snmp-includes.h>
00078 #include <net-snmp/agent/net-snmp-agent-includes.h>
00079 
00080 #include <net-snmp/library/snmp_assert.h>
00081 
00082 #include "hashTable.h"
00083 #include "interprocess_buffer.h"
00084 #include "utilities.h"
00085 #include "openserSIPRegUserTable.h"
00086 #include "snmpstats_globals.h"
00087 
00088 #include "../../sr_module.h"
00089 #include "../../locking.h"
00090 #include "../usrloc/usrloc.h"
00091 
00092 static netsnmp_handler_registration *my_handler = NULL;
00093 static netsnmp_table_array_callbacks cb;
00094 
00095 oid    openserSIPRegUserTable_oid[]   = { openserSIPRegUserTable_TABLE_OID };
00096 size_t openserSIPRegUserTable_oid_len = OID_LENGTH(openserSIPRegUserTable_oid);
00097 
00098 
00099 /* If the usrloc module is loaded, this function will grab hooks into its
00100  * callback registration function, and add handleContactCallbacks() as the
00101  * callback for UL_CONTACT_INSERT and UL_CONTACT_EXPIRE.
00102  *
00103  * Returns 1 on success, and zero otherwise. */
00104 int registerForUSRLOCCallbacks(void)  
00105 {
00106    bind_usrloc_t bind_usrloc;
00107    usrloc_api_t ul;
00108 
00109    bind_usrloc = (bind_usrloc_t)find_export("ul_bind_usrloc", 1, 0);
00110    if (!bind_usrloc)
00111    {
00112       LM_ERR("Can't find ul_bind_usrloc\n");
00113       goto error;
00114    }
00115    if (bind_usrloc(&ul) < 0 || ul.register_ulcb == NULL)
00116    {
00117       LM_ERR("Can't bind usrloc\n");
00118       goto error;
00119    }
00120 
00121    ul.register_ulcb(UL_CONTACT_INSERT, handleContactCallbacks, NULL);
00122    
00123    ul.register_ulcb(UL_CONTACT_EXPIRE, handleContactCallbacks, NULL);
00124 
00125    return 1;
00126 
00127 error:
00128    LM_INFO("failed to register for callbacks with the USRLOC module.");
00129    LM_INFO("openserSIPContactTable and openserSIPUserTable will be"
00130          " unavailable");
00131    return 0;
00132 }
00133 
00134 
00135 /* Removes an SNMP row indexed by userIndex, and frees the string and index it
00136  * pointed to. */
00137 void deleteRegUserRow(int userIndex) 
00138 {
00139    
00140    openserSIPRegUserTable_context *theRow;
00141 
00142    netsnmp_index indexToRemove;
00143    oid indexToRemoveOID;
00144       
00145    indexToRemoveOID   = userIndex;
00146    indexToRemove.oids = &indexToRemoveOID;
00147    indexToRemove.len  = 1;
00148 
00149    theRow = CONTAINER_FIND(cb.container, &indexToRemove);
00150 
00151    /* The userURI is shared memory, the index.oids was allocated from
00152     * pkg_malloc(), and theRow was made with the NetSNMP API which uses
00153     * malloc() */
00154    if (theRow != NULL) {
00155       CONTAINER_REMOVE(cb.container, &indexToRemove);
00156       pkg_free(theRow->openserSIPUserUri);
00157       pkg_free(theRow->index.oids);
00158       free(theRow);
00159    }
00160 
00161 }
00162 
00163 /*
00164  * Adds or updates a user:
00165  *
00166  *   - If a user with the name userName exists, its 'number of contacts' count
00167  *     will be incremented.  
00168  *   - If the user doesn't exist, the user will be added to the table, and its
00169  *     number of contacts' count set to 1. 
00170  */
00171 void updateUser(char *userName) 
00172 {
00173    int userIndex; 
00174 
00175    aorToIndexStruct_t *newRecord;
00176 
00177    aorToIndexStruct_t *existingRecord = 
00178       findHashRecord(hashTable, userName, HASH_SIZE);
00179 
00180    /* We found an existing record, so  we need to update its 'number of
00181     * contacts' count. */
00182    if (existingRecord != NULL) 
00183    {
00184       existingRecord->numContacts++;
00185       return;
00186    }
00187 
00188    /* Make a new row, and insert a record of it into our mapping data
00189     * structures */
00190    userIndex = createRegUserRow(userName);
00191 
00192    if (userIndex == 0) 
00193    {
00194       LM_ERR("openserSIPRegUserTable ran out of memory."
00195             "  Not able to add user: %s", userName);
00196       return;
00197    }
00198 
00199    newRecord = createHashRecord(userIndex, userName);
00200    
00201    /* If we couldn't create a record in the hash table, then we won't be
00202     * able to access this row properly later.  So remove the row from the
00203     * table and fail. */
00204    if (newRecord == NULL) {
00205       deleteRegUserRow(userIndex);
00206       LM_ERR("openserSIPRegUserTable was not able to push %s into the hash."
00207             "  User not added to this table\n", userName);
00208       return;
00209    }
00210    
00211    /* Insert the new record of the mapping data structure into the hash
00212     * table */
00213    /*insertHashRecord(hashTable,
00214          createHashRecord(userIndex, userName), 
00215          HASH_SIZE);*/
00216    
00217    insertHashRecord(hashTable,
00218          newRecord, 
00219          HASH_SIZE);
00220 }
00221 
00222 
00223 /* Creates a row and inserts it.  
00224  *
00225  * Returns: The rows userIndex on success, and 0 otherwise. */
00226 int createRegUserRow(char *stringToRegister) 
00227 {
00228    int static index = 0;
00229    
00230    index++;
00231 
00232    openserSIPRegUserTable_context *theRow;
00233 
00234    oid  *OIDIndex;
00235    int  stringLength;
00236 
00237    theRow = SNMP_MALLOC_TYPEDEF(openserSIPRegUserTable_context);
00238 
00239    if (theRow == NULL) {
00240       LM_ERR("failed to create a row for openserSIPRegUserTable\n");
00241       return 0;
00242    }
00243 
00244    OIDIndex = pkg_malloc(sizeof(oid));
00245 
00246    if (OIDIndex == NULL) {
00247       free(theRow);
00248       LM_ERR("failed to create a row for openserSIPRegUserTable\n");
00249       return 0;
00250    }
00251 
00252    stringLength = strlen(stringToRegister);
00253 
00254    OIDIndex[0] = index;
00255 
00256    theRow->index.len  = 1;
00257    theRow->index.oids = OIDIndex;
00258    theRow->openserSIPUserIndex = index;
00259 
00260    theRow->openserSIPUserUri     = (unsigned char*)pkg_malloc(stringLength* sizeof(char));
00261     if(theRow->openserSIPUserUri== NULL)
00262     {
00263         pkg_free(OIDIndex);
00264       free(theRow);
00265       LM_ERR("failed to create a row for openserSIPRegUserTable\n");
00266       return 0;
00267 
00268     }
00269     memcpy(theRow->openserSIPUserUri, stringToRegister, stringLength);
00270    
00271     theRow->openserSIPUserUri_len = stringLength;
00272 
00273    theRow->openserSIPUserAuthenticationFailures = 0;
00274 
00275    CONTAINER_INSERT(cb.container, theRow);
00276 
00277    return index;
00278 }
00279 
00280 /* Initializes the openserSIPRegUserTable module.  */
00281 void init_openserSIPRegUserTable(void)
00282 {
00283    /* Register this table with the master agent */
00284    initialize_table_openserSIPRegUserTable();
00285 
00286    /* We need to create a default row, so create DefaultUser */
00287    static char *defaultUser = "DefaultUser";
00288    
00289    createRegUserRow(defaultUser);
00290 }
00291 
00292 
00293 
00294 /*
00295  * Initialize the openserSIPRegUserTable table by defining its contents and how
00296  * it's structured
00297  */
00298 void initialize_table_openserSIPRegUserTable(void)
00299 {
00300    netsnmp_table_registration_info *table_info;
00301 
00302    if(my_handler) {
00303       snmp_log(LOG_ERR, "initialize_table_openserSIPRegUserTable_hand"
00304             "ler called again\n");
00305       return;
00306    }
00307 
00308    memset(&cb, 0x00, sizeof(cb));
00309 
00310    /* create the table structure itself */
00311    table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
00312 
00313    my_handler = 
00314       netsnmp_create_handler_registration(
00315          "openserSIPRegUserTable",
00316          netsnmp_table_array_helper_handler, 
00317          openserSIPRegUserTable_oid,
00318          openserSIPRegUserTable_oid_len,
00319          HANDLER_CAN_RONLY);
00320 
00321    if (!my_handler || !table_info) {
00322       snmp_log(LOG_ERR, "malloc failed in initialize_table_openser"
00323             "SIPRegUserTable_handler\n");
00324       return; /** mallocs failed */
00325    }
00326 
00327    netsnmp_table_helper_add_index(table_info, ASN_UNSIGNED);
00328 
00329    table_info->min_column = openserSIPRegUserTable_COL_MIN;
00330    table_info->max_column = openserSIPRegUserTable_COL_MAX;
00331 
00332    cb.get_value = openserSIPRegUserTable_get_value;
00333    cb.container = netsnmp_container_find("openserSIPRegUserTable_primary:"
00334          "openserSIPRegUserTable:" "table_container");
00335 
00336    DEBUGMSGTL(("initialize_table_openserSIPRegUserTable",
00337             "Registering table openserSIPRegUserTable "
00338             "as a table array\n"));
00339 
00340    netsnmp_table_container_register(my_handler, table_info, &cb, 
00341          cb.container, 1);
00342 }
00343 
00344 
00345 /* Handles SNMP GET requests. */
00346 int openserSIPRegUserTable_get_value(
00347       netsnmp_request_info *request,
00348       netsnmp_index *item,
00349       netsnmp_table_request_info *table_info )
00350 {
00351    /* First things first, we need to consume the interprocess buffer, in
00352     * case something has changed. We want to return the freshest data. */
00353    consumeInterprocessBuffer();
00354 
00355    netsnmp_variable_list *var = request->requestvb;
00356 
00357    openserSIPRegUserTable_context *context = 
00358       (openserSIPRegUserTable_context *)item;
00359 
00360    switch(table_info->colnum) 
00361    {
00362 
00363       case COLUMN_OPENSERSIPUSERURI:
00364          /** SnmpAdminString = ASN_OCTET_STR */
00365          snmp_set_var_typed_value(var, ASN_OCTET_STR,
00366             (unsigned char*)context->openserSIPUserUri,
00367             context->openserSIPUserUri_len );
00368          break;
00369    
00370       case COLUMN_OPENSERSIPUSERAUTHENTICATIONFAILURES:
00371          /** COUNTER = ASN_COUNTER */
00372          snmp_set_var_typed_value(var, ASN_COUNTER,
00373             (unsigned char*)
00374             &context->openserSIPUserAuthenticationFailures,
00375             sizeof(
00376             context->openserSIPUserAuthenticationFailures));
00377       break;
00378    
00379       default: /** We shouldn't get here */
00380          snmp_log(LOG_ERR, "unknown column in "
00381             "openserSIPRegUserTable_get_value\n");
00382 
00383          return SNMP_ERR_GENERR;
00384    }
00385 
00386    return SNMP_ERR_NOERROR;
00387 }
00388 
00389 
00390 const openserSIPRegUserTable_context *
00391 openserSIPRegUserTable_get_by_idx(netsnmp_index * hdr)
00392 {
00393    return (const openserSIPRegUserTable_context *)
00394       CONTAINER_FIND(cb.container, hdr );
00395 }
00396 
00397 

Generated on Thu May 24 00:00:28 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6