openserSIPContactTable.c

Go to the documentation of this file.
00001 /*
00002  * $Id: openserSIPContactTable.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 contains the implementation of the openserSIPContact Table.  For a
00033  * full description of this structure, please see the OPENSER-SIP-SERVER-MIB.
00034  *
00035  * Some important notes on implementation follow:
00036  *
00037  * We require OpenSERs usrloc module to inform us when a contact is
00038  * added/removed.  The general callback process works as follows:
00039  *
00040  * 1) On startup, we register handleContactCallbacks() for USRLOC callbacks, so 
00041  *    we can be informed whenever a contact is added/removed from the system.  
00042  *    This registration happens with a call to registerForUSRLOCCallbacks().  
00043  *    (This is actually called when the SNMPStats module is initialized)
00044  *
00045  * 2) Whenever we receive a contact callback, handleContactCallbacks() will 
00046  *    quickly add the contact information and operation type to the
00047  *    interprocess buffer.  
00048  *
00049  * 3) When we receive an SNMP request for user/contact information, we consume
00050  *    the interprocess buffer with consumeInterprocessBuffer().  The function
00051  *    will add/delete rows to the tables, and then service the SNMP request.
00052  *
00053  * Notes: 
00054  *
00055  * - The interprocess buffer was necessary, because NetSNMP's containers can be
00056  *   very inefficient at adding large amounts of data at a time, such as when
00057  *   OpenSER first starts up.  It was decided its better to make an SNMP manager
00058  *   wait for data, instead of slowing down the rest of OpenSER while the
00059  *   sub-agent processes the data. 
00060  *
00061  * - It is important to send periodic SNMP requests to this table (or the user
00062  *   table), to make sure the process buffer doesn't get too large.  
00063  *
00064  */
00065 
00066 #include <net-snmp/net-snmp-config.h>
00067 #include <net-snmp/net-snmp-includes.h>
00068 #include <net-snmp/agent/net-snmp-agent-includes.h>
00069 
00070 #include <net-snmp/library/snmp_assert.h>
00071 
00072 #include "hashTable.h"
00073 #include "interprocess_buffer.h"
00074 #include "utilities.h"
00075 #include "openserSIPContactTable.h"
00076 #include "snmpstats_globals.h"
00077 
00078 #include "../../mem/mem.h"
00079 #include "../../str.h"
00080 #include "../../sr_module.h"
00081 #include "../../locking.h"
00082 #include "../usrloc/usrloc.h"
00083 #include "../usrloc/ucontact.h"
00084 
00085 
00086 static netsnmp_handler_registration *my_handler = NULL;
00087 static netsnmp_table_array_callbacks cb;
00088 
00089 oid openserSIPContactTable_oid[]      = { openserSIPContactTable_TABLE_OID };
00090 size_t openserSIPContactTable_oid_len = OID_LENGTH(openserSIPContactTable_oid);
00091 
00092 /* 
00093  * This function adds a new contactToIndexStruct_t record to the front of
00094  * 'contactRecord'.  
00095  *
00096  * The structure is used to map a contact name to the SNMPStats modules integer
00097  * indexing scheme.  It will be used later when a delete command comes in, and
00098  * we need to find out which SNMP row the information is stored under.
00099  */
00100 int insertContactRecord(
00101       contactToIndexStruct_t **contactRecord, int index, char *name) 
00102 {
00103     int nameLength =strlen(name);
00104    
00105     contactToIndexStruct_t *newContactRecord = (contactToIndexStruct_t *)
00106         pkg_malloc(sizeof(contactToIndexStruct_t) +(nameLength+1)* sizeof(char));
00107 
00108    if (newContactRecord == NULL)
00109    {
00110         LM_ERR("no more pkg memory\n");
00111       return 0;
00112    }
00113 
00114    newContactRecord->next         = *contactRecord;
00115    newContactRecord->contactName  = (char*)newContactRecord + sizeof(contactToIndexStruct_t);
00116     memcpy(newContactRecord->contactName, name, nameLength);
00117     newContactRecord->contactName[nameLength]= '\0';
00118    newContactRecord->contactIndex = index;
00119 
00120    *contactRecord = newContactRecord;
00121 
00122    return 1;
00123 }
00124 
00125 
00126 /*
00127  * This function will remove the contactToIndexStruct_T record matching
00128  * 'contactName' from the users contactToIndexStruct_t linked-list, and return
00129  * the records index.  In the event that the record could not be found, 0 will
00130  * be returned. 
00131  */
00132 int deleteContactRecord(contactToIndexStruct_t **contactRecord,char *contactName)
00133 {
00134    int contactIndexToReturn;
00135    contactToIndexStruct_t *currentContact  = *contactRecord;
00136    contactToIndexStruct_t *previousContact = *contactRecord;
00137 
00138    while (currentContact != NULL) {
00139 
00140       if (strcmp(currentContact->contactName, contactName) == 0) 
00141       {
00142          /* This means that this is the first element.  Link up
00143           * the pointer to the next element */
00144          if (currentContact == previousContact) {
00145             *contactRecord = currentContact->next;
00146          } else {
00147             previousContact->next = currentContact->next;
00148          }
00149 
00150          contactIndexToReturn = currentContact->contactIndex;
00151             pkg_free(currentContact);
00152          return contactIndexToReturn;
00153       }
00154 
00155       previousContact = currentContact;
00156       currentContact  = currentContact->next;
00157 
00158    }
00159 
00160    return 0;
00161 }
00162 
00163 
00164 /* 
00165  * Creates an SNMP row and inserts it into the contact table. This function
00166  * should only be called when the interprocess buffer is being consumed.
00167  *
00168  * Returns: 1 on success, and 0 otherwise. 
00169  */
00170 int createContactRow(int userIndex, int contactIndex, char *contactName, 
00171       ucontact_t *contactInfo)  
00172 {
00173    openserSIPContactTable_context *theRow;
00174 
00175    oid  *OIDIndex;
00176    int  stringLength;
00177 
00178    theRow = SNMP_MALLOC_TYPEDEF(openserSIPContactTable_context);
00179 
00180    if (theRow == NULL) {
00181       LM_ERR("failed to create a row for openserSIPContactTable\n");
00182       return 0;
00183    }
00184 
00185    /* We need enough memory for both the user index and contact index. */
00186    OIDIndex = pkg_malloc(sizeof(oid)*2);
00187 
00188    if (OIDIndex == NULL) {
00189       free(theRow);
00190       LM_ERR("failed to create a row for openserSIPContactTable\n");
00191       return 0;
00192    }
00193 
00194    stringLength = strlen(contactName);
00195 
00196    /* Generate the Rows Index */
00197    OIDIndex[0] = userIndex;
00198    OIDIndex[1] = contactIndex;
00199 
00200    theRow->index.len  = 2;
00201    theRow->index.oids = OIDIndex;
00202    theRow->openserSIPContactIndex = contactIndex;
00203 
00204    /* Fill in the rest of the rows columns */
00205    theRow->openserSIPContactURI = (unsigned char*)
00206         pkg_malloc((stringLength+ 1)* sizeof(char));
00207     if(theRow->openserSIPContactURI == NULL)
00208     {
00209         pkg_free(OIDIndex);
00210       free(theRow);
00211       LM_ERR("failed to allocate memory for contact name\n");
00212       return 0;
00213     }
00214     memcpy(theRow->openserSIPContactURI, contactName, stringLength);
00215     theRow->openserSIPContactURI[stringLength] = '\0';
00216 
00217     theRow->openserSIPContactURI_len = stringLength;
00218    theRow->contactInfo = contactInfo;
00219 
00220    CONTAINER_INSERT(cb.container, theRow);
00221 
00222    return 1;
00223 }
00224 
00225 
00226 /* 
00227  * Removes the row indexed by userIndex and contactIndex, and free's up the
00228  * memory allocated to it.  If the row could not be found, then nothing is done.
00229  */
00230 void deleteContactRow(int userIndex, int contactIndex) 
00231 {
00232    openserSIPContactTable_context *theRow;
00233 
00234    netsnmp_index indexToRemove;
00235    oid indexToRemoveOID[2];
00236 
00237    /* Form the OID Index of the row so we can search for it */
00238    indexToRemoveOID[0] = userIndex;
00239    indexToRemoveOID[1] = contactIndex;
00240    indexToRemove.oids  = indexToRemoveOID;
00241    indexToRemove.len   = 2;
00242 
00243    theRow = CONTAINER_FIND(cb.container, &indexToRemove);
00244 
00245    /* The ContactURI is shared memory, the index.oids was allocated from
00246     * pkg_malloc(), and theRow was made with the NetSNMP API which uses
00247     * malloc() */
00248    if (theRow != NULL) {
00249       CONTAINER_REMOVE(cb.container, &indexToRemove);
00250       pkg_free(theRow->openserSIPContactURI);
00251       pkg_free(theRow->index.oids);
00252       free(theRow);
00253    } 
00254 }
00255 
00256 /*
00257  * Initializes the openserSIPContactTable module.  This involves:
00258  *
00259  *  1) Registering the tables OID with the master agent
00260  *
00261  *  2) Creating a default row, so that there is a row to query to trigger the
00262  *     consumption of the interprocess buffer.
00263  */
00264 void init_openserSIPContactTable(void)
00265 {
00266    initialize_table_openserSIPContactTable();
00267 
00268    static char *defaultUser = "DefaultUser";
00269 
00270    createContactRow(1, 1, defaultUser, NULL);
00271 }
00272 
00273 
00274 
00275 /*
00276  * Initialize the openserSIPContactTable table by defining its contents and how
00277  * it's structured.
00278  *
00279  * This function is mostly auto-generated.
00280  */
00281 void initialize_table_openserSIPContactTable(void)
00282 {
00283    netsnmp_table_registration_info *table_info;
00284 
00285    if(my_handler) {
00286       snmp_log(LOG_ERR, "initialize_table_openserSIPContactTable_"
00287             "handler called again\n");
00288       return;
00289    }
00290 
00291    memset(&cb, 0x00, sizeof(cb));
00292 
00293    /** create the table structure itself */
00294    table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
00295 
00296    my_handler = netsnmp_create_handler_registration(
00297          "openserSIPContactTable",
00298          netsnmp_table_array_helper_handler,
00299          openserSIPContactTable_oid,
00300          openserSIPContactTable_oid_len,
00301          HANDLER_CAN_RONLY);
00302          
00303    if (!my_handler || !table_info) {
00304       snmp_log(LOG_ERR, "malloc failed in initialize_table_openser"
00305             "SIPContactTable_handler\n");
00306       return; /** mallocs failed */
00307    }
00308 
00309    /** index: openserSIPUserIndex */
00310    netsnmp_table_helper_add_index(table_info, ASN_UNSIGNED);
00311    /** index: openserSIPContactIndex */
00312    netsnmp_table_helper_add_index(table_info, ASN_UNSIGNED);
00313 
00314    table_info->min_column = openserSIPContactTable_COL_MIN;
00315    table_info->max_column = openserSIPContactTable_COL_MAX;
00316 
00317    /***************************************************
00318     * registering the table with the master agent
00319     */
00320    cb.get_value = openserSIPContactTable_get_value;
00321    cb.container = netsnmp_container_find("openserSIPContactTable_primary:"
00322          "openserSIPContactTable:" "table_container");
00323    
00324    DEBUGMSGTL(("initialize_table_openserSIPContactTable",
00325             "Registering table openserSIPContactTable "
00326             "as a table array\n"));
00327    
00328    netsnmp_table_container_register(my_handler, table_info, &cb, 
00329          cb.container, 1);
00330 }
00331 
00332 
00333 /*
00334  * This routine is called to process get requests for elements of the table.
00335  *
00336  * The function differs from its original auto-generated form in that the row
00337  * itself doesn't store all the data that is needed.  Some of the values
00338  * (openserSIPContactURI, openserSIPContactExpiry, openserSIPContactPreference)
00339  * may have changed since the row was first created.  Therefore, this data is
00340  * retrieved when it is requested for.
00341  */
00342 int openserSIPContactTable_get_value(
00343          netsnmp_request_info *request,
00344          netsnmp_index *item,
00345          netsnmp_table_request_info *table_info )
00346 {
00347    static char defaultExpiry[8]      = {0, 0, 0, 0, 0, 0, 0, 0};
00348 
00349    /* Needs to be large enough to hold the null terminated string "-0.01".
00350     */
00351    char  contactPreference[6];   
00352    float preferenceAsFloat     = -1;
00353 
00354    char       *retrievedExpiry;
00355    struct tm  *timeValue;
00356 
00357    /* First things first, we need to consume the interprocess buffer, in
00358     * case something has changed. We want to return the freshest data. */
00359    consumeInterprocessBuffer();
00360 
00361    netsnmp_variable_list *var = request->requestvb;
00362 
00363    openserSIPContactTable_context *context = 
00364       (openserSIPContactTable_context *)item;
00365 
00366    switch(table_info->colnum) 
00367    {
00368 
00369       case COLUMN_OPENSERSIPCONTACTDISPLAYNAME:
00370 
00371          /* FIXME: WHERE DO WE FIND THIS??  Setting to the same
00372           * thing as contact uri for now. */
00373          snmp_set_var_typed_value(var, ASN_OCTET_STR, 
00374                (unsigned char*)
00375                context->openserSIPContactURI,
00376                context->openserSIPContactURI_len);
00377          break;
00378 
00379       case COLUMN_OPENSERSIPCONTACTURI:
00380 
00381          snmp_set_var_typed_value(var, ASN_OCTET_STR,
00382                 (unsigned char*)
00383                 context->openserSIPContactURI,
00384                 context->openserSIPContactURI_len);
00385          break;
00386    
00387       case COLUMN_OPENSERSIPCONTACTLASTUPDATED:
00388       
00389          if (context->contactInfo != NULL) 
00390          {
00391             timeValue = 
00392                localtime(&(context->contactInfo->last_modified));
00393             retrievedExpiry  = 
00394                convertTMToSNMPDateAndTime(timeValue);
00395          } else {
00396             retrievedExpiry = defaultExpiry;
00397          }
00398 
00399          snmp_set_var_typed_value(var, ASN_OCTET_STR,
00400                 (unsigned char*)
00401                 retrievedExpiry,
00402                 8);
00403          break;
00404    
00405       case COLUMN_OPENSERSIPCONTACTEXPIRY:
00406 
00407          if (context->contactInfo != NULL) 
00408          {
00409             timeValue = 
00410                localtime(&(context->contactInfo->expires));
00411 
00412             retrievedExpiry  = 
00413                convertTMToSNMPDateAndTime(timeValue);
00414          } else {
00415             retrievedExpiry = defaultExpiry;
00416          }
00417          snmp_set_var_typed_value(var, ASN_OCTET_STR,
00418                 (unsigned char*)
00419                 retrievedExpiry,
00420                 8);
00421          break;
00422    
00423       case COLUMN_OPENSERSIPCONTACTPREFERENCE:
00424 
00425          if (context->contactInfo != NULL) {
00426             preferenceAsFloat = context->contactInfo->q;
00427          }
00428 
00429          /* OpenSER stores the q-value as an integer for speed
00430           * purposes.  We need to convert this value to a float
00431           * to conform to the MIB and RFC specifications of the q
00432           * value. */
00433          preferenceAsFloat /= 100.0;
00434 
00435          /* Convert the float into a string, as specified by the
00436           * MIB. */
00437          sprintf(contactPreference, "%5.2f", preferenceAsFloat);
00438 
00439          snmp_set_var_typed_value(var, ASN_OCTET_STR,
00440                 (unsigned char*)
00441                 contactPreference,
00442                 5);
00443          break;
00444    
00445       default: /** We shouldn't get here */
00446          snmp_log(LOG_ERR, "unknown column in "
00447                 "openserSIPContactTable_get_value\n");
00448          return SNMP_ERR_GENERR;
00449    }
00450 
00451    return SNMP_ERR_NOERROR;
00452 }
00453 
00454 /* 
00455  * openserSIPContactTable_get_by_idx is an auto-generated function. 
00456  */
00457 const openserSIPContactTable_context *
00458 openserSIPContactTable_get_by_idx(netsnmp_index * hdr)
00459 {
00460    return (const openserSIPContactTable_context *)
00461       CONTAINER_FIND(cb.container, hdr );
00462 }
00463 
00464 

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