dlist.c

Go to the documentation of this file.
00001 /*
00002  * $Id: dlist.c 5160 2008-11-03 17:51:22Z henningw $
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License 
00019  * along with this program; if not, write to the Free Software 
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  * History:
00023  * ========
00024  * 2005-07-11 get_all_ucontacts returns also the contact's flags (bogdan)
00025  * 2006-11-28 added get_number_of_users() (Jeffrey Magder - SOMA Networks)
00026  * 2007-09-12 added partitioning support for fetching all ul contacts
00027  *            (bogdan)
00028  */
00029 
00030 /*! \file
00031  *  \brief USRLOC - List of registered domains
00032  *  \ingroup usrloc
00033  *
00034  * - Module: \ref usrloc
00035  */
00036 
00037 
00038 #include "dlist.h"
00039 #include <stdlib.h>         /* abort */
00040 #include <string.h>            /* strlen, memcmp */
00041 #include <stdio.h>             /* printf */
00042 #include "../../ut.h"
00043 #include "../../db/db_ut.h"
00044 #include "../../mem/shm_mem.h"
00045 #include "../../dprint.h"
00046 #include "../../ip_addr.h"
00047 #include "../../socket_info.h"
00048 #include "udomain.h"           /* new_udomain, free_udomain */
00049 #include "utime.h"
00050 #include "ul_mod.h"
00051 
00052 
00053 /*! \brief Global list of all registered domains */
00054 dlist_t* root = 0;
00055 
00056 
00057 /*!
00058  * \brief Find domain with the given name
00059  * \param _n domain name
00060  * \param _d pointer to domain
00061  * \return 0 if the domain was found and 1 of not
00062  */
00063 static inline int find_dlist(str* _n, dlist_t** _d)
00064 {
00065    dlist_t* ptr;
00066 
00067    ptr = root;
00068    while(ptr) {
00069       if ((_n->len == ptr->name.len) &&
00070           !memcmp(_n->s, ptr->name.s, _n->len)) {
00071          *_d = ptr;
00072          return 0;
00073       }
00074       
00075       ptr = ptr->next;
00076    }
00077    
00078    return 1;
00079 }
00080 
00081 
00082 /*!
00083  * \brief Get all contacts from the database, in partitions if wanted
00084  * \see get_all_ucontacts
00085  * \param buf target buffer
00086  * \param len length of buffer
00087  * \param flags contact flags
00088  * \param part_idx part index
00089  * \param part_max maximal part
00090  * \return 0 on success, positive if buffer size was not sufficient, negative on failure
00091  */
00092 static inline int get_all_db_ucontacts(void *buf, int len, unsigned int flags,
00093                         unsigned int part_idx, unsigned int part_max)
00094 {
00095    static char query_buf[512];
00096    static str query_str;
00097 
00098    struct socket_info *sock;
00099    unsigned int dbflags;
00100    db_res_t* res = NULL;
00101    db_row_t *row;
00102    dlist_t *dom;
00103    char *p, *p1;
00104    char now_s[25];
00105    int now_len;
00106    int port, proto, p_len, p1_len;
00107    str host;
00108    int i;
00109    void *cp;
00110    int shortage, needed;
00111 
00112    cp = buf;
00113    shortage = 0;
00114    /* Reserve space for terminating 0000 */
00115    len -= sizeof(p_len);
00116 
00117    /* get the current time in DB format */
00118    now_len = 25;
00119    if (db_time2str( time(0), now_s, &now_len)!=0) {
00120       LM_ERR("failed to print now time\n");
00121       return -1;
00122    }
00123 
00124    for (dom = root; dom!=NULL ; dom=dom->next) {
00125       /* build query */
00126       i = snprintf( query_buf, sizeof(query_buf), "select %.*s, %.*s, %.*s,"
00127 #ifdef ORACLE_USRLOC
00128          " %.*s, %.*s from %s where %.*s > %.*s and "
00129          "bitand(%.*s, %d) = %d and mod(id, %u) = %u",
00130 #else
00131          " %.*s, %.*s from %s where %.*s > %.*s and %.*s & %d = %d and "
00132          "id %% %u = %u",
00133 #endif
00134          received_col.len, received_col.s,
00135          contact_col.len, contact_col.s,
00136          sock_col.len, sock_col.s,
00137          cflags_col.len, cflags_col.s,
00138          path_col.len, path_col.s,
00139          dom->d->name->s,
00140          expires_col.len, expires_col.s,
00141          now_len, now_s,
00142          cflags_col.len, cflags_col.s,
00143          flags, flags, part_max, part_idx);
00144       if ( i>=sizeof(query_buf) ) {
00145          LM_ERR("DB query too long\n");
00146          return -1;
00147       }
00148       query_str.s = query_buf;
00149       query_str.len = i;
00150       if ( ul_dbf.raw_query( ul_dbh, &query_str, &res)<0 ) {
00151          LM_ERR("raw_query failed\n");
00152          return -1;
00153       }
00154       if( RES_ROW_N(res)==0 ) {
00155          ul_dbf.free_result(ul_dbh, res);
00156          continue;
00157       }
00158 
00159       for(i = 0; i < RES_ROW_N(res); i++) {
00160          row = RES_ROWS(res) + i;
00161 
00162          /* received */
00163          p = (char*)VAL_STRING(ROW_VALUES(row));
00164          if ( VAL_NULL(ROW_VALUES(row)) || p==0 || p[0]==0 ) {
00165             /* contact */
00166             p = (char*)VAL_STRING(ROW_VALUES(row)+1);
00167             if (VAL_NULL(ROW_VALUES(row)+1) || p==0 || p[0]==0) {
00168                LM_ERR("empty contact -> skipping\n");
00169                continue;
00170             }
00171          }
00172          p_len = strlen(p);
00173 
00174          /* path */
00175          p1 = (char*)VAL_STRING(ROW_VALUES(row)+4);
00176          if (VAL_NULL(ROW_VALUES(row)+4) || p1==0 || p1[0]==0){
00177             p1 = NULL;
00178             p1_len = 0;
00179          } else {
00180             p1_len = strlen(p1);
00181          }
00182 
00183          needed = (int)(sizeof(p_len)+p_len+sizeof(sock)+sizeof(dbflags)+
00184             sizeof(p1_len)+p1_len);
00185          if (len < needed) {
00186             shortage += needed ;
00187             continue;
00188          }
00189 
00190          /* write received/contact */
00191          memcpy(cp, &p_len, sizeof(p_len));
00192          cp = (char*)cp + sizeof(p_len);
00193          memcpy(cp, p, p_len);
00194          cp = (char*)cp + p_len;
00195 
00196          /* sock */
00197          p  = (char*)VAL_STRING(ROW_VALUES(row) + 2);
00198          if (VAL_NULL(ROW_VALUES(row)+2) || p==0 || p[0]==0){
00199             sock = 0;
00200          } else {
00201             if (parse_phostport( p, strlen(p), &host.s, &host.len,
00202             &port, &proto)!=0) {
00203                LM_ERR("bad socket <%s>...ignoring\n", p);
00204                sock = 0;
00205             } else {
00206                sock = grep_sock_info( &host, (unsigned short)port, proto);
00207                if (sock==0) {
00208                   LM_WARN("non-local socket <%s>...ignoring\n", p);
00209                }
00210             }
00211          }
00212 
00213          /* flags */
00214          dbflags = VAL_BITMAP(ROW_VALUES(row) + 3);
00215 
00216          /* write sock and flags */
00217          memcpy(cp, &sock, sizeof(sock));
00218          cp = (char*)cp + sizeof(sock);
00219          memcpy(cp, &dbflags, sizeof(dbflags));
00220          cp = (char*)cp + sizeof(dbflags);
00221 
00222          /* write path */
00223          memcpy(cp, &p1_len, sizeof(p1_len));
00224          cp = (char*)cp + sizeof(p1_len);
00225          memcpy(cp, p1, p1_len);
00226          cp = (char*)cp + p1_len;
00227 
00228          len -= needed;
00229       } /* row cycle */
00230 
00231       ul_dbf.free_result(ul_dbh, res);
00232    } /* domain cycle */
00233 
00234    /* len < 0 is possible, if size of the buffer < sizeof(c->c.len) */
00235    if (len >= 0)
00236       memset(cp, 0, sizeof(p_len));
00237 
00238    /* Shouldn't happen */
00239    if (shortage > 0 && len > shortage) {
00240       abort();
00241    }
00242 
00243    shortage -= len;
00244 
00245    return shortage > 0 ? shortage : 0;
00246 }
00247 
00248 
00249 /*!
00250  * \brief Get all contacts from the memory, in partitions if wanted
00251  * \see get_all_ucontacts
00252  * \param buf target buffer
00253  * \param len length of buffer
00254  * \param flags contact flags
00255  * \param part_idx part index
00256  * \param part_max maximal part
00257  * \return 0 on success, positive if buffer size was not sufficient, negative on failure
00258  */
00259 static inline int get_all_mem_ucontacts(void *buf, int len, unsigned int flags,
00260                         unsigned int part_idx, unsigned int part_max)
00261 {
00262    dlist_t *p;
00263    urecord_t *r;
00264    ucontact_t *c;
00265    void *cp;
00266    int shortage;
00267    int needed;
00268    int i = 0;
00269    cp = buf;
00270    shortage = 0;
00271    /* Reserve space for terminating 0000 */
00272    len -= sizeof(c->c.len);
00273 
00274    for (p = root; p != NULL; p = p->next) {
00275 
00276       for(i=0; i<p->d->size; i++) {
00277 
00278          if ( (i % part_max) != part_idx )
00279             continue;
00280 
00281          lock_ulslot(p->d, i);
00282          if(p->d->table[i].n<=0)
00283          {
00284             unlock_ulslot(p->d, i);
00285             continue;
00286          }
00287          for (r = p->d->table[i].first; r != NULL; r = r->next) {
00288             for (c = r->contacts; c != NULL; c = c->next) {
00289                if (c->c.len <= 0)
00290                   continue;
00291                /*
00292                 * List only contacts that have all requested
00293                 * flags set
00294                 */
00295                if ((c->cflags & flags) != flags)
00296                   continue;
00297                if (c->received.s) {
00298                   needed = (int)(sizeof(c->received.len)
00299                         + c->received.len + sizeof(c->sock)
00300                         + sizeof(c->cflags) + sizeof(c->path.len)
00301                         + c->path.len);
00302                   if (len >= needed) {
00303                      memcpy(cp,&c->received.len,sizeof(c->received.len));
00304                      cp = (char*)cp + sizeof(c->received.len);
00305                      memcpy(cp, c->received.s, c->received.len);
00306                      cp = (char*)cp + c->received.len;
00307                      memcpy(cp, &c->sock, sizeof(c->sock));
00308                      cp = (char*)cp + sizeof(c->sock);
00309                      memcpy(cp, &c->cflags, sizeof(c->cflags));
00310                      cp = (char*)cp + sizeof(c->cflags);
00311                      memcpy(cp, &c->path.len, sizeof(c->path.len));
00312                      cp = (char*)cp + sizeof(c->path.len);
00313                      memcpy(cp, c->path.s, c->path.len);
00314                      cp = (char*)cp + c->path.len;
00315                      len -= needed;
00316                   } else {
00317                      shortage += needed;
00318                   }
00319                } else {
00320                   needed = (int)(sizeof(c->c.len) + c->c.len +
00321                      sizeof(c->sock) + sizeof(c->cflags) +
00322                      sizeof(c->path.len) + c->path.len);
00323                   if (len >= needed) {
00324                      memcpy(cp, &c->c.len, sizeof(c->c.len));
00325                      cp = (char*)cp + sizeof(c->c.len);
00326                      memcpy(cp, c->c.s, c->c.len);
00327                      cp = (char*)cp + c->c.len;
00328                      memcpy(cp, &c->sock, sizeof(c->sock));
00329                      cp = (char*)cp + sizeof(c->sock);
00330                      memcpy(cp, &c->cflags, sizeof(c->cflags));
00331                      cp = (char*)cp + sizeof(c->cflags);
00332                      memcpy(cp, &c->path.len, sizeof(c->path.len));
00333                      cp = (char*)cp + sizeof(c->path.len);
00334                      memcpy(cp, c->path.s, c->path.len);
00335                      cp = (char*)cp + c->path.len;
00336                      len -= needed;
00337                   } else {
00338                      shortage += needed;
00339                   }
00340                }
00341             }
00342          }
00343          unlock_ulslot(p->d, i);
00344       }
00345    }
00346    /* len < 0 is possible, if size of the buffer < sizeof(c->c.len) */
00347    if (len >= 0)
00348       memset(cp, 0, sizeof(c->c.len));
00349 
00350    /* Shouldn't happen */
00351    if (shortage > 0 && len > shortage) {
00352       abort();
00353    }
00354 
00355    shortage -= len;
00356 
00357    return shortage > 0 ? shortage : 0;
00358 }
00359 
00360 
00361 
00362 /*!
00363  * \brief Get all contacts from the usrloc, in partitions if wanted
00364  *
00365  * Return list of all contacts for all currently registered
00366  * users in all domains. The caller must provide buffer of
00367  * sufficient length for fitting all those contacts. In the
00368  * case when buffer was exhausted, the function returns
00369  * estimated amount of additional space needed, in this
00370  * case the caller is expected to repeat the call using
00371  * this value as the hint.
00372  *
00373  * Information is packed into the buffer as follows:
00374  *
00375  * +------------+----------+-----+------+-----+
00376  * |contact1.len|contact1.s|sock1|flags1|path1|
00377  * +------------+----------+-----+------+-----+
00378  * |contact2.len|contact2.s|sock2|flags2|path1|
00379  * +------------+----------+-----+------+-----+
00380  * |..........................................|
00381  * +------------+----------+-----+------+-----+
00382  * |contactN.len|contactN.s|sockN|flagsN|pathN|
00383  * +------------+----------+-----+------+-----+
00384  * |000000000000|
00385  * +------------+
00386  *
00387  * \param buf target buffer
00388  * \param len length of buffer
00389  * \param flags contact flags
00390  * \param part_idx part index
00391  * \param part_max maximal part
00392  * \return 0 on success, positive if buffer size was not sufficient, negative on failure
00393  */
00394 int get_all_ucontacts(void *buf, int len, unsigned int flags,
00395                         unsigned int part_idx, unsigned int part_max)
00396 {
00397    if (db_mode==DB_ONLY)
00398       return get_all_db_ucontacts( buf, len, flags, part_idx, part_max);
00399    else
00400       return get_all_mem_ucontacts( buf, len, flags, part_idx, part_max);
00401 }
00402 
00403 
00404 
00405 /*!
00406  * \brief Create a new domain structure
00407  * \return 0 if everything went OK, otherwise value < 0 is returned
00408  *
00409  * \note The structure is NOT created in shared memory so the
00410  * function must be called before the server forks if it should
00411  * be available to all processes
00412  */
00413 static inline int new_dlist(str* _n, dlist_t** _d)
00414 {
00415    dlist_t* ptr;
00416 
00417    /* Domains are created before ser forks,
00418     * so we can create them using pkg_malloc
00419     */
00420    ptr = (dlist_t*)shm_malloc(sizeof(dlist_t));
00421    if (ptr == 0) {
00422       LM_ERR("no more share memory\n");
00423       return -1;
00424    }
00425    memset(ptr, 0, sizeof(dlist_t));
00426 
00427    /* copy domain name as null terminated string */
00428    ptr->name.s = (char*)shm_malloc(_n->len+1);
00429    if (ptr->name.s == 0) {
00430       LM_ERR("no more memory left\n");
00431       shm_free(ptr);
00432       return -2;
00433    }
00434 
00435    memcpy(ptr->name.s, _n->s, _n->len);
00436    ptr->name.len = _n->len;
00437    ptr->name.s[ptr->name.len] = 0;
00438 
00439    if (new_udomain(&(ptr->name), ul_hash_size, &(ptr->d)) < 0) {
00440       LM_ERR("creating domain structure failed\n");
00441       shm_free(ptr->name.s);
00442       shm_free(ptr);
00443       return -3;
00444    }
00445 
00446    *_d = ptr;
00447    return 0;
00448 }
00449 
00450 
00451 /*!
00452  * \brief Registers a new domain with usrloc
00453  *
00454  * Registers a new domain with usrloc. If the domain exists,
00455  * a pointer to existing structure will be returned, otherwise
00456  * a new domain will be created
00457  * \param _n domain name
00458  * \param _d new created domain
00459  * \return 0 on success, -1 on failure
00460  */
00461 int register_udomain(const char* _n, udomain_t** _d)
00462 {
00463    dlist_t* d;
00464    str s;
00465    db_con_t* con;
00466 
00467    s.s = (char*)_n;
00468    s.len = strlen(_n);
00469 
00470    if (find_dlist(&s, &d) == 0) {
00471       *_d = d->d;
00472       return 0;
00473    }
00474    
00475    if (new_dlist(&s, &d) < 0) {
00476       LM_ERR("failed to create new domain\n");
00477       return -1;
00478    }
00479 
00480    /* Test tables from database if we are gonna
00481     * to use database
00482     */
00483    if (db_mode != NO_DB) {
00484       con = ul_dbf.init(&db_url);
00485       if (!con) {
00486          LM_ERR("failed to open database connection\n");
00487          goto err;
00488       }
00489 
00490       if(db_check_table_version(&ul_dbf, con, &s, UL_TABLE_VERSION) < 0) {
00491          LM_ERR("error during table version check.\n");
00492          goto err;
00493       }
00494       /* test if DB really exists */
00495       if (testdb_udomain(con, d->d) < 0) {
00496          LM_ERR("testing domain '%.*s' failed\n", s.len, ZSW(s.s));
00497          goto err;
00498       }
00499 
00500       ul_dbf.close(con);
00501    }
00502 
00503    d->next = root;
00504    root = d;
00505    
00506    *_d = d->d;
00507    return 0;
00508 
00509 err:
00510    if (con) ul_dbf.close(con);
00511    free_udomain(d->d);
00512    shm_free(d->name.s);
00513    shm_free(d);
00514    return -1;
00515 }
00516 
00517 
00518 /*!
00519  * \brief Free all allocated memory for domains
00520  */
00521 void free_all_udomains(void)
00522 {
00523    dlist_t* ptr;
00524 
00525    while(root) {
00526       ptr = root;
00527       root = root->next;
00528 
00529       free_udomain(ptr->d);
00530       shm_free(ptr->name.s);
00531       shm_free(ptr);
00532    }
00533 }
00534 
00535 
00536 /*!
00537  * \brief Print all domains, just for debugging
00538  * \param _f output file
00539  */
00540 void print_all_udomains(FILE* _f)
00541 {
00542    dlist_t* ptr;
00543    
00544    ptr = root;
00545 
00546    fprintf(_f, "===Domain list===\n");
00547    while(ptr) {
00548       print_udomain(_f, ptr->d);
00549       ptr = ptr->next;
00550    }
00551    fprintf(_f, "===/Domain list===\n");
00552 }
00553 
00554 
00555 /*!
00556  * \brief Loops through all domains summing up the number of users
00557  * \return the number of users, could be zero
00558  */
00559 unsigned long get_number_of_users(void)
00560 {
00561    int numberOfUsers = 0;
00562 
00563    dlist_t* current_dlist;
00564    
00565    current_dlist = root;
00566 
00567    while (current_dlist)
00568    {
00569       numberOfUsers += get_stat_val(current_dlist->d->users); 
00570       current_dlist  = current_dlist->next;
00571    }
00572 
00573    return numberOfUsers;
00574 }
00575 
00576 
00577 /*!
00578  * \brief Run timer handler of all domains
00579  * \return 0 if all timer return 0, != 0 otherwise
00580  */
00581 int synchronize_all_udomains(void)
00582 {
00583    int res = 0;
00584    dlist_t* ptr;
00585 
00586    get_act_time(); /* Get and save actual time */
00587 
00588    if (db_mode==DB_ONLY) {
00589       for( ptr=root ; ptr ; ptr=ptr->next)
00590          res |= db_timer_udomain(ptr->d);
00591    } else {
00592       for( ptr=root ; ptr ; ptr=ptr->next)
00593          mem_timer_udomain(ptr->d);
00594    }
00595 
00596    return res;
00597 }
00598 
00599 
00600 /*!
00601  * \brief Find a particular domain, small wrapper around find_dlist
00602  * \param _d domain name
00603  * \param _p pointer to domain if found
00604  * \return 1 if domain was found, 0 otherwise
00605  */
00606 int find_domain(str* _d, udomain_t** _p)
00607 {
00608    dlist_t* d;
00609 
00610    if (find_dlist(_d, &d) == 0) {
00611            *_p = d->d;
00612       return 0;
00613    }
00614 
00615    return 1;
00616 }

Generated on Tue May 22 16:00:27 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6