1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2004 VideoLAN
7 * Authors: Laurent Aimar <fenrir@videolan.org>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
36 #ifdef HAVE_SYS_TIME_H
37 # include <sys/time.h>
40 #if defined( UNDER_CE )
42 #elif defined( WIN32 )
43 # include <winsock2.h>
44 # include <ws2tcpip.h>
46 # define IN_MULTICAST(a) IN_CLASSD(a)
49 # include <sys/socket.h>
54 #elif defined( WIN32 ) && !defined( UNDER_CE )
60 /*****************************************************************************
62 *****************************************************************************
63 * Open a TCP connection and return a handle
64 *****************************************************************************/
65 int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
70 char *psz_network = "";
71 network_socket_t sock;
74 /* Check if we have force ipv4 or ipv6 */
75 var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
76 var_Get( p_this, "ipv4", &val );
82 var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
83 var_Get( p_this, "ipv6", &val );
89 /* Prepare the network_socket_t structure */
90 sock.i_type = NETWORK_TCP;
91 sock.psz_bind_addr = "";
93 sock.psz_server_addr = psz_host;
94 sock.i_server_port = i_port;
97 msg_Dbg( p_this, "net: connecting to '%s:%d'", psz_host, i_port );
98 private = p_this->p_private;
99 p_this->p_private = (void*)&sock;
100 if( !( p_network = module_Need( p_this, "network", psz_network, 0 ) ) )
102 msg_Dbg( p_this, "net: connection to '%s:%d' failed",
106 module_Unneed( p_this, p_network );
107 p_this->p_private = private;
109 return sock.i_handle;
112 /*****************************************************************************
114 *****************************************************************************
115 * Open a TCP listening socket and return it
116 *****************************************************************************/
117 int __net_ListenTCP( vlc_object_t *p_this, char *psz_host, int i_port )
122 char *psz_network = "";
123 network_socket_t sock;
126 /* Check if we have force ipv4 or ipv6 */
127 var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
128 var_Get( p_this, "ipv4", &val );
131 psz_network = "ipv4";
134 var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
135 var_Get( p_this, "ipv6", &val );
138 psz_network = "ipv6";
141 /* Prepare the network_socket_t structure */
142 sock.i_type = NETWORK_TCP_PASSIVE;
143 sock.psz_bind_addr = "";
144 sock.i_bind_port = 0;
145 sock.psz_server_addr = psz_host;
146 sock.i_server_port = i_port;
149 msg_Dbg( p_this, "net: listening to '%s:%d'", psz_host, i_port );
150 private = p_this->p_private;
151 p_this->p_private = (void*)&sock;
152 if( !( p_network = module_Need( p_this, "network", psz_network, 0 ) ) )
154 msg_Dbg( p_this, "net: listening to '%s:%d' failed",
158 module_Unneed( p_this, p_network );
159 p_this->p_private = private;
161 return sock.i_handle;
164 /*****************************************************************************
166 *****************************************************************************
167 * Accept a connection on a listening socket and return it
168 *****************************************************************************/
169 int __net_Accept( vlc_object_t *p_this, int fd, mtime_t i_wait )
171 vlc_bool_t b_die = p_this->b_die, b_block = (i_wait < 0);
172 struct timeval timeout;
176 while( p_this->b_die == b_die )
178 /* Initialize file descriptor set */
180 FD_SET( fd, &fds_r );
182 FD_SET( fd, &fds_e );
185 timeout.tv_usec = b_block ? 500000 : i_wait;
187 i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout);
188 if( (i_ret < 0 && errno == EINTR) || i_ret == 0 )
190 if( b_block ) continue;
195 #if defined(WIN32) || defined(UNDER_CE)
196 msg_Err( p_this, "network select error (%i)", WSAGetLastError() );
198 msg_Err( p_this, "network select error (%s)", strerror(errno) );
203 if( ( i_ret = accept( fd, 0, 0 ) ) <= 0 )
205 #if defined(WIN32) || defined(UNDER_CE)
206 msg_Err( p_this, "accept failed (%i)", WSAGetLastError() );
208 msg_Err( p_this, "accept failed (%s)", strerror(errno) );
219 /*****************************************************************************
221 *****************************************************************************
222 * Open a UDP connection and return a handle
223 *****************************************************************************/
224 int __net_OpenUDP( vlc_object_t *p_this, char *psz_bind, int i_bind,
225 char *psz_server, int i_server )
230 char *psz_network = "";
231 network_socket_t sock;
235 /* Check if we have force ipv4 or ipv6 */
236 var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
237 var_Get( p_this, "ipv4", &val );
240 psz_network = "ipv4";
243 var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
244 var_Get( p_this, "ipv6", &val );
247 psz_network = "ipv6";
249 if( psz_server == NULL ) psz_server = "";
250 if( psz_bind == NULL ) psz_bind = "";
252 /* Prepare the network_socket_t structure */
253 sock.i_type = NETWORK_UDP;
254 sock.psz_bind_addr = psz_bind;
255 sock.i_bind_port = i_bind;
256 sock.psz_server_addr = psz_server;
257 sock.i_server_port = i_server;
260 msg_Dbg( p_this, "net: connecting to '%s:%d@%s:%d'",
261 psz_server, i_server, psz_bind, i_bind );
262 private = p_this->p_private;
263 p_this->p_private = (void*)&sock;
264 if( !( p_network = module_Need( p_this, "network", psz_network, 0 ) ) )
266 msg_Dbg( p_this, "net: connection to '%s:%d@%s:%d' failed",
267 psz_server, i_server, psz_bind, i_bind );
270 module_Unneed( p_this, p_network );
271 p_this->p_private = private;
273 return sock.i_handle;
276 /*****************************************************************************
278 *****************************************************************************
279 * Close a network handle
280 *****************************************************************************/
281 void net_Close( int fd )
284 CloseHandle( (HANDLE)fd );
285 #elif defined( WIN32 )
292 /*****************************************************************************
294 *****************************************************************************
295 * Read from a network socket
296 * If b_rety is true, then we repeat until we have read the right amount of
298 *****************************************************************************/
299 int __net_Read( vlc_object_t *p_this, int fd, uint8_t *p_data, int i_data,
302 struct timeval timeout;
307 vlc_bool_t b_die = p_this->b_die;
313 if( p_this->b_die != b_die )
318 /* Initialize file descriptor set */
320 FD_SET( fd, &fds_r );
322 FD_SET( fd, &fds_e );
324 /* We'll wait 0.5 second if nothing happens */
326 timeout.tv_usec = 500000;
328 } while( (i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout)) == 0
329 || ( i_ret < 0 && errno == EINTR ) );
333 #if defined(WIN32) || defined(UNDER_CE)
334 msg_Err( p_this, "network select error" );
336 msg_Err( p_this, "network select error (%s)", strerror(errno) );
338 return i_total > 0 ? i_total : -1;
341 if( ( i_recv = recv( fd, p_data, i_data, 0 ) ) < 0 )
343 #if defined(WIN32) || defined(UNDER_CE)
345 /* On win32 recv() will fail if the datagram doesn't fit inside
346 * the passed buffer, even though the buffer will be filled with
347 * the first part of the datagram. */
348 if( WSAGetLastError() == WSAEMSGSIZE )
350 msg_Err( p_this, "recv() failed. "
351 "Increase the mtu size (--mtu option)" );
355 msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
357 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
359 return i_total > 0 ? i_total : -1;
361 else if( i_recv == 0 )
363 /* Connection closed */
378 /*****************************************************************************
379 * __net_ReadNonBlock:
380 *****************************************************************************
381 * Read from a network socket, non blocking mode (with timeout)
382 *****************************************************************************/
383 int __net_ReadNonBlock( vlc_object_t *p_this, int fd, uint8_t *p_data,
384 int i_data, mtime_t i_wait)
386 struct timeval timeout;
391 /* Initialize file descriptor set */
393 FD_SET( fd, &fds_r );
395 FD_SET( fd, &fds_e );
398 timeout.tv_usec = i_wait;
400 i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout);
402 if( i_ret < 0 && errno == EINTR )
408 #if defined(WIN32) || defined(UNDER_CE)
409 msg_Err( p_this, "network select error" );
411 msg_Err( p_this, "network select error (%s)", strerror(errno) );
421 #if !defined(UNDER_CE)
422 if( fd == 0/*STDIN_FILENO*/ ) i_recv = read( fd, p_data, i_data ); else
424 if( ( i_recv = recv( fd, p_data, i_data, 0 ) ) <= 0 )
426 #if defined(WIN32) || defined(UNDER_CE)
428 /* On win32 recv() will fail if the datagram doesn't fit inside
429 * the passed buffer, even though the buffer will be filled with
430 * the first part of the datagram. */
431 if( WSAGetLastError() == WSAEMSGSIZE )
433 msg_Err( p_this, "recv() failed. "
434 "Increase the mtu size (--mtu option)" );
437 msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
439 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
444 return i_recv ? i_recv : -1; /* !i_recv -> connection closed if tcp */
447 /* We will never be here */
451 /* Write exact amount requested */
452 int __net_Write( vlc_object_t *p_this, int fd, uint8_t *p_data, int i_data )
454 struct timeval timeout;
460 vlc_bool_t b_die = p_this->b_die;
466 if( p_this->b_die != b_die )
471 /* Initialize file descriptor set */
473 FD_SET( fd, &fds_w );
475 FD_SET( fd, &fds_e );
477 /* We'll wait 0.5 second if nothing happens */
479 timeout.tv_usec = 500000;
481 } while( (i_ret = select(fd + 1, NULL, &fds_w, &fds_e, &timeout)) == 0
482 || ( i_ret < 0 && errno == EINTR ) );
486 #if defined(WIN32) || defined(UNDER_CE)
487 msg_Err( p_this, "network select error" );
489 msg_Err( p_this, "network select error (%s)", strerror(errno) );
491 return i_total > 0 ? i_total : -1;
494 if( ( i_send = send( fd, p_data, i_data, 0 ) ) < 0 )
496 /* XXX With udp for example, it will issue a message if the host
498 /* msg_Err( p_this, "send failed (%s)", strerror(errno) ); */
499 return i_total > 0 ? i_total : -1;
509 char *__net_Gets( vlc_object_t *p_this, int fd )
511 char *psz_line = malloc( 1024 );
518 if( net_Read( p_this, fd, &psz_line[i_line], 1, VLC_TRUE ) != 1 )
520 psz_line[i_line] = '\0';
525 if( psz_line[i_line-1] == '\n' )
527 psz_line[i_line] = '\0';
531 if( i_line >= i_max - 1 )
534 psz_line = realloc( psz_line, i_max );
544 while( i_line >= 1 &&
545 ( psz_line[i_line-1] == '\n' || psz_line[i_line-1] == '\r' ) )
548 psz_line[i_line] = '\0';
553 int net_Printf( vlc_object_t *p_this, int fd, const char *psz_fmt, ... )
557 va_start( args, psz_fmt );
558 i_ret = net_vaPrintf( p_this, fd, psz_fmt, args );
564 int __net_vaPrintf( vlc_object_t *p_this, int fd, const char *psz_fmt,
570 vasprintf( &psz, psz_fmt, args );
571 i_size = strlen( psz );
572 i_ret = __net_Write( p_this, fd, psz, i_size ) < i_size ? -1 : i_size;