Sun Mar 9 07:00:01 CET 2003
authorMatteo Brancaleoni <mbrancaleoni@espia.it>
Sun, 9 Mar 2003 06:00:18 +0000 (06:00 +0000)
committerMatteo Brancaleoni <mbrancaleoni@espia.it>
Sun, 9 Mar 2003 06:00:18 +0000 (06:00 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@636 65c4cc65-6c06-0410-ace0-fbb531ad65f3

CHANGES
channels/chan_iax2.c
channels/chan_mgcp.c
channels/chan_sip.c
config.c
dsp.c
include/asterisk/config.h
manager.c
rtp.c

diff --git a/CHANGES b/CHANGES
index a79d6f4..b2c18ff 100755 (executable)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,4 @@
+ -- Add NAT and dynamic support to MGCP
  -- Allow selection of in-band, out-of-band, or INFO based DTMF
  -- Add contributed "*80" support to blacklist numbers (Thanks James!)
  -- Add "NAT" option to sip user, peer, friend
  -- Allow selection of in-band, out-of-band, or INFO based DTMF
  -- Add contributed "*80" support to blacklist numbers (Thanks James!)
  -- Add "NAT" option to sip user, peer, friend
index 03cc833..a304038 100755 (executable)
@@ -830,7 +830,7 @@ static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short
 
 static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new)
 {
 
 static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new)
 {
-       int res = -1;
+       int res = 0;
        int x;
        int start;
        if (new <= NEW_ALLOW) {
        int x;
        int start;
        if (new <= NEW_ALLOW) {
@@ -852,7 +852,7 @@ static int find_callno(unsigned short callno, unsigned short dcallno, struct soc
                for (x = ((nextcallno + 1) % (AST_IAX2_MAX_CALLS - 1)) + 1; iaxs[x] && (x != start); x = (x + 1) % AST_IAX2_MAX_CALLS)
                if (x == start) {
                        ast_log(LOG_WARNING, "Unable to accept more calls\n");
                for (x = ((nextcallno + 1) % (AST_IAX2_MAX_CALLS - 1)) + 1; iaxs[x] && (x != start); x = (x + 1) % AST_IAX2_MAX_CALLS)
                if (x == start) {
                        ast_log(LOG_WARNING, "Unable to accept more calls\n");
-                       return -1;
+                       return 0;
                }
                ast_pthread_mutex_lock(&iaxsl[x]);
                iaxs[x] = new_iax();
                }
                ast_pthread_mutex_lock(&iaxsl[x]);
                iaxs[x] = new_iax();
@@ -873,7 +873,7 @@ static int find_callno(unsigned short callno, unsigned short dcallno, struct soc
                        strncpy(iaxs[x]->accountcode, accountcode, sizeof(iaxs[x]->accountcode)-1);
                } else {
                        ast_log(LOG_WARNING, "Out of resources\n");
                        strncpy(iaxs[x]->accountcode, accountcode, sizeof(iaxs[x]->accountcode)-1);
                } else {
                        ast_log(LOG_WARNING, "Out of resources\n");
-                       return -1;
+                       return 0;
                }
                res = x;
                nextcallno = x;
                }
                res = x;
                nextcallno = x;
@@ -4270,7 +4270,7 @@ static int iax2_do_register(struct iax2_registry *reg)
                if (option_debug)
                        ast_log(LOG_DEBUG, "Allocate call number\n");
                reg->callno = find_callno(0, 0, &reg->addr, NEW_FORCE);
                if (option_debug)
                        ast_log(LOG_DEBUG, "Allocate call number\n");
                reg->callno = find_callno(0, 0, &reg->addr, NEW_FORCE);
-               if (reg->callno < 0) {
+               if (reg->callno < 1) {
                        ast_log(LOG_WARNING, "Unable to create call for registration\n");
                        return -1;
                } else if (option_debug)
                        ast_log(LOG_WARNING, "Unable to create call for registration\n");
                        return -1;
                } else if (option_debug)
@@ -4322,7 +4322,7 @@ static int iax2_poke_peer(struct iax2_peer *peer)
                iax2_destroy(peer->callno);
        }
        peer->callno = find_callno(0, 0, &peer->addr, NEW_FORCE);
                iax2_destroy(peer->callno);
        }
        peer->callno = find_callno(0, 0, &peer->addr, NEW_FORCE);
-       if (peer->callno < 0) {
+       if (peer->callno < 1) {
                ast_log(LOG_WARNING, "Unable to allocate call for poking peer '%s'\n", peer->name);
                return -1;
        }
                ast_log(LOG_WARNING, "Unable to allocate call for poking peer '%s'\n", peer->name);
                return -1;
        }
@@ -4374,7 +4374,7 @@ static struct ast_channel *iax2_request(char *type, int format, void *data)
                return NULL;
        }
        callno = find_callno(0, 0, &sin, NEW_FORCE);
                return NULL;
        }
        callno = find_callno(0, 0, &sin, NEW_FORCE);
-       if (callno < 0) {
+       if (callno < 1) {
                ast_log(LOG_WARNING, "Unable to create call\n");
                return NULL;
        }
                ast_log(LOG_WARNING, "Unable to create call\n");
                return NULL;
        }
index 83df5d6..0db0e42 100755 (executable)
@@ -75,6 +75,8 @@ static char ourhost[256];
 static struct in_addr __ourip;
 static int ourport;
 
 static struct in_addr __ourip;
 static int ourport;
 
+static int mgcpdebug = 0;
+
 static struct sched_context *sched;
 static struct io_context *io;
 /* The private structures of the  mgcp channels are linked for
 static struct sched_context *sched;
 static struct io_context *io;
 /* The private structures of the  mgcp channels are linked for
@@ -141,7 +143,10 @@ struct mgcp_gateway {
        /* A gateway containing one or more endpoints */
        char name[80];
        struct sockaddr_in addr;
        /* A gateway containing one or more endpoints */
        char name[80];
        struct sockaddr_in addr;
+       struct sockaddr_in defaddr;
        struct in_addr ourip;
        struct in_addr ourip;
+       int dynamic;
+       int expire;             /* XXX Should we ever expire dynamic registrations? XXX */
        struct mgcp_endpoint *endpoints;
        struct ast_ha *ha;
        struct mgcp_gateway *next;
        struct mgcp_endpoint *endpoints;
        struct ast_ha *ha;
        struct mgcp_gateway *next;
@@ -162,7 +167,10 @@ static int transmit_notify_request_with_callerid(struct mgcp_endpoint *p, char *
 static int __mgcp_xmit(struct mgcp_endpoint *p, char *data, int len)
 {
        int res;
 static int __mgcp_xmit(struct mgcp_endpoint *p, char *data, int len)
 {
        int res;
-    res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&p->parent->addr, sizeof(struct sockaddr_in));
+       if (p->parent->addr.sin_addr.s_addr)
+           res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&p->parent->addr, sizeof(struct sockaddr_in));
+       else 
+           res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&p->parent->defaddr, sizeof(struct sockaddr_in));
        if (res != len) {
                ast_log(LOG_WARNING, "mgcp_xmit returned %d: %s\n", res, strerror(errno));
        }
        if (res != len) {
                ast_log(LOG_WARNING, "mgcp_xmit returned %d: %s\n", res, strerror(errno));
        }
@@ -172,7 +180,8 @@ static int __mgcp_xmit(struct mgcp_endpoint *p, char *data, int len)
 static int send_response(struct mgcp_endpoint *p, struct mgcp_request *req)
 {
        int res;
 static int send_response(struct mgcp_endpoint *p, struct mgcp_request *req)
 {
        int res;
-       printf("Transmitting:\n%s\n to %s:%d\n", req->data, inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
+       if (mgcpdebug)
+               ast_verbose("Transmitting:\n%s\n to %s:%d\n", req->data, inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
        res = __mgcp_xmit(p, req->data, req->len);
        if (res > 0)
                res = 0;
        res = __mgcp_xmit(p, req->data, req->len);
        if (res > 0)
                res = 0;
@@ -182,7 +191,8 @@ static int send_response(struct mgcp_endpoint *p, struct mgcp_request *req)
 static int send_request(struct mgcp_endpoint *p, struct mgcp_request *req)
 {
        int res;
 static int send_request(struct mgcp_endpoint *p, struct mgcp_request *req)
 {
        int res;
-       printf("XXX Need to handle Retransmitting XXX:\n%s to %s:%d\n", req->data, inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
+       if (mgcpdebug)
+               ast_verbose("XXX Need to handle Retransmitting XXX:\n%s to %s:%d\n", req->data, inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
        res = __mgcp_xmit(p, req->data, req->len);
        return res;
 }
        res = __mgcp_xmit(p, req->data, req->len);
        return res;
 }
@@ -291,9 +301,11 @@ static struct in_addr *myaddrfor(struct in_addr *them)
 #endif         
                if (((remote_ip & mask) ^ dest) == 0) {
 
 #endif         
                if (((remote_ip & mask) ^ dest) == 0) {
 
-                       printf("Interface is %s\n",iface);
+                       if (mgcpdebug)
+                                       ast_verbose("Interface is %s\n",iface);
                        temp = lookup_iface(iface);
                        temp = lookup_iface(iface);
-                       printf("IP Address is %s\n",inet_ntoa(*temp));
+                       if (mgcpdebug)
+                               ast_verbose("IP Address is %s\n",inet_ntoa(*temp));
                        break;
                }
        }
                        break;
                }
        }
@@ -349,7 +361,7 @@ static int mgcp_show_endpoints(int fd, int argc, char *argv[])
        g = gateways;
        while(g) {
                e = g->endpoints;
        g = gateways;
        while(g) {
                e = g->endpoints;
-               ast_cli(fd, "Gateway '%s' at %s\n", g->name, inet_ntoa(g->addr.sin_addr));
+               ast_cli(fd, "Gateway '%s' at %s (%s)\n", g->name, g->addr.sin_addr.s_addr ? inet_ntoa(g->addr.sin_addr) : inet_ntoa(g->defaddr.sin_addr), g->dynamic ? "Dynamic" : "Static");
                while(e) {
                        ast_cli(fd, "   -- '%s@%s in '%s' is %s\n", e->name, g->name, e->context, e->owner ? "active" : "idle");
                        hasendpoints = 1;
                while(e) {
                        ast_cli(fd, "   -- '%s@%s in '%s' is %s\n", e->name, g->name, e->context, e->owner ? "active" : "idle");
                        hasendpoints = 1;
@@ -634,8 +646,18 @@ static struct mgcp_endpoint *find_endpoint(char *name, int msgid, struct sockadd
        ast_pthread_mutex_lock(&gatelock);
        g = gateways;
        while(g) {
        ast_pthread_mutex_lock(&gatelock);
        g = gateways;
        while(g) {
-               if (!name || !strcasecmp(g->name, at)) {
-                       /* Found the gateway -- now for the endpoint */
+               if ((!name || !strcasecmp(g->name, at)) && 
+                   (sin || g->addr.sin_addr.s_addr || g->defaddr.sin_addr.s_addr)) {
+                       /* Found the gateway.  If it's dynamic, save it's address -- now for the endpoint */
+                       if (sin && g->dynamic) {
+                               if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) ||
+                                       (g->addr.sin_port != sin->sin_port)) {
+                                       memcpy(&g->addr, sin, sizeof(g->addr));
+                                       memcpy(&g->ourip, myaddrfor(&g->addr.sin_addr), sizeof(g->ourip));
+                                       if (option_verbose > 2)
+                                               ast_verbose(VERBOSE_PREFIX_3 "Registered MGCP gateway '%s' at %s port %d\n", g->name, inet_ntoa(g->addr.sin_addr), ntohs(g->addr.sin_port));
+                               }
+                       }
                        p = g->endpoints;
                        while(p) {
                                if ((name && !strcasecmp(p->name, tmp)) ||
                        p = g->endpoints;
                        while(p) {
                                if ((name && !strcasecmp(p->name, tmp)) ||
@@ -753,9 +775,11 @@ static void parse(struct mgcp_request *req)
                }
        }
                
                }
        }
                
-       printf("Verb: '%s', Identifier: '%s', Endpoint: '%s', Version: '%s'\n",
+       if (mgcpdebug) {
+               ast_verbose("Verb: '%s', Identifier: '%s', Endpoint: '%s', Version: '%s'\n",
                req->verb, req->identifier, req->endpoint, req->version);
                req->verb, req->identifier, req->endpoint, req->version);
-       printf("%d headers, %d lines\n", req->headers, req->lines);
+               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);
 }
        if (*c) 
                ast_log(LOG_WARNING, "Odd content, extra stuff left over ('%s')\n", c);
 }
@@ -817,7 +841,8 @@ static int process_sdp(struct mgcp_endpoint *p, struct mgcp_request *req)
                codecs += len;
        }
        p->capability = capability & peercapability;
                codecs += len;
        }
        p->capability = capability & peercapability;
-       printf("Capabilities: us - %d, them - %d, combined - %d\n",
+       if (mgcpdebug)
+               ast_verbose("Capabilities: us - %d, them - %d, combined - %d\n",
                capability, peercapability, p->capability);
        if (!p->capability) {
                ast_log(LOG_WARNING, "No compatible codecs!\n");
                capability, peercapability, p->capability);
        if (!p->capability) {
                ast_log(LOG_WARNING, "No compatible codecs!\n");
@@ -966,7 +991,8 @@ static int add_sdp(struct mgcp_request *resp, struct mgcp_endpoint *p, struct as
                        dest.sin_port = sin.sin_port;
                }
        }
                        dest.sin_port = sin.sin_port;
                }
        }
-       printf("We're at %s port %d\n", inet_ntoa(p->parent->ourip), ntohs(sin.sin_port));      
+       if (mgcpdebug)
+               ast_verbose("We're at %s port %d\n", inet_ntoa(p->parent->ourip), ntohs(sin.sin_port)); 
        snprintf(v, sizeof(v), "v=0\r\n");
        snprintf(o, sizeof(o), "o=root %d %d IN IP4 %s\r\n", getpid(), getpid(), inet_ntoa(dest.sin_addr));
        snprintf(s, sizeof(s), "s=session\r\n");
        snprintf(v, sizeof(v), "v=0\r\n");
        snprintf(o, sizeof(o), "o=root %d %d IN IP4 %s\r\n", getpid(), getpid(), inet_ntoa(dest.sin_addr));
        snprintf(s, sizeof(s), "s=session\r\n");
@@ -975,7 +1001,8 @@ static int add_sdp(struct mgcp_request *resp, struct mgcp_endpoint *p, struct as
        snprintf(m, sizeof(m), "m=audio %d RTP/AVP", ntohs(dest.sin_port));
        for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) {
                if (p->capability & x) {
        snprintf(m, sizeof(m), "m=audio %d RTP/AVP", ntohs(dest.sin_port));
        for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) {
                if (p->capability & x) {
-                       printf("Answering with capability %d\n", x);
+                       if (mgcpdebug)
+                               ast_verbose("Answering with capability %d\n", x);
                        if ((codec = ast2rtp(x)) > -1) {
                                snprintf(costr, sizeof(costr), " %d", codec);
                                strcat(m, costr);
                        if ((codec = ast2rtp(x)) > -1) {
                                snprintf(costr, sizeof(costr), " %d", codec);
                                strcat(m, costr);
@@ -1192,7 +1219,8 @@ static int handle_request(struct mgcp_endpoint *p, struct mgcp_request *req, str
        struct ast_channel *c;
        pthread_t t;
        struct ast_frame f = { 0, };
        struct ast_channel *c;
        pthread_t t;
        struct ast_frame f = { 0, };
-       printf("Handling request '%s' on %s@%s\n", req->verb, p->name, p->parent->name);
+       if (mgcpdebug)
+               ast_verbose("Handling request '%s' on %s@%s\n", req->verb, p->name, p->parent->name);
        /* Clear out potential response */
        if (!strcasecmp(req->verb, "RSIP")) {
                if (option_verbose > 2)
        /* Clear out potential response */
        if (!strcasecmp(req->verb, "RSIP")) {
                if (option_verbose > 2)
@@ -1282,7 +1310,8 @@ static int mgcpsock_read(int *id, int fd, short events, void *ignore)
        }
        req.data[res] = '\0';
        req.len = res;
        }
        req.data[res] = '\0';
        req.len = res;
-       printf("MGCP read: \n%s\n", req.data);
+       if (mgcpdebug)
+               ast_verbose("MGCP read: \n%s\nfrom %s:%d", req.data, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
        parse(&req);
        if (req.headers < 1) {
                /* Must have at least one header */
        parse(&req);
        if (req.headers < 1) {
                /* Must have at least one header */
@@ -1431,6 +1460,7 @@ static struct ast_channel *mgcp_request(char *type, int format, void *data)
                ast_log(LOG_WARNING, "Unable to find MGCP endpoint '%s'\n", tmp);
                return NULL;
        }
                ast_log(LOG_WARNING, "Unable to find MGCP endpoint '%s'\n", tmp);
                return NULL;
        }
+       
        /* Must be busy */
        if (p->owner)
                return NULL;
        /* Must be busy */
        if (p->owner)
                return NULL;
@@ -1453,10 +1483,32 @@ struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
        gw = malloc(sizeof(struct mgcp_gateway));
        if (gw) {
                memset(gw, 0, sizeof(struct mgcp_gateway));
        gw = malloc(sizeof(struct mgcp_gateway));
        if (gw) {
                memset(gw, 0, sizeof(struct mgcp_gateway));
+               gw->expire = -1;
                strncpy(gw->name, cat, sizeof(gw->name) - 1);
                while(v) {
                        if (!strcasecmp(v->name, "host")) {
                strncpy(gw->name, cat, sizeof(gw->name) - 1);
                while(v) {
                        if (!strcasecmp(v->name, "host")) {
-                               if (ast_get_ip(&gw->addr, v->value)) {
+                               if (!strcasecmp(v->value, "dynamic")) {
+                                       /* They'll register with us */
+                                       gw->dynamic = 1;
+                                       memset(&gw->addr.sin_addr, 0, 4);
+                                       if (gw->addr.sin_port) {
+                                               /* If we've already got a port, make it the default rather than absolute */
+                                               gw->defaddr.sin_port = gw->addr.sin_port;
+                                               gw->addr.sin_port = 0;
+                                       }
+                               } else {
+                                       /* Non-dynamic.  Make sure we become that way if we're not */
+                                       if (gw->expire > -1)
+                                               ast_sched_del(sched, gw->expire);
+                                       gw->expire = -1;
+                                       gw->dynamic = 0;
+                                       if (ast_get_ip(&gw->addr, v->value)) {
+                                               free(gw);
+                                               return NULL;
+                                       }
+                               }
+                       } else if (!strcasecmp(v->name, "defaultip")) {
+                               if (ast_get_ip(&gw->defaddr, v->value)) {
                                        free(gw);
                                        return NULL;
                                }
                                        free(gw);
                                        return NULL;
                                }
@@ -1503,14 +1555,17 @@ struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
                }
                
        }
                }
                
        }
-       if (!ntohl(gw->addr.sin_addr.s_addr)) {
-               ast_log(LOG_WARNING, "Gateway '%s' lacks IP address\n", gw->name);
+       if (!ntohl(gw->addr.sin_addr.s_addr) && !gw->dynamic) {
+               ast_log(LOG_WARNING, "Gateway '%s' lacks IP address and isn't dynamic\n", gw->name);
                free(gw);
                free(gw);
-               gw = NULL;
-       } else if (!ntohs(gw->addr.sin_port)) {
+               return NULL;
+       }
+       if (gw->defaddr.sin_addr.s_addr && !ntohs(gw->defaddr.sin_port)) 
+               gw->defaddr.sin_port = htons(DEFAULT_MGCP_PORT);
+       if (gw->addr.sin_addr.s_addr && !ntohs(gw->addr.sin_port))
                gw->addr.sin_port = htons(DEFAULT_MGCP_PORT);
                gw->addr.sin_port = htons(DEFAULT_MGCP_PORT);
+       if (gw->addr.sin_addr.s_addr)
                memcpy(&gw->ourip, myaddrfor(&gw->addr.sin_addr), sizeof(gw->ourip));
                memcpy(&gw->ourip, myaddrfor(&gw->addr.sin_addr), sizeof(gw->ourip));
-       }
        return gw;
 }
 
        return gw;
 }
 
@@ -1539,6 +1594,38 @@ static struct ast_rtp_protocol mgcp_rtp = {
        set_rtp_peer: mgcp_set_rtp_peer,
 };
 
        set_rtp_peer: mgcp_set_rtp_peer,
 };
 
+static int mgcp_do_debug(int fd, int argc, char *argv[])
+{
+       if (argc != 2)
+               return RESULT_SHOWUSAGE;
+       mgcpdebug = 1;
+       ast_cli(fd, "MGCP Debugging Enabled\n");
+       return RESULT_SUCCESS;
+}
+
+static int mgcp_no_debug(int fd, int argc, char *argv[])
+{
+       if (argc != 3)
+               return RESULT_SHOWUSAGE;
+       mgcpdebug = 0;
+       ast_cli(fd, "MGCP Debugging Disabled\n");
+       return RESULT_SUCCESS;
+}
+
+static char debug_usage[] = 
+"Usage: mgcp debug\n"
+"       Enables dumping of MGCP packets for debugging purposes\n";
+
+static char no_debug_usage[] = 
+"Usage: mgcp no debug\n"
+"       Disables dumping of MGCP packets for debugging purposes\n";
+
+static struct ast_cli_entry  cli_debug =
+       { { "mgcp", "debug", NULL }, mgcp_do_debug, "Enable MGCP debugging", debug_usage };
+static struct ast_cli_entry  cli_no_debug =
+       { { "mgcp", "no", "debug", NULL }, mgcp_no_debug, "Disable MGCP debugging", no_debug_usage };
+
+
 int load_module()
 {
        struct ast_config *cfg;
 int load_module()
 {
        struct ast_config *cfg;
@@ -1649,6 +1736,8 @@ int load_module()
        mgcp_rtp.type = type;
        ast_rtp_proto_register(&mgcp_rtp);
        ast_cli_register(&cli_show_endpoints);
        mgcp_rtp.type = type;
        ast_rtp_proto_register(&mgcp_rtp);
        ast_cli_register(&cli_show_endpoints);
+       ast_cli_register(&cli_debug);
+       ast_cli_register(&cli_no_debug);
        /* And start the monitor for the first time */
        restart_monitor();
        return 0;
        /* And start the monitor for the first time */
        restart_monitor();
        return 0;
index c9f9d89..81c760b 100755 (executable)
@@ -387,6 +387,11 @@ static int create_addr(struct sip_pvt *r, char *peer)
                if (!strcasecmp(p->name, peer)) {
                        found++;
                        r->capability = p->capability;
                if (!strcasecmp(p->name, peer)) {
                        found++;
                        r->capability = p->capability;
+                       r->nat = p->nat;
+                       if (r->rtp) {
+                               ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", r->nat);
+                               ast_rtp_setnat(r->rtp, r->nat);
+                       }
                        strncpy(r->peername, p->username, sizeof(r->peername)-1);
                        strncpy(r->peersecret, p->secret, sizeof(r->peersecret)-1);
                        strncpy(r->username, p->username, sizeof(r->username)-1);
                        strncpy(r->peername, p->username, sizeof(r->peername)-1);
                        strncpy(r->peersecret, p->secret, sizeof(r->peersecret)-1);
                        strncpy(r->username, p->username, sizeof(r->username)-1);
@@ -2550,8 +2555,10 @@ static int check_user(struct sip_pvt *p, struct sip_request *req, char *cmd, cha
        while(user) {
                if (!strcasecmp(user->name, of)) {
                        p->nat = user->nat;
        while(user) {
                if (!strcasecmp(user->name, of)) {
                        p->nat = user->nat;
-                       if (p->rtp)
+                       if (p->rtp) {
+                               ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", p->nat);
                                ast_rtp_setnat(p->rtp, p->nat);
                                ast_rtp_setnat(p->rtp, p->nat);
+                       }
                        if (!(res = check_auth(p, req, p->randdata, sizeof(p->randdata), user->name, user->secret, cmd, uri))) {
                                strncpy(p->context, user->context, sizeof(p->context) - 1);
                                if (strlen(user->callerid) && strlen(p->callerid)) 
                        if (!(res = check_auth(p, req, p->randdata, sizeof(p->randdata), user->name, user->secret, cmd, uri))) {
                                strncpy(p->context, user->context, sizeof(p->context) - 1);
                                if (strlen(user->callerid) && strlen(p->callerid)) 
@@ -3766,6 +3773,7 @@ static struct sip_user *build_user(char *name, struct ast_variable *v)
                user->canreinvite = 1;
                /* JK02: set default context */
                strcpy(user->context, context);
                user->canreinvite = 1;
                /* JK02: set default context */
                strcpy(user->context, context);
+               user->dtmfmode = SIP_DTMF_RFC2833;
                while(v) {
                        if (!strcasecmp(v->name, "context")) {
                                strncpy(user->context, v->value, sizeof(user->context));
                while(v) {
                        if (!strcasecmp(v->name, "context")) {
                                strncpy(user->context, v->value, sizeof(user->context));
index 114d658..1ce10de 100755 (executable)
--- a/config.c
+++ b/config.c
@@ -16,6 +16,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <time.h>
 #include <asterisk/config.h>
 #include <asterisk/options.h>
 #include <asterisk/logger.h>
 #include <asterisk/config.h>
 #include <asterisk/options.h>
 #include <asterisk/logger.h>
@@ -28,12 +29,22 @@ struct ast_category {
        char name[80];
        struct ast_variable *root;
        struct ast_category *next;
        char name[80];
        struct ast_variable *root;
        struct ast_category *next;
+       struct ast_comment *precomments;
+       struct ast_comment *sameline;
 };
 
 struct ast_config {
        /* Maybe this structure isn't necessary but we'll keep it
           for now */
        struct ast_category *root;
 };
 
 struct ast_config {
        /* Maybe this structure isn't necessary but we'll keep it
           for now */
        struct ast_category *root;
+       struct ast_category *prev;
+       struct ast_comment *trailingcomments;
+};
+
+struct ast_comment_struct
+{
+       struct ast_comment *root;
+       struct ast_comment *prev;
 };
 
 static char *strip(char *buf)
 };
 
 static char *strip(char *buf)
@@ -49,6 +60,16 @@ static char *strip(char *buf)
        return start;
 }
 
        return start;
 }
 
+static void free_comments(struct ast_comment *com)
+{
+       struct ast_comment *l;
+       while (com) {
+               l = com;
+               com = com->next;
+               free(l);
+       }
+}
+
 void ast_destroy(struct ast_config *ast)
 {
        struct ast_category *cat, *catn;
 void ast_destroy(struct ast_config *ast)
 {
        struct ast_category *cat, *catn;
@@ -64,13 +85,18 @@ void ast_destroy(struct ast_config *ast)
                        vn = v;
                        free(v->name);
                        free(v->value);
                        vn = v;
                        free(v->name);
                        free(v->value);
+                       free_comments(v->precomments);
+                       free_comments(v->sameline);
                        v = v->next;
                        free(vn);
                }
                catn = cat;
                        v = v->next;
                        free(vn);
                }
                catn = cat;
+               free_comments(cat->precomments);
+               free_comments(cat->sameline);
                cat = cat->next;
                free(catn);
        }
                cat = cat->next;
                free(catn);
        }
+       free_comments(ast->trailingcomments);
        free(ast);
 }
 
        free(ast);
 }
 
@@ -138,6 +164,220 @@ char *ast_variable_retrieve(struct ast_config *config, char *category, char *val
        return NULL;
 }
 
        return NULL;
 }
 
+int ast_variable_delete(struct ast_config *cfg, char *category, char *variable, char *value)
+{
+       struct ast_variable *v, *pv, *bv, *bpv;
+       struct ast_category *cat;
+       cat = cfg->root;
+       while(cat) {
+               if (cat->name == category) {
+                       break;
+               }
+               cat = cat->next;
+       }
+       if (!cat) {
+               cat = cfg->root;
+               while(cat) {
+                       if (!strcasecmp(cat->name, category)) {
+                               break;
+                       }
+                       cat = cat->next;
+               }
+       }
+       if (!cat)
+               return -1;
+       v = cat->root;
+       pv = NULL;
+       while (v) {
+               if ((variable == v->name) && (!value || !strcmp(v->value, value)))
+                       break;
+               pv = v;
+               v=v->next;
+       }
+       if (!v) {
+               /* Get the last one that looks like it */
+               bv = NULL;
+               bpv = NULL;
+               v = cat->root;
+               pv = NULL;
+               while (v) {
+                       if (!strcasecmp(variable, v->name) && (!value || !strcmp(v->value, value))) {
+                               bv = v;
+                               bpv = pv;
+                       }
+                       pv = v;
+                       v=v->next;
+               }
+               v = bv;
+       }
+
+       if (v) {
+               /* Unlink from original position */
+               if (pv) 
+                       pv->next = v->next;
+               else
+                       cat->root = v->next;
+               v->next = NULL;
+               free(v->name);
+               if (v->value)
+                       free(v->value);
+               free_comments(v->sameline);
+               free_comments(v->precomments);
+               return 0;
+       }
+       return -1;
+}
+
+int ast_category_delete(struct ast_config *cfg, char *category)
+{
+       struct ast_variable *v, *pv;
+       struct ast_category *cat, *cprev;
+       cat = cfg->root;
+       cprev = NULL;
+       while(cat) {
+               if (cat->name == category) {
+                       break;
+               }
+               cprev = cat;
+               cat = cat->next;
+       }
+       if (!cat) {
+               cat = cfg->root;
+               cprev = NULL;
+               while(cat) {
+                       if (!strcasecmp(cat->name, category)) {
+                               break;
+                       }
+                       cprev = cat;
+                       cat = cat->next;
+               }
+       }
+       if (!cat)
+               return -1;
+       /* Unlink it */
+       if (cprev)
+               cprev->next = cat->next;
+       else
+               cfg->root = cat->next;
+       v = cat->root;
+       while (v) {
+               pv = v;
+               v=v->next;
+               if (pv->value)
+                       free(pv->value);
+               if (pv->name)
+                       free(pv->name);
+               free_comments(pv->sameline);
+               free_comments(pv->precomments);
+               free(pv);
+       }
+       free_comments(cat->sameline);
+       free_comments(cat->precomments);
+       free(cat);
+       return 0;
+}
+
+struct ast_variable *ast_variable_append_modify(struct ast_config *config, char *category, char *variable, char *value, int newcat, int newvar, int move)
+{
+       struct ast_variable *v, *pv, *bv, *bpv;
+       struct ast_category *cat, *pcat;
+       cat = config->root;
+       if (!newcat) {
+               while(cat) {
+                       if (cat->name == category) {
+                               break;
+                       }
+                       cat = cat->next;
+               }
+               if (!cat) {
+                       cat = config->root;
+                       while(cat) {
+                               if (!strcasecmp(cat->name, category)) {
+                                       break;
+                               }
+                               cat = cat->next;
+                       }
+               }
+       }
+       if (!cat) {
+               cat = malloc(sizeof(struct ast_category));
+               if (!cat)
+                       return NULL;
+               memset(cat, 0, sizeof(struct ast_category));
+               strncpy(cat->name, category, sizeof(cat->name));
+               if (config->root) {
+                       /* Put us at the end */
+                       pcat = config->root;
+                       while(pcat->next)
+                               pcat = pcat->next;
+                       pcat->next = cat;
+               } else {
+                       /* We're the first one */
+                       config->root = cat;
+               }
+                       
+       }
+       if (!newvar) {
+               v = cat->root;
+               pv = NULL;
+               while (v) {
+                       if (variable == v->name)
+                               break;
+                       pv = v;
+                       v=v->next;
+               }
+               if (!v) {
+                       /* Get the last one that looks like it */
+                       bv = NULL;
+                       bpv = NULL;
+                       v = cat->root;
+                       pv = NULL;
+                       while (v) {
+                               if (!strcasecmp(variable, v->name)) {
+                                       bv = v;
+                                       bpv = pv;
+                               }
+                               pv = v;
+                               v=v->next;
+                       }
+                       v = bv;
+               }
+       } else v = NULL;
+       if (v && move) {
+               /* Unlink from original position */
+               if (pv) 
+                       pv->next = v->next;
+               else
+                       cat->root = v->next;
+               v->next = NULL;
+       }
+       if (!v) {
+               v = malloc(sizeof(struct ast_variable));
+               if (!v)
+                       return NULL;
+               memset(v, 0, sizeof(struct ast_variable));
+               v->name = strdup(variable);
+               move = 1;
+       }
+       if (v->value)
+               free(v->value);
+       if (value)
+               v->value = strdup(value);
+       else
+               v->value = strdup("");
+       if (move) {
+               if (cat->root) {
+                       pv = cat->root;
+                       while (pv->next) 
+                               pv = pv->next;
+                       pv->next = v;
+               } else {
+                       cat->root = v;
+               }
+       }
+       return v;
+}
+
 int ast_category_exist(struct ast_config *config, char *category_name)
 {
        struct ast_category *category = NULL;
 int ast_category_exist(struct ast_config *config, char *category_name)
 {
        struct ast_category *category = NULL;
@@ -153,16 +393,33 @@ int ast_category_exist(struct ast_config *config, char *category_name)
        return 0;
 }
 
        return 0;
 }
 
-static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel);
-static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, char *buf, int lineno, char *configfile, int includelevel)
+static struct ast_comment *build_comment(char *cmt)
+{
+       struct ast_comment *c;
+       c = malloc(sizeof(struct ast_comment));
+       if (c) {
+               memset(c, 0, sizeof(struct ast_comment));
+               c->comment = strdup(cmt);
+       }
+       return c;
+}
+
+static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel, struct ast_comment_struct *acs);
+static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, char *buf, int lineno, char *configfile, int includelevel, struct ast_comment_struct *acs)
 {
        char *c;
        char *cur;
        struct ast_variable *v;
 {
        char *c;
        char *cur;
        struct ast_variable *v;
+       struct ast_comment *com = NULL;
+       int object;
        /* Strip off lines using ; as comment */
        c = strchr(buf, ';');
        /* Strip off lines using ; as comment */
        c = strchr(buf, ';');
-       if (c)
+       if (c) {
                *c = '\0';
                *c = '\0';
+               c++;
+               if (*c != '!')
+                       com = build_comment(c);
+       }
        cur = strip(buf);
        if (strlen(cur)) {
                /* Actually parse the entry */
        cur = strip(buf);
        if (strlen(cur)) {
                /* Actually parse the entry */
@@ -181,8 +438,16 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru
                                memset(*_tmpc, 0, sizeof(struct ast_category));
                                strncpy((*_tmpc)->name, cur+1, sizeof((*_tmpc)->name) - 1);
                                (*_tmpc)->root =  NULL;
                                memset(*_tmpc, 0, sizeof(struct ast_category));
                                strncpy((*_tmpc)->name, cur+1, sizeof((*_tmpc)->name) - 1);
                                (*_tmpc)->root =  NULL;
-                               (*_tmpc)->next = tmp->root;
-                               tmp->root = *_tmpc;
+                               (*_tmpc)->precomments = acs->root;
+                               (*_tmpc)->sameline = com;
+                               if (!tmp->prev)
+                                       tmp->root = *_tmpc;
+                               else
+                                       tmp->prev->next = *_tmpc;
+
+                               tmp->prev = *_tmpc;
+                               acs->root = NULL;
+                               acs->prev = NULL;
                                *_last =  NULL;
                        } else {
                                ast_log(LOG_WARNING, 
                                *_last =  NULL;
                        } else {
                                ast_log(LOG_WARNING, 
@@ -216,7 +481,7 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru
                                                        break;
                                        }
                                        if (includelevel < MAX_INCLUDE_LEVEL) {
                                                        break;
                                        }
                                        if (includelevel < MAX_INCLUDE_LEVEL) {
-                                               __ast_load(cur, tmp, _tmpc, _last, includelevel + 1);
+                                               __ast_load(cur, tmp, _tmpc, _last, includelevel + 1, acs);
                                        } else 
                                                ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", includelevel);
                                } else
                                        } else 
                                                ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", includelevel);
                                } else
@@ -237,8 +502,11 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru
                                *c = 0;
                                c++;
                                /* Ignore > in => */
                                *c = 0;
                                c++;
                                /* Ignore > in => */
-                               if (*c== '>')
+                               if (*c== '>') {
+                                       object = 1;
                                        c++;
                                        c++;
+                               } else
+                                       object = 0;
                                v = malloc(sizeof(struct ast_variable));
                                if (v) {
                                        memset(v, 0, sizeof(struct ast_variable));
                                v = malloc(sizeof(struct ast_variable));
                                if (v) {
                                        memset(v, 0, sizeof(struct ast_variable));
@@ -246,7 +514,14 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru
                                        v->name = strdup(strip(cur));
                                        v->value = strdup(strip(c));
                                        v->lineno = lineno;
                                        v->name = strdup(strip(cur));
                                        v->value = strdup(strip(c));
                                        v->lineno = lineno;
-                                       if (*_last)  
+                                       v->object = object;
+                                       /* Put and reset comments */
+                                       v->precomments = acs->root;
+                                       v->blanklines = 0;
+                                       acs->prev = NULL;
+                                       acs->root = NULL;
+                                       v->sameline = com;
+                                       if (*_last)
                                                (*_last)->next = v;
                                        else
                                                (*_tmpc)->root = v;
                                                (*_last)->next = v;
                                        else
                                                (*_tmpc)->root = v;
@@ -261,16 +536,107 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru
                        }
                                                                                                                
                }
                        }
                                                                                                                
                }
+       } else {
+               /* store any comments if there are any */
+               if (com) {
+                       if (acs->prev)
+                               acs->prev->next = com;
+                       else
+                               acs->root = com;
+                       acs->prev = com;
+               } else {
+               if (*_last) 
+                       (*_last)->blanklines++;
+
+               }
        }
        return 0;
 }
 
        }
        return 0;
 }
 
-static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel)
+static void dump_comments(FILE *f, struct ast_comment *comment)
+{
+       while (comment) {
+               fprintf(f, ";%s", comment->comment);
+               comment = comment->next;
+       }
+}
+
+int ast_save(char *configfile, struct ast_config *cfg, char *generator)
+{
+       FILE *f;
+       char fn[256];
+       char date[256];
+       time_t t;
+       struct ast_variable *var;
+       struct ast_category *cat;
+       int blanklines = 0;
+       if (configfile[0] == '/') {
+               strncpy(fn, configfile, sizeof(fn)-1);
+       } else {
+               snprintf(fn, sizeof(fn), "%s/%s", AST_CONFIG_DIR, configfile);
+       }
+       time(&t);
+       strncpy(date, ctime(&t), sizeof(date));
+       if ((f = fopen(fn, "w"))) {
+               if ((option_verbose > 1) && !option_debug)
+                       ast_verbose(  VERBOSE_PREFIX_2 "Saving '%s': ", fn);
+               fprintf(f, ";!\n");
+               fprintf(f, ";! Automatically generated configuration file\n");
+               fprintf(f, ";! Filename: %s (%s)\n", configfile, fn);
+               fprintf(f, ";! Generator: %s\n", generator);
+               fprintf(f, ";! Creation Date: %s", date);
+               fprintf(f, ";!\n");
+               cat = cfg->root;
+               while(cat) {
+                       /* Dump any precomments */
+                       dump_comments(f, cat->precomments);
+                       /* Dump section with any appropriate comment */
+                       if (cat->sameline) 
+                               fprintf(f, "[%s]  ; %s\n", cat->name, cat->sameline->comment);
+                       else
+                               fprintf(f, "[%s]\n", cat->name);
+                       var = cat->root;
+                       while(var) {
+                               dump_comments(f, var->precomments);
+                               if (var->sameline) 
+                                       fprintf(f, "%s %s %s  ; %s\n", var->name, (var->object ? "=>" : "="), var->value, var->sameline->comment);
+                               else    
+                                       fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="), var->value);
+                               if (var->blanklines) {
+                                       blanklines = var->blanklines;
+                                       while (blanklines) {
+                                               fprintf(f, "\n");
+                                               blanklines--;
+                                       }
+                               }
+                                       
+                               var = var->next;
+                       }
+#if 0
+                       /* Put an empty line */
+                       fprintf(f, "\n");
+#endif
+                       cat = cat->next;
+               }
+               dump_comments(f, cfg->trailingcomments);
+       } else {
+               if (option_debug)
+                       printf("Unable to open for writing: %s\n", fn);
+               else if (option_verbose > 1)
+                       printf( "Unable to write (%s)", strerror(errno));
+               return -1;
+       }
+       fclose(f);
+       return 0;
+}
+
+static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel, struct ast_comment_struct *acs)
 {
        char fn[256];
        char buf[256];
        FILE *f;
        int lineno=0;
 {
        char fn[256];
        char buf[256];
        FILE *f;
        int lineno=0;
+       int master=0;
 
        if (configfile[0] == '/') {
                strncpy(fn, configfile, sizeof(fn)-1);
 
        if (configfile[0] == '/') {
                strncpy(fn, configfile, sizeof(fn)-1);
@@ -290,6 +656,8 @@ static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, s
                        tmp = malloc(sizeof(struct ast_config));
                        if (tmp)
                                memset(tmp, 0, sizeof(struct ast_config));
                        tmp = malloc(sizeof(struct ast_config));
                        if (tmp)
                                memset(tmp, 0, sizeof(struct ast_config));
+
+                       master = 1;
                }
                if (!tmp) {
                        ast_log(LOG_WARNING, "Out of memory\n");
                }
                if (!tmp) {
                        ast_log(LOG_WARNING, "Out of memory\n");
@@ -300,7 +668,7 @@ static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, s
                        fgets(buf, sizeof(buf), f);
                        lineno++;
                        if (!feof(f)) {
                        fgets(buf, sizeof(buf), f);
                        lineno++;
                        if (!feof(f)) {
-                               if (cfg_process(tmp, _tmpc, _last, buf, lineno, configfile, includelevel)) {
+                               if (cfg_process(tmp, _tmpc, _last, buf, lineno, configfile, includelevel, acs)) {
                                        fclose(f);
                                        return NULL;
                                }
                                        fclose(f);
                                        return NULL;
                                }
@@ -313,6 +681,12 @@ static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, s
                else if (option_verbose > 1)
                        ast_verbose( "Not found (%s)", strerror(errno));
        }
                else if (option_verbose > 1)
                        ast_verbose( "Not found (%s)", strerror(errno));
        }
+       if (master) {
+               /* Keep trailing comments */
+               tmp->trailingcomments = acs->root;
+               acs->root = NULL;
+               acs->prev = NULL;
+       }
        return tmp;
 }
 
        return tmp;
 }
 
@@ -320,7 +694,8 @@ struct ast_config *ast_load(char *configfile)
 {
        struct ast_category *tmpc=NULL;
        struct ast_variable *last = NULL;
 {
        struct ast_category *tmpc=NULL;
        struct ast_variable *last = NULL;
-       return __ast_load(configfile, NULL, &tmpc, &last, 0);
+       struct ast_comment_struct acs = { NULL, NULL };
+       return __ast_load(configfile, NULL, &tmpc, &last, 0, &acs);
 }
 
 char *ast_category_browse(struct ast_config *config, char *prev)
 }
 
 char *ast_category_browse(struct ast_config *config, char *prev)
diff --git a/dsp.c b/dsp.c
index 9851a0c..62e0342 100755 (executable)
--- a/dsp.c
+++ b/dsp.c
@@ -519,6 +519,7 @@ static int dtmf_detect (dtmf_detect_state_t *s,
                                } /* Don't reset fax hits counter */
                } else {
                        if (s->fax_hits > 5) {
                                } /* Don't reset fax hits counter */
                } else {
                        if (s->fax_hits > 5) {
+                                hit = 'f';
                                 s->mhit = 'f';
                     s->detected_digits++;
                     if (s->current_digits < MAX_DTMF_DIGITS)
                                 s->mhit = 'f';
                     s->detected_digits++;
                     if (s->current_digits < MAX_DTMF_DIGITS)
index ff7ad45..b687504 100755 (executable)
@@ -30,6 +30,7 @@ struct ast_variable {
        char *value;
        int lineno;
        int object;             /* 0 for variable, 1 for object */
        char *value;
        int lineno;
        int object;             /* 0 for variable, 1 for object */
+       int blanklines;         /* Number of blanklines following entry */
        struct ast_comment *precomments;
        struct ast_comment *sameline;
        struct ast_variable *next;
        struct ast_comment *precomments;
        struct ast_comment *sameline;
        struct ast_variable *next;
index 638c951..f9d224d 100755 (executable)
--- a/manager.c
+++ b/manager.c
@@ -733,5 +733,6 @@ int init_manager(void)
 
 int reload_manager(void)
 {
 
 int reload_manager(void)
 {
+       manager_event(EVENT_FLAG_SYSTEM, "Reload", NULL);
        return init_manager();
 }
        return init_manager();
 }
diff --git a/rtp.c b/rtp.c
index 54b7e94..fb3ea67 100755 (executable)
--- a/rtp.c
+++ b/rtp.c
@@ -282,7 +282,11 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
        }
        if (rtp->nat) {
                /* Send to whoever sent to us */
        }
        if (rtp->nat) {
                /* Send to whoever sent to us */
-               memcpy(&rtp->them, &sin, sizeof(rtp->them));
+               if ((rtp->them.sin_addr.s_addr != sin.sin_addr.s_addr) ||
+                   (rtp->them.sin_port != sin.sin_port)) {
+                       memcpy(&rtp->them, &sin, sizeof(rtp->them));
+                       ast_log(LOG_DEBUG, "RTP NAT: Using address %s:%d\n", inet_ntoa(rtp->them.sin_addr), ntohs(rtp->them.sin_port));
+               }
        }
        /* Get fields */
        seqno = ntohl(rtpheader[0]);
        }
        /* Get fields */
        seqno = ntohl(rtpheader[0]);