io.c 18.5 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

31
32
33
34
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

35
#include <vlc_common.h>
Laurent Aimar's avatar
   
Laurent Aimar committed
36

37
38
#include <stdlib.h>
#include <stdio.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
39
#include <limits.h>
40

41
#include <errno.h>
42
#include <assert.h>
Laurent Aimar's avatar
   
Laurent Aimar committed
43
44
45
46
47
48
49

#ifdef HAVE_FCNTL_H
#   include <fcntl.h>
#endif
#ifdef HAVE_SYS_TIME_H
#    include <sys/time.h>
#endif
gbazin's avatar
gbazin committed
50
51
52
#ifdef HAVE_UNISTD_H
#   include <unistd.h>
#endif
53
#ifdef HAVE_POLL
54
#   include <poll.h>
55
#endif
gbazin's avatar
gbazin committed
56

zorglub's avatar
zorglub committed
57
#include <vlc_network.h>
Laurent Aimar's avatar
   
Laurent Aimar committed
58

59
60
61
62
63
64
65
#ifndef INADDR_ANY
#   define INADDR_ANY  0x00000000
#endif
#ifndef INADDR_NONE
#   define INADDR_NONE 0xFFFFFFFF
#endif

66
#if defined(WIN32) || defined(UNDER_CE)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
67
68
# undef EAFNOSUPPORT
# define EAFNOSUPPORT WSAEAFNOSUPPORT
69
70
#endif

71
72
73
74
75
76
#ifdef HAVE_LINUX_DCCP_H
/* TODO: use glibc instead of linux-kernel headers */
# include <linux/dccp.h>
# define SOL_DCCP 269
#endif

77
78
79
extern int rootwrap_bind (int family, int socktype, int protocol,
                          const struct sockaddr *addr, size_t alen);

80
81
82
83
84
85
86
87
88
89
90
91
92
93
int net_SetupSocket (int fd)
{
#if defined (WIN32) || defined (UNDER_CE)
    ioctlsocket (fd, FIONBIO, &(unsigned long){ 1 });
#else
    fcntl (fd, F_SETFD, FD_CLOEXEC);
    fcntl (fd, F_SETFL, fcntl (fd, F_GETFL, 0) | O_NONBLOCK);
#endif

    setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof (int));
    return 0;
}


Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
94
95
96
97
98
int net_Socket (vlc_object_t *p_this, int family, int socktype,
                int protocol)
{
    int fd = socket (family, socktype, protocol);
    if (fd == -1)
99
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
100
        if (net_errno != EAFNOSUPPORT)
101
            msg_Err (p_this, "cannot create socket: %m");
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
102
        return -1;
103
    }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
104

105
    net_SetupSocket (fd);
106
107
108

#ifdef IPV6_V6ONLY
    /*
109
     * Accepts only IPv6 connections on IPv6 sockets.
110
     * If possible, we should open two sockets, but it is not always possible.
111
     */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
112
    if (family == AF_INET6)
113
        setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){ 1 }, sizeof (int));
114
115
#endif

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
116
#if defined (WIN32) || defined (UNDER_CE)
117
# ifndef IPV6_PROTECTION_LEVEL
118
#  warning Please update your C library headers.
119
#  define IPV6_PROTECTION_LEVEL 23
120
#  define PROTECTION_LEVEL_UNRESTRICTED 10
121
# endif
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
122
123
124
    if (family == AF_INET6)
        setsockopt (fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL,
                    &(int){ PROTECTION_LEVEL_UNRESTRICTED }, sizeof (int));
125
#endif
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
126

127
#ifdef DCCP_SOCKOPT_SERVICE
128
    if (socktype == SOL_DCCP)
129
    {
130
131
132
133
134
135
136
        char *dccps = var_CreateGetNonEmptyString (p_this, "dccp-service");
        if (dccps != NULL)
        {
            setsockopt (fd, SOL_DCCP, DCCP_SOCKOPT_SERVICE, dccps,
                        (strlen (dccps) + 3) & ~3);
            free (dccps);
        }
137
138
139
    }
#endif

140
141
142
    return fd;
}

Laurent Aimar's avatar
Laurent Aimar committed
143

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
144
int *net_Listen (vlc_object_t *p_this, const char *psz_host,
145
                 int i_port, int protocol)
146
147
{
    struct addrinfo hints, *res;
148
149
150
151
152
153
154
155
156
    int socktype = SOCK_DGRAM;

    switch( protocol )
    {
        case IPPROTO_TCP:
            socktype = SOCK_STREAM;
            break;
        case 33: /* DCCP */
#ifdef __linux__
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
157
158
159
160
# ifndef SOCK_DCCP
#  define SOCK_DCCP 6
# endif
            socktype = SOCK_DCCP;
161
162
163
#endif
            break;
    }
164
165

    memset (&hints, 0, sizeof( hints ));
166
167
    /* Since we use port numbers rather than service names, the socket type
     * does not really matter. */
168
    hints.ai_socktype = SOCK_DGRAM;
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
    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)
    {
186
        int fd = net_Socket (p_this, ptr->ai_family, socktype, protocol);
187
188
        if (fd == -1)
        {
189
            msg_Dbg (p_this, "socket error: %m");
190
191
192
193
            continue;
        }

        /* Bind the socket */
194
#if defined (WIN32) || defined (UNDER_CE)
195
196
197
198
199
200
201
202
203
        /*
         * 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))
        {
204
205
            // This works for IPv4 too - don't worry!
            struct sockaddr_in6 dumb =
206
            {
207
208
                .sin6_family = ptr->ai_addr->sa_family,
                .sin6_port =  ((struct sockaddr_in *)(ptr->ai_addr))->sin_port
209
210
211
212
213
214
            };

            bind (fd, (struct sockaddr *)&dumb, ptr->ai_addrlen);
        }
        else
#endif
215
216
217
218
        if (bind (fd, ptr->ai_addr, ptr->ai_addrlen))
        {
            net_Close (fd);
#if !defined(WIN32) && !defined(UNDER_CE)
219
            fd = rootwrap_bind (ptr->ai_family, socktype,
220
                                protocol ?: ptr->ai_protocol, ptr->ai_addr,
221
222
223
224
225
226
227
228
                                ptr->ai_addrlen);
            if (fd != -1)
            {
                msg_Dbg (p_this, "got socket %d from rootwrap", fd);
            }
            else
#endif
            {
229
                msg_Err (p_this, "socket bind error (%m)");
230
231
232
233
                continue;
            }
        }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
234
235
236
237
238
239
240
241
242
        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;
            }
        }

243
        /* Listen */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
244
        switch (socktype)
245
246
247
248
        {
            case SOCK_STREAM:
            case SOCK_RDM:
            case SOCK_SEQPACKET:
249
250
251
#ifdef SOCK_DCCP
            case SOCK_DCCP:
#endif
252
253
                if (listen (fd, INT_MAX))
                {
254
                    msg_Err (p_this, "socket listen error (%m)");
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
                    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;
}


279
280
281
/*****************************************************************************
 * __net_Read:
 *****************************************************************************
282
 * Reads from a network socket.
283
 * If waitall is true, then we repeat until we have read the right amount of
284
285
 * data; in that case, a short count means EOF has been reached or the VLC
 * object has been signaled.
286
287
288
 *****************************************************************************/
ssize_t
__net_Read (vlc_object_t *restrict p_this, int fd, const v_socket_t *vs,
289
            uint8_t *restrict p_buf, size_t i_buflen, bool waitall)
290
{
291
    size_t i_total = 0;
292
    struct pollfd ufd[2] = {
293
294
        { .fd = fd,                           .events = POLLIN },
        { .fd = vlc_object_waitpipe (p_this), .events = POLLIN },
295
    };
296

297
298
299
    if (ufd[1].fd == -1)
        return -1; /* vlc_object_waitpipe() sets errno */

300
    while (i_buflen > 0)
301
    {
302
        ufd[0].revents = ufd[1].revents = 0;
303

304
        if (poll (ufd, sizeof (ufd) / sizeof (ufd[0]), -1) < 0)
305
        {
306
            if (errno != EINTR)
307
                goto error;
308
            continue;
309
        }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
310

Christophe Mutricy's avatar
Christophe Mutricy committed
311
#ifndef POLLRDHUP /* This is nice but non-portable */
312
313
# define POLLRDHUP 0
#endif
314
315
316
317
318
319
        if (i_total > 0)
        {
            /* Errors (-1) and EOF (0) will be returned on next call,
             * otherwise we'd "hide" the error from the caller, which is a
             * bad idea™. */
            if (ufd[0].revents & (POLLERR|POLLNVAL|POLLRDHUP))
320
                break;
321
322
323
324
325
326
327
            if (ufd[1].revents)
                break;
        }
        else
        {
            if (ufd[1].revents)
            {
328
                assert (p_this->b_die);
329
330
331
332
333
334
                msg_Dbg (p_this, "socket %d polling interrupted", fd);
#if defined(WIN32) || defined(UNDER_CE)
                WSASetLastError (WSAEINTR);
#else
                errno = EINTR;
#endif
335
                goto silent;
336
            }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
337
        }
338

339
340
        assert (ufd[0].revents);

341
        ssize_t n;
342
        if (vs != NULL)
343
        {
344
            n = vs->pf_recv (vs->p_sys, p_buf, i_buflen);
345
        }
346
        else
347
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
348
#ifdef WIN32
349
            n = recv (fd, p_buf, i_buflen, 0);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
350
#else
351
            n = read (fd, p_buf, i_buflen);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
352
#endif
353
        }
354

355
        if (n == -1)
356
357
        {
#if defined(WIN32) || defined(UNDER_CE)
358
            switch (WSAGetLastError ())
359
360
            {
                case WSAEWOULDBLOCK:
361
                /* only happens with vs != NULL (TLS) - not really an error */
362
363
364
365
366
367
368
                    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. */
369
370
                    msg_Err (p_this, "Receive error: "
                                     "Increase the mtu size (--mtu option)");
371
372
                    n = i_buflen;
                    break;
373
374
            }
#else
375
376
377
378
379
380
            switch (errno)
            {
                case EAGAIN: /* spurious wakeup or no TLS data */
                case EINTR:  /* asynchronous signal */
                    continue;
            }
381
#endif
382
            goto error;
383
384
        }

385
386
387
388
389
390
391
392
393
        if (n == 0)
            /* For streams, this means end of file, and there will not be any
             * further data ever on the stream. For datagram sockets, this
             * means empty datagram, and there could be more data coming.
             * However, it makes no sense to set <waitall> with datagrams in the
             * first place.
             */
            break; // EOF

394
395
396
        i_total += n;
        p_buf += n;
        i_buflen -= n;
Rémi Denis-Courmont's avatar
Fixes    
Rémi Denis-Courmont committed
397

398
        if (!waitall)
399
            break;
400
    }
401

damienf's avatar
damienf committed
402
    return i_total;
403
404

error:
405
    msg_Err (p_this, "Read error: %m");
406
silent:
407
    return -1;
408
409
410
}


Laurent Aimar's avatar
   
Laurent Aimar committed
411
/* Write exact amount requested */
412
413
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
414
{
415
    size_t i_total = 0;
416
417
418
419
420
421
422
    struct pollfd ufd[2] = {
        { .fd = fd,                           .events = POLLOUT },
        { .fd = vlc_object_waitpipe (p_this), .events = POLLIN  },
    };

    if (ufd[1].fd == -1)
        return -1;
Laurent Aimar's avatar
   
Laurent Aimar committed
423

424
    while( i_data > 0 )
Laurent Aimar's avatar
   
Laurent Aimar committed
425
    {
426
        ssize_t val;
Laurent Aimar's avatar
   
Laurent Aimar committed
427

428
        ufd[0].revents = ufd[1].revents = 0;
429

430
        if (poll (ufd, 1, -1) == -1)
Laurent Aimar's avatar
   
Laurent Aimar committed
431
        {
432
433
434
435
            if (errno == EINTR)
                continue;
            msg_Err (p_this, "Polling error: %m");
            return -1;
Laurent Aimar's avatar
   
Laurent Aimar committed
436
437
        }

438
        if (i_total > 0)
439
440
441
442
        {   /* If POLLHUP resp. POLLERR|POLLNVAL occurs while we have already
             * read some data, it is important that we first return the number
             * of bytes read, and then return 0 resp. -1 on the NEXT call. */
            if (ufd[0].revents & (POLLHUP|POLLERR|POLLNVAL))
443
                break;
444
            if (ufd[1].revents) /* VLC object signaled */
445
446
                break;
        }
447
448
449
450
451
452
453
454
455
        else
        {
            if (ufd[1].revents)
            {
                assert (p_this->b_die);
                errno = EINTR;
                goto error;
            }
        }
456

457
458
459
        if (p_vs != NULL)
            val = p_vs->pf_send (p_vs->p_sys, p_data, i_data);
        else
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
460
#ifdef WIN32
zorglub's avatar
zorglub committed
461
            val = send (fd, p_data, i_data, 0);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
462
463
464
#else
            val = write (fd, p_data, i_data);
#endif
465
466

        if (val == -1)
467
        {
468
469
            if (errno == EINTR)
                continue;
470
            msg_Err (p_this, "Write error: %m");
471
472
            break;
        }
473
474
475

        p_data += val;
        i_data -= val;
476
        i_total += val;
Laurent Aimar's avatar
   
Laurent Aimar committed
477
    }
478

479
480
481
    if ((i_total > 0) || (i_data == 0))
        return i_total;

482
error:
483
    return -1;
Laurent Aimar's avatar
   
Laurent Aimar committed
484
485
}

486
char *__net_Gets( vlc_object_t *p_this, int fd, const v_socket_t *p_vs )
Laurent Aimar's avatar
   
Laurent Aimar committed
487
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
488
489
    char *psz_line = NULL, *ptr = NULL;
    size_t  i_line = 0, i_max = 0;
Laurent Aimar's avatar
   
Laurent Aimar committed
490
491
492
493


    for( ;; )
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
494
        if( i_line == i_max )
Laurent Aimar's avatar
   
Laurent Aimar committed
495
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
496
497
498
            i_max += 1024;
            psz_line = realloc( psz_line, i_max );
            ptr = psz_line + i_line;
Laurent Aimar's avatar
   
Laurent Aimar committed
499
        }
500

501
        if( net_Read( p_this, fd, p_vs, (uint8_t *)ptr, 1, true ) != 1 )
Laurent Aimar's avatar
   
Laurent Aimar committed
502
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
503
504
505
506
507
            if( i_line == 0 )
            {
                free( psz_line );
                return NULL;
            }
Laurent Aimar's avatar
   
Laurent Aimar committed
508
509
510
            break;
        }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
511
512
        if ( *ptr == '\n' )
            break;
Laurent Aimar's avatar
   
Laurent Aimar committed
513

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
514
515
        i_line++;
        ptr++;
Laurent Aimar's avatar
   
Laurent Aimar committed
516
517
    }

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

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
520
    if( ( ptr >= psz_line ) && ( *ptr == '\r' ) )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
521
522
        *ptr = '\0';

Laurent Aimar's avatar
   
Laurent Aimar committed
523
524
525
    return psz_line;
}

526
527
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
528
{
529
    int i_ret;
Laurent Aimar's avatar
   
Laurent Aimar committed
530
    va_list args;
531
    va_start( args, psz_fmt );
532
    i_ret = net_vaPrintf( p_this, fd, p_vs, psz_fmt, args );
533
534
535
536
537
    va_end( args );

    return i_ret;
}

538
539
ssize_t __net_vaPrintf( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
                        const char *psz_fmt, va_list args )
540
{
Laurent Aimar's avatar
   
Laurent Aimar committed
541
    char    *psz;
542
    int     i_size, i_ret;
Laurent Aimar's avatar
   
Laurent Aimar committed
543

544
    i_size = vasprintf( &psz, psz_fmt, args );
545
546
    i_ret = __net_Write( p_this, fd, p_vs, (uint8_t *)psz, i_size ) < i_size
        ? -1 : i_size;
547
548
549
    free( psz );

    return i_ret;
Laurent Aimar's avatar
   
Laurent Aimar committed
550
}
551
552


Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
553
554
555
/*****************************************************************************
 * inet_pton replacement for obsolete and/or crap operating systems
 *****************************************************************************/
556
int vlc_inet_pton(int af, const char *src, void *dst)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
557
{
558
#ifndef HAVE_INET_PTON
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
559
560
561
562
563
564
565
# 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
566
567
568
569
570
571
#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
572
    char *workaround_for_ill_designed_api = strdup( src );
gbazin's avatar
gbazin committed
573
574
#endif

575
    if( WSAStringToAddress( workaround_for_ill_designed_api, af, NULL,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
576
577
578
579
580
581
582
583
584
585
586
587
                             (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;
588

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
        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
613
    memcpy( dst, &ipv4, 4 );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
614
615
# endif /* WIN32 */
    return 0;
616
617
#else /* HAVE_INET_PTON */
    return inet_pton( af, src, dst );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
618
#endif /* HAVE_INET_PTON */
619
}
620

621
const char *vlc_inet_ntop(int af, const void * src,
622
623
                               char * dst, socklen_t cnt)
{
624
625
#ifndef HAVE_INET_NTOP
#ifdef WIN32
626
627
628
629
630
631
632
633
634
    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);
635
636
                if( 0 == WSAAddressToStringA((LPSOCKADDR)&addr,
                                             sizeof(struct sockaddr_in6),
637
638
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
                                             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;
668
669
670
671
672
673
#else /* WIN32 */
    return NULL;
#endif /* WIN32 */
#else /* HAVE_INET_NTOP */
    return inet_ntop( af, src, dst, cnt );
#endif /* HAVE_INET_NTOP */
674
}
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689

#ifdef WIN32
    /* vlc_sendmsg, vlc_recvmsg Defined in winsock.c */
#else /* !WIN32 */
ssize_t vlc_sendmsg (int s, struct msghdr *hdr, int flags)
{
    return sendmsg (s, hdr, flags);
}

ssize_t vlc_recvmsg (int s, struct msghdr *hdr, int flags)
{
    return recvmsg (s, hdr, flags);
}
#endif /* WIN32 */