pdb.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2009 1&1 Internet AG
00003  *
00004  * This file is part of sip-router, a free SIP server.
00005  *
00006  * sip-router is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version
00010  *
00011  * sip-router is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License 
00017  * along with this program; if not, write to the Free Software 
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 
00027 #include "../../sr_module.h"
00028 #include "../../mem/mem.h"
00029 #include "../../mem/shm_mem.h"
00030 #include "../../lib/kmi/mi.h"
00031 #include <sys/time.h>
00032 #include <poll.h>
00033 #include <stdlib.h>
00034 #include <unistd.h>
00035 #include <ctype.h>
00036 #include <sys/socket.h>
00037 #include <netinet/in.h>
00038 #include <arpa/inet.h>
00039 #include <errno.h>
00040 
00041 MODULE_VERSION
00042 
00043 
00044 #define NETBUFSIZE 200
00045 
00046 
00047 static char* modp_server = NULL;  
00048 static int timeout = 50;  
00049 static int timeoutlogs = -10;  
00050 static int *active = NULL;
00051 
00052 
00057 struct multiparam_t {
00058         enum {
00059                 MP_INT,
00060                 MP_STR,
00061                 MP_AVP,
00062                 MP_PVE,
00063         } type;
00064         union {
00065                 int n;
00066                 str s;
00067                 struct {
00068                         unsigned short flags;
00069                         int_str name;
00070                 } a;
00071                 pv_elem_t *p;
00072         } u;
00073 };
00074 
00075 
00076 /* ---- exported commands: */
00077 static int pdb_query(struct sip_msg *_msg, struct multiparam_t *_number, struct multiparam_t *_dstavp);
00078 
00079 /* ---- fixup functions: */
00080 static int pdb_query_fixup(void **arg, int arg_no);
00081 
00082 /* ---- module init functions: */
00083 static int mod_init(void);
00084 static int child_init(int rank);
00085 static int mi_child_init(void);
00086 static void mod_destroy();
00087 
00088 /* --- fifo functions */
00089 struct mi_root * mi_pdb_status(struct mi_root* cmd, void* param);  /* usage: kamctl fifo pdb_status */
00090 struct mi_root * mi_pdb_activate(struct mi_root* cmd, void* param);  /* usage: kamctl fifo pdb_activate */
00091 struct mi_root * mi_pdb_deactivate(struct mi_root* cmd, void* param);  /* usage: kamctl fifo pdb_deactivate */
00092 
00093 
00094 static cmd_export_t cmds[]={
00095         { "pdb_query", (cmd_function)pdb_query, 2, pdb_query_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE },
00096         {0,0,0,0,0,0}
00097 };
00098 
00099 
00100 static param_export_t params[] = {
00101         {"server",      STR_PARAM, &modp_server },
00102         {"timeout",     INT_PARAM, &timeout },
00103         {0, 0, 0 }
00104 };
00105 
00106 
00107 /* Exported MI functions */
00108 static mi_export_t mi_cmds[] = {
00109         { "pdb_status", mi_pdb_status, MI_NO_INPUT_FLAG, 0, mi_child_init },
00110         { "pdb_activate", mi_pdb_activate, MI_NO_INPUT_FLAG, 0, mi_child_init },
00111         { "pdb_deactivate", mi_pdb_deactivate, MI_NO_INPUT_FLAG, 0, mi_child_init },
00112         { 0, 0, 0, 0, 0}
00113 };
00114 
00115 
00116 struct module_exports exports = {
00117         "pdb",
00118         DEFAULT_DLFLAGS, /* dlopen flags */
00119         cmds,       /* Exported functions */
00120         params,     /* Export parameters */
00121         0,          /* exported statistics */
00122         mi_cmds,    /* exported MI functions */
00123         0,          /* exported pseudo-variables */
00124         0,          /* extra processes */
00125         mod_init,   /* Module initialization function */
00126         0,          /* Response function */
00127         mod_destroy,/* Destroy function */
00128         child_init  /* Child initialization function */
00129 };
00130 
00131 
00132 struct server_item_t {
00133         struct server_item_t *next;
00134         char *host;
00135         unsigned short int port;
00136         struct sockaddr_in dstaddr;
00137         socklen_t dstaddrlen;
00138         int sock;
00139 };
00140 
00141 
00142 struct server_list_t {
00143         struct server_item_t *head;
00144         int nserver;
00145         struct pollfd *fds;
00146 };
00147 
00148 
00150 static struct server_list_t *server_list;
00151 
00152 
00157 static int pdb_query(struct sip_msg *_msg, struct multiparam_t *_number, struct multiparam_t *_dstavp)
00158 {
00159         struct timeval tstart, tnow;
00160         struct server_item_t *server;
00161         short int carrierid;
00162         char buf[NETBUFSIZE+1+sizeof(carrierid)];
00163         size_t reqlen;
00164         int_str avp_val;
00165         struct usr_avp *avp;
00166         int i, ret, nflush;
00167         long int td;
00168         str number = { .len = 0, .s = NULL};
00169 
00170         if ((active == NULL) || (*active == 0)) return -1;
00171 
00172         switch (_number->type) {
00173         case MP_STR:
00174                 number = _number->u.s;
00175                 break;
00176         case MP_AVP:
00177                 avp = search_first_avp(_number->u.a.flags, _number->u.a.name, &avp_val, 0);
00178                 if (!avp) {
00179                         LM_ERR("cannot find AVP '%.*s'\n", _number->u.a.name.s.len, _number->u.a.name.s.s);
00180                         return -1;
00181                 }
00182                 if ((avp->flags&AVP_VAL_STR)==0) {
00183                         LM_ERR("cannot process integer value in AVP '%.*s'\n", _number->u.a.name.s.len, _number->u.a.name.s.s);
00184                         return -1;
00185                 }
00186                 else number = avp_val.s;
00187                 break;
00188         case MP_PVE:
00189                 if (pv_printf_s(_msg, _number->u.p, &number)<0) {
00190                         LM_ERR("cannot print the number\n");
00191                         return -1;
00192                 }
00193                 break;
00194         default:
00195                 LM_ERR("invalid number type\n");
00196                 return -1;
00197         }
00198 
00199         LM_DBG("querying '%.*s'...\n", number.len, number.s);
00200         if (server_list == NULL) return -1;
00201         if (server_list->fds == NULL) return -1;
00202 
00203         if (gettimeofday(&tstart, NULL) != 0) {
00204                 LM_ERR("gettimeofday() failed with errno=%d (%s)\n", errno, strerror(errno));
00205                 return -1;
00206         }
00207 
00208         /* clear recv buffer */
00209         server = server_list->head;
00210         while (server) {
00211                 nflush = 0;
00212                 while (recv(server->sock, buf, NETBUFSIZE, MSG_DONTWAIT) > 0) {
00213                         nflush++;
00214                         if (gettimeofday(&tnow, NULL) != 0) {
00215                                 LM_ERR("gettimeofday() failed with errno=%d (%s)\n", errno, strerror(errno));
00216                                 return -1;
00217                         }
00218                         td=(tnow.tv_usec-tstart.tv_usec+(tnow.tv_sec-tstart.tv_sec)*1000000) / 1000;
00219                         if (td > timeout) {
00220                                 LM_WARN("exceeded timeout while flushing recv buffer.\n");
00221                                 return -1;
00222                         }
00223                 }
00224                 LM_DBG("flushed %d packets for '%s:%d'\n", nflush, server->host, server->port);
00225                 server = server ->next;
00226         }
00227 
00228         /* prepare request */
00229         reqlen = number.len + 1; /* include null termination */
00230         if (reqlen > NETBUFSIZE) {
00231                 LM_ERR("number too long '%.*s'.\n", number.len, number.s);
00232                 return -1;
00233         }
00234         strncpy(buf, number.s, number.len);
00235         buf[number.len] = '\0';
00236 
00237         /* send request to all servers */
00238         server = server_list->head;
00239         while (server) {
00240                 LM_DBG("sending request to '%s:%d'\n", server->host, server->port);
00241                 ret=sendto(server->sock, buf, reqlen, MSG_DONTWAIT, (struct sockaddr *)&(server->dstaddr), server->dstaddrlen);
00242                 if (ret < 0) {
00243                         LM_ERR("sendto() failed with errno=%d (%s)\n", errno, strerror(errno));
00244                 }
00245                 server = server->next;
00246         }
00247                 
00248         /* wait for response */
00249         for (;;) {
00250                 if (gettimeofday(&tnow, NULL) != 0) {
00251                         LM_ERR("gettimeofday() failed with errno=%d (%s)\n", errno, strerror(errno));
00252                         return -1;
00253                 }
00254                 td=(tnow.tv_usec-tstart.tv_usec+(tnow.tv_sec-tstart.tv_sec)*1000000) / 1000;
00255                 if (td > timeout) {
00256                         timeoutlogs++;
00257                         if (timeoutlogs<0) {
00258                                 LM_WARN("exceeded timeout while waiting for response.\n");
00259                         }
00260                         else if (timeoutlogs>1000) {
00261                                 LM_WARN("exceeded timeout %d times while waiting for response.\n", timeoutlogs);
00262                                 timeoutlogs=0;
00263                         }
00264                         return -1;
00265                 }
00266                 
00267                 ret=poll(server_list->fds, server_list->nserver, timeout-td);
00268                 for (i=0; i<server_list->nserver; i++) {
00269                         if (server_list->fds[i].revents & POLLIN) {
00270                                 if (recv(server_list->fds[i].fd, buf, NETBUFSIZE, MSG_DONTWAIT) > 0) { /* do not block - just in case select/poll was wrong */
00271                                         buf[NETBUFSIZE] = '\0';
00272                                         if (strncmp(buf, number.s, number.len) == 0) {
00273                                                 carrierid=ntohs(*((short int *)&(buf[reqlen]))); /* convert to host byte order */
00274                                                 goto found;
00275                                         }
00276                                 }
00277                         }
00278                         server_list->fds[i].revents = 0;
00279                 }
00280         }
00281 
00282         found:
00283         if (timeoutlogs>0) {
00284                 LM_WARN("exceeded timeout while waiting for response (buffered %d lines).\n", timeoutlogs);
00285                 timeoutlogs=-10;
00286         }
00287         if (gettimeofday(&tnow, NULL) == 0) {
00288                 LM_INFO("got an answer in %f ms\n", ((double)(tnow.tv_usec-tstart.tv_usec+(tnow.tv_sec-tstart.tv_sec)*1000000))/1000);
00289         }
00290         avp_val.n=carrierid;
00291         /* set avp ! */
00292         if (add_avp(_dstavp->u.a.flags, _dstavp->u.a.name, avp_val)<0) {
00293                 LM_ERR("add AVP failed\n");
00294                 return -1;
00295         }
00296 
00297         return 1;
00298 }
00299 
00300 
00308 static int mp_fixup(void ** param) {
00309         pv_spec_t avp_spec;
00310         struct multiparam_t *mp;
00311         str s;
00312 
00313         mp = (struct multiparam_t *)pkg_malloc(sizeof(struct multiparam_t));
00314         if (mp == NULL) {
00315                 PKG_MEM_ERROR;
00316                 return -1;
00317         }
00318         memset(mp, 0, sizeof(struct multiparam_t));
00319         
00320         s.s = (char *)(*param);
00321         s.len = strlen(s.s);
00322 
00323         if (s.s[0]!='$') {
00324                 /* This is string */
00325                 mp->type=MP_STR;
00326                 mp->u.s=s;
00327         }
00328         else {
00329                 /* This is a pseudo-variable */
00330                 if (pv_parse_spec(&s, &avp_spec)==0) {
00331                         LM_ERR("pv_parse_spec failed for '%s'\n", (char *)(*param));
00332                         pkg_free(mp);
00333                         return -1;
00334                 }
00335                 if (avp_spec.type==PVT_AVP) {
00336                         /* This is an AVP - could be an id or name */
00337                         mp->type=MP_AVP;
00338                         if(pv_get_avp_name(0, &(avp_spec.pvp), &(mp->u.a.name), &(mp->u.a.flags))!=0) {
00339                                 LM_ERR("Invalid AVP definition <%s>\n", (char *)(*param));
00340                                 pkg_free(mp);
00341                                 return -1;
00342                         }
00343                 } else {
00344                         mp->type=MP_PVE;
00345                         if(pv_parse_format(&s, &(mp->u.p))<0) {
00346                                 LM_ERR("pv_parse_format failed for '%s'\n", (char *)(*param));
00347                                 pkg_free(mp);
00348                                 return -1;
00349                         }
00350                 }
00351         }
00352         *param = (void*)mp;
00353 
00354         return 0;
00355 }
00356 
00357 
00364 static int avp_name_fixup(void ** param) {
00365         pv_spec_t avp_spec;
00366         struct multiparam_t *mp;
00367         str s;
00368 
00369         s.s = (char *)(*param);
00370         s.len = strlen(s.s);
00371         if (s.len <= 0) return -1;
00372         if (pv_parse_spec(&s, &avp_spec)==0 || avp_spec.type!=PVT_AVP) {
00373                 LM_ERR("Malformed or non AVP definition <%s>\n", (char *)(*param));
00374                 return -1;
00375         }
00376         
00377         mp = (struct multiparam_t *)pkg_malloc(sizeof(struct multiparam_t));
00378         if (mp == NULL) {
00379                 PKG_MEM_ERROR;
00380                 return -1;
00381         }
00382         memset(mp, 0, sizeof(struct multiparam_t));
00383         
00384         mp->type=MP_AVP;
00385         if(pv_get_avp_name(0, &(avp_spec.pvp), &(mp->u.a.name), &(mp->u.a.flags))!=0) {
00386                 LM_ERR("Invalid AVP definition <%s>\n", (char *)(*param));
00387                 pkg_free(mp);
00388                 return -1;
00389         }
00390 
00391         *param = (void*)mp;
00392         
00393         return 0;
00394 }
00395 
00396 
00397 static int pdb_query_fixup(void **arg, int arg_no)
00398 {
00399         if (arg_no == 1) {
00400                 /* phone number */
00401                 if (mp_fixup(arg) < 0) {
00402                         LM_ERR("cannot fixup parameter %d\n", arg_no);
00403                         return -1;
00404                 }
00405         }
00406         else if (arg_no == 2) {
00407                 /* destination avp name */
00408                 if (avp_name_fixup(arg) < 0) {
00409                         LM_ERR("cannot fixup parameter %d\n", arg_no);
00410                         return -1;
00411                 }
00412         }
00413 
00414         return 0;
00415 }
00416 
00417 
00422 static int add_server(char *host, char *port)
00423 {
00424         long int ret;
00425         struct server_item_t *server;
00426 
00427         LM_DBG("adding server '%s:%s'\n", host, port);
00428         server= pkg_malloc(sizeof(struct server_item_t));
00429         if (server == NULL) {
00430                 PKG_MEM_ERROR;
00431                 return -1;
00432         }
00433         memset(server, 0, sizeof(struct server_item_t));
00434 
00435         server->next = server_list->head;
00436         server_list->head = server;
00437 
00438         server->host = pkg_malloc(strlen(host)+1);
00439         if (server->host == NULL) {
00440                 PKG_MEM_ERROR;
00441                 return -1;
00442         }
00443         strcpy(server->host, host);
00444 
00445         ret=strtol(port, NULL, 10);
00446         if ((ret<0) || (ret>65535)) {
00447                 LM_ERR("invalid port '%s'\n", port);
00448                 return -1;
00449         }
00450         server->port=ret;
00451 
00452         return 0;
00453 }
00454 
00455 
00460 static int prepare_server(void)
00461 {
00462         char *p, *dst, *end, *sep, *host, *port;
00463 
00464         if (modp_server == NULL) {
00465                 LM_ERR("server parameter missing.\n");
00466                 return -1;
00467         }
00468 
00469         /* Remove white space from db_sources */
00470         for (p = modp_server, dst = modp_server; *p != '\0'; ++p, ++dst) {
00471                 while (isspace(*p)) ++p;
00472                 *dst = *p;
00473         }
00474         *dst = '\0';
00475 
00476         p = modp_server;
00477         end = p + strlen(p);
00478 
00479         while (p < end) {
00480                 sep = strchr(p, ':');
00481                 if (sep == NULL) {
00482                         LM_ERR("syntax error in sources parameter.\n");
00483                         return -1;
00484                 }
00485                 host = p;
00486                 *sep = '\0';
00487                 p = sep + 1;
00488 
00489                 sep = strchr(p, ',');
00490                 if (sep == NULL) sep = end;
00491                 port = p;
00492                 *sep = '\0';
00493                 p = sep + 1;
00494 
00495                 if (add_server(host, port) != 0)  return -1;
00496         }
00497 
00498         return 0;
00499 }
00500 
00501 
00502 static void destroy_server_list(void)
00503 {
00504         if (server_list) {
00505                 while (server_list->head) {
00506                         struct server_item_t *server = server_list->head;
00507                         server_list->head = server->next;
00508                         if (server->host) pkg_free(server->host);
00509                         pkg_free(server);
00510                 }
00511                 pkg_free(server_list);
00512                 server_list = NULL;
00513         }
00514 }
00515 
00516 
00521 static int init_server_list(void)
00522 {
00523         server_list = pkg_malloc(sizeof(struct server_list_t));
00524         if (server_list == NULL) {
00525                 PKG_MEM_ERROR;
00526                 return -1;
00527         }
00528         memset(server_list, 0, sizeof(struct server_list_t));
00529 
00530         if (prepare_server() != 0) {
00531                 destroy_server_list();
00532                 return -1;
00533         }
00534 
00535   return 0;
00536 }
00537 
00538 
00543 static int init_server_socket(void)
00544 {
00545         struct server_item_t *server;
00546         struct hostent *hp;
00547         int i;
00548 
00549         if (server_list) {
00550                 server_list->nserver=0;
00551                 server = server_list->head;
00552                 while (server) {
00553                         LM_DBG("initializing socket for '%s:%d'\n", server->host, server->port);
00554                         server->sock = socket(AF_INET, SOCK_DGRAM, 0);
00555                         if (server->sock<0) {
00556                                 LM_ERR("socket() failed with errno=%d (%s).\n", errno, strerror(errno));
00557                                 return -1;
00558                         }
00559 
00560                         memset(&(server->dstaddr), 0, sizeof(server->dstaddr));
00561                         server->dstaddr.sin_family = AF_INET;
00562                         server->dstaddr.sin_port = htons(server->port);
00563                         hp = gethostbyname(server->host);
00564                         if (hp == NULL) {
00565                                 LM_ERR("gethostbyname(%s) failed with h_errno=%d.\n", server->host, h_errno);
00566                                 close(server->sock);
00567                                 server->sock=0;
00568                                 return -1;
00569                         }
00570                         memcpy(&(server->dstaddr.sin_addr.s_addr), hp->h_addr, hp->h_length);
00571                         server->dstaddrlen=sizeof(server->dstaddr);
00572 
00573                         server = server->next;
00574                         server_list->nserver++;
00575                 }
00576 
00577                 LM_DBG("got %d server in list\n", server_list->nserver);
00578                 server_list->fds = pkg_malloc(sizeof(struct pollfd)*server_list->nserver);
00579                 if (server_list->fds == NULL) {
00580                         PKG_MEM_ERROR;
00581                         return -1;
00582                 }
00583                 memset(server_list->fds, 0, sizeof(struct pollfd)*server_list->nserver);
00584 
00585                 i=0;
00586                 server = server_list->head;
00587                 while (server) {
00588                         server_list->fds[i].fd=server->sock;
00589                         server_list->fds[i].events=POLLIN;
00590                         server = server->next;
00591                         i++;
00592                 }
00593         }
00594         return 0;
00595 }
00596 
00597 
00601 static void destroy_server_socket(void)
00602 {
00603         if (server_list) {
00604                 struct server_item_t *server = server_list->head;
00605                 while (server) {
00606                         if (server->sock>0) close(server->sock);
00607                         server = server->next;
00608                 }
00609                 if (server_list->fds) pkg_free(server_list->fds);
00610         }
00611 }
00612 
00613 
00614 struct mi_root * mi_pdb_status(struct mi_root* cmd, void* param)
00615 {
00616         struct mi_root * root = NULL;
00617         struct mi_node * node = NULL;
00618 
00619         if (active == NULL) return init_mi_tree(500, "NULL pointer", 12);
00620 
00621         root = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00622         if (root == NULL) return NULL;
00623 
00624         if (*active) node = addf_mi_node_child(&root->node, 0, 0, 0, "pdb is active");
00625         else node = addf_mi_node_child(&root->node, 0, 0, 0, "pdb is deactivated");
00626         if (node == NULL) {
00627                 free_mi_tree(root);
00628                 return NULL;
00629         }
00630 
00631         return root;
00632 }
00633 
00634 
00635 struct mi_root * mi_pdb_deactivate(struct mi_root* cmd, void* param)
00636 {
00637         if (active == NULL) return init_mi_tree(500, "NULL pointer", 12);
00638 
00639         *active=0;
00640         return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
00641 }
00642 
00643 
00644 struct mi_root * mi_pdb_activate(struct mi_root* cmd, void* param)
00645 {
00646         if (active == NULL) return init_mi_tree(500, "NULL pointer", 12);
00647 
00648         *active=1;
00649         return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00650 }
00651 
00652 
00653 static int mod_init(void)
00654 {
00655         active = shm_malloc(sizeof(*active));
00656         if (active == NULL) {
00657                 SHM_MEM_ERROR;
00658                 return -1;
00659         }
00660         *active=1;
00661 
00662         if (init_server_list() != 0) {
00663                 shm_free(active);
00664                 return -1;
00665         }
00666         return 0;
00667 }
00668 
00669 static int child_init (int rank)
00670 {
00671         if(rank==PROC_INIT || rank==PROC_TCP_MAIN)
00672                 return 0;
00673         return mi_child_init();
00674 }
00675 
00676 
00677 static int pdb_child_initialized = 0;
00678 
00679 static int mi_child_init(void)
00680 {
00681         if(pdb_child_initialized)
00682                 return 0;
00683         if (init_server_socket() != 0) return -1;
00684         pdb_child_initialized = 1;
00685         return 0;
00686 }
00687 
00688 
00689 static void mod_destroy(void)
00690 {
00691         destroy_server_socket();
00692         destroy_server_list();
00693         if (active) shm_free(active);
00694 }