avformat/rt*p: Joining a SSM multicast group using an SDP (Issue #2171)
[ffmpeg.git] / libavformat / rtpproto.c
1 /*
2  * RTP network protocol
3  * Copyright (c) 2002 Fabrice Bellard
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 /**
23  * @file
24  * RTP protocol
25  */
26
27 #include "libavutil/parseutils.h"
28 #include "libavutil/avstring.h"
29 #include "avformat.h"
30 #include "avio_internal.h"
31 #include "rtpdec.h"
32 #include "url.h"
33
34 #include <stdarg.h>
35 #include "internal.h"
36 #include "network.h"
37 #include "os_support.h"
38 #include <fcntl.h>
39 #if HAVE_POLL_H
40 #include <sys/poll.h>
41 #endif
42
43 typedef struct RTPContext {
44     URLContext *rtp_hd, *rtcp_hd;
45     int rtp_fd, rtcp_fd, ssm;
46     struct sockaddr_storage ssm_addr;
47 } RTPContext;
48
49 /**
50  * If no filename is given to av_open_input_file because you want to
51  * get the local port first, then you must call this function to set
52  * the remote server address.
53  *
54  * @param h media file context
55  * @param uri of the remote server
56  * @return zero if no error.
57  */
58
59 int ff_rtp_set_remote_url(URLContext *h, const char *uri)
60 {
61     RTPContext *s = h->priv_data;
62     char hostname[256];
63     int port;
64
65     char buf[1024];
66     char path[1024];
67
68     av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port,
69                  path, sizeof(path), uri);
70
71     ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port, "%s", path);
72     ff_udp_set_remote_url(s->rtp_hd, buf);
73
74     ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port + 1, "%s", path);
75     ff_udp_set_remote_url(s->rtcp_hd, buf);
76     return 0;
77 }
78
79 static struct addrinfo* rtp_resolve_host(const char *hostname, int port,
80                                          int type, int family, int flags)
81 {
82     struct addrinfo hints = { 0 }, *res = 0;
83     int error;
84     char sport[16];
85     const char *node = 0, *service = "0";
86
87     if (port > 0) {
88         snprintf(sport, sizeof(sport), "%d", port);
89         service = sport;
90     }
91     if ((hostname) && (hostname[0] != '\0') && (hostname[0] != '?')) {
92         node = hostname;
93     }
94     hints.ai_socktype = type;
95     hints.ai_family   = family;
96     hints.ai_flags = flags;
97     if ((error = getaddrinfo(node, service, &hints, &res))) {
98         res = NULL;
99         av_log(NULL, AV_LOG_ERROR, "rtp_resolve_host: %s\n", gai_strerror(error));
100     }
101
102     return res;
103 }
104
105 /**
106  * add option to url of the form:
107  * "http://host:port/path?option1=val1&option2=val2...
108  */
109
110 static av_printf_format(3, 4) void url_add_option(char *buf, int buf_size, const char *fmt, ...)
111 {
112     char buf1[1024];
113     va_list ap;
114
115     va_start(ap, fmt);
116     if (strchr(buf, '?'))
117         av_strlcat(buf, "&", buf_size);
118     else
119         av_strlcat(buf, "?", buf_size);
120     vsnprintf(buf1, sizeof(buf1), fmt, ap);
121     av_strlcat(buf, buf1, buf_size);
122     va_end(ap);
123 }
124
125 static void build_udp_url(char *buf, int buf_size,
126                           const char *hostname, int port,
127                           int ssm, const char* source_addr,
128                           int local_port, int ttl,
129                           int max_packet_size, int connect)
130 {
131     ff_url_join(buf, buf_size, "udp", NULL, hostname, port, NULL);
132     if (local_port >= 0)
133         url_add_option(buf, buf_size, "localport=%d", local_port);
134     if (ttl >= 0)
135         url_add_option(buf, buf_size, "ttl=%d", ttl);
136     if (max_packet_size >=0)
137         url_add_option(buf, buf_size, "pkt_size=%d", max_packet_size);
138     if (ssm)
139         url_add_option(buf, buf_size, "sources=%s", source_addr);
140     if (connect)
141         url_add_option(buf, buf_size, "connect=1");
142     url_add_option(buf, buf_size, "fifo_size=0");
143 }
144
145 /**
146  * url syntax: rtp://host:port[?option=val...]
147  * option: 'ttl=n'            : set the ttl value (for multicast only)
148  *         'rtcpport=n'       : set the remote rtcp port to n
149  *         'localrtpport=n'   : set the local rtp port to n
150  *         'localrtcpport=n'  : set the local rtcp port to n
151  *         'pkt_size=n'       : set max packet size
152  *         'connect=0/1'      : do a connect() on the UDP socket
153  * deprecated option:
154  *         'localport=n'      : set the local port to n
155  *         'ssm=ip'           : use ip as source-specific multicast address
156  *
157  * if rtcpport isn't set the rtcp port will be the rtp port + 1
158  * if local rtp port isn't set any available port will be used for the local
159  * rtp and rtcp ports
160  * if the local rtcp port is not set it will be the local rtp port + 1
161  */
162
163 static int rtp_open(URLContext *h, const char *uri, int flags)
164 {
165     RTPContext *s = h->priv_data;
166     int rtp_port, rtcp_port,
167         ttl, connect,
168         local_rtp_port, local_rtcp_port, max_packet_size;
169     char hostname[256],source_ip[50];
170     char buf[1024];
171     char path[1024];
172     const char *p;
173     struct addrinfo *sourceaddr;
174
175     av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port,
176                  path, sizeof(path), uri);
177     /* extract parameters */
178     ttl = -1;
179     rtcp_port = rtp_port+1;
180     local_rtp_port = -1;
181     local_rtcp_port = -1;
182     max_packet_size = -1;
183     s->ssm = 0;
184     connect = 0;
185
186     p = strchr(uri, '?');
187     if (p) {
188         if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) {
189             ttl = strtol(buf, NULL, 10);
190         }
191         if (av_find_info_tag(buf, sizeof(buf), "rtcpport", p)) {
192             rtcp_port = strtol(buf, NULL, 10);
193         }
194         if (av_find_info_tag(buf, sizeof(buf), "localport", p)) {
195             local_rtp_port = strtol(buf, NULL, 10);
196         }
197         if (av_find_info_tag(buf, sizeof(buf), "localrtpport", p)) {
198             local_rtp_port = strtol(buf, NULL, 10);
199         }
200         if (av_find_info_tag(buf, sizeof(buf), "localrtcpport", p)) {
201             local_rtcp_port = strtol(buf, NULL, 10);
202         }
203         if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
204             max_packet_size = strtol(buf, NULL, 10);
205         }
206         if (av_find_info_tag(buf, sizeof(buf), "connect", p)) {
207             connect = strtol(buf, NULL, 10);
208         }
209         if (av_find_info_tag(buf, sizeof(buf), "ssm", p)) {
210             s->ssm = 1;
211             snprintf(source_ip, sizeof(source_ip), "%s", buf);
212
213             sourceaddr = rtp_resolve_host(source_ip, 0,
214                                           SOCK_DGRAM, AF_UNSPEC,
215                                           AI_NUMERICHOST);
216
217             memcpy(&s->ssm_addr, sourceaddr->ai_addr, sourceaddr->ai_addrlen);
218             freeaddrinfo(sourceaddr);
219         }
220     }
221
222     build_udp_url(buf, sizeof(buf),
223                   hostname, rtp_port, s->ssm, source_ip, local_rtp_port, ttl, max_packet_size,
224                   connect);
225     if (ffurl_open(&s->rtp_hd, buf, flags, &h->interrupt_callback, NULL) < 0)
226         goto fail;
227     if (local_rtp_port>=0 && local_rtcp_port<0)
228         local_rtcp_port = ff_udp_get_local_port(s->rtp_hd) + 1;
229
230     build_udp_url(buf, sizeof(buf),
231                   hostname, rtcp_port, s->ssm, source_ip, local_rtcp_port, ttl, max_packet_size,
232                   connect);
233     if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL) < 0)
234         goto fail;
235
236     /* just to ease handle access. XXX: need to suppress direct handle
237        access */
238     s->rtp_fd = ffurl_get_file_handle(s->rtp_hd);
239     s->rtcp_fd = ffurl_get_file_handle(s->rtcp_hd);
240
241     h->max_packet_size = s->rtp_hd->max_packet_size;
242     h->is_streamed = 1;
243     return 0;
244
245  fail:
246     if (s->rtp_hd)
247         ffurl_close(s->rtp_hd);
248     if (s->rtcp_hd)
249         ffurl_close(s->rtcp_hd);
250     return AVERROR(EIO);
251 }
252
253 static int rtp_read(URLContext *h, uint8_t *buf, int size)
254 {
255     RTPContext *s = h->priv_data;
256     struct sockaddr_storage from;
257     socklen_t from_len;
258     int len, n;
259     struct pollfd p[2] = {{s->rtp_fd, POLLIN, 0}, {s->rtcp_fd, POLLIN, 0}};
260
261     for(;;) {
262         if (ff_check_interrupt(&h->interrupt_callback))
263             return AVERROR_EXIT;
264         /* build fdset to listen to RTP and RTCP packets */
265         n = poll(p, 2, 100);
266         if (n > 0) {
267             /* first try RTCP */
268             if (p[1].revents & POLLIN) {
269                 from_len = sizeof(from);
270                 len = recvfrom (s->rtcp_fd, buf, size, 0,
271                                 (struct sockaddr *)&from, &from_len);
272                 if (len < 0) {
273                     if (ff_neterrno() == AVERROR(EAGAIN) ||
274                         ff_neterrno() == AVERROR(EINTR))
275                         continue;
276                     return AVERROR(EIO);
277                 }
278                 if (s->ssm) {
279                     if (from.ss_family == AF_INET && s->ssm_addr.ss_family == AF_INET) {
280                         uint32_t intended_source = ((struct sockaddr_in *)&s->ssm_addr)->sin_addr.s_addr;
281                         uint32_t actual_source = ((struct sockaddr_in *)&from)->sin_addr.s_addr;
282                         if (intended_source != actual_source) {
283                             // discard the packet without any processing
284                             continue;
285                         }
286                     }
287
288 #if defined(IPPROTO_IPV6)
289                     if (from.ss_family == AF_INET6 && s->ssm_addr.ss_family == AF_INET6) {
290                         unsigned char* intended_source = ((struct sockaddr_in6 *)&s->ssm_addr)->sin6_addr.s6_addr;
291                         unsigned char* actual_source = ((struct sockaddr_in6 *)&from)->sin6_addr.s6_addr;
292                         if (memcmp(intended_source, actual_source, 16) != 0) {
293                             // discard the packet without any processing
294                             continue;
295                         }
296                     }
297 #endif
298                 }
299                 break;
300             }
301             /* then RTP */
302             if (p[0].revents & POLLIN) {
303                 from_len = sizeof(from);
304                 len = recvfrom (s->rtp_fd, buf, size, 0,
305                                 (struct sockaddr *)&from, &from_len);
306                 if (len < 0) {
307                     if (ff_neterrno() == AVERROR(EAGAIN) ||
308                         ff_neterrno() == AVERROR(EINTR))
309                         continue;
310                     return AVERROR(EIO);
311                 }
312                 if (s->ssm) {
313                     if (from.ss_family == AF_INET && s->ssm_addr.ss_family == AF_INET) {
314                         uint32_t intended_source = ((struct sockaddr_in *)&s->ssm_addr)->sin_addr.s_addr;
315                         uint32_t actual_source = ((struct sockaddr_in *)&from)->sin_addr.s_addr;
316                         if (intended_source != actual_source) {
317                             // discard the packet without any processing
318                             continue;
319                         }
320                     }
321
322 #if defined(IPPROTO_IPV6)
323                     if (from.ss_family == AF_INET6 && s->ssm_addr.ss_family == AF_INET6) {
324                         unsigned char* intended_source = ((struct sockaddr_in6 *)&s->ssm_addr)->sin6_addr.s6_addr;
325                         unsigned char* actual_source = ((struct sockaddr_in6 *)&from)->sin6_addr.s6_addr;
326                         if (memcmp(intended_source, actual_source, 16) != 0) {
327                             // discard the packet without any processing
328                             continue;
329                         }
330                     }
331 #endif
332                 }
333                 break;
334             }
335         } else if (n < 0) {
336             if (ff_neterrno() == AVERROR(EINTR))
337                 continue;
338             return AVERROR(EIO);
339         }
340     }
341     return len;
342 }
343
344 static int rtp_write(URLContext *h, const uint8_t *buf, int size)
345 {
346     RTPContext *s = h->priv_data;
347     int ret;
348     URLContext *hd;
349
350     if (RTP_PT_IS_RTCP(buf[1])) {
351         /* RTCP payload type */
352         hd = s->rtcp_hd;
353     } else {
354         /* RTP payload type */
355         hd = s->rtp_hd;
356     }
357
358     ret = ffurl_write(hd, buf, size);
359     return ret;
360 }
361
362 static int rtp_close(URLContext *h)
363 {
364     RTPContext *s = h->priv_data;
365
366     ffurl_close(s->rtp_hd);
367     ffurl_close(s->rtcp_hd);
368     return 0;
369 }
370
371 /**
372  * Return the local rtp port used by the RTP connection
373  * @param h media file context
374  * @return the local port number
375  */
376
377 int ff_rtp_get_local_rtp_port(URLContext *h)
378 {
379     RTPContext *s = h->priv_data;
380     return ff_udp_get_local_port(s->rtp_hd);
381 }
382
383 /**
384  * Return the local rtcp port used by the RTP connection
385  * @param h media file context
386  * @return the local port number
387  */
388
389 int ff_rtp_get_local_rtcp_port(URLContext *h)
390 {
391     RTPContext *s = h->priv_data;
392     return ff_udp_get_local_port(s->rtcp_hd);
393 }
394
395 static int rtp_get_file_handle(URLContext *h)
396 {
397     RTPContext *s = h->priv_data;
398     return s->rtp_fd;
399 }
400
401 static int rtp_get_multi_file_handle(URLContext *h, int **handles,
402                                      int *numhandles)
403 {
404     RTPContext *s = h->priv_data;
405     int *hs       = *handles = av_malloc(sizeof(**handles) * 2);
406     if (!hs)
407         return AVERROR(ENOMEM);
408     hs[0] = s->rtp_fd;
409     hs[1] = s->rtcp_fd;
410     *numhandles = 2;
411     return 0;
412 }
413
414 URLProtocol ff_rtp_protocol = {
415     .name                      = "rtp",
416     .url_open                  = rtp_open,
417     .url_read                  = rtp_read,
418     .url_write                 = rtp_write,
419     .url_close                 = rtp_close,
420     .url_get_file_handle       = rtp_get_file_handle,
421     .url_get_multi_file_handle = rtp_get_multi_file_handle,
422     .priv_data_size            = sizeof(RTPContext),
423     .flags                     = URL_PROTOCOL_FLAG_NETWORK,
424 };