b72ecf7f29893a91a85df2e4561d89ba72fcc2cf
[sip-router] / src / modules / pdb / pdb.c
1 /*
2  * Copyright (C) 2009 1&1 Internet AG
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * Kamailio is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  * Kamailio is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21 /*!
22  * @file pdb.c
23  * @brief Contains the functions exported by the module.
24  */
25
26
27 #include "../../core/sr_module.h"
28 #include "../../core/mem/mem.h"
29 #include "../../core/mem/shm_mem.h"
30 #include "../../core/rpc_lookup.h"
31 #include <sys/time.h>
32 #include <poll.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <ctype.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
39 #include <errno.h>
40
41 #include "common.h"
42
43 MODULE_VERSION
44
45 static char* modp_server = NULL;  /*!< format: \<host\>:\<port\>,... */
46 static int timeout = 50;  /*!< timeout for queries in milliseconds */
47 static int timeoutlogs = -10;  /*!< for aggregating timeout logs */
48 static int *active = NULL;
49 static uint16_t *global_id = NULL;
50
51
52 /*!
53  * Generic parameter that holds a string, an int or an pseudo-variable
54  * @todo replace this with gparam_t
55  */
56 struct multiparam_t {
57         enum {
58                 MP_INT,
59                 MP_STR,
60                 MP_AVP,
61                 MP_PVE,
62         } type;
63         union {
64                 int n;
65                 str s;
66                 struct {
67                         unsigned short flags;
68                         int_str name;
69                 } a;
70                 pv_elem_t *p;
71         } u;
72 };
73
74
75 /* ---- exported commands: */
76 static int pdb_query(struct sip_msg *_msg, struct multiparam_t *_number,
77                 struct multiparam_t *_dstavp);
78
79 /* ---- fixup functions: */
80 static int pdb_query_fixup(void **arg, int arg_no);
81
82 /* ---- module init functions: */
83 static int mod_init(void);
84 static int child_init(int rank);
85 static int rpc_child_init(void);
86 static void mod_destroy();
87
88 /* debug function for the new client <-> server protocol */
89 static void pdb_msg_dbg(struct pdb_msg msg, char *dbg_msg);
90
91 /* build the new protocol message before transmission */
92 static int pdb_msg_format_send(struct pdb_msg *msg,
93                                uint8_t version, uint8_t type,
94                                uint8_t code, uint16_t id,
95                                char *payload, uint16_t payload_len);
96
97 static cmd_export_t cmds[]={
98         { "pdb_query", (cmd_function)pdb_query, 2, pdb_query_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE },
99         {0,0,0,0,0,0}
100 };
101
102
103 static param_export_t params[] = {
104         {"server",      PARAM_STRING, &modp_server },
105         {"timeout",     INT_PARAM, &timeout },
106         {0, 0, 0 }
107 };
108
109
110 struct module_exports exports = {
111         "pdb",           /* module name */
112         DEFAULT_DLFLAGS, /* dlopen flags */
113         cmds,            /* cmd (cfg function) exports */
114         params,          /* param exports */
115         0,               /* RPC method exports */
116         0,               /* pseudo-variables exports */
117         0,               /* response handling function */
118         mod_init,        /* Module initialization function */
119         child_init,      /* Child initialization function */
120         mod_destroy      /* Destroy function */
121 };
122
123
124 struct server_item_t {
125         struct server_item_t *next;
126         char *host;
127         unsigned short int port;
128         struct sockaddr_in dstaddr;
129         socklen_t dstaddrlen;
130         int sock;
131 };
132
133
134 struct server_list_t {
135         struct server_item_t *head;
136         int nserver;
137         struct pollfd *fds;
138 };
139
140
141 /*! global server list */
142 static struct server_list_t *server_list;
143
144
145 /* debug function for the new client <-> server protocol */
146 static void pdb_msg_dbg(struct pdb_msg msg, char *dbg_msg) {
147     int i;
148     char buf[PAYLOADSIZE * 3 + 1];
149     char *ptr = buf;
150
151         if(msg.hdr.length > sizeof(msg.hdr)) {
152                 for (i = 0; i < msg.hdr.length - sizeof(msg.hdr); i++) {
153                         ptr += sprintf(ptr, "%02X ", msg.bdy.payload[i]);
154                 }
155         } else {
156                 *ptr = '\0';
157         }
158
159     LM_DBG("%s\n"
160            "version = %d\ntype = %d\ncode = %d\nid = %d\nlen = %d\n"
161            "payload = %s\n",
162             dbg_msg,
163             msg.hdr.version, msg.hdr.type, msg.hdr.code, msg.hdr.id, msg.hdr.length,
164             buf);
165 }
166
167 /* build the message before send */
168 static int pdb_msg_format_send(struct pdb_msg *msg,
169                                uint8_t version, uint8_t type,
170                                uint8_t code, uint16_t id,
171                                char *payload, uint16_t payload_len)
172 {
173     msg->hdr.version    = version;
174     msg->hdr.type       = type;
175     msg->hdr.code       = code;
176     msg->hdr.id         = id;
177
178     if (payload == NULL) {
179         /* just ignore the NULL buff (called when just want to set the len) */
180         msg->hdr.length     = sizeof(struct pdb_hdr);
181         return 0;
182     } else {
183         msg->hdr.length     = sizeof(struct pdb_hdr) + payload_len;
184         memcpy(msg->bdy.payload, payload, payload_len);
185         return 0;
186     }
187
188     return 0;
189 }
190
191
192
193 /*!
194  * \return 1 if query for the number succeded and the avp with the corresponding carrier id was set,
195  * -1 otherwise
196  */
197 static int pdb_query(struct sip_msg *_msg, struct multiparam_t *_number, struct multiparam_t *_dstavp)
198 {
199     struct pdb_msg msg;
200         struct timeval tstart, tnow;
201         struct server_item_t *server;
202         short int carrierid, *_id;
203         short int _idv;
204     char buf[sizeof(struct pdb_msg)];
205         size_t reqlen;
206         int_str avp_val;
207         struct usr_avp *avp;
208         int i, ret, nflush, bytes_received;
209         long int td;
210         str number = STR_NULL;
211
212         if ((active == NULL) || (*active == 0)) return -1;
213
214         switch (_number->type) {
215         case MP_STR:
216                 number = _number->u.s;
217                 break;
218         case MP_AVP:
219                 avp = search_first_avp(_number->u.a.flags, _number->u.a.name, &avp_val, 0);
220                 if (!avp) {
221                         LM_ERR("cannot find AVP '%.*s'\n", _number->u.a.name.s.len, _number->u.a.name.s.s);
222                         return -1;
223                 }
224                 if ((avp->flags&AVP_VAL_STR)==0) {
225                         LM_ERR("cannot process integer value in AVP '%.*s'\n", _number->u.a.name.s.len, _number->u.a.name.s.s);
226                         return -1;
227                 }
228                 else number = avp_val.s;
229                 break;
230         case MP_PVE:
231                 if (pv_printf_s(_msg, _number->u.p, &number)<0) {
232                         LM_ERR("cannot print the number\n");
233                         return -1;
234                 }
235                 break;
236         default:
237                 LM_ERR("invalid number type\n");
238                 return -1;
239         }
240
241         LM_DBG("querying '%.*s'...\n", number.len, number.s);
242         if (server_list == NULL) return -1;
243         if (server_list->fds == NULL) return -1;
244
245         if (gettimeofday(&tstart, NULL) != 0) {
246                 LM_ERR("gettimeofday() failed with errno=%d (%s)\n", errno, strerror(errno));
247                 return -1;
248         }
249
250         /* clear recv buffer */
251         server = server_list->head;
252         while (server) {
253                 nflush = 0;
254                 while (recv(server->sock, buf, sizeof(struct pdb_msg), MSG_DONTWAIT) > 0) {
255                         nflush++;
256                         if (gettimeofday(&tnow, NULL) != 0) {
257                                 LM_ERR("gettimeofday() failed with errno=%d (%s)\n", errno, strerror(errno));
258                                 return -1;
259                         }
260                         td=(tnow.tv_usec-tstart.tv_usec+(tnow.tv_sec-tstart.tv_sec)*1000000) / 1000;
261                         if (td > timeout) {
262                                 LM_NOTICE("exceeded timeout while flushing recv buffer.\n");
263                                 return -1;
264                         }
265                 }
266                 LM_DBG("flushed %d packets for '%s:%d'\n", nflush, server->host, server->port);
267                 server = server ->next;
268         }
269
270         /* prepare request */
271         reqlen = number.len + 1; /* include null termination */
272         if (reqlen > PAYLOADSIZE) {
273                 LM_ERR("number too long '%.*s'.\n", number.len, number.s);
274                 return -1;
275         }
276         strncpy(buf, number.s, number.len);
277         buf[number.len] = '\0';
278
279     switch (PDB_VERSION) {
280         case PDB_VERSION_1:
281             pdb_msg_format_send(&msg, PDB_VERSION, PDB_TYPE_REQUEST_ID, PDB_CODE_DEFAULT, htons(*global_id), buf, reqlen);
282             pdb_msg_dbg(msg, "Kamailio pdb client sends:");
283
284             /* increment msg id for the next request */
285             *global_id = *global_id + 1;
286
287             /* send request to all servers */
288             server = server_list->head;
289             while (server) {
290                 LM_DBG("sending request to '%s:%d'\n", server->host, server->port);
291                 ret=sendto(server->sock, (struct pdb_msg*)&msg, msg.hdr.length, MSG_DONTWAIT, (struct sockaddr *)&(server->dstaddr), server->dstaddrlen);
292                 if (ret < 0) {
293                     LM_ERR("sendto() failed with errno=%d (%s)\n", errno, strerror(errno));
294                 }
295                 server = server->next;
296             }
297             break;
298         default:
299             /* send request to all servers */
300             server = server_list->head;
301             while (server) {
302                 LM_DBG("sending request to '%s:%d'\n", server->host, server->port);
303                 ret=sendto(server->sock, buf, reqlen, MSG_DONTWAIT, (struct sockaddr *)&(server->dstaddr), server->dstaddrlen);
304                 if (ret < 0) {
305                     LM_ERR("sendto() failed with errno=%d (%s)\n", errno, strerror(errno));
306                 }
307                 server = server->next;
308             }
309             break;
310     }
311
312         memset(&msg, 0, sizeof(struct pdb_msg));
313         /* wait for response */
314         for (;;) {
315                 if (gettimeofday(&tnow, NULL) != 0) {
316                         LM_ERR("gettimeofday() failed with errno=%d (%s)\n", errno, strerror(errno));
317                         return -1;
318                 }
319                 td=(tnow.tv_usec-tstart.tv_usec+(tnow.tv_sec-tstart.tv_sec)*1000000) / 1000;
320                 if (td > timeout) {
321                         timeoutlogs++;
322                         if (timeoutlogs<0) {
323                                 LM_NOTICE("exceeded timeout while waiting for response.\n");
324                         }
325                         else if (timeoutlogs>1000) {
326                                 LM_NOTICE("exceeded timeout %d times while waiting for response.\n", timeoutlogs);
327                                 timeoutlogs=0;
328                         }
329                         return -1;
330                 }
331
332                 ret=poll(server_list->fds, server_list->nserver, timeout-td);
333                 for (i=0; i<server_list->nserver; i++) {
334                         if (server_list->fds[i].revents & POLLIN) {
335                                 if ((bytes_received = recv(server_list->fds[i].fd, buf,  sizeof(struct pdb_msg), MSG_DONTWAIT)) > 0) { /* do not block - just in case select/poll was wrong */
336                     switch (PDB_VERSION) {
337                         case PDB_VERSION_1:
338                             memcpy(&msg, buf, bytes_received);
339                             pdb_msg_dbg(msg, "Kamailio pdb client receives:");
340
341                             _idv = msg.hdr.id; /* make gcc happy */
342                             msg.hdr.id = ntohs(_idv);
343
344                             switch (msg.hdr.code) {
345                                 case PDB_CODE_OK:
346                                     msg.bdy.payload[sizeof(struct pdb_bdy) - 1] = '\0';
347                                     if (strcmp(msg.bdy.payload, number.s) == 0) {
348                                         _id = (short int *)&(msg.bdy.payload[reqlen]); /* make gcc happy */
349                                         carrierid=ntohs(*_id); /* convert to host byte order */
350                                         goto found;
351                                     }
352                                     break;
353                                 case PDB_CODE_NOT_NUMBER:
354                                     LM_NOTICE("Number %s has letters in it\n", number.s);
355                                     carrierid = 0;
356                                     goto found;
357                                 case PDB_CODE_NOT_FOUND:
358                                     LM_NOTICE("Number %s pdb_id not found\n", number.s);
359                                     carrierid = 0;
360                                     goto found;
361                                 default:
362                                     LM_NOTICE("Invalid code %d received\n", msg.hdr.code);
363                                     carrierid = 0;
364                                     goto found;
365                             }
366
367                             break;
368                         default:
369                             buf[sizeof(struct pdb_msg) - 1] = '\0';
370                             if (strncmp(buf, number.s, number.len) == 0) {
371                                 _id = (short int *)&(buf[reqlen]);
372                                 carrierid=ntohs(*_id); /* convert to host byte order */
373                                 goto found;
374                             }
375                             break;
376                     }
377                                 }
378                         }
379                         server_list->fds[i].revents = 0;
380                 }
381         }
382
383         found:
384         if (timeoutlogs>0) {
385                 LM_NOTICE("exceeded timeout while waiting for response (buffered %d lines).\n", timeoutlogs);
386                 timeoutlogs=-10;
387         }
388         if (gettimeofday(&tnow, NULL) == 0) {
389                 LM_INFO("got an answer in %f ms\n", ((double)(tnow.tv_usec-tstart.tv_usec+(tnow.tv_sec-tstart.tv_sec)*1000000))/1000);
390         }
391         avp_val.n=carrierid;
392         /* set avp ! */
393         if (add_avp(_dstavp->u.a.flags, _dstavp->u.a.name, avp_val)<0) {
394                 LM_ERR("add AVP failed\n");
395                 return -1;
396         }
397
398         return 1;
399 }
400
401
402 /*!
403  * fixes the module functions' parameters if it is a phone number.
404  * supports string, pseudo-variables and AVPs.
405  *
406  * @param param the parameter
407  * @return 0 on success, -1 on failure
408  */
409 static int mp_fixup(void ** param) {
410         pv_spec_t avp_spec;
411         struct multiparam_t *mp;
412         str s;
413
414         mp = (struct multiparam_t *)pkg_malloc(sizeof(struct multiparam_t));
415         if (mp == NULL) {
416                 PKG_MEM_ERROR;
417                 return -1;
418         }
419         memset(mp, 0, sizeof(struct multiparam_t));
420         
421         s.s = (char *)(*param);
422         s.len = strlen(s.s);
423
424         if (s.s[0]!='$') {
425                 /* This is string */
426                 mp->type=MP_STR;
427                 mp->u.s=s;
428         }
429         else {
430                 /* This is a pseudo-variable */
431                 if (pv_parse_spec(&s, &avp_spec)==0) {
432                         LM_ERR("pv_parse_spec failed for '%s'\n", (char *)(*param));
433                         pkg_free(mp);
434                         return -1;
435                 }
436                 if (avp_spec.type==PVT_AVP) {
437                         /* This is an AVP - could be an id or name */
438                         mp->type=MP_AVP;
439                         if(pv_get_avp_name(0, &(avp_spec.pvp), &(mp->u.a.name), &(mp->u.a.flags))!=0) {
440                                 LM_ERR("Invalid AVP definition <%s>\n", (char *)(*param));
441                                 pkg_free(mp);
442                                 return -1;
443                         }
444                 } else {
445                         mp->type=MP_PVE;
446                         if(pv_parse_format(&s, &(mp->u.p))<0) {
447                                 LM_ERR("pv_parse_format failed for '%s'\n", (char *)(*param));
448                                 pkg_free(mp);
449                                 return -1;
450                         }
451                 }
452         }
453         *param = (void*)mp;
454
455         return 0;
456 }
457
458
459 /*!
460  * fixes the module functions' parameters in case of AVP names.
461  *
462  * @param param the parameter
463  * @return 0 on success, -1 on failure
464  */
465 static int avp_name_fixup(void ** param) {
466         pv_spec_t avp_spec;
467         struct multiparam_t *mp;
468         str s;
469
470         s.s = (char *)(*param);
471         s.len = strlen(s.s);
472         if (s.len <= 0) return -1;
473         if (pv_parse_spec(&s, &avp_spec)==0 || avp_spec.type!=PVT_AVP) {
474                 LM_ERR("Malformed or non AVP definition <%s>\n", (char *)(*param));
475                 return -1;
476         }
477         
478         mp = (struct multiparam_t *)pkg_malloc(sizeof(struct multiparam_t));
479         if (mp == NULL) {
480                 PKG_MEM_ERROR;
481                 return -1;
482         }
483         memset(mp, 0, sizeof(struct multiparam_t));
484         
485         mp->type=MP_AVP;
486         if(pv_get_avp_name(0, &(avp_spec.pvp), &(mp->u.a.name), &(mp->u.a.flags))!=0) {
487                 LM_ERR("Invalid AVP definition <%s>\n", (char *)(*param));
488                 pkg_free(mp);
489                 return -1;
490         }
491
492         *param = (void*)mp;
493         
494         return 0;
495 }
496
497
498 static int pdb_query_fixup(void **arg, int arg_no)
499 {
500         if (arg_no == 1) {
501                 /* phone number */
502                 if (mp_fixup(arg) < 0) {
503                         LM_ERR("cannot fixup parameter %d\n", arg_no);
504                         return -1;
505                 }
506         }
507         else if (arg_no == 2) {
508                 /* destination avp name */
509                 if (avp_name_fixup(arg) < 0) {
510                         LM_ERR("cannot fixup parameter %d\n", arg_no);
511                         return -1;
512                 }
513         }
514
515         return 0;
516 }
517
518
519 /*!
520  * Adds new server structure to server list.
521  * \return 0 on success -1 otherwise
522  */
523 static int add_server(char *host, char *port)
524 {
525         long int ret;
526         struct server_item_t *server;
527
528         LM_DBG("adding server '%s:%s'\n", host, port);
529         server= pkg_malloc(sizeof(struct server_item_t));
530         if (server == NULL) {
531                 PKG_MEM_ERROR;
532                 return -1;
533         }
534         memset(server, 0, sizeof(struct server_item_t));
535
536         server->next = server_list->head;
537         server_list->head = server;
538
539         server->host = pkg_malloc(strlen(host)+1);
540         if (server->host == NULL) {
541                 PKG_MEM_ERROR;
542                 return -1;
543         }
544         strcpy(server->host, host);
545
546         ret=strtol(port, NULL, 10);
547         if ((ret<0) || (ret>65535)) {
548                 LM_ERR("invalid port '%s'\n", port);
549                 return -1;
550         }
551         server->port=ret;
552
553         return 0;
554 }
555
556
557 /*!
558  * Prepares data structures for all configured servers.
559  *  \return 0 on success, -1 otherwise
560  */
561 static int prepare_server(void)
562 {
563         char *p, *dst, *end, *sep, *host, *port;
564
565         if (modp_server == NULL) {
566                 LM_ERR("server parameter missing.\n");
567                 return -1;
568         }
569
570         /* Remove white space from db_sources */
571         for (p = modp_server, dst = modp_server; *p != '\0'; ++p, ++dst) {
572                 while (isspace(*p)) ++p;
573                 *dst = *p;
574         }
575         *dst = '\0';
576
577         p = modp_server;
578         end = p + strlen(p);
579
580         while (p < end) {
581                 sep = strchr(p, ':');
582                 if (sep == NULL) {
583                         LM_ERR("syntax error in sources parameter.\n");
584                         return -1;
585                 }
586                 host = p;
587                 *sep = '\0';
588                 p = sep + 1;
589
590                 sep = strchr(p, ',');
591                 if (sep == NULL) sep = end;
592                 port = p;
593                 *sep = '\0';
594                 p = sep + 1;
595
596                 if (add_server(host, port) != 0)  return -1;
597         }
598
599         return 0;
600 }
601
602
603 static void destroy_server_list(void)
604 {
605         if (server_list) {
606                 while (server_list->head) {
607                         struct server_item_t *server = server_list->head;
608                         server_list->head = server->next;
609                         if (server->host) pkg_free(server->host);
610                         pkg_free(server);
611                 }
612                 pkg_free(server_list);
613                 server_list = NULL;
614         }
615 }
616
617
618 /*!
619  * Allocates memory and builds a list of all servers defined in module parameter.
620  * \return 0 on success, -1 otherwise
621  */
622 static int init_server_list(void)
623 {
624         server_list = pkg_malloc(sizeof(struct server_list_t));
625         if (server_list == NULL) {
626                 PKG_MEM_ERROR;
627                 return -1;
628         }
629         memset(server_list, 0, sizeof(struct server_list_t));
630
631         if (prepare_server() != 0) {
632                 destroy_server_list();
633                 return -1;
634         }
635
636   return 0;
637 }
638
639
640 /*!
641  * Initializes sockets for all servers in server list.
642  * \return 0 on success, -1 otherwise
643  */
644 static int init_server_socket(void)
645 {
646         struct server_item_t *server;
647         struct hostent *hp;
648         int i;
649
650         if (server_list) {
651                 server_list->nserver=0;
652                 server = server_list->head;
653                 while (server) {
654                         LM_DBG("initializing socket for '%s:%d'\n", server->host, server->port);
655                         server->sock = socket(AF_INET, SOCK_DGRAM, 0);
656                         if (server->sock<0) {
657                                 LM_ERR("socket() failed with errno=%d (%s).\n", errno, strerror(errno));
658                                 return -1;
659                         }
660
661                         memset(&(server->dstaddr), 0, sizeof(server->dstaddr));
662                         server->dstaddr.sin_family = AF_INET;
663                         server->dstaddr.sin_port = htons(server->port);
664                         hp = gethostbyname(server->host);
665                         if (hp == NULL) {
666                                 LM_ERR("gethostbyname(%s) failed with h_errno=%d.\n", server->host, h_errno);
667                                 close(server->sock);
668                                 server->sock=0;
669                                 return -1;
670                         }
671                         memcpy(&(server->dstaddr.sin_addr.s_addr), hp->h_addr, hp->h_length);
672                         server->dstaddrlen=sizeof(server->dstaddr);
673
674                         server = server->next;
675                         server_list->nserver++;
676                 }
677
678                 LM_DBG("got %d server in list\n", server_list->nserver);
679                 server_list->fds = pkg_malloc(sizeof(struct pollfd)*server_list->nserver);
680                 if (server_list->fds == NULL) {
681                         PKG_MEM_ERROR;
682                         return -1;
683                 }
684                 memset(server_list->fds, 0, sizeof(struct pollfd)*server_list->nserver);
685
686                 i=0;
687                 server = server_list->head;
688                 while (server) {
689                         server_list->fds[i].fd=server->sock;
690                         server_list->fds[i].events=POLLIN;
691                         server = server->next;
692                         i++;
693                 }
694         }
695         return 0;
696 }
697
698
699 /*!
700  * Destroys sockets for all servers in server list.
701  */
702 static void destroy_server_socket(void)
703 {
704         if (server_list) {
705                 struct server_item_t *server = server_list->head;
706                 while (server) {
707                         if (server->sock>0) close(server->sock);
708                         server = server->next;
709                 }
710                 if (server_list->fds) pkg_free(server_list->fds);
711         }
712 }
713
714
715 static void pdb_rpc_status(rpc_t* rpc, void* ctx)
716 {
717         void *vh;
718         if (active == NULL) {
719                 rpc->fault(ctx, 500, "Active field not initialized");
720                 return;
721         }
722         if (rpc->add(ctx, "{", &vh) < 0) {
723                 rpc->fault(ctx, 500, "Server error");
724                 return;
725         }
726         rpc->struct_add(vh, "ds",
727                         "active", *active,
728                         "status", (*active)?"active":"inactive");
729 }
730
731 static void pdb_rpc_activate(rpc_t* rpc, void* ctx)
732 {
733         if (active == NULL) {
734                 rpc->fault(ctx, 500, "Active field not initialized");
735                 return;
736         }
737         *active=1;
738 }
739
740 static void pdb_rpc_deactivate(rpc_t* rpc, void* ctx)
741 {
742         if (active == NULL) {
743                 rpc->fault(ctx, 500, "Active field not initialized");
744                 return;
745         }
746         *active=0;
747 }
748
749 static const char* pdb_rpc_status_doc[2] = {
750         "Get the pdb status.",
751         0
752 };
753
754 static const char* pdb_rpc_activate_doc[2] = {
755         "Activate pdb.",
756         0
757 };
758
759 static const char* pdb_rpc_deactivate_doc[2] = {
760         "Deactivate pdb.",
761         0
762 };
763
764 rpc_export_t pdb_rpc[] = {
765         {"pdb.status", pdb_rpc_status, pdb_rpc_status_doc, 0},
766         {"pdb.activate", pdb_rpc_activate, pdb_rpc_activate_doc, 0},
767         {"pdb.deactivate", pdb_rpc_deactivate, pdb_rpc_deactivate_doc, 0},
768         {0, 0, 0, 0}
769 };
770
771 static int pdb_rpc_init(void)
772 {
773         if (rpc_register_array(pdb_rpc)!=0)
774         {
775                 LM_ERR("failed to register RPC commands\n");
776                 return -1;
777         }
778         return 0;
779 }
780
781 static int mod_init(void)
782 {
783         if(pdb_rpc_init()<0) {
784                 LM_ERR("failed to register RPC commands\n");
785                 return -1;
786         }
787         active = shm_malloc(sizeof(*active));
788         if (active == NULL) {
789                 SHM_MEM_ERROR;
790                 return -1;
791         }
792         *active=1;
793
794         if (init_server_list() != 0) {
795                 shm_free(active);
796                 return -1;
797         }
798
799     global_id = (uint16_t*)shm_malloc(sizeof(uint16_t));
800
801     return 0;
802 }
803
804 static int child_init (int rank)
805 {
806         if(rank==PROC_INIT || rank==PROC_TCP_MAIN)
807                 return 0;
808         return rpc_child_init();
809 }
810
811
812 static int pdb_child_initialized = 0;
813
814 static int rpc_child_init(void)
815 {
816         if(pdb_child_initialized)
817                 return 0;
818         if (init_server_socket() != 0) return -1;
819         pdb_child_initialized = 1;
820         return 0;
821 }
822
823
824 static void mod_destroy(void)
825 {
826         destroy_server_socket();
827         destroy_server_list();
828         if (active) shm_free(active);
829 }