]> git.sesse.net Git - vlc/blob - modules/access/rtp/input.c
Fixed deadlock when no data are received in rtp.
[vlc] / modules / access / rtp / input.c
1 /**
2  * @file input.c
3  * @brief RTP packet input
4  */
5 /*****************************************************************************
6  * Copyright © 2008 Rémi Denis-Courmont
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2.0
11  * of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  ****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26
27 #include <vlc_common.h>
28 #include <vlc_demux.h>
29 #include <vlc_block.h>
30 #include <vlc_network.h>
31
32 #include <unistd.h>
33 #ifdef HAVE_POLL
34 # include <poll.h>
35 #endif
36
37 #include "rtp.h"
38 #include <srtp.h>
39
40 /**
41  * Gets a datagram from the network.
42  * @param fd datagram file descriptor
43  * @return a block or NULL on fatal error (socket dead)
44  */
45 static block_t *rtp_dgram_recv (int fd)
46 {
47     block_t *block = block_Alloc (0xffff);
48     ssize_t len;
49
50     do
51     {
52         struct pollfd ufd = { .fd = fd, .events = POLLIN, };
53
54         block_cleanup_push (block);
55         poll (&ufd, 1, -1);
56         len = recv (fd, block->p_buffer, block->i_buffer, 0);
57         vlc_cleanup_pop ();
58
59         if ((len <= 0) && (ufd.revents & POLLHUP))
60         {   /* POLLHUP -> permanent (DCCP) socket error */
61             block_Release (block);
62             return NULL;
63         }
64     }
65     while (len == -1);
66
67     return block_Realloc (block, 0, len);
68 }
69
70
71 /**
72  * Gets a framed RTP packet.
73  * @param fd stream file descriptor
74  * @return a block or NULL in case of fatal error
75  */
76 static block_t *rtp_stream_recv (int fd)
77 {
78     ssize_t len = 0;
79     struct pollfd ufd = { .fd = fd, .events = POLLIN, };
80     uint8_t hdr[2]; /* frame header */
81
82     /* Receives the RTP frame header */
83     do
84     {
85         ssize_t val;
86
87         poll (&ufd, 1, -1);
88         val = recv (fd, hdr + len, 2 - len, 0);
89         if (val <= 0)
90             return NULL;
91         len += val;
92     }
93     while (len < 2);
94
95     block_t *block = block_Alloc (GetWBE (hdr));
96
97     /* Receives the RTP packet */
98     for (ssize_t i = 0; i < len;)
99     {
100         ssize_t val;
101
102         block_cleanup_push (block);
103         poll (&ufd, 1, -1);
104         val = recv (fd, block->p_buffer + i, block->i_buffer - i, 0);
105         vlc_cleanup_pop ();
106
107         if (val <= 0)
108         {
109             block_Release (block);
110             return NULL;
111         }
112         i += val;
113     }
114
115     return block;
116 }
117
118
119 static block_t *rtp_recv (demux_t *demux)
120 {
121     demux_sys_t *p_sys = demux->p_sys;
122
123     for (block_t *block;; block_Release (block))
124     {
125         block = p_sys->framed_rtp
126                 ? rtp_stream_recv (p_sys->fd)
127                 : rtp_dgram_recv (p_sys->fd);
128         if (block == NULL)
129         {
130             msg_Err (demux, "RTP flow stopped");
131             break; /* fatal error */
132         }
133
134         if (block->i_buffer < 2)
135             continue;
136
137         /* FIXME */
138         const uint8_t ptype = rtp_ptype (block);
139         if (ptype >= 72 && ptype <= 76)
140             continue; /* Muxed RTCP, ignore for now */
141
142         if (p_sys->srtp)
143         {
144             size_t len = block->i_buffer;
145             int canc, err;
146
147             canc = vlc_savecancel ();
148             err = srtp_recv (p_sys->srtp, block->p_buffer, &len);
149             vlc_restorecancel (canc);
150             if (err)
151             {
152                 msg_Dbg (demux, "SRTP authentication/decryption failed");
153                 continue;
154             }
155             block->i_buffer = len;
156         }
157         return block; /* success! */
158     }
159     return NULL;
160 }
161
162
163 void *rtp_thread (void *data)
164 {
165     demux_t *demux = data;
166     demux_sys_t *p_sys = demux->p_sys;
167
168     for (;;)
169     {
170         block_t *block = rtp_recv (demux);
171         if (block == NULL)
172             break; /* fatal error: abort */
173
174         vlc_mutex_lock (&p_sys->lock);
175
176         /* Autodetect payload type, _before_ rtp_queue() */
177         if (p_sys->autodetect)
178         {
179             if (rtp_autodetect (demux, p_sys->session, block))
180             {
181                 block_Release (block);
182                 continue;
183             }
184             p_sys->autodetect = false;
185         }
186
187         rtp_queue (demux, p_sys->session, block);
188         vlc_cond_signal (&p_sys->wait);
189         vlc_mutex_unlock (&p_sys->lock);
190     }
191     /* TODO: return 0 from Demux */
192     return NULL;
193 }
194
195
196 void rtp_process (demux_t *demux)
197 {
198     demux_sys_t *p_sys = demux->p_sys;
199     mtime_t deadline;
200
201     vlc_mutex_lock (&p_sys->lock);
202     if (!rtp_dequeue (demux, p_sys->session, &deadline))
203         deadline = mdate () + CLOCK_FREQ / 5;
204     vlc_cond_timedwait (&p_sys->wait, &p_sys->lock, deadline);
205     vlc_mutex_unlock (&p_sys->lock);
206 }
207