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