00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "asterisk.h"
00029
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 134595 $")
00031
00032 #include <stdlib.h>
00033 #include <stdio.h>
00034 #include <unistd.h>
00035 #include <netinet/in.h>
00036 #include <arpa/inet.h>
00037 #include <sys/socket.h>
00038 #include <string.h>
00039 #include <errno.h>
00040 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(SOLARIS) || defined(__Darwin__)
00041 #include <sys/types.h>
00042 #include <netinet/in_systm.h>
00043 #endif
00044 #include <netinet/ip.h>
00045 #include <sys/ioctl.h>
00046 #include <netinet/in.h>
00047 #include <net/if.h>
00048 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__Darwin__)
00049 #include <net/if_dl.h>
00050 #include <ifaddrs.h>
00051 #endif
00052 #include <zlib.h>
00053 #include <sys/signal.h>
00054 #include <pthread.h>
00055
00056 #include "asterisk/file.h"
00057 #include "asterisk/logger.h"
00058 #include "asterisk/channel.h"
00059 #include "asterisk/config.h"
00060 #include "asterisk/options.h"
00061 #include "asterisk/pbx.h"
00062 #include "asterisk/module.h"
00063 #include "asterisk/frame.h"
00064 #include "asterisk/file.h"
00065 #include "asterisk/cli.h"
00066 #include "asterisk/lock.h"
00067 #include "asterisk/md5.h"
00068 #include "asterisk/dundi.h"
00069 #include "asterisk/sched.h"
00070 #include "asterisk/io.h"
00071 #include "asterisk/utils.h"
00072 #include "asterisk/crypto.h"
00073 #include "asterisk/astdb.h"
00074 #include "asterisk/acl.h"
00075 #include "asterisk/aes.h"
00076
00077 #include "dundi-parser.h"
00078
00079 #define MAX_RESULTS 64
00080
00081 #define MAX_PACKET_SIZE 8192
00082
00083 #define DUNDI_MODEL_INBOUND (1 << 0)
00084 #define DUNDI_MODEL_OUTBOUND (1 << 1)
00085 #define DUNDI_MODEL_SYMMETRIC (DUNDI_MODEL_INBOUND | DUNDI_MODEL_OUTBOUND)
00086
00087
00088 #define DUNDI_TIMING_HISTORY 10
00089
00090 #define FLAG_ISREG (1 << 0)
00091 #define FLAG_DEAD (1 << 1)
00092 #define FLAG_FINAL (1 << 2)
00093 #define FLAG_ISQUAL (1 << 3)
00094 #define FLAG_ENCRYPT (1 << 4)
00095 #define FLAG_SENDFULLKEY (1 << 5)
00096 #define FLAG_STOREHIST (1 << 6)
00097
00098 #define DUNDI_FLAG_INTERNAL_NOPARTIAL (1 << 17)
00099
00100 #if 0
00101 #define DUNDI_SECRET_TIME 15
00102 #else
00103 #define DUNDI_SECRET_TIME DUNDI_DEFAULT_CACHE_TIME
00104 #endif
00105
00106 #define KEY_OUT 0
00107 #define KEY_IN 1
00108
00109 static struct io_context *io;
00110 static struct sched_context *sched;
00111 static int netsocket = -1;
00112 static pthread_t netthreadid = AST_PTHREADT_NULL;
00113 static pthread_t precachethreadid = AST_PTHREADT_NULL;
00114 static int tos = 0;
00115 static int dundidebug = 0;
00116 static int authdebug = 0;
00117 static int dundi_ttl = DUNDI_DEFAULT_TTL;
00118 static int dundi_key_ttl = DUNDI_DEFAULT_KEY_EXPIRE;
00119 static int dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME;
00120 static int global_autokilltimeout = 0;
00121 static dundi_eid global_eid;
00122 static int default_expiration = 60;
00123 static int global_storehistory = 0;
00124 static char dept[80];
00125 static char org[80];
00126 static char locality[80];
00127 static char stateprov[80];
00128 static char country[80];
00129 static char email[80];
00130 static char phone[80];
00131 static char secretpath[80];
00132 static char cursecret[80];
00133 static char ipaddr[80];
00134 static time_t rotatetime;
00135 static dundi_eid empty_eid = { { 0, 0, 0, 0, 0, 0 } };
00136 static int dundi_shutdown = 0;
00137
00138 struct permission {
00139 AST_LIST_ENTRY(permission) list;
00140 int allow;
00141 char name[0];
00142 };
00143
00144 struct dundi_packet {
00145 AST_LIST_ENTRY(dundi_packet) list;
00146 struct dundi_hdr *h;
00147 int datalen;
00148 struct dundi_transaction *parent;
00149 int retransid;
00150 int retrans;
00151 unsigned char data[0];
00152 };
00153
00154 struct dundi_hint_metadata {
00155 unsigned short flags;
00156 char exten[AST_MAX_EXTENSION];
00157 };
00158
00159 struct dundi_precache_queue {
00160 AST_LIST_ENTRY(dundi_precache_queue) list;
00161 char *context;
00162 time_t expiration;
00163 char number[0];
00164 };
00165
00166 struct dundi_request;
00167
00168 struct dundi_transaction {
00169 struct sockaddr_in addr;
00170 struct timeval start;
00171 dundi_eid eids[DUNDI_MAX_STACK + 1];
00172 int eidcount;
00173 dundi_eid us_eid;
00174 dundi_eid them_eid;
00175 aes_encrypt_ctx ecx;
00176 aes_decrypt_ctx dcx;
00177 unsigned int flags;
00178 int ttl;
00179 int thread;
00180 int retranstimer;
00181 int autokillid;
00182 int autokilltimeout;
00183 unsigned short strans;
00184 unsigned short dtrans;
00185 unsigned char iseqno;
00186 unsigned char oiseqno;
00187 unsigned char oseqno;
00188 unsigned char aseqno;
00189 AST_LIST_HEAD_NOLOCK(packetlist, dundi_packet) packets;
00190 struct packetlist lasttrans;
00191 struct dundi_request *parent;
00192 AST_LIST_ENTRY(dundi_transaction) parentlist;
00193 AST_LIST_ENTRY(dundi_transaction) all;
00194 };
00195
00196 struct dundi_request {
00197 char dcontext[AST_MAX_EXTENSION];
00198 char number[AST_MAX_EXTENSION];
00199 dundi_eid query_eid;
00200 dundi_eid root_eid;
00201 struct dundi_result *dr;
00202 struct dundi_entity_info *dei;
00203 struct dundi_hint_metadata *hmd;
00204 int maxcount;
00205 int respcount;
00206 int expiration;
00207 int cbypass;
00208 int pfds[2];
00209 unsigned long crc32;
00210 AST_LIST_HEAD_NOLOCK(, dundi_transaction) trans;
00211 AST_LIST_ENTRY(dundi_request) list;
00212 };
00213
00214 struct dundi_mapping {
00215 char dcontext[AST_MAX_EXTENSION];
00216 char lcontext[AST_MAX_EXTENSION];
00217 int weight;
00218 int options;
00219 int tech;
00220 int dead;
00221 char dest[AST_MAX_EXTENSION];
00222 AST_LIST_ENTRY(dundi_mapping) list;
00223 };
00224
00225 struct dundi_peer {
00226 dundi_eid eid;
00227 struct sockaddr_in addr;
00228 AST_LIST_HEAD_NOLOCK(permissionlist, permission) permit;
00229 struct permissionlist include;
00230 dundi_eid us_eid;
00231 char inkey[80];
00232 char outkey[80];
00233 int dead;
00234 int registerid;
00235 int qualifyid;
00236 int sentfullkey;
00237 int order;
00238 unsigned char txenckey[256];
00239 unsigned char rxenckey[256];
00240 unsigned long us_keycrc32;
00241 aes_encrypt_ctx us_ecx;
00242 aes_decrypt_ctx us_dcx;
00243 unsigned long them_keycrc32;
00244 aes_encrypt_ctx them_ecx;
00245 aes_decrypt_ctx them_dcx;
00246 time_t keyexpire;
00247 int registerexpire;
00248 int lookuptimes[DUNDI_TIMING_HISTORY];
00249 char *lookups[DUNDI_TIMING_HISTORY];
00250 int avgms;
00251 struct dundi_transaction *regtrans;
00252 struct dundi_transaction *qualtrans;
00253 int model;
00254 int pcmodel;
00255
00256 unsigned int dynamic:1;
00257 int lastms;
00258 int maxms;
00259 struct timeval qualtx;
00260 AST_LIST_ENTRY(dundi_peer) list;
00261 };
00262
00263 static AST_LIST_HEAD_STATIC(peers, dundi_peer);
00264 static AST_LIST_HEAD_STATIC(pcq, dundi_precache_queue);
00265 static AST_LIST_HEAD_NOLOCK_STATIC(mappings, dundi_mapping);
00266 static AST_LIST_HEAD_NOLOCK_STATIC(requests, dundi_request);
00267 static AST_LIST_HEAD_NOLOCK_STATIC(alltrans, dundi_transaction);
00268
00269
00270
00271
00272
00273
00274 static struct dundi_peer *any_peer;
00275
00276 static int dundi_xmit(struct dundi_packet *pack);
00277
00278 static void dundi_debug_output(const char *data)
00279 {
00280 if (dundidebug)
00281 ast_verbose("%s", data);
00282 }
00283
00284 static void dundi_error_output(const char *data)
00285 {
00286 ast_log(LOG_WARNING, "%s", data);
00287 }
00288
00289 static int has_permission(struct permissionlist *permlist, char *cont)
00290 {
00291 struct permission *perm;
00292 int res = 0;
00293
00294 AST_LIST_TRAVERSE(permlist, perm, list) {
00295 if (!strcasecmp(perm->name, "all") || !strcasecmp(perm->name, cont))
00296 res = perm->allow;
00297 }
00298
00299 return res;
00300 }
00301
00302 static char *tech2str(int tech)
00303 {
00304 switch(tech) {
00305 case DUNDI_PROTO_NONE:
00306 return "None";
00307 case DUNDI_PROTO_IAX:
00308 return "IAX2";
00309 case DUNDI_PROTO_SIP:
00310 return "SIP";
00311 case DUNDI_PROTO_H323:
00312 return "H323";
00313 default:
00314 return "Unknown";
00315 }
00316 }
00317
00318 static int str2tech(char *str)
00319 {
00320 if (!strcasecmp(str, "IAX") || !strcasecmp(str, "IAX2"))
00321 return DUNDI_PROTO_IAX;
00322 else if (!strcasecmp(str, "SIP"))
00323 return DUNDI_PROTO_SIP;
00324 else if (!strcasecmp(str, "H323"))
00325 return DUNDI_PROTO_H323;
00326 else
00327 return -1;
00328 }
00329
00330 static int dundi_lookup_internal(struct dundi_result *result, int maxret, struct ast_channel *chan, const char *dcontext, const char *number, int ttl, int blockempty, struct dundi_hint_metadata *md, int *expiration, int cybpass, int modeselect, dundi_eid *skip, dundi_eid *avoid[], int direct[]);
00331 static int dundi_precache_internal(const char *context, const char *number, int ttl, dundi_eid *avoids[]);
00332 static struct dundi_transaction *create_transaction(struct dundi_peer *p);
00333 static struct dundi_transaction *find_transaction(struct dundi_hdr *hdr, struct sockaddr_in *sin)
00334 {
00335 struct dundi_transaction *trans;
00336
00337
00338 AST_LIST_TRAVERSE(&alltrans, trans, all) {
00339 if (!inaddrcmp(&trans->addr, sin) &&
00340 ((trans->strans == (ntohs(hdr->dtrans) & 32767)) ||
00341 ((trans->dtrans == (ntohs(hdr->strans) & 32767)) && (!hdr->dtrans))) ) {
00342 if (hdr->strans)
00343 trans->dtrans = ntohs(hdr->strans) & 32767;
00344 break;
00345 }
00346 }
00347 if (!trans) {
00348 switch(hdr->cmdresp & 0x7f) {
00349 case DUNDI_COMMAND_DPDISCOVER:
00350 case DUNDI_COMMAND_EIDQUERY:
00351 case DUNDI_COMMAND_PRECACHERQ:
00352 case DUNDI_COMMAND_REGREQ:
00353 case DUNDI_COMMAND_NULL:
00354 case DUNDI_COMMAND_ENCRYPT:
00355 if (hdr->strans) {
00356
00357 trans = create_transaction(NULL);
00358 if (trans) {
00359 memcpy(&trans->addr, sin, sizeof(trans->addr));
00360 trans->dtrans = ntohs(hdr->strans) & 32767;
00361 } else
00362 ast_log(LOG_WARNING, "Out of memory!\n");
00363 }
00364 break;
00365 default:
00366 break;
00367 }
00368 }
00369 return trans;
00370 }
00371
00372 static int dundi_send(struct dundi_transaction *trans, int cmdresp, int flags, int final, struct dundi_ie_data *ied);
00373
00374 static int dundi_ack(struct dundi_transaction *trans, int final)
00375 {
00376 return dundi_send(trans, DUNDI_COMMAND_ACK, 0, final, NULL);
00377 }
00378 static void dundi_reject(struct dundi_hdr *h, struct sockaddr_in *sin)
00379 {
00380 struct {
00381 struct dundi_packet pack;
00382 struct dundi_hdr hdr;
00383 } tmp;
00384 struct dundi_transaction trans;
00385
00386 if (h->cmdresp == DUNDI_COMMAND_INVALID)
00387 return;
00388 memset(&tmp, 0, sizeof(tmp));
00389 memset(&trans, 0, sizeof(trans));
00390 memcpy(&trans.addr, sin, sizeof(trans.addr));
00391 tmp.hdr.strans = h->dtrans;
00392 tmp.hdr.dtrans = h->strans;
00393 tmp.hdr.iseqno = h->oseqno;
00394 tmp.hdr.oseqno = h->iseqno;
00395 tmp.hdr.cmdresp = DUNDI_COMMAND_INVALID;
00396 tmp.hdr.cmdflags = 0;
00397 tmp.pack.h = (struct dundi_hdr *)tmp.pack.data;
00398 tmp.pack.datalen = sizeof(struct dundi_hdr);
00399 tmp.pack.parent = &trans;
00400 dundi_xmit(&tmp.pack);
00401 }
00402
00403 static void reset_global_eid(void)
00404 {
00405 #if defined(SIOCGIFHWADDR)
00406 int x,s;
00407 char eid_str[20];
00408 struct ifreq ifr;
00409
00410 s = socket(AF_INET, SOCK_STREAM, 0);
00411 if (s > 0) {
00412 x = 0;
00413 for(x=0;x<10;x++) {
00414 memset(&ifr, 0, sizeof(ifr));
00415 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "eth%d", x);
00416 if (!ioctl(s, SIOCGIFHWADDR, &ifr)) {
00417 memcpy(&global_eid, ((unsigned char *)&ifr.ifr_hwaddr) + 2, sizeof(global_eid));
00418 ast_log(LOG_DEBUG, "Seeding global EID '%s' from '%s' using 'siocgifhwaddr'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid), ifr.ifr_name);
00419 close(s);
00420 return;
00421 }
00422 }
00423 close(s);
00424 }
00425 #else
00426 #if defined(ifa_broadaddr) && !defined(SOLARIS)
00427 char eid_str[20];
00428 struct ifaddrs *ifap;
00429
00430 if (getifaddrs(&ifap) == 0) {
00431 struct ifaddrs *p;
00432 for (p = ifap; p; p = p->ifa_next) {
00433 if ((p->ifa_addr->sa_family == AF_LINK) && !(p->ifa_flags & IFF_LOOPBACK) && (p->ifa_flags & IFF_RUNNING)) {
00434 struct sockaddr_dl* sdp = (struct sockaddr_dl*) p->ifa_addr;
00435 memcpy(&(global_eid.eid), sdp->sdl_data + sdp->sdl_nlen, 6);
00436 ast_log(LOG_DEBUG, "Seeding global EID '%s' from '%s' using 'getifaddrs'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid), p->ifa_name);
00437 freeifaddrs(ifap);
00438 return;
00439 }
00440 }
00441 freeifaddrs(ifap);
00442 }
00443 #endif
00444 #endif
00445 ast_log(LOG_NOTICE, "No ethernet interface found for seeding global EID. You will have to set it manually.\n");
00446 }
00447
00448 static int get_trans_id(void)
00449 {
00450 struct dundi_transaction *t;
00451 int stid = (ast_random() % 32766) + 1;
00452 int tid = stid;
00453
00454 do {
00455 AST_LIST_TRAVERSE(&alltrans, t, all) {
00456 if (t->strans == tid)
00457 break;
00458 }
00459 if (!t)
00460 return tid;
00461 tid = (tid % 32766) + 1;
00462 } while (tid != stid);
00463
00464 return 0;
00465 }
00466
00467 static int reset_transaction(struct dundi_transaction *trans)
00468 {
00469 int tid;
00470 tid = get_trans_id();
00471 if (tid < 1)
00472 return -1;
00473 trans->strans = tid;
00474 trans->dtrans = 0;
00475 trans->iseqno = 0;
00476 trans->oiseqno = 0;
00477 trans->oseqno = 0;
00478 trans->aseqno = 0;
00479 ast_clear_flag(trans, FLAG_FINAL);
00480 return 0;
00481 }
00482
00483 static struct dundi_peer *find_peer(dundi_eid *eid)
00484 {
00485 struct dundi_peer *cur = NULL;
00486
00487 if (!eid)
00488 eid = &empty_eid;
00489
00490 AST_LIST_TRAVERSE(&peers, cur, list) {
00491 if (!dundi_eid_cmp(&cur->eid,eid))
00492 break;
00493 }
00494
00495 if (!cur && any_peer)
00496 cur = any_peer;
00497
00498 return cur;
00499 }
00500
00501 static void build_iv(unsigned char *iv)
00502 {
00503
00504 unsigned int *fluffy;
00505 int x;
00506 fluffy = (unsigned int *)(iv);
00507 for (x=0;x<4;x++)
00508 fluffy[x] = ast_random();
00509 }
00510
00511 struct dundi_query_state {
00512 dundi_eid *eids[DUNDI_MAX_STACK + 1];
00513 int directs[DUNDI_MAX_STACK + 1];
00514 dundi_eid reqeid;
00515 char called_context[AST_MAX_EXTENSION];
00516 char called_number[AST_MAX_EXTENSION];
00517 struct dundi_mapping *maps;
00518 int nummaps;
00519 int nocache;
00520 struct dundi_transaction *trans;
00521 void *chal;
00522 int challen;
00523 int ttl;
00524 char fluffy[0];
00525 };
00526
00527 static int dundi_lookup_local(struct dundi_result *dr, struct dundi_mapping *map, char *called_number, dundi_eid *us_eid, int anscnt, struct dundi_hint_metadata *hmd)
00528 {
00529 struct ast_flags flags = {0};
00530 int x;
00531 if (!ast_strlen_zero(map->lcontext)) {
00532 if (ast_exists_extension(NULL, map->lcontext, called_number, 1, NULL))
00533 ast_set_flag(&flags, DUNDI_FLAG_EXISTS);
00534 if (ast_canmatch_extension(NULL, map->lcontext, called_number, 1, NULL))
00535 ast_set_flag(&flags, DUNDI_FLAG_CANMATCH);
00536 if (ast_matchmore_extension(NULL, map->lcontext, called_number, 1, NULL))
00537 ast_set_flag(&flags, DUNDI_FLAG_MATCHMORE);
00538 if (ast_ignore_pattern(map->lcontext, called_number))
00539 ast_set_flag(&flags, DUNDI_FLAG_IGNOREPAT);
00540
00541
00542 if (ast_test_flag(&flags, AST_FLAGS_ALL))
00543 ast_clear_flag_nonstd(hmd, DUNDI_HINT_DONT_ASK);
00544
00545 if (map->options & DUNDI_FLAG_INTERNAL_NOPARTIAL) {
00546
00547 ast_clear_flag(&flags, DUNDI_FLAG_MATCHMORE|DUNDI_FLAG_CANMATCH);
00548 }
00549 if (ast_test_flag(&flags, AST_FLAGS_ALL)) {
00550 struct varshead headp;
00551 struct ast_var_t *newvariable;
00552 ast_set_flag(&flags, map->options & 0xffff);
00553 ast_copy_flags(dr + anscnt, &flags, AST_FLAGS_ALL);
00554 dr[anscnt].techint = map->tech;
00555 dr[anscnt].weight = map->weight;
00556 dr[anscnt].expiration = dundi_cache_time;
00557 ast_copy_string(dr[anscnt].tech, tech2str(map->tech), sizeof(dr[anscnt].tech));
00558 dr[anscnt].eid = *us_eid;
00559 dundi_eid_to_str(dr[anscnt].eid_str, sizeof(dr[anscnt].eid_str), &dr[anscnt].eid);
00560 if (ast_test_flag(&flags, DUNDI_FLAG_EXISTS)) {
00561 AST_LIST_HEAD_INIT_NOLOCK(&headp);
00562 newvariable = ast_var_assign("NUMBER", called_number);
00563 AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00564 newvariable = ast_var_assign("EID", dr[anscnt].eid_str);
00565 AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00566 newvariable = ast_var_assign("SECRET", cursecret);
00567 AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00568 newvariable = ast_var_assign("IPADDR", ipaddr);
00569 AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
00570 pbx_substitute_variables_varshead(&headp, map->dest, dr[anscnt].dest, sizeof(dr[anscnt].dest));
00571 while ((newvariable = AST_LIST_REMOVE_HEAD(&headp, entries)))
00572 ast_var_delete(newvariable);
00573 } else
00574 dr[anscnt].dest[0] = '\0';
00575 anscnt++;
00576 } else {
00577
00578
00579 char tmp[AST_MAX_EXTENSION + 1] = "";
00580 for (x = 0; x < (sizeof(tmp) - 1); x++) {
00581 tmp[x] = called_number[x];
00582 if (!tmp[x])
00583 break;
00584 if (!ast_canmatch_extension(NULL, map->lcontext, tmp, 1, NULL)) {
00585
00586
00587 if (strlen(tmp) > strlen(hmd->exten)) {
00588 ast_copy_string(hmd->exten, tmp, sizeof(hmd->exten));
00589 }
00590 break;
00591 }
00592 }
00593 }
00594 }
00595 return anscnt;
00596 }
00597
00598 static void destroy_trans(struct dundi_transaction *trans, int fromtimeout);
00599
00600 static void *dundi_lookup_thread(void *data)
00601 {
00602 struct dundi_query_state *st = data;
00603 struct dundi_result dr[MAX_RESULTS];
00604 struct dundi_ie_data ied;
00605 struct dundi_hint_metadata hmd;
00606 char eid_str[20];
00607 int res, x;
00608 int ouranswers=0;
00609 int max = 999999;
00610 int expiration = dundi_cache_time;
00611
00612 ast_log(LOG_DEBUG, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context,
00613 st->eids[0] ? dundi_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) : "ourselves");
00614 memset(&ied, 0, sizeof(ied));
00615 memset(&dr, 0, sizeof(dr));
00616 memset(&hmd, 0, sizeof(hmd));
00617
00618 hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
00619 for (x=0;x<st->nummaps;x++)
00620 ouranswers = dundi_lookup_local(dr, st->maps + x, st->called_number, &st->trans->us_eid, ouranswers, &hmd);
00621 if (ouranswers < 0)
00622 ouranswers = 0;
00623 for (x=0;x<ouranswers;x++) {
00624 if (dr[x].weight < max)
00625 max = dr[x].weight;
00626 }
00627
00628 if (max) {
00629
00630 res = dundi_lookup_internal(dr + ouranswers, MAX_RESULTS - ouranswers, NULL, st->called_context, st->called_number, st->ttl, 1, &hmd, &expiration, st->nocache, 0, NULL, st->eids, st->directs);
00631 if (res > 0) {
00632
00633 ouranswers += res;
00634 } else {
00635 if ((res < -1) && (!ouranswers))
00636 dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_DUPLICATE, "Duplicate Request Pending");
00637 }
00638 }
00639 AST_LIST_LOCK(&peers);
00640
00641 if (!ast_test_flag_nonstd(&hmd, DUNDI_HINT_DONT_ASK))
00642 hmd.exten[0] = '\0';
00643 if (ast_test_flag(st->trans, FLAG_DEAD)) {
00644 ast_log(LOG_DEBUG, "Our transaction went away!\n");
00645 st->trans->thread = 0;
00646 destroy_trans(st->trans, 0);
00647 } else {
00648 for (x=0;x<ouranswers;x++) {
00649
00650 if (dr[x].expiration && (expiration > dr[x].expiration))
00651 expiration = dr[x].expiration;
00652 dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest);
00653 }
00654 dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
00655 dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration);
00656 dundi_send(st->trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
00657 st->trans->thread = 0;
00658 }
00659 AST_LIST_UNLOCK(&peers);
00660 free(st);
00661 return NULL;
00662 }
00663
00664 static void *dundi_precache_thread(void *data)
00665 {
00666 struct dundi_query_state *st = data;
00667 struct dundi_ie_data ied;
00668 struct dundi_hint_metadata hmd;
00669 char eid_str[20];
00670
00671 ast_log(LOG_DEBUG, "Whee, precaching '%s@%s' for '%s'\n", st->called_number, st->called_context,
00672 st->eids[0] ? dundi_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) : "ourselves");
00673 memset(&ied, 0, sizeof(ied));
00674
00675
00676 dundi_precache_internal(st->called_context, st->called_number, st->ttl, st->eids);
00677
00678 AST_LIST_LOCK(&peers);
00679
00680 if (!ast_test_flag_nonstd(&hmd, DUNDI_HINT_DONT_ASK))
00681 hmd.exten[0] = '\0';
00682 if (ast_test_flag(st->trans, FLAG_DEAD)) {
00683 ast_log(LOG_DEBUG, "Our transaction went away!\n");
00684 st->trans->thread = 0;
00685 destroy_trans(st->trans, 0);
00686 } else {
00687 dundi_send(st->trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
00688 st->trans->thread = 0;
00689 }
00690 AST_LIST_UNLOCK(&peers);
00691 free(st);
00692 return NULL;
00693 }
00694
00695 static int dundi_query_eid_internal(struct dundi_entity_info *dei, const char *dcontext, dundi_eid *eid, struct dundi_hint_metadata *hmd, int ttl, int blockempty, dundi_eid *avoid[]);
00696
00697 static void *dundi_query_thread(void *data)
00698 {
00699 struct dundi_query_state *st = data;
00700 struct dundi_entity_info dei;
00701 struct dundi_ie_data ied;
00702 struct dundi_hint_metadata hmd;
00703 char eid_str[20];
00704 int res;
00705 ast_log(LOG_DEBUG, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context,
00706 st->eids[0] ? dundi_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) : "ourselves");
00707 memset(&ied, 0, sizeof(ied));
00708 memset(&dei, 0, sizeof(dei));
00709 memset(&hmd, 0, sizeof(hmd));
00710 if (!dundi_eid_cmp(&st->trans->us_eid, &st->reqeid)) {
00711
00712 ast_log(LOG_DEBUG, "Neat, someone look for us!\n");
00713 ast_copy_string(dei.orgunit, dept, sizeof(dei.orgunit));
00714 ast_copy_string(dei.org, org, sizeof(dei.org));
00715 ast_copy_string(dei.locality, locality, sizeof(dei.locality));
00716 ast_copy_string(dei.stateprov, stateprov, sizeof(dei.stateprov));
00717 ast_copy_string(dei.country, country, sizeof(dei.country));
00718 ast_copy_string(dei.email, email, sizeof(dei.email));
00719 ast_copy_string(dei.phone, phone, sizeof(dei.phone));
00720 res = 1;
00721 } else {
00722
00723 res = dundi_query_eid_internal(&dei, st->called_context, &st->reqeid, &hmd, st->ttl, 1, st->eids);
00724 }
00725 AST_LIST_LOCK(&peers);
00726 if (ast_test_flag(st->trans, FLAG_DEAD)) {
00727 ast_log(LOG_DEBUG, "Our transaction went away!\n");
00728 st->trans->thread = 0;
00729 destroy_trans(st->trans, 0);
00730 } else {
00731 if (res) {
00732 dundi_ie_append_str(&ied, DUNDI_IE_DEPARTMENT, dei.orgunit);
00733 dundi_ie_append_str(&ied, DUNDI_IE_ORGANIZATION, dei.org);
00734 dundi_ie_append_str(&ied, DUNDI_IE_LOCALITY, dei.locality);
00735 dundi_ie_append_str(&ied, DUNDI_IE_STATE_PROV, dei.stateprov);
00736 dundi_ie_append_str(&ied, DUNDI_IE_COUNTRY, dei.country);
00737 dundi_ie_append_str(&ied, DUNDI_IE_EMAIL, dei.email);
00738 dundi_ie_append_str(&ied, DUNDI_IE_PHONE, dei.phone);
00739 if (!ast_strlen_zero(dei.ipaddr))
00740 dundi_ie_append_str(&ied, DUNDI_IE_IPADDR, dei.ipaddr);
00741 }
00742 dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
00743 dundi_send(st->trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
00744 st->trans->thread = 0;
00745 }
00746 AST_LIST_UNLOCK(&peers);
00747 free(st);
00748 return NULL;
00749 }
00750
00751 static int dundi_answer_entity(struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext)
00752 {
00753 struct dundi_query_state *st;
00754 int totallen;
00755 int x;
00756 int skipfirst=0;
00757 struct dundi_ie_data ied;
00758 char eid_str[20];
00759 char *s;
00760 pthread_t lookupthread;
00761 pthread_attr_t attr;
00762 if (ies->eidcount > 1) {
00763
00764
00765
00766
00767 if (!dundi_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
00768 skipfirst = 1;
00769 }
00770 totallen = sizeof(struct dundi_query_state);
00771 totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
00772 st = ast_calloc(1, totallen);
00773 if (st) {
00774 ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context));
00775 memcpy(&st->reqeid, ies->reqeid, sizeof(st->reqeid));
00776 st->trans = trans;
00777 st->ttl = ies->ttl - 1;
00778 if (st->ttl < 0)
00779 st->ttl = 0;
00780 s = st->fluffy;
00781 for (x=skipfirst;ies->eids[x];x++) {
00782 st->eids[x-skipfirst] = (dundi_eid *)s;
00783 *st->eids[x-skipfirst] = *ies->eids[x];
00784 s += sizeof(dundi_eid);
00785 }
00786 ast_log(LOG_DEBUG, "Answering EID query for '%s@%s'!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), ies->reqeid), ies->called_context);
00787 pthread_attr_init(&attr);
00788 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00789 trans->thread = 1;
00790 if (ast_pthread_create(&lookupthread, &attr, dundi_query_thread, st)) {
00791 trans->thread = 0;
00792 ast_log(LOG_WARNING, "Unable to create thread!\n");
00793 free(st);
00794 memset(&ied, 0, sizeof(ied));
00795 dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
00796 dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
00797 pthread_attr_destroy(&attr);
00798