io.c 19.1 KB
Newer Older
Laurent Aimar's avatar
 
Laurent Aimar committed
1
/*****************************************************************************
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
2
 * io.c: network I/O functions
Laurent Aimar's avatar
 
Laurent Aimar committed
3
 *****************************************************************************
4
 * Copyright (C) 2004-2005, 2007 the VideoLAN team
5
 * Copyright © 2005-2006 Rémi Denis-Courmont
6
 * $Id$
Laurent Aimar's avatar
 
Laurent Aimar committed
7
8
 *
 * Authors: Laurent Aimar <fenrir@videolan.org>
9
 *          Rémi Denis-Courmont <rem # videolan.org>
10
 *          Christophe Mutricy <xtophe at videolan dot org>
Laurent Aimar's avatar
 
Laurent Aimar committed
11
12
13
14
15
16
17
18
19
20
21
22
23
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
dionoea's avatar
dionoea committed
24
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
Laurent Aimar's avatar
 
Laurent Aimar committed
25
26
27
28
29
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
30

Laurent Aimar's avatar
 
Laurent Aimar committed
31
32
#include <vlc/vlc.h>

33
34
#include <stdlib.h>
#include <stdio.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
35
#include <limits.h>
36

37
#include <errno.h>
38
#include <assert.h>
Laurent Aimar's avatar
 
Laurent Aimar committed
39
40
41
42
43
44
45

#ifdef HAVE_FCNTL_H
#   include <fcntl.h>
#endif
#ifdef HAVE_SYS_TIME_H
#    include <sys/time.h>
#endif
gbazin's avatar
gbazin committed
46
47
48
#ifdef HAVE_UNISTD_H
#   include <unistd.h>
#endif
49
#ifdef HAVE_POLL
50
#   include <poll.h>
51
#endif
gbazin's avatar
gbazin committed
52

zorglub's avatar
zorglub committed
53
#include <vlc_network.h>
Laurent Aimar's avatar
 
Laurent Aimar committed
54

55
56
57
58
59
60
61
#ifndef INADDR_ANY
#   define INADDR_ANY  0x00000000
#endif
#ifndef INADDR_NONE
#   define INADDR_NONE 0xFFFFFFFF
#endif

62
#if defined(WIN32) || defined(UNDER_CE)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
63
64
# undef EAFNOSUPPORT
# define EAFNOSUPPORT WSAEAFNOSUPPORT
65
66
#endif

67
68
69
extern int rootwrap_bind (int family, int socktype, int protocol,
                          const struct sockaddr *addr, size_t alen);

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
70
71
72
73
74
int net_Socket (vlc_object_t *p_this, int family, int socktype,
                int protocol)
{
    int fd = socket (family, socktype, protocol);
    if (fd == -1)
75
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
76
77
78
79
        if (net_errno != EAFNOSUPPORT)
            msg_Err (p_this, "cannot create socket: %s",
                     net_strerror (net_errno));
        return -1;
80
    }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
81
82
83

#if defined (WIN32) || defined (UNDER_CE)
    ioctlsocket (fd, FIONBIO, &(unsigned long){ 1 });
84
#else
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
85
86
    fcntl (fd, F_SETFD, FD_CLOEXEC);
    fcntl (fd, F_SETFL, fcntl (fd, F_GETFL, 0) | O_NONBLOCK);
87
88
#endif

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
89
    setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof (int));
90
91
92
93
94
95
96
97
98
99

#ifdef IPV6_V6ONLY
    /*
     * Accepts only IPv6 connections on IPv6 sockets
     * (and open an IPv4 socket later as well if needed).
     * Only Linux and FreeBSD can map IPv4 connections on IPv6 sockets,
     * so this allows for more uniform handling across platforms. Besides,
     * it makes sure that IPv4 addresses will be printed as w.x.y.z rather
     * than ::ffff:w.x.y.z
     */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
100
    if (family == AF_INET6)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
101
        setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){ 1 }, sizeof (int));
102
103
#endif

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
104
#if defined (WIN32) || defined (UNDER_CE)
105
# ifndef IPV6_PROTECTION_LEVEL
106
#  warning Please update your C library headers.
107
#  define IPV6_PROTECTION_LEVEL 23
108
#  define PROTECTION_LEVEL_UNRESTRICTED 10
109
# endif
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
110
111
112
    if (family == AF_INET6)
        setsockopt (fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL,
                    &(int){ PROTECTION_LEVEL_UNRESTRICTED }, sizeof (int));
113
#endif
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
114

115
116
117
    return fd;
}

Laurent Aimar's avatar
Laurent Aimar committed
118

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
119
120
int *net_Listen (vlc_object_t *p_this, const char *psz_host,
                 int i_port, int family, int socktype, int protocol)
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
{
    struct addrinfo hints, *res;

    memset (&hints, 0, sizeof( hints ));
    hints.ai_family = family;
    hints.ai_socktype = socktype;
    hints.ai_flags = AI_PASSIVE;

    msg_Dbg (p_this, "net: listening to %s port %d", psz_host, i_port);

    int i_val = vlc_getaddrinfo (p_this, psz_host, i_port, &hints, &res);
    if (i_val)
    {
        msg_Err (p_this, "Cannot resolve %s port %d : %s", psz_host, i_port,
                 vlc_gai_strerror (i_val));
        return NULL;
    }

    int *sockv = NULL;
    unsigned sockc = 0;

    for (struct addrinfo *ptr = res; ptr != NULL; ptr = ptr->ai_next)
    {
        int fd = net_Socket (p_this, ptr->ai_family, ptr->ai_socktype,
145
                             protocol ?: ptr->ai_protocol);
146
147
148
149
150
151
152
        if (fd == -1)
        {
            msg_Dbg (p_this, "socket error: %s", net_strerror (net_errno));
            continue;
        }

        /* Bind the socket */
153
#if defined (WIN32) || defined (UNDER_CE)
154
155
156
157
158
159
160
161
162
        /*
         * Under Win32 and for multicasting, we bind to INADDR_ANY.
         * This is of course a severe bug, since the socket would logically
         * receive unicast traffic, and multicast traffic of groups subscribed
         * to via other sockets.
         */
        if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen)
         && (sizeof (struct sockaddr_storage) >= ptr->ai_addrlen))
        {
163
164
            // This works for IPv4 too - don't worry!
            struct sockaddr_in6 dumb =
165
            {
166
167
                .sin6_family = ptr->ai_addr->sa_family,
                .sin6_port =  ((struct sockaddr_in *)(ptr->ai_addr))->sin_port
168
169
170
171
172
173
            };

            bind (fd, (struct sockaddr *)&dumb, ptr->ai_addrlen);
        }
        else
#endif
174
175
176
177
178
179
180
        if (bind (fd, ptr->ai_addr, ptr->ai_addrlen))
        {
            int saved_errno = net_errno;

            net_Close (fd);
#if !defined(WIN32) && !defined(UNDER_CE)
            fd = rootwrap_bind (ptr->ai_family, ptr->ai_socktype,
181
                                protocol ?: ptr->ai_protocol, ptr->ai_addr,
182
183
184
185
186
187
188
189
190
191
192
193
194
195
                                ptr->ai_addrlen);
            if (fd != -1)
            {
                msg_Dbg (p_this, "got socket %d from rootwrap", fd);
            }
            else
#endif
            {
                msg_Err (p_this, "socket bind error (%s)",
                         net_strerror( saved_errno ) );
                continue;
            }
        }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
196
197
198
199
200
201
202
203
204
        if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen))
        {
            if (net_Subscribe (p_this, fd, ptr->ai_addr, ptr->ai_addrlen))
            {
                net_Close (fd);
                continue;
            }
        }

205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
        /* Listen */
        switch (ptr->ai_socktype)
        {
            case SOCK_STREAM:
            case SOCK_RDM:
            case SOCK_SEQPACKET:
                if (listen (fd, INT_MAX))
                {
                    msg_Err (p_this, "socket listen error (%s)",
                            net_strerror (net_errno));
                    net_Close (fd);
                    continue;
                }
        }

        int *nsockv = (int *)realloc (sockv, (sockc + 2) * sizeof (int));
        if (nsockv != NULL)
        {
            nsockv[sockc++] = fd;
            sockv = nsockv;
        }
        else
            net_Close (fd);
    }

    vlc_freeaddrinfo (res);

    if (sockv != NULL)
        sockv[sockc] = -1;

    return sockv;
}


Rémi Denis-Courmont's avatar
Cleanup    
Rémi Denis-Courmont committed
239
240
241
242
243
244
245
246
247
int net_ListenSingle (vlc_object_t *obj, const char *host, int port,
                      int family, int socktype, int protocol)
{
    int *fdv = net_Listen (obj, host, port, family, socktype, protocol);
    if (fdv == NULL)
        return -1;

    for (unsigned i = 1; fdv[i] != -1; i++)
    {
248
        msg_Warn (obj, "Multiple sockets opened. Dropping extra ones!");
Rémi Denis-Courmont's avatar
Cleanup    
Rémi Denis-Courmont committed
249
250
251
252
253
254
255
256
257
258
259
260
        net_Close (fdv[i]);
    }

    int fd = fdv[0];
    assert (fd != -1);

    free (fdv);
    return fd;
}



Laurent Aimar's avatar
 
Laurent Aimar committed
261
262
263
264
265
/*****************************************************************************
 * __net_Close:
 *****************************************************************************
 * Close a network handle
 *****************************************************************************/
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
266
void net_Close (int fd)
Laurent Aimar's avatar
 
Laurent Aimar committed
267
268
{
#ifdef UNDER_CE
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
269
270
271
    CloseHandle ((HANDLE)fd);
#elif defined (WIN32)
    closesocket (fd);
Laurent Aimar's avatar
 
Laurent Aimar committed
272
#else
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
273
    (void)close (fd);
Laurent Aimar's avatar
 
Laurent Aimar committed
274
275
276
#endif
}

277

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
278
static ssize_t
279
net_ReadInner( vlc_object_t *restrict p_this, unsigned fdc, const int *fdv,
280
               const v_socket_t *const *restrict vsv,
281
               uint8_t *restrict p_buf, size_t i_buflen,
282
283
               int wait_ms, vlc_bool_t waitall )
{
284
    size_t i_total = 0;
285

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
286
    while (i_buflen > 0)
287
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
288
289
        unsigned i;
        ssize_t n;
290
291
        struct pollfd ufd[fdc];

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
292
293
        int delay_ms = 500;
        if ((wait_ms != -1) && (wait_ms < 500))
Rémi Denis-Courmont's avatar
Fixes    
Rémi Denis-Courmont committed
294
            delay_ms = wait_ms;
295

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
296
        if (p_this->b_die)
297
298
299
300
301
        {
            errno = EINTR;
            goto error;
        }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
302
        memset (ufd, 0, sizeof (ufd));
303

304
        for( i = 0; i < fdc; i++ )
305
306
307
308
309
        {
            ufd[i].fd = fdv[i];
            ufd[i].events = POLLIN;
        }

310
        n = poll( ufd, fdc, delay_ms );
311
        if( n == -1 )
312
313
            goto error;

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
314
        assert ((unsigned)n <= fdc);
315

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
316
317
318
319
320
321
322
323
324
325
        if (n == 0) // timeout
            continue;

        for (i = 0;; i++)
        {
            if ((i_total > 0) && (ufd[i].revents & POLLERR))
                return i_total; // error will be dequeued on next run

            if ((ufd[i].revents & POLLIN) == 0)
                continue;
326

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
327
328
329
330
331
            fdc = 1;
            fdv += i;
            vsv += i;
            break;
        }
332

333
334
335
336
        if( (*vsv) != NULL )
        {
            n = (*vsv)->pf_recv( (*vsv)->p_sys, p_buf, i_buflen );
        }
337
        else
338
        {
339
#if defined(WIN32) || defined(UNDER_CE)
340
            n = recv( *fdv, p_buf, i_buflen, 0 );
341
#else
342
            n = read( *fdv, p_buf, i_buflen );
343
#endif
344
        }
345

346
        if( n == -1 )
347
348
        {
#if defined(WIN32) || defined(UNDER_CE)
349
            switch( WSAGetLastError() )
350
351
352
353
354
355
356
357
358
359
            {
                case WSAEWOULDBLOCK:
                /* only happens with vs != NULL (SSL) - not really an error */
                    continue;

                case WSAEMSGSIZE:
                /* For UDP only */
                /* On Win32, recv() fails if the datagram doesn't fit inside
                 * the passed buffer, even though the buffer will be filled
                 * with the first part of the datagram. */
360
                    msg_Err( p_this, "Receive error: "
361
                                     "Increase the mtu size (--mtu option)" );
362
363
                    i_total += i_buflen;
                    return i_total;
364
365
366
367
368
369
370
371
            }
#else
            if( errno == EAGAIN ) /* spurious wake-up (sucks if fdc > 1) */
                continue;
#endif
            goto error;
        }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
372
373
374
        if (n == 0) // EOF
            return i_total;

375
376
377
        i_total += n;
        p_buf += n;
        i_buflen -= n;
Rémi Denis-Courmont's avatar
Fixes    
Rémi Denis-Courmont committed
378

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
379
380
381
382
        if (!waitall)
            return i_total;

        if (wait_ms != -1)
383
        {
Rémi Denis-Courmont's avatar
Fixes    
Rémi Denis-Courmont committed
384
            wait_ms -= delay_ms;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
385
386
            if (wait_ms == 0)
                return i_total; // time's up!
387
        }
388
    }
damienf's avatar
damienf committed
389
    return i_total;
390
391

error:
zorglub's avatar
zorglub committed
392
393
    if( errno != EINTR )
        msg_Err( p_this, "Read error: %s", net_strerror (net_errno) );
Rémi Denis-Courmont's avatar
Oups    
Rémi Denis-Courmont committed
394
    return i_total ? (ssize_t)i_total : -1;
395
396
397
}


Laurent Aimar's avatar
 
Laurent Aimar committed
398
399
400
401
/*****************************************************************************
 * __net_Read:
 *****************************************************************************
 * Read from a network socket
402
 * If b_retry is true, then we repeat until we have read the right amount of
Laurent Aimar's avatar
 
Laurent Aimar committed
403
404
 * data
 *****************************************************************************/
405
406
407
ssize_t __net_Read( vlc_object_t *restrict p_this, int fd,
                    const v_socket_t *restrict p_vs,
                    uint8_t *restrict buf, size_t len, vlc_bool_t b_retry )
Laurent Aimar's avatar
 
Laurent Aimar committed
408
{
409
    return net_ReadInner( p_this, 1, &(int){ fd },
410
411
                          &(const v_socket_t *){ p_vs }, buf, len, -1,
                          b_retry );
Laurent Aimar's avatar
 
Laurent Aimar committed
412
413
}

414

zorglub's avatar
zorglub committed
415
416
417
418
419
/*****************************************************************************
 * __net_ReadNonBlock:
 *****************************************************************************
 * Read from a network socket, non blocking mode (with timeout)
 *****************************************************************************/
420
421
422
ssize_t __net_ReadNonBlock( vlc_object_t *restrict p_this, int fd,
                            const v_socket_t *restrict p_vs,
                            uint8_t *restrict buf, size_t len, mtime_t i_wait)
zorglub's avatar
zorglub committed
423
{
424
425
    return net_ReadInner (p_this, 1, &(int){ fd },
                          &(const v_socket_t *){ p_vs },
426
                          buf, len, i_wait / 1000, VLC_FALSE);
zorglub's avatar
zorglub committed
427
428
}

429

zorglub's avatar
zorglub committed
430
431
432
/*****************************************************************************
 * __net_Select:
 *****************************************************************************
433
434
 * Read from several sockets (with timeout). Takes data from the first socket
 * that has some.
zorglub's avatar
zorglub committed
435
 *****************************************************************************/
436
437
438
ssize_t __net_Select( vlc_object_t *restrict p_this,
                      const int *restrict fds, int nfd,
                      uint8_t *restrict buf, size_t len, mtime_t i_wait )
zorglub's avatar
zorglub committed
439
{
440
    const v_socket_t *vsv[nfd];
441
    memset( vsv, 0, sizeof (vsv) );
zorglub's avatar
zorglub committed
442

443
    return net_ReadInner( p_this, nfd, fds, vsv, buf, len,
444
                          i_wait / 1000, VLC_FALSE );
zorglub's avatar
zorglub committed
445
446
447
}


Laurent Aimar's avatar
 
Laurent Aimar committed
448
/* Write exact amount requested */
449
450
ssize_t __net_Write( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
                     const uint8_t *p_data, size_t i_data )
Laurent Aimar's avatar
 
Laurent Aimar committed
451
{
452
    size_t i_total = 0;
Laurent Aimar's avatar
 
Laurent Aimar committed
453

454
    while( i_data > 0 )
Laurent Aimar's avatar
 
Laurent Aimar committed
455
    {
456
        if( p_this->b_die )
457
            break;
Laurent Aimar's avatar
 
Laurent Aimar committed
458

459
460
461
462
        struct pollfd ufd[1];
        memset (ufd, 0, sizeof (ufd));
        ufd[0].fd = fd;
        ufd[0].events = POLLOUT;
463

464
465
        int val = poll (ufd, 1, 500);
        switch (val)
Laurent Aimar's avatar
 
Laurent Aimar committed
466
        {
467
            case -1:
468
469
               msg_Err (p_this, "Write error: %s", net_strerror (net_errno));
               goto out;
470
471
472

            case 0:
                continue;
Laurent Aimar's avatar
 
Laurent Aimar committed
473
474
        }

475
476
477
        if ((ufd[0].revents & POLLERR) && (i_total > 0))
            return i_total; // error will be dequeued separately on next call

478
479
480
481
        if (p_vs != NULL)
            val = p_vs->pf_send (p_vs->p_sys, p_data, i_data);
        else
#if defined(WIN32) || defined(UNDER_CE)
zorglub's avatar
zorglub committed
482
            val = send (fd, p_data, i_data, 0);
483
484
485
486
487
#else
            val = write (fd, p_data, i_data);
#endif

        if (val == -1)
488
489
490
491
        {
            msg_Err (p_this, "Write error: %s", net_strerror (net_errno));
            break;
        }
492
        if (val == 0)
493
            return i_total;
494
495
496

        p_data += val;
        i_data -= val;
497
        i_total += val;
Laurent Aimar's avatar
 
Laurent Aimar committed
498
    }
499

500
501
502
503
504
out:
    if ((i_total > 0) || (i_data == 0))
        return i_total;

    return -1;
Laurent Aimar's avatar
 
Laurent Aimar committed
505
506
}

507
char *__net_Gets( vlc_object_t *p_this, int fd, const v_socket_t *p_vs )
Laurent Aimar's avatar
 
Laurent Aimar committed
508
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
509
510
    char *psz_line = NULL, *ptr = NULL;
    size_t  i_line = 0, i_max = 0;
Laurent Aimar's avatar
 
Laurent Aimar committed
511
512
513
514


    for( ;; )
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
515
        if( i_line == i_max )
Laurent Aimar's avatar
 
Laurent Aimar committed
516
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
517
518
519
            i_max += 1024;
            psz_line = realloc( psz_line, i_max );
            ptr = psz_line + i_line;
Laurent Aimar's avatar
 
Laurent Aimar committed
520
        }
521

522
        if( net_Read( p_this, fd, p_vs, (uint8_t *)ptr, 1, VLC_TRUE ) != 1 )
Laurent Aimar's avatar
 
Laurent Aimar committed
523
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
524
525
526
527
528
            if( i_line == 0 )
            {
                free( psz_line );
                return NULL;
            }
Laurent Aimar's avatar
 
Laurent Aimar committed
529
530
531
            break;
        }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
532
533
        if ( *ptr == '\n' )
            break;
Laurent Aimar's avatar
 
Laurent Aimar committed
534

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
535
536
        i_line++;
        ptr++;
Laurent Aimar's avatar
 
Laurent Aimar committed
537
538
    }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
539
540
    *ptr-- = '\0';

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
541
    if( ( ptr >= psz_line ) && ( *ptr == '\r' ) )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
542
543
        *ptr = '\0';

Laurent Aimar's avatar
 
Laurent Aimar committed
544
545
546
    return psz_line;
}

547
548
ssize_t net_Printf( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
                    const char *psz_fmt, ... )
Laurent Aimar's avatar
 
Laurent Aimar committed
549
{
550
    int i_ret;
Laurent Aimar's avatar
 
Laurent Aimar committed
551
    va_list args;
552
    va_start( args, psz_fmt );
553
    i_ret = net_vaPrintf( p_this, fd, p_vs, psz_fmt, args );
554
555
556
557
558
    va_end( args );

    return i_ret;
}

559
560
ssize_t __net_vaPrintf( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
                        const char *psz_fmt, va_list args )
561
{
Laurent Aimar's avatar
 
Laurent Aimar committed
562
    char    *psz;
563
    int     i_size, i_ret;
Laurent Aimar's avatar
 
Laurent Aimar committed
564

565
    i_size = vasprintf( &psz, psz_fmt, args );
566
567
    i_ret = __net_Write( p_this, fd, p_vs, (uint8_t *)psz, i_size ) < i_size
        ? -1 : i_size;
568
569
570
    free( psz );

    return i_ret;
Laurent Aimar's avatar
 
Laurent Aimar committed
571
}
572
573


Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
574
575
576
577
578
579
580
581
582
583
584
585
586
/*****************************************************************************
 * inet_pton replacement for obsolete and/or crap operating systems
 *****************************************************************************/
#ifndef HAVE_INET_PTON
int inet_pton(int af, const char *src, void *dst)
{
# ifdef WIN32
    /* As we already know, Microsoft always go its own way, so even if they do
     * provide IPv6, they don't provide the API. */
    struct sockaddr_storage addr;
    int len = sizeof( addr );

    /* Damn it, they didn't even put LPCSTR for the firs parameter!!! */
gbazin's avatar
gbazin committed
587
588
589
590
591
592
#ifdef UNICODE
    wchar_t *workaround_for_ill_designed_api =
        malloc( MAX_PATH * sizeof(wchar_t) );
    mbstowcs( workaround_for_ill_designed_api, src, MAX_PATH );
    workaround_for_ill_designed_api[MAX_PATH-1] = 0;
#else
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
593
    char *workaround_for_ill_designed_api = strdup( src );
gbazin's avatar
gbazin committed
594
595
#endif

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
596
597
598
599
600
601
602
603
604
605
606
607
608
    if( !WSAStringToAddress( workaround_for_ill_designed_api, af, NULL,
                             (LPSOCKADDR)&addr, &len ) )
    {
        free( workaround_for_ill_designed_api );
        return -1;
    }
    free( workaround_for_ill_designed_api );

    switch( af )
    {
        case AF_INET6:
            memcpy( dst, &((struct sockaddr_in6 *)&addr)->sin6_addr, 16 );
            break;
609

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
        case AF_INET:
            memcpy( dst, &((struct sockaddr_in *)&addr)->sin_addr, 4 );
            break;

        default:
            WSASetLastError( WSAEAFNOSUPPORT );
            return -1;
    }
# else
    /* Assume IPv6 is not supported. */
    /* Would be safer and more simpler to use inet_aton() but it is most
     * likely not provided either. */
    uint32_t ipv4;

    if( af != AF_INET )
    {
        errno = EAFNOSUPPORT;
        return -1;
    }

    ipv4 = inet_addr( src );
    if( ipv4 == INADDR_NONE )
        return -1;

Eric Petit's avatar
Eric Petit committed
634
    memcpy( dst, &ipv4, 4 );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
635
636
637
638
# endif /* WIN32 */
    return 0;
}
#endif /* HAVE_INET_PTON */
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689

#ifndef HAVE_INET_NTOP
#ifdef WIN32
const char *inet_ntop(int af, const void * src,
                               char * dst, socklen_t cnt)
{
    switch( af )
    {
#ifdef AF_INET6
        case AF_INET6:
            {
                struct sockaddr_in6 addr;
                memset(&addr, 0, sizeof(addr));
                addr.sin6_family = AF_INET6;
                addr.sin6_addr = *((struct in6_addr*)src);
                if( 0 == WSAAddressToStringA((LPSOCKADDR)&addr, 
                                             sizeof(struct sockaddr_in6), 
                                             NULL, dst, &cnt) )
                {
                    dst[cnt] = '\0';
                    return dst;
                }
                errno = WSAGetLastError();
                return NULL;

            }

#endif
        case AF_INET:
            {
                struct sockaddr_in addr;
                memset(&addr, 0, sizeof(addr));
                addr.sin_family = AF_INET;
                addr.sin_addr = *((struct in_addr*)src);
                if( 0 == WSAAddressToStringA((LPSOCKADDR)&addr,
                                             sizeof(struct sockaddr_in),
                                             NULL, dst, &cnt) )
                {
                    dst[cnt] = '\0';
                    return dst;
                }
                errno = WSAGetLastError();
                return NULL;

            }
    }
    errno = EAFNOSUPPORT;
    return NULL;
}
#endif
#endif