blob: 3e95ed1754a2398ef10424f5c654e5744fdfd93d [file] [log] [blame]
Philipp Maier87bd9be2017-08-22 16:35:41 +02001/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
2/* Message parser/generator utilities */
3
4/*
5 * (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
6 * (C) 2009-2012 by On-Waves
7 * (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
8 * All Rights Reserved
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Affero General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Affero General Public License for more details.
19 *
20 * You should have received a copy of the GNU Affero General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
25#include <limits.h>
26
27#include <osmocom/mgcp/mgcp_internal.h>
Neels Hofmeyr67793542017-09-08 04:25:16 +020028#include <osmocom/mgcp/mgcp_common.h>
Philipp Maier87bd9be2017-08-22 16:35:41 +020029#include <osmocom/mgcp/mgcp_msg.h>
30#include <osmocom/mgcp/mgcp_conn.h>
Philipp Maier37d11c82018-02-01 14:38:12 +010031#include <osmocom/mgcp/mgcp_endp.h>
Philipp Maier87bd9be2017-08-22 16:35:41 +020032
33/*! Display an mgcp message on the log output.
34 * \param[in] message mgcp message string
35 * \param[in] len message mgcp message string length
36 * \param[in] preamble string to display in logtext in front of each line */
37void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble)
38{
39 unsigned char line[80];
40 unsigned char *ptr;
41 unsigned int consumed = 0;
42 unsigned int consumed_line = 0;
43 unsigned int line_count = 0;
44
45 if (!log_check_level(DLMGCP, LOGL_DEBUG))
46 return;
47
48 while (1) {
49 memset(line, 0, sizeof(line));
50 ptr = line;
51 consumed_line = 0;
52 do {
53 if (*message != '\n' && *message != '\r') {
54 *ptr = *message;
55 ptr++;
56 }
57 message++;
58 consumed++;
59 consumed_line++;
60 } while (*message != '\n' && consumed < len
61 && consumed_line < sizeof(line));
62
63 if (strlen((const char *)line)) {
64 LOGP(DLMGCP, LOGL_DEBUG, "%s: line #%02u: %s\n",
65 preamble, line_count, line);
66 line_count++;
67 }
68
69 if (consumed >= len)
70 return;
71 }
72}
73
74/*! Parse connection mode.
75 * \param[in] mode as string (recvonly, sendrecv, sendonly or loopback)
76 * \param[in] endp pointer to endpoint (only used for log output)
77 * \param[out] associated connection to be modified accordingly
78 * \returns 0 on success, -1 on error */
79int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
80 struct mgcp_conn *conn)
81{
82 int ret = 0;
83
84 if (!mode) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +020085 LOGPCONN(conn, DLMGCP, LOGL_ERROR,
86 "missing connection mode\n");
Philipp Maier87bd9be2017-08-22 16:35:41 +020087 return -1;
88 }
89 if (!conn)
90 return -1;
91 if (!endp)
92 return -1;
93
Pau Espin Pedrol17058482019-06-26 12:23:02 +020094 if (strcasecmp(mode, "recvonly") == 0)
Philipp Maier87bd9be2017-08-22 16:35:41 +020095 conn->mode = MGCP_CONN_RECV_ONLY;
Pau Espin Pedrol17058482019-06-26 12:23:02 +020096 else if (strcasecmp(mode, "sendrecv") == 0)
Philipp Maier87bd9be2017-08-22 16:35:41 +020097 conn->mode = MGCP_CONN_RECV_SEND;
Pau Espin Pedrol17058482019-06-26 12:23:02 +020098 else if (strcasecmp(mode, "sendonly") == 0)
Philipp Maier87bd9be2017-08-22 16:35:41 +020099 conn->mode = MGCP_CONN_SEND_ONLY;
Pau Espin Pedrol17058482019-06-26 12:23:02 +0200100 else if (strcasecmp(mode, "loopback") == 0)
Philipp Maier87bd9be2017-08-22 16:35:41 +0200101 conn->mode = MGCP_CONN_LOOPBACK;
102 else {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200103 LOGPCONN(conn, DLMGCP, LOGL_ERROR,
104 "unknown connection mode: '%s'\n", mode);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200105 ret = -1;
106 }
107
108 /* Special handling für RTP connections */
109 if (conn->type == MGCP_CONN_TYPE_RTP) {
110 conn->u.rtp.end.output_enabled =
111 conn->mode & MGCP_CONN_SEND_ONLY ? 1 : 0;
112 }
113
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200114 LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "conn:%s\n", mgcp_conn_dump(conn));
Philipp Maier87bd9be2017-08-22 16:35:41 +0200115
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200116 LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "connection mode '%s' %d\n",
117 mode, conn->mode);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200118
119 /* Special handling für RTP connections */
120 if (conn->type == MGCP_CONN_TYPE_RTP) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200121 LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "output_enabled %d\n",
122 conn->u.rtp.end.output_enabled);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200123 }
124
125 /* The VTY might change the connection mode at any time, so we have
126 * to hold a copy of the original connection mode */
127 conn->mode_orig = conn->mode;
128
129 return ret;
130}
131
132/* We have a null terminated string with the endpoint name here. We only
133 * support two kinds. Simple ones as seen on the BSC level and the ones
134 * seen on the trunk side. (helper function for find_endpoint()) */
135static struct mgcp_endpoint *find_e1_endpoint(struct mgcp_config *cfg,
136 const char *mgcp)
137{
138 char *rest = NULL;
139 struct mgcp_trunk_config *tcfg;
140 int trunk, endp;
Philipp Maier207ab512018-02-02 14:19:26 +0100141 struct mgcp_endpoint *endp_ptr;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200142
143 trunk = strtoul(mgcp + 6, &rest, 10);
144 if (rest == NULL || rest[0] != '/' || trunk < 1) {
145 LOGP(DLMGCP, LOGL_ERROR, "Wrong trunk name '%s'\n", mgcp);
146 return NULL;
147 }
148
149 endp = strtoul(rest + 1, &rest, 10);
150 if (rest == NULL || rest[0] != '@') {
151 LOGP(DLMGCP, LOGL_ERROR, "Wrong endpoint name '%s'\n", mgcp);
152 return NULL;
153 }
154
155 /* signalling is on timeslot 1 */
156 if (endp == 1)
157 return NULL;
158
159 tcfg = mgcp_trunk_num(cfg, trunk);
160 if (!tcfg) {
161 LOGP(DLMGCP, LOGL_ERROR, "The trunk %d is not declared.\n",
162 trunk);
163 return NULL;
164 }
165
166 if (!tcfg->endpoints) {
167 LOGP(DLMGCP, LOGL_ERROR,
168 "Endpoints of trunk %d not allocated.\n", trunk);
169 return NULL;
170 }
171
172 if (endp < 1 || endp >= tcfg->number_endpoints) {
173 LOGP(DLMGCP, LOGL_ERROR, "Failed to find endpoint '%s'\n",
174 mgcp);
175 return NULL;
176 }
177
Philipp Maier207ab512018-02-02 14:19:26 +0100178 endp_ptr = &tcfg->endpoints[endp];
179 endp_ptr->wildcarded_req = false;
180 return endp_ptr;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200181}
182
Philipp Maier55295f72018-01-15 14:00:28 +0100183/* Find an endpoint that is not in use. Do this by going through the endpoint
184 * array, check the callid. A callid nullpointer indicates that the endpoint
185 * is free */
186static struct mgcp_endpoint *find_free_endpoint(struct mgcp_endpoint *endpoints,
187 unsigned int number_endpoints)
188{
189 struct mgcp_endpoint *endp;
190 unsigned int i;
191
192 for (i = 0; i < number_endpoints; i++) {
193 if (endpoints[i].callid == NULL) {
194 endp = &endpoints[i];
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200195 LOGPENDP(endp, DLMGCP, LOGL_DEBUG,
196 "found free endpoint\n");
Philipp Maier207ab512018-02-02 14:19:26 +0100197 endp->wildcarded_req = true;
Philipp Maier55295f72018-01-15 14:00:28 +0100198 return endp;
199 }
200 }
201
Philipp Maierb911b872018-02-02 11:48:16 +0100202 LOGP(DLMGCP, LOGL_ERROR, "Not able to find a free endpoint\n");
Philipp Maier55295f72018-01-15 14:00:28 +0100203 return NULL;
204}
205
Philipp Maier12943ea2018-01-17 15:40:25 +0100206/* Check if the domain name, which is supplied with the endpoint name
207 * matches the configuration. */
208static int check_domain_name(struct mgcp_config *cfg, const char *mgcp)
209{
210 char *domain_to_check;
211
212 domain_to_check = strstr(mgcp, "@");
213 if (!domain_to_check)
214 return -EINVAL;
215
Neels Hofmeyr352eed02018-08-20 23:59:32 +0200216 /* Accept any domain if configured as "*" */
217 if (!strcmp(cfg->domain, "*"))
218 return 0;
219
Neels Hofmeyr96c31072018-12-19 00:31:48 +0100220 if (strcmp(domain_to_check+1, cfg->domain) != 0) {
221 LOGP(DLMGCP, LOGL_ERROR, "Wrong domain name '%s', expecting '%s'\n", mgcp, cfg->domain);
Philipp Maier12943ea2018-01-17 15:40:25 +0100222 return -EINVAL;
Neels Hofmeyr96c31072018-12-19 00:31:48 +0100223 }
Philipp Maier12943ea2018-01-17 15:40:25 +0100224
225 return 0;
226}
227
Philipp Maier87bd9be2017-08-22 16:35:41 +0200228/* Search the endpoint pool for the endpoint that had been selected via the
229 * MGCP message (helper function for mgcp_analyze_header()) */
230static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg,
Philipp Maiera49e32a2018-02-01 18:18:50 +0100231 const char *mgcp,
232 int *cause)
Philipp Maier87bd9be2017-08-22 16:35:41 +0200233{
234 char *endptr = NULL;
235 unsigned int gw = INT_MAX;
Philipp Maier7f0966c2018-01-17 18:18:12 +0100236 const char *endpoint_number_str;
Philipp Maiera49e32a2018-02-01 18:18:50 +0100237 struct mgcp_endpoint *endp;
238
239 *cause = 0;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200240
Philipp Maier7f0966c2018-01-17 18:18:12 +0100241 /* Check if the domainname in the request is correct */
Philipp Maier12943ea2018-01-17 15:40:25 +0100242 if (check_domain_name(cfg, mgcp)) {
Neels Hofmeyr0a89e922018-08-20 22:39:53 +0200243 *cause = -500;
Philipp Maier12943ea2018-01-17 15:40:25 +0100244 return NULL;
245 }
246
Philipp Maier7f0966c2018-01-17 18:18:12 +0100247 /* Check if the E1 trunk is requested */
Philipp Maiera49e32a2018-02-01 18:18:50 +0100248 if (strncmp(mgcp, "ds/e1", 5) == 0) {
249 endp = find_e1_endpoint(cfg, mgcp);
250 if (!endp)
251 *cause = -500;
252 return endp;
253 }
Philipp Maier87bd9be2017-08-22 16:35:41 +0200254
Philipp Maier7f0966c2018-01-17 18:18:12 +0100255 /* Check if the virtual trunk is addressed (new, correct way with prefix) */
256 if (strncmp
257 (mgcp, MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK,
258 strlen(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK)) == 0) {
259 endpoint_number_str =
260 mgcp + strlen(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK);
261 if (endpoint_number_str[0] == '*') {
Philipp Maiera49e32a2018-02-01 18:18:50 +0100262 endp = find_free_endpoint(cfg->trunk.endpoints,
Philipp Maier7f0966c2018-01-17 18:18:12 +0100263 cfg->trunk.number_endpoints);
Philipp Maiera49e32a2018-02-01 18:18:50 +0100264 if (!endp)
265 *cause = -403;
266 return endp;
Philipp Maier7f0966c2018-01-17 18:18:12 +0100267 }
Philipp Maier7f0966c2018-01-17 18:18:12 +0100268 gw = strtoul(endpoint_number_str, &endptr, 16);
Philipp Maier207ab512018-02-02 14:19:26 +0100269 if (gw < cfg->trunk.number_endpoints && endptr[0] == '@') {
270 endp = &cfg->trunk.endpoints[gw];
271 endp->wildcarded_req = false;
272 return endp;
273 }
Philipp Maier55295f72018-01-15 14:00:28 +0100274 }
275
Philipp Maier7f0966c2018-01-17 18:18:12 +0100276 /* Deprecated method without prefix */
277 LOGP(DLMGCP, LOGL_NOTICE,
278 "Addressing virtual trunk without prefix (deprecated), please use %s: '%s'\n",
279 MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK, mgcp);
Harald Welte33eafe02017-12-28 03:15:27 +0100280 gw = strtoul(mgcp, &endptr, 16);
Philipp Maier207ab512018-02-02 14:19:26 +0100281 if (gw < cfg->trunk.number_endpoints && endptr[0] == '@') {
282 endp = &cfg->trunk.endpoints[gw];
283 endp->wildcarded_req = false;
284 return endp;
285 }
Philipp Maier87bd9be2017-08-22 16:35:41 +0200286
287 LOGP(DLMGCP, LOGL_ERROR, "Not able to find the endpoint: '%s'\n", mgcp);
Philipp Maiera49e32a2018-02-01 18:18:50 +0100288 *cause = -500;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200289 return NULL;
290}
291
292/*! Analyze and parse the the hader of an MGCP messeage string.
293 * \param[out] pdata caller provided memory to store the parsing results
294 * \param[in] data mgcp message string
295 * \returns when the status line was complete and transaction_id and
296 * endp out parameters are set, -1 on error */
297int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
298{
299 int i = 0;
300 char *elem, *save = NULL;
Philipp Maiera49e32a2018-02-01 18:18:50 +0100301 int cause;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200302
303 /*! This function will parse the header part of the received
304 * MGCP message. The parsing results are stored in pdata.
305 * The function will also automatically search the pool with
306 * available endpoints in order to find an endpoint that matches
307 * the endpoint string in in the header */
308
309 OSMO_ASSERT(data);
310 pdata->trans = "000000";
311
312 for (elem = strtok_r(data, " ", &save); elem;
313 elem = strtok_r(NULL, " ", &save)) {
314 switch (i) {
315 case 0:
316 pdata->trans = elem;
317 break;
318 case 1:
Philipp Maiera49e32a2018-02-01 18:18:50 +0100319 pdata->endp = find_endpoint(pdata->cfg, elem, &cause);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200320 if (!pdata->endp) {
321 LOGP(DLMGCP, LOGL_ERROR,
322 "Unable to find Endpoint `%s'\n", elem);
Neels Hofmeyr0a89e922018-08-20 22:39:53 +0200323 OSMO_ASSERT(cause < 0);
Philipp Maiera49e32a2018-02-01 18:18:50 +0100324 return cause;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200325 }
326 break;
327 case 2:
Pau Espin Pedrol9a345922019-06-26 13:06:30 +0200328 if (strcasecmp("MGCP", elem)) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200329 LOGP(DLMGCP, LOGL_ERROR,
330 "MGCP header parsing error\n");
Harald Welteabbb6b92017-12-28 13:13:50 +0100331 return -510;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200332 }
333 break;
334 case 3:
335 if (strcmp("1.0", elem)) {
336 LOGP(DLMGCP, LOGL_ERROR, "MGCP version `%s' "
337 "not supported\n", elem);
Harald Welteabbb6b92017-12-28 13:13:50 +0100338 return -528;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200339 }
340 break;
341 }
342 i++;
343 }
344
345 if (i != 4) {
346 LOGP(DLMGCP, LOGL_ERROR, "MGCP status line too short.\n");
347 pdata->trans = "000000";
348 pdata->endp = NULL;
Harald Welteabbb6b92017-12-28 13:13:50 +0100349 return -510;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200350 }
351
352 return 0;
353}
354
355/*! Extract OSMUX CID from an MGCP parameter line (string).
356 * \param[in] line single parameter line from the MGCP message
Pau Espin Pedrol2b896172019-04-24 13:47:23 +0200357 * \returns OSMUX CID, -1 wildcard, -2 on error */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200358int mgcp_parse_osmux_cid(const char *line)
359{
360 int osmux_cid;
361
Pau Espin Pedrol2b896172019-04-24 13:47:23 +0200362
Pau Espin Pedrolc1bf4692019-05-14 16:23:24 +0200363 if (strcasecmp(line + 2, "Osmux: *") == 0) {
Pau Espin Pedrol2b896172019-04-24 13:47:23 +0200364 LOGP(DLMGCP, LOGL_DEBUG, "Parsed wilcard Osmux CID\n");
365 return -1;
366 }
367
Pau Espin Pedrolc1bf4692019-05-14 16:23:24 +0200368 if (sscanf(line + 2 + 7, "%u", &osmux_cid) != 1) {
Pau Espin Pedrolef6304e2019-04-23 13:24:37 +0200369 LOGP(DLMGCP, LOGL_ERROR, "Failed parsing Osmux in MGCP msg line: %s\n",
370 line);
Pau Espin Pedrol2b896172019-04-24 13:47:23 +0200371 return -2;
Pau Espin Pedrolef6304e2019-04-23 13:24:37 +0200372 }
Philipp Maier87bd9be2017-08-22 16:35:41 +0200373
374 if (osmux_cid > OSMUX_CID_MAX) {
375 LOGP(DLMGCP, LOGL_ERROR, "Osmux ID too large: %u > %u\n",
376 osmux_cid, OSMUX_CID_MAX);
Pau Espin Pedrol2b896172019-04-24 13:47:23 +0200377 return -2;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200378 }
379 LOGP(DLMGCP, LOGL_DEBUG, "bsc-nat offered Osmux CID %u\n", osmux_cid);
380
381 return osmux_cid;
382}
383
384/*! Check MGCP parameter line (string) for plausibility.
385 * \param[in] endp pointer to endpoint (only used for log output)
386 * \param[in] line single parameter line from the MGCP message
387 * \returns 1 when line seems plausible, 0 on error */
388int mgcp_check_param(const struct mgcp_endpoint *endp, const char *line)
389{
390 const size_t line_len = strlen(line);
391 if (line[0] != '\0' && line_len < 2) {
392 LOGP(DLMGCP, LOGL_ERROR,
393 "Wrong MGCP option format: '%s' on 0x%x\n",
394 line, ENDPOINT_NUMBER(endp));
395 return 0;
396 }
397
398 /* FIXME: A couple more checks wouldn't hurt... */
399
400 return 1;
401}
402
403/*! Check if the specified callid seems plausible.
404 * \param[in] endp pointer to endpoint
405 * \param{in] callid to verify
406 * \returns 1 when callid seems plausible, 0 on error */
407int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid)
408{
409 /*! This function compares the supplied callid with the called that is
410 * stored in the endpoint structure. */
411
412 if (!endp)
413 return -1;
Neels Hofmeyre6d8e912018-08-23 16:36:48 +0200414
415 /* Accept any CallID for "X-Osmo-IGN: C" */
416 if (endp->x_osmo_ign & MGCP_X_OSMO_IGN_CALLID)
417 return 0;
418
Philipp Maier87bd9be2017-08-22 16:35:41 +0200419 if (!callid)
420 return -1;
421 if (!endp->callid)
422 return -1;
423
424 if (strcmp(endp->callid, callid) != 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200425 LOGPENDP(endp, DLMGCP, LOGL_ERROR,
426 "CallIDs mismatch: '%s' != '%s'\n",
427 endp->callid, callid);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200428 return -1;
429 }
430
431 return 0;
432}
433
434/*! Check if the specified connection id seems plausible.
435 * \param[in] endp pointer to endpoint
436 * \param{in] connection id to verify
Neels Hofmeyreb72ff02018-09-03 23:00:07 +0200437 * \returns 0 when connection id is valid and exists, an RFC3435 error code on error.
Neels Hofmeyr8a91d2c2018-09-03 22:51:30 +0200438 */
Philipp Maier01d24a32017-11-21 17:26:09 +0100439int mgcp_verify_ci(struct mgcp_endpoint *endp, const char *conn_id)
Philipp Maier87bd9be2017-08-22 16:35:41 +0200440{
Neels Hofmeyreb72ff02018-09-03 23:00:07 +0200441 /* For invalid conn_ids, return 510 "The transaction could not be executed, because some
442 * unspecified protocol error was detected." */
443
Philipp Maier01d24a32017-11-21 17:26:09 +0100444 /* Check for null identifiers */
445 if (!conn_id) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200446 LOGPENDP(endp, DLMGCP, LOGL_ERROR,
447 "invalid ConnectionIdentifier (missing)\n");
Neels Hofmeyreb72ff02018-09-03 23:00:07 +0200448 return 510;
Philipp Maier01d24a32017-11-21 17:26:09 +0100449 }
Philipp Maier87bd9be2017-08-22 16:35:41 +0200450
Philipp Maier01d24a32017-11-21 17:26:09 +0100451 /* Check for empty connection identifiers */
452 if (strlen(conn_id) == 0) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200453 LOGPENDP(endp, DLMGCP, LOGL_ERROR,
454 "invalid ConnectionIdentifier (empty)\n");
Neels Hofmeyreb72ff02018-09-03 23:00:07 +0200455 return 510;
Philipp Maier01d24a32017-11-21 17:26:09 +0100456 }
Philipp Maier87bd9be2017-08-22 16:35:41 +0200457
Philipp Maier01d24a32017-11-21 17:26:09 +0100458 /* Check for over long connection identifiers */
Neels Hofmeyr5336f572018-09-03 22:05:48 +0200459 if (strlen(conn_id) > (MGCP_CONN_ID_MAXLEN-1)) {
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200460 LOGPENDP(endp, DLMGCP, LOGL_ERROR,
461 "invalid ConnectionIdentifier (too long: %zu > %d) 0x%s\n",
462 strlen(conn_id), MGCP_CONN_ID_MAXLEN-1, conn_id);
Neels Hofmeyreb72ff02018-09-03 23:00:07 +0200463 return 510;
Philipp Maier01d24a32017-11-21 17:26:09 +0100464 }
465
466 /* Check if connection exists */
467 if (mgcp_conn_get(endp, conn_id))
Philipp Maier87bd9be2017-08-22 16:35:41 +0200468 return 0;
469
Pau Espin Pedrol3239f622019-04-24 18:47:46 +0200470 LOGPENDP(endp, DLMGCP, LOGL_ERROR,
471 "no connection found under ConnectionIdentifier 0x%s\n", conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200472
Neels Hofmeyreb72ff02018-09-03 23:00:07 +0200473 /* When the conn_id was not found, return error code 515 "The transaction refers to an incorrect
474 * connection-id (may have been already deleted)." */
475 return 515;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200476}
477
478/*! Extract individual lines from MCGP message.
479 * \param[in] str MGCP message string, consisting of multiple lines
480 * \param{in] saveptr pointer to next line in str
481 * \returns line, NULL when done */
482char *mgcp_strline(char *str, char **saveptr)
483{
484 char *result;
485
486 /*! The function must be called with *str set to the input string
487 * for the first line. After that saveptr will be initalized.
488 * all consecutive lines are extracted by calling the function
489 * with str set to NULL. When done, the function will return NULL
490 * to indicate that all lines have been parsed. */
491
492 if (str)
493 *saveptr = str;
494
495 result = *saveptr;
496
497 if (*saveptr != NULL) {
498 *saveptr = strpbrk(*saveptr, "\r\n");
499
500 if (*saveptr != NULL) {
501 char *eos = *saveptr;
502
503 if ((*saveptr)[0] == '\r' && (*saveptr)[1] == '\n')
504 (*saveptr)++;
505 (*saveptr)++;
506 if ((*saveptr)[0] == '\0')
507 *saveptr = NULL;
508
509 *eos = '\0';
510 }
511 }
512
513 return result;
514}