]> git.sesse.net Git - vlc/blob - modules/access/udp.c
access: simplify control default case, remove dummy warnings
[vlc] / modules / access / udp.c
1 /*****************************************************************************
2  * udp.c: raw UDP input module
3  *****************************************************************************
4  * Copyright (C) 2001-2005 VLC authors and VideoLAN
5  * Copyright (C) 2007 Remi Denis-Courmont
6  * $Id$
7  *
8  * Authors: Christophe Massiot <massiot@via.ecp.fr>
9  *          Tristan Leteurtre <tooney@via.ecp.fr>
10  *          Laurent Aimar <fenrir@via.ecp.fr>
11  *          Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
12  *          Remi Denis-Courmont
13  *
14  * Reviewed: 23 October 2003, Jean-Paul Saman <jpsaman _at_ videolan _dot_ org>
15  *
16  * This program is free software; you can redistribute it and/or modify it
17  * under the terms of the GNU Lesser General Public License as published by
18  * the Free Software Foundation; either version 2.1 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24  * GNU Lesser General Public License for more details.
25  *
26  * You should have received a copy of the GNU Lesser General Public License
27  * along with this program; if not, write to the Free Software Foundation,
28  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
29  *****************************************************************************/
30
31 /*****************************************************************************
32  * Preamble
33  *****************************************************************************/
34
35 #ifdef HAVE_CONFIG_H
36 # include "config.h"
37 #endif
38
39 #include <errno.h>
40 #include <vlc_common.h>
41 #include <vlc_plugin.h>
42 #include <vlc_access.h>
43 #include <vlc_network.h>
44 #include <vlc_block.h>
45
46 #define MTU 65535
47
48 /*****************************************************************************
49  * Module descriptor
50  *****************************************************************************/
51 static int  Open( vlc_object_t * );
52 static void Close( vlc_object_t * );
53
54 #define BUFFER_TEXT N_("Receive buffer")
55 #define BUFFER_LONGTEXT N_("UDP receive buffer size (bytes)" )
56
57 vlc_module_begin ()
58     set_shortname( N_("UDP" ) )
59     set_description( N_("UDP input") )
60     set_category( CAT_INPUT )
61     set_subcategory( SUBCAT_INPUT_ACCESS )
62
63     add_obsolete_integer( "server-port" ) /* since 2.0.0 */
64     add_integer( "udp-buffer", 0x400000, BUFFER_TEXT, BUFFER_LONGTEXT, true )
65
66     set_capability( "access", 0 )
67     add_shortcut( "udp", "udpstream", "udp4", "udp6" )
68
69     set_callbacks( Open, Close )
70 vlc_module_end ()
71
72 struct access_sys_t
73 {
74     int fd;
75     size_t fifo_size;
76     block_fifo_t *fifo;
77     vlc_thread_t thread;
78 };
79
80 /*****************************************************************************
81  * Local prototypes
82  *****************************************************************************/
83 static block_t *BlockUDP( access_t * );
84 static int Control( access_t *, int, va_list );
85 static void* ThreadRead( void *data );
86
87 /*****************************************************************************
88  * Open: open the socket
89  *****************************************************************************/
90 static int Open( vlc_object_t *p_this )
91 {
92     access_t     *p_access = (access_t*)p_this;
93
94     char *psz_name = strdup( p_access->psz_location );
95     char *psz_parser;
96     const char *psz_server_addr, *psz_bind_addr = "";
97     int  i_bind_port = 1234, i_server_port = 0;
98
99     access_sys_t *sys = malloc( sizeof( *sys ) );
100     if( unlikely( sys == NULL ) )
101         return VLC_ENOMEM;
102
103     p_access->p_sys = sys;
104
105     /* Set up p_access */
106     access_InitFields( p_access );
107     ACCESS_SET_CALLBACKS( NULL, BlockUDP, Control, NULL );
108
109     /* Parse psz_name syntax :
110      * [serveraddr[:serverport]][@[bindaddr]:[bindport]] */
111     psz_parser = strchr( psz_name, '@' );
112     if( psz_parser != NULL )
113     {
114         /* Found bind address and/or bind port */
115         *psz_parser++ = '\0';
116         psz_bind_addr = psz_parser;
117
118         if( psz_bind_addr[0] == '[' )
119             /* skips bracket'd IPv6 address */
120             psz_parser = strchr( psz_parser, ']' );
121
122         if( psz_parser != NULL )
123         {
124             psz_parser = strchr( psz_parser, ':' );
125             if( psz_parser != NULL )
126             {
127                 *psz_parser++ = '\0';
128                 i_bind_port = atoi( psz_parser );
129             }
130         }
131     }
132
133     psz_server_addr = psz_name;
134     psz_parser = ( psz_server_addr[0] == '[' )
135         ? strchr( psz_name, ']' ) /* skips bracket'd IPv6 address */
136         : psz_name;
137
138     if( psz_parser != NULL )
139     {
140         psz_parser = strchr( psz_parser, ':' );
141         if( psz_parser != NULL )
142         {
143             *psz_parser++ = '\0';
144             i_server_port = atoi( psz_parser );
145         }
146     }
147
148     msg_Dbg( p_access, "opening server=%s:%d local=%s:%d",
149              psz_server_addr, i_server_port, psz_bind_addr, i_bind_port );
150
151     sys->fd = net_OpenDgram( p_access, psz_bind_addr, i_bind_port,
152                              psz_server_addr, i_server_port, IPPROTO_UDP );
153     free( psz_name );
154     if( sys->fd == -1 )
155     {
156         msg_Err( p_access, "cannot open socket" );
157         goto error;
158     }
159
160     sys->fifo = block_FifoNew();
161     if( unlikely( sys->fifo == NULL ) )
162     {
163         net_Close( sys->fd );
164         goto error;
165     }
166
167     sys->fifo_size = var_InheritInteger( p_access, "udp-buffer");
168
169     if( vlc_clone( &sys->thread, ThreadRead, p_access,
170                    VLC_THREAD_PRIORITY_INPUT ) )
171     {
172         block_FifoRelease( sys->fifo );
173         net_Close( sys->fd );
174 error:
175         free( sys );
176         return VLC_EGENERIC;
177     }
178
179     return VLC_SUCCESS;
180 }
181
182 /*****************************************************************************
183  * Close: free unused data structures
184  *****************************************************************************/
185 static void Close( vlc_object_t *p_this )
186 {
187     access_t     *p_access = (access_t*)p_this;
188     access_sys_t *sys = p_access->p_sys;
189
190     vlc_cancel( sys->thread );
191     vlc_join( sys->thread, NULL );
192     block_FifoRelease( sys->fifo );
193     net_Close( sys->fd );
194     free( sys );
195 }
196
197 /*****************************************************************************
198  * Control:
199  *****************************************************************************/
200 static int Control( access_t *p_access, int i_query, va_list args )
201 {
202     bool    *pb_bool;
203     int64_t *pi_64;
204
205     switch( i_query )
206     {
207         case ACCESS_CAN_SEEK:
208         case ACCESS_CAN_FASTSEEK:
209         case ACCESS_CAN_PAUSE:
210         case ACCESS_CAN_CONTROL_PACE:
211             pb_bool = (bool*)va_arg( args, bool* );
212             *pb_bool = false;
213             break;
214
215         case ACCESS_GET_PTS_DELAY:
216             pi_64 = (int64_t*)va_arg( args, int64_t * );
217             *pi_64 = INT64_C(1000)
218                    * var_InheritInteger(p_access, "network-caching");
219             break;
220
221         default:
222             return VLC_EGENERIC;
223     }
224     return VLC_SUCCESS;
225 }
226
227 /*****************************************************************************
228  * BlockUDP:
229  *****************************************************************************/
230 static block_t *BlockUDP( access_t *p_access )
231 {
232     access_sys_t *sys = p_access->p_sys;
233
234     return block_FifoGet( sys->fifo );
235 }
236
237 /*****************************************************************************
238  * ThreadRead: Pull packets from socket as soon as possible.
239  *****************************************************************************/
240 static void* ThreadRead( void *data )
241 {
242     access_t *access = data;
243     access_sys_t *sys = access->p_sys;
244
245     for( ;; )
246     {
247         block_t *pkt;
248         ssize_t len;
249
250         block_FifoPace( sys->fifo, SIZE_MAX, sys->fifo_size );
251
252         pkt = block_Alloc( MTU );
253         if( unlikely( pkt == NULL ) )
254             break;
255
256         block_cleanup_push( pkt );
257         len = net_Read( access, sys->fd, NULL, pkt->p_buffer, MTU, false );
258         vlc_cleanup_pop();
259
260         if( len == -1 )
261         {
262             block_Release( pkt );
263
264             if( errno == EINTR )
265                 break;
266             continue;
267         }
268
269         pkt = block_Realloc( pkt, 0, len );
270         block_FifoPut( sys->fifo, pkt );
271     }
272
273     block_FifoWake( sys->fifo );
274     return NULL;
275 }