1 /*****************************************************************************
2 * udp.c: raw UDP access plug-in
3 *****************************************************************************
4 * Copyright (C) 2001, 2002 VideoLAN
5 * $Id: udp.c,v 1.5 2002/12/11 20:13:50 fenrir Exp $
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
28 #include <sys/types.h>
35 #include <vlc/input.h>
39 #elif defined( _MSC_VER ) && defined( _WIN32 )
44 # include <winsock2.h>
45 # include <ws2tcpip.h>
47 # define IN_MULTICAST(a) IN_CLASSD(a)
50 # include <sys/socket.h>
55 /*****************************************************************************
57 *****************************************************************************/
58 static int Open ( vlc_object_t * );
59 static void Close ( vlc_object_t * );
60 static ssize_t Read ( input_thread_t *, byte_t *, size_t );
62 /*****************************************************************************
64 *****************************************************************************/
66 set_description( _("raw UDP access module") );
67 set_capability( "access", 0 );
68 add_shortcut( "udp" );
69 add_shortcut( "udpstream" );
70 add_shortcut( "udp4" );
71 add_shortcut( "udp6" );
72 set_callbacks( Open, Close );
75 /*****************************************************************************
76 * Open: open the socket
77 *****************************************************************************/
78 static int Open( vlc_object_t *p_this )
80 input_thread_t * p_input = (input_thread_t *)p_this;
81 input_socket_t * p_access_data;
83 char * psz_network = "";
84 char * psz_name = strdup(p_input->psz_name);
85 char * psz_parser = psz_name;
86 char * psz_server_addr = "";
87 char * psz_server_port = "";
88 char * psz_bind_addr = "";
89 char * psz_bind_port = "";
90 int i_bind_port = 0, i_server_port = 0;
91 network_socket_t socket_desc;
93 if( config_GetInt( p_input, "ipv4" ) )
97 if( config_GetInt( p_input, "ipv6" ) )
102 if( *p_input->psz_access )
104 /* Find out which shortcut was used */
105 if( !strncmp( p_input->psz_access, "udp6", 5 ) )
107 psz_network = "ipv6";
109 else if( !strncmp( p_input->psz_access, "udp4", 5 ) )
111 psz_network = "ipv4";
115 /* Parse psz_name syntax :
116 * [serveraddr[:serverport]][@[bindaddr]:[bindport]] */
118 if( *psz_parser && *psz_parser != '@' )
121 psz_server_addr = psz_parser;
123 while( *psz_parser && *psz_parser != ':' && *psz_parser != '@' )
125 if( *psz_parser == '[' )
128 while( *psz_parser && *psz_parser != ']' )
136 if( *psz_parser == ':' )
138 /* Found server port */
139 *psz_parser = '\0'; /* Terminate server name */
141 psz_server_port = psz_parser;
143 while( *psz_parser && *psz_parser != '@' )
150 if( *psz_parser == '@' )
152 /* Found bind address or bind port */
153 *psz_parser = '\0'; /* Terminate server port or name if necessary */
156 if( *psz_parser && *psz_parser != ':' )
158 /* Found bind address */
159 psz_bind_addr = psz_parser;
161 while( *psz_parser && *psz_parser != ':' )
163 if( *psz_parser == '[' )
166 while( *psz_parser && *psz_parser != ']' )
175 if( *psz_parser == ':' )
177 /* Found bind port */
178 *psz_parser = '\0'; /* Terminate bind address if necessary */
181 psz_bind_port = psz_parser;
185 /* Convert ports format */
186 if( *psz_server_port )
188 i_server_port = strtol( psz_server_port, &psz_parser, 10 );
191 msg_Err( p_input, "cannot parse server port near %s", psz_parser );
199 i_bind_port = strtol( psz_bind_port, &psz_parser, 10 );
202 msg_Err( p_input, "cannot parse bind port near %s", psz_parser );
208 p_input->pf_read = Read;
209 p_input->pf_set_program = input_SetProgram;
210 p_input->pf_set_area = NULL;
211 p_input->pf_seek = NULL;
213 vlc_mutex_lock( &p_input->stream.stream_lock );
214 p_input->stream.b_pace_control = 0;
215 p_input->stream.b_seekable = 0;
216 p_input->stream.p_selected_area->i_tell = 0;
217 p_input->stream.i_method = INPUT_METHOD_NETWORK;
218 vlc_mutex_unlock( &p_input->stream.stream_lock );
220 if( *psz_server_addr || i_server_port )
222 msg_Err( p_input, "this UDP syntax is deprecated; the server argument will be");
223 msg_Err( p_input, "ignored (%s:%d). If you wanted to enter a multicast address",
224 psz_server_addr, i_server_port);
225 msg_Err( p_input, "or local port, type : %s:@%s:%d",
226 *p_input->psz_access ? p_input->psz_access : "udp",
227 psz_server_addr, i_server_port );
230 psz_server_addr = "";
233 msg_Dbg( p_input, "opening server=%s:%d local=%s:%d",
234 psz_server_addr, i_server_port, psz_bind_addr, i_bind_port );
236 /* Prepare the network_socket_t structure */
237 socket_desc.i_type = NETWORK_UDP;
238 socket_desc.psz_bind_addr = psz_bind_addr;
239 socket_desc.i_bind_port = i_bind_port;
240 socket_desc.psz_server_addr = psz_server_addr;
241 socket_desc.i_server_port = i_server_port;
243 /* Find an appropriate network module */
244 p_input->p_private = (void*) &socket_desc;
245 p_network = module_Need( p_input, "network", psz_network );
247 if( p_network == NULL )
251 module_Unneed( p_input, p_network );
253 p_access_data = malloc( sizeof(input_socket_t) );
254 p_input->p_access_data = (access_sys_t *)p_access_data;
256 if( p_access_data == NULL )
258 msg_Err( p_input, "out of memory" );
262 p_access_data->i_handle = socket_desc.i_handle;
263 p_input->i_mtu = socket_desc.i_mtu;
268 /*****************************************************************************
269 * Close: free unused data structures
270 *****************************************************************************/
271 static void Close( vlc_object_t *p_this )
273 input_thread_t * p_input = (input_thread_t *)p_this;
274 input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
276 msg_Info( p_input, "closing UDP target `%s'", p_input->psz_source );
279 CloseHandle( (HANDLE)p_access_data->i_handle );
280 #elif defined( WIN32 )
281 closesocket( p_access_data->i_handle );
283 close( p_access_data->i_handle );
286 free( p_access_data );
289 /*****************************************************************************
290 * Read: read on a file descriptor, checking b_die periodically
291 *****************************************************************************/
292 static ssize_t Read( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
298 input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
299 struct timeval timeout;
303 /* Initialize file descriptor set */
305 FD_SET( p_access_data->i_handle, &fds );
307 /* We'll wait 0.5 second if nothing happens */
309 timeout.tv_usec = 500000;
311 /* Find if some data is available */
312 i_ret = select( p_access_data->i_handle + 1, &fds,
313 NULL, NULL, &timeout );
315 if( i_ret == -1 && errno != EINTR )
317 msg_Err( p_input, "network select error (%s)", strerror(errno) );
321 ssize_t i_recv = recv( p_access_data->i_handle, p_buffer, i_len, 0 );
325 msg_Err( p_input, "recv failed (%s)", strerror(errno) );