ds_backend.c

00001 
00031 #include <stdio.h>
00032 #include <string.h>
00033 #include <stdlib.h>
00034 
00035 #include "../../trim.h"
00036 #include "../../dprint.h"
00037 #include "../../mem/mem.h"
00038 #include "../../mem/shm_mem.h"
00039 #include "../../parser/parse_uri.h"
00040 #include "../../parser/parse_from.h"
00041 #include "../../dset.h"
00042 
00043 #include "dispatcher.h"
00044 
00045 /******************************************************************************
00046  *
00047  * ds_destroy_lists()
00048  *
00049  * free all memory occupied by dispatcher module
00050  *
00051  *****************************************************************************/
00052  
00053 int ds_destroy_lists()
00054 {
00055         extern int *ds_activelist;      
00056         extern char ***ds_setp_a, ***ds_setp_b;
00057         extern int *ds_setlen_a, *ds_setlen_b;
00058         int set, node;
00059 
00060         /* assume the whole structure has been allocated if ds_activelist
00061          * is non-NULL
00062          * hint: when using ser -c memory wasn't allocated
00063          */
00064         if (ds_activelist == NULL)
00065                 return 0;
00066 
00067         /* free sets and nodes */
00068         for (set = 0; set < DS_MAX_SETS; set++) {
00069                 for (node = 0; node < DS_MAX_NODES; node++) {
00070                         shm_free(ds_setp_a[set][node]);
00071                         shm_free(ds_setp_b[set][node]);
00072                 }
00073                 shm_free(ds_setp_a[set]);
00074                 shm_free(ds_setp_b[set]);
00075         }
00076         /* free counters */
00077         shm_free(ds_setlen_a);
00078         shm_free(ds_setlen_b);
00079 
00080         /* eventually, free ds_activelist */
00081         shm_free(ds_activelist);
00082 
00083         return 0;
00084 }
00085 
00086 /******************************************************************************
00087  *
00088  * ds_get_hash()
00089  *
00090  * obtain hash from given strings
00091  *
00092  *****************************************************************************/
00093 
00094 unsigned int ds_get_hash(str *x, str *y)
00095 {
00096         char* p;
00097         register unsigned v;
00098         register unsigned h;
00099 
00100         if(!x && !y)
00101                 return 0;
00102         h=0;
00103         if(x)
00104         {
00105                 p=x->s;
00106                 if (x->len>=4){
00107                         for (;p<=(x->s+x->len-4); p+=4){
00108                                 v=(*p<<24)+(p[1]<<16)+(p[2]<<8)+p[3];
00109                                 h+=v^(v>>3);
00110                         }
00111                 };
00112                 v=0;
00113                 for (;p<(x->s+x->len); p++)
00114                 { 
00115                         v<<=8; 
00116                         v+=*p;
00117                 }
00118                 h+=v^(v>>3);
00119         }
00120         if(y)
00121         {
00122                 p=y->s;
00123                 if (y->len>=4){
00124                         for (;p<=(y->s+y->len-4); p+=4){
00125                                 v=(*p<<24)+(p[1]<<16)+(p[2]<<8)+p[3];
00126                                 h+=v^(v>>3);
00127                         }
00128                 };
00129                 v=0;
00130                 for (;p<(y->s+y->len); p++)
00131                 { 
00132                         v<<=8; 
00133                         v+=*p;
00134                 }
00135                 h+=v^(v>>3);
00136         }
00137         h=((h)+(h>>11))+((h>>13)+(h>>23));
00138 
00139         return (h)?h:1;
00140 }
00141 
00142 
00143 /*
00144  * gets the part of the uri we will use as a key for hashing
00145  * params:  key1       - will be filled with first part of the key
00146  *                       (uri user or "" if no user)
00147  *          key2       - will be filled with the second part of the key
00148  *                       (uri host:port)
00149  *          uri        - str with the whole uri
00150  *          parsed_uri - struct sip_uri pointer with the parsed uri
00151  *                       (it must point inside uri). It can be null
00152  *                       (in this case the uri will be parsed internally).
00153  *          flags  -    if & DS_HASH_USER_ONLY, only the user part of the uri
00154  *                      will be used
00155  * returns: -1 on error, 0 on success
00156  */
00157 static inline int get_uri_hash_keys(str* key1, str* key2,
00158                                                         str* uri, struct sip_uri* parsed_uri, int flags)
00159 {
00160         struct sip_uri tmp_p_uri; /* used only if parsed_uri==0 */
00161         
00162         if (parsed_uri==0){
00163                 if (parse_uri(uri->s, uri->len, &tmp_p_uri)<0){
00164                         LOG(L_ERR, "DISPATCHER: get_uri_hash_keys: invalid uri %.*s\n",
00165                                         uri->len, uri->len?uri->s:"");
00166                         goto error;
00167                 }
00168                 parsed_uri=&tmp_p_uri;
00169         }
00170         /* uri sanity checks */
00171         if (parsed_uri->host.s==0){
00172                         LOG(L_ERR, "DISPATCHER: get_uri_hash_keys: invalid uri, no host"
00173                                            "present: %.*s\n", uri->len, uri->len?uri->s:"");
00174                         goto error;
00175         }
00176         
00177         /* we want: user@host:port if port !=5060
00178          *          user@host if port==5060
00179          *          user if the user flag is set*/
00180         *key1=parsed_uri->user;
00181         key2->s=0;
00182         key2->len=0;
00183         if ((!(flags & (DS_HASH_USER_ONLY | DS_HASH_USER_OR_HOST))) ||
00184                 ((key1->s==0) && (flags & DS_HASH_USER_OR_HOST))){
00185                 /* key2=host */
00186                 *key2=parsed_uri->host;
00187                 /* add port if needed */
00188                 if (parsed_uri->port.s!=0){ /* uri has a port */
00189                         /* skip port if == 5060 or sips and == 5061 */
00190                         if (parsed_uri->port_no !=
00191                                         ((parsed_uri->type==SIPS_URI_T)?SIPS_PORT:SIP_PORT))
00192                                 key2->len+=parsed_uri->port.len+1 /* ':' */;
00193                 }
00194         }
00195         if (key1->s==0 && (flags & DS_HASH_USER_ONLY)){
00196                 LOG(L_WARN, "DISPATCHER: get_uri_hash_keys: empty username in:"
00197                                         " %.*s\n", uri->len, uri->len?uri->s:"");
00198         }
00199         return 0;
00200 error:
00201         return -1;
00202 }
00203 
00204 
00205 
00209 int ds_hash_fromuri(struct sip_msg *msg, unsigned int *hash)
00210 {
00211         str from;
00212         str key1;
00213         str key2;
00214         
00215         if(msg==NULL || hash == NULL)
00216         {
00217                 LOG(L_ERR, "DISPATCHER:ds_hash_fromuri: bad parameters\n");
00218                 return -1;
00219         }
00220         
00221         if(parse_from_header(msg)==-1)
00222         {
00223                 LOG(L_ERR, "DISPATCHER:ds_hash_fromuri:ERROR cannot parse From hdr\n");
00224                 return -1;
00225         }
00226         
00227         if(msg->from==NULL || get_from(msg)==NULL)
00228         {
00229                 LOG(L_ERR, "DISPATCHER:ds_hash_fromuri:ERROR cannot get From uri\n");
00230                 return -1;
00231         }
00232         
00233         from   = get_from(msg)->uri;
00234         trim(&from);
00235         if (get_uri_hash_keys(&key1, &key2, &from, 0, ds_flags)<0)
00236                 return -1;
00237         *hash = ds_get_hash(&key1, &key2);
00238         
00239         return 0;
00240 }
00241 
00242 
00243 
00247 int ds_hash_touri(struct sip_msg *msg, unsigned int *hash)
00248 {
00249         str to;
00250         str key1;
00251         str key2;
00252         
00253         if(msg==NULL || hash == NULL)
00254         {
00255                 LOG(L_ERR, "DISPATCHER:ds_hash_touri: bad parameters\n");
00256                 return -1;
00257         }
00258         if ((msg->to==0) && ((parse_headers(msg, HDR_TO_F, 0)==-1) ||
00259                                 (msg->to==0)))
00260         {
00261                 LOG(L_ERR, "DISPATCHER:ds_hash_touri:ERROR cannot parse To hdr\n");
00262                 return -1;
00263         }
00264         
00265         
00266         to   = get_to(msg)->uri;
00267         trim(&to);
00268         
00269         if (get_uri_hash_keys(&key1, &key2, &to, 0, ds_flags)<0)
00270                 return -1;
00271         *hash = ds_get_hash(&key1, &key2);
00272         
00273         return 0;
00274 }
00275 
00276 
00277 
00281 int ds_hash_callid(struct sip_msg *msg, unsigned int *hash)
00282 {
00283         str cid;
00284         if(msg==NULL || hash == NULL)
00285         {
00286                 LOG(L_ERR, "DISPATCHER:ds_hash_callid: bad parameters\n");
00287                 return -1;
00288         }
00289         
00290         if(msg->callid==NULL && ((parse_headers(msg, HDR_CALLID_F, 0)==-1) ||
00291                                 (msg->callid==NULL)) )
00292         {
00293                 LOG(L_ERR, "DISPATCHER:ds_hash_callid:ERROR cannot parse Call-Id\n");
00294                 return -1;
00295         }
00296         
00297         cid.s   = msg->callid->body.s;
00298         cid.len = msg->callid->body.len;
00299         trim(&cid);
00300         
00301         *hash = ds_get_hash(&cid, NULL);
00302         
00303         return 0;
00304 }
00305 
00306 
00307 
00308 int ds_hash_ruri(struct sip_msg *msg, unsigned int *hash)
00309 {
00310         str* uri;
00311         str key1;
00312         str key2;
00313         
00314         
00315         if(msg==NULL || hash == NULL)
00316         {
00317                 LOG(L_ERR, "DISPATCHER:ds_hash_ruri: bad parameters\n");
00318                 return -1;
00319         }
00320         if (parse_sip_msg_uri(msg)<0){
00321                 LOG(L_ERR, "DISPATCHER: ds_hash_ruri: ERROR: bad request uri\n");
00322                 return -1;
00323         }
00324         
00325         uri=GET_RURI(msg);
00326         if (get_uri_hash_keys(&key1, &key2, uri, &msg->parsed_uri, ds_flags)<0)
00327                 return -1;
00328         
00329         *hash = ds_get_hash(&key1, &key2);
00330         return 0;
00331 }
00332 
00333 /* from dispatcher */
00334 static int set_new_uri_simple(struct sip_msg *msg, str *uri)
00335 {
00336         if (msg->new_uri.s)
00337         {
00338                 pkg_free(msg->new_uri.s);
00339                 msg->new_uri.len=0;
00340         }
00341 
00342         msg->parsed_uri_ok=0;
00343         msg->new_uri.s = (char*)pkg_malloc(uri->len+1);
00344         if (msg->new_uri.s==0)
00345         {
00346                 ERR("no more pkg memory\n");
00347                 return -1;
00348         }
00349         memcpy(msg->new_uri.s, uri->s, uri->len);
00350         msg->new_uri.s[uri->len]=0;
00351         msg->new_uri.len=uri->len;
00352         ruri_mark_new();
00353         return 0;
00354 }
00355 
00356 /* from dispatcher */
00357 static int set_new_uri_with_user(struct sip_msg *msg, str *uri, str *user)
00358 {
00359         struct sip_uri dst;
00360         int start_len, stop_len;
00361         
00362         if (parse_uri(uri->s, uri->len, &dst) < 0) {
00363                 ERR("can't parse destination URI\n");
00364                 return -1;
00365         }
00366         if ((!dst.host.s) || (dst.host.len <= 0)) {
00367                 ERR("destination URI host not set\n");
00368                 return -1;
00369         }
00370         if (dst.user.s && (dst.user.len > 0)) {
00371                 DBG("user already exists\n");
00372                 /* don't replace the user */
00373                 return set_new_uri_simple(msg, uri);
00374         }
00375         
00376         if (msg->new_uri.s)
00377         {
00378                 pkg_free(msg->new_uri.s);
00379                 msg->new_uri.len=0;
00380         }
00381         
00382         start_len = dst.host.s - uri->s;
00383         stop_len = uri->len - start_len;
00384         
00385         msg->parsed_uri_ok=0;
00386         msg->new_uri.s = (char*)pkg_malloc(uri->len+1+user->len+1);
00387         if (msg->new_uri.s==0)
00388         {
00389                 ERR("no more pkg memory\n");
00390                 return -1;
00391         }
00392         memcpy(msg->new_uri.s, uri->s, start_len);
00393         memcpy(msg->new_uri.s + start_len, user->s, user->len);
00394         *(msg->new_uri.s + start_len + user->len) = '@';
00395         memcpy(msg->new_uri.s + start_len + user->len + 1, dst.host.s, stop_len);
00396         
00397         msg->new_uri.len=uri->len + user->len + 1;
00398         msg->new_uri.s[msg->new_uri.len]=0;
00399         ruri_mark_new();
00400         
00401         return 0;
00402 }
00403 
00404 static int set_new_uri(struct sip_msg *msg, str *uri)
00405 {
00406         struct to_body* to;
00407         struct sip_uri to_uri;
00408         
00409         /* we need to leave original user */
00410         to = get_to(msg);
00411         if (to) {
00412                 if (parse_uri(to->uri.s, to->uri.len, &to_uri) >= 0) {
00413                         if (to_uri.user.s && (to_uri.user.len > 0)) {
00414                                 return set_new_uri_with_user(msg, uri, &to_uri.user);
00415                         }
00416                 }
00417         }
00418 
00419         return set_new_uri_simple(msg, uri);
00420 }
00421 
00422 
00423 /******************************************************************************
00424  *
00425  * ds_select_dst_impl()
00426  *
00427  * use requested algorithm to calculate hash and pull an URI off the
00428  * active dispatcher list.
00429  * set dst_uri or new_uri accordingly
00430  * Attention: if specific hash algorithms fail the module falls back
00431  *            to a hash on the Call-ID
00432  *
00433  *****************************************************************************/
00434 
00435 int ds_select_dst_impl(struct sip_msg *msg, char *set_, char *alg_, int set_new)
00436 {
00437         extern int *ds_activelist;
00438         extern char ***ds_setp_a, ***ds_setp_b;
00439         extern int *ds_setlen_a, *ds_setlen_b;
00440 
00441         int set, alg;
00442         unsigned int hash;
00443 
00444         str uri;
00445 
00446         if(msg==NULL)
00447     {
00448         LOG(L_ERR, "DISPATCHER:ds_select_dst: bad parameters\n");
00449         return -1;
00450     }
00451 
00452         if ( get_int_fparam(&set, msg, (fparam_t*)set_) < 0 ) {
00453           LOG(L_ERR, "DISPATCHER:ds_select_dst: bad set value (%d)\n", set);
00454           return -1;
00455         }
00456 
00457         if ( get_int_fparam(&alg, msg, (fparam_t*)alg_) < 0 ) {
00458           LOG(L_ERR, "DISPATCHER:ds_select_dst: bad algorithm (%d)\n", alg);
00459           return -1;
00460         }
00461 
00462     if ((set < 0) || (set >= DS_MAX_SETS)) {
00463         LOG(L_ERR, "DISPATCHER:ds_select_dst: bad set offset (%d)\n", set);
00464         return -1;
00465     }
00466     if ((alg < 0) || (alg > 4)) {
00467         LOG(L_ERR, "DISPATCHER:ds_select_dst: invalid algorithm\n");
00468         return -1;
00469     }
00470 
00471         if (((*ds_activelist == 0) ?  ds_setlen_a[set] : ds_setlen_b[set]) <= 0) {
00472         LOG(L_ERR, "DISPATCHER:ds_select_dst: empty destination set\n");
00473         return -1;
00474     }
00475     if (msg->dst_uri.s != NULL || msg->dst_uri.len > 0) {
00476                 if (msg->dst_uri.s)
00477             pkg_free(msg->dst_uri.s);
00478         msg->dst_uri.s = NULL;
00479         msg->dst_uri.len = 0;
00480     }
00481     /* get hash */
00482     hash = 0;
00483     switch (alg) {
00484                 /* see bottom for case '0' */
00485         case 1: /* hash from uri */
00486             if (ds_hash_fromuri(msg, &hash) != 0) {
00487                 if (ds_hash_callid(msg, &hash) != 0) {
00488                     LOG(L_ERR, "DISPATCHER:ds_select_dst: cannot determine from uri hash\n");
00489                     return -1;
00490                 }
00491             }
00492             break;
00493         case 2: /* hash to uri */
00494             if (ds_hash_touri(msg, &hash) != 0) {
00495                 if (ds_hash_callid(msg, &hash) != 0) {
00496                     LOG(L_ERR, "DISPATCHER:ds_select_dst: cannot determine from uri hash\n");
00497                     return -1;
00498                 }
00499             }
00500             break;
00501         case 3: /* hash Request uri */
00502             if (ds_hash_ruri(msg, &hash) != 0) {
00503                 if (ds_hash_callid(msg, &hash) != 0) {
00504                     LOG(L_ERR, "DISPATCHER:ds_select_dst: cannot determine from uri hash\n");
00505                     return -1;
00506                 }
00507             }
00508             break;
00509                 case 4: /* Call ID hash, shifted right once to skip low bit
00510                                  * This should allow for even distribution when using
00511                                  * Call ID hash twice (i.e. fe + be)
00512                                  */
00513             if (ds_hash_callid(msg, &hash) != 0) {
00514                 LOG(L_ERR,
00515                     "DISPATCHER:ds_select_dst: cannot determine callid hash\n");
00516                 hash = 0; /* bad default, just to be sure */
00517                 return -1;
00518             }
00519                         hash = hash >> 4; /* should be enough for even more backends */
00520                         break;
00521         case 0: /* hash call id */ /* fall-through */
00522         default:
00523             if (ds_hash_callid(msg, &hash) != 0) {
00524                 LOG(L_ERR,
00525                     "DISPATCHER:ds_select_dst: cannot determine callid hash\n");
00526                 hash = 0; /* bad default, just to be sure */
00527                 return -1;
00528             }
00529                         break; /* make gcc happy */
00530     }
00531 
00532     DBG("DISPATCHER:ds_select_dst: hash: [%u]\n", hash);
00533     /* node list offset from hash */
00534     if (*ds_activelist == 0) {
00535         hash = hash % ds_setlen_a[set];
00536         uri.s = ds_setp_a[set][hash];
00537         uri.len = strlen(ds_setp_a[set][hash]);
00538     } else {
00539         hash = hash % ds_setlen_b[set];
00540         uri.s = ds_setp_b[set][hash];
00541         uri.len = strlen(ds_setp_b[set][hash]);
00542     }
00543 
00544         if (!set_new) {
00545                 if (set_dst_uri(msg, &uri) < 0) {
00546             LOG(L_ERR,
00547                                 "DISPATCHER:dst_select_dst: Error while setting dst_uri\n");
00548             return -1;
00549         }
00550                 /* dst_uri changed, so it makes sense to re-use the current uri for
00551                         forking */
00552                 ruri_mark_new(); /* re-use uri for serial forking */
00553         DBG("DISPATCHER:ds_select_dst: selected [%d-%d-%d] <%.*s>\n",
00554                 alg, set, hash, msg->dst_uri.len, msg->dst_uri.s);
00555         } else {
00556                 if (set_new_uri(msg, &uri) < 0) {
00557             LOG(L_ERR,
00558                                 "DISPATCHER:dst_select_dst: Error while setting new_uri\n");
00559             return -1;
00560         }
00561         DBG("DISPATCHER:ds_select_dst: selected [%d-%d-%d] <%.*s>\n",
00562                 alg, set, hash, msg->new_uri.len, msg->dst_uri.s);
00563     }
00564 
00565     return 1;
00566 }
00567 
00571 int ds_select_dst(struct sip_msg *msg, char *set, char *alg)
00572 {
00573         return ds_select_dst_impl(msg, set, alg, 0);
00574 }
00575 
00579 int ds_select_new(struct sip_msg *msg, char *set, char *alg)
00580 {
00581         return ds_select_dst_impl(msg, set, alg, 1);
00582 }
00583 
00584 
00585 
00586 /******************************************************************************
00587  *
00588  * ds_init_memory()
00589  *
00590  * init memory structure
00591  *
00592  * - ds_activelist: active list (0 or 1)
00593  * - ds_setp_a/ds_setp_b: each active config has up to DS_MAX_SETS so
00594  *   called sets. Each set references to a node list with DS_MAX_NODES
00595  *   slots that hold SIP URIs up to DS_MAX_URILEN-1 Bytes
00596  *
00597  *****************************************************************************/
00598 
00599 #define MALLOC_ERR  LOG(L_ERR, \
00600         "ERROR:DISPATCHER:init_dispatcher_mem: shm_malloc() failed\n");
00601 int ds_init_memory() {
00602 
00603     extern int *ds_activelist;
00604     extern char ***ds_setp_a, ***ds_setp_b;
00605     extern int *ds_setlen_a, *ds_setlen_b;
00606 
00607     int set, node;
00608 
00609     /* active list */
00610     ds_activelist = (int *) shm_malloc(sizeof(int));
00611     if (ds_activelist == NULL) {
00612         MALLOC_ERR;
00613         return -1;
00614     }
00615     *ds_activelist = 0;
00616 
00617     ds_setp_a = (char ***) shm_malloc(sizeof(char **) * DS_MAX_SETS);
00618     if (ds_setp_a == NULL) {
00619         MALLOC_ERR;
00620         return -1;
00621     }
00622     /* attach node list to each set */
00623     for (set = 0; set < DS_MAX_SETS; set++) {
00624         ds_setp_a[set] = (char **) shm_malloc(sizeof(char *) * DS_MAX_NODES);
00625         if (ds_setp_a[set] == NULL) {
00626             MALLOC_ERR;
00627             return -1;
00628         }
00629         /* init each node */
00630         for (node = 0; node < DS_MAX_NODES; node++) {
00631             ds_setp_a[set][node] = (char *)
00632                     shm_malloc(sizeof(char) * DS_MAX_URILEN);
00633             if (ds_setp_a[set][node] == NULL) {
00634                 MALLOC_ERR;
00635                 return -1;
00636             }
00637             *ds_setp_a[set][node] = '\0';
00638         }
00639     }
00640 
00641     ds_setp_b = (char ***) shm_malloc(sizeof(char **) * DS_MAX_SETS);
00642     if (ds_setp_b == NULL) {
00643         MALLOC_ERR;
00644         return -1;
00645     }
00646     /* attach node list to each set */
00647     for (set = 0; set < DS_MAX_SETS; set++) {
00648         ds_setp_b[set] = (char **) shm_malloc(sizeof(char *) * DS_MAX_NODES);
00649         if (ds_setp_b[set] == NULL) {
00650             MALLOC_ERR;
00651             return -1;
00652         }
00653         /* init each node */
00654         for (node = 0; node < DS_MAX_NODES; node++) {
00655             ds_setp_b[set][node] = (char *)
00656                     shm_malloc(sizeof(char) * DS_MAX_URILEN);
00657             if (ds_setp_b[set][node] == NULL) {
00658                 MALLOC_ERR;
00659                 return -1;
00660             }
00661             *ds_setp_b[set][node] = '\0';
00662         }
00663     }
00664 
00665     /* set length counters */
00666     ds_setlen_a = (int *) shm_malloc(sizeof(int) * DS_MAX_SETS);
00667     if (ds_setlen_a == NULL) {
00668         MALLOC_ERR;
00669         return -1;
00670     }
00671     ds_setlen_b = (int *) shm_malloc(sizeof(int) * DS_MAX_SETS);
00672     if (ds_setlen_b == NULL) {
00673         MALLOC_ERR;
00674         return -1;
00675     }
00676     for (set = 0; set < DS_MAX_SETS; set++) {
00677         ds_setlen_a[set] = 0;
00678         ds_setlen_b[set] = 0;
00679     }
00680     return 0;
00681 }
00682 
00683 /******************************************************************************
00684  *
00685  * ds_clean_list()
00686  *
00687  * empty the in-active config so we can reload a new one
00688  * this does not free() memory!
00689  *
00690  *****************************************************************************/
00691 
00692 void ds_clean_list(void) {
00693 
00694     extern int *ds_activelist;
00695     extern char ***ds_setp_a, ***ds_setp_b;
00696     extern int *ds_setlen_a, *ds_setlen_b;
00697 
00698     int set, node;
00699 
00700     for (set = 0; set < DS_MAX_SETS; set++) {
00701         for (node = 0; node < DS_MAX_NODES; node++) {
00702             if (*ds_activelist == 0) {
00703                 *ds_setp_b[set][node] = '\0';
00704             } else {
00705                 *ds_setp_a[set][node] = '\0';
00706             }
00707         }
00708         if (*ds_activelist == 0) {
00709             ds_setlen_b[set] = 0;
00710         } else {
00711             ds_setlen_a[set] = 0;
00712         }
00713     }
00714     return;
00715 }
00716 
00717 /******************************************************************************
00718  *
00719  * ds_load_list()
00720  *
00721  * (re)load dispatcher module config file using the dispatcher module
00722  * parser.
00723  * Save config in the in-active shared memory section
00724  * Attention: We do not bail out with an error if we try to store more
00725  *            sets/nodes than we have room for since we might be running
00726  *            live and don't want SER to stop processing packets, do we?
00727  *
00728  *****************************************************************************/
00729 
00730 int ds_load_list (char *lfile) {
00731 
00732     /* storage */
00733     extern int *ds_activelist;
00734     extern char ***ds_setp_a, ***ds_setp_b;
00735     extern int *ds_setlen_a, *ds_setlen_b;
00736 
00737     /* parser related */
00738     char line[MAX_LINE_LEN], *p;
00739     int set;
00740     str uri;
00741     struct sip_uri puri;
00742     FILE *f = NULL;
00743 
00744     DBG("ds_load_list() invoked\n");
00745 
00746     /* clean up temporary list before saving updated config */
00747     (void) ds_clean_list();
00748 
00749     if (lfile == NULL || strlen(lfile) <= 0) {
00750         LOG(L_ERR, "DISPATCHER:ds_load_list: cannot open list file [%s]\n",
00751             lfile);
00752         return -1;
00753     }
00754 
00755     f = fopen(lfile, "r");
00756     if (f == NULL) {
00757         LOG(L_ERR, "DISPATCHER:ds_load_list: cannot open list file [%s]\n",
00758             lfile);
00759         return -1;
00760     }
00761 
00762     p = fgets(line, MAX_LINE_LEN-1, f);
00763     while (p)
00764     {
00765         /* eat all white spaces */
00766         while (*p && (*p==' ' || *p=='\t' || *p=='\r' || *p=='\n'))
00767             p++;
00768         if (*p=='\0' || *p=='#')
00769             goto next_line;
00770 
00771         /* get set id */
00772         set = 0;
00773         while(*p>='0' && *p<='9')
00774         {
00775             set = set*10+ (*p-'0');
00776             p++;
00777         }
00778 
00779         /* eat all white spaces */
00780         while(*p && (*p==' ' || *p=='\t' || *p=='\r' || *p=='\n'))
00781             p++;
00782         if(*p=='\0' || *p=='#')
00783         {
00784             LOG(L_ERR, "DISPATCHER:ds_load_list: bad line [%s]\n", line);
00785             goto error;
00786         }
00787         /* get uri */
00788         uri.s = p;
00789         while(*p && *p!=' ' && *p!='\t' && *p!='\r' && *p!='\n' && *p!='#')
00790             p++;
00791         uri.len = p-uri.s;
00792 
00793         /* check uri */
00794         if(parse_uri(uri.s, uri.len, &puri)!=0)
00795         {
00796             LOG(L_ERR, "DISPATCHER:ds_load_list: bad uri [%.*s]\n",
00797                     uri.len, uri.s);
00798             goto next_line;
00799         }
00800 
00801         /* now we have set id and get uri -> save to shared mem */
00802         if ((set > DS_MAX_SETS-1) || (uri.len > DS_MAX_URILEN))
00803         {
00804             LOG(L_ERR, "DISPATCHER:ds_load_list: increase DS_MAX_SETS or DS_MAX_URILEN ...\n");
00805             goto next_line;
00806         }
00807         /* save correct line from config file */
00808         DBG("content: set %d, str: %.*s\n", set, uri.len, uri.s);
00809 
00810         if (*ds_activelist == 0) {
00811             DBG("[%d] active nodes in this set so far: %d\n",
00812                 *ds_activelist, ds_setlen_b[set]);
00813             if (ds_setlen_b[set] >= (DS_MAX_NODES-1)) {
00814                 LOG(L_ERR, "DISPATCHER:ds_load_list: increase DS_MAX_NODES!\n");
00815                 goto next_line;
00816             }
00817             snprintf((char *)ds_setp_b[set][ds_setlen_b[set]], DS_MAX_URILEN-1,
00818                     "%.*s", uri.len, uri.s);
00819             ds_setlen_b[set]++;
00820             DBG("[%d] active nodes in this set now: %d\n",
00821                 *ds_activelist, ds_setlen_b[set]);
00822             DBG("node now contains: %s\n", (char *)ds_setp_b[set][ds_setlen_b[set]-1]);
00823         } else {
00824             DBG("[%d] active nodes in this set so far: %d\n",
00825                 *ds_activelist, ds_setlen_a[set]);
00826             if (ds_setlen_a[set] >= (DS_MAX_NODES-1)) {
00827                 LOG(L_ERR, "DISPATCHER:ds_load_list: increase DS_MAX_NODES!\n");
00828                 goto next_line;
00829             }
00830             snprintf((char *)ds_setp_a[set][ds_setlen_a[set]], DS_MAX_URILEN-1,
00831                     "%.*s", uri.len, uri.s);
00832             ds_setlen_a[set]++;
00833             DBG("[%d] active nodes in this set now: %d\n",
00834                 *ds_activelist, ds_setlen_a[set]);
00835             DBG("node now contains: %s\n", (char *)ds_setp_a[set][ds_setlen_a[set]-1]);
00836         }
00837 
00838 next_line:
00839         p = fgets(line, MAX_LINE_LEN-1, f);
00840     }
00841     if (f != NULL)
00842         fclose(f);
00843     /* see if there are any active sets at all */
00844     if (*ds_activelist == 0) {
00845         int found = 0;
00846         int i;
00847         for (i = 0; i < DS_MAX_SETS; i++) {
00848             if (ds_setlen_b[i] > 0)
00849                 found++;
00850         }
00851         if (!found)
00852             return -1;
00853     } else {
00854         int found = 0;
00855         int i;
00856         for (i = 0; i < DS_MAX_SETS; i++) {
00857             if (ds_setlen_a[i] > 0)
00858                 found++;
00859         }
00860         if (!found)
00861             return -1;
00862 
00863     }
00864     return 0;
00865 error:
00866 
00867     if (f != NULL)
00868         fclose(f);
00869 
00870     return -1;
00871 }