--- asterisk/channels/chan_sip.c_orginal Mon Jan 26 01:41:30 2004 +++ asterisk/channels/chan_sip.c Mon Jan 26 03:26:07 2004 @@ -92,6 +92,9 @@ static char mydbname[80]; #endif +#define DEBUG_READ 0 /* Direction of data for sipdebug */ +#define DEBUG_SEND 1 /* Direction of data for sipdebug */ + static char *desc = "Session Initiation Protocol (SIP)"; static char *type = "SIP"; static char *tdesc = "Session Initiation Protocol (SIP)"; @@ -358,6 +361,11 @@ struct sip_peer *next; }; +struct sip_debug_filter { + struct sockaddr_in addr; + struct sip_debug_filter *next; +}; + static struct ast_user_list { struct sip_user *users; ast_mutex_t lock; @@ -410,6 +418,9 @@ static int globalnat = 0; static int globalcanreinvite = REINVITE_INVITE; +static struct ast_debug_filter { + struct sip_debug_filter *filters; +} debfilterl = { NULL }; static struct sockaddr_in bindaddr; static struct sockaddr_in localnet; @@ -435,13 +446,94 @@ static int find_user(struct sip_pvt *fup, int event); static void prune_peers(void); +static void filter_sip_debug(int direction, char *data, int len, struct sockaddr_in *addr) +{ +#define FORMAT "\r%s %-80s %-10s %-5d %-21s\n" +#define FORMAT2 "\r%s %-80s %-10s %-5d %s:%d\n" +#define FORMAT3 " %s\n" + static struct sip_debug_filter *filter; + static struct sip_peer *peer; + static char row[SIP_MAX_PACKET]; + int i, j, rowno, seqno = 0; + int pass = 0; + char *cp; + if (sipdebug == 0) return; + /* See if we pass debug IP filter */ + if (debfilterl.filters) { + for (filter = debfilterl.filters; filter; filter = filter->next) + if (((ntohs(filter->addr.sin_port) == 0) && + (filter->addr.sin_addr.s_addr == addr->sin_addr.s_addr)) || + ((filter->addr.sin_port == addr->sin_port) && + (filter->addr.sin_addr.s_addr == addr->sin_addr.s_addr))) { + pass = 1; + break; + } + if (!pass) return; + } + /* Find extension with same IP and port */ + peer = NULL; + if (!ast_mutex_trylock(&peerl.lock)) { + for (peer = peerl.peers;peer;peer = peer->next) + if ((peer->addr.sin_addr.s_addr == addr->sin_addr.s_addr) && + (peer->addr.sin_port == addr->sin_port)) + break; + ast_mutex_unlock(&peerl.lock); + } + /* Scan data for CSeq */ + j = 0; + for (i = 0; isin_port) == 5060) + ast_verbose(FORMAT, + (direction==DEBUG_READ ? "<--" : "-->"), + row, + (peer?peer->name:"?"), + seqno, + inet_ntoa(addr->sin_addr)); + else + ast_verbose(FORMAT2, + (direction==DEBUG_READ ? "<--" : "-->"), + row, + (peer?peer->name:"?"), + seqno, + inet_ntoa(addr->sin_addr), + ntohs(addr->sin_port)); + if (sipdebug == 1) + return; + } else + ast_verbose(FORMAT3, row); + rowno++; + j = 0; + } else if (data[i] != '\r' ) + row[j++] = data[i]; + } +#undef FORMAT +#undef FORMAT2 +#undef FORMAT3 +} + static int __sip_xmit(struct sip_pvt *p, char *data, int len) { int res; - if (p->nat) - res=sendto(sipsock, data, len, 0, (struct sockaddr *)&p->recv, sizeof(struct sockaddr_in)); - else - res=sendto(sipsock, data, len, 0, (struct sockaddr *)&p->sa, sizeof(struct sockaddr_in)); + if (p->nat) { + filter_sip_debug(DEBUG_SEND, data, len, &p->recv); + res=sendto(sipsock, data, len, 0, (struct sockaddr *)&p->recv, sizeof(struct sockaddr_in)); + } else { + filter_sip_debug(DEBUG_SEND, data, len, &p->sa); + res=sendto(sipsock, data, len, 0, (struct sockaddr *)&p->sa, sizeof(struct sockaddr_in)); + } if (res != len) { ast_log(LOG_WARNING, "sip_xmit of %p (len %d) to %s returned %d: %s\n", data, len, inet_ntoa(p->sa.sin_addr), res, strerror(errno)); } @@ -474,11 +566,11 @@ ast_mutex_lock(&pkt->owner->lock); if (pkt->retrans < MAX_RETRANS) { pkt->retrans++; - if (sipdebug) { + if (sipdebug == 3) { if (pkt->owner->nat) - ast_verbose("Retransmitting #%d (NAT):\n%s\n to %s:%d\n", pkt->retrans, pkt->data, inet_ntoa(pkt->owner->recv.sin_addr), ntohs(pkt->owner->recv.sin_port)); + ast_verbose("Retransmitting (NAT):\n"); else - ast_verbose("Retransmitting #%d (no NAT):\n%s\n to %s:%d\n", pkt->retrans, pkt->data, inet_ntoa(pkt->owner->sa.sin_addr), ntohs(pkt->owner->sa.sin_port)); + ast_verbose("Retransmitting (no NAT):\n"); } __sip_xmit(pkt->owner, pkt->data, pkt->packetlen); res = 1; @@ -613,11 +705,11 @@ static int send_response(struct sip_pvt *p, struct sip_request *req, int reliable, int seqno) { int res; - if (sipdebug) { + if (sipdebug == 3) { if (p->nat) - ast_verbose("%sTransmitting (NAT):\n%s\n to %s:%d\n", reliable ? "Reliably " : "", req->data, inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port)); + ast_verbose("%sTransmitting (NAT) to %s:%d\n", reliable ? "Reliably " : "", inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port)); else - ast_verbose("%sTransmitting (no NAT):\n%s\n to %s:%d\n", reliable ? "Reliably " : "", req->data, inet_ntoa(p->sa.sin_addr), ntohs(p->sa.sin_port)); + ast_verbose("%sTransmitting (no NAT) to %s:%d\n", reliable ? "Reliably " : "", inet_ntoa(p->sa.sin_addr), ntohs(p->sa.sin_port)); } if (reliable) res = __sip_reliable_xmit(p, seqno, 1, req->data, req->len); @@ -631,11 +723,11 @@ static int send_request(struct sip_pvt *p, struct sip_request *req, int reliable, int seqno) { int res; - if (sipdebug) { + if (sipdebug == 3) { if (p->nat) - ast_verbose("%sTransmitting:\n%s (NAT) to %s:%d\n", reliable ? "Reliably " : "", req->data, inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port)); + ast_verbose("%sTransmitting (NAT):\n", reliable ? "Reliably " : ""); else - ast_verbose("%sTransmitting:\n%s (no NAT) to %s:%d\n", reliable ? "Reliably " : "", req->data, inet_ntoa(p->sa.sin_addr), ntohs(p->sa.sin_port)); + ast_verbose("%sTransmitting (no NAT):\n", reliable ? "Reliably " : ""); } if (reliable) res = __sip_reliable_xmit(p, seqno, 0, req->data, req->len); @@ -664,13 +756,13 @@ static int sip_sendtext(struct ast_channel *ast, char *text) { struct sip_pvt *p = ast->pvt->pvt; - if (sipdebug) + if (sipdebug == 3) ast_verbose("Sending text %s on %s\n", text, ast->name); if (!p) return -1; if (!text || !strlen(text)) return 0; - if (sipdebug) + if (sipdebug == 3) ast_verbose("Really sending text %s on %s\n", text, ast->name); transmit_message_with_text(p, text); return 0; @@ -1018,7 +1110,7 @@ { struct sip_pvt *cur, *prev = NULL; struct sip_pkt *cp; - if (sipdebug) + if (sipdebug == 3) ast_log(LOG_DEBUG, "Destorying call '%s'\n", p->callid); if (p->stateid > -1) ast_extension_state_del(p->stateid, NULL); @@ -1948,7 +2040,7 @@ if (strlen(req->line[f])) f++; req->lines = f; - if (sipdebug) + if (sipdebug == 3) ast_verbose("%d headers, %d lines\n", req->headers, req->lines); if (*c) ast_log(LOG_WARNING, "Odd content, extra stuff left over ('%s')\n", c); @@ -2006,7 +2098,7 @@ ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs); return -1; } - if (sipdebug) + if (sipdebug == 3) ast_verbose("Found audio format %s\n", ast_getformatname(codec)); ast_rtp_set_m_type(p->rtp, codec); codecs += len; @@ -2024,7 +2116,7 @@ ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs); return -1; } - if (sipdebug) + if (sipdebug == 3) ast_verbose("Found video format %s\n", ast_getformatname(codec)); ast_rtp_set_m_type(p->vrtp, codec); codecs += len; @@ -2059,7 +2151,7 @@ sendonly=0; } if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) != 2) continue; - if (sipdebug) + if (sipdebug == 3) ast_verbose("Found description format %s\n", mimeSubtype); // Note: should really look at the 'freq' and '#chans' params too ast_rtp_set_rtpmap_type(p->rtp, codec, "audio", mimeSubtype); @@ -2076,7 +2168,7 @@ p->jointcapability = p->capability & (peercapability | vpeercapability); p->noncodeccapability = noncodeccapability & (peernoncodeccapability | vpeernoncodeccapability); - if (sipdebug) { + if (sipdebug == 3) { ast_verbose("Capabilities: us - %d, them - %d/%d, combined - %d\n", p->capability, peercapability, vpeercapability, p->jointcapability); ast_verbose("Non-codec capabilities: us - %d, them - %d, combined - %d\n", @@ -2274,7 +2366,7 @@ /* Parse uri to h (host) and port - uri is already just the part inside the <> */ /* general form we are expecting is sip[s]:username[:password]@host[:port][;...] */ - if (sipdebug) + if (sipdebug == 3) ast_verbose("set_destination: Parsing <%s> for address/port to send to\n", uri); /* Find and parse hostname */ @@ -2319,7 +2411,7 @@ p->sa.sin_family = AF_INET; memcpy(&p->sa.sin_addr, hp->h_addr, sizeof(p->sa.sin_addr)); p->sa.sin_port = htons(port); - if (sipdebug) + if (sipdebug == 3) ast_verbose("set_destination: set destination to %s, port %d\n", inet_ntoa(p->sa.sin_addr), port); } @@ -2633,9 +2725,9 @@ vdest.sin_port = vsin.sin_port; } } - if (sipdebug) + if (sipdebug == 3) ast_verbose("We're at %s port %d\n", inet_ntoa(p->ourip), ntohs(sin.sin_port)); - if (sipdebug && p->vrtp) + if ((sipdebug == 3) && p->vrtp) ast_verbose("Video is at %s port %d\n", inet_ntoa(p->ourip), ntohs(vsin.sin_port)); snprintf(v, sizeof(v), "v=0\r\n"); snprintf(o, sizeof(o), "o=root %d %d IN IP4 %s\r\n", p->sessionid, p->sessionversion, inet_ntoa(dest.sin_addr)); @@ -2648,7 +2740,7 @@ cur = prefs; while(cur) { if (p->jointcapability & cur->codec) { - if (sipdebug) + if (sipdebug == 3) ast_verbose("Answering with preferred capability %d\n", cur->codec); codec = ast_rtp_lookup_code(p->rtp, 1, cur->codec); if (codec > -1) { @@ -2670,7 +2762,7 @@ /* Now send any other common codecs, and non-codec formats: */ for (x = 1; x <= AST_FORMAT_MAX_AUDIO; x <<= 1) { if ((p->jointcapability & x) && !(alreadysent & x)) { - if (sipdebug) + if (sipdebug == 3) ast_verbose("Answering with capability %d\n", x); codec = ast_rtp_lookup_code(p->rtp, 1, x); if (codec > -1) { @@ -2689,7 +2781,7 @@ } for (x = 1; x <= AST_RTP_MAX; x <<= 1) { if (p->noncodeccapability & x) { - if (sipdebug) + if (sipdebug == 3) ast_verbose("Answering with non-codec capability %d\n", x); codec = ast_rtp_lookup_code(p->rtp, 0, x); if (codec > -1) { @@ -3596,7 +3688,7 @@ p->route = head; /* For debugging dump what we ended up with */ - if (sipdebug) + if (sipdebug == 3) list_route(p->route); } @@ -3831,7 +3923,7 @@ if ((a = strchr(c, '@')) || (a = strchr(c, ';'))) { *a = '\0'; } - if (sipdebug) + if (sipdebug == 3) ast_verbose("RDNIS is %s\n", c); strncpy(p->rdnis, c, sizeof(p->rdnis) - 1); @@ -3877,7 +3969,7 @@ if ((a = strchr(fr, '@')) || (a = strchr(fr, ';'))) { *a = '\0'; } - if (sipdebug) + if (sipdebug == 3) ast_verbose("Looking for %s in %s\n", c, p->context); if (ast_exists_extension(NULL, p->context, c, 1, fr) || !strcmp(c, ast_pickup_ext())) { @@ -3971,7 +4063,7 @@ *a2 = '\0'; - if (sipdebug) { + if (sipdebug == 3) { ast_verbose("Looking for %s in %s\n", c, p->context); ast_verbose("Looking for %s in %s\n", c2, p->context); } @@ -4043,7 +4135,7 @@ if ((a = strchr(c, ';'))) *a = '\0'; - if (sipdebug) { + if (sipdebug == 3) { ast_verbose("Looking for %s in %s\n", c, p->context); } if (ast_exists_extension(NULL, p->context, c, 1, NULL)) { @@ -4097,7 +4189,7 @@ p->sa.sin_family = AF_INET; memcpy(&p->sa.sin_addr, hp->h_addr, sizeof(p->sa.sin_addr)); p->sa.sin_port = htons(pt ? atoi(pt) : DEFAULT_SIP_PORT); - if (sipdebug) { + if (sipdebug == 3) { if (p->nat) ast_verbose("Sending to %s : %d (NAT)\n", inet_ntoa(p->sa.sin_addr), ntohs(p->sa.sin_port)); else @@ -4302,7 +4394,7 @@ return; } if (p->owner) { - if (sipdebug) + if (sipdebug == 3) ast_verbose("Message received: '%s'\n", buf); memset(&f, 0, sizeof(f)); f.frametype = AST_FRAME_TEXT; @@ -4405,6 +4497,101 @@ #undef FORMAT2 } +static int sip_show_debug_filter(int fd, int argc, char *argv[]) +{ +#define FORMAT2 "%-15.15s %-8s\n" +#define FORMAT "%-15.15s %-8d\n" + struct sip_debug_filter *filter; + if (argc != 3) + return RESULT_SHOWUSAGE; + ast_cli(fd, FORMAT2, "IP", "Port"); + for (filter = debfilterl.filters;filter;filter = filter->next) { + if (ntohs(filter->addr.sin_port) == 0) + ast_cli(fd, FORMAT2, + inet_ntoa(filter->addr.sin_addr) , + ""); + else + ast_cli(fd, FORMAT, + inet_ntoa(filter->addr.sin_addr) , + ntohs(filter->addr.sin_port)); + } + return RESULT_SUCCESS; +#undef FORMAT +#undef FORMAT2 +} + +static int sip_clear_filter(int fd, int argc, char *argv[]) +{ + struct sip_debug_filter *filter; + struct sip_debug_filter *filter2; + if (argc != 3) + return RESULT_SHOWUSAGE; + for (filter = debfilterl.filters;filter;) { + filter2 = filter->next; + free(filter); + filter = filter2; + } + debfilterl.filters = NULL; + return RESULT_SUCCESS; +} + +static int sip_filter_add_ip(int fd, int argc, char *argv[]) +{ + struct sip_debug_filter *filter; + struct hostent *hp; + int port = 0; + char *p, *arg; + if (argc != 5) + return RESULT_SHOWUSAGE; + arg = argv[4]; + p = strstr(arg, ":"); + if (p) { + *p = '\0'; + p++; + port = atoi(p); + } + hp = gethostbyname(arg); + if (hp == NULL) { + return RESULT_SHOWUSAGE; + } + filter = (struct sip_debug_filter *)malloc(sizeof(struct sip_debug_filter)); + if (filter) { + filter->next = debfilterl.filters; + filter->addr.sin_family = AF_INET; + memcpy(&filter->addr.sin_addr, hp->h_addr, sizeof(filter->addr.sin_addr)); + filter->addr.sin_port = htons(port); + debfilterl.filters = filter; + } + return RESULT_SUCCESS; +} + +static int sip_filter_add_peer(int fd, int argc, char *argv[]) +{ + struct sip_debug_filter *filter; + struct sip_peer *peer; + if (argc != 5) + return RESULT_SHOWUSAGE; + ast_mutex_lock(&peerl.lock); + for (peer = peerl.peers;peer;peer = peer->next) + if (!strcmp(peer->name, argv[4])) + break; + ast_mutex_unlock(&peerl.lock); + if (peer) { + filter = (struct sip_debug_filter *)malloc(sizeof(struct sip_debug_filter)); + if (filter) { + filter->next = debfilterl.filters; + filter->addr.sin_family = AF_INET; + memcpy(&filter->addr.sin_addr, &peer->addr.sin_addr, sizeof(filter->addr.sin_addr)); + filter->addr.sin_port = peer->addr.sin_port; + debfilterl.filters = filter; + } + } else + ast_cli(fd, "No such peer '%s'\n", argv[4]); + return RESULT_SUCCESS; +} + + + static char *regstate2str(int regstate) { switch(regstate) { @@ -4557,7 +4744,7 @@ if (p->owner) { if (strlen(buf)) { - if (sipdebug) + if (sipdebug == 3) ast_verbose("DTMF received: '%c'\n", buf[0]); if (buf[0] == '*') event = 10; @@ -4587,10 +4774,15 @@ static int sip_do_debug(int fd, int argc, char *argv[]) { - if (argc != 2) + int tmp; + if (argc != 3) return RESULT_SHOWUSAGE; - sipdebug = 1; - ast_cli(fd, "SIP Debugging Enabled\n"); + tmp = atoi(argv[2]); + if (tmp < 1 || tmp > 3) + return RESULT_SHOWUSAGE; + sipdebug = tmp; + ast_cli(fd, "SIP Debug level %d Enabled\n", sipdebug); + ast_cli(fd, "\r%s %-80s %-10s %-5s %s\n", "DIR", "Sip data", "Peer", "CSeq", "IP"); return RESULT_SUCCESS; } @@ -4749,13 +4941,32 @@ "Usage: sip show peers\n" " Lists all known SIP peers.\n"; +static char show_filter_usage[] = +"Usage: sip show filter\n" +" Lists IP-adresses and ports used for SIP debug output filtering.\n"; + +static char show_filter_add_ip_usage[] = +"Usage: sip filter add ip \n" +" Adds an IP to filter for filtering SIP debug output.\n"; + +static char show_filter_clear[] = +"Usage: sip filter clear\n" +" Clears filtering list for SIP debug output.\n"; + +static char show_filter_add_peer_usage[] = +"Usage: sip filter add peer \n" +" Adds an IP to filter for filtering SIP debug output.\n"; + static char show_reg_usage[] = "Usage: sip show registry\n" " Lists all registration requests and status.\n"; static char debug_usage[] = -"Usage: sip debug\n" -" Enables dumping of SIP packets for debugging purposes\n"; +"Usage: sip debug \n" +" Enables dumping of SIP packets for debugging purposes\n" +" Level 1: Dumping IP, Port and SIP-headers\n" +" Level 2: Dumping IP, Port and full SIP-packets\n" +" Level 3: Dumping IP, Port, full SIP-packets and detailed comments\n"; static char no_debug_usage[] = "Usage: sip no debug\n" @@ -4771,6 +4982,14 @@ { { "sip", "show", "channels", NULL }, sip_show_channels, "Show active SIP channels", show_channels_usage}; static struct ast_cli_entry cli_show_channel = { { "sip", "show", "channel", NULL }, sip_show_channel, "Show detailed SIP channel info", show_channel_usage, complete_sipch }; +static struct ast_cli_entry cli_show_debug_filter = + { { "sip", "show", "filter", NULL }, sip_show_debug_filter, "Show SIP debug filter", show_filter_usage }; +static struct ast_cli_entry cli_filter_add_ip = + { { "sip", "filter", "add", "ip", NULL }, sip_filter_add_ip, "Add IP to SIP debug filter", show_filter_add_ip_usage }; +static struct ast_cli_entry cli_clear_filter = + { { "sip", "filter", "clear", NULL }, sip_clear_filter, "Clear SIP debug filter", show_filter_clear }; +static struct ast_cli_entry cli_filter_add_peer = + { { "sip", "filter", "add", "peer", NULL }, sip_filter_add_peer, "Add IP by peer to SIP debug filter", show_filter_add_peer_usage }; static struct ast_cli_entry cli_show_peers = { { "sip", "show", "peers", NULL }, sip_show_peers, "Show defined SIP peers", show_peers_usage }; static struct ast_cli_entry cli_inuse_show = @@ -5074,7 +5293,7 @@ ast_log(LOG_NOTICE, "Dunno anything about a %d %s response from %s\n", resp, rest, p->owner ? p->owner->name : inet_ntoa(p->sa.sin_addr)); } } else { - if (sipdebug) + if (sipdebug == 3) ast_verbose("Message is %s\n", msg); switch(resp) { case 200: @@ -5242,7 +5461,7 @@ /* Process the SDP portion */ if (!ignore) { /* Use this as the basis */ - if (sipdebug) + if (sipdebug == 3) ast_verbose("Using latest request as basis request\n"); /* This call is no longer outgoing if it ever was */ p->outgoing = 0; @@ -5258,7 +5477,7 @@ /* Queue NULL frame to prod ast_rtp_bridge if appropriate */ if (p->owner) ast_queue_frame(p->owner, &af, 0); - } else if (sipdebug) + } else if (sipdebug == 3) ast_verbose("Ignoring this request\n"); if (!p->lastinvite) { /* Handle authentication if this is our first invite */ @@ -5466,20 +5685,20 @@ p->needdestroy = 1; transmit_response(p, "200 OK", req); } else if (!strcasecmp(cmd, "MESSAGE")) { - if (sipdebug) + if (sipdebug == 3) ast_verbose("Receiving message!\n"); receive_message(p, req); transmit_response(p, "200 OK", req); } else if (!strcasecmp(cmd, "SUBSCRIBE")) { if (!ignore) { /* Use this as the basis */ - if (sipdebug) + if (sipdebug == 3) ast_verbose("Using latest SUBSCRIBE request as basis request\n"); /* This call is no longer outgoing if it ever was */ p->outgoing = 0; copy_request(&p->initreq, req); check_via(p, req); - } else if (sipdebug) + } else if (sipdebug == 3) ast_verbose("Ignoring this request\n"); if (!p->lastinvite) { @@ -5536,13 +5755,13 @@ transmit_state_notify(p, ast_extension_state(NULL, p->context, p->exten),1); } } else if (!strcasecmp(cmd, "INFO")) { - if (sipdebug) + if (sipdebug == 3) ast_verbose("Receiving DTMF!\n"); receive_info(p, req); transmit_response(p, "200 OK", req); } else if (!strcasecmp(cmd, "REGISTER")) { /* Use this as the basis */ - if (sipdebug) + if (sipdebug == 3) ast_verbose("Using latest request as basis request\n"); copy_request(&p->initreq, req); check_via(p, req); @@ -5599,8 +5818,7 @@ } req.data[res] = '\0'; req.len = res; - if (sipdebug) - ast_verbose("\n\nSip read: \n%s\n", req.data); + filter_sip_debug(DEBUG_READ, req.data, res, &sin); parse(&req); if (req.headers < 2) { /* Must have at least two headers */ @@ -6732,6 +6950,10 @@ ast_cli_register(&cli_show_users); ast_cli_register(&cli_show_channels); ast_cli_register(&cli_show_channel); + ast_cli_register(&cli_show_debug_filter); + ast_cli_register(&cli_filter_add_ip); + ast_cli_register(&cli_clear_filter); + ast_cli_register(&cli_filter_add_peer); ast_cli_register(&cli_show_peers); ast_cli_register(&cli_show_registry); ast_cli_register(&cli_debug); @@ -6764,6 +6986,10 @@ ast_cli_unregister(&cli_show_users); ast_cli_unregister(&cli_show_channels); ast_cli_unregister(&cli_show_channel); + ast_cli_unregister(&cli_show_debug_filter); + ast_cli_unregister(&cli_filter_add_ip); + ast_cli_unregister(&cli_clear_filter); + ast_cli_unregister(&cli_filter_add_peer); ast_cli_unregister(&cli_show_peers); ast_cli_unregister(&cli_show_registry); ast_cli_unregister(&cli_debug);