2016-05-20 19:59:55 +00:00
|
|
|
/*
|
|
|
|
* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
|
|
|
* All Rights Reserved
|
|
|
|
*
|
|
|
|
* Author: Neels Hofmeyr
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Affero General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2018-02-21 15:45:38 +00:00
|
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
|
|
|
2016-05-20 19:59:55 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <osmocom/core/msgb.h>
|
|
|
|
#include <osmocom/core/application.h>
|
2017-09-03 23:02:56 +00:00
|
|
|
#include <osmocom/mgcp_client/mgcp_client.h>
|
|
|
|
#include <osmocom/mgcp_client/mgcp_client_internal.h>
|
mgcp_client: add transaction cleanup
So far, if an MGCP message is sent, the transaction gets enqueued, but there is
no way to end the transaction other than receiving a valid reply. So, if the
caller decides that the transaction timed out and tears down the priv pointer
passed to mgcp_client_tx, and if then a late reply arrives, the callback will
dereference the invalid priv pointer and cause a segfault. Hence it is possible
to crash an mgcp_client program by sending a late response.
Furthermore, if no reply ever arrives, we would keep the pending response in
the list forever, amounting to a "memory leak".
Add mgcp_client_cancel() to discard a pending transaction. The caller can now
decide to discard a pending response when it sees fit (e.g. the caller's
timeout expired). This needs to be added to OsmoMSC and OsmoBSC.
Add mgcp_msg_trans_id() to provide an obvious way to obtain the transaction id
from a generated MGCP message.
No public API is broken; but refine the negative return code from
mgcp_client_rx(): return -ENOENT if no such transaction ID is found, and still
-1 if decoding failed. This is mainly for mgcp_client_test.
Implement a test for mgcp_client_cancel() in mgcp_client_test.c.
Tweak internal mgcp_client_response_pending_get() to take only the transaction
id as argument instead of the entire mgcp message struct.
Found-by: dexter
Related: OS#2695 OS#2696
Change-Id: I16811e168a46a82a05943252a737b3434143f4bd
2017-11-30 12:43:11 +00:00
|
|
|
#include <errno.h>
|
2016-05-20 19:59:55 +00:00
|
|
|
|
|
|
|
void *ctx;
|
|
|
|
|
|
|
|
#define buf_len 4096
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
static struct msgb *from_hex(const char *hex)
|
|
|
|
{
|
|
|
|
struct msgb *msg = msgb_alloc(buf_len, "mgcpgw_test_from_hex");
|
|
|
|
unsigned int l = osmo_hexparse(hex, msg->data, buf_len);
|
|
|
|
msg->l2h = msgb_put(msg, l);
|
|
|
|
return msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct msgb *mgcp_from_str(const char *head, const char *params)
|
|
|
|
{
|
|
|
|
struct msgb *msg = msgb_alloc(buf_len, "mgcp_from_str");
|
|
|
|
unsigned int l;
|
|
|
|
char *data;
|
|
|
|
l = strlen(head);
|
|
|
|
msg->l2h = msgb_put(msg, l);
|
|
|
|
data = (char*)msgb_l2(msg);
|
2017-11-23 18:32:31 +00:00
|
|
|
osmo_strlcpy(data, head, l);
|
2016-05-20 19:59:55 +00:00
|
|
|
|
|
|
|
data = (char*)msgb_put(msg, 1);
|
|
|
|
*data = '\n';
|
|
|
|
|
|
|
|
l = strlen(params);
|
|
|
|
data = (char*)msgb_put(msg, l);
|
2017-11-23 18:32:31 +00:00
|
|
|
osmo_strlcpy(data, params, l);
|
2016-05-20 19:59:55 +00:00
|
|
|
|
|
|
|
return msg;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static struct msgb *from_str(const char *str)
|
|
|
|
{
|
|
|
|
struct msgb *msg = msgb_alloc(buf_len, "from_str");
|
|
|
|
unsigned int l = strlen(str);
|
|
|
|
char *data;
|
|
|
|
msg->l2h = msgb_put(msg, l);
|
|
|
|
data = (char*)msgb_l2(msg);
|
2017-11-23 18:32:31 +00:00
|
|
|
osmo_strlcpy(data, str, l);
|
2016-05-20 19:59:55 +00:00
|
|
|
return msg;
|
|
|
|
}
|
|
|
|
|
mgcp_client: Introduce mgcp_client_conf_alloc(), deprecate mgcp_client_conf_init()
So far, the users of the old non-pooled API were in charge of allocating
the struct mgcp_client_conf by themselves, then init them using
mgcp_client_conf_init(). This causes a major problem, since it makes it
difficult to extend the struct mgcp_client_conf structure to add new
features, which may happen frequently.
The MGW pool API doesn't have this problem, because the struct
mgcp_client_conf is allocated as parts/fields of private structs defined
in internal headers. Only pointers to it are used in public headers.
Since it still has to internally initialize the conf fields, we still
need the API to initialize it internally, and hence why is it marked as
DEPRECTED_OUTSIDE instead of DEPRECATED.
While some programs already moved to the new MGW pool infrastructure,
they still use the old APIs to accomodate for old config files in order
to be back-compatible, hence most users of libosmo-mgcp-client are
affected.
Introduce an API to allocate the conf struct internally, which, while
still breaking the ABI, allows for a more relaxed update path where it's
possible to extend the struct mgcp_client_conf at the end.
Eventually the non pooled API should be gone and the struct
mgcp_client_conf can then be moved to a private header, but for now
let's add this small feature to avoid major ABI breakage.
Change-Id: Iba0853ed099a32cf1dde78c17e1b34343db41cfc
2023-06-13 17:41:44 +00:00
|
|
|
static struct mgcp_client_conf *conf;
|
2017-09-03 23:02:56 +00:00
|
|
|
struct mgcp_client *mgcp = NULL;
|
2016-05-20 19:59:55 +00:00
|
|
|
|
mgcp_client: add transaction cleanup
So far, if an MGCP message is sent, the transaction gets enqueued, but there is
no way to end the transaction other than receiving a valid reply. So, if the
caller decides that the transaction timed out and tears down the priv pointer
passed to mgcp_client_tx, and if then a late reply arrives, the callback will
dereference the invalid priv pointer and cause a segfault. Hence it is possible
to crash an mgcp_client program by sending a late response.
Furthermore, if no reply ever arrives, we would keep the pending response in
the list forever, amounting to a "memory leak".
Add mgcp_client_cancel() to discard a pending transaction. The caller can now
decide to discard a pending response when it sees fit (e.g. the caller's
timeout expired). This needs to be added to OsmoMSC and OsmoBSC.
Add mgcp_msg_trans_id() to provide an obvious way to obtain the transaction id
from a generated MGCP message.
No public API is broken; but refine the negative return code from
mgcp_client_rx(): return -ENOENT if no such transaction ID is found, and still
-1 if decoding failed. This is mainly for mgcp_client_test.
Implement a test for mgcp_client_cancel() in mgcp_client_test.c.
Tweak internal mgcp_client_response_pending_get() to take only the transaction
id as argument instead of the entire mgcp message struct.
Found-by: dexter
Related: OS#2695 OS#2696
Change-Id: I16811e168a46a82a05943252a737b3434143f4bd
2017-11-30 12:43:11 +00:00
|
|
|
static int reply_to(mgcp_trans_id_t trans_id, int code, const char *comment,
|
2018-09-03 19:05:13 +00:00
|
|
|
const char *params)
|
2016-05-20 19:59:55 +00:00
|
|
|
{
|
|
|
|
static char compose[4096 - 128];
|
|
|
|
int len;
|
|
|
|
|
|
|
|
len = snprintf(compose, sizeof(compose),
|
2018-09-03 19:05:13 +00:00
|
|
|
"%d %u %s\r\n%s",
|
|
|
|
code, trans_id, comment, params);
|
2016-05-20 19:59:55 +00:00
|
|
|
OSMO_ASSERT(len < sizeof(compose));
|
|
|
|
OSMO_ASSERT(len > 0);
|
|
|
|
|
|
|
|
printf("composed response:\n-----\n%s\n-----\n",
|
|
|
|
compose);
|
mgcp_client: add transaction cleanup
So far, if an MGCP message is sent, the transaction gets enqueued, but there is
no way to end the transaction other than receiving a valid reply. So, if the
caller decides that the transaction timed out and tears down the priv pointer
passed to mgcp_client_tx, and if then a late reply arrives, the callback will
dereference the invalid priv pointer and cause a segfault. Hence it is possible
to crash an mgcp_client program by sending a late response.
Furthermore, if no reply ever arrives, we would keep the pending response in
the list forever, amounting to a "memory leak".
Add mgcp_client_cancel() to discard a pending transaction. The caller can now
decide to discard a pending response when it sees fit (e.g. the caller's
timeout expired). This needs to be added to OsmoMSC and OsmoBSC.
Add mgcp_msg_trans_id() to provide an obvious way to obtain the transaction id
from a generated MGCP message.
No public API is broken; but refine the negative return code from
mgcp_client_rx(): return -ENOENT if no such transaction ID is found, and still
-1 if decoding failed. This is mainly for mgcp_client_test.
Implement a test for mgcp_client_cancel() in mgcp_client_test.c.
Tweak internal mgcp_client_response_pending_get() to take only the transaction
id as argument instead of the entire mgcp message struct.
Found-by: dexter
Related: OS#2695 OS#2696
Change-Id: I16811e168a46a82a05943252a737b3434143f4bd
2017-11-30 12:43:11 +00:00
|
|
|
return mgcp_client_rx(mgcp, from_str(compose));
|
2016-05-20 19:59:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void test_response_cb(struct mgcp_response *response, void *priv)
|
|
|
|
{
|
2018-06-07 16:51:31 +00:00
|
|
|
unsigned int i;
|
2016-05-20 19:59:55 +00:00
|
|
|
OSMO_ASSERT(priv == mgcp);
|
|
|
|
mgcp_response_parse_params(response);
|
|
|
|
|
2018-06-07 16:51:31 +00:00
|
|
|
printf("response cb received:\n");
|
|
|
|
printf(" head.response_code = %d\n", response->head.response_code);
|
|
|
|
printf(" head.trans_id = %u\n", response->head.trans_id);
|
2018-09-03 19:12:48 +00:00
|
|
|
printf(" head.conn_id = %s\n", response->head.conn_id);
|
2018-06-07 16:51:31 +00:00
|
|
|
printf(" head.comment = %s\n", response->head.comment);
|
|
|
|
printf(" audio_port = %u\n", response->audio_port);
|
|
|
|
printf(" audio_ip = %s\n", response->audio_ip);
|
|
|
|
printf(" ptime = %u\n", response->ptime);
|
|
|
|
printf(" codecs_len = %u\n", response->codecs_len);
|
|
|
|
for(i=0;i<response->codecs_len;i++)
|
|
|
|
printf(" codecs[%u] = %u\n", i, response->codecs[i]);
|
|
|
|
printf(" ptmap_len = %u\n", response->ptmap_len);
|
|
|
|
for(i=0;i<response->ptmap_len;i++) {
|
|
|
|
printf(" ptmap[%u].codec = %u\n", i, response->ptmap[i].codec);
|
2019-04-23 10:36:32 +00:00
|
|
|
printf(" ptmap[%u].pt = %u\n", i, response->ptmap[i].pt);
|
2018-06-07 16:51:31 +00:00
|
|
|
}
|
2019-04-23 10:36:32 +00:00
|
|
|
|
2016-05-20 19:59:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
mgcp_trans_id_t dummy_mgcp_send(struct msgb *msg)
|
|
|
|
{
|
|
|
|
mgcp_trans_id_t trans_id;
|
|
|
|
trans_id = msg->cb[MSGB_CB_MGCP_TRANS_ID];
|
|
|
|
char *end;
|
|
|
|
|
2017-09-03 23:02:56 +00:00
|
|
|
OSMO_ASSERT(mgcp_client_pending_add(mgcp, trans_id, test_response_cb, mgcp));
|
2016-05-20 19:59:55 +00:00
|
|
|
|
|
|
|
end = (char*)msgb_put(msg, 1);
|
|
|
|
*end = '\0';
|
|
|
|
printf("composed:\n-----\n%s\n-----\n",
|
|
|
|
(char*)msgb_l2(msg));
|
|
|
|
|
|
|
|
talloc_free(msg);
|
|
|
|
return trans_id;
|
|
|
|
}
|
|
|
|
|
2017-10-05 16:25:37 +00:00
|
|
|
void test_mgcp_msg(void)
|
|
|
|
{
|
|
|
|
struct msgb *msg;
|
|
|
|
char audio_ip_overflow[5000];
|
|
|
|
|
|
|
|
/* A message struct prefilled with some arbitary values */
|
|
|
|
struct mgcp_msg mgcp_msg = {
|
|
|
|
.audio_ip = "192.168.100.23",
|
|
|
|
.endpoint = "23@mgw",
|
|
|
|
.audio_port = 1234,
|
|
|
|
.call_id = 47,
|
2017-11-21 16:26:09 +00:00
|
|
|
.conn_id = "11",
|
2018-06-07 16:51:31 +00:00
|
|
|
.conn_mode = MGCP_CONN_RECV_SEND,
|
|
|
|
.ptime = 20,
|
|
|
|
.codecs[0] = CODEC_GSM_8000_1,
|
|
|
|
.codecs[1] = CODEC_AMR_8000_1,
|
|
|
|
.codecs[2] = CODEC_GSMEFR_8000_1,
|
|
|
|
.codecs_len = 1,
|
|
|
|
.ptmap[0].codec = CODEC_GSMEFR_8000_1,
|
|
|
|
.ptmap[0].pt = 96,
|
2018-08-23 14:36:48 +00:00
|
|
|
.ptmap_len = 1,
|
|
|
|
.x_osmo_ign = MGCP_X_OSMO_IGN_CALLID,
|
2019-04-24 20:06:22 +00:00
|
|
|
.x_osmo_osmux_cid = -1, /* wildcard */
|
2017-10-05 16:25:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if (mgcp)
|
|
|
|
talloc_free(mgcp);
|
mgcp_client: Introduce mgcp_client_conf_alloc(), deprecate mgcp_client_conf_init()
So far, the users of the old non-pooled API were in charge of allocating
the struct mgcp_client_conf by themselves, then init them using
mgcp_client_conf_init(). This causes a major problem, since it makes it
difficult to extend the struct mgcp_client_conf structure to add new
features, which may happen frequently.
The MGW pool API doesn't have this problem, because the struct
mgcp_client_conf is allocated as parts/fields of private structs defined
in internal headers. Only pointers to it are used in public headers.
Since it still has to internally initialize the conf fields, we still
need the API to initialize it internally, and hence why is it marked as
DEPRECTED_OUTSIDE instead of DEPRECATED.
While some programs already moved to the new MGW pool infrastructure,
they still use the old APIs to accomodate for old config files in order
to be back-compatible, hence most users of libosmo-mgcp-client are
affected.
Introduce an API to allocate the conf struct internally, which, while
still breaking the ABI, allows for a more relaxed update path where it's
possible to extend the struct mgcp_client_conf at the end.
Eventually the non pooled API should be gone and the struct
mgcp_client_conf can then be moved to a private header, but for now
let's add this small feature to avoid major ABI breakage.
Change-Id: Iba0853ed099a32cf1dde78c17e1b34343db41cfc
2023-06-13 17:41:44 +00:00
|
|
|
mgcp = mgcp_client_init(ctx, conf);
|
2017-10-05 16:25:37 +00:00
|
|
|
|
|
|
|
printf("\n");
|
|
|
|
|
|
|
|
printf("Generated CRCX message:\n");
|
|
|
|
mgcp_msg.verb = MGCP_VERB_CRCX;
|
|
|
|
mgcp_msg.presence =
|
|
|
|
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
|
|
|
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE);
|
|
|
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
|
|
|
printf("%s\n", (char *)msg->data);
|
|
|
|
|
2018-06-07 16:51:31 +00:00
|
|
|
printf("Generated CRCX message (two codecs):\n");
|
|
|
|
mgcp_msg.verb = MGCP_VERB_CRCX;
|
|
|
|
mgcp_msg.presence =
|
|
|
|
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
|
|
|
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE);
|
|
|
|
mgcp_msg.codecs_len = 2;
|
|
|
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
2019-04-23 10:36:32 +00:00
|
|
|
mgcp_msg.codecs_len = 1;
|
2018-06-07 16:51:31 +00:00
|
|
|
printf("%s\n", (char *)msg->data);
|
|
|
|
|
|
|
|
printf("Generated CRCX message (three codecs, one with custom pt):\n");
|
|
|
|
mgcp_msg.verb = MGCP_VERB_CRCX;
|
|
|
|
mgcp_msg.presence =
|
|
|
|
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
|
|
|
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE);
|
|
|
|
mgcp_msg.codecs_len = 3;
|
|
|
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
2019-04-23 10:36:32 +00:00
|
|
|
mgcp_msg.codecs_len = 1;
|
|
|
|
printf("%s\n", (char *)msg->data);
|
2018-06-07 16:51:31 +00:00
|
|
|
|
2017-10-05 16:25:37 +00:00
|
|
|
printf("Generated MDCX message:\n");
|
|
|
|
mgcp_msg.verb = MGCP_VERB_MDCX;
|
|
|
|
mgcp_msg.presence =
|
|
|
|
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
|
|
|
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
|
|
|
|
MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
|
|
|
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
|
|
|
printf("%s\n", (char *)msg->data);
|
|
|
|
|
2018-06-07 16:51:31 +00:00
|
|
|
printf("Generated MDCX message (two codecs):\n");
|
|
|
|
mgcp_msg.verb = MGCP_VERB_MDCX;
|
|
|
|
mgcp_msg.presence =
|
|
|
|
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
|
|
|
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
|
|
|
|
MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
|
|
|
|
mgcp_msg.codecs_len = 2;
|
|
|
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
2019-04-23 10:36:32 +00:00
|
|
|
mgcp_msg.codecs_len = 1;
|
2018-06-07 16:51:31 +00:00
|
|
|
printf("%s\n", (char *)msg->data);
|
|
|
|
|
|
|
|
printf("Generated MDCX message (three codecs, one with custom pt):\n");
|
|
|
|
mgcp_msg.verb = MGCP_VERB_MDCX;
|
|
|
|
mgcp_msg.presence =
|
|
|
|
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
|
|
|
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
|
|
|
|
MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
|
|
|
|
mgcp_msg.codecs_len = 3;
|
|
|
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
2019-04-23 10:36:32 +00:00
|
|
|
mgcp_msg.codecs_len = 1;
|
|
|
|
printf("%s\n", (char *)msg->data);
|
2018-06-07 16:51:31 +00:00
|
|
|
|
2017-10-05 16:25:37 +00:00
|
|
|
printf("Generated DLCX message:\n");
|
|
|
|
mgcp_msg.verb = MGCP_VERB_DLCX;
|
|
|
|
mgcp_msg.presence =
|
|
|
|
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
|
|
|
MGCP_MSG_PRESENCE_CONN_ID);
|
|
|
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
|
|
|
printf("%s\n", (char *)msg->data);
|
|
|
|
|
|
|
|
printf("Generated AUEP message:\n");
|
|
|
|
mgcp_msg.verb = MGCP_VERB_AUEP;
|
|
|
|
mgcp_msg.presence = (MGCP_MSG_PRESENCE_ENDPOINT);
|
|
|
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
|
|
|
printf("%s\n", msg->data);
|
|
|
|
|
|
|
|
printf("Generated RSIP message:\n");
|
|
|
|
mgcp_msg.verb = MGCP_VERB_RSIP;
|
|
|
|
mgcp_msg.presence = (MGCP_MSG_PRESENCE_ENDPOINT);
|
|
|
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
|
|
|
printf("%s\n", (char *)msg->data);
|
|
|
|
|
2018-08-23 14:36:48 +00:00
|
|
|
printf("Generate X-Osmo-IGN message:\n");
|
|
|
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
|
|
|
mgcp_msg.verb = MGCP_VERB_CRCX;
|
|
|
|
mgcp_msg.presence =
|
|
|
|
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
|
|
|
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE
|
|
|
|
| MGCP_MSG_PRESENCE_X_OSMO_IGN);
|
|
|
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
|
|
|
printf("%s\n", (char *)msg->data);
|
|
|
|
|
2019-04-24 20:06:22 +00:00
|
|
|
printf("Generate X-Osmo-Osmux message:\n");
|
|
|
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
|
|
|
mgcp_msg.verb = MGCP_VERB_CRCX;
|
|
|
|
mgcp_msg.presence =
|
|
|
|
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
|
|
|
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE
|
|
|
|
| MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID);
|
|
|
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
|
|
|
printf("%s\n", (char *)msg->data);
|
|
|
|
|
|
|
|
printf("Generate X-Osmo-Osmux message (fixed CID 2):\n");
|
|
|
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
|
|
|
mgcp_msg.verb = MGCP_VERB_CRCX;
|
|
|
|
mgcp_msg.x_osmo_osmux_cid = 2;
|
|
|
|
mgcp_msg.presence =
|
|
|
|
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
|
|
|
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE
|
|
|
|
| MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID);
|
2019-05-10 14:49:59 +00:00
|
|
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
|
|
|
printf("%s\n", (char *)msg->data);
|
|
|
|
|
|
|
|
printf("Generate X-Osmo-Osmux message (MDCX):\n");
|
|
|
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
|
|
|
mgcp_msg.verb = MGCP_VERB_MDCX;
|
|
|
|
mgcp_msg.x_osmo_osmux_cid = 2;
|
|
|
|
mgcp_msg.presence =
|
|
|
|
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
|
|
|
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE
|
|
|
|
| MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID);
|
2019-04-24 20:06:22 +00:00
|
|
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
|
|
|
printf("%s\n", (char *)msg->data);
|
|
|
|
|
2017-10-05 16:25:37 +00:00
|
|
|
printf("Overfolow test:\n");
|
|
|
|
mgcp_msg.verb = MGCP_VERB_MDCX;
|
|
|
|
mgcp_msg.presence =
|
|
|
|
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
|
|
|
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
|
|
|
|
MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
|
|
|
|
memset(audio_ip_overflow, 'X', sizeof(audio_ip_overflow));
|
2020-08-28 18:21:55 +00:00
|
|
|
audio_ip_overflow[1] = '.';
|
2017-10-05 16:25:37 +00:00
|
|
|
audio_ip_overflow[sizeof(audio_ip_overflow) - 1] = '\0';
|
|
|
|
mgcp_msg.audio_ip = audio_ip_overflow;
|
|
|
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
|
|
|
OSMO_ASSERT(msg == NULL);
|
|
|
|
|
2020-08-28 18:21:55 +00:00
|
|
|
printf("IPv6 test:\n");
|
|
|
|
mgcp_msg.verb = MGCP_VERB_MDCX;
|
|
|
|
mgcp_msg.presence =
|
|
|
|
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
|
|
|
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
|
|
|
|
MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
|
|
|
|
mgcp_msg.audio_ip = "2001:db8:1::ab9:c0a8:102";
|
|
|
|
mgcp->actual.remote_addr = "::1";
|
|
|
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
|
|
|
printf("%s\n", (char *)msg->data);
|
|
|
|
|
2017-10-05 16:25:37 +00:00
|
|
|
printf("\n");
|
|
|
|
msgb_free(msg);
|
|
|
|
}
|
|
|
|
|
2022-11-03 10:41:05 +00:00
|
|
|
void test_mgcp_client_cancel(void)
|
mgcp_client: add transaction cleanup
So far, if an MGCP message is sent, the transaction gets enqueued, but there is
no way to end the transaction other than receiving a valid reply. So, if the
caller decides that the transaction timed out and tears down the priv pointer
passed to mgcp_client_tx, and if then a late reply arrives, the callback will
dereference the invalid priv pointer and cause a segfault. Hence it is possible
to crash an mgcp_client program by sending a late response.
Furthermore, if no reply ever arrives, we would keep the pending response in
the list forever, amounting to a "memory leak".
Add mgcp_client_cancel() to discard a pending transaction. The caller can now
decide to discard a pending response when it sees fit (e.g. the caller's
timeout expired). This needs to be added to OsmoMSC and OsmoBSC.
Add mgcp_msg_trans_id() to provide an obvious way to obtain the transaction id
from a generated MGCP message.
No public API is broken; but refine the negative return code from
mgcp_client_rx(): return -ENOENT if no such transaction ID is found, and still
-1 if decoding failed. This is mainly for mgcp_client_test.
Implement a test for mgcp_client_cancel() in mgcp_client_test.c.
Tweak internal mgcp_client_response_pending_get() to take only the transaction
id as argument instead of the entire mgcp message struct.
Found-by: dexter
Related: OS#2695 OS#2696
Change-Id: I16811e168a46a82a05943252a737b3434143f4bd
2017-11-30 12:43:11 +00:00
|
|
|
{
|
|
|
|
mgcp_trans_id_t trans_id;
|
|
|
|
struct msgb *msg;
|
|
|
|
struct mgcp_msg mgcp_msg = {
|
|
|
|
.verb = MGCP_VERB_CRCX,
|
|
|
|
.audio_ip = "192.168.100.23",
|
|
|
|
.endpoint = "23@mgw",
|
|
|
|
.audio_port = 1234,
|
|
|
|
.call_id = 47,
|
2017-12-04 14:53:37 +00:00
|
|
|
.conn_id = "11",
|
mgcp_client: add transaction cleanup
So far, if an MGCP message is sent, the transaction gets enqueued, but there is
no way to end the transaction other than receiving a valid reply. So, if the
caller decides that the transaction timed out and tears down the priv pointer
passed to mgcp_client_tx, and if then a late reply arrives, the callback will
dereference the invalid priv pointer and cause a segfault. Hence it is possible
to crash an mgcp_client program by sending a late response.
Furthermore, if no reply ever arrives, we would keep the pending response in
the list forever, amounting to a "memory leak".
Add mgcp_client_cancel() to discard a pending transaction. The caller can now
decide to discard a pending response when it sees fit (e.g. the caller's
timeout expired). This needs to be added to OsmoMSC and OsmoBSC.
Add mgcp_msg_trans_id() to provide an obvious way to obtain the transaction id
from a generated MGCP message.
No public API is broken; but refine the negative return code from
mgcp_client_rx(): return -ENOENT if no such transaction ID is found, and still
-1 if decoding failed. This is mainly for mgcp_client_test.
Implement a test for mgcp_client_cancel() in mgcp_client_test.c.
Tweak internal mgcp_client_response_pending_get() to take only the transaction
id as argument instead of the entire mgcp message struct.
Found-by: dexter
Related: OS#2695 OS#2696
Change-Id: I16811e168a46a82a05943252a737b3434143f4bd
2017-11-30 12:43:11 +00:00
|
|
|
.conn_mode = MGCP_CONN_RECV_SEND,
|
|
|
|
.presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID
|
|
|
|
| MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE),
|
2018-06-07 16:51:31 +00:00
|
|
|
.ptime = 20,
|
|
|
|
.codecs[0] = CODEC_AMR_8000_1,
|
2019-04-23 10:36:32 +00:00
|
|
|
.codecs_len = 1
|
mgcp_client: add transaction cleanup
So far, if an MGCP message is sent, the transaction gets enqueued, but there is
no way to end the transaction other than receiving a valid reply. So, if the
caller decides that the transaction timed out and tears down the priv pointer
passed to mgcp_client_tx, and if then a late reply arrives, the callback will
dereference the invalid priv pointer and cause a segfault. Hence it is possible
to crash an mgcp_client program by sending a late response.
Furthermore, if no reply ever arrives, we would keep the pending response in
the list forever, amounting to a "memory leak".
Add mgcp_client_cancel() to discard a pending transaction. The caller can now
decide to discard a pending response when it sees fit (e.g. the caller's
timeout expired). This needs to be added to OsmoMSC and OsmoBSC.
Add mgcp_msg_trans_id() to provide an obvious way to obtain the transaction id
from a generated MGCP message.
No public API is broken; but refine the negative return code from
mgcp_client_rx(): return -ENOENT if no such transaction ID is found, and still
-1 if decoding failed. This is mainly for mgcp_client_test.
Implement a test for mgcp_client_cancel() in mgcp_client_test.c.
Tweak internal mgcp_client_response_pending_get() to take only the transaction
id as argument instead of the entire mgcp message struct.
Found-by: dexter
Related: OS#2695 OS#2696
Change-Id: I16811e168a46a82a05943252a737b3434143f4bd
2017-11-30 12:43:11 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
printf("\n%s():\n", __func__);
|
|
|
|
fprintf(stderr, "\n%s():\n", __func__);
|
|
|
|
|
|
|
|
if (mgcp)
|
|
|
|
talloc_free(mgcp);
|
mgcp_client: Introduce mgcp_client_conf_alloc(), deprecate mgcp_client_conf_init()
So far, the users of the old non-pooled API were in charge of allocating
the struct mgcp_client_conf by themselves, then init them using
mgcp_client_conf_init(). This causes a major problem, since it makes it
difficult to extend the struct mgcp_client_conf structure to add new
features, which may happen frequently.
The MGW pool API doesn't have this problem, because the struct
mgcp_client_conf is allocated as parts/fields of private structs defined
in internal headers. Only pointers to it are used in public headers.
Since it still has to internally initialize the conf fields, we still
need the API to initialize it internally, and hence why is it marked as
DEPRECTED_OUTSIDE instead of DEPRECATED.
While some programs already moved to the new MGW pool infrastructure,
they still use the old APIs to accomodate for old config files in order
to be back-compatible, hence most users of libosmo-mgcp-client are
affected.
Introduce an API to allocate the conf struct internally, which, while
still breaking the ABI, allows for a more relaxed update path where it's
possible to extend the struct mgcp_client_conf at the end.
Eventually the non pooled API should be gone and the struct
mgcp_client_conf can then be moved to a private header, but for now
let's add this small feature to avoid major ABI breakage.
Change-Id: Iba0853ed099a32cf1dde78c17e1b34343db41cfc
2023-06-13 17:41:44 +00:00
|
|
|
mgcp = mgcp_client_init(ctx, conf);
|
mgcp_client: add transaction cleanup
So far, if an MGCP message is sent, the transaction gets enqueued, but there is
no way to end the transaction other than receiving a valid reply. So, if the
caller decides that the transaction timed out and tears down the priv pointer
passed to mgcp_client_tx, and if then a late reply arrives, the callback will
dereference the invalid priv pointer and cause a segfault. Hence it is possible
to crash an mgcp_client program by sending a late response.
Furthermore, if no reply ever arrives, we would keep the pending response in
the list forever, amounting to a "memory leak".
Add mgcp_client_cancel() to discard a pending transaction. The caller can now
decide to discard a pending response when it sees fit (e.g. the caller's
timeout expired). This needs to be added to OsmoMSC and OsmoBSC.
Add mgcp_msg_trans_id() to provide an obvious way to obtain the transaction id
from a generated MGCP message.
No public API is broken; but refine the negative return code from
mgcp_client_rx(): return -ENOENT if no such transaction ID is found, and still
-1 if decoding failed. This is mainly for mgcp_client_test.
Implement a test for mgcp_client_cancel() in mgcp_client_test.c.
Tweak internal mgcp_client_response_pending_get() to take only the transaction
id as argument instead of the entire mgcp message struct.
Found-by: dexter
Related: OS#2695 OS#2696
Change-Id: I16811e168a46a82a05943252a737b3434143f4bd
2017-11-30 12:43:11 +00:00
|
|
|
|
|
|
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
|
|
|
trans_id = mgcp_msg_trans_id(msg);
|
|
|
|
fprintf(stderr, "- composed msg with trans_id=%u\n", trans_id);
|
|
|
|
|
|
|
|
fprintf(stderr, "- not in queue yet, cannot cancel yet\n");
|
|
|
|
OSMO_ASSERT(mgcp_client_cancel(mgcp, trans_id) == -ENOENT);
|
|
|
|
|
|
|
|
fprintf(stderr, "- enqueue\n");
|
|
|
|
dummy_mgcp_send(msg);
|
|
|
|
|
|
|
|
fprintf(stderr, "- cancel succeeds\n");
|
|
|
|
OSMO_ASSERT(mgcp_client_cancel(mgcp, trans_id) == 0);
|
|
|
|
|
|
|
|
fprintf(stderr, "- late response gets discarded\n");
|
2018-09-03 19:07:26 +00:00
|
|
|
OSMO_ASSERT(reply_to(trans_id, 200, "OK", "I: 1\r\n\r\nv=0\r\n") == -ENOENT);
|
mgcp_client: add transaction cleanup
So far, if an MGCP message is sent, the transaction gets enqueued, but there is
no way to end the transaction other than receiving a valid reply. So, if the
caller decides that the transaction timed out and tears down the priv pointer
passed to mgcp_client_tx, and if then a late reply arrives, the callback will
dereference the invalid priv pointer and cause a segfault. Hence it is possible
to crash an mgcp_client program by sending a late response.
Furthermore, if no reply ever arrives, we would keep the pending response in
the list forever, amounting to a "memory leak".
Add mgcp_client_cancel() to discard a pending transaction. The caller can now
decide to discard a pending response when it sees fit (e.g. the caller's
timeout expired). This needs to be added to OsmoMSC and OsmoBSC.
Add mgcp_msg_trans_id() to provide an obvious way to obtain the transaction id
from a generated MGCP message.
No public API is broken; but refine the negative return code from
mgcp_client_rx(): return -ENOENT if no such transaction ID is found, and still
-1 if decoding failed. This is mainly for mgcp_client_test.
Implement a test for mgcp_client_cancel() in mgcp_client_test.c.
Tweak internal mgcp_client_response_pending_get() to take only the transaction
id as argument instead of the entire mgcp message struct.
Found-by: dexter
Related: OS#2695 OS#2696
Change-Id: I16811e168a46a82a05943252a737b3434143f4bd
2017-11-30 12:43:11 +00:00
|
|
|
|
|
|
|
fprintf(stderr, "- canceling again does nothing\n");
|
|
|
|
OSMO_ASSERT(mgcp_client_cancel(mgcp, trans_id) == -ENOENT);
|
|
|
|
|
|
|
|
fprintf(stderr, "%s() done\n", __func__);
|
|
|
|
}
|
|
|
|
|
2018-02-21 14:36:45 +00:00
|
|
|
struct sdp_section_start_test {
|
|
|
|
const char *body;
|
|
|
|
int expect_rc;
|
|
|
|
struct mgcp_response expect_params;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct sdp_section_start_test sdp_section_start_tests[] = {
|
|
|
|
{
|
|
|
|
.body = "",
|
2019-09-19 01:06:46 +00:00
|
|
|
.expect_rc = 0,
|
2018-02-21 14:36:45 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.body = "\n\n",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.body = "\r\n\r\n",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.body = "\n\r\n\r",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.body = "some mgcp header data\r\nand header params"
|
|
|
|
"\n\n"
|
|
|
|
"m=audio 23\r\n",
|
|
|
|
.expect_params = {
|
|
|
|
.audio_port = 23,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.body = "some mgcp header data\r\nand header params"
|
|
|
|
"\r\n\r\n"
|
|
|
|
"m=audio 23\r\n",
|
|
|
|
.expect_params = {
|
|
|
|
.audio_port = 23,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.body = "some mgcp header data\r\nand header params"
|
|
|
|
"\n\r\n\r"
|
|
|
|
"m=audio 23\r\n",
|
|
|
|
.expect_params = {
|
|
|
|
.audio_port = 23,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.body = "some mgcp header data\r\nand header params"
|
|
|
|
"\n\r\n"
|
|
|
|
"m=audio 23\r\n",
|
2019-09-19 01:06:46 +00:00
|
|
|
.expect_rc = 0,
|
2018-02-21 14:36:45 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.body = "some mgcp header data\r\nand header params"
|
|
|
|
"\r\n\r"
|
|
|
|
"m=audio 23\r\n",
|
2019-09-19 01:06:46 +00:00
|
|
|
.expect_rc = 0,
|
2018-02-21 14:36:45 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.body = "some mgcp header data\r\nand header params"
|
|
|
|
"\n\r\r"
|
|
|
|
"m=audio 23\r\n",
|
2019-09-19 01:06:46 +00:00
|
|
|
.expect_rc = 0,
|
2018-02-21 14:36:45 +00:00
|
|
|
},
|
2020-08-28 18:21:55 +00:00
|
|
|
{
|
|
|
|
.body = "some mgcp header data\r\nand header params"
|
|
|
|
"\r\n\r\n"
|
|
|
|
"c=IN IP4 1.2.3.4\r\n",
|
|
|
|
.expect_params = {
|
|
|
|
.audio_ip = "1.2.3.4",
|
|
|
|
},
|
|
|
|
.expect_rc = 0,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.body = "some mgcp header data\r\nand header params"
|
|
|
|
"\r\n\r\n"
|
|
|
|
"c=IN IP6 2001:db8:1::ab9:c0a8:102\r\n",
|
|
|
|
.expect_params = {
|
|
|
|
.audio_ip = "2001:db8:1::ab9:c0a8:102",
|
|
|
|
},
|
|
|
|
.expect_rc = 0,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.body = "some mgcp header data\r\nand header params"
|
|
|
|
"\r\n\r\n"
|
|
|
|
"c=IN IP6 1.2.3.4\r\n",
|
|
|
|
.expect_rc = -22,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.body = "some mgcp header data\r\nand header params"
|
|
|
|
"\r\n\r\n"
|
|
|
|
"c=IN IP4 ::1\r\n",
|
|
|
|
.expect_rc = -22,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.body = "some mgcp header data\r\nand header params"
|
|
|
|
"\r\n\r\n"
|
|
|
|
"c=IN IP4 notanip\r\n",
|
|
|
|
.expect_rc = -22,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.body = "some mgcp header data\r\nand header params"
|
|
|
|
"\r\n\r\n"
|
|
|
|
"c=IN IP4 1.2.3.4.5.6\r\n",
|
|
|
|
.expect_rc = -22,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.body = "some mgcp header data\r\nand header params"
|
|
|
|
"\r\n\r\n"
|
|
|
|
"c=IN IP4 1.2 .3\r\n",
|
|
|
|
.expect_rc = -22,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.body = "some mgcp header data\r\nand header params"
|
|
|
|
"\r\n\r\n"
|
|
|
|
"c=IN IP4 1.2 .3\r\n",
|
|
|
|
.expect_rc = -22,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.body = "some mgcp header data\r\nand header params"
|
|
|
|
"\r\n\r\n"
|
|
|
|
"c=IN IP4 \r\n",
|
|
|
|
.expect_rc = -22,
|
|
|
|
},
|
2018-02-21 14:36:45 +00:00
|
|
|
};
|
|
|
|
|
2022-11-03 10:41:05 +00:00
|
|
|
void test_sdp_section_start(void)
|
2018-02-21 14:36:45 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int failures = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(sdp_section_start_tests); i++) {
|
|
|
|
int rc;
|
|
|
|
struct sdp_section_start_test *t = &sdp_section_start_tests[i];
|
|
|
|
struct mgcp_response *r = talloc_zero(ctx, struct mgcp_response);
|
|
|
|
|
|
|
|
r->body = talloc_strdup(r, t->body);
|
|
|
|
|
|
|
|
printf("\n%s() test [%d]:\n", __func__, i);
|
|
|
|
fprintf(stderr, "\n%s() test [%d]:\n", __func__, i);
|
|
|
|
fprintf(stderr, "body: \"%s\"\n", osmo_escape_str(r->body, -1));
|
|
|
|
|
|
|
|
rc = mgcp_response_parse_params(r);
|
|
|
|
|
|
|
|
fprintf(stderr, "got rc=%d\n", rc);
|
|
|
|
if (rc != t->expect_rc) {
|
|
|
|
fprintf(stderr, "FAIL: Expected rc=%d\n", t->expect_rc);
|
|
|
|
failures++;
|
|
|
|
}
|
|
|
|
if (rc) {
|
|
|
|
talloc_free(r);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-08-28 18:21:55 +00:00
|
|
|
fprintf(stderr, "got audio_ip=\"%s\"\n", r->audio_ip);
|
|
|
|
if (strcmp(r->audio_ip, t->expect_params.audio_ip)) {
|
|
|
|
fprintf(stderr, "FAIL: Expected audio_ip=\"%s\"\n", t->expect_params.audio_ip);
|
|
|
|
failures++;
|
|
|
|
}
|
|
|
|
fprintf(stderr, "got audio_port=%u\n", r->audio_port);
|
2018-02-21 14:36:45 +00:00
|
|
|
if (r->audio_port != t->expect_params.audio_port) {
|
|
|
|
fprintf(stderr, "FAIL: Expected audio_port=%u\n", t->expect_params.audio_port);
|
|
|
|
failures++;
|
|
|
|
}
|
|
|
|
talloc_free(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
OSMO_ASSERT(!failures);
|
|
|
|
}
|
|
|
|
|
2023-12-07 02:41:52 +00:00
|
|
|
static void test_map_str_to_codec(void)
|
2018-06-07 16:51:31 +00:00
|
|
|
{
|
|
|
|
/* Full form */
|
|
|
|
OSMO_ASSERT(map_str_to_codec("PCMU/8000/1") == CODEC_PCMU_8000_1);
|
|
|
|
OSMO_ASSERT(map_str_to_codec("GSM/8000/1") == CODEC_GSM_8000_1);
|
|
|
|
OSMO_ASSERT(map_str_to_codec("PCMA/8000/1") == CODEC_PCMA_8000_1);
|
|
|
|
OSMO_ASSERT(map_str_to_codec("G729/8000/1") == CODEC_G729_8000_1);
|
|
|
|
OSMO_ASSERT(map_str_to_codec("GSM-EFR/8000/1") == CODEC_GSMEFR_8000_1);
|
|
|
|
OSMO_ASSERT(map_str_to_codec("GSM-HR-08/8000/1") == CODEC_GSMHR_8000_1);
|
|
|
|
OSMO_ASSERT(map_str_to_codec("AMR/8000/1") == CODEC_AMR_8000_1);
|
|
|
|
OSMO_ASSERT(map_str_to_codec("AMR-WB/16000/1") == CODEC_AMRWB_16000_1);
|
|
|
|
|
|
|
|
/* Short form */
|
|
|
|
OSMO_ASSERT(map_str_to_codec("GSM-EFR") == CODEC_GSMEFR_8000_1);
|
|
|
|
OSMO_ASSERT(map_str_to_codec("G729") == CODEC_G729_8000_1);
|
|
|
|
OSMO_ASSERT(map_str_to_codec("GSM-HR-08") == CODEC_GSMHR_8000_1);
|
|
|
|
|
|
|
|
/* We do not care about what is after the first delimiter */
|
|
|
|
OSMO_ASSERT(map_str_to_codec("AMR-WB/123///456") == CODEC_AMRWB_16000_1);
|
|
|
|
OSMO_ASSERT(map_str_to_codec("PCMA/asdf") == CODEC_PCMA_8000_1);
|
|
|
|
OSMO_ASSERT(map_str_to_codec("GSM/qwertz") == CODEC_GSM_8000_1);
|
|
|
|
|
|
|
|
/* A trailing delimiter should not hurt */
|
|
|
|
OSMO_ASSERT(map_str_to_codec("AMR/") == CODEC_AMR_8000_1);
|
|
|
|
OSMO_ASSERT(map_str_to_codec("G729/") == CODEC_G729_8000_1);
|
|
|
|
OSMO_ASSERT(map_str_to_codec("GSM/") == CODEC_GSM_8000_1);
|
|
|
|
|
|
|
|
/* This is expected to fail */
|
|
|
|
OSMO_ASSERT(map_str_to_codec("INVALID/1234/7") == -1);
|
|
|
|
OSMO_ASSERT(map_str_to_codec(NULL) == -1);
|
|
|
|
OSMO_ASSERT(map_str_to_codec("") == -1);
|
|
|
|
OSMO_ASSERT(map_str_to_codec("/////") == -1);
|
|
|
|
|
|
|
|
/* The buffers are 64 bytes long, check what happens with overlong
|
|
|
|
* strings as input (This schould still work.) */
|
|
|
|
OSMO_ASSERT(map_str_to_codec("AMR-WB/16000/1############################################################################################################") == CODEC_AMRWB_16000_1);
|
|
|
|
|
|
|
|
/* This should not work, as there is no delimiter after the codec
|
|
|
|
* name */
|
|
|
|
OSMO_ASSERT(map_str_to_codec("AMR-WB####################################################################################################################") == -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_map_codec_to_pt_and_map_pt_to_codec(void)
|
|
|
|
{
|
|
|
|
struct ptmap ptmap[10];
|
|
|
|
unsigned int ptmap_len;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
ptmap[0].codec = CODEC_GSMEFR_8000_1;
|
|
|
|
ptmap[0].pt = 96;
|
|
|
|
ptmap[1].codec = CODEC_GSMHR_8000_1;
|
|
|
|
ptmap[1].pt = 97;
|
|
|
|
ptmap[2].codec = CODEC_AMR_8000_1;
|
|
|
|
ptmap[2].pt = 98;
|
|
|
|
ptmap[3].codec = CODEC_AMRWB_16000_1;
|
|
|
|
ptmap[3].pt = 99;
|
|
|
|
ptmap_len = 4;
|
|
|
|
|
|
|
|
/* Mappings that are covered by the table */
|
|
|
|
for (i = 0; i < ptmap_len; i++)
|
|
|
|
printf(" %u => %u\n", ptmap[i].codec, map_codec_to_pt(ptmap, ptmap_len, ptmap[i].codec));
|
|
|
|
for (i = 0; i < ptmap_len; i++)
|
|
|
|
printf(" %u <= %u\n", ptmap[i].pt, map_pt_to_codec(ptmap, ptmap_len, ptmap[i].pt));
|
|
|
|
printf("\n");
|
|
|
|
|
|
|
|
/* Map some codecs/payload types from the static range, result must
|
|
|
|
* always be a 1:1 mapping */
|
|
|
|
printf(" %u => %u\n", CODEC_PCMU_8000_1, map_codec_to_pt(ptmap, ptmap_len, CODEC_PCMU_8000_1));
|
|
|
|
printf(" %u => %u\n", CODEC_GSM_8000_1, map_codec_to_pt(ptmap, ptmap_len, CODEC_GSM_8000_1));
|
|
|
|
printf(" %u => %u\n", CODEC_PCMA_8000_1, map_codec_to_pt(ptmap, ptmap_len, CODEC_PCMA_8000_1));
|
|
|
|
printf(" %u => %u\n", CODEC_G729_8000_1, map_codec_to_pt(ptmap, ptmap_len, CODEC_G729_8000_1));
|
|
|
|
printf(" %u <= %u\n", CODEC_PCMU_8000_1, map_pt_to_codec(ptmap, ptmap_len, CODEC_PCMU_8000_1));
|
|
|
|
printf(" %u <= %u\n", CODEC_GSM_8000_1, map_pt_to_codec(ptmap, ptmap_len, CODEC_GSM_8000_1));
|
|
|
|
printf(" %u <= %u\n", CODEC_PCMA_8000_1, map_pt_to_codec(ptmap, ptmap_len, CODEC_PCMA_8000_1));
|
|
|
|
printf(" %u <= %u\n", CODEC_G729_8000_1, map_pt_to_codec(ptmap, ptmap_len, CODEC_G729_8000_1));
|
|
|
|
printf("\n");
|
|
|
|
|
|
|
|
/* Try to do mappings from statically defined range to danymic range and vice versa. This
|
|
|
|
* is illegal and should result into a 1:1 mapping */
|
|
|
|
ptmap[3].codec = CODEC_AMRWB_16000_1;
|
|
|
|
ptmap[3].pt = 2;
|
|
|
|
ptmap[4].codec = CODEC_PCMU_8000_1;
|
|
|
|
ptmap[4].pt = 100;
|
|
|
|
ptmap_len = 5;
|
|
|
|
|
|
|
|
/* Apply all mappings again, the illegal ones we defined should result into 1:1 mappings */
|
|
|
|
for (i = 0; i < ptmap_len; i++)
|
|
|
|
printf(" %u => %u\n", ptmap[i].codec, map_codec_to_pt(ptmap, ptmap_len, ptmap[i].codec));
|
|
|
|
for (i = 0; i < ptmap_len; i++)
|
|
|
|
printf(" %u <= %u\n", ptmap[i].pt, map_pt_to_codec(ptmap, ptmap_len, ptmap[i].pt));
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
|
2020-06-25 18:16:22 +00:00
|
|
|
void test_mgcp_client_e1_epname(void)
|
|
|
|
{
|
|
|
|
char *epname;
|
|
|
|
|
|
|
|
if (mgcp)
|
|
|
|
talloc_free(mgcp);
|
mgcp_client: Introduce mgcp_client_conf_alloc(), deprecate mgcp_client_conf_init()
So far, the users of the old non-pooled API were in charge of allocating
the struct mgcp_client_conf by themselves, then init them using
mgcp_client_conf_init(). This causes a major problem, since it makes it
difficult to extend the struct mgcp_client_conf structure to add new
features, which may happen frequently.
The MGW pool API doesn't have this problem, because the struct
mgcp_client_conf is allocated as parts/fields of private structs defined
in internal headers. Only pointers to it are used in public headers.
Since it still has to internally initialize the conf fields, we still
need the API to initialize it internally, and hence why is it marked as
DEPRECTED_OUTSIDE instead of DEPRECATED.
While some programs already moved to the new MGW pool infrastructure,
they still use the old APIs to accomodate for old config files in order
to be back-compatible, hence most users of libosmo-mgcp-client are
affected.
Introduce an API to allocate the conf struct internally, which, while
still breaking the ABI, allows for a more relaxed update path where it's
possible to extend the struct mgcp_client_conf at the end.
Eventually the non pooled API should be gone and the struct
mgcp_client_conf can then be moved to a private header, but for now
let's add this small feature to avoid major ABI breakage.
Change-Id: Iba0853ed099a32cf1dde78c17e1b34343db41cfc
2023-06-13 17:41:44 +00:00
|
|
|
mgcp = mgcp_client_init(ctx, conf);
|
2020-06-25 18:16:22 +00:00
|
|
|
|
|
|
|
/* Valid endpoint names */
|
|
|
|
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 1, 15, 64, 0);
|
|
|
|
printf("%s\n", epname);
|
|
|
|
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 2, 14, 32, 0);
|
|
|
|
printf("%s\n", epname);
|
|
|
|
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 3, 13, 32, 4);
|
|
|
|
printf("%s\n", epname);
|
|
|
|
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 4, 12, 16, 0);
|
|
|
|
printf("%s\n", epname);
|
|
|
|
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 5, 11, 16, 2);
|
|
|
|
printf("%s\n", epname);
|
|
|
|
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 6, 10, 16, 4);
|
|
|
|
printf("%s\n", epname);
|
|
|
|
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 7, 9, 16, 6);
|
|
|
|
printf("%s\n", epname);
|
|
|
|
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 8, 8, 8, 0);
|
|
|
|
printf("%s\n", epname);
|
|
|
|
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 9, 7, 8, 1);
|
|
|
|
printf("%s\n", epname);
|
|
|
|
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 10, 6, 8, 2);
|
|
|
|
printf("%s\n", epname);
|
|
|
|
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 11, 5, 8, 3);
|
|
|
|
printf("%s\n", epname);
|
|
|
|
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 12, 4, 8, 4);
|
|
|
|
printf("%s\n", epname);
|
|
|
|
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 13, 3, 8, 5);
|
|
|
|
printf("%s\n", epname);
|
|
|
|
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 14, 2, 8, 6);
|
|
|
|
printf("%s\n", epname);
|
|
|
|
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 15, 1, 8, 7);
|
|
|
|
printf("%s\n", epname);
|
|
|
|
|
|
|
|
/* A few invalid enpoint names */
|
|
|
|
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 15, 1, 128, 0);
|
|
|
|
OSMO_ASSERT(epname == NULL);
|
|
|
|
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 15, 1, 8, 16);
|
|
|
|
OSMO_ASSERT(epname == NULL);
|
|
|
|
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 15, 0, 8, 2);
|
|
|
|
OSMO_ASSERT(epname == NULL);
|
|
|
|
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 15, 64, 8, 2);
|
|
|
|
OSMO_ASSERT(epname == NULL);
|
|
|
|
}
|
|
|
|
|
2017-07-10 13:07:22 +00:00
|
|
|
static const struct log_info_cat log_categories[] = {
|
|
|
|
};
|
|
|
|
|
|
|
|
const struct log_info log_info = {
|
|
|
|
.cat = log_categories,
|
|
|
|
.num_cat = ARRAY_SIZE(log_categories),
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-05-20 19:59:55 +00:00
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
2017-09-03 23:02:56 +00:00
|
|
|
ctx = talloc_named_const(NULL, 1, "mgcp_client_test");
|
2016-05-20 19:59:55 +00:00
|
|
|
msgb_talloc_ctx_init(ctx, 0);
|
2018-03-30 21:01:07 +00:00
|
|
|
osmo_init_logging2(ctx, &log_info);
|
2021-02-19 12:33:52 +00:00
|
|
|
log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
|
2017-10-25 10:14:13 +00:00
|
|
|
log_set_print_timestamp(osmo_stderr_target, 0);
|
|
|
|
log_set_use_color(osmo_stderr_target, 0);
|
2021-02-19 12:33:52 +00:00
|
|
|
log_set_print_category_hex(osmo_stderr_target, 0);
|
2017-10-25 10:14:13 +00:00
|
|
|
log_set_print_category(osmo_stderr_target, 1);
|
2016-05-20 19:59:55 +00:00
|
|
|
|
mgcp_client: add transaction cleanup
So far, if an MGCP message is sent, the transaction gets enqueued, but there is
no way to end the transaction other than receiving a valid reply. So, if the
caller decides that the transaction timed out and tears down the priv pointer
passed to mgcp_client_tx, and if then a late reply arrives, the callback will
dereference the invalid priv pointer and cause a segfault. Hence it is possible
to crash an mgcp_client program by sending a late response.
Furthermore, if no reply ever arrives, we would keep the pending response in
the list forever, amounting to a "memory leak".
Add mgcp_client_cancel() to discard a pending transaction. The caller can now
decide to discard a pending response when it sees fit (e.g. the caller's
timeout expired). This needs to be added to OsmoMSC and OsmoBSC.
Add mgcp_msg_trans_id() to provide an obvious way to obtain the transaction id
from a generated MGCP message.
No public API is broken; but refine the negative return code from
mgcp_client_rx(): return -ENOENT if no such transaction ID is found, and still
-1 if decoding failed. This is mainly for mgcp_client_test.
Implement a test for mgcp_client_cancel() in mgcp_client_test.c.
Tweak internal mgcp_client_response_pending_get() to take only the transaction
id as argument instead of the entire mgcp message struct.
Found-by: dexter
Related: OS#2695 OS#2696
Change-Id: I16811e168a46a82a05943252a737b3434143f4bd
2017-11-30 12:43:11 +00:00
|
|
|
log_set_category_filter(osmo_stderr_target, DLMGCP, 1, LOGL_DEBUG);
|
|
|
|
|
mgcp_client: Introduce mgcp_client_conf_alloc(), deprecate mgcp_client_conf_init()
So far, the users of the old non-pooled API were in charge of allocating
the struct mgcp_client_conf by themselves, then init them using
mgcp_client_conf_init(). This causes a major problem, since it makes it
difficult to extend the struct mgcp_client_conf structure to add new
features, which may happen frequently.
The MGW pool API doesn't have this problem, because the struct
mgcp_client_conf is allocated as parts/fields of private structs defined
in internal headers. Only pointers to it are used in public headers.
Since it still has to internally initialize the conf fields, we still
need the API to initialize it internally, and hence why is it marked as
DEPRECTED_OUTSIDE instead of DEPRECATED.
While some programs already moved to the new MGW pool infrastructure,
they still use the old APIs to accomodate for old config files in order
to be back-compatible, hence most users of libosmo-mgcp-client are
affected.
Introduce an API to allocate the conf struct internally, which, while
still breaking the ABI, allows for a more relaxed update path where it's
possible to extend the struct mgcp_client_conf at the end.
Eventually the non pooled API should be gone and the struct
mgcp_client_conf can then be moved to a private header, but for now
let's add this small feature to avoid major ABI breakage.
Change-Id: Iba0853ed099a32cf1dde78c17e1b34343db41cfc
2023-06-13 17:41:44 +00:00
|
|
|
conf = mgcp_client_conf_alloc(ctx);
|
2016-05-20 19:59:55 +00:00
|
|
|
|
2017-10-05 16:25:37 +00:00
|
|
|
test_mgcp_msg();
|
mgcp_client: add transaction cleanup
So far, if an MGCP message is sent, the transaction gets enqueued, but there is
no way to end the transaction other than receiving a valid reply. So, if the
caller decides that the transaction timed out and tears down the priv pointer
passed to mgcp_client_tx, and if then a late reply arrives, the callback will
dereference the invalid priv pointer and cause a segfault. Hence it is possible
to crash an mgcp_client program by sending a late response.
Furthermore, if no reply ever arrives, we would keep the pending response in
the list forever, amounting to a "memory leak".
Add mgcp_client_cancel() to discard a pending transaction. The caller can now
decide to discard a pending response when it sees fit (e.g. the caller's
timeout expired). This needs to be added to OsmoMSC and OsmoBSC.
Add mgcp_msg_trans_id() to provide an obvious way to obtain the transaction id
from a generated MGCP message.
No public API is broken; but refine the negative return code from
mgcp_client_rx(): return -ENOENT if no such transaction ID is found, and still
-1 if decoding failed. This is mainly for mgcp_client_test.
Implement a test for mgcp_client_cancel() in mgcp_client_test.c.
Tweak internal mgcp_client_response_pending_get() to take only the transaction
id as argument instead of the entire mgcp message struct.
Found-by: dexter
Related: OS#2695 OS#2696
Change-Id: I16811e168a46a82a05943252a737b3434143f4bd
2017-11-30 12:43:11 +00:00
|
|
|
test_mgcp_client_cancel();
|
2018-02-21 14:36:45 +00:00
|
|
|
test_sdp_section_start();
|
2018-06-07 16:51:31 +00:00
|
|
|
test_map_codec_to_pt_and_map_pt_to_codec();
|
2023-12-07 02:41:52 +00:00
|
|
|
test_map_str_to_codec();
|
2020-06-25 18:16:22 +00:00
|
|
|
test_mgcp_client_e1_epname();
|
2016-05-20 19:59:55 +00:00
|
|
|
|
|
|
|
printf("Done\n");
|
|
|
|
fprintf(stderr, "Done\n");
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|