]> git.sesse.net Git - vlc/blob - src/input/input_network.c
9be288c9f2f099f515f672fb107e3c1455249564
[vlc] / src / input / input_network.c
1 /*****************************************************************************
2  * network.c: functions to read from the network
3  * Manages a socket.
4  *****************************************************************************
5  * Copyright (C) 1999, 2000 VideoLAN
6  *
7  * Authors:
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 "defs.h"
28
29 #include <sys/types.h>                        /* on BSD, uio.h needs types.h */
30 #include <sys/uio.h>                                            /* "input.h" */
31 #include <string.h>                                            /* strerror() */
32 #include <unistd.h>                                               /* close() */
33 #include <errno.h>                                                  /* errno */
34 #include <sys/time.h>                                   /* "input_network.h" */
35
36 #if defined(SYS_BSD) || defined(SYS_BEOS)
37 #include <sys/socket.h>                                   /* struct sockaddr */
38 #endif
39
40 #include <netdb.h>     /* servent, getservbyname(), hostent, gethostbyname() */
41 #include <netinet/in.h>                     /* sockaddr_in, htons(), htonl() */
42
43 #include "config.h"
44 #include "common.h"
45 #include "threads.h"
46 #include "mtime.h"
47 #include "netutils.h"
48
49 #include "input.h"
50 #include "input_network.h"
51 #include "input_vlan.h"
52
53 #include "intf_msg.h"
54 #include "main.h"
55
56 /*****************************************************************************
57  * input_NetworkOpen: initialize a network stream
58  *****************************************************************************/
59 int input_NetworkOpen( input_thread_t *p_input )
60 {
61     int                     i_socket_option;
62     struct sockaddr_in      sa_in;
63     char                    psz_hostname[INPUT_MAX_SOURCE_LENGTH];
64
65     /* First and foremost, in the VLAN method, join the desired VLAN. */
66     if( p_input->i_method == INPUT_METHOD_TS_VLAN_BCAST )
67     {
68         if( input_VlanJoin( p_input->i_vlan ) )
69         {
70             intf_ErrMsg("error: can't join vlan %d\n", p_input->i_vlan);
71             return( 1 );
72         }
73     }
74
75     /* Open a SOCK_DGRAM (UDP) socket, in the AF_INET domain, automatic (0)
76      * protocol */
77     if( (p_input->i_handle = socket( AF_INET, SOCK_DGRAM, 0 )) == (-1) )
78     {
79         intf_ErrMsg("error: can't create socket (%s)\n", strerror(errno));
80         return( 1 );
81     }
82
83     /*
84      * Set up the options of the socket
85      */
86
87     /* Set SO_REUSEADDR option which allows to re-bind() a busy port */
88     i_socket_option = 1;
89     if( setsockopt( p_input->i_handle,
90                     SOL_SOCKET,
91                     SO_REUSEADDR,
92                     &i_socket_option,
93                     sizeof( i_socket_option ) ) == (-1) )
94     {
95         intf_ErrMsg("error: can't configure socket (SO_REUSEADDR: %s)\n", strerror(errno));
96         close( p_input->i_handle );
97         return( 1 );
98     }
99
100 #ifndef SYS_BEOS
101     /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid
102      * packet loss caused by scheduling problems */
103     i_socket_option = 524288;
104     if( setsockopt( p_input->i_handle,
105                     SOL_SOCKET,
106                     SO_RCVBUF,
107                     &i_socket_option,
108                     sizeof( i_socket_option ) ) == (-1) )
109     {
110         intf_ErrMsg("error: can't configure socket (SO_RCVBUF: %s)\n", strerror(errno));
111         close( p_input->i_handle );
112         return( 1 );
113     }
114 #endif /* SYS_BEOS */
115
116     /*
117      * Bind the socket
118      */
119
120     /* Use default port if not specified */
121     if( p_input->i_port == 0 )
122     {
123         p_input->i_port = main_GetIntVariable( INPUT_PORT_VAR, INPUT_PORT_DEFAULT );
124     }
125
126     /* Find the address. */
127     switch( p_input->i_method )
128     {
129     case INPUT_METHOD_TS_BCAST:
130     case INPUT_METHOD_TS_VLAN_BCAST:
131         /* In that case, we have to bind with the broadcast address.
132          * broadcast addresses are very hard to find and depends on
133          * implementation, so we thought using a #define would be much
134          * simpler. */
135 #ifdef INPUT_BCAST_ADDR
136         if( BuildInetAddr( &sa_in, INPUT_BCAST_ADDR, p_input->i_port ) == (-1) )
137         {
138             close( p_input->i_handle );
139             return( 1 );
140         }
141 #else
142         /* We bind with any address. Security problem ! */
143         if( BuildInetAddr( &sa_in, NULL, p_input->i_port ) == (-1) )
144         {
145             close( p_input->i_handle );
146             return( -1 );
147         }
148 #endif
149         break;
150
151     case INPUT_METHOD_TS_UCAST:
152         /* Unicast: bind with the local address. */
153         if( gethostname( psz_hostname, sizeof( psz_hostname ) ) == (-1) )
154         {
155             intf_ErrMsg("error: can't get hostname (%s)\n", strerror(errno));
156             close( p_input->i_handle );
157             return( 1 );
158         }
159         if( BuildInetAddr( &sa_in, psz_hostname, p_input->i_port ) == (-1) )
160         {
161             close( p_input->i_handle );
162             return( 1 );
163         }
164         break;
165
166     case INPUT_METHOD_TS_MCAST:
167         /* Multicast: bind with 239.0.0.1. */
168         if( BuildInetAddr( &sa_in, "239.0.0.1", p_input->i_port ) == (-1) )
169         {
170             close( p_input->i_handle );
171             return( 1 );
172         }
173         break;
174     }
175
176     /* Effectively bind the socket. */
177     if( bind( p_input->i_handle, (struct sockaddr *) &sa_in, sizeof( sa_in ) ) < 0 )
178     {
179         intf_ErrMsg("error: can't bind socket (%s)\n", strerror(errno));
180         close( p_input->i_handle );
181         return( 1 );
182     }
183
184     /*
185      * Connect the socket to the remote server
186      */
187
188     /* Use default host if not specified */
189     if( p_input->p_source == NULL )
190     {
191         p_input->p_source = main_GetPszVariable( INPUT_SERVER_VAR, INPUT_SERVER_DEFAULT );
192     }
193
194     if( BuildInetAddr( &sa_in, p_input->p_source, htons(0) ) == (-1) )
195     {
196         close( p_input->i_handle );
197         return( -1 );
198     }
199
200     /* Connect the socket. */
201     if( connect( p_input->i_handle, (struct sockaddr *) &sa_in,
202                  sizeof( sa_in ) ) == (-1) )
203     {
204         intf_ErrMsg("error: can't connect socket\n" );
205         close( p_input->i_handle );
206         return( 1 );
207     }
208     return( 0 );
209 }
210
211 /*****************************************************************************
212  * input_NetworkRead: read a stream from the network
213  *****************************************************************************
214  * Wait for data during up to 1 second and then abort if none is arrived. The
215  * number of bytes read is returned or -1 if an error occurs (so 0 is returned
216  * after a timeout)
217  * We don't have to make any test on presentation times, since we suppose
218  * the network server sends us data when we need it.
219  *****************************************************************************/
220 int input_NetworkRead( input_thread_t *p_input, const struct iovec *p_vector,
221                        size_t i_count )
222 {
223     fd_set rfds;
224     struct timeval tv;
225     int i_rc;
226
227     /* Watch the given fd to see when it has input */
228     FD_ZERO(&rfds);
229     FD_SET(p_input->i_handle, &rfds);
230
231     /* Wait up to 1 second */
232     tv.tv_sec = 1;
233     tv.tv_usec = 0;
234
235     i_rc = select(p_input->i_handle+1, &rfds, NULL, NULL, &tv);
236
237     if( i_rc > 0 )
238     {
239         /* Data were received before timeout */
240         i_rc = readv( p_input->i_handle, p_vector, i_count );
241     }
242
243     return( i_rc );
244 }
245
246 /*****************************************************************************
247  * input_NetworkClose: close a network stream
248  *****************************************************************************/
249 void input_NetworkClose( input_thread_t *p_input )
250 {
251     /* Close local socket. */
252     if( p_input->i_handle )
253     {
254         close( p_input->i_handle );
255     }
256
257     /* Leave vlan if required */
258     if( p_input->i_method == INPUT_METHOD_TS_VLAN_BCAST )
259     {
260         input_VlanLeave( p_input->i_vlan );
261     }
262 }
263