rtp_media_server: fix crash in sdp payload pasring
[sip-router] / src / modules / rtp_media_server / rms_sdp.c
1 /*
2  * Copyright (C) 2017-2018 Julien Chavanton jchavanton@gmail.com
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * Kamailio is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  * Kamailio is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
19  */
20
21 #include "rms_sdp.h"
22 #include "rms_util.h"
23 #include "../../core/data_lump.h"
24 #include "../../core/parser/parse_content.h"
25 #include "../../core/parser/sdp/sdp.h"
26
27 // https://tools.ietf.org/html/rfc4566
28 // (protocol version)
29 const char *sdp_v = "v=0\r\n";
30 // (session name)
31 const char *sdp_s = "s=-\r\n";
32 // (time the session is active)
33 const char *sdp_t = "t=0 0\r\n";
34 //"a=rtpmap:101 telephone-event/8000\r\n"
35 //"a=fmtp:101 0-15\r\n";
36 //"a=rtpmap:0 PCMU/8000\r\n"
37 //"a=rtpmap:8 PCMA/8000\r\n"
38 //"a=rtpmap:96 opus/48000/2\r\n"
39 //"a=fmtp:96 useinbandfec=1\r\n";
40
41 int rms_get_sdp_info(rms_sdp_info_t *sdp_info, struct sip_msg *msg)
42 {
43         sdp_session_cell_t *sdp_session;
44         sdp_stream_cell_t *sdp_stream;
45         str media_ip, media_port;
46         int sdp_session_num = 0;
47         int sdp_stream_num = get_sdp_stream_num(msg);
48         if(parse_sdp(msg) < 0) {
49                 LM_INFO("can not parse sdp\n");
50                 return 0;
51         }
52         sdp_info_t *sdp = (sdp_info_t *)msg->body;
53         if(!sdp) {
54                 LM_INFO("sdp null\n");
55                 return 0;
56         }
57         rms_str_dup(&sdp_info->recv_body, &sdp->text, 1);
58         if(!sdp_info->recv_body.s)
59                 goto error;
60         LM_INFO("sdp body - type[%d]\n", sdp->type);
61         if(sdp_stream_num > 1 || !sdp_stream_num) {
62                 LM_INFO("only support one stream[%d]\n", sdp_stream_num);
63         }
64         sdp_stream_num = 0;
65         sdp_session = get_sdp_session(msg, sdp_session_num);
66         if(!sdp_session) {
67                 return 0;
68         } else {
69                 int sdp_stream_num = 0;
70                 sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num);
71                 if(!sdp_stream) {
72                         LM_INFO("can not get the sdp stream\n");
73                         return 0;
74                 } else {
75                         rms_str_dup(&sdp_info->payloads, &sdp_stream->payloads, 1);
76                         if(!sdp_info->payloads.s)
77                                 goto error;
78                 }
79         }
80         if(sdp_stream->ip_addr.s && sdp_stream->ip_addr.len > 0) {
81                 media_ip = sdp_stream->ip_addr;
82         } else {
83                 media_ip = sdp_session->ip_addr;
84         }
85         rms_str_dup(&sdp_info->remote_ip, &media_ip, 1);
86         if(!sdp_info->remote_ip.s)
87                 goto error;
88         rms_str_dup(&media_port, &sdp_stream->port, 0);
89         if(!media_port.s)
90                 goto error;
91         sdp_info->remote_port = atoi(media_port.s);
92         pkg_free(media_port.s);
93         return 1;
94 error:
95         rms_sdp_info_free(sdp_info);
96         return 0;
97 }
98
99 static char *rms_sdp_get_rtpmap(str body, int type_number)
100 {
101         char *pos = body.s;
102         while((pos = strstr(pos, "a=rtpmap:"))) {
103                 int id;
104                 int sampling_rate;
105                 char codec[64];
106                 sscanf(pos, "a=rtpmap:%d %s/%d", &id, codec, &sampling_rate);
107                 if(id == type_number) {
108                         LM_INFO("[%d][%s/%d]\n", id, codec, sampling_rate);
109                         return rms_char_dup(codec, 1);
110                 }
111                 pos++;
112         }
113         return NULL;
114 }
115
116 void rms_sdp_info_init(rms_sdp_info_t *sdp_info)
117 {
118         memset(sdp_info, 0, sizeof(rms_sdp_info_t));
119 }
120
121 void rms_sdp_info_free(rms_sdp_info_t *sdp_info)
122 {
123         if(sdp_info->remote_ip.s) {
124                 shm_free(sdp_info->remote_ip.s);
125                 sdp_info->remote_ip.s = NULL;
126         }
127         if(sdp_info->payloads.s) {
128                 shm_free(sdp_info->payloads.s);
129                 sdp_info->payloads.s = NULL;
130         }
131         if(sdp_info->new_body.s) {
132                 shm_free(sdp_info->new_body.s);
133                 sdp_info->new_body.s = NULL;
134         }
135 }
136
137 int rms_sdp_prepare_new_body(rms_sdp_info_t *sdp_info, PayloadType *pt)
138 {
139         if(sdp_info->new_body.s)
140                 return 0;
141
142         str *body = &sdp_info->new_body;
143         body->len = strlen(sdp_v) + strlen(sdp_s) + strlen(sdp_t);
144
145         // (originator and session identifier)
146         char sdp_o[128];
147         snprintf(
148                         sdp_o, 128, "o=- 1028316687 1 IN IP4 %s\r\n", sdp_info->local_ip.s);
149         body->len += strlen(sdp_o);
150
151         // (connection information -- not required if included in all media)
152         char sdp_c[128];
153         snprintf(sdp_c, 128, "c=IN IP4 %s\r\n", sdp_info->local_ip.s);
154         body->len += strlen(sdp_c);
155
156         char sdp_m[128];
157         snprintf(sdp_m, 128, "m=audio %d RTP/AVP %d\r\n", sdp_info->udp_local_port, pt->type);
158         body->len += strlen(sdp_m);
159
160         char sdp_a[128];
161         if (pt->type >= 96) {
162                 if (strcasecmp(pt->mime_type,"opus") == 0) {
163                         snprintf(sdp_a, 128, "a=rtpmap:%d opus/48000/2\r\n", pt->type);
164                 } else {
165                         snprintf(sdp_a, 128, "a=rtpmap:%d %s/%d/%d\r\n", pt->type, pt->mime_type, pt->clock_rate, pt->channels);
166                 }
167                 body->len += strlen(sdp_a);
168         }
169
170         body->s = shm_malloc(body->len + 1);
171         if(!body->s)
172                 return 0;
173         strcpy(body->s, sdp_v);
174         strcat(body->s, sdp_o);
175         strcat(body->s, sdp_s);
176         strcat(body->s, sdp_c);
177         strcat(body->s, sdp_t);
178         strcat(body->s, sdp_m);
179
180         if (pt->type >= 96) {
181                 strcat(body->s, sdp_a);
182         }
183         return 1;
184 }
185
186 PayloadType *
187 rms_payload_type_new() // This could be problematic as it must remain compatible with the constructor in MS2.
188 {
189         PayloadType *newpayload = (PayloadType *)shm_malloc(sizeof(PayloadType));
190         newpayload->flags |= PAYLOAD_TYPE_ALLOCATED;
191         memset(newpayload, 0, sizeof(PayloadType));
192         return newpayload;
193 }
194
195 PayloadType *rms_sdp_check_payload_type(PayloadType *pt, rms_sdp_info_t *sdp)
196 {
197         pt->clock_rate = 8000;
198         pt->channels = 1;
199         pt->mime_type = NULL;
200         if (pt->type > 127) {
201                 return NULL;
202         } else if (pt->type >= 96) {
203                 char *rtpmap = rms_sdp_get_rtpmap(sdp->recv_body, pt->type);
204                 if (!rtpmap) return NULL;
205                 char *s_mime_type = strtok(rtpmap,"/");
206                 if (!s_mime_type) {
207                         shm_free(rtpmap);
208                         return NULL;
209                 }
210                 if (strcasecmp(s_mime_type,"opus") == 0) {
211                         int payload_type = pt->type;
212                         memcpy(pt, &payload_type_opus, sizeof(PayloadType));
213                         pt->type = payload_type;
214                         char * s_clock_rate = strtok(NULL,"/");
215                         char * s_channels = strtok(NULL,"/");
216                         if (s_clock_rate) {
217                                 pt->clock_rate = atoi(s_clock_rate);
218                         } else {
219                                 pt->clock_rate = 8000;
220                         }
221                         if (s_channels) {
222                                 pt->channels = atoi(s_channels);
223                         } else {
224                                 pt->channels = 2;
225                         }
226                         shm_free(rtpmap);
227                         LM_INFO("[%p][%d][%s|%d|%d]\n", pt, pt->type, pt->mime_type, pt->clock_rate, pt->channels);
228                         return pt;
229                 }
230                 shm_free(pt->mime_type);
231                 shm_free(rtpmap);
232
233         } else if (pt->type == 0) {
234                 pt->mime_type = rms_char_dup("pcmu", 1); /* ia=rtpmap:0 PCMU/8000*/
235         } else if (pt->type == 8) {
236                 pt->mime_type = rms_char_dup("pcma", 1);
237         }
238         //      } else if (pt->type == 9) {
239         //              pt->mime_type=rms_char_dup("g722", 1);
240         //      } else if (pt->type == 18) {
241         //              pt->mime_type=rms_char_dup("g729", 1);
242         //      }
243         return pt;
244 }
245
246 PayloadType *rms_sdp_select_payload(rms_sdp_info_t *sdp)
247 {
248         // https://tools.ietf.org/html/rfc3551
249         LM_INFO("payloads[%s]\n", sdp->payloads.s); // 0 8
250         PayloadType *pt = rms_payload_type_new();
251         char *payloads = sdp->payloads.s;
252         char *payload_type_number = strtok(payloads, " ");
253
254         while (payload_type_number) {
255                 pt->type = atoi(payload_type_number);
256                 pt = rms_sdp_check_payload_type(pt, sdp);
257                 if (pt->mime_type) return pt;
258                 payload_type_number = strtok(NULL, " ");
259         }
260         if (!pt->mime_type) {
261                 LM_INFO("unsuported codec\n");
262                 if (pt) shm_free(pt); // payload_type_destroy(pt);
263                 return NULL;
264         }
265         LM_INFO("payload_type:%d %s/%d/%d\n", pt->type, pt->mime_type,
266                         pt->clock_rate, pt->channels);
267         return pt;
268 }
269
270
271 int rms_sdp_set_body(struct sip_msg *msg, str *new_body)
272 {
273         struct lump *anchor;
274         char *buf;
275         int len;
276         char *value_s;
277         int value_len;
278         str body = {0, 0};
279         str content_type_sdp = str_init("application/sdp");
280
281         if(!new_body->s || new_body->len == 0) {
282                 LM_ERR("invalid body parameter\n");
283                 return -1;
284         }
285
286         body.len = 0;
287         body.s = get_body(msg);
288         if(body.s == 0) {
289                 LM_ERR("malformed sip message\n");
290                 return -1;
291         }
292
293         del_nonshm_lump(&(msg->body_lumps));
294         msg->body_lumps = NULL;
295
296         if(msg->content_length) {
297                 body.len = get_content_length(msg);
298                 if(body.len > 0) {
299                         if(body.s + body.len > msg->buf + msg->len) {
300                                 LM_ERR("invalid content length: %d\n", body.len);
301                                 return -1;
302                         }
303                         if(del_lump(msg, body.s - msg->buf, body.len, 0) == 0) {
304                                 LM_ERR("cannot delete existing body");
305                                 return -1;
306                         }
307                 }
308         }
309
310         anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0);
311         if(!anchor) {
312                 LM_ERR("failed to get anchor\n");
313                 return -1;
314         }
315
316         if(msg->content_length == 0) {
317                 /* need to add Content-Length */
318                 len = new_body->len;
319                 value_s = int2str(len, &value_len);
320                 LM_DBG("content-length: %d (%s)\n", value_len, value_s);
321
322                 len = CONTENT_LENGTH_LEN + value_len + CRLF_LEN;
323                 buf = pkg_malloc(sizeof(char) * (len));
324                 if(!buf) {
325                         LM_ERR("out of pkg memory\n");
326                         return -1;
327                 }
328
329                 memcpy(buf, CONTENT_LENGTH, CONTENT_LENGTH_LEN);
330                 memcpy(buf + CONTENT_LENGTH_LEN, value_s, value_len);
331                 memcpy(buf + CONTENT_LENGTH_LEN + value_len, CRLF, CRLF_LEN);
332                 if(insert_new_lump_after(anchor, buf, len, 0) == 0) {
333                         LM_ERR("failed to insert content-length lump\n");
334                         pkg_free(buf);
335                         return -1;
336                 }
337         }
338
339         /* add content-type */
340         if(msg->content_type == NULL
341                         || msg->content_type->body.len != content_type_sdp.len
342                         || strncmp(msg->content_type->body.s, content_type_sdp.s,
343                                            content_type_sdp.len)
344                                            != 0) {
345                 if(msg->content_type != NULL) {
346                         if(del_lump(msg, msg->content_type->name.s - msg->buf,
347                                            msg->content_type->len, 0)
348                                         == 0) {
349                                 LM_ERR("failed to delete content type\n");
350                                 return -1;
351                         }
352                 }
353                 value_len = content_type_sdp.len;
354                 len = sizeof("Content-Type: ") - 1 + value_len + CRLF_LEN;
355                 buf = pkg_malloc(sizeof(char) * (len));
356                 if(!buf) {
357                         LM_ERR("out of pkg memory\n");
358                         return -1;
359                 }
360                 memcpy(buf, "Content-Type: ", sizeof("Content-Type: ") - 1);
361                 memcpy(buf + sizeof("Content-Type: ") - 1, content_type_sdp.s,
362                                 value_len);
363                 memcpy(buf + sizeof("Content-Type: ") - 1 + value_len, CRLF, CRLF_LEN);
364                 if(insert_new_lump_after(anchor, buf, len, 0) == 0) {
365                         LM_ERR("failed to insert content-type lump\n");
366                         pkg_free(buf);
367                         return -1;
368                 }
369         }
370         anchor = anchor_lump(msg, body.s - msg->buf, 0, 0);
371
372         if(anchor == 0) {
373                 LM_ERR("failed to get body anchor\n");
374                 return -1;
375         }
376
377         buf = pkg_malloc(sizeof(char) * (new_body->len));
378         if(!buf) {
379                 LM_ERR("out of pkg memory\n");
380                 return -1;
381         }
382         memcpy(buf, new_body->s, new_body->len);
383         if(!insert_new_lump_after(anchor, buf, new_body->len, 0)) {
384                 LM_ERR("failed to insert body lump\n");
385                 pkg_free(buf);
386                 return -1;
387         }
388         LM_DBG("new body: [%.*s]", new_body->len, new_body->s);
389         return 1;
390 }