io.c 17.6 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);

70
71
72
73
74
75
76
77
78
79
80
81
82
83
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
84
85
86
87
88
int net_Socket (vlc_object_t *p_this, int family, int socktype,
                int protocol)
{
    int fd = socket (family, socktype, protocol);
    if (fd == -1)
89
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
90
        if (net_errno != EAFNOSUPPORT)
91
            msg_Err (p_this, "cannot create socket: %m");
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
92
        return -1;
93
    }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
94

95
    net_SetupSocket (fd);
96
97
98

#ifdef IPV6_V6ONLY
    /*
99
     * Accepts only IPv6 connections on IPv6 sockets.
100
     * If possible, we should open two sockets, but it is not always possible.
101
     */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
102
    if (family == AF_INET6)
103
        setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){ 1 }, sizeof (int));
104
105
#endif

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

117
118
119
    return fd;
}

Laurent Aimar's avatar
Laurent Aimar committed
120

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
121
int *net_Listen (vlc_object_t *p_this, const char *psz_host,
122
                 int i_port, int protocol)
123
124
{
    struct addrinfo hints, *res;
125
126
127
128
129
130
131
132
133
    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
134
135
136
137
# ifndef SOCK_DCCP
#  define SOCK_DCCP 6
# endif
            socktype = SOCK_DCCP;
138
139
140
#endif
            break;
    }
141
142

    memset (&hints, 0, sizeof( hints ));
143
144
    /* Since we use port numbers rather than service names, the socket type
     * does not really matter. */
145
    hints.ai_socktype = SOCK_DGRAM;
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
    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)
    {
163
        int fd = net_Socket (p_this, ptr->ai_family, socktype, protocol);
164
165
        if (fd == -1)
        {
166
            msg_Dbg (p_this, "socket error: %m");
167
168
169
170
            continue;
        }

        /* Bind the socket */
171
#if defined (WIN32) || defined (UNDER_CE)
172
173
174
175
176
177
178
179
180
        /*
         * 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))
        {
181
182
            // This works for IPv4 too - don't worry!
            struct sockaddr_in6 dumb =
183
            {
184
185
                .sin6_family = ptr->ai_addr->sa_family,
                .sin6_port =  ((struct sockaddr_in *)(ptr->ai_addr))->sin_port
186
187
188
189
190
191
            };

            bind (fd, (struct sockaddr *)&dumb, ptr->ai_addrlen);
        }
        else
#endif
192
193
194
195
196
        if (bind (fd, ptr->ai_addr, ptr->ai_addrlen))
        {
            net_Close (fd);
#if !defined(WIN32) && !defined(UNDER_CE)
            fd = rootwrap_bind (ptr->ai_family, ptr->ai_socktype,
197
                                protocol ?: ptr->ai_protocol, ptr->ai_addr,
198
199
200
201
202
203
204
205
                                ptr->ai_addrlen);
            if (fd != -1)
            {
                msg_Dbg (p_this, "got socket %d from rootwrap", fd);
            }
            else
#endif
            {
206
                msg_Err (p_this, "socket bind error (%m)");
207
208
209
210
                continue;
            }
        }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
211
212
213
214
215
216
217
218
219
        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;
            }
        }

220
        /* Listen */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
221
        switch (socktype)
222
223
224
225
        {
            case SOCK_STREAM:
            case SOCK_RDM:
            case SOCK_SEQPACKET:
226
227
228
#ifdef SOCK_DCCP
            case SOCK_DCCP:
#endif
229
230
                if (listen (fd, INT_MAX))
                {
231
                    msg_Err (p_this, "socket listen error (%m)");
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
                    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;
}


256
257
258
static ssize_t
net_ReadInner (vlc_object_t *restrict p_this, unsigned fdc, const int *fdv,
               const v_socket_t *const *restrict vsv,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
259
               uint8_t *restrict p_buf, size_t i_buflen, vlc_bool_t waitall)
260
{
261
    size_t i_total = 0;
262

263
    while (i_buflen > 0)
264
    {
265
        if( ( p_this->b_die ) || ( p_this->p_libvlc->b_die ) )
266
        {
267
#if defined(WIN32) || defined(UNDER_CE)
268
            WSASetLastError (WSAEINTR);
269
#else
Rafaël Carré's avatar
Rafaël Carré committed
270
271
            if( p_this->b_die ) printf("b_die\n");
            else printf("p_libvlc->b_die\n");
272
            errno = EINTR;
273
#endif
274
275
276
            goto error;
        }

277
        struct pollfd ufd[fdc];
278

279
        for (unsigned i = 0; i < fdc; i++)
280
        {
281
            ufd[i].fd = fdv[i];
282
            ufd[i].events = POLLIN;
283
            ufd[i].revents = 0;
284
285
        }

286
        switch (poll (ufd, fdc, 500))
287
288
289
        {
            case -1:
                goto error;
290

291
292
293
            case 0: // timeout
                continue;
        }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
294

295
        for (unsigned i = 0;; i++)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
296
        {
297
            assert (i < fdc); /* no events found = bug ! */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
298

299
            if (ufd[i].revents == 0)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
300
                continue;
301

Christophe Mutricy's avatar
Christophe Mutricy committed
302
#ifndef POLLRDHUP /* This is nice but non-portable */
303
304
# define POLLRDHUP 0
#endif
305
306
307
            if (i_total > 0)
            {
                // Errors (-1) and EOF (0) will be returned on next run
308
                if (ufd[i].revents & (POLLERR|POLLNVAL|POLLRDHUP))
309
310
311
312
                    return i_total;
            }
            else
            {
313
                if (ufd[i].revents & POLLRDHUP)
314
315
316
317
318
319
                    return 0; // EOF, read() would yield 0
            }

            fdc = 1;
            fdv += i;
            vsv += i;
320

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
321
322
            break;
        }
323

324
325
        ssize_t n;
        if (*vsv != NULL)
326
        {
327
            n = (*vsv)->pf_recv ((*vsv)->p_sys, p_buf, i_buflen);
328
        }
329
        else
330
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
331
#ifdef WIN32
332
            n = recv (*fdv, p_buf, i_buflen, 0);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
333
334
335
#else
            n = read (*fdv, p_buf, i_buflen);
#endif
336
        }
337

338
        if (n == -1)
339
340
        {
#if defined(WIN32) || defined(UNDER_CE)
341
            switch (WSAGetLastError ())
342
343
344
345
346
347
348
349
350
351
            {
                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. */
352
353
                    msg_Err (p_this, "Receive error: "
                                     "Increase the mtu size (--mtu option)");
354
355
356
357
358
                    n = i_buflen;
                    break;

                default:
                    goto error;
359
360
            }
#else
361
362
            /* spurious wake-up or TLS did not yield any actual data */
            if (errno == EAGAIN)
363
364
                continue;
            goto error;
365
#endif
366
367
        }

368
369
370
        i_total += n;
        p_buf += n;
        i_buflen -= n;
Rémi Denis-Courmont's avatar
Fixes    
Rémi Denis-Courmont committed
371

372
        if ((n == 0) || !waitall)
373
            break;
374
    }
damienf's avatar
damienf committed
375
    return i_total;
376
377

error:
378
    msg_Err (p_this, "Read error: %m");
Rémi Denis-Courmont's avatar
Oups    
Rémi Denis-Courmont committed
379
    return i_total ? (ssize_t)i_total : -1;
380
381
382
}


Laurent Aimar's avatar
   
Laurent Aimar committed
383
384
385
386
/*****************************************************************************
 * __net_Read:
 *****************************************************************************
 * Read from a network socket
387
 * If b_retry is true, then we repeat until we have read the right amount of
388
 * data; in that case, a short count means EOF has been reached.
Laurent Aimar's avatar
   
Laurent Aimar committed
389
 *****************************************************************************/
390
391
392
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
393
{
394
    return net_ReadInner( p_this, 1, &(int){ fd },
395
                          &(const v_socket_t *){ p_vs },
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
396
                          buf, len, b_retry );
Laurent Aimar's avatar
   
Laurent Aimar committed
397
398
}

399

zorglub's avatar
zorglub committed
400
401
402
/*****************************************************************************
 * __net_Select:
 *****************************************************************************
403
 * Read from several sockets. Takes data from the first socket that has some.
zorglub's avatar
zorglub committed
404
 *****************************************************************************/
405
406
ssize_t __net_Select( vlc_object_t *restrict p_this,
                      const int *restrict fds, int nfd,
407
                      uint8_t *restrict buf, size_t len )
zorglub's avatar
zorglub committed
408
{
409
    const v_socket_t *vsv[nfd];
410
    memset( vsv, 0, sizeof (vsv) );
zorglub's avatar
zorglub committed
411

412
    return net_ReadInner( p_this, nfd, fds, vsv,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
413
                          buf, len, VLC_FALSE );
zorglub's avatar
zorglub committed
414
415
416
}


Laurent Aimar's avatar
   
Laurent Aimar committed
417
/* Write exact amount requested */
418
419
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
420
{
421
    size_t i_total = 0;
Laurent Aimar's avatar
   
Laurent Aimar committed
422

423
    while( i_data > 0 )
Laurent Aimar's avatar
   
Laurent Aimar committed
424
    {
425
        if( p_this->b_die )
426
            break;
Laurent Aimar's avatar
   
Laurent Aimar committed
427

428
429
430
431
        struct pollfd ufd[1];
        memset (ufd, 0, sizeof (ufd));
        ufd[0].fd = fd;
        ufd[0].events = POLLOUT;
432

433
434
        int val = poll (ufd, 1, 500);
        switch (val)
Laurent Aimar's avatar
   
Laurent Aimar committed
435
        {
436
            case -1:
437
               msg_Err (p_this, "Write error: %m");
438
               goto out;
439
440
441

            case 0:
                continue;
Laurent Aimar's avatar
   
Laurent Aimar committed
442
443
        }

444
        if ((ufd[0].revents & (POLLERR|POLLNVAL|POLLHUP)) && (i_total > 0))
445
446
            return i_total; // error will be dequeued separately on next call

447
448
449
        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
450
#ifdef WIN32
zorglub's avatar
zorglub committed
451
            val = send (fd, p_data, i_data, 0);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
452
453
454
#else
            val = write (fd, p_data, i_data);
#endif
455
456

        if (val == -1)
457
        {
458
            msg_Err (p_this, "Write error: %m");
459
460
            break;
        }
461
462
463

        p_data += val;
        i_data -= val;
464
        i_total += val;
Laurent Aimar's avatar
   
Laurent Aimar committed
465
    }
466

467
468
469
470
471
out:
    if ((i_total > 0) || (i_data == 0))
        return i_total;

    return -1;
Laurent Aimar's avatar
   
Laurent Aimar committed
472
473
}

474
char *__net_Gets( vlc_object_t *p_this, int fd, const v_socket_t *p_vs )
Laurent Aimar's avatar
   
Laurent Aimar committed
475
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
476
477
    char *psz_line = NULL, *ptr = NULL;
    size_t  i_line = 0, i_max = 0;
Laurent Aimar's avatar
   
Laurent Aimar committed
478
479
480
481


    for( ;; )
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
482
        if( i_line == i_max )
Laurent Aimar's avatar
   
Laurent Aimar committed
483
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
484
485
486
            i_max += 1024;
            psz_line = realloc( psz_line, i_max );
            ptr = psz_line + i_line;
Laurent Aimar's avatar
   
Laurent Aimar committed
487
        }
488

489
        if( net_Read( p_this, fd, p_vs, (uint8_t *)ptr, 1, VLC_TRUE ) != 1 )
Laurent Aimar's avatar
   
Laurent Aimar committed
490
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
491
492
493
494
495
            if( i_line == 0 )
            {
                free( psz_line );
                return NULL;
            }
Laurent Aimar's avatar
   
Laurent Aimar committed
496
497
498
            break;
        }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
499
500
        if ( *ptr == '\n' )
            break;
Laurent Aimar's avatar
   
Laurent Aimar committed
501

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
502
503
        i_line++;
        ptr++;
Laurent Aimar's avatar
   
Laurent Aimar committed
504
505
    }

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

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
508
    if( ( ptr >= psz_line ) && ( *ptr == '\r' ) )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
509
510
        *ptr = '\0';

Laurent Aimar's avatar
   
Laurent Aimar committed
511
512
513
    return psz_line;
}

514
515
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
516
{
517
    int i_ret;
Laurent Aimar's avatar
   
Laurent Aimar committed
518
    va_list args;
519
    va_start( args, psz_fmt );
520
    i_ret = net_vaPrintf( p_this, fd, p_vs, psz_fmt, args );
521
522
523
524
525
    va_end( args );

    return i_ret;
}

526
527
ssize_t __net_vaPrintf( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
                        const char *psz_fmt, va_list args )
528
{
Laurent Aimar's avatar
   
Laurent Aimar committed
529
    char    *psz;
530
    int     i_size, i_ret;
Laurent Aimar's avatar
   
Laurent Aimar committed
531

532
    i_size = vasprintf( &psz, psz_fmt, args );
533
534
    i_ret = __net_Write( p_this, fd, p_vs, (uint8_t *)psz, i_size ) < i_size
        ? -1 : i_size;
535
536
537
    free( psz );

    return i_ret;
Laurent Aimar's avatar
   
Laurent Aimar committed
538
}
539
540


Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
541
542
543
544
545
546
547
548
549
550
551
552
553
/*****************************************************************************
 * 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
554
555
556
557
558
559
#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
560
    char *workaround_for_ill_designed_api = strdup( src );
gbazin's avatar
gbazin committed
561
562
#endif

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
563
564
565
566
567
568
569
570
571
572
573
574
575
    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;
576

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

#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);
621
622
                if( 0 == WSAAddressToStringA((LPSOCKADDR)&addr,
                                             sizeof(struct sockaddr_in6),
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
                                             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