]> git.sesse.net Git - vlc/blob - modules/access/tcp.c
* modules/misc/dummy/renderer.c:
[vlc] / modules / access / tcp.c
1 /*****************************************************************************
2  * tcp.c: TCP access plug-in
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id: tcp.c,v 1.2 2003/12/04 16:49:43 sam Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@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
29 #include <vlc/vlc.h>
30 #include <vlc/input.h>
31
32 #include <sys/stat.h>
33 #include <errno.h>
34 #include <fcntl.h>
35
36 #ifdef HAVE_SYS_TIME_H
37 #    include <sys/time.h>
38 #endif
39
40 #ifdef HAVE_UNISTD_H
41 #   include <unistd.h>
42 #endif
43
44 #ifdef WIN32
45 #   include <winsock2.h>
46 #   include <ws2tcpip.h>
47 #   ifndef IN_MULTICAST
48 #       define IN_MULTICAST(a) IN_CLASSD(a)
49 #   endif
50 #else
51 #   include <sys/socket.h>
52 #endif
53
54 #include "network.h"
55
56 /*****************************************************************************
57  * Module descriptor
58  *****************************************************************************/
59 #define CACHING_TEXT N_("caching value in ms")
60 #define CACHING_LONGTEXT N_( \
61     "Allows you to modify the default caching value for udp streams. This " \
62     "value should be set in miliseconds units." )
63
64 static int  Open ( vlc_object_t * );
65 static void Close( vlc_object_t * );
66
67 vlc_module_begin();
68     set_description( _("TCP input") );
69     add_category_hint( N_("TCP"), NULL , VLC_TRUE );
70     add_integer( "tcp-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
71     set_capability( "access", 0 );
72     add_shortcut( "tcp" );
73     add_shortcut( "tcp4" );
74     add_shortcut( "tcp6" );
75     set_callbacks( Open, Close );
76 vlc_module_end();
77
78
79 /*****************************************************************************
80  * Local prototypes
81  *****************************************************************************/
82 struct access_sys_t
83 {
84     int fd;
85 };
86
87 static ssize_t  Read ( input_thread_t *, byte_t *, size_t );
88
89 /*****************************************************************************
90  * Open: open the socket
91  *****************************************************************************/
92 static int Open( vlc_object_t *p_this )
93 {
94     input_thread_t *p_input = (input_thread_t *)p_this;
95     access_sys_t   *p_sys;
96
97     char           *psz_network;
98     char           *psz_dup = strdup(p_input->psz_name);
99     char           *psz_parser = psz_dup;
100
101     network_socket_t sock;
102     module_t         *p_network;
103
104     vlc_value_t     val;
105
106     /* Select ip version */
107     psz_network = "";
108     if( config_GetInt( p_input, "ipv4" ) )
109     {
110         psz_network = "ipv4";
111     }
112     if( config_GetInt( p_input, "ipv6" ) )
113     {
114         psz_network = "ipv6";
115     }
116     if( *p_input->psz_access )
117     {
118         /* Find out which shortcut was used */
119         if( !strncmp( p_input->psz_access, "tcp6", 5 ) )
120         {
121             psz_network = "ipv6";
122         }
123         else if( !strncmp( p_input->psz_access, "tcp4", 5 ) )
124         {
125             psz_network = "ipv4";
126         }
127     }
128
129     /* Parse server:port */
130     while( *psz_parser && *psz_parser != ':' )
131     {
132         if( *psz_parser == '[' )
133         {
134             /* IPV6 */
135             while( *psz_parser && *psz_parser  != ']' )
136             {
137                 psz_parser++;
138             }
139         }
140         psz_parser++;
141     }
142
143     if( *psz_parser != ':' || psz_parser == psz_dup )
144     {
145         msg_Err( p_input, "you have to provide server:port addresse" );
146         free( psz_dup );
147         return VLC_EGENERIC;
148     }
149
150     *psz_parser++ = '\0';
151
152     /* Prepare the network_socket_t structure */
153     sock.i_type = NETWORK_TCP;
154     sock.psz_bind_addr = "";
155     sock.i_bind_port = 0;
156     sock.psz_server_addr = psz_dup;
157     sock.i_server_port = atoi( psz_parser );
158     sock.i_ttl           = 0;
159
160     if( sock.i_server_port <= 0 )
161     {
162         msg_Err( p_input, "invalid port number (%d)", sock.i_server_port );
163         free( psz_dup );
164         return VLC_EGENERIC;
165     }
166
167     /* connecting */
168     msg_Dbg( p_input, "opening server=%s:%d",
169              sock.psz_server_addr, sock.i_server_port );
170     p_input->p_private = (void*)&sock;
171     p_network = module_Need( p_input, "network", psz_network );
172     free( psz_dup );
173     if( p_network == NULL )
174     {
175         return VLC_EGENERIC;
176     }
177     module_Unneed( p_input, p_network );
178
179     p_input->p_access_data = p_sys = malloc( sizeof( access_sys_t ) );
180     p_sys->fd = sock.i_handle;
181
182     p_input->pf_read = Read;
183     p_input->pf_set_program = input_SetProgram;
184     p_input->pf_set_area = NULL;
185     p_input->pf_seek = NULL;
186
187     vlc_mutex_lock( &p_input->stream.stream_lock );
188     p_input->stream.b_pace_control = VLC_TRUE;  /* FIXME ? */
189     p_input->stream.b_seekable = 0;
190     p_input->stream.p_selected_area->i_tell = 0;
191     p_input->stream.i_method = INPUT_METHOD_NETWORK;
192     p_input->i_mtu = 0;
193     vlc_mutex_unlock( &p_input->stream.stream_lock );
194
195     /* Update default_pts to a suitable value for udp access */
196     var_Create( p_input, "tcp-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
197     var_Get( p_input, "tcp-caching", &val );
198     p_input->i_pts_delay = val.i_int * 1000;
199
200     return VLC_SUCCESS;
201 }
202
203 /*****************************************************************************
204  * Close: free unused data structures
205  *****************************************************************************/
206 static void Close( vlc_object_t *p_this )
207 {
208     input_thread_t *p_input = (input_thread_t *)p_this;
209     access_sys_t   *p_sys = p_input->p_access_data;
210
211     msg_Info( p_input, "closing TCP target `%s'", p_input->psz_source );
212
213 #ifdef UNDER_CE
214     CloseHandle( (HANDLE)p_sys->fd );
215 #elif defined( WIN32 )
216     closesocket( p_sys->fd );
217 #else
218     close( p_sys->fd );
219 #endif
220
221     free( p_sys );
222 }
223
224 /*****************************************************************************
225  * Read: read on a file descriptor, checking b_die periodically
226  *****************************************************************************/
227 static ssize_t Read( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
228 {
229 #ifdef UNDER_CE
230     return -1;
231 #else
232     access_sys_t   *p_sys = p_input->p_access_data;
233     struct timeval  timeout;
234     fd_set          fds;
235     ssize_t         i_recv;
236     int             i_ret;
237
238     do
239     {
240         if( p_input->b_die || p_input->b_error )
241         {
242             return 0;
243         }
244
245         /* Initialize file descriptor set */
246         FD_ZERO( &fds );
247         FD_SET( p_sys->fd, &fds );
248
249         /* We'll wait 0.5 second if nothing happens */
250         timeout.tv_sec = 0;
251         timeout.tv_usec = 500000;
252     } while( ( i_ret = select( p_sys->fd + 1, &fds, NULL, NULL, &timeout )) == 0 ||
253              ( i_ret < 0 && errno == EINTR ) );
254
255     if( i_ret < 0 )
256     {
257         msg_Err( p_input, "network select error (%s)", strerror(errno) );
258         return -1;
259     }
260
261     if( ( i_recv = recv( p_sys->fd, p_buffer, i_len, 0 ) ) < 0 )
262     {
263         msg_Err( p_input, "recv failed (%s)", strerror(errno) );
264     }
265     return i_recv;
266 #endif
267 }
268