Index: pbx_dundi.c =================================================================== RCS file: /usr/cvsroot/asterisk/pbx/pbx_dundi.c,v retrieving revision 1.11 diff -u -r1.11 pbx_dundi.c --- pbx_dundi.c 24 Oct 2004 17:53:10 -0000 1.11 +++ pbx_dundi.c 26 Oct 2004 04:07:20 -0000 @@ -112,6 +112,10 @@ 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 char map_context[80]; +static struct sockaddr_in map_addr; static char dept[80]; static char org[80]; static char locality[80]; @@ -2199,6 +2203,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"); @@ -2240,13 +2245,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)) { @@ -2256,7 +2263,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; @@ -2278,9 +2285,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])) { @@ -2297,7 +2320,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); @@ -2533,6 +2556,150 @@ return res; } +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); + + /* Used in the memory copies */ + short shorttmp; + int inttmp; + + if(!map_addr.sin_addr.s_addr) { + if(option_verbose) + ast_verbose(VERBOSE_PREFIX_1 "No server to send mapping update to...\n"); + ast_sched_add(sched, map_update_interval, dundi_xmit_peering, 0); + return 0; + } + + /* Start with the protocol version */ + *ptr++ = '\001'; + + /* Provide a sequence number for the packet and totals */ + ast_mutex_lock(&peerlock); + peer_count = 0; + for (peer = peers;peer;peer = peer->next) { + if(has_permission(peer->include, map_context) || has_permission(peer->permit, map_context)) { + peer_count++; + if(peer_count > map_updates_per_pkt) { /* Peer count = MTU - 64 - header / peerlen -- yeah. really.*/ + totseq++; + peer_count = 1; + } + } + } + totseq++; + + /* Timestamp this sequence */ + inttmp = htonl(send_t); + memcpy(ptr, &inttmp, sizeof(time_t)); + ptr += sizeof(time_t); + + /* Include our update interval, in seconds */ + shorttmp = htons(map_update_interval/1000); + memcpy(ptr, &shorttmp, sizeof(short)); + ptr += sizeof(short); + + /* Include peers/packet configured */ + *ptr++ = (unsigned char)map_updates_per_pkt; + + /* Setup sequence headers */ + shorttmp = htons(seq); + memcpy(ptr, &shorttmp, sizeof(short)); + ptr += sizeof(short); + + shorttmp = htons(totseq); + memcpy(ptr, &shorttmp, sizeof(short)); + ptr += sizeof(short); + + /* Append our global EID */ + memcpy(ptr, &global_eid, sizeof(global_eid)); + ptr+= sizeof(global_eid); + + peer_count = 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 */ + (unsigned char)*ptr = (unsigned char)(peer->dynamic?0:1); + ptr++; + 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 */ + (unsigned char)*ptr = (unsigned char)peer->model; ptr++; + (unsigned char)*ptr = (unsigned char)peer->order; ptr++; + + /* Do some long encoding of the timings */ + inttmp = htonl(peer->maxms); + memcpy(ptr, &inttmp, sizeof(long)); + ptr += sizeof(long); + inttmp = htonl(peer->lastms); + memcpy(ptr, &inttmp, sizeof(long)); + ptr += sizeof(long); + inttmp = htonl(peer->avgms); + memcpy(ptr, &inttmp, sizeof(long)); + ptr += sizeof(long); + + if(peer_count == map_updates_per_pkt) { /* Okay, it's actually arbitrary */ + sendto(netsocket, buf, ptr - buf, 0, (struct sockaddr *)&map_addr, sizeof(map_addr)); + + peer_count = 0; + need_send = 0; + seq++; /* We sent one, so move on */ + + /* Recreate the packet header */ + ptr = buf + 1; + + /* Use the same timestamp header */ + inttmp = htonl(send_t); + memcpy(ptr, &inttmp, sizeof(time_t)); + ptr += sizeof(time_t); + + /* Include our update interval, in seconds */ + shorttmp = htons(map_update_interval/1000); + memcpy(ptr, &shorttmp, sizeof(short)); + ptr += sizeof(short); + + /* Include peers/packet configured */ + *ptr++ = map_updates_per_pkt; + + shorttmp = htons(seq); + memcpy(ptr, &shorttmp, sizeof(short)); + ptr += sizeof(short); + + shorttmp = htons(totseq); + memcpy(ptr, &shorttmp, sizeof(short)); + ptr += sizeof(short); + + memcpy(ptr, &global_eid, sizeof(global_eid)); + ptr += sizeof(global_eid); + } + + } + + /* 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 */ + ast_sched_add(sched, map_update_interval, dundi_xmit_peering, 0); + return RESULT_SUCCESS; +} + static void destroy_packet(struct dundi_packet *pack, int needfree) { struct dundi_packet *prev, *cur; @@ -3969,6 +4136,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; } @@ -3995,6 +4190,7 @@ prune_peers(); ast_destroy(cfg); load_password(); + return 0; } @@ -4043,6 +4239,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, "e164", sizeof(map_context) - 1); + /* Make a UDP socket */ io = io_context_create(); sched = sched_context_create(); @@ -4096,6 +4298,10 @@ close(netsocket); } res = ast_register_application(app, dundi_lookup_exec, synopsis, descrip); + + if(map_update_interval) + ast_sched_add(sched, map_update_interval, dundi_xmit_peering, 0); + return 0; }