modules_k/usrloc/dlist.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
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 
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 "../../lib/srdb1/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 "usrloc.h"
00050 #include "utime.h"
00051 #include "ul_mod.h"
00052 
00053 
00055 dlist_t* root = 0;
00056 
00057 
00064 static inline int find_dlist(str* _n, dlist_t** _d)
00065 {
00066         dlist_t* ptr;
00067 
00068         ptr = root;
00069         while(ptr) {
00070                 if ((_n->len == ptr->name.len) &&
00071                     !memcmp(_n->s, ptr->name.s, _n->len)) {
00072                         *_d = ptr;
00073                         return 0;
00074                 }
00075                 
00076                 ptr = ptr->next;
00077         }
00078         
00079         return 1;
00080 }
00081 
00082 
00093 static inline int get_all_db_ucontacts(void *buf, int len, unsigned int flags,
00094                                                                 unsigned int part_idx, unsigned int part_max)
00095 {
00096         static char query_buf[512];
00097         static str query_str;
00098 
00099         struct socket_info *sock;
00100         unsigned int dbflags;
00101         db1_res_t* res = NULL;
00102         db_row_t *row;
00103         dlist_t *dom;
00104         char *p, *p1;
00105         char now_s[25];
00106         int now_len;
00107         int port, proto, p_len, p1_len;
00108         str host;
00109         int i;
00110         void *cp;
00111         int shortage, needed;
00112 
00113         cp = buf;
00114         shortage = 0;
00115         /* Reserve space for terminating 0000 */
00116         len -= sizeof(p_len);
00117 
00118         /* get the current time in DB format */
00119         now_len = 25;
00120         if (db_time2str( time(0), now_s, &now_len)!=0) {
00121                 LM_ERR("failed to print now time\n");
00122                 return -1;
00123         }
00124 
00125         for (dom = root; dom!=NULL ; dom=dom->next) {
00126                 /* build query */
00127                 i = snprintf( query_buf, sizeof(query_buf), "select %.*s, %.*s, %.*s,"
00128 #ifdef ORACLE_USRLOC
00129                         " %.*s, %.*s from %s where %.*s > %.*s and "
00130                         "bitand(%.*s, %d) = %d and mod(id, %u) = %u",
00131 #else
00132                         " %.*s, %.*s from %s where %.*s > %.*s and %.*s & %d = %d and "
00133                         "id %% %u = %u",
00134 #endif
00135                         received_col.len, received_col.s,
00136                         contact_col.len, contact_col.s,
00137                         sock_col.len, sock_col.s,
00138                         cflags_col.len, cflags_col.s,
00139                         path_col.len, path_col.s,
00140                         dom->d->name->s,
00141                         expires_col.len, expires_col.s,
00142                         now_len, now_s,
00143                         cflags_col.len, cflags_col.s,
00144                         flags, flags, part_max, part_idx);
00145                 if ( i>=sizeof(query_buf) ) {
00146                         LM_ERR("DB query too long\n");
00147                         return -1;
00148                 }
00149                 query_str.s = query_buf;
00150                 query_str.len = i;
00151                 if ( ul_dbf.raw_query( ul_dbh, &query_str, &res)<0 ) {
00152                         LM_ERR("raw_query failed\n");
00153                         return -1;
00154                 }
00155                 if( RES_ROW_N(res)==0 ) {
00156                         ul_dbf.free_result(ul_dbh, res);
00157                         continue;
00158                 }
00159 
00160                 for(i = 0; i < RES_ROW_N(res); i++) {
00161                         row = RES_ROWS(res) + i;
00162 
00163                         /* received */
00164                         p = (char*)VAL_STRING(ROW_VALUES(row));
00165                         if ( VAL_NULL(ROW_VALUES(row)) || p==0 || p[0]==0 ) {
00166                                 /* contact */
00167                                 p = (char*)VAL_STRING(ROW_VALUES(row)+1);
00168                                 if (VAL_NULL(ROW_VALUES(row)+1) || p==0 || p[0]==0) {
00169                                         LM_ERR("empty contact -> skipping\n");
00170                                         continue;
00171                                 }
00172                         }
00173                         p_len = strlen(p);
00174 
00175                         /* path */
00176                         p1 = (char*)VAL_STRING(ROW_VALUES(row)+4);
00177                         if (VAL_NULL(ROW_VALUES(row)+4) || p1==0 || p1[0]==0){
00178                                 p1 = NULL;
00179                                 p1_len = 0;
00180                         } else {
00181                                 p1_len = strlen(p1);
00182                         }
00183 
00184                         needed = (int)(sizeof(p_len)+p_len+sizeof(sock)+sizeof(dbflags)+
00185                                 sizeof(p1_len)+p1_len);
00186                         if (len < needed) {
00187                                 shortage += needed ;
00188                                 continue;
00189                         }
00190 
00191                         /* write received/contact */
00192                         memcpy(cp, &p_len, sizeof(p_len));
00193                         cp = (char*)cp + sizeof(p_len);
00194                         memcpy(cp, p, p_len);
00195                         cp = (char*)cp + p_len;
00196 
00197                         /* sock */
00198                         p  = (char*)VAL_STRING(ROW_VALUES(row) + 2);
00199                         if (VAL_NULL(ROW_VALUES(row)+2) || p==0 || p[0]==0){
00200                                 sock = 0;
00201                         } else {
00202                                 if (parse_phostport( p, &host.s, &host.len,
00203                                 &port, &proto)!=0) {
00204                                         LM_ERR("bad socket <%s>...ignoring\n", p);
00205                                         sock = 0;
00206                                 } else {
00207                                         sock = grep_sock_info( &host, (unsigned short)port, proto);
00208                                         if (sock==0) {
00209                                                 LM_WARN("non-local socket <%s>...ignoring\n", p);
00210                                         }
00211                                 }
00212                         }
00213 
00214                         /* flags */
00215                         dbflags = VAL_BITMAP(ROW_VALUES(row) + 3);
00216 
00217                         /* write sock and flags */
00218                         memcpy(cp, &sock, sizeof(sock));
00219                         cp = (char*)cp + sizeof(sock);
00220                         memcpy(cp, &dbflags, sizeof(dbflags));
00221                         cp = (char*)cp + sizeof(dbflags);
00222 
00223                         /* write path */
00224                         memcpy(cp, &p1_len, sizeof(p1_len));
00225                         cp = (char*)cp + sizeof(p1_len);
00226                         /* copy path only if exist */
00227                         if(p1_len){
00228                                 memcpy(cp, p1, p1_len);
00229                                 cp = (char*)cp + p1_len;
00230                         }
00231 
00232                         len -= needed;
00233                 } /* row cycle */
00234 
00235                 ul_dbf.free_result(ul_dbh, res);
00236         } /* domain cycle */
00237 
00238         /* len < 0 is possible, if size of the buffer < sizeof(c->c.len) */
00239         if (len >= 0)
00240                 memset(cp, 0, sizeof(p_len));
00241 
00242         /* Shouldn't happen */
00243         if (shortage > 0 && len > shortage) {
00244                 abort();
00245         }
00246 
00247         shortage -= len;
00248 
00249         return shortage > 0 ? shortage : 0;
00250 }
00251 
00252 
00263 static inline int get_all_mem_ucontacts(void *buf, int len, unsigned int flags,
00264                                                                 unsigned int part_idx, unsigned int part_max)
00265 {
00266         dlist_t *p;
00267         urecord_t *r;
00268         ucontact_t *c;
00269         void *cp;
00270         int shortage;
00271         int needed;
00272         int i = 0;
00273         cp = buf;
00274         shortage = 0;
00275         /* Reserve space for terminating 0000 */
00276         len -= sizeof(c->c.len);
00277 
00278         for (p = root; p != NULL; p = p->next) {
00279 
00280                 for(i=0; i<p->d->size; i++) {
00281 
00282                         if ( (i % part_max) != part_idx )
00283                                 continue;
00284 
00285                         lock_ulslot(p->d, i);
00286                         if(p->d->table[i].n<=0)
00287                         {
00288                                 unlock_ulslot(p->d, i);
00289                                 continue;
00290                         }
00291                         for (r = p->d->table[i].first; r != NULL; r = r->next) {
00292                                 for (c = r->contacts; c != NULL; c = c->next) {
00293                                         if (c->c.len <= 0)
00294                                                 continue;
00295                                         /*
00296                                          * List only contacts that have all requested
00297                                          * flags set
00298                                          */
00299                                         if ((c->cflags & flags) != flags)
00300                                                 continue;
00301                                         if (c->received.s) {
00302                                                 needed = (int)(sizeof(c->received.len)
00303                                                                 + c->received.len + sizeof(c->sock)
00304                                                                 + sizeof(c->cflags) + sizeof(c->path.len)
00305                                                                 + c->path.len);
00306                                                 if (len >= needed) {
00307                                                         memcpy(cp,&c->received.len,sizeof(c->received.len));
00308                                                         cp = (char*)cp + sizeof(c->received.len);
00309                                                         memcpy(cp, c->received.s, c->received.len);
00310                                                         cp = (char*)cp + c->received.len;
00311                                                         memcpy(cp, &c->sock, sizeof(c->sock));
00312                                                         cp = (char*)cp + sizeof(c->sock);
00313                                                         memcpy(cp, &c->cflags, sizeof(c->cflags));
00314                                                         cp = (char*)cp + sizeof(c->cflags);
00315                                                         memcpy(cp, &c->path.len, sizeof(c->path.len));
00316                                                         cp = (char*)cp + sizeof(c->path.len);
00317                                                         memcpy(cp, c->path.s, c->path.len);
00318                                                         cp = (char*)cp + c->path.len;
00319                                                         len -= needed;
00320                                                 } else {
00321                                                         shortage += needed;
00322                                                 }
00323                                         } else {
00324                                                 needed = (int)(sizeof(c->c.len) + c->c.len +
00325                                                         sizeof(c->sock) + sizeof(c->cflags) +
00326                                                         sizeof(c->path.len) + c->path.len);
00327                                                 if (len >= needed) {
00328                                                         memcpy(cp, &c->c.len, sizeof(c->c.len));
00329                                                         cp = (char*)cp + sizeof(c->c.len);
00330                                                         memcpy(cp, c->c.s, c->c.len);
00331                                                         cp = (char*)cp + c->c.len;
00332                                                         memcpy(cp, &c->sock, sizeof(c->sock));
00333                                                         cp = (char*)cp + sizeof(c->sock);
00334                                                         memcpy(cp, &c->cflags, sizeof(c->cflags));
00335                                                         cp = (char*)cp + sizeof(c->cflags);
00336                                                         memcpy(cp, &c->path.len, sizeof(c->path.len));
00337                                                         cp = (char*)cp + sizeof(c->path.len);
00338                                                         memcpy(cp, c->path.s, c->path.len);
00339                                                         cp = (char*)cp + c->path.len;
00340                                                         len -= needed;
00341                                                 } else {
00342                                                         shortage += needed;
00343                                                 }
00344                                         }
00345                                 }
00346                         }
00347                         unlock_ulslot(p->d, i);
00348                 }
00349         }
00350         /* len < 0 is possible, if size of the buffer < sizeof(c->c.len) */
00351         if (len >= 0)
00352                 memset(cp, 0, sizeof(c->c.len));
00353 
00354         /* Shouldn't happen */
00355         if (shortage > 0 && len > shortage) {
00356                 abort();
00357         }
00358 
00359         shortage -= len;
00360 
00361         return shortage > 0 ? shortage : 0;
00362 }
00363 
00364 
00365 
00398 int get_all_ucontacts(void *buf, int len, unsigned int flags,
00399                                                                 unsigned int part_idx, unsigned int part_max)
00400 {
00401         if (db_mode==DB_ONLY)
00402                 return get_all_db_ucontacts( buf, len, flags, part_idx, part_max);
00403         else
00404                 return get_all_mem_ucontacts( buf, len, flags, part_idx, part_max);
00405 }
00406 
00407 
00408 
00417 static inline int new_dlist(str* _n, dlist_t** _d)
00418 {
00419         dlist_t* ptr;
00420 
00421         /* Domains are created before ser forks,
00422          * so we can create them using pkg_malloc
00423          */
00424         ptr = (dlist_t*)shm_malloc(sizeof(dlist_t));
00425         if (ptr == 0) {
00426                 LM_ERR("no more share memory\n");
00427                 return -1;
00428         }
00429         memset(ptr, 0, sizeof(dlist_t));
00430 
00431         /* copy domain name as null terminated string */
00432         ptr->name.s = (char*)shm_malloc(_n->len+1);
00433         if (ptr->name.s == 0) {
00434                 LM_ERR("no more memory left\n");
00435                 shm_free(ptr);
00436                 return -2;
00437         }
00438 
00439         memcpy(ptr->name.s, _n->s, _n->len);
00440         ptr->name.len = _n->len;
00441         ptr->name.s[ptr->name.len] = 0;
00442 
00443         if (new_udomain(&(ptr->name), ul_hash_size, &(ptr->d)) < 0) {
00444                 LM_ERR("creating domain structure failed\n");
00445                 shm_free(ptr->name.s);
00446                 shm_free(ptr);
00447                 return -3;
00448         }
00449 
00450         *_d = ptr;
00451         return 0;
00452 }
00453 
00462 int get_udomain(const char* _n, udomain_t** _d)
00463 {
00464         dlist_t* d;
00465         str s;
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         *_d = NULL;
00475         return -1;
00476 }
00477 
00488 int register_udomain(const char* _n, udomain_t** _d)
00489 {
00490         dlist_t* d;
00491         str s;
00492         db1_con_t* con;
00493 
00494         s.s = (char*)_n;
00495         s.len = strlen(_n);
00496 
00497         if (find_dlist(&s, &d) == 0) {
00498                 *_d = d->d;
00499                 return 0;
00500         }
00501         
00502         if (new_dlist(&s, &d) < 0) {
00503                 LM_ERR("failed to create new domain\n");
00504                 return -1;
00505         }
00506 
00507         /* Test tables from database if we are gonna
00508          * to use database
00509          */
00510         if (db_mode != NO_DB) {
00511                 con = ul_dbf.init(&db_url);
00512                 if (!con) {
00513                         LM_ERR("failed to open database connection\n");
00514                         goto err;
00515                 }
00516 
00517                 if(db_check_table_version(&ul_dbf, con, &s, UL_TABLE_VERSION) < 0) {
00518                         LM_ERR("error during table version check.\n");
00519                         goto err;
00520                 }
00521                 /* test if DB really exists */
00522                 if (testdb_udomain(con, d->d) < 0) {
00523                         LM_ERR("testing domain '%.*s' failed\n", s.len, ZSW(s.s));
00524                         goto err;
00525                 }
00526 
00527                 ul_dbf.close(con);
00528         }
00529 
00530         d->next = root;
00531         root = d;
00532         
00533         *_d = d->d;
00534         return 0;
00535 
00536 err:
00537         if (con) ul_dbf.close(con);
00538         free_udomain(d->d);
00539         shm_free(d->name.s);
00540         shm_free(d);
00541         return -1;
00542 }
00543 
00544 
00548 void free_all_udomains(void)
00549 {
00550         dlist_t* ptr;
00551 
00552         while(root) {
00553                 ptr = root;
00554                 root = root->next;
00555 
00556                 free_udomain(ptr->d);
00557                 shm_free(ptr->name.s);
00558                 shm_free(ptr);
00559         }
00560 }
00561 
00562 
00567 void print_all_udomains(FILE* _f)
00568 {
00569         dlist_t* ptr;
00570         
00571         ptr = root;
00572 
00573         fprintf(_f, "===Domain list===\n");
00574         while(ptr) {
00575                 print_udomain(_f, ptr->d);
00576                 ptr = ptr->next;
00577         }
00578         fprintf(_f, "===/Domain list===\n");
00579 }
00580 
00581 
00586 unsigned long get_number_of_users(void)
00587 {
00588         long numberOfUsers = 0;
00589 
00590         dlist_t* current_dlist;
00591         
00592         current_dlist = root;
00593 
00594         while (current_dlist)
00595         {
00596                 numberOfUsers += get_stat_val(current_dlist->d->users); 
00597                 current_dlist  = current_dlist->next;
00598         }
00599 
00600         return numberOfUsers;
00601 }
00602 
00603 
00608 int synchronize_all_udomains(int istart, int istep)
00609 {
00610         int res = 0;
00611         dlist_t* ptr;
00612 
00613         get_act_time(); /* Get and save actual time */
00614 
00615         if (db_mode==DB_ONLY) {
00616                 for( ptr=root ; ptr ; ptr=ptr->next)
00617                         res |= db_timer_udomain(ptr->d);
00618         } else {
00619                 for( ptr=root ; ptr ; ptr=ptr->next)
00620                         mem_timer_udomain(ptr->d, istart, istep);
00621         }
00622 
00623         return res;
00624 }
00625 
00626 
00633 int find_domain(str* _d, udomain_t** _p)
00634 {
00635         dlist_t* d;
00636 
00637         if (find_dlist(_d, &d) == 0) {
00638                 *_p = d->d;
00639                 return 0;
00640         }
00641 
00642         return 1;
00643 }