libosmo-mgcp: Connection Identifiers are allocated by MGW, not CA
The MGCP connection identifier is allocated by the MGW while processing
the CRCX, see RFC3435 2.1.3.2:. Including/Accepting a connection
identifier in CRCX is "forbidden" as per RFC3435 Section 3.2.2.
So the MGW side must *reject* a CRCX message with 'I' parameter, and
allocate a connection identifier which is subsequently returned in the
response.
Closes: OS#2648
Change-Id: Iab6a6038e7610c62f34e642cd49c93d11151252c
diff --git a/TODO-RELEASE b/TODO-RELEASE
index 917c995..9d0e0dc 100644
--- a/TODO-RELEASE
+++ b/TODO-RELEASE
@@ -23,5 +23,7 @@
# If any interfaces have been added since the last public release, a++;
# If any interfaces have been removed or changed since the last public release, a=0.
#
-#library what description / commit summary line
-libosmo-mgcp API/ABI change parse and represent connection identifiers as hex strings
\ No newline at end of file
+#library what description / commit summary line
+libosmo-mgcp API/ABI change parse and represent connection identifiers as hex strings
+libosmo-mgcp API/ABI change connection identifiers are assigned by the server, not CA
+libosmo-mgcp-client API/ABI change parse and store connection identifier in response
\ No newline at end of file
diff --git a/configure.ac b/configure.ac
index f72b9e1..606f404 100644
--- a/configure.ac
+++ b/configure.ac
@@ -40,6 +40,7 @@
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.10.0)
+PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.10.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.10.0)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.1.0)
diff --git a/include/osmocom/mgcp/mgcp_conn.h b/include/osmocom/mgcp/mgcp_conn.h
index 982a311..e2a423f 100644
--- a/include/osmocom/mgcp/mgcp_conn.h
+++ b/include/osmocom/mgcp/mgcp_conn.h
@@ -28,8 +28,7 @@
#include <inttypes.h>
struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
- const char *id, enum mgcp_conn_type type,
- char *name);
+ enum mgcp_conn_type type, char *name);
struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, const char *id);
struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp,
const char *id);
diff --git a/src/libosmo-mgcp-client/mgcp_client.c b/src/libosmo-mgcp-client/mgcp_client.c
index a89da99..7e83f95 100644
--- a/src/libosmo-mgcp-client/mgcp_client.c
+++ b/src/libosmo-mgcp-client/mgcp_client.c
@@ -257,6 +257,58 @@
return 0;
}
+/* Parse a line like "I: 0cedfd5a19542d197af9afe5231f1d61" */
+static int mgcp_parse_conn_id(struct mgcp_response *r, const char *line)
+{
+ if (strlen(line) < 4)
+ goto response_parse_failure;
+
+ if (memcmp("I: ", line, 3) != 0)
+ goto response_parse_failure;
+
+ osmo_strlcpy(r->head.conn_id, line + 3, sizeof(r->head.conn_id));
+ return 0;
+
+response_parse_failure:
+ LOGP(DLMGCP, LOGL_ERROR,
+ "Failed to parse MGCP response (connectionIdentifier)\n");
+ return -EINVAL;
+}
+
+/* Parse MGCP parameters of the response */
+static int parse_head_params(struct mgcp_response *r)
+{
+ char *line;
+ int rc = 0;
+ OSMO_ASSERT(r->body);
+ char *data = r->body;
+ char *data_end = strstr(r->body, "\n\n");
+
+ /* Protect SDP body, for_each_non_empty_line() will
+ * only parse until it hits \0 mark. */
+ if (data_end)
+ *data_end = '\0';
+
+ for_each_non_empty_line(line, data) {
+ switch (line[0]) {
+ case 'I':
+ rc = mgcp_parse_conn_id(r, line);
+ if (rc)
+ goto exit;
+ break;
+ default:
+ /* skip unhandled parameters */
+ break;
+ }
+ }
+exit:
+ /* Restore original state */
+ if (data_end)
+ *data_end = '\n';
+
+ return rc;
+}
+
static struct mgcp_response_pending *mgcp_client_response_pending_get(
struct mgcp_client *mgcp,
struct mgcp_response *r)
@@ -287,7 +339,13 @@
rc = mgcp_response_parse_head(&r, msg);
if (rc) {
- LOGP(DLMGCP, LOGL_ERROR, "Cannot parse MGCP response\n");
+ LOGP(DLMGCP, LOGL_ERROR, "Cannot parse MGCP response (head)\n");
+ return -1;
+ }
+
+ rc = parse_head_params(&r);
+ if (rc) {
+ LOGP(DLMGCP, LOGL_ERROR, "Cannot parse MGCP response (head parameters)\n");
return -1;
}
@@ -648,7 +706,6 @@
#define MGCP_CRCX_MANDATORY (MGCP_MSG_PRESENCE_ENDPOINT | \
MGCP_MSG_PRESENCE_CALL_ID | \
- MGCP_MSG_PRESENCE_CONN_ID | \
MGCP_MSG_PRESENCE_CONN_MODE)
#define MGCP_MDCX_MANDATORY (MGCP_MSG_PRESENCE_ENDPOINT | \
MGCP_MSG_PRESENCE_CONN_ID)
@@ -719,8 +776,7 @@
rc += msgb_printf(msg, "I: %s\r\n", mgcp_msg->conn_id);
/* Add local connection options */
- if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CONN_ID
- && mgcp_msg->verb == MGCP_VERB_CRCX)
+ if (mgcp_msg->verb == MGCP_VERB_CRCX)
rc += msgb_printf(msg, "L: p:20, a:AMR, nt:IN\r\n");
/* Add mode */
diff --git a/src/libosmo-mgcp/Makefile.am b/src/libosmo-mgcp/Makefile.am
index fce0e1b..a785d62 100644
--- a/src/libosmo-mgcp/Makefile.am
+++ b/src/libosmo-mgcp/Makefile.am
@@ -7,6 +7,7 @@
AM_CFLAGS = \
-Wall \
$(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) \
$(LIBOSMONETIF_CFLAGS) \
$(COVERAGE_CFLAGS) \
@@ -14,6 +15,7 @@
AM_LDFLAGS = \
$(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(LIBOSMONETIF_LIBS) \
$(COVERAGE_LDFLAGS) \
diff --git a/src/libosmo-mgcp/mgcp_conn.c b/src/libosmo-mgcp/mgcp_conn.c
index 31713cb..e33596d 100644
--- a/src/libosmo-mgcp/mgcp_conn.c
+++ b/src/libosmo-mgcp/mgcp_conn.c
@@ -25,6 +25,46 @@
#include <osmocom/mgcp/mgcp_internal.h>
#include <osmocom/mgcp/mgcp_common.h>
#include <osmocom/mgcp/mgcp_ep.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <ctype.h>
+
+/* Allocate a new connection identifier. According to RFC3435, they must
+ * be unique only within the scope of the endpoint. */
+static int mgcp_alloc_id(struct mgcp_endpoint *endp, char *id)
+{
+ int i;
+ int k;
+ int rc;
+ uint8_t id_bin[16];
+ char *id_hex;
+
+ /* Generate a connection id that is unique for the current endpoint.
+ * Technically a counter would be sufficient, but in order to
+ * be able to find a specific connection in large logfiles and to
+ * prevent unintentional connections we assign the connection
+ * identifiers randomly from a reasonable large number space */
+ for (i = 0; i < 32; i++) {
+ rc = osmo_get_rand_id(id_bin, sizeof(id_bin));
+ if (rc < 0)
+ return rc;
+
+ id_hex = osmo_hexdump_nospc(id_bin, sizeof(id_bin));
+ for (k = 0; k < strlen(id_hex); k++)
+ id_hex[k] = toupper(id_hex[k]);
+
+ /* ensure that the generated conn_id is unique
+ * for this endpoint */
+ if (!mgcp_conn_get_rtp(endp, id_hex)) {
+ osmo_strlcpy(id, id_hex, MGCP_CONN_ID_LENGTH);
+ return 0;
+ }
+ }
+
+ LOGP(DLMGCP, LOGL_ERROR, "endpoint:%x, unable to generate a unique connectionIdentifier\n",
+ ENDPOINT_NUMBER(endp));
+
+ return -1;
+}
/* Reset codec state and free memory */
static void mgcp_rtp_codec_reset(struct mgcp_rtp_codec *codec)
@@ -78,30 +118,19 @@
* \param[in] type connection type (e.g. MGCP_CONN_TYPE_RTP)
* \returns pointer to allocated connection, NULL on error */
struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
- const char *id, enum mgcp_conn_type type,
- char *name)
+ enum mgcp_conn_type type, char *name)
{
struct mgcp_conn *conn;
+ int rc;
+
OSMO_ASSERT(endp);
OSMO_ASSERT(endp->conns.next != NULL && endp->conns.prev != NULL);
OSMO_ASSERT(strlen(name) < sizeof(conn->name));
- /* Id is a mandatory parameter */
- if (!id)
- return NULL;
-
- /* Prevent over long id strings */
- if (strlen(id) >= MGCP_CONN_ID_LENGTH)
- return NULL;
-
/* Do not allow more then two connections */
if (llist_count(&endp->conns) >= endp->type->max_conns)
return NULL;
- /* Prevent duplicate connection IDs */
- if (mgcp_conn_get(endp, id))
- return NULL;
-
/* Create new connection and add it to the list */
conn = talloc_zero(ctx, struct mgcp_conn);
if (!conn)
@@ -112,7 +141,11 @@
conn->mode_orig = MGCP_CONN_NONE;
conn->u.rtp.conn = conn;
strcpy(conn->name, name);
- osmo_strlcpy(conn->id, id, sizeof(conn->id));
+ rc = mgcp_alloc_id(endp, conn->id);
+ if (rc < 0) {
+ talloc_free(conn);
+ return NULL;
+ }
switch (type) {
case MGCP_CONN_TYPE_RTP:
diff --git a/src/libosmo-mgcp/mgcp_protocol.c b/src/libosmo-mgcp/mgcp_protocol.c
index 672a8d4..feca8da 100644
--- a/src/libosmo-mgcp/mgcp_protocol.c
+++ b/src/libosmo-mgcp/mgcp_protocol.c
@@ -447,7 +447,7 @@
char *line;
int have_sdp = 0, osmux_cid = -1;
struct mgcp_conn_rtp *conn = NULL;
- const char *conn_id = NULL;
+ struct mgcp_conn *_conn = NULL;
char conn_name[512];
LOGP(DLMGCP, LOGL_NOTICE, "CRCX: creating new connection ...\n");
@@ -468,7 +468,10 @@
callid = (const char *)line + 3;
break;
case 'I':
- conn_id = (const char *)line + 3;
+ /* It is illegal to send a connection identifier
+ * together with a CRCX, the MGW will assign the
+ * connection identifier by itself on CRCX */
+ return create_err_response(NULL, 523, "CRCX", p->trans);
break;
case 'M':
mode = (const char *)line + 3;
@@ -510,13 +513,6 @@
return create_err_response(endp, 400, "CRCX", p->trans);
}
- if (!conn_id) {
- LOGP(DLMGCP, LOGL_ERROR,
- "CRCX: endpoint:%x insufficient parameters, missing connection id\n",
- ENDPOINT_NUMBER(endp));
- return create_err_response(endp, 400, "CRCX", p->trans);
- }
-
/* Check if we are able to accept the creation of another connection */
if (llist_count(&endp->conns) >= endp->type->max_conns) {
LOGP(DLMGCP, LOGL_ERROR,
@@ -560,32 +556,17 @@
set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
local_options);
- /* Only accept another connection when the connection ID is different. */
- if (mgcp_conn_get_rtp(endp, conn_id)) {
- LOGP(DLMGCP, LOGL_ERROR,
- "CRCX: endpoint:%x there is already a connection with id %u present!\n",
- conn_id, ENDPOINT_NUMBER(endp));
- if (tcfg->force_realloc) {
- /* Ignore the existing connection by just freeing it */
- mgcp_conn_free(endp, conn_id);
- } else {
- /* There is already a connection with that ID present,
- * leave everything as it is and return with an error. */
- return create_err_response(endp, 400, "CRCX", p->trans);
- }
- }
-
- snprintf(conn_name, sizeof(conn_name), "%s-%s", callid, conn_id);
- mgcp_conn_alloc(NULL, endp, conn_id, MGCP_CONN_TYPE_RTP,
- conn_name);
- conn = mgcp_conn_get_rtp(endp, conn_id);
- if (!conn) {
+ snprintf(conn_name, sizeof(conn_name), "%s", callid);
+ _conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP, conn_name);
+ if (!_conn) {
LOGP(DLMGCP, LOGL_ERROR,
"CRCX: endpoint:%x unable to allocate RTP connection\n",
ENDPOINT_NUMBER(endp));
goto error2;
}
+ conn = mgcp_conn_get_rtp(endp, _conn->id);
+ OSMO_ASSERT(conn);
if (mgcp_parse_conn_mode(mode, endp, conn->conn) != 0) {
error_code = 517;
diff --git a/tests/mgcp/mgcp_test.c b/tests/mgcp/mgcp_test.c
index 7d976da..fb99911 100644
--- a/tests/mgcp/mgcp_test.c
+++ b/tests/mgcp/mgcp_test.c
@@ -82,27 +82,27 @@
#define MDCX3 \
"MDCX 18983215 1@mgw MGCP 1.0\r\n" \
- "I: 1\n"
+ "I: %s\n"
#define MDCX3_RET \
"200 18983215 OK\r\n" \
- "I: 1\n" \
+ "I: %s\n" \
"\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
- "m=audio 16002 RTP/AVP 128\r\n" \
- "a=rtpmap:128 GSM-EFR/8000\r\n" \
+ "m=audio 16002 RTP/AVP 97\r\n" \
+ "a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:40\r\n"
#define MDCX3A_RET \
"200 18983215 OK\r\n" \
- "I: 1\n" \
+ "I: %s\n" \
"\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
@@ -112,15 +112,15 @@
#define MDCX3_FMTP_RET \
"200 18983215 OK\r\n" \
- "I: 1\n" \
+ "I: %s\n" \
"\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
- "m=audio 16006 RTP/AVP 128\r\n" \
- "a=rtpmap:128 GSM-EFR/8000\r\n" \
+ "m=audio 16006 RTP/AVP 97\r\n" \
+ "a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=fmtp:126 0/1/2\r\n" \
"a=ptime:40\r\n"
@@ -128,11 +128,11 @@
"MDCX 18983216 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
- "I: 1\r\n" \
+ "I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n" \
"\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
@@ -141,10 +141,10 @@
#define MDCX4_RET(Ident) \
"200 " Ident " OK\r\n" \
- "I: 1\n" \
+ "I: %s\n" \
"\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
@@ -154,10 +154,10 @@
#define MDCX4_RO_RET(Ident) \
"200 " Ident " OK\r\n" \
- "I: 1\n" \
+ "I: %s\n" \
"\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
@@ -169,11 +169,11 @@
"MDCX 18983217 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
- "I: 1\r\n" \
+ "I: %s\r\n" \
"L: p:20-40, a:AMR, nt:IN\r\n" \
"\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
@@ -184,11 +184,11 @@
"MDCX 18983218 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
- "I: 1\r\n" \
+ "I: %s\r\n" \
"L: p:20-20, a:AMR, nt:IN\r\n" \
"\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
@@ -199,11 +199,11 @@
"MDCX 18983219 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
- "I: 1\r\n" \
+ "I: %s\r\n" \
"L: a:AMR, nt:IN\r\n" \
"\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
@@ -214,11 +214,11 @@
"MDCX 18983220 1@mgw MGCP 1.0\r\n" \
"M: sendonly\r" \
"C: 2\r\n" \
- "I: 1\r\n" \
+ "I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n" \
"\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
@@ -229,7 +229,7 @@
"MDCX 18983221 1@mgw MGCP 1.0\r\n" \
"M: recvonly\r" \
"C: 2\r\n" \
- "I: 1\r\n" \
+ "I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n"
#define SHORT2 "CRCX 1"
@@ -242,7 +242,6 @@
"CRCX 2 1@mgw MGCP 1.0\r\n" \
"M: recvonly\r\n" \
"C: 2\r\n" \
- "I: 1\r\n" \
"L: p:20\r\n" \
"\r\n" \
"v=0\r\n" \
@@ -253,10 +252,10 @@
#define CRCX_RET \
"200 2 OK\r\n" \
- "I: 1\n" \
+ "I: %s\n" \
"\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
@@ -266,10 +265,10 @@
#define CRCX_RET_NO_RTPMAP \
"200 2 OK\r\n" \
- "I: 1\n" \
+ "I: %s\n" \
"\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
@@ -278,10 +277,10 @@
#define CRCX_FMTP_RET \
"200 2 OK\r\n" \
- "I: 1\n" \
+ "I: %s\n" \
"\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
@@ -294,7 +293,6 @@
"CRCX 2 1@mgw MGCP 1.0\r" \
"M: recvonly\r" \
"C: 2\r\n" \
- "I: 1\n" \
"\n" \
"v=0\r" \
"c=IN IP4 123.12.12.123\r" \
@@ -303,10 +301,10 @@
#define CRCX_ZYN_RET \
"200 2 OK\r\n" \
- "I: 1\n" \
+ "I: %s\n" \
"\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
@@ -316,7 +314,7 @@
#define DLCX \
"DLCX 7 1@mgw MGCP 1.0\r\n" \
- "I: 1\r\n" \
+ "I: %s\r\n" \
"C: 2\r\n"
#define DLCX_RET \
@@ -343,7 +341,6 @@
#define CRCX_MULT_1 \
"CRCX 2 1@mgw MGCP 1.0\r\n" \
- "I: 4711\r\n" \
"M: recvonly\r\n" \
"C: 2\r\n" \
"X\r\n" \
@@ -358,7 +355,6 @@
#define CRCX_MULT_2 \
"CRCX 2 2@mgw MGCP 1.0\r\n" \
- "I: 90210\r\n" \
"M: recvonly\r\n" \
"C: 2\r\n" \
"X\r\n" \
@@ -374,7 +370,6 @@
#define CRCX_MULT_3 \
"CRCX 2 3@mgw MGCP 1.0\r\n" \
- "I: 0815\r\n" \
"M: recvonly\r\n" \
"C: 2\r\n" \
"X\r\n" \
@@ -390,7 +385,6 @@
#define CRCX_MULT_4 \
"CRCX 2 4@mgw MGCP 1.0\r\n" \
- "I: 32168\r\n" \
"M: recvonly\r\n" \
"C: 2\r\n" \
"X\r\n" \
@@ -407,7 +401,6 @@
#define CRCX_MULT_GSM_EXACT \
"CRCX 259260421 5@mgw MGCP 1.0\r\n" \
"C: 1355c6041e\r\n" \
- "I: 3\r\n" \
"L: p:20, a:GSM, nt:IN\r\n" \
"M: recvonly\r\n" \
"\r\n" \
@@ -432,7 +425,7 @@
#define MDCX_NAT_DUMMY \
"MDCX 23 5@mgw MGCP 1.0\r\n" \
"C: 1355c6041e\r\n" \
- "I: 3\r\n" \
+ "I: %s\r\n" \
"\r\n" \
"c=IN IP4 8.8.8.8\r\n" \
"m=audio 16434 RTP/AVP 255\r\n"
@@ -482,12 +475,20 @@
{"DLCX", DLCX, DLCX_RET},
};
-static struct msgb *create_msg(const char *str)
+static struct msgb *create_msg(const char *str, const char *conn_id)
{
struct msgb *msg;
+ int len;
+
+ printf("creating message from statically defined input:\n");
+ printf("---------8<---------\n%s\n---------8<---------\n", str);
msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
- int len = sprintf((char *)msg->data, "%s", str);
+ if (conn_id && strlen(conn_id))
+ len = sprintf((char *)msg->data, str, conn_id, conn_id);
+ else
+ len = sprintf((char *)msg->data, "%s", str);
+
msg->l2h = msgb_put(msg, len);
return msg;
}
@@ -554,12 +555,87 @@
MGCP_CONN_RECV_SEND);
}
+/* Extract a connection ID from a response (CRCX) */
+static int get_conn_id_from_response(uint8_t *resp, char *conn_id,
+ unsigned int conn_id_len)
+{
+ char *conn_id_ptr;
+ int i;
+
+ conn_id_ptr = strstr((char *)resp, "I: ");
+ if (!conn_id_ptr)
+ return -EINVAL;
+
+ memset(conn_id, 0, conn_id_len);
+ memcpy(conn_id, conn_id_ptr + 3, 32);
+
+ for (i = 0; i < conn_id_len; i++) {
+ if (conn_id[i] == '\n' || conn_id[i] == '\r')
+ conn_id[i] = '\0';
+ }
+
+ /* A valid conn_id must at least contain one digit, and must
+ * not exceed a length of 32 digits */
+ OSMO_ASSERT(strlen(conn_id) <= 32);
+ OSMO_ASSERT(strlen(conn_id) > 0);
+
+ return 0;
+}
+
+/* Check response, automatically patch connection ID if needed */
+static int check_response(uint8_t *resp, const char *exp_resp)
+{
+ char exp_resp_patched[4096];
+ const char *exp_resp_ptr;
+ char conn_id[256];
+
+ printf("checking response:\n");
+
+ /* If the expected response is intened to be patched
+ * (%s placeholder inside) we will patch it with the
+ * connection identifier we just received from the
+ * real response. This is necessary because the CI
+ * is generated by the mgcp code on CRCX and we can
+ * not know it in advance */
+ if (strstr(exp_resp, "%s")) {
+ if (get_conn_id_from_response(resp, conn_id, sizeof(conn_id)) ==
+ 0) {
+ sprintf(exp_resp_patched, exp_resp, conn_id, conn_id);
+ exp_resp_ptr = exp_resp_patched;
+ printf
+ ("using message with patched conn_id for comparison\n");
+ } else {
+ printf
+ ("patching conn_id failed, using message as statically defined for comparison\n");
+ exp_resp_ptr = exp_resp;
+ }
+ } else {
+ printf("using message as statically defined for comparison\n");
+ exp_resp_ptr = exp_resp;
+ }
+
+ if (strcmp((char *)resp, exp_resp_ptr) != 0) {
+ printf("Unexpected response, please check!\n");
+ printf
+ ("Got:\n---------8<---------\n%s\n---------8<---------\n\n",
+ resp);
+ printf
+ ("Expected:\n---------8<---------\n%s\n---------8<---------\n",
+ exp_resp_ptr);
+ return -EINVAL;
+ }
+
+ printf("Response matches our expectations.\n");
+ return 0;
+}
+
static void test_messages(void)
{
struct mgcp_config *cfg;
struct mgcp_endpoint *endp;
int i;
struct mgcp_conn_rtp *conn = NULL;
+ char last_conn_id[256];
cfg = mgcp_config_alloc();
@@ -567,6 +643,8 @@
mgcp_endpoints_allocate(&cfg->trunk);
cfg->policy_cb = mgcp_test_policy_cb;
+ memset(last_conn_id, 0, sizeof(last_conn_id));
+
mgcp_endpoints_allocate(mgcp_trunk_alloc(cfg, 1));
for (i = 0; i < ARRAY_SIZE(tests); i++) {
@@ -574,6 +652,7 @@
struct msgb *inp;
struct msgb *msg;
+ printf("\n================================================\n");
printf("Testing %s\n", t->name);
last_endpoint = -1;
@@ -582,7 +661,7 @@
osmo_talloc_replace_string(cfg, &cfg->trunk.audio_fmtp_extra,
t->extra_fmtp);
- inp = create_msg(t->req);
+ inp = create_msg(t->req, last_conn_id);
msg = mgcp_handle_message(cfg, inp);
msgb_free(inp);
if (!t->exp_resp) {
@@ -591,11 +670,15 @@
(char *)msg->data);
OSMO_ASSERT(false);
}
- } else if (strcmp((char *)msg->data, t->exp_resp) != 0) {
- printf("%s failed.\nExpected:\n%s\nGot:\n%s\n",
- t->name, t->exp_resp, (char *) msg->data);
+ } else if (check_response(msg->data, t->exp_resp) != 0) {
+ printf("%s failed.\n", t->name);
OSMO_ASSERT(false);
}
+
+ if (msg)
+ get_conn_id_from_response(msg->data, last_conn_id,
+ sizeof(last_conn_id));
+
msgb_free(msg);
if (dummy_packets)
@@ -656,7 +739,7 @@
}
/* Check detected payload type */
- if (t->ptype != PTYPE_IGNORE) {
+ if (conn && t->ptype != PTYPE_IGNORE) {
OSMO_ASSERT(last_endpoint != -1);
endp = &cfg->trunk.endpoints[last_endpoint];
@@ -681,12 +764,15 @@
{
struct mgcp_config *cfg;
int i;
+ char last_conn_id[256];
cfg = mgcp_config_alloc();
cfg->trunk.vty_number_endpoints = 64;
mgcp_endpoints_allocate(&cfg->trunk);
+ memset(last_conn_id, 0, sizeof(last_conn_id));
+
mgcp_endpoints_allocate(mgcp_trunk_alloc(cfg, 1));
for (i = 0; i < ARRAY_SIZE(retransmit); i++) {
@@ -694,24 +780,30 @@
struct msgb *inp;
struct msgb *msg;
+ printf("\n================================================\n");
printf("Testing %s\n", t->name);
- inp = create_msg(t->req);
+ inp = create_msg(t->req, last_conn_id);
msg = mgcp_handle_message(cfg, inp);
msgb_free(inp);
- if (strcmp((char *)msg->data, t->exp_resp) != 0) {
+ if (check_response(msg->data, t->exp_resp) != 0) {
printf("%s failed '%s'\n", t->name, (char *)msg->data);
OSMO_ASSERT(false);
}
+
+ if (msg && strcmp(t->name, CRCX))
+ get_conn_id_from_response(msg->data, last_conn_id,
+ sizeof(last_conn_id));
+
msgb_free(msg);
/* Retransmit... */
printf("Re-transmitting %s\n", t->name);
- inp = create_msg(t->req);
+ inp = create_msg(t->req, last_conn_id);
msg = mgcp_handle_message(cfg, inp);
msgb_free(inp);
- if (strcmp((char *)msg->data, t->exp_resp) != 0) {
+ if (check_response(msg->data, t->exp_resp) != 0) {
printf("%s failed '%s'\n", t->name, (char *)msg->data);
OSMO_ASSERT(false);
}
@@ -732,6 +824,7 @@
{
struct mgcp_config *cfg;
struct msgb *inp, *msg;
+ char conn_id[256];
cfg = mgcp_config_alloc();
cfg->rqnt_cb = rqnt_cb;
@@ -741,12 +834,16 @@
mgcp_endpoints_allocate(mgcp_trunk_alloc(cfg, 1));
- inp = create_msg(CRCX);
- msgb_free(mgcp_handle_message(cfg, inp));
+ inp = create_msg(CRCX, NULL);
+ msg = mgcp_handle_message(cfg, inp);
+ OSMO_ASSERT(msg);
+ OSMO_ASSERT(get_conn_id_from_response(msg->data, conn_id,
+ sizeof(conn_id)) == 0);
+ msgb_free(msg);
msgb_free(inp);
/* send the RQNT and check for the CB */
- inp = create_msg(RQNT);
+ inp = create_msg(RQNT, conn_id);
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);
@@ -761,7 +858,7 @@
msgb_free(msg);
msgb_free(inp);
- inp = create_msg(DLCX);
+ inp = create_msg(DLCX, conn_id);
msgb_free(mgcp_handle_message(cfg, inp));
msgb_free(inp);
talloc_free(cfg);
@@ -864,7 +961,7 @@
int loss;
int rc;
- msg = create_msg(DLCX_RET);
+ msg = create_msg(DLCX_RET, NULL);
rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter);
printf("Parsing result: %d\n", rc);
if (bps != 0 || bos != 0 || pr != 0 || _or != 0 || loss != 0
@@ -874,7 +971,7 @@
msg =
create_msg
- ("250 7 OK\r\nP: PS=10, OS=20, PR=30, OR=40, PL=-3, JI=40\r\n");
+ ("250 7 OK\r\nP: PS=10, OS=20, PR=30, OR=40, PL=-3, JI=40\r\n", NULL);
rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter);
printf("Parsing result: %d\n", rc);
if (bps != 10 || bos != 20 || pr != 30 || _or != 40 || loss != -3
@@ -1013,6 +1110,7 @@
int last_in_ts_err_cnt = 0;
int last_out_ts_err_cnt = 0;
struct mgcp_conn_rtp *conn = NULL;
+ struct mgcp_conn *_conn = NULL;
printf("Testing packet error detection%s%s.\n",
patch_ssrc ? ", patch SSRC" : "",
@@ -1032,9 +1130,10 @@
endp.tcfg = &trunk;
INIT_LLIST_HEAD(&endp.conns);
- mgcp_conn_alloc(NULL, &endp, "4711", MGCP_CONN_TYPE_RTP,
- "test-connection");
- conn = mgcp_conn_get_rtp(&endp, "4711");
+ _conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
+ "test-connection");
+ OSMO_ASSERT(_conn);
+ conn = mgcp_conn_get_rtp(&endp, _conn->id);
OSMO_ASSERT(conn);
rtp = &conn->end;
@@ -1092,6 +1191,7 @@
struct msgb *inp, *resp;
struct in_addr addr;
struct mgcp_conn_rtp *conn = NULL;
+ char conn_id[256];
printf("Testing multiple payload types\n");
@@ -1103,85 +1203,95 @@
/* Allocate endpoint 1@mgw with two codecs */
last_endpoint = -1;
- inp = create_msg(CRCX_MULT_1);
+ inp = create_msg(CRCX_MULT_1, NULL);
resp = mgcp_handle_message(cfg, inp);
+ OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
+ sizeof(conn_id)) == 0);
msgb_free(inp);
msgb_free(resp);
OSMO_ASSERT(last_endpoint == 1);
endp = &cfg->trunk.endpoints[last_endpoint];
- conn = mgcp_conn_get_rtp(endp, "4711");
+ conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.codec.payload_type == 18);
OSMO_ASSERT(conn->end.alt_codec.payload_type == 97);
/* Allocate 2@mgw with three codecs, last one ignored */
last_endpoint = -1;
- inp = create_msg(CRCX_MULT_2);
+ inp = create_msg(CRCX_MULT_2, NULL);
resp = mgcp_handle_message(cfg, inp);
+ OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
+ sizeof(conn_id)) == 0);
msgb_free(inp);
msgb_free(resp);
OSMO_ASSERT(last_endpoint == 2);
endp = &cfg->trunk.endpoints[last_endpoint];
- conn = mgcp_conn_get_rtp(endp, "90210");
+ conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.codec.payload_type == 18);
OSMO_ASSERT(conn->end.alt_codec.payload_type == 97);
/* Allocate 3@mgw with no codecs, check for PT == -1 */
last_endpoint = -1;
- inp = create_msg(CRCX_MULT_3);
+ inp = create_msg(CRCX_MULT_3, NULL);
resp = mgcp_handle_message(cfg, inp);
+ OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
+ sizeof(conn_id)) == 0);
msgb_free(inp);
msgb_free(resp);
OSMO_ASSERT(last_endpoint == 3);
endp = &cfg->trunk.endpoints[last_endpoint];
- conn = mgcp_conn_get_rtp(endp, "0815");
+ conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.codec.payload_type == -1);
OSMO_ASSERT(conn->end.alt_codec.payload_type == -1);
/* Allocate 4@mgw with a single codec */
last_endpoint = -1;
- inp = create_msg(CRCX_MULT_4);
+ inp = create_msg(CRCX_MULT_4, NULL);
resp = mgcp_handle_message(cfg, inp);
+ OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
+ sizeof(conn_id)) == 0);
msgb_free(inp);
msgb_free(resp);
OSMO_ASSERT(last_endpoint == 4);
endp = &cfg->trunk.endpoints[last_endpoint];
- conn = mgcp_conn_get_rtp(endp, "32168");
+ conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.codec.payload_type == 18);
OSMO_ASSERT(conn->end.alt_codec.payload_type == -1);
/* Allocate 5@mgw at select GSM.. */
last_endpoint = -1;
- inp = create_msg(CRCX_MULT_GSM_EXACT);
+ inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
talloc_free(cfg->trunk.audio_name);
cfg->trunk.audio_name = "GSM/8000";
cfg->trunk.no_audio_transcoding = 1;
resp = mgcp_handle_message(cfg, inp);
+ OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
+ sizeof(conn_id)) == 0);
msgb_free(inp);
msgb_free(resp);
OSMO_ASSERT(last_endpoint == 5);
endp = &cfg->trunk.endpoints[last_endpoint];
- conn = mgcp_conn_get_rtp(endp, "3");
+ conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.codec.payload_type == 3);
OSMO_ASSERT(conn->end.alt_codec.payload_type == -1);
- inp = create_msg(MDCX_NAT_DUMMY);
+ inp = create_msg(MDCX_NAT_DUMMY, conn_id);
last_endpoint = -1;
resp = mgcp_handle_message(cfg, inp);
msgb_free(inp);
msgb_free(resp);
OSMO_ASSERT(last_endpoint == 5);
endp = &cfg->trunk.endpoints[last_endpoint];
- conn = mgcp_conn_get_rtp(endp, "3");
+ conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.codec.payload_type == 3);
OSMO_ASSERT(conn->end.alt_codec.payload_type == -1);
@@ -1198,19 +1308,21 @@
talloc_free(endp->last_response);
talloc_free(endp->last_trans);
endp->last_response = endp->last_trans = NULL;
- conn = mgcp_conn_get_rtp(endp, "3");
+ conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(!conn);
last_endpoint = -1;
- inp = create_msg(CRCX_MULT_GSM_EXACT);
+ inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
cfg->trunk.no_audio_transcoding = 0;
resp = mgcp_handle_message(cfg, inp);
+ OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
+ sizeof(conn_id)) == 0);
msgb_free(inp);
msgb_free(resp);
OSMO_ASSERT(last_endpoint == 5);
endp = &cfg->trunk.endpoints[last_endpoint];
- conn = mgcp_conn_get_rtp(endp, "3");
+ conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.codec.payload_type == 255);
OSMO_ASSERT(conn->end.alt_codec.payload_type == 0);
@@ -1223,6 +1335,7 @@
struct mgcp_config *cfg;
struct mgcp_endpoint *endp;
struct mgcp_conn_rtp *conn = NULL;
+ struct mgcp_conn *_conn = NULL;
printf("Testing no sequence flow on initial packet\n");
@@ -1232,9 +1345,10 @@
endp = &cfg->trunk.endpoints[1];
- mgcp_conn_alloc(NULL, endp, "4711", MGCP_CONN_TYPE_RTP,
- "test-connection");
- conn = mgcp_conn_get_rtp(endp, "4711");
+ _conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP,
+ "test-connection");
+ OSMO_ASSERT(_conn);
+ conn = mgcp_conn_get_rtp(endp, _conn->id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->state.stats_initialized == 0);
@@ -1281,9 +1395,10 @@
mgcp_endpoints_allocate(mgcp_trunk_alloc(cfg, 1));
- inp = create_msg(CRCX);
+ inp = create_msg(CRCX, NULL);
msg = mgcp_handle_message(cfg, inp);
- if (strcmp((char *)msg->data, CRCX_RET_NO_RTPMAP) != 0) {
+
+ if (check_response(msg->data, CRCX_RET_NO_RTPMAP) != 0) {
printf("FAILED: there should not be a RTPMAP: %s\n",
(char *)msg->data);
OSMO_ASSERT(false);
diff --git a/tests/mgcp/mgcp_test.ok b/tests/mgcp/mgcp_test.ok
index 7376930..c764531 100644
--- a/tests/mgcp/mgcp_test.ok
+++ b/tests/mgcp/mgcp_test.ok
Binary files differ