aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2012-11-29 20:19:32 +0100
committerHolger Hans Peter Freyther <zecke@selfish.org>2012-12-10 13:45:40 +0100
commitacb7aa81b0a421e26ba0758f60626c062240635a (patch)
tree64f9bb6d8b41044e4abeeb498acb9c5ea943dd8b
parentc6f118a3322d538d85c767e8475589655152f205 (diff)
mgcp: Begin handling of the RQNT message as needed for DTMF
Introduce a callback for the request and forward the signalrequest to the callback. This is not a full implementation of MGCP RQNT. Manual merge and backport from OpenBSC.
-rw-r--r--include/mgcp/mgcp.h6
-rw-r--r--src/mgcp/mgcp_protocol.c42
-rw-r--r--tests/mgcp/Makefile.am5
-rw-r--r--tests/mgcp/mgcp_patch_test.c86
4 files changed, 132 insertions, 7 deletions
diff --git a/include/mgcp/mgcp.h b/include/mgcp/mgcp.h
index e02da08..cde4594 100644
--- a/include/mgcp/mgcp.h
+++ b/include/mgcp/mgcp.h
@@ -1,8 +1,8 @@
/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
/*
- * (C) 2009-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009-2011 by On-Waves
+ * (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2009-2012 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -83,6 +83,7 @@ typedef int (*mgcp_realloc)(struct mgcp_trunk_config *cfg, int endpoint);
typedef int (*mgcp_change)(struct mgcp_trunk_config *cfg, int endpoint, int state);
typedef int (*mgcp_policy)(struct mgcp_trunk_config *cfg, int endpoint, int state, const char *transactio_id);
typedef int (*mgcp_reset)(struct mgcp_trunk_config *cfg);
+typedef int (*mgcp_rqnt)(struct mgcp_endpoint *endp, char tone, const char *data);
#define PORT_ALLOC_STATIC 0
#define PORT_ALLOC_DYNAMIC 1
@@ -165,6 +166,7 @@ struct mgcp_config {
mgcp_policy policy_cb;
mgcp_reset reset_cb;
mgcp_realloc realloc_cb;
+ mgcp_rqnt rqnt_cb;
void *data;
/* trunk handling */
diff --git a/src/mgcp/mgcp_protocol.c b/src/mgcp/mgcp_protocol.c
index f76342c..92559a3 100644
--- a/src/mgcp/mgcp_protocol.c
+++ b/src/mgcp/mgcp_protocol.c
@@ -2,8 +2,8 @@
/* The protocol implementation */
/*
- * (C) 2009-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009-2011 by On-Waves
+ * (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2009-2012 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -879,6 +879,15 @@ static struct msgb *handle_rsip(struct mgcp_config *cfg, struct msgb *msg)
return NULL;
}
+static char extract_tone(const char *line)
+{
+ const char *str = strstr(line, "D/");
+ if (!str)
+ return CHAR_MAX;
+
+ return str[2];
+}
+
/*
* This can request like DTMF detection and forward, fax detection... it
* can also request when the notification should be send and such. We don't
@@ -889,7 +898,8 @@ static struct msgb *handle_noti_req(struct mgcp_config *cfg, struct msgb *msg)
struct mgcp_msg_ptr data_ptrs[6];
const char *trans_id;
struct mgcp_endpoint *endp;
- int found;
+ int found, res = 0, i, line_start;
+ char tone = 0;
found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
if (found != 0)
@@ -899,7 +909,31 @@ static struct msgb *handle_noti_req(struct mgcp_config *cfg, struct msgb *msg)
LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n", ENDPOINT_NUMBER(endp));
return create_err_response(400, "RQNT", trans_id);
}
- return create_ok_response(200, "RQNT", trans_id);
+
+ MSG_TOKENIZE_START
+ switch (msg->l3h[line_start]) {
+ case 'S':
+ tone = extract_tone((const char *)&msg->l3h[line_start]);
+ break;
+ }
+ MSG_TOKENIZE_END
+
+ /* we didn't see a signal request with a tone */
+ if (tone == CHAR_MAX)
+ return create_ok_response(200, "RQNT", trans_id);
+
+ if (cfg->rqnt_cb)
+ res = cfg->rqnt_cb(endp, tone, (const char *) msg->l3h);
+
+ return res == 0 ?
+ create_ok_response(200, "RQNT", trans_id) :
+ create_err_response(res, "RQNT", trans_id);
+
+error:
+ LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d\n",
+ osmo_hexdump(msg->l3h, msgb_l3len(msg)),
+ ENDPOINT_NUMBER(endp), line_start, i);
+ return create_err_response(400, "RQNT", trans_id);
}
static void trunk_init(struct mgcp_trunk_config *trunk)
diff --git a/tests/mgcp/Makefile.am b/tests/mgcp/Makefile.am
index 008979b..e4aee29 100644
--- a/tests/mgcp/Makefile.am
+++ b/tests/mgcp/Makefile.am
@@ -4,5 +4,8 @@ noinst_PROGRAMS = mgcp_patch_test
EXTRA_DIST = mgcp_patch_test.ok
-mgcp_patch_test_SOURCES = mgcp_patch_test.c $(top_srcdir)/src/mgcp_patch.c
+mgcp_patch_test_SOURCES = mgcp_patch_test.c $(top_srcdir)/src/mgcp_patch.c \
+ $(top_srcdir)/src/mgcp/mgcp_protocol.c \
+ $(top_srcdir)/src/mgcp/mgcp_network.c \
+ $(top_srcdir)/src/debug.c
mgcp_patch_test_LDADD = $(LIBOSMOCORE_LIBS)
diff --git a/tests/mgcp/mgcp_patch_test.c b/tests/mgcp/mgcp_patch_test.c
index 683ea01..834b3e4 100644
--- a/tests/mgcp/mgcp_patch_test.c
+++ b/tests/mgcp/mgcp_patch_test.c
@@ -17,9 +17,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <mgcp/mgcp.h>
+#include <mgcp/mgcp_internal.h>
#include <mgcp_patch.h>
#include <ss7_application.h>
+#include <osmocom/core/application.h>
+#include <osmocom/core/talloc.h>
+
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
@@ -62,12 +67,44 @@ static const char mgcp_out[] =
"a=T38FaxVersion:0\r\n"
"a=T38MaxBitRate:14400\r\n";
+#define CRCX "CRCX 2 1@mgw MGCP 1.0\r\n" \
+ "M: sendrecv\r\n" \
+ "C: 2\r\n" \
+ "\r\n" \
+ "v=0\r\n" \
+ "c=IN IP4 123.12.12.123\r\n" \
+ "m=audio 5904 RTP/AVP 97\r\n" \
+ "a=rtpmap:97 GSM-EFR/8000\r\n"
+
+#define DLCX "DLCX 7 1@mgw MGCP 1.0\r\n" \
+ "C: 2\r\n"
+
+#define RQNT "RQNT 186908780 1@mgw MGCP 1.0\r\n" \
+ "X: B244F267488\r\n" \
+ "S: D/9\r\n"
+
+#define RQNT2 "RQNT 186908780 1@mgw MGCP 1.0\r\n" \
+ "X: ADD4F26746F\r\n" \
+ "R: D/[0-9#*](N), G/ft, fxr/t38\r\n"
+
+#define RQNT_RET "200 186908780 OK\r\n"
+
#define ASSERT(a, cmp, b, text) \
if (!((a) cmp (b))) { \
fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, text); \
abort(); \
}
+static struct msgb *create_msg(const char *str)
+{
+ struct msgb *msg;
+
+ msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
+ int len = sprintf((char *)msg->data, str);
+ msg->l2h = msgb_put(msg, len);
+ return msg;
+}
+
static void test_endp_name_rewriting()
{
struct ss7_application app;
@@ -95,9 +132,58 @@ static void test_endp_name_rewriting()
ASSERT(strcmp((const char *)msg_out->l2h, mgcp_out), ==, 0, "Text don't match");
}
+static int rqnt_cb(struct mgcp_endpoint *endp, char _tone, const char *data)
+{
+ ptrdiff_t tone = _tone;
+ endp->cfg->data = (void *) tone;
+ return 0;
+}
+
+static void test_rqnt_cb(void)
+{
+ struct mgcp_config *cfg;
+ struct mgcp_trunk_config *tcfg;
+ struct msgb *inp, *msg;
+
+ cfg = mgcp_config_alloc();
+ cfg->rqnt_cb = rqnt_cb;
+
+ tcfg = mgcp_vtrunk_alloc(cfg, "mgw");
+ tcfg->number_endpoints = 64;
+ mgcp_endpoints_allocate(tcfg);
+
+ inp = create_msg(CRCX);
+ msgb_free(mgcp_handle_message(cfg, inp));
+ msgb_free(inp);
+
+ /* send the RQNT and check for the CB */
+ inp = create_msg(RQNT);
+ msg = mgcp_handle_message(cfg, inp);
+ if (strncmp((const char *) msg->l2h, "200", 3) != 0) {
+ printf("FAILED: message is not 200. '%s'\n", msg->l2h);
+ abort();
+ }
+
+ if (cfg->data != (void *) '9') {
+ printf("FAILED: callback not called: %p\n", cfg->data);
+ abort();
+ }
+
+ msgb_free(msg);
+ msgb_free(inp);
+
+ inp = create_msg(DLCX);
+ msgb_free(mgcp_handle_message(cfg, inp));
+ msgb_free(inp);
+ talloc_free(cfg);
+}
+
int main(int argc, char **argv)
{
+ osmo_init_logging(&log_info);
+
test_endp_name_rewriting();
+ test_rqnt_cb();
printf("All tests passed.\n");
return 0;