Convert the PBX core to use read/write locks. This yields a nifty performance improve...
[asterisk/asterisk.git] / pbx / pbx_dundi.c
index 241cc5d..62c2c55 100644 (file)
@@ -86,13 +86,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 /*! Keep times of last 10 lookups */
 #define DUNDI_TIMING_HISTORY   10
 
-#define FLAG_ISREG       (1 << 0)   /*!< Transaction is register request */
-#define FLAG_DEAD        (1 << 1)   /*!< Transaction is dead */
-#define FLAG_FINAL       (1 << 2)   /*!< Transaction has final message sent */
-#define FLAG_ISQUAL      (1 << 3)   /*!< Transaction is a qualification */
-#define FLAG_ENCRYPT     (1 << 4)   /*!< Transaction is encrypted wiht ECX/DCX */
-#define FLAG_SENDFULLKEY (1 << 5)   /*!< Send full key on transaction */
-#define FLAG_STOREHIST   (1 << 6)   /*!< Record historic performance */
+enum {
+       FLAG_ISREG =       (1 << 0),  /*!< Transaction is register request */
+       FLAG_DEAD =        (1 << 1),  /*!< Transaction is dead */
+       FLAG_FINAL =       (1 << 2),  /*!< Transaction has final message sent */
+       FLAG_ISQUAL =      (1 << 3),  /*!< Transaction is a qualification */
+       FLAG_ENCRYPT =     (1 << 4),  /*!< Transaction is encrypted wiht ECX/DCX */
+       FLAG_SENDFULLKEY = (1 << 5),  /*!< Send full key on transaction */
+       FLAG_STOREHIST =   (1 << 6),  /*!< Record historic performance */
+};
 
 #define DUNDI_FLAG_INTERNAL_NOPARTIAL (1 << 17)
 
@@ -102,9 +104,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #define DUNDI_SECRET_TIME DUNDI_DEFAULT_CACHE_TIME
 #endif
 
-#define KEY_OUT                        0
-#define KEY_IN                 1
-
 static struct io_context *io;
 static struct sched_context *sched;
 static int netsocket = -1;
@@ -331,31 +330,28 @@ static struct dundi_transaction *find_transaction(struct dundi_hdr *hdr, struct
                          ((trans->dtrans == (ntohs(hdr->strans) & 32767)) && (!hdr->dtrans))) /* We match their destination */) {
                          if (hdr->strans)
                                  trans->dtrans = ntohs(hdr->strans) & 32767;
-                         break;
+                         return trans;
                }
        }
-       if (!trans) {
-               switch(hdr->cmdresp & 0x7f) {
-               case DUNDI_COMMAND_DPDISCOVER:
-               case DUNDI_COMMAND_EIDQUERY:
-               case DUNDI_COMMAND_PRECACHERQ:
-               case DUNDI_COMMAND_REGREQ:
-               case DUNDI_COMMAND_NULL:
-               case DUNDI_COMMAND_ENCRYPT:
-                       if (hdr->strans) {      
-                               /* Create new transaction */
-                               trans = create_transaction(NULL);
-                               if (trans) {
-                                       memcpy(&trans->addr, sin, sizeof(trans->addr));
-                                       trans->dtrans = ntohs(hdr->strans) & 32767;
-                               } else
-                                       ast_log(LOG_WARNING, "Out of memory!\n");
-                       }
+       
+       switch(hdr->cmdresp & 0x7f) {
+       case DUNDI_COMMAND_DPDISCOVER:
+       case DUNDI_COMMAND_EIDQUERY:
+       case DUNDI_COMMAND_PRECACHERQ:
+       case DUNDI_COMMAND_REGREQ:
+       case DUNDI_COMMAND_NULL:
+       case DUNDI_COMMAND_ENCRYPT:
+               if (!hdr->strans)
                        break;
-               default:
+               /* Create new transaction */
+               if (!(trans = create_transaction(NULL)))
                        break;
-               }
+               memcpy(&trans->addr, sin, sizeof(trans->addr));
+               trans->dtrans = ntohs(hdr->strans) & 32767;
+       default:
+               break;
        }
+       
        return trans;
 }
 
@@ -393,26 +389,26 @@ static void dundi_reject(struct dundi_hdr *h, struct sockaddr_in *sin)
 static void reset_global_eid(void)
 {
 #if defined(SIOCGIFHWADDR)
-       int x,s;
+       int s, x = 0;
        char eid_str[20];
        struct ifreq ifr;
 
        s = socket(AF_INET, SOCK_STREAM, 0);
-       if (s > 0) {
-               x = 0;
-               for(x=0;x<10;x++) {
-                       memset(&ifr, 0, sizeof(ifr));
-                       snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "eth%d", x);
-                       if (!ioctl(s, SIOCGIFHWADDR, &ifr)) {
-                               memcpy(&global_eid, ((unsigned char *)&ifr.ifr_hwaddr) + 2, sizeof(global_eid));
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "Seeding global EID '%s' from '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid), ifr.ifr_name);
-                               close(s);
-                               return;
-                       }
-        }
-               close(s);
+       if (s < 0)
+               return;
+       for (x = 0; x < 10; x++) {
+               memset(&ifr, 0, sizeof(ifr));
+               snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "eth%d", x);
+               if (ioctl(s, SIOCGIFHWADDR, &ifr))
+                       continue;
+               memcpy(&global_eid, ((unsigned char *)&ifr.ifr_hwaddr) + 2, sizeof(global_eid));
+               if (option_debug) {
+                       ast_log(LOG_DEBUG, "Seeding global EID '%s' from '%s'\n", 
+                               dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid), ifr.ifr_name);
+               }
+               break;
        }
+       close(s);
 #else
 #if defined(ifa_broadaddr) && !defined(SOLARIS)
        char eid_str[20];
@@ -794,8 +790,10 @@ static int dundi_answer_entity(struct dundi_transaction *trans, struct dundi_ies
                        memset(&ied, 0, sizeof(ied));
                        dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
                        dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
+                       pthread_attr_destroy(&attr);
                        return -1;
                }
+               pthread_attr_destroy(&attr);
        } else {
                ast_log(LOG_WARNING, "Out of memory!\n");
                memset(&ied, 0, sizeof(ied));
@@ -1023,8 +1021,10 @@ static int dundi_prop_precache(struct dundi_transaction *trans, struct dundi_ies
                        memset(&ied, 0, sizeof(ied));
                        dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
                        dundi_send(trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
+                       pthread_attr_destroy(&attr);
                        return -1;
                }
+               pthread_attr_destroy(&attr);
        } else {
                ast_log(LOG_WARNING, "Out of memory!\n");
                memset(&ied, 0, sizeof(ied));
@@ -1110,8 +1110,10 @@ static int dundi_answer_query(struct dundi_transaction *trans, struct dundi_ies
                        memset(&ied, 0, sizeof(ied));
                        dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
                        dundi_send(trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
+                       pthread_attr_destroy(&attr);
                        return -1;
                }
+               pthread_attr_destroy(&attr);
        } else {
                ast_log(LOG_WARNING, "Out of memory!\n");
                memset(&ied, 0, sizeof(ied));
@@ -1986,8 +1988,8 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
        int res;
        struct dundi_hdr *h;
        char buf[MAX_PACKET_SIZE];
-       socklen_t len;
-       len = sizeof(sin);
+       socklen_t len = sizeof(sin);
+       
        res = recvfrom(netsocket, buf, sizeof(buf) - 1, 0,(struct sockaddr *) &sin, &len);
        if (res < 0) {
                if (errno != ECONNREFUSED)
@@ -1999,7 +2001,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                return 1;
        }
        buf[res] = '\0';
-       h = (struct dundi_hdr *)buf;
+       h = (struct dundi_hdr *) buf;
        if (dundidebug)
                dundi_showframe(h, 1, &sin, res - sizeof(struct dundi_hdr));
        AST_LIST_LOCK(&peers);
@@ -2635,71 +2637,71 @@ static int dundi_show_precache(int fd, int argc, char *argv[])
 #undef FORMAT2
 }
 
-static char debug_usage[] = 
+static const char debug_usage[] = 
 "Usage: dundi debug\n"
 "       Enables dumping of DUNDi packets for debugging purposes\n";
 
-static char no_debug_usage[] = 
+static const char no_debug_usage[] = 
 "Usage: dundi no debug\n"
 "       Disables dumping of DUNDi packets for debugging purposes\n";
 
-static char store_history_usage[] = 
+static const char store_history_usage[] = 
 "Usage: dundi store history\n"
 "       Enables storing of DUNDi requests and times for debugging\n"
 "purposes\n";
 
-static char no_store_history_usage[] = 
+static const char no_store_history_usage[] = 
 "Usage: dundi no store history\n"
 "       Disables storing of DUNDi requests and times for debugging\n"
 "purposes\n";
 
-static char show_peers_usage[] = 
+static const char show_peers_usage[] = 
 "Usage: dundi show peers\n"
 "       Lists all known DUNDi peers.\n";
 
-static char show_trans_usage[] = 
+static const char show_trans_usage[] = 
 "Usage: dundi show trans\n"
 "       Lists all known DUNDi transactions.\n";
 
-static char show_mappings_usage[] = 
+static const char show_mappings_usage[] = 
 "Usage: dundi show mappings\n"
 "       Lists all known DUNDi mappings.\n";
 
-static char show_precache_usage[] = 
+static const char show_precache_usage[] = 
 "Usage: dundi show precache\n"
 "       Lists all known DUNDi scheduled precache updates.\n";
 
-static char show_entityid_usage[] = 
+static const char show_entityid_usage[] = 
 "Usage: dundi show entityid\n"
 "       Displays the global entityid for this host.\n";
 
-static char show_peer_usage[] = 
+static const char show_peer_usage[] = 
 "Usage: dundi show peer [peer]\n"
 "       Provide a detailed description of a specifid DUNDi peer.\n";
 
-static char show_requests_usage[] = 
+static const char show_requests_usage[] = 
 "Usage: dundi show requests\n"
 "       Lists all known pending DUNDi requests.\n";
 
-static char lookup_usage[] =
+static const char lookup_usage[] =
 "Usage: dundi lookup <number>[@context] [bypass]\n"
 "       Lookup the given number within the given DUNDi context\n"
 "(or e164 if none is specified).  Bypasses cache if 'bypass'\n"
 "keyword is specified.\n";
 
-static char precache_usage[] =
+static const char precache_usage[] =
 "Usage: dundi precache <number>[@context]\n"
 "       Lookup the given number within the given DUNDi context\n"
 "(or e164 if none is specified) and precaches the results to any\n"
 "upstream DUNDi push servers.\n";
 
-static char query_usage[] =
+static const char query_usage[] =
 "Usage: dundi query <entity>[@context]\n"
 "       Attempts to retrieve contact information for a specific\n"
 "DUNDi entity identifier (EID) within a given DUNDi context (or\n"
 "e164 if none is specified).\n";
 
-static char flush_usage[] =
+static const char flush_usage[] =
 "Usage: dundi flush [stats]\n"
 "       Flushes DUNDi answer cache, used primarily for debug.  If\n"
 "'stats' is present, clears timer statistics instead of normal\n"
@@ -2778,22 +2780,23 @@ static struct dundi_transaction *create_transaction(struct dundi_peer *p)
        tid = get_trans_id();
        if (tid < 1)
                return NULL;
-       trans = ast_calloc(1, sizeof(*trans));
-       if (trans) {
-               if (global_storehistory) {
-                       trans->start = ast_tvnow();
-                       ast_set_flag(trans, FLAG_STOREHIST);
-               }
-               trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
-               trans->autokillid = -1;
-               if (p) {
-                       apply_peer(trans, p);
-                       if (!p->sentfullkey)
-                               ast_set_flag(trans, FLAG_SENDFULLKEY);
-               }
-               trans->strans = tid;
-               AST_LIST_INSERT_HEAD(&alltrans, trans, all);
+       if (!(trans = ast_calloc(1, sizeof(*trans))))
+               return NULL;
+
+       if (global_storehistory) {
+               trans->start = ast_tvnow();
+               ast_set_flag(trans, FLAG_STOREHIST);
        }
+       trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
+       trans->autokillid = -1;
+       if (p) {
+               apply_peer(trans, p);
+               if (!p->sentfullkey)
+                       ast_set_flag(trans, FLAG_SENDFULLKEY);
+       }
+       trans->strans = tid;
+       AST_LIST_INSERT_HEAD(&alltrans, trans, all);
+       
        return trans;
 }
 
@@ -3610,20 +3613,17 @@ static void dundi_precache_full(void)
 
        AST_LIST_TRAVERSE(&mappings, cur, list) {
                ast_log(LOG_NOTICE, "Should precache context '%s'\n", cur->dcontext);
-               ast_lock_contexts();
-               con = ast_walk_contexts(NULL);
-               while (con) {
-                       if (!strcasecmp(cur->lcontext, ast_get_context_name(con))) {
-                               /* Found the match, now queue them all up */
-                               ast_lock_context(con);
-                               e = ast_walk_context_extensions(con, NULL);
-                               while (e) {
-                                       reschedule_precache(ast_get_extension_name(e), cur->dcontext, 0);
-                                       e = ast_walk_context_extensions(con, e);
-                               }
-                               ast_unlock_context(con);
-                       }
-                       con = ast_walk_contexts(con);
+               ast_rdlock_contexts();
+               con = NULL;
+               while ((con = ast_walk_contexts(con))) {
+                       if (strcasecmp(cur->lcontext, ast_get_context_name(con)))
+                               continue;
+                       /* Found the match, now queue them all up */
+                       ast_rdlock_context(con);
+                       e = NULL;
+                       while ((e = ast_walk_context_extensions(con, e)))
+                               reschedule_precache(ast_get_extension_name(e), cur->dcontext, 0);
+                       ast_unlock_context(con);
                }
                ast_unlock_contexts();
        }
@@ -3761,7 +3761,7 @@ int dundi_query_eid(struct dundi_entity_info *dei, const char *dcontext, dundi_e
        return dundi_query_eid_internal(dei, dcontext, &eid, &hmd, dundi_ttl, 0, avoid);
 }
 
-static int dundifunc_read(struct ast_channel *chan, char *cmd, char *num, char *buf, size_t len)
+static int dundifunc_read(struct ast_channel *chan, const char *cmd, char *num, char *buf, size_t len)
 {
        char *context;
        char *opts;
@@ -4277,6 +4277,7 @@ static int dundi_exec(struct ast_channel *chan, const char *context, const char
        int res;
        int x=0;
        char req[1024];
+       const char *dundiargs;
        struct ast_app *dial;
        
        if (!strncasecmp(context, "macro-", 6)) {
@@ -4314,7 +4315,9 @@ static int dundi_exec(struct ast_channel *chan, const char *context, const char
        }
        if (x < res) {
                /* Got a hit! */
-               snprintf(req, sizeof(req), "%s/%s", results[x].tech, results[x].dest);
+               dundiargs = pbx_builtin_getvar_helper(chan, "DUNDIDIALARGS");
+               snprintf(req, sizeof(req), "%s/%s||%s", results[x].tech, results[x].dest, 
+                       S_OR(dundiargs, ""));
                dial = pbx_findapp("Dial");
                if (dial)
                        res = pbx_exec(chan, dial, req);
@@ -4507,13 +4510,15 @@ static int unload_module(void)
 static int reload(void)
 {
        struct sockaddr_in sin;
-       set_config("dundi.conf",&sin);
+
+       if (set_config("dundi.conf", &sin))
+               return -1;
+
        return 0;
 }
 
 static int load_module(void)
 {
-       int res = 0;
        struct sockaddr_in sin;
 
        dundi_set_output(dundi_debug_output);
@@ -4527,23 +4532,22 @@ static int load_module(void)
        io = io_context_create();
        sched = sched_context_create();
        
-       if (!io || !sched) {
-               ast_log(LOG_ERROR, "Out of memory\n");
-               return -1;
-       }
+       if (!io || !sched)
+               return AST_MODULE_LOAD_FAILURE;
 
-       if(set_config("dundi.conf",&sin))
+       if (set_config("dundi.conf", &sin))
                return AST_MODULE_LOAD_DECLINE;
 
        netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
        
        if (netsocket < 0) {
                ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
-               return -1;
+               return AST_MODULE_LOAD_FAILURE;
        }
-       if (bind(netsocket,(struct sockaddr *)&sin, sizeof(sin))) {
-               ast_log(LOG_ERROR, "Unable to bind to %s port %d: %s\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), strerror(errno));
-               return -1;
+       if (bind(netsocket, (struct sockaddr *) &sin, sizeof(sin))) {
+               ast_log(LOG_ERROR, "Unable to bind to %s port %d: %s\n", 
+                       ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), strerror(errno));
+               return AST_MODULE_LOAD_FAILURE;
        }
 
        if (option_verbose > 1)
@@ -4552,22 +4556,23 @@ static int load_module(void)
        if (setsockopt(netsocket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos))) 
                ast_log(LOG_WARNING, "Unable to set TOS to %d\n", tos);
        
-       res = start_network_thread();
-       if (res) {
+       if (start_network_thread()) {
                ast_log(LOG_ERROR, "Unable to start network thread\n");
                close(netsocket);
-               return -1;
+               return AST_MODULE_LOAD_FAILURE;
        }
-
-       if (option_verbose > 1)
-               ast_verbose(VERBOSE_PREFIX_2 "DUNDi Ready and Listening on %s port %d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
-
-       ast_cli_register_multiple(cli_dundi, sizeof(cli_dundi) / sizeof(struct ast_cli_entry));
+       
+       ast_cli_register_multiple(cli_dundi, sizeof(cli_dundi) / sizeof(*cli_dundi));
        if (ast_register_switch(&dundi_switch))
                ast_log(LOG_ERROR, "Unable to register DUNDi switch\n");
-       ast_custom_function_register(&dundi_function); 
+       ast_custom_function_register(&dundi_function);
        
-       return res;
+       if (option_verbose > 1) {
+               ast_verbose(VERBOSE_PREFIX_2 "DUNDi Ready and Listening on %s port %d\n", 
+                       ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+       }
+
+       return AST_MODULE_LOAD_SUCCESS;
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Distributed Universal Number Discovery (DUNDi)",