]> git.sesse.net Git - vlc/blob - modules/access/udp.c
* ALL: the build mechanism now uses automake. See HACKING for more details.
[vlc] / modules / access / udp.c
1 /*****************************************************************************
2  * udp.c: raw UDP access plug-in
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  * $Id: udp.c,v 1.3 2002/09/30 11:05:34 sam Exp $
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *
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.
13  * 
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <fcntl.h>
33
34 #include <vlc/vlc.h>
35 #include <vlc/input.h>
36
37 #ifdef HAVE_UNISTD_H
38 #   include <unistd.h>
39 #elif defined( _MSC_VER ) && defined( _WIN32 )
40 #   include <io.h>
41 #endif
42
43 #include "network.h"
44
45 /*****************************************************************************
46  * Local prototypes
47  *****************************************************************************/
48 static int  Open       ( vlc_object_t * );
49
50 /*****************************************************************************
51  * Module descriptor
52  *****************************************************************************/
53 vlc_module_begin();
54     set_description( _("raw UDP access module") );
55     set_capability( "access", 0 );
56     add_shortcut( "udp" );
57     add_shortcut( "udpstream" );
58     add_shortcut( "udp4" );
59     add_shortcut( "udp6" );
60     set_callbacks( Open, __input_FDNetworkClose );
61 vlc_module_end();
62
63 /*****************************************************************************
64  * Open: open the socket
65  *****************************************************************************/
66 static int Open( vlc_object_t *p_this )
67 {
68     input_thread_t *    p_input = (input_thread_t *)p_this;
69     input_socket_t *    p_access_data;
70     module_t *          p_network;
71     char *              psz_network = "";
72     char *              psz_name = strdup(p_input->psz_name);
73     char *              psz_parser = psz_name;
74     char *              psz_server_addr = "";
75     char *              psz_server_port = "";
76     char *              psz_bind_addr = "";
77     char *              psz_bind_port = "";
78     int                 i_bind_port = 0, i_server_port = 0;
79     network_socket_t    socket_desc;
80
81     if( config_GetInt( p_input, "ipv4" ) )
82     {
83         psz_network = "ipv4";
84     }
85     if( config_GetInt( p_input, "ipv6" ) )
86     {
87         psz_network = "ipv6";
88     }
89
90     if( *p_input->psz_access )
91     {
92         /* Find out which shortcut was used */
93         if( !strncmp( p_input->psz_access, "udp6", 5 ) )
94         {
95             psz_network = "ipv6";
96         }
97         else if( !strncmp( p_input->psz_access, "udp4", 5 ) )
98         {
99             psz_network = "ipv4";
100         }
101     }
102
103     /* Parse psz_name syntax :
104      * [serveraddr[:serverport]][@[bindaddr]:[bindport]] */
105
106     if( *psz_parser && *psz_parser != '@' )
107     {
108         /* Found server */
109         psz_server_addr = psz_parser;
110
111         while( *psz_parser && *psz_parser != ':' && *psz_parser != '@' )
112         {
113             if( *psz_parser == '[' )
114             {
115                 /* IPv6 address */
116                 while( *psz_parser && *psz_parser != ']' )
117                 {
118                     psz_parser++;
119                 }
120             }
121             psz_parser++;
122         }
123
124         if( *psz_parser == ':' )
125         {
126             /* Found server port */
127             *psz_parser = '\0'; /* Terminate server name */
128             psz_parser++;
129             psz_server_port = psz_parser;
130
131             while( *psz_parser && *psz_parser != '@' )
132             {
133                 psz_parser++;
134             }
135         }
136     }
137
138     if( *psz_parser == '@' )
139     {
140         /* Found bind address or bind port */
141         *psz_parser = '\0'; /* Terminate server port or name if necessary */
142         psz_parser++;
143
144         if( *psz_parser && *psz_parser != ':' )
145         {
146             /* Found bind address */
147             psz_bind_addr = psz_parser;
148
149             while( *psz_parser && *psz_parser != ':' )
150             {
151                 if( *psz_parser == '[' )
152                 {
153                     /* IPv6 address */
154                     while( *psz_parser && *psz_parser != ']' )
155                     {
156                         psz_parser++;
157                     }
158                 }
159                 psz_parser++;
160             }
161         }
162
163         if( *psz_parser == ':' )
164         {
165             /* Found bind port */
166             *psz_parser = '\0'; /* Terminate bind address if necessary */
167             psz_parser++;
168
169             psz_bind_port = psz_parser;
170         }
171     }
172
173     /* Convert ports format */
174     if( *psz_server_port )
175     {
176         i_server_port = strtol( psz_server_port, &psz_parser, 10 );
177         if( *psz_parser )
178         {
179             msg_Err( p_input, "cannot parse server port near %s", psz_parser );
180             free(psz_name);
181             return( -1 );
182         }
183     }
184
185     if( *psz_bind_port )
186     {
187         i_bind_port = strtol( psz_bind_port, &psz_parser, 10 );
188         if( *psz_parser )
189         {
190             msg_Err( p_input, "cannot parse bind port near %s", psz_parser );
191             free(psz_name);
192             return( -1 );
193         }
194     }
195
196     p_input->pf_read = input_FDNetworkRead;
197     p_input->pf_set_program = input_SetProgram;
198     p_input->pf_set_area = NULL;
199     p_input->pf_seek = NULL;
200
201     vlc_mutex_lock( &p_input->stream.stream_lock );
202     p_input->stream.b_pace_control = 0;
203     p_input->stream.b_seekable = 0;
204     p_input->stream.p_selected_area->i_tell = 0;
205     p_input->stream.i_method = INPUT_METHOD_NETWORK;
206     vlc_mutex_unlock( &p_input->stream.stream_lock );
207
208     if( *psz_server_addr || i_server_port )
209     {
210         msg_Err( p_input, "this UDP syntax is deprecated; the server argument will be");
211         msg_Err( p_input, "ignored (%s:%d). If you wanted to enter a multicast address",
212                           psz_server_addr, i_server_port);
213         msg_Err( p_input, "or local port, type : %s:@%s:%d",
214                           *p_input->psz_access ? p_input->psz_access : "udp",
215                           psz_server_addr, i_server_port );
216
217         i_server_port = 0;
218         psz_server_addr = "";
219     }
220  
221     msg_Dbg( p_input, "opening server=%s:%d local=%s:%d",
222              psz_server_addr, i_server_port, psz_bind_addr, i_bind_port );
223
224     /* Prepare the network_socket_t structure */
225     socket_desc.i_type = NETWORK_UDP;
226     socket_desc.psz_bind_addr = psz_bind_addr;
227     socket_desc.i_bind_port = i_bind_port;
228     socket_desc.psz_server_addr = psz_server_addr;
229     socket_desc.i_server_port = i_server_port;
230
231     /* Find an appropriate network module */
232     p_input->p_private = (void*) &socket_desc;
233     p_network = module_Need( p_input, "network", psz_network );
234     free(psz_name);
235     if( p_network == NULL )
236     {
237         return( -1 );
238     }
239     module_Unneed( p_input, p_network );
240     
241     p_access_data = malloc( sizeof(input_socket_t) );
242     p_input->p_access_data = (access_sys_t *)p_access_data;
243
244     if( p_access_data == NULL )
245     {
246         msg_Err( p_input, "out of memory" );
247         return( -1 );
248     }
249
250     p_access_data->i_handle = socket_desc.i_handle;
251     p_input->i_mtu = socket_desc.i_mtu;
252
253     return( 0 );
254 }