]> git.sesse.net Git - vlc/blob - modules/access/ftp.c
* modules/access/dshow/dshow.cpp: fixed crash when no dshow devices found.
[vlc] / modules / access / ftp.c
1 /*****************************************************************************
2  * ftp.c:
3  *****************************************************************************
4  * Copyright (C) 2001-2003 VideoLAN
5  * $Id: ftp.c,v 1.20 2003/07/31 23:44:49 fenrir Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
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 <sys/types.h>
29 #include <sys/time.h>
30 #include <sys/stat.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <fcntl.h>
34
35 #include <vlc/vlc.h>
36 #include <vlc/input.h>
37
38 #ifdef HAVE_SYS_TIME_H
39 #    include <sys/time.h>
40 #endif
41
42 #ifdef HAVE_UNISTD_H
43 #   include <unistd.h>
44 #endif
45
46 #ifdef WIN32
47 #   include <winsock2.h>
48 #   include <ws2tcpip.h>
49 #   ifndef IN_MULTICAST
50 #       define IN_MULTICAST(a) IN_CLASSD(a)
51 #   endif
52 #else
53 #   include <sys/socket.h>
54 #   include <netinet/in.h>
55 #   if HAVE_ARPA_INET_H
56 #      include <arpa/inet.h>
57 #   elif defined( SYS_BEOS )
58 #      include <net/netdb.h>
59 #   endif
60 #endif
61
62 #include "network.h"
63
64 /*****************************************************************************
65  * Local prototypes
66  *****************************************************************************/
67 static int     Open     ( vlc_object_t * );
68 static void    Close    ( vlc_object_t * );
69
70 static ssize_t Read     ( input_thread_t * p_input, byte_t * p_buffer,
71                           size_t i_len );
72 static void    Seek     ( input_thread_t *, off_t );
73
74
75 static ssize_t NetRead ( input_thread_t *, input_socket_t *, byte_t *, size_t );
76 static void    NetClose( input_thread_t *, input_socket_t *);
77
78 static int  ftp_SendCommand( input_thread_t *, char *, ... );
79 static int  ftp_ReadCommand( input_thread_t *, int *, char ** );
80 static int  ftp_StartStream( input_thread_t *, off_t );
81 static int  ftp_StopStream ( input_thread_t *);
82
83 /*****************************************************************************
84  * Module descriptor
85  *****************************************************************************/
86 #define CACHING_TEXT N_("Caching value in ms")
87 #define CACHING_LONGTEXT N_( \
88     "Allows you to modify the default caching value for ftp streams. This " \
89     "value should be set in miliseconds units." )
90
91 vlc_module_begin();
92     set_description( _("FTP input") );
93     set_capability( "access", 0 );
94     add_category_hint( "stream", NULL, VLC_FALSE );
95         add_integer( "ftp-caching", 2 * DEFAULT_PTS_DELAY / 1000, NULL,
96                      CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
97         add_string( "ftp-user", "anonymous", NULL, "ftp user name", "ftp user name", VLC_FALSE );
98         add_string( "ftp-pwd", "anonymous@dummy.org", NULL, "ftp password", "ftp password, be careful with that option...", VLC_FALSE );
99         add_string( "ftp-account", "anonymous", NULL, "ftp account", "ftp account", VLC_FALSE );
100     add_shortcut( "ftp" );
101     set_callbacks( Open, Close );
102 vlc_module_end();
103
104 /* url: [/]host[:port][/path] */
105 typedef struct url_s
106 {
107     char    *psz_server_addr;
108     int     i_server_port;
109
110     char    *psz_bind_addr;
111     int     i_bind_port;
112
113     char    *psz_path;
114
115     /* private */
116     char *psz_private;
117 } url_t;
118
119 static void ftp_ParseURL( url_t *, char * );
120
121 #define FREE( p ) if( p ) free( p )
122
123 typedef struct access_s
124 {
125     input_socket_t  socket_cmd;
126     input_socket_t  socket_data;
127
128     url_t           url;                        /* connect to this server */
129
130     off_t           i_filesize;
131
132     int             i_eos;
133
134 } access_t;
135
136
137 /****************************************************************************
138  ****************************************************************************
139  *******************                                      *******************
140  *******************       Main functions                 *******************
141  *******************                                      *******************
142  ****************************************************************************
143  ****************************************************************************/
144
145 /****************************************************************************
146  * Open: connect to ftp server and ask for file
147  ****************************************************************************/
148 static int Open( vlc_object_t *p_this )
149 {
150     input_thread_t  *p_input = (input_thread_t*)p_this;
151
152     access_t    *p_access;
153     char        *psz_network;
154
155     module_t            *p_network;
156     network_socket_t    socket_desc;
157     url_t               *p_url;
158
159     int                 i_answer;
160     char                *psz_user, *psz_pwd, *psz_account;
161
162     char                *psz_arg;
163
164     /* *** allocate p_access_data *** */
165     p_input->p_access_data =
166         (void*)p_access = malloc( sizeof( access_t ) );
167     memset( p_access, 0, sizeof( access_t ) );
168     p_url = &p_access->url;
169
170     /* *** Parse URL and get server addr/port and path *** */
171     ftp_ParseURL( p_url, p_input->psz_name );
172
173     if( p_url->psz_server_addr == NULL ||
174         !( *p_url->psz_server_addr ) )
175     {
176         FREE( p_url->psz_private );
177         msg_Err( p_input, "invalid server name" );
178         return( -1 );
179     }
180     if( p_url->i_server_port == 0 )
181     {
182         p_url->i_server_port = 21; /* default port */
183     }
184
185     /* 2: look at ip version ipv4/ipv6 */
186     psz_network = "";
187     if( config_GetInt( p_input, "ipv4" ) )
188     {
189         psz_network = "ipv4";
190     }
191     else if( config_GetInt( p_input, "ipv6" ) )
192     {
193         psz_network = "ipv6";
194     }
195
196     /* 3: Open a TCP connection with server *** */
197     msg_Dbg( p_input, "waiting for connection..." );
198     socket_desc.i_type = NETWORK_TCP;
199     socket_desc.psz_server_addr = p_url->psz_server_addr;
200     socket_desc.i_server_port   = p_url->i_server_port;
201     socket_desc.psz_bind_addr   = "";
202     socket_desc.i_bind_port     = 0;
203     socket_desc.i_ttl           = 0;
204     p_input->p_private = (void*)&socket_desc;
205     if( !( p_network = module_Need( p_input, "network", psz_network ) ) )
206     {
207         msg_Err( p_input, "failed to connect with server" );
208         FREE( p_access->url.psz_private );
209         FREE( p_input->p_access_data );
210         return( -1 );
211     }
212     module_Unneed( p_input, p_network );
213     p_access->socket_cmd.i_handle = socket_desc.i_handle;
214     p_input->i_mtu    = socket_desc.i_mtu;
215     msg_Dbg( p_input,
216              "connection with \"%s:%d\" successful",
217              p_url->psz_server_addr,
218              p_url->i_server_port );
219
220
221     for( ;; )
222     {
223         if( ftp_ReadCommand( p_input, &i_answer, NULL ) < 0)
224         {
225             msg_Err( p_input, "failed to get answer" );
226             goto exit_error;
227         }
228         if( i_answer / 100 != 1 )
229         {
230             break;
231         }
232     }
233
234     if( i_answer / 100 != 2 )
235     {
236         msg_Err( p_input, "connection rejected" );
237         goto exit_error;
238     }
239     else
240     {
241         msg_Dbg( p_input, "connection accepted (%d)", i_answer );
242     }
243
244     psz_user = config_GetPsz( p_input, "ftp-user" );
245     if( ftp_SendCommand( p_input, "USER %s", psz_user ) < 0 )
246     {
247         FREE( psz_user );
248         goto exit_error;
249     }
250     FREE( psz_user );
251
252     if( ftp_ReadCommand( p_input, &i_answer, NULL ) < 0)
253     {
254         msg_Err( p_input, "failed to get answer" );
255         goto exit_error;
256     }
257     switch( i_answer / 100 )
258     {
259         case 2:
260             msg_Dbg( p_input, "user accepted" );
261             break;
262         case 3:
263             msg_Dbg( p_input, "password needed" );
264             psz_pwd = config_GetPsz( p_input, "ftp-pwd" );
265             if( ftp_SendCommand( p_input, "PASS %s", psz_pwd ) < 0 )
266             {
267                 FREE( psz_pwd );
268                 goto exit_error;
269             }
270             FREE( psz_pwd );
271             if( ftp_ReadCommand( p_input, &i_answer, NULL ) < 0)
272             {
273                 msg_Err( p_input, "failed to get answer" );
274                 goto exit_error;
275             }
276             switch( i_answer / 100 )
277             {
278                 case 2:
279                     msg_Dbg( p_input, "password accepted" );
280                     break;
281                 case 3:
282                     msg_Dbg( p_input, "account needed" );
283                     psz_account = config_GetPsz( p_input, "ftp-account" );
284                     if( ftp_SendCommand( p_input, "ACCT %s", psz_account ) < 0 )
285                     {
286                         FREE( psz_account );
287                         goto exit_error;
288                     }
289                     FREE( psz_account );
290                     if( ftp_ReadCommand( p_input, &i_answer, NULL ) < 0)
291                     {
292                         msg_Err( p_input, "failed to get answer" );
293                         goto exit_error;
294                     }
295                     if( i_answer / 100 != 2 )
296                     {
297                         msg_Err( p_input, "account rejected" );
298                         goto exit_error;
299                     }
300                     else
301                     {
302                         msg_Dbg( p_input, "account accepted" );
303                     }
304                     break;
305                 default:
306                     msg_Err( p_input, "password rejected" );
307                     goto exit_error;
308             }
309             break;
310         default:
311             msg_Err( p_input, "user rejected" );
312             goto exit_error;
313     }
314
315     if( ftp_SendCommand( p_input, "TYPE I" ) < 0 )
316     {
317         msg_Err( p_input, "cannot set binary transfert mode" );
318         goto exit_error;
319     }
320     if( ftp_ReadCommand( p_input, &i_answer, NULL ) != 2 )
321     {
322         msg_Err( p_input, "cannot set binary transfert mode" );
323         goto exit_error;
324     }
325
326     /* get size */
327     if( ftp_SendCommand( p_input, "SIZE %s", p_url->psz_path ) < 0 )
328     {
329         msg_Err( p_input, "cannot get file size" );
330         goto exit_error;
331     }
332     if( ftp_ReadCommand( p_input, &i_answer, &psz_arg ) != 2 )
333     {
334         msg_Err( p_input, "cannot get file size" );
335         goto exit_error;
336     }
337
338 #ifdef HAVE_ATOLL
339     p_access->i_filesize = atoll( psz_arg + 4 );
340 #else
341     {
342         int64_t i_size = 0;
343         char    *psz_parser = psz_arg + 4;
344         int     sign = 1;
345
346         while( *psz_parser == ' ' || *psz_parser == '\t' ) psz_parser++;
347
348         if( *psz_parser == '-' ) sign = -1;
349         while( *psz_parser >= '0' && *psz_parser <= '9' )
350         {
351             i_size = i_size * 10 + *psz_parser++ - '0';
352         }
353         p_access->i_filesize = i_size * sign;
354     }
355 #endif
356
357     msg_Dbg( p_input, "file size: "I64Fd, p_access->i_filesize );
358     FREE( psz_arg );
359
360     if( ftp_StartStream( p_input, 0 ) < 0 )
361     {
362         msg_Err( p_input, "cannot retrieve file" );
363         goto exit_error;
364     }
365     /* *** set exported functions *** */
366     p_input->pf_read = Read;
367     p_input->pf_seek = Seek;
368     p_input->pf_set_program = input_SetProgram;
369     p_input->pf_set_area = NULL;
370
371     p_input->p_private = NULL;
372
373     /* *** finished to set some variable *** */
374     vlc_mutex_lock( &p_input->stream.stream_lock );
375     p_input->stream.b_pace_control = 1;
376     p_input->stream.p_selected_area->i_tell = 0;
377     p_input->stream.b_seekable = 1;
378     p_input->stream.p_selected_area->i_size = p_access->i_filesize;
379     p_input->stream.i_method = INPUT_METHOD_NETWORK;
380     vlc_mutex_unlock( &p_input->stream.stream_lock );
381
382     /* Update default_pts to a suitable value for ftp access */
383     p_input->i_pts_delay = config_GetInt( p_input, "ftp-caching" ) * 1000;
384
385     return( 0 );
386
387 exit_error:
388     NetClose( p_input, &p_access->socket_cmd );
389     FREE( p_access->url.psz_private );
390     FREE( p_input->p_access_data );
391     return( -1 );
392 }
393
394 /*****************************************************************************
395  * Close: free unused data structures
396  *****************************************************************************/
397 static void Close( vlc_object_t *p_this )
398 {
399     input_thread_t  *p_input = (input_thread_t *)p_this;
400     access_t        *p_access = (access_t*)p_input->p_access_data;
401
402     msg_Dbg( p_input, "stopping stream" );
403     ftp_StopStream( p_input );
404
405     if( ftp_SendCommand( p_input, "QUIT" ) < 0 )
406     {
407         msg_Err( p_input, "cannot quit" );
408     }
409     else
410     {
411         ftp_ReadCommand( p_input, NULL, NULL );
412     }
413
414
415     NetClose( p_input, &p_access->socket_cmd );
416
417     /* free memory */
418     FREE( p_access->url.psz_private );
419 }
420
421 /*****************************************************************************
422  * Seek: try to go at the right place
423  *****************************************************************************/
424 static void Seek( input_thread_t * p_input, off_t i_pos )
425 {
426     //access_t    *p_access = (access_t*)p_input->p_access_data;
427     if( i_pos < 0 )
428     {
429         return;
430     }
431     vlc_mutex_lock( &p_input->stream.stream_lock );
432
433     msg_Dbg( p_input, "seeking to "I64Fd, i_pos );
434
435     ftp_StopStream( p_input );
436     ftp_StartStream( p_input, i_pos );
437
438     p_input->stream.p_selected_area->i_tell = i_pos;
439     vlc_mutex_unlock( &p_input->stream.stream_lock );
440 }
441
442 static ssize_t Read     ( input_thread_t * p_input, byte_t * p_buffer,
443                           size_t i_len )
444 {
445     access_t    *p_access = (access_t*)p_input->p_access_data;
446     size_t      i_data;
447
448     i_data = NetRead( p_input, &p_access->socket_data, p_buffer, i_len );
449
450     return( i_data );
451 }
452
453 static int  ftp_SendCommand( input_thread_t *p_input, char *psz_fmt, ... )
454 {
455     access_t        *p_access = (access_t*)p_input->p_access_data;
456     va_list args;
457     char    *psz_buffer;
458 #if !defined(HAVE_VASPRINTF) || defined(SYS_DARWIN) || defined(SYS_BEOS)
459         size_t  i_size;
460 #endif
461
462     va_start( args, psz_fmt );
463
464 #if defined(HAVE_VASPRINTF) && !defined(SYS_DARWIN) && !defined(SYS_BEOS)
465     vasprintf( &psz_buffer, psz_fmt, args );
466 #else
467     i_size = strlen( psz_fmt ) + 2048;
468     psz_buffer = calloc( i_size, sizeof( char ) );
469     vsnprintf( psz_buffer, i_size, psz_fmt, args );
470     psz_buffer[i_size - 1] = 0;
471 #endif
472     if( !strncmp( psz_buffer, "PASS", 4 ) )
473     {
474         msg_Dbg( p_input, "ftp_SendCommand:\"PASS xxx\"" );
475     }
476     else
477     {
478         msg_Dbg( p_input, "ftp_SendCommand:\"%s\"", psz_buffer );
479     }
480     psz_buffer = realloc( psz_buffer, strlen( psz_buffer ) + 3 );
481     strcat( psz_buffer, "\r\n" );
482     if( send( p_access->socket_cmd.i_handle,
483               psz_buffer,
484               strlen( psz_buffer ),
485               0 ) == -1 )
486     {
487         FREE( psz_buffer );
488         msg_Err( p_input, "failed to send command" );
489         return( -1 );
490     }
491     FREE( psz_buffer );
492
493     va_end( args );
494
495     return( 0 );
496 }
497
498 #define BLOCK_SIZE  1024
499 /* TODO support this s**t :
500  RFC 959 allows the client to send certain TELNET strings at any moment,
501  even in the middle of a request:
502
503  * \377\377.
504  * \377\376x where x is one byte.
505  * \377\375x where x is one byte. The server is obliged to send \377\374x
506  *                                immediately after reading x.
507  * \377\374x where x is one byte.
508  * \377\373x where x is one byte. The server is obliged to send \377\376x
509  *                                immediately after reading x.
510  * \377x for any other byte x.
511
512  These strings are not part of the requests, except in the case \377\377,
513  where the request contains one \377. */
514
515 static int  ftp_ReadCommand( input_thread_t *p_input,
516                              int *pi_answer, char **ppsz_answer )
517 {
518     access_t        *p_access = (access_t*)p_input->p_access_data;
519     uint8_t *p_buffer;
520     int     i_buffer;
521     int     i_buffer_size;
522
523     int i_answer;
524
525     i_buffer      = 0;
526     i_buffer_size = BLOCK_SIZE + 1;
527     p_buffer      = malloc( BLOCK_SIZE + 1);
528
529     for( ;; )
530     {
531         ssize_t i_read;
532         i_read = NetRead( p_input, &p_access->socket_cmd,
533                           p_buffer + i_buffer, BLOCK_SIZE );
534         if( i_read <= 0 || p_input->b_die || p_input->b_error )
535         {
536             free( p_buffer );
537             if( pi_answer )   *pi_answer    = 500;
538             if( ppsz_answer ) *ppsz_answer  = NULL;
539             return( -1 );
540         }
541         if( i_read == 0 )
542         {
543 //            continue;
544         }
545         i_buffer += i_read;
546         if( i_read < BLOCK_SIZE )
547         {
548             p_buffer[i_buffer] = '\0';
549             break;
550         }
551         i_buffer_size += BLOCK_SIZE;
552         p_buffer = realloc( p_buffer, i_buffer_size );
553     }
554
555     if( i_buffer < 3 )
556     {
557         goto exit_error;
558     }
559
560     i_answer = atoi( p_buffer );
561
562     if( pi_answer ) *pi_answer = i_answer;
563     if( ppsz_answer )
564     {
565         *ppsz_answer = p_buffer;
566     }
567     else
568     {
569         free( p_buffer );
570     }
571     return( i_answer / 100 );
572
573 exit_error:
574     free( p_buffer );
575     if( pi_answer )   *pi_answer    = 500;
576     if( ppsz_answer ) *ppsz_answer  = NULL;
577     return( -1 );
578 }
579
580 static int  ftp_StartStream( input_thread_t *p_input, off_t i_start )
581 {
582     access_t        *p_access = (access_t*)p_input->p_access_data;
583
584     char psz_ip[1000];
585     int  i_answer;
586     char *psz_arg, *psz_parser;
587     int  a1,a2,a3,a4;
588     int  p1,p2;
589     int  i_port;
590     module_t            *p_network;
591     network_socket_t    socket_desc;
592
593     if( ftp_SendCommand( p_input, "PASV" ) < 0 )
594     {
595         msg_Err( p_input, "cannot set passive transfert mode" );
596         return( -1 );
597     }
598     if( ftp_ReadCommand( p_input, &i_answer, &psz_arg ) != 2 )
599     {
600         msg_Err( p_input, "cannot set passive transfert mode" );
601         return( -1 );
602     }
603     psz_parser = strchr( psz_arg, '(' );
604     if( !psz_parser || sscanf( psz_parser, "(%d,%d,%d,%d,%d,%d", &a1, &a2, &a3, &a4, &p1, &p2 ) < 6 )
605     {
606         FREE( psz_arg );
607         msg_Err( p_input, "cannot get ip/port for passive transfert mode" );
608         return( -1 );
609     }
610     FREE( psz_arg );
611
612     sprintf( psz_ip, "%d.%d.%d.%d", a1, a2, a3, a4 );
613     i_port = p1 * 256 + p2;
614     msg_Dbg( p_input, "ip:%s port:%d", psz_ip, i_port );
615
616     if( ftp_SendCommand( p_input, "TYPE I" ) < 0 )
617     {
618         msg_Err( p_input, "cannot set binary transfert mode" );
619         return( -1 );
620     }
621     if( ftp_ReadCommand( p_input, &i_answer, NULL ) != 2 )
622     {
623         msg_Err( p_input, "cannot set binary transfert mode" );
624         return( -1 );
625     }
626
627
628     if( i_start > 0 )
629     {
630         if( ftp_SendCommand( p_input, "REST "I64Fu, i_start ) < 0 )
631         {
632             msg_Err( p_input, "cannot set restart point" );
633             return( -1 );
634         }
635         if( ftp_ReadCommand( p_input, &i_answer, NULL ) > 3 )
636         {
637             msg_Err( p_input, "cannot set restart point" );
638             return( -1 );
639         }
640     }
641
642     msg_Dbg( p_input, "waiting for data connection..." );
643     socket_desc.i_type = NETWORK_TCP;
644     socket_desc.psz_server_addr = psz_ip;
645     socket_desc.i_server_port   = i_port;
646     socket_desc.psz_bind_addr   = "";
647     socket_desc.i_bind_port     = 0;
648     socket_desc.i_ttl           = 0;
649     p_input->p_private = (void*)&socket_desc;
650     if( !( p_network = module_Need( p_input, "network", "" ) ) )
651     {
652         msg_Err( p_input, "failed to connect with server" );
653         return( -1 );
654     }
655     module_Unneed( p_input, p_network );
656     p_access->socket_data.i_handle = socket_desc.i_handle;
657     p_input->i_mtu    = socket_desc.i_mtu;
658     msg_Dbg( p_input,
659              "connection with \"%s:%d\" successful",
660              psz_ip, i_port );
661
662     if( ftp_SendCommand( p_input, "RETR %s", p_access->url.psz_path ) < 0 )
663     {
664         msg_Err( p_input, "cannot retreive file" );
665         return( -1 );
666     }
667     /* "1xx" message */
668     if( ftp_ReadCommand( p_input, &i_answer, NULL ) > 2 )
669     {
670         msg_Err( p_input, "cannot retreive file" );
671         return( -1 );
672     }
673
674     return( 0 );
675 }
676
677 static int  ftp_StopStream ( input_thread_t *p_input)
678 {
679     access_t        *p_access = (access_t*)p_input->p_access_data;
680
681     int i_answer;
682
683     NetClose( p_input, &p_access->socket_data );
684
685     if( ftp_SendCommand( p_input, "ABOR" ) < 0 )
686     {
687         msg_Err( p_input, "cannot abord file" );
688     }
689     else
690     {
691         ftp_ReadCommand( p_input, &i_answer, NULL );
692         ftp_ReadCommand( p_input, &i_answer, NULL );
693     }
694
695     return( 0 );
696 }
697
698 /****************************************************************************
699  *
700  ****************************************************************************/
701 static void ftp_ParseURL( url_t *p_url, char *psz_url )
702 {
703     char *psz_parser;
704     char *psz_server_port;
705
706     p_url->psz_private = strdup( psz_url );
707
708     psz_parser = p_url->psz_private;
709
710     while( *psz_parser == '/' )
711     {
712         psz_parser++;
713     }
714     p_url->psz_server_addr = psz_parser;
715
716     while( *psz_parser &&
717            *psz_parser != ':' &&  *psz_parser != '/' && *psz_parser != '@' )
718     {
719         psz_parser++;
720     }
721
722     if( *psz_parser == ':' )
723     {
724         *psz_parser = '\0';
725         psz_parser++;
726         psz_server_port = psz_parser;
727
728         while( *psz_parser && *psz_parser != '/' )
729         {
730             psz_parser++;
731         }
732     }
733     else
734     {
735         psz_server_port = "";
736     }
737
738     if( *psz_parser == '@' )
739     {
740         char *psz_bind_port;
741
742         *psz_parser = '\0';
743         psz_parser++;
744
745         p_url->psz_bind_addr = psz_parser;
746
747         while( *psz_parser && *psz_parser != ':' && *psz_parser != '/' )
748         {
749             psz_parser++;
750         }
751
752         if( *psz_parser == ':' )
753         {
754             *psz_parser = '\0';
755             psz_parser++;
756             psz_bind_port = psz_parser;
757
758             while( *psz_parser && *psz_parser != '/' )
759             {
760                 psz_parser++;
761             }
762         }
763         else
764         {
765             psz_bind_port = "";
766         }
767         if( *psz_bind_port )
768         {
769             p_url->i_bind_port = strtol( psz_bind_port, &psz_parser, 10 );
770         }
771         else
772         {
773             p_url->i_bind_port = 0;
774         }
775     }
776     else
777     {
778         p_url->psz_bind_addr = "";
779         p_url->i_bind_port = 0;
780     }
781
782     if( *psz_parser == '/' )
783     {
784         *psz_parser = '\0';
785         psz_parser++;
786         p_url->psz_path = psz_parser;
787     }
788
789     if( *psz_server_port )
790     {
791         p_url->i_server_port = strtol( psz_server_port, &psz_parser, 10 );
792     }
793     else
794     {
795         p_url->i_server_port = 0;
796     }
797 }
798
799 /*****************************************************************************
800  * Read: read on a file descriptor, checking b_die periodically
801  *****************************************************************************/
802 static ssize_t NetRead( input_thread_t *p_input,
803                         input_socket_t *p_socket,
804                         byte_t *p_buffer, size_t i_len )
805 {
806 #ifdef UNDER_CE
807     return -1;
808
809 #else
810     struct timeval  timeout;
811     fd_set          fds;
812     ssize_t         i_recv;
813     int             i_ret;
814
815     /* Initialize file descriptor set */
816     FD_ZERO( &fds );
817     FD_SET( p_socket->i_handle, &fds );
818
819     /* We'll wait 1 second if nothing happens */
820     timeout.tv_sec  = 1;
821     timeout.tv_usec = 0;
822
823     /* Find if some data is available */
824     while( (i_ret = select( p_socket->i_handle + 1, &fds,
825                             NULL, NULL, &timeout )) == 0
826            || (i_ret < 0 && errno == EINTR) )
827     {
828         FD_ZERO( &fds );
829         FD_SET( p_socket->i_handle, &fds );
830         timeout.tv_sec  = 1;
831         timeout.tv_usec = 0;
832
833         if( p_input->b_die || p_input->b_error )
834         {
835             return 0;
836         }
837     }
838
839     if( i_ret < 0 )
840     {
841         msg_Err( p_input, "network select error (%s)", strerror(errno) );
842         return -1;
843     }
844
845     i_recv = recv( p_socket->i_handle, p_buffer, i_len, 0 );
846
847     if( i_recv < 0 )
848     {
849         msg_Err( p_input, "recv failed (%s)", strerror(errno) );
850     }
851
852     return i_recv;
853
854 #endif
855 }
856
857 static void NetClose( input_thread_t *p_input, input_socket_t *p_socket )
858 {
859 #if defined( UNDER_CE )
860     CloseHandle( (HANDLE)p_socket->i_handle );
861 #elif defined( WIN32 )
862     closesocket( p_socket->i_handle );
863 #else
864     close( p_socket->i_handle );
865 #endif
866 }
867