]> git.sesse.net Git - vlc/blob - src/misc/net.c
* src/misc/net.c: Compilation fix.
[vlc] / src / misc / net.c
1 /*****************************************************************************
2  * net.c:
3  *****************************************************************************
4  * Copyright (C) 2004 VideoLAN
5  * $Id: net.c,v 1.8 2004/01/22 17:03:44 gbazin Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@videolan.org>
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 <vlc/vlc.h>
29
30 #ifdef HAVE_ERRNO_H
31 #   include <errno.h>
32 #endif
33
34 #ifdef HAVE_FCNTL_H
35 #   include <fcntl.h>
36 #endif
37
38 #ifdef HAVE_SYS_TIME_H
39 #    include <sys/time.h>
40 #endif
41
42 #if defined( UNDER_CE )
43 #   include <winsock.h>
44 #elif defined( 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 #ifdef HAVE_UNISTD_H
55 #   include <unistd.h>
56 #endif
57
58 #include "network.h"
59
60
61 /*****************************************************************************
62  * __net_OpenTCP:
63  *****************************************************************************
64  * Open a TCP connection and return a handle
65  *****************************************************************************/
66 int __net_OpenTCP( vlc_object_t *p_this, char *psz_host, int i_port )
67 {
68     vlc_value_t      val;
69     void            *private;
70
71     char            *psz_network = "";
72     network_socket_t sock;
73     module_t         *p_network;
74
75
76     /* Check if we have force ipv4 or ipv6 */
77     var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
78     var_Get( p_this, "ipv4", &val );
79     if( val.b_bool )
80     {
81         psz_network = "ipv4";
82     }
83
84     var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
85     var_Get( p_this, "ipv6", &val );
86     if( val.b_bool )
87     {
88         psz_network = "ipv6";
89     }
90
91     /* Prepare the network_socket_t structure */
92     sock.i_type = NETWORK_TCP;
93     sock.psz_bind_addr   = "";
94     sock.i_bind_port     = 0;
95     sock.psz_server_addr = psz_host;
96     sock.i_server_port   = i_port;
97     sock.i_ttl           = 0;
98
99     msg_Dbg( p_this, "net: connecting to '%s:%d'", psz_host, i_port );
100     private = p_this->p_private;
101     p_this->p_private = (void*)&sock;
102     if( ( p_network = module_Need( p_this, "network", psz_network ) ) == NULL )
103     {
104         msg_Dbg( p_this, "net: connection to '%s:%d' failed", psz_host, i_port );
105         return -1;
106     }
107     module_Unneed( p_this, p_network );
108     p_this->p_private = private;
109
110     return sock.i_handle;
111 }
112
113 /*****************************************************************************
114  * __net_OpenUDP:
115  *****************************************************************************
116  * Open a UDP connection and return a handle
117  *****************************************************************************/
118 int __net_OpenUDP( vlc_object_t *p_this, char *psz_bind, int i_bind,
119                    char *psz_server, int i_server )
120 {
121     vlc_value_t      val;
122     void            *private;
123
124     char            *psz_network = "";
125     network_socket_t sock;
126     module_t         *p_network;
127
128
129     /* Check if we have force ipv4 or ipv6 */
130     var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
131     var_Get( p_this, "ipv4", &val );
132     if( val.b_bool )
133     {
134         psz_network = "ipv4";
135     }
136
137     var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
138     var_Get( p_this, "ipv6", &val );
139     if( val.b_bool )
140     {
141         psz_network = "ipv6";
142     }
143     if( psz_server == NULL ) psz_server = "";
144     if( psz_bind   == NULL ) psz_bind   = "";
145
146     /* Prepare the network_socket_t structure */
147     sock.i_type = NETWORK_UDP;
148     sock.psz_bind_addr   = psz_bind;
149     sock.i_bind_port     = i_bind;
150     sock.psz_server_addr = psz_server;
151     sock.i_server_port   = i_server;
152     sock.i_ttl           = 0;
153
154     msg_Dbg( p_this, "net: connecting to '%s:%d@%s:%d'",
155              psz_server, i_server, psz_bind, i_bind );
156     private = p_this->p_private;
157     p_this->p_private = (void*)&sock;
158     if( ( p_network = module_Need( p_this, "network", psz_network ) ) == NULL )
159     {
160         msg_Dbg( p_this, "net: connection to '%s:%d@%s:%d' failed",
161                  psz_server, i_server, psz_bind, i_bind );
162         return -1;
163     }
164     module_Unneed( p_this, p_network );
165     p_this->p_private = private;
166
167     return sock.i_handle;
168 }
169
170 /*****************************************************************************
171  * __net_Close:
172  *****************************************************************************
173  * Close a network handle
174  *****************************************************************************/
175 void net_Close( int fd )
176 {
177 #ifdef UNDER_CE
178     CloseHandle( (HANDLE)fd );
179 #elif defined( WIN32 )
180     closesocket( fd );
181 #else
182     close( fd );
183 #endif
184 }
185
186 /*****************************************************************************
187  * __net_Read:
188  *****************************************************************************
189  * Read from a network socket
190  * If b_rety is true, then we repeat until we have read the right amount of
191  * data
192  *****************************************************************************/
193 int __net_Read( vlc_object_t *p_this, int fd, uint8_t *p_data, int i_data,
194                 vlc_bool_t b_retry )
195 {
196     struct timeval  timeout;
197     fd_set          fds;
198     int             i_recv;
199     int             i_total = 0;
200     int             i_ret;
201     vlc_bool_t      b_die = p_this->b_die;
202
203     while( i_data > 0 )
204     {
205         do
206         {
207             if( p_this->b_die != b_die )
208             {
209                 return 0;
210             }
211
212             /* Initialize file descriptor set */
213             FD_ZERO( &fds );
214             FD_SET( fd, &fds );
215
216             /* We'll wait 0.5 second if nothing happens */
217             timeout.tv_sec = 0;
218             timeout.tv_usec = 500000;
219         } while( ( i_ret = select( fd + 1, &fds, NULL, NULL, &timeout )) == 0 ||
220                  ( i_ret < 0 && errno == EINTR ) );
221
222         if( i_ret < 0 )
223         {
224             msg_Err( p_this, "network select error (%s)", strerror(errno) );
225             return i_total > 0 ? i_total : -1;
226         }
227
228         if( ( i_recv = recv( fd, p_data, i_data, 0 ) ) < 0 )
229         {
230 #ifdef WIN32
231             /* For udp only */
232             /* On win32 recv() will fail if the datagram doesn't fit inside
233              * the passed buffer, even though the buffer will be filled with
234              * the first part of the datagram. */
235             if( WSAGetLastError() == WSAEMSGSIZE ) 
236             {
237                 msg_Err( p_this, "recv() failed. "
238                          "Increase the mtu size (--mtu option)" );
239                 i_recv = i_data;
240             }
241             else
242 #endif
243             msg_Err( p_this, "recv failed (%s)", strerror(errno) );
244             return i_total > 0 ? i_total : -1;
245         }
246
247         p_data += i_recv;
248         i_data -= i_recv;
249         i_total+= i_recv;
250         if( !b_retry )
251         {
252             break;
253         }
254     }
255     return i_total;
256 }
257
258 /* Write exact amount requested */
259 int __net_Write( vlc_object_t *p_this, int fd, uint8_t *p_data, int i_data )
260 {
261     struct timeval  timeout;
262     fd_set          fds;
263     int             i_send;
264     int             i_total = 0;
265     int             i_ret;
266
267     vlc_bool_t      b_die = p_this->b_die;
268
269     while( i_data > 0 )
270     {
271         do
272         {
273             if( p_this->b_die != b_die )
274             {
275                 return 0;
276             }
277
278             /* Initialize file descriptor set */
279             FD_ZERO( &fds );
280             FD_SET( fd, &fds );
281
282             /* We'll wait 0.5 second if nothing happens */
283             timeout.tv_sec = 0;
284             timeout.tv_usec = 500000;
285         } while( ( i_ret = select( fd + 1, NULL, &fds, NULL, &timeout )) == 0 ||
286                  ( i_ret < 0 && errno == EINTR ) );
287
288         if( i_ret < 0 )
289         {
290             msg_Err( p_this, "network select error (%s)", strerror(errno) );
291             return i_total > 0 ? i_total : -1;
292         }
293
294         if( ( i_send = send( fd, p_data, i_data, 0 ) ) < 0 )
295         {
296             /* XXX With udp for example, it will issue a message if the host
297              * isn't listening */
298             /* msg_Err( p_this, "send failed (%s)", strerror(errno) ); */
299             return i_total > 0 ? i_total : -1;
300         }
301
302         p_data += i_send;
303         i_data -= i_send;
304         i_total+= i_send;
305     }
306     return i_total;
307 }
308
309 char *__net_Gets( vlc_object_t *p_this, int fd )
310 {
311     char *psz_line = malloc( 1024 );
312     int  i_line = 0;
313     int  i_max = 1024;
314
315
316     for( ;; )
317     {
318         if( net_Read( p_this, fd, &psz_line[i_line], 1, VLC_TRUE ) != 1 )
319         {
320             psz_line[i_line] = '\0';
321             break;
322         }
323         i_line++;
324
325         if( psz_line[i_line-1] == '\n' )
326         {
327             psz_line[i_line] = '\0';
328             break;
329         }
330
331         if( i_line >= i_max - 1 )
332         {
333             i_max += 1024;
334             psz_line = realloc( psz_line, i_max );
335         }
336     }
337
338     if( i_line <= 0 )
339     {
340         free( psz_line );
341         return NULL;
342     }
343
344     while( i_line >= 1 &&
345            ( psz_line[i_line-1] == '\n' || psz_line[i_line-1] == '\r' ) )
346     {
347         i_line--;
348         psz_line[i_line] = '\0';
349     }
350     return psz_line;
351 }
352
353 int net_Printf( vlc_object_t *p_this, int fd, char *psz_fmt, ... )
354 {
355     va_list args;
356     char    *psz;
357     int     i_size, i_ret;
358
359     va_start( args, psz_fmt );
360     vasprintf( &psz, psz_fmt, args );
361     va_end( args );
362
363     i_size = strlen( psz );
364
365     i_ret = __net_Write( p_this, fd, psz, i_size ) < i_size ? -1 : i_size;
366     free( psz );
367
368     return i_ret;
369 }