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 *****************************************************************************/
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;
75 /* Check if we have force ipv4 or ipv6 */
76 var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
77 var_Get( p_this, "ipv4", &val );
83 var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
84 var_Get( p_this, "ipv6", &val );
90 /* Prepare the network_socket_t structure */
91 sock.i_type = NETWORK_TCP;
92 sock.psz_bind_addr = "";
94 sock.psz_server_addr = psz_host;
95 sock.i_server_port = i_port;
98 msg_Dbg( p_this, "net: connecting to '%s:%d'", psz_host, i_port );
99 private = p_this->p_private;
100 p_this->p_private = (void*)&sock;
101 if( !( p_network = module_Need( p_this, "network", psz_network, 0 ) ) )
103 msg_Dbg( p_this, "net: connection to '%s:%d' failed",
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, 0 ) ) )
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 */
214 FD_SET( fd, &fds_r );
216 FD_SET( fd, &fds_e );
218 /* We'll wait 0.5 second if nothing happens */
220 timeout.tv_usec = 500000;
222 } while( (i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout)) == 0
223 || ( i_ret < 0 && errno == EINTR ) );
227 msg_Err( p_this, "network select error (%s)", strerror(errno) );
228 return i_total > 0 ? i_total : -1;
231 if( ( i_recv = recv( fd, p_data, i_data, 0 ) ) < 0 )
235 /* On win32 recv() will fail if the datagram doesn't fit inside
236 * the passed buffer, even though the buffer will be filled with
237 * the first part of the datagram. */
238 if( WSAGetLastError() == WSAEMSGSIZE )
240 msg_Err( p_this, "recv() failed. "
241 "Increase the mtu size (--mtu option)" );
245 msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
247 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
249 return i_total > 0 ? i_total : -1;
251 else if( i_recv == 0 )
253 /* Connection closed */
268 /* Write exact amount requested */
269 int __net_Write( vlc_object_t *p_this, int fd, uint8_t *p_data, int i_data )
271 struct timeval timeout;
277 vlc_bool_t b_die = p_this->b_die;
283 if( p_this->b_die != b_die )
288 /* Initialize file descriptor set */
290 FD_SET( fd, &fds_w );
292 FD_SET( fd, &fds_e );
294 /* We'll wait 0.5 second if nothing happens */
296 timeout.tv_usec = 500000;
298 } while( (i_ret = select(fd + 1, NULL, &fds_w, &fds_e, &timeout)) == 0
299 || ( i_ret < 0 && errno == EINTR ) );
303 msg_Err( p_this, "network select error (%s)", strerror(errno) );
304 return i_total > 0 ? i_total : -1;
307 if( ( i_send = send( fd, p_data, i_data, 0 ) ) < 0 )
309 /* XXX With udp for example, it will issue a message if the host
311 /* msg_Err( p_this, "send failed (%s)", strerror(errno) ); */
312 return i_total > 0 ? i_total : -1;
322 char *__net_Gets( vlc_object_t *p_this, int fd )
324 char *psz_line = malloc( 1024 );
331 if( net_Read( p_this, fd, &psz_line[i_line], 1, VLC_TRUE ) != 1 )
333 psz_line[i_line] = '\0';
338 if( psz_line[i_line-1] == '\n' )
340 psz_line[i_line] = '\0';
344 if( i_line >= i_max - 1 )
347 psz_line = realloc( psz_line, i_max );
357 while( i_line >= 1 &&
358 ( psz_line[i_line-1] == '\n' || psz_line[i_line-1] == '\r' ) )
361 psz_line[i_line] = '\0';
366 int net_Printf( vlc_object_t *p_this, int fd, char *psz_fmt, ... )
372 va_start( args, psz_fmt );
373 vasprintf( &psz, psz_fmt, args );
376 i_size = strlen( psz );
378 i_ret = __net_Write( p_this, fd, psz, i_size ) < i_size ? -1 : i_size;