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