Index: pbx_dundi.c =================================================================== RCS file: /usr/cvsroot/asterisk/pbx/pbx_dundi.c,v retrieving revision 1.15 diff -u -r1.15 pbx_dundi.c --- pbx_dundi.c 29 Oct 2004 22:31:36 -0000 1.15 +++ pbx_dundi.c 30 Oct 2004 18:36:41 -0000 @@ -113,6 +113,12 @@ static dundi_eid global_eid; static int default_expiration = 60; static int global_storehistory = 0; +static int map_update_interval = 0; +static int map_updates_per_pkt = 45; +static int map_peering_sid = -1; +static int map_contact_sid = -1; +static char map_context[80]; +static struct sockaddr_in map_addr; static char dept[80]; static char org[80]; static char locality[80]; @@ -2414,6 +2420,7 @@ } ast_cli(fd, "Peer: %s\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); ast_cli(fd, "Model: %s\n", model2str(peer->model)); + ast_cli(fd, "Order: %s\n", order); ast_cli(fd, "Host: %s\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : ""); ast_cli(fd, "Dynamic: %s\n", peer->dynamic ? "yes" : "no"); ast_cli(fd, "KeyPend: %s\n", peer->keypending ? "yes" : "no"); @@ -2455,13 +2462,15 @@ static int dundi_show_peers(int fd, int argc, char *argv[]) { -#define FORMAT2 "%-20.20s %-15.15s %-10.10s %-8.8s %-15.15s\n" -#define FORMAT "%-20.20s %-15.15s %s %-10.10s %-8.8s %-15.15s\n" +#define FORMAT2 "%-20.20s %-15.15s %-10.10s %-10.10s %-8.8s %-15.15s\n" +#define FORMAT "%-20.20s %-15.15s %s %-10.10s %-10.10s %-8.8s %-15.15s\n" struct dundi_peer *peer; char iabuf[INET_ADDRSTRLEN]; int registeredonly=0; char avgms[20]; char eid_str[20]; + char *order = NULL; + if ((argc != 3) && (argc != 4) && (argc != 5)) return RESULT_SHOWUSAGE; if ((argc == 4)) { @@ -2471,7 +2480,7 @@ return RESULT_SHOWUSAGE; } ast_mutex_lock(&peerlock); - ast_cli(fd, FORMAT2, "EID", "Host", "Model", "AvgTime", "Status"); + ast_cli(fd, FORMAT2, "EID", "Host", "Model", "Order", "AvgTime", "Status"); for (peer = peers;peer;peer = peer->next) { char status[20] = ""; int print_line = -1; @@ -2493,9 +2502,25 @@ snprintf(avgms, sizeof(avgms), "%d ms", peer->avgms); else strcpy(avgms, "Unavail"); + switch(peer->order) { + case 0: + order = "Primary"; + break; + case 1: + order = "Secondary"; + break; + case 2: + order = "Tertiary"; + break; + case 3: + order = "Quartiary"; + break; + default: + order = "Unknown"; + } snprintf(srch, sizeof(srch), FORMAT, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)", - peer->dynamic ? "(D)" : "(S)", model2str(peer->model), avgms, status); + peer->dynamic ? "(D)" : "(S)", model2str(peer->model), order, avgms, status); if (argc == 5) { if (!strcasecmp(argv[3],"include") && strstr(srch,argv[4])) { @@ -2512,7 +2537,7 @@ if (print_line) { ast_cli(fd, FORMAT, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)", - peer->dynamic ? "(D)" : "(S)", model2str(peer->model), avgms, status); + peer->dynamic ? "(D)" : "(S)", model2str(peer->model), order, avgms, status); } } ast_mutex_unlock(&peerlock); @@ -2791,6 +2816,162 @@ return res; } +static inline char *dstatus_append_long(char *buf, long val) { + val = htonl(val); + memcpy(buf, &val, sizeof(long)); + return (buf + sizeof(long)); +} + +static inline char *dstatus_append_short(char *buf, short val) { + val = htons(val); + memcpy(buf, &val, sizeof(short)); + return (buf + sizeof(short)); +} + +static inline char *dstatus_append_string(char *buf, char *str) { + unsigned short len = (unsigned short)strlen(str); + buf = dstatus_append_short(buf, len); + memcpy(buf, str, len); + return (buf + len); +} + +/* Create a packet for the DUNDi Status Updates */ +static char *dstatus_v2_pkt_header(char *buf, char pkt_type, time_t ts, short seq, short totseq) { + *buf++ = '\003'; + *buf++ = pkt_type; + + /* Timestamp this sequence */ + buf = dstatus_append_long(buf, ts); + + /* Setup sequence headers */ + buf = dstatus_append_short(buf, seq); + buf = dstatus_append_short(buf, totseq); + + /* Append our global EID */ + memcpy(buf, &global_eid, sizeof(global_eid)); + buf += sizeof(global_eid); + + buf = dstatus_append_string(buf, map_context); + + return buf; +} + +static int dundi_xmit_peering(void *data) +{ + char buf[1500]; + char *ptr = buf; + short seq = 1, totseq = 0; + int need_send = 0, peer_count = 0; + struct dundi_peer *peer; + time_t send_t = time(NULL); + + /* If we have no where to send, don't bother */ + if(!map_addr.sin_addr.s_addr) { + if(option_verbose) + ast_verbose(VERBOSE_PREFIX_1 "No server to send mapping update to...\n"); + map_peering_sid = ast_sched_add(sched, map_update_interval, dundi_xmit_peering, 0); + return 0; + } + + /* Provide a sequence number for the packet and totals */ + ast_mutex_lock(&peerlock); + for (peer = peers;peer;peer = peer->next) { + if(has_permission(peer->include, map_context) || has_permission(peer->permit, map_context)) { + peer_count++; + need_send = 1; + if(peer_count == map_updates_per_pkt) { + peer_count = 0; + need_send = 0; + totseq++; + } + } + } + totseq += need_send; + + /* Initialize the packet header */ + ptr = dstatus_v2_pkt_header(buf, 1, send_t, seq, totseq); + + /* Include our update interval, in seconds */ + ptr = dstatus_append_short(ptr, map_update_interval/1000); + + /* Include peers/packet configured */ + *ptr++ = (unsigned char)map_updates_per_pkt; + + peer_count = 0; + need_send = 0; + for (peer = peers;peer;peer = peer->next) { + if(!has_permission(peer->include, map_context) && !has_permission(peer->permit, map_context)) + continue; + + peer_count++; + need_send = 1; + + /* Copy the peers EID */ + memcpy(ptr, &peer->eid, sizeof(peer->eid)); + ptr += sizeof(peer->eid); + + /* This is the remote peer */ + *ptr++ = (peer->dynamic?0:1); + memcpy(ptr, &peer->addr.sin_addr.s_addr, sizeof(peer->addr.sin_addr.s_addr)); + ptr += sizeof(peer->addr.sin_addr.s_addr); + + /* Append the model and order */ + *ptr++ = peer->model; + *ptr++ = peer->order; + + /* Do some long encoding of the timings */ + ptr = dstatus_append_long(ptr, peer->maxms); + ptr = dstatus_append_long(ptr, peer->lastms); + ptr = dstatus_append_long(ptr, peer->avgms); + + if(peer_count == map_updates_per_pkt) { /* Okay, it's actually arbitrary */ + peer_count = 0; + need_send = 0; + sendto(netsocket, buf, ptr - buf, 0, (struct sockaddr *)&map_addr, sizeof(map_addr)); + seq++; /* We sent one, so move on */ + + ptr = dstatus_v2_pkt_header(buf, 1, send_t, seq, totseq); + /* Include our update interval, in seconds */ + ptr = dstatus_append_short(ptr, map_update_interval/1000); + + /* Include peers/packet configured */ + *ptr++ = (unsigned char)map_updates_per_pkt; + } + } + + /* If we get here, and haven't sent the packet, send it now */ + if(need_send) + sendto(netsocket, buf, ptr - buf, 0, (struct sockaddr *)&map_addr, sizeof(map_addr)); + + /* Unlock */ + ast_mutex_unlock(&peerlock); + + /* Reschedule yourselves */ + map_peering_sid = ast_sched_add(sched, map_update_interval, dundi_xmit_peering, 0); + return RESULT_SUCCESS; +} + +static int dundi_xmit_contact(void *data) { + char buf[1500]; + char *ptr = buf; + + /* Packet type 2, sent now, 1/1 packets */ + ptr = dstatus_v2_pkt_header(buf, 2, time(NULL), 1, 1); + + ptr = dstatus_append_string(ptr, dept); + ptr = dstatus_append_string(ptr, org); + ptr = dstatus_append_string(ptr, locality); + ptr = dstatus_append_string(ptr, stateprov); + ptr = dstatus_append_string(ptr, country); + ptr = dstatus_append_string(ptr, email); + ptr = dstatus_append_string(ptr, phone); + + sendto(netsocket, buf, ptr - buf, 0, (struct sockaddr *)&map_addr, sizeof(map_addr)); + + map_contact_sid = ast_sched_add(sched, map_update_interval * 5, dundi_xmit_contact, 0); + return RESULT_SUCCESS; +} + static void destroy_packet(struct dundi_packet *pack, int needfree) { struct dundi_packet *prev, *cur; @@ -4497,6 +4678,34 @@ strncpy(phone, v->value, sizeof(phone) - 1); } else if (!strcasecmp(v->name, "storehistory")) { global_storehistory = ast_true(v->value); + } else if (!strcasecmp(v->name, "mapserver")) { + hp = ast_gethostbyname(v->value, &he); + if (hp) { + memcpy(&map_addr.sin_addr, hp->h_addr, sizeof(map_addr.sin_addr)); + if (option_verbose > 1) + ast_verbose(VERBOSE_PREFIX_2 "Using mapping server at %s\n", v->value); + } else { + memset(&map_addr.sin_addr, 0, sizeof(map_addr.sin_addr)); + ast_log(LOG_WARNING, "Could not find host '%s' for mapping host\n", v->value); + } + } else if (!strcasecmp(v->name, "mappeers_per_pkt")) { + map_updates_per_pkt = atoi(v->value); + if(map_updates_per_pkt < 1 || map_updates_per_pkt > 45) { + ast_log(LOG_WARNING, "Map updates must be between 1 and 45 inclusive. Setting to 45.\n"); + map_updates_per_pkt = 45; + } + } else if (!strcasecmp(v->name, "mapport")) { + if (option_verbose > 1) + ast_verbose(VERBOSE_PREFIX_2 "Using mapping server at port %d\n", atoi(v->value)); + map_addr.sin_port = htons(atoi(v->value)); + } else if (!strcasecmp(v->name, "mapinterval")) { + map_update_interval = atoi(v->value) * 1000; + if(map_update_interval < 5000 && map_update_interval != 0) + map_update_interval = 5000; + if (option_verbose > 1) + ast_verbose(VERBOSE_PREFIX_2 "Using mapping update interval of %d ms\n", map_update_interval); + } else if(!strcasecmp(v->name, "mapcontext")) { + strncpy(map_context, v->value, sizeof(map_context) - 1); } v = v->next; } @@ -4523,8 +4732,20 @@ prune_peers(); ast_destroy(cfg); load_password(); + + /* Schedule updates */ + if(map_peering_sid > -1) + ast_sched_del(sched, map_peering_sid); + if(map_contact_sid > -1) + ast_sched_del(sched, map_contact_sid); + if(map_update_interval) { + map_peering_sid = ast_sched_add(sched, 1000, dundi_xmit_peering, 0); + map_contact_sid = ast_sched_add(sched, 1000, dundi_xmit_contact, 0); + } + if (globalpcmodel & DUNDI_MODEL_OUTBOUND) dundi_precache_full(); + return 0; } @@ -4575,6 +4796,12 @@ sin.sin_port = ntohs(DUNDI_PORT); sin.sin_addr.s_addr = INADDR_ANY; + /* INADDR_ANY should be 0.0.0.0 */ + map_addr.sin_family = AF_INET; + map_addr.sin_port = ntohs(4525); + map_addr.sin_addr.s_addr = INADDR_ANY; + strncpy(map_context, "open-e164", sizeof(map_context) - 1); + /* Make a UDP socket */ io = io_context_create(); sched = sched_context_create(); @@ -4630,6 +4857,7 @@ close(netsocket); } res = ast_register_application(app, dundi_lookup_exec, synopsis, descrip); + return 0; }