[Home]

Summary:ASTERISK-11755: [patch] chan_mgcp NCS PacketCable patch
Reporter:Nickola Kolev (minus273)Labels:
Date Opened:2008-03-30 09:45:42Date Closed:2008-03-31 11:44:05
Priority:MajorRegression?No
Status:Closed/CompleteComponents:Channels/NewFeature
Versions:Frequency of
Occurrence
Related
Issues:
Environment:Attachments:
Description:Hello,

For a couple of days I’ve been trying to find a working patch for Asterisk
PBX, that would allow me to use an eMTA device, provisioned according to
[some of] the PacketCable specifications - i.e. with MGCP/NCS. So, I’ve
found a patch, written by Jason Burton in 2006, as shown here:
http://lists.digium.com/pipermail/asterisk-dev/2006-October/024164.html

When I tried to apply it on a vanilla 1.4.18 Asterisk source tree, it spew
a lot of rejects, which then I kind of fixed.

Please, if anyone is interested, give this patch a try a fix any further
mistakes.

Disclaimer: I’m not a programmer!

****** ADDITIONAL INFORMATION ******

--- chan_mgcp.c 2008-03-21 10:11:27.000000000 +0200
+++ chan_mgcp.c.patched 2008-03-28 16:17:58.000000000 +0200
@@ -162,6 +162,9 @@
static int dtmfmode = 0;
static int nat = 0;

+static int ncs = 0;
+static int hidecallerid = 0;
+
static ast_group_t cur_callergroup = 0;
static ast_group_t cur_pickupgroup = 0;

@@ -342,6 +345,7 @@
int hidecallerid;
int dtmfmode;
int amaflags;
+ int ncs;
int type;
int slowsequence; /*!< MS: Sequence the endpoint as a whole */
int group;
@@ -396,7 +400,7 @@
int delme;                 /*!< needed for reload */
struct mgcp_response *responses;
struct mgcp_gateway *next;
-} *gateways;
+} *gateways = NULL, *gatetemplate = NULL;

AST_MUTEX_DEFINE_STATIC(mgcp_reload_lock);
static int mgcp_reloading = 0;
@@ -918,6 +922,7 @@
{
struct mgcp_subchannel *sub = ast->tech_pvt;
struct mgcp_endpoint *p = sub->parent;
+ int unhidecallerid = 0;

if (option_debug) {
ast_log(LOG_DEBUG, "mgcp_hangup(%s)\n", ast->name);
@@ -991,7 +996,11 @@
ast_module_unref(ast_module_info->self);

if ((p->hookstate == MGCP_ONHOOK) && (!sub->next->rtp)) {
+
+ if (p->hidecallerid) unhidecallerid = 1;
+    
p->hidecallerid = 0;
+
if (p->hascallwaiting && !p->callwaiting) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Enabling call waiting on %s\n", ast->name);
@@ -1010,6 +1019,8 @@
}
transmit_notify_request(sub, "L/vmwi(-)");
}
+
+ if (unhidecallerid) p->hidecallerid = 1;
}
ast_mutex_unlock(&sub->lock);
return 0;
@@ -1427,14 +1438,14 @@
#ifdef DLINK_BUGGY_FIRMWARE
transmit_notify_request(sub, "rt");
#else
- transmit_notify_request(sub, "G/rt");
+ transmit_notify_request(sub, sub->parent->ncs ? "L/rt" : "G/rt");
#endif
break;
case AST_CONTROL_BUSY:
transmit_notify_request(sub, "L/bz");
break;
case AST_CONTROL_CONGESTION:
- transmit_notify_request(sub, "G/cg");
+ transmit_notify_request(sub, sub->parent->ncs ? "L/cg" : "G/cg");
break;
case AST_CONTROL_HOLD:
ast_moh_start(ast, data, NULL);
@@ -1564,7 +1575,7 @@
return "";
}

-static char *__get_header(struct mgcp_request *req, char *name, int *start)
+static char *__get_header(struct mgcp_request *req, char *name, int *start, char *def)
{
int x;
int len = strlen(name);
@@ -1580,13 +1591,19 @@
}
}
/* Don't return NULL, so get_header is always a valid pointer */
- return "";
+ return def;
}

static char *get_header(struct mgcp_request *req, char *name)
{
int start = 0;
- return __get_header(req, name, &start);
+ return __get_header(req, name, &start, "");
+}
+
+static char *get_header_default(struct mgcp_request *req, char *name, char *def)
+{
+ int start = 0;
+ return __get_header(req, name, &start, def);
}

/*! \brief get_csv: (SC:) get comma separated value */
@@ -1611,7 +1628,50 @@
return s;
}

-static struct mgcp_subchannel *find_subchannel_and_lock(char *name, int msgid, struct sockaddr_in *sin)
+static struct mgcp_gateway *clone_gateway(struct mgcp_gateway *gw, char *at)
+{
+    struct mgcp_gateway *gw_new;
+    struct mgcp_endpoint *e, *e_new;
+    struct mgcp_subchannel *sub, *sub_new;
+
+    if ((gw_new = malloc(sizeof(struct mgcp_gateway)))) {
+ memcpy(gw_new, gw, sizeof (struct mgcp_gateway));
+        strncpy(gw_new->name, at, 79);
+        gw_new->endpoints = NULL;
+ gw_new->dynamic = 1;
+ for (e = gw->endpoints; e; e = e->next) {
+    if ((e_new = malloc(sizeof(struct mgcp_endpoint)))) {
+ if (mgcpdebug)
+    ast_verbose("Cloning endpoint %s@%s\n", e_new->name, gw_new->name);
+    e_new->parent = gw_new;
+    e_new->sub = NULL;
+    e_new->next = gw_new->endpoints;
+    gw_new->endpoints = e_new;
+    for (sub = e->sub; sub; sub = sub->next) {
+ if ((sub_new = malloc(sizeof(struct mgcp_subchannel)))) {
+    memcpy(sub_new, sub, sizeof(struct mgcp_subchannel));
+    if (mgcpdebug)
+ ast_verbose("Cloning subchannel %d of endpoint %s@%s\n", sub_new->id, e_new->name, gw_new->name);
+    sub_new->parent = e_new;
+    sub_new->next = e_new->sub;
+    e_new->sub = sub_new;
+    }
+                            //fix circular reference
+    if (sub->next == e->sub) {
+ while(sub_new->next){
+    sub_new = sub_new->next;
+ }
+ sub_new->next = e_new->sub;
+ break;
+                           }
+                       }
+                   }
+           }
+   }
+   return gw_new;
+}
+
+static struct mgcp_subchannel *find_subchannel_and_lock(char *name, int msgid, struct sockaddr_in *sin, struct mgcp_gateway *gt)
{
struct mgcp_endpoint *p = NULL;
struct mgcp_subchannel *sub = NULL;
@@ -1709,7 +1769,7 @@
p = p->next;
}
if (sub && found) {
- ast_mutex_lock(&sub->lock);
+ ast_mutex_lock(&sub->lock);
break;
}
}
@@ -1718,10 +1778,20 @@
ast_mutex_unlock(&gatelock);
if (!sub) {
if (name) {
- if (g)
- ast_log(LOG_NOTICE, "Endpoint '%s' not found on gateway '%s'\n", tmp, at);
- else
- ast_log(LOG_NOTICE, "Gateway '%s' (and thus its endpoint '%s') does not exist\n", at, tmp);
+ if (g) {
+    ast_log(LOG_NOTICE, "Endpoint '%s' not found on gateway '%s'\n", tmp, at);
+ } else {
+ if (gt && (g = clone_gateway(gt, at))) {
+    ast_mutex_lock(&gatelock);
+    g->next = gateways;
+    gateways = g;
+    ast_mutex_unlock(&gatelock);
+    ast_log(LOG_NOTICE, "Gateway '%s' dynamically allocated\n", at);
+    return find_subchannel_and_lock(name, msgid, sin, NULL);
+    } else {
+ ast_log(LOG_NOTICE, "Gateway '%s' (and thus its endpoint '%s') does not exist\n", at, tmp);
+    }
+    }
}
}
return sub;
@@ -1986,9 +2056,11 @@
req->header[req->headers] = req->data + req->len;
/* check if we need brackets around the gw name */
if (p->parent->isnamedottedip)
- snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %d %s@[%s] MGCP 1.0\r\n", verb, oseq, p->name, p->parent->name);
+// snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %d %s@[%s] MGCP 1.0\r\n", verb, oseq, p->name, p->parent->name);
+ snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %d %s@[%s] MGCP 1.0%s\r\n", verb, oseq, p->name, p->parent->name, p->ncs ? " NCS 1.0" : "");
else
- snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %d %s@%s MGCP 1.0\r\n", verb, oseq, p->name, p->parent->name);
+// snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %d %s@%s MGCP 1.0\r\n", verb, oseq, p->name, p->parent->name);
+ snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %d %s@%s MGCP 1.0%s\r\n", verb, oseq, p->name, p->parent->name, p->ncs ? " NCS 1.0" : "");
req->len += strlen(req->header[req->headers]);
if (req->headers < MGCP_MAX_HEADERS)
req->headers++;
@@ -2149,7 +2221,7 @@
ast_rtp_get_peer(rtp, &sub->tmpdest);
return 0;
}
- snprintf(local, sizeof(local), "p:20");
+ snprintf(local, sizeof(local), "p:20, s:off, e:on");
for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) {
if (p->capability & x) {
snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype(1, x, 0));
@@ -2179,7 +2251,7 @@
int x;
struct mgcp_endpoint *p = sub->parent;

- snprintf(local, sizeof(local), "p:20");
+ snprintf(local, sizeof(local), "p:20, s:off, e:on");
for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) {
if (p->capability & x) {
snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype(1, x, 0));
@@ -2221,7 +2293,8 @@
add_header(&resp, "R", "L/hd(N)");
break;
case MGCP_OFFHOOK:
- add_header_offhook(sub, &resp);
+ //add_header_offhook(sub, &resp);
+ add_header(&resp, "R", (sub->rtp && (p->dtmfmode & MGCP_DTMF_INBAND)) ? "L/hu(N),L/hf(N)" : (p->ncs ? "L/hu(N), L/hf(N), L/[0-9#*](N)" : "L/hu(N),L/hf(N),D/[0-9#*](N)"));
break;
}
if (!ast_strlen_zero(tone)) {
@@ -2264,7 +2337,8 @@
add_header(&resp, "R", "L/hd(N)");
break;
case MGCP_OFFHOOK:
- add_header_offhook(sub, &resp);
+ //add_header_offhook(sub, &resp);
+ add_header(&resp, "R", (sub->rtp && (p->dtmfmode & MGCP_DTMF_INBAND)) ? "L/hu(N),L/hf(N)" : (p->ncs ? "L/hu(N), L/hf(N), L/[0-9#*](N)" : "L/hu(N),L/hf(N),D/[0-9#*](N)"));
break;
}
if (!ast_strlen_zero(tone2)) {
@@ -2305,7 +2379,8 @@
add_header(&resp, "R", "L/hd(N)");
break;
case MGCP_OFFHOOK:
- add_header_offhook(sub, &resp);
+ //add_header_offhook(sub, &resp);
+ add_header(&resp, "R", (sub->rtp && (p->dtmfmode & MGCP_DTMF_INBAND)) ? "L/hu(N),L/hf(N)" : (p->ncs ? "L/hu(N), L/hf(N), L/[0-9#*](N)" : "L/hu(N),L/hf(N),D/[0-9#*](N)"));
break;
}
/* fill in new fields */
@@ -2492,6 +2567,10 @@
break;
}
if (sub) {
+ if (!sub->cxident[0] && (req->cmd == MGCP_CMD_CRCX)) {
+    ast_log(LOG_NOTICE, "DLCX for all connections on %s due to error %d\n", gw->name, result);
+    transmit_connection_del(sub);
+ }
if (sub->owner) {
ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n",
result, p->name, p->parent->name, sub ? sub->id:-1);
@@ -2515,6 +2594,14 @@
}

if (resp) {
+               /* responseAck: */
+ if ((req->cmd == MGCP_CMD_CRCX || req->cmd == MGCP_CMD_MDCX)) {
+                if ((c = get_header_default(resp, "K", NULL))) {
+ if (c == '\0') {
+    transmit_response(sub, "000", resp, "OK");
+ }
+    }
+ }
if (req->cmd == MGCP_CMD_CRCX) {
if ((c = get_header(resp, "I"))) {
if (!ast_strlen_zero(c) && sub) {
@@ -2720,7 +2807,7 @@
ast_log(LOG_WARNING, "PBX exited non-zero\n");
/*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_CONGESTION);*/
/*transmit_notify_request(p, "nbz", 1);*/
- transmit_notify_request(sub, "G/cg");
+ transmit_notify_request(sub, p->ncs ? "L/cg" : "G/cg");
}
return NULL;
}
@@ -2732,7 +2819,7 @@
} else if (res == 0) {
ast_log(LOG_DEBUG, "not enough digits (and no ambiguous match)...\n");
/*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_CONGESTION);*/
- transmit_notify_request(sub, "G/cg");
+ transmit_notify_request(sub, p->ncs ? "L/cg" : "G/cg");
/*zt_wait_event(p->subs[index].zfd);*/
ast_hangup(chan);
memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
@@ -2756,7 +2843,7 @@
if (ast_pickup_call(chan)) {
ast_log(LOG_WARNING, "No call pickup possible...\n");
/*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_CONGESTION);*/
- transmit_notify_request(sub, "G/cg");
+ transmit_notify_request(sub, p->ncs ? "L/cg" : "G/cg");
}
memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
ast_hangup(chan);
@@ -3002,12 +3089,12 @@
#ifdef DLINK_BUGGY_FIRMWARE
transmit_notify_request(sub, "rt");
#else
- transmit_notify_request(sub, "G/rt");
+ transmit_notify_request(sub, p->ncs ? "L/rt" : "G/rt");
#endif
c = mgcp_new(sub, AST_STATE_RING);
if (!c) {
ast_log(LOG_WARNING, "Unable to start PBX on channel %s@%s\n", p->name, p->parent->name);
- transmit_notify_request(sub, "G/cg");
+ transmit_notify_request(sub, p->ncs ? "L/cg" : "G/cg");
ast_hangup(c);
}
} else {
@@ -3056,6 +3143,7 @@
struct mgcp_endpoint *p = sub->parent;
struct mgcp_gateway *g = NULL;
int res;
+ int unhidecallerid = 0;

if (mgcpdebug) {
ast_verbose("Handling request '%s' on %s@%s\n", req->verb, p->name, p->parent->name);
@@ -3259,6 +3347,9 @@
}
}
if ((p->hookstate == MGCP_ONHOOK) && (!sub->rtp) && (!sub->next->rtp)) {
+
+ if (p->hidecallerid) unhidecallerid = 1;
+
p->hidecallerid = 0;
if (p->hascallwaiting && !p->callwaiting) {
if (option_verbose > 2)
@@ -3276,6 +3367,8 @@
}
transmit_notify_request(sub, "L/vmwi(-)");
}
+
+ if (unhidecallerid) p->hidecallerid = 1;
}
} else if ((strlen(ev) == 1) &&
(((ev[0] >= '0') && (ev[0] <= '9')) ||
@@ -3377,8 +3470,12 @@
}

if (sscanf(req.verb, "%d", &result) && sscanf(req.identifier, "%d", &ident)) {
+    if (result < 200) {
+ ast_log(LOG_DEBUG, "Ignoring provisional response on transaction %d\n", ident);
+ return 1;
+    }
/* Try to find who this message is for, if it's important */
- sub = find_subchannel_and_lock(NULL, ident, &sin);
+ sub = find_subchannel_and_lock(NULL, ident, &sin, gatetemplate);
if (sub) {
struct mgcp_gateway *gw = sub->parent->parent;
struct mgcp_message *cur, *prev;
@@ -3419,7 +3516,7 @@
return 1;
}
/* Process request, with iflock held */
- sub = find_subchannel_and_lock(req.endpoint, 0, &sin);
+ sub = find_subchannel_and_lock(req.endpoint, 0, &sin, gatetemplate);
if (sub) {
/* look first to find a matching response in the queue */
if (!find_and_retrans(sub, &req))
@@ -3567,7 +3664,7 @@
ast_log(LOG_NOTICE, "MGCP Channels require an endpoint\n");
return NULL;
}
- sub = find_subchannel_and_lock(tmp, 0, NULL);
+ sub = find_subchannel_and_lock(tmp, 0, NULL, gatetemplate);
if (!sub) {
ast_log(LOG_WARNING, "Unable to find MGCP endpoint '%s'\n", tmp);
*cause = AST_CAUSE_UNREGISTERED;
@@ -3692,6 +3789,8 @@
ast_log(LOG_WARNING, "'%s' is not a valid DTMF mode at line %d\n", v->value, v->lineno);
} else if (!strcasecmp(v->name, "nat")) {
nat = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "ncs")) {
+ ncs = ast_true(v->value);
} else if (!strcasecmp(v->name, "callerid")) {
if (!strcasecmp(v->value, "asreceived")) {
cid_num[0] = '\0';
@@ -3720,6 +3819,8 @@
immediate = ast_true(v->value);
} else if (!strcasecmp(v->name, "cancallforward")) {
cancallforward = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "hidecallerid")) {
+ hidecallerid = ast_true(v->value);
} else if (!strcasecmp(v->name, "singlepath")) {
singlepath = ast_true(v->value);
} else if (!strcasecmp(v->name, "canreinvite")) {
@@ -3780,6 +3881,7 @@
e->amaflags = amaflags;
e->capability = capability;
e->parent = gw;
+ e->hidecallerid = hidecallerid;
e->dtmfmode = dtmfmode;
if (!ep_reload && e->sub && e->sub->rtp)
e->dtmfmode |= MGCP_DTMF_INBAND;
@@ -3884,6 +3986,7 @@
e->amaflags = amaflags;
e->capability = capability;
e->dtmfmode = dtmfmode;
+ e->ncs = ncs;
e->adsi = adsi;
if (!strcasecmp(v->name, "trunk"))
e->type = TYPE_TRUNK;
@@ -3895,6 +3998,7 @@
e->pickupgroup=cur_pickupgroup;
e->callreturn = callreturn;
e->cancallforward = cancallforward;
+ e->hidecallerid = hidecallerid;
e->canreinvite = canreinvite;
e->singlepath = singlepath;
e->callwaiting = callwaiting;
@@ -4205,20 +4309,30 @@
cat = ast_category_browse(cfg, NULL);
while(cat) {
if (strcasecmp(cat, "general")) {
+    if (!(strcasecmp(cat, "template"))) {
+ ast_mutex_lock(&gatelock);
+ gatetemplate = build_gateway(cat, ast_variable_browse(cfg, cat));
+ if (gatetemplate) {
+    if (option_verbose > 2) {
+ ast_verbose(VERBOSE_PREFIX_3 "Added template gateway\n");
+    }
+ }
+    ast_mutex_unlock(&gatelock);
+    } else {
ast_mutex_lock(&gatelock);
g = build_gateway(cat, ast_variable_browse(cfg, cat));
if (g) {
- if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3 "Added gateway '%s'\n", g->name);
- }
- g->next = gateways;
- gateways = g;
+    if (option_verbose > 2) {
+ ast_verbose(VERBOSE_PREFIX_3 "Added gateway '%s'\n", g->name);
+    }
+    g->next = gateways;
+    gateways = g;
}
ast_mutex_unlock(&gatelock);
-
- /* FS: process queue and IO */
- if (monitor_thread == pthread_self()) {
- if (sched) ast_sched_runq(sched);
+    }
+ /* FS: process queue and IO */
+ if (monitor_thread == pthread_self()) {
+ if (sched) ast_sched_runq(sched);
if (io) ast_io_wait(io, 10);
}
}
Comments:By: Joshua C. Colp (jcolp) 2008-03-31 08:58:40

If this is not your patch but also someone elses we can't accept it for legal reasons. We would need them to sign the agreement as well.

By: Russell Bryant (russell) 2008-03-31 11:44:03

I have deleted the patch and have closed the issue for the exact reason that file noted.  Please do not upload code that you did not write!  Feel free to encourage the original author to submit these changes.