1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2004 VideoLAN
5 * $Id: net.c,v 1.9 2004/01/25 17:16:06 zorglub Exp $
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 *****************************************************************************/
38 #ifdef HAVE_SYS_TIME_H
39 # include <sys/time.h>
42 #if defined( UNDER_CE )
44 #elif defined( WIN32 )
45 # include <winsock2.h>
46 # include <ws2tcpip.h>
48 # define IN_MULTICAST(a) IN_CLASSD(a)
51 # include <sys/socket.h>
61 /*****************************************************************************
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 )
71 char *psz_network = "";
72 network_socket_t sock;
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 );
84 var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
85 var_Get( p_this, "ipv6", &val );
91 /* Prepare the network_socket_t structure */
92 sock.i_type = NETWORK_TCP;
93 sock.psz_bind_addr = "";
95 sock.psz_server_addr = psz_host;
96 sock.i_server_port = i_port;
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 )
104 msg_Dbg( p_this, "net: connection to '%s:%d' failed", psz_host, i_port );
107 module_Unneed( p_this, p_network );
108 p_this->p_private = private;
110 return sock.i_handle;
113 /*****************************************************************************
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 )
124 char *psz_network = "";
125 network_socket_t sock;
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 );
134 psz_network = "ipv4";
137 var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
138 var_Get( p_this, "ipv6", &val );
141 psz_network = "ipv6";
143 if( psz_server == NULL ) psz_server = "";
144 if( psz_bind == NULL ) psz_bind = "";
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;
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 )
160 msg_Dbg( p_this, "net: connection to '%s:%d@%s:%d' failed",
161 psz_server, i_server, psz_bind, i_bind );
164 module_Unneed( p_this, p_network );
165 p_this->p_private = private;
167 return sock.i_handle;
170 /*****************************************************************************
172 *****************************************************************************
173 * Close a network handle
174 *****************************************************************************/
175 void net_Close( int fd )
178 CloseHandle( (HANDLE)fd );
179 #elif defined( WIN32 )
186 /*****************************************************************************
188 *****************************************************************************
189 * Read from a network socket
190 * If b_rety is true, then we repeat until we have read the right amount of
192 *****************************************************************************/
193 int __net_Read( vlc_object_t *p_this, int fd, uint8_t *p_data, int i_data,
196 struct timeval timeout;
201 vlc_bool_t b_die = p_this->b_die;
207 if( p_this->b_die != b_die )
212 /* Initialize file descriptor set */
216 /* We'll wait 0.5 second if nothing happens */
218 timeout.tv_usec = 500000;
219 } while( ( i_ret = select( fd + 1, &fds, NULL, NULL, &timeout )) == 0 ||
220 ( i_ret < 0 && errno == EINTR ) );
224 msg_Err( p_this, "network select error (%s)", strerror(errno) );
225 return i_total > 0 ? i_total : -1;
228 if( ( i_recv = recv( fd, p_data, i_data, 0 ) ) < 0 )
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 )
237 msg_Err( p_this, "recv() failed. "
238 "Increase the mtu size (--mtu option)" );
243 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
244 return i_total > 0 ? i_total : -1;
258 /* Write exact amount requested */
259 int __net_Write( vlc_object_t *p_this, int fd, uint8_t *p_data, int i_data )
261 struct timeval timeout;
267 vlc_bool_t b_die = p_this->b_die;
273 if( p_this->b_die != b_die )
278 /* Initialize file descriptor set */
282 /* We'll wait 0.5 second if nothing happens */
284 timeout.tv_usec = 500000;
285 } while( ( i_ret = select( fd + 1, NULL, &fds, NULL, &timeout )) == 0 ||
286 ( i_ret < 0 && errno == EINTR ) );
290 msg_Err( p_this, "network select error (%s)", strerror(errno) );
291 return i_total > 0 ? i_total : -1;
294 if( ( i_send = send( fd, p_data, i_data, 0 ) ) < 0 )
296 /* XXX With udp for example, it will issue a message if the host
298 /* msg_Err( p_this, "send failed (%s)", strerror(errno) ); */
299 return i_total > 0 ? i_total : -1;
309 char *__net_Gets( vlc_object_t *p_this, int fd )
311 char *psz_line = malloc( 1024 );
318 if( net_Read( p_this, fd, &psz_line[i_line], 1, VLC_TRUE ) != 1 )
320 psz_line[i_line] = '\0';
325 if( psz_line[i_line-1] == '\n' )
327 psz_line[i_line] = '\0';
331 if( i_line >= i_max - 1 )
334 psz_line = realloc( psz_line, i_max );
344 while( i_line >= 1 &&
345 ( psz_line[i_line-1] == '\n' || psz_line[i_line-1] == '\r' ) )
348 psz_line[i_line] = '\0';
353 int net_Printf( vlc_object_t *p_this, int fd, char *psz_fmt, ... )
359 va_start( args, psz_fmt );
360 vasprintf( &psz, psz_fmt, args );
363 i_size = strlen( psz );
365 i_ret = __net_Write( p_this, fd, psz, i_size ) < i_size ? -1 : i_size;