mgcp_client: fix error handling in mgcp message generation

The functions add_lco and add_sdp assert when the codec string can not
be generated. This is the case when an unexpected codec is addressed in
the input parameter mgcp_msg for mgcp_msg_gen(). Even though the API
user is expected only to use the codec identifiers in mgcp_client.h the
check should not be done with an assert. Instead mgcp_msg_gen() should
just return NULL imediately.

Also all generation functions should not use magic numbers as return
codes. Instead constants from errno.h should be used. It is also
problematic that the return codes from msgb_printf are added up.
Depending. It makes more sense to use an OR operator since msgb_printf
only returns 0 or -EINVAL, so the end result will be -EINVAL if one or
more msgb_printf fail and not just a random negative value.

Change-Id: Ibb788343e0bec9c0eaf33e6e4727d4d36c100017
Related: OS#5119
This commit is contained in:
Philipp Maier 2021-06-11 15:16:13 +02:00
parent eb984bd630
commit 7d86d4c523
2 changed files with 67 additions and 48 deletions

View File

@ -1105,30 +1105,40 @@ static int add_lco(struct msgb *msg, struct mgcp_msg *mgcp_msg)
const char *codec; const char *codec;
unsigned int pt; unsigned int pt;
rc += msgb_printf(msg, "L:"); rc |= msgb_printf(msg, "L:");
if (mgcp_msg->ptime) if (mgcp_msg->ptime)
rc += msgb_printf(msg, " p:%u,", mgcp_msg->ptime); rc |= msgb_printf(msg, " p:%u,", mgcp_msg->ptime);
if (mgcp_msg->codecs_len) { if (mgcp_msg->codecs_len) {
rc += msgb_printf(msg, " a:"); rc |= msgb_printf(msg, " a:");
for (i = 0; i < mgcp_msg->codecs_len; i++) { for (i = 0; i < mgcp_msg->codecs_len; i++) {
pt = mgcp_msg->codecs[i]; pt = mgcp_msg->codecs[i];
codec = get_value_string_or_null(osmo_mgcpc_codec_names, pt); codec = get_value_string_or_null(osmo_mgcpc_codec_names, pt);
/* Note: Use codec descriptors from enum mgcp_codecs /* Note: Use codec descriptors from enum mgcp_codecs
* in mgcp_client only! */ * in mgcp_client only! */
OSMO_ASSERT(codec); if (!codec) {
rc += msgb_printf(msg, "%s", extract_codec_name(codec)); msgb_free(msg);
return -EINVAL;
}
rc |= msgb_printf(msg, "%s", extract_codec_name(codec));
if (i < mgcp_msg->codecs_len - 1) if (i < mgcp_msg->codecs_len - 1)
rc += msgb_printf(msg, ";"); rc |= msgb_printf(msg, ";");
} }
rc += msgb_printf(msg, ","); rc |= msgb_printf(msg, ",");
} }
rc += msgb_printf(msg, " nt:IN\r\n"); rc |= msgb_printf(msg, " nt:IN\r\n");
return rc; if (rc != 0) {
LOGP(DLMGCP, LOGL_ERROR,
"message buffer to small, can not generate MGCP message (LCO)\n");
msgb_free(msg);
return -ENOBUFS;
}
return 0;
} }
/* Helper function for mgcp_msg_gen(): Add SDP information to MGCP message */ /* Helper function for mgcp_msg_gen(): Add SDP information to MGCP message */
@ -1142,64 +1152,64 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
unsigned int pt; unsigned int pt;
/* Add separator to mark the beginning of the SDP block */ /* Add separator to mark the beginning of the SDP block */
rc += msgb_printf(msg, "\r\n"); rc |= msgb_printf(msg, "\r\n");
/* Add SDP protocol version */ /* Add SDP protocol version */
rc += msgb_printf(msg, "v=0\r\n"); rc |= msgb_printf(msg, "v=0\r\n");
/* Determine local IP-Address */ /* Determine local IP-Address */
if (osmo_sock_local_ip(local_ip, mgcp->actual.remote_addr) < 0) { if (osmo_sock_local_ip(local_ip, mgcp->actual.remote_addr) < 0) {
LOGP(DLMGCP, LOGL_ERROR, LOGP(DLMGCP, LOGL_ERROR,
"Could not determine local IP-Address!\n"); "Could not determine local IP-Address!\n");
msgb_free(msg); msgb_free(msg);
return -2; return -EINVAL;
} }
local_ip_family = osmo_ip_str_type(local_ip); local_ip_family = osmo_ip_str_type(local_ip);
if (local_ip_family == AF_UNSPEC) { if (local_ip_family == AF_UNSPEC) {
msgb_free(msg); msgb_free(msg);
return -2; return -EINVAL;
} }
audio_ip_family = osmo_ip_str_type(mgcp_msg->audio_ip); audio_ip_family = osmo_ip_str_type(mgcp_msg->audio_ip);
if (audio_ip_family == AF_UNSPEC) { if (audio_ip_family == AF_UNSPEC) {
msgb_free(msg); msgb_free(msg);
return -2; return -EINVAL;
} }
/* Add owner/creator (SDP) */ /* Add owner/creator (SDP) */
rc += msgb_printf(msg, "o=- %x 23 IN IP%c %s\r\n", mgcp_msg->call_id, rc |= msgb_printf(msg, "o=- %x 23 IN IP%c %s\r\n", mgcp_msg->call_id,
local_ip_family == AF_INET6 ? '6' : '4', local_ip_family == AF_INET6 ? '6' : '4',
local_ip); local_ip);
/* Add session name (none) */ /* Add session name (none) */
rc += msgb_printf(msg, "s=-\r\n"); rc |= msgb_printf(msg, "s=-\r\n");
/* Add RTP address and port */ /* Add RTP address and port */
if (mgcp_msg->audio_port == 0) { if (mgcp_msg->audio_port == 0) {
LOGP(DLMGCP, LOGL_ERROR, LOGP(DLMGCP, LOGL_ERROR,
"Invalid port number, can not generate MGCP message\n"); "Invalid port number, can not generate MGCP message\n");
msgb_free(msg); msgb_free(msg);
return -2; return -EINVAL;
} }
if (strlen(mgcp_msg->audio_ip) <= 0) { if (strlen(mgcp_msg->audio_ip) <= 0) {
LOGP(DLMGCP, LOGL_ERROR, LOGP(DLMGCP, LOGL_ERROR,
"Empty ip address, can not generate MGCP message\n"); "Empty ip address, can not generate MGCP message\n");
msgb_free(msg); msgb_free(msg);
return -2; return -EINVAL;
} }
rc += msgb_printf(msg, "c=IN IP%c %s\r\n", rc |= msgb_printf(msg, "c=IN IP%c %s\r\n",
audio_ip_family == AF_INET6 ? '6' : '4', audio_ip_family == AF_INET6 ? '6' : '4',
mgcp_msg->audio_ip); mgcp_msg->audio_ip);
/* Add time description, active time (SDP) */ /* Add time description, active time (SDP) */
rc += msgb_printf(msg, "t=0 0\r\n"); rc |= msgb_printf(msg, "t=0 0\r\n");
rc += msgb_printf(msg, "m=audio %u RTP/AVP", mgcp_msg->audio_port); rc |= msgb_printf(msg, "m=audio %u RTP/AVP", mgcp_msg->audio_port);
for (i = 0; i < mgcp_msg->codecs_len; i++) { for (i = 0; i < mgcp_msg->codecs_len; i++) {
pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]); pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
rc += msgb_printf(msg, " %u", pt); rc |= msgb_printf(msg, " %u", pt);
} }
rc += msgb_printf(msg, "\r\n"); rc |= msgb_printf(msg, "\r\n");
/* Add optional codec parameters (fmtp) */ /* Add optional codec parameters (fmtp) */
if (mgcp_msg->param_present) { if (mgcp_msg->param_present) {
@ -1209,9 +1219,9 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
continue; continue;
pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]); pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
if (mgcp_msg->param.amr_octet_aligned_present && mgcp_msg->param.amr_octet_aligned) if (mgcp_msg->param.amr_octet_aligned_present && mgcp_msg->param.amr_octet_aligned)
rc += msgb_printf(msg, "a=fmtp:%u octet-align=1\r\n", pt); rc |= msgb_printf(msg, "a=fmtp:%u octet-align=1\r\n", pt);
else if (mgcp_msg->param.amr_octet_aligned_present && !mgcp_msg->param.amr_octet_aligned) else if (mgcp_msg->param.amr_octet_aligned_present && !mgcp_msg->param.amr_octet_aligned)
rc += msgb_printf(msg, "a=fmtp:%u octet-align=0\r\n", pt); rc |= msgb_printf(msg, "a=fmtp:%u octet-align=0\r\n", pt);
} }
} }
@ -1226,16 +1236,26 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
/* Note: Use codec descriptors from enum mgcp_codecs /* Note: Use codec descriptors from enum mgcp_codecs
* in mgcp_client only! */ * in mgcp_client only! */
OSMO_ASSERT(codec); if (!codec) {
msgb_free(msg);
return -EINVAL;
}
rc += msgb_printf(msg, "a=rtpmap:%u %s\r\n", pt, codec); rc |= msgb_printf(msg, "a=rtpmap:%u %s\r\n", pt, codec);
} }
} }
if (mgcp_msg->ptime) if (mgcp_msg->ptime)
rc += msgb_printf(msg, "a=ptime:%u\r\n", mgcp_msg->ptime); rc |= msgb_printf(msg, "a=ptime:%u\r\n", mgcp_msg->ptime);
return rc; if (rc != 0) {
LOGP(DLMGCP, LOGL_ERROR,
"message buffer to small, can not generate MGCP message (SDP)\n");
msgb_free(msg);
return -ENOBUFS;
}
return 0;
} }
/*! Generate an MGCP message /*! Generate an MGCP message
@ -1248,7 +1268,6 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
uint32_t mandatory_mask; uint32_t mandatory_mask;
struct msgb *msg = msgb_alloc_headroom(4096, 128, "MGCP tx"); struct msgb *msg = msgb_alloc_headroom(4096, 128, "MGCP tx");
int rc = 0; int rc = 0;
int rc_sdp;
bool use_sdp = false; bool use_sdp = false;
char buf[32]; char buf[32];
@ -1259,23 +1278,23 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
switch (mgcp_msg->verb) { switch (mgcp_msg->verb) {
case MGCP_VERB_CRCX: case MGCP_VERB_CRCX:
mandatory_mask = MGCP_CRCX_MANDATORY; mandatory_mask = MGCP_CRCX_MANDATORY;
rc += msgb_printf(msg, "CRCX %u", trans_id); rc |= msgb_printf(msg, "CRCX %u", trans_id);
break; break;
case MGCP_VERB_MDCX: case MGCP_VERB_MDCX:
mandatory_mask = MGCP_MDCX_MANDATORY; mandatory_mask = MGCP_MDCX_MANDATORY;
rc += msgb_printf(msg, "MDCX %u", trans_id); rc |= msgb_printf(msg, "MDCX %u", trans_id);
break; break;
case MGCP_VERB_DLCX: case MGCP_VERB_DLCX:
mandatory_mask = MGCP_DLCX_MANDATORY; mandatory_mask = MGCP_DLCX_MANDATORY;
rc += msgb_printf(msg, "DLCX %u", trans_id); rc |= msgb_printf(msg, "DLCX %u", trans_id);
break; break;
case MGCP_VERB_AUEP: case MGCP_VERB_AUEP:
mandatory_mask = MGCP_AUEP_MANDATORY; mandatory_mask = MGCP_AUEP_MANDATORY;
rc += msgb_printf(msg, "AUEP %u", trans_id); rc |= msgb_printf(msg, "AUEP %u", trans_id);
break; break;
case MGCP_VERB_RSIP: case MGCP_VERB_RSIP:
mandatory_mask = MGCP_RSIP_MANDATORY; mandatory_mask = MGCP_RSIP_MANDATORY;
rc += msgb_printf(msg, "RSIP %u", trans_id); rc |= msgb_printf(msg, "RSIP %u", trans_id);
break; break;
default: default:
LOGP(DLMGCP, LOGL_ERROR, LOGP(DLMGCP, LOGL_ERROR,
@ -1309,15 +1328,15 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
return NULL; return NULL;
} }
rc += msgb_printf(msg, " %s", mgcp_msg->endpoint); rc |= msgb_printf(msg, " %s", mgcp_msg->endpoint);
} }
/* Add protocol version */ /* Add protocol version */
rc += msgb_printf(msg, " MGCP 1.0\r\n"); rc |= msgb_printf(msg, " MGCP 1.0\r\n");
/* Add call id */ /* Add call id */
if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CALL_ID) if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CALL_ID)
rc += msgb_printf(msg, "C: %x\r\n", mgcp_msg->call_id); rc |= msgb_printf(msg, "C: %x\r\n", mgcp_msg->call_id);
/* Add connection id */ /* Add connection id */
if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CONN_ID) { if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CONN_ID) {
@ -1327,7 +1346,7 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
msgb_free(msg); msgb_free(msg);
return NULL; return NULL;
} }
rc += msgb_printf(msg, "I: %s\r\n", mgcp_msg->conn_id); rc |= msgb_printf(msg, "I: %s\r\n", mgcp_msg->conn_id);
} }
/* Using SDP makes sense when a valid IP/Port combination is specifiec, /* Using SDP makes sense when a valid IP/Port combination is specifiec,
@ -1339,19 +1358,21 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
/* Add local connection options (LCO) */ /* Add local connection options (LCO) */
if (!use_sdp if (!use_sdp
&& (mgcp_msg->verb == MGCP_VERB_CRCX && (mgcp_msg->verb == MGCP_VERB_CRCX
|| mgcp_msg->verb == MGCP_VERB_MDCX)) || mgcp_msg->verb == MGCP_VERB_MDCX)) {
rc += add_lco(msg, mgcp_msg); if (add_lco(msg, mgcp_msg) < 0)
return NULL;
}
/* Add mode */ /* Add mode */
if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CONN_MODE) if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CONN_MODE)
rc += rc |=
msgb_printf(msg, "M: %s\r\n", msgb_printf(msg, "M: %s\r\n",
mgcp_client_cmode_name(mgcp_msg->conn_mode)); mgcp_client_cmode_name(mgcp_msg->conn_mode));
/* Add X-Osmo-IGN */ /* Add X-Osmo-IGN */
if ((mgcp_msg->presence & MGCP_MSG_PRESENCE_X_OSMO_IGN) if ((mgcp_msg->presence & MGCP_MSG_PRESENCE_X_OSMO_IGN)
&& (mgcp_msg->x_osmo_ign != 0)) && (mgcp_msg->x_osmo_ign != 0))
rc += rc |=
msgb_printf(msg, MGCP_X_OSMO_IGN_HEADER "%s\r\n", msgb_printf(msg, MGCP_X_OSMO_IGN_HEADER "%s\r\n",
mgcp_msg->x_osmo_ign & MGCP_X_OSMO_IGN_CALLID ? " C": ""); mgcp_msg->x_osmo_ign & MGCP_X_OSMO_IGN_CALLID ? " C": "");
@ -1365,7 +1386,7 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
return NULL; return NULL;
} }
snprintf(buf, sizeof(buf), " %d", mgcp_msg->x_osmo_osmux_cid); snprintf(buf, sizeof(buf), " %d", mgcp_msg->x_osmo_osmux_cid);
rc += rc |=
msgb_printf(msg, MGCP_X_OSMO_OSMUX_HEADER "%s\r\n", msgb_printf(msg, MGCP_X_OSMO_OSMUX_HEADER "%s\r\n",
mgcp_msg->x_osmo_osmux_cid == -1 ? " *": buf); mgcp_msg->x_osmo_osmux_cid == -1 ? " *": buf);
} }
@ -1375,10 +1396,8 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
if (use_sdp if (use_sdp
&& (mgcp_msg->verb == MGCP_VERB_CRCX && (mgcp_msg->verb == MGCP_VERB_CRCX
|| mgcp_msg->verb == MGCP_VERB_MDCX)) { || mgcp_msg->verb == MGCP_VERB_MDCX)) {
rc_sdp = add_sdp(msg, mgcp_msg, mgcp); if (add_sdp(msg, mgcp_msg, mgcp) < 0)
if (rc_sdp == -2)
return NULL; return NULL;
rc += rc_sdp;
} }
if (rc != 0) { if (rc != 0) {

View File

@ -1,5 +1,5 @@
DLMGCP MGCP client: using endpoint domain '@mgw' DLMGCP MGCP client: using endpoint domain '@mgw'
DLMGCP message buffer to small, can not generate MGCP message DLMGCP message buffer to small, can not generate MGCP message (SDP)
test_mgcp_client_cancel(): test_mgcp_client_cancel():
DLMGCP MGCP client: using endpoint domain '@mgw' DLMGCP MGCP client: using endpoint domain '@mgw'