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

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
91
92
93
        if (net_errno != EAFNOSUPPORT)
            msg_Err (p_this, "cannot create socket: %s",
                     net_strerror (net_errno));
        return -1;
94
    }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
95

96
    net_SetupSocket (fd);
97
98
99

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

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

118
119
120
    return fd;
}

Laurent Aimar's avatar
Laurent Aimar committed
121

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
122
123
int *net_Listen (vlc_object_t *p_this, const char *psz_host,
                 int i_port, int family, int socktype, int protocol)
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
{
    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,
148
                             protocol ?: ptr->ai_protocol);
149
150
151
152
153
154
155
        if (fd == -1)
        {
            msg_Dbg (p_this, "socket error: %s", net_strerror (net_errno));
            continue;
        }

        /* Bind the socket */
156
#if defined (WIN32) || defined (UNDER_CE)
157
158
159
160
161
162
163
164
165
        /*
         * 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))
        {
166
167
            // This works for IPv4 too - don't worry!
            struct sockaddr_in6 dumb =
168
            {
169
170
                .sin6_family = ptr->ai_addr->sa_family,
                .sin6_port =  ((struct sockaddr_in *)(ptr->ai_addr))->sin_port
171
172
173
174
175
176
            };

            bind (fd, (struct sockaddr *)&dumb, ptr->ai_addrlen);
        }
        else
#endif
177
178
179
180
181
182
183
        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,
184
                                protocol ?: ptr->ai_protocol, ptr->ai_addr,
185
186
187
188
189
190
191
192
193
194
195
196
197
198
                                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
199
200
201
202
203
204
205
206
207
        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;
            }
        }

208
209
210
211
212
213
        /* Listen */
        switch (ptr->ai_socktype)
        {
            case SOCK_STREAM:
            case SOCK_RDM:
            case SOCK_SEQPACKET:
214
215
216
#ifdef SOCK_DCCP
            case SOCK_DCCP:
#endif
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
                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;
}


245
246
247
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
248
               uint8_t *restrict p_buf, size_t i_buflen, vlc_bool_t waitall)
249
{
250
    size_t i_total = 0;
251

252
    while (i_buflen > 0)
253
    {
254
        if( ( p_this->b_die ) || ( p_this->p_libvlc->b_die ) )
255
        {
256
#if defined(WIN32) || defined(UNDER_CE)
257
            WSASetLastError (WSAEINTR);
258
#else
259
            errno = EINTR;
260
#endif
261
262
263
            goto error;
        }

264
        struct pollfd ufd[fdc];
265

266
        for (unsigned i = 0; i < fdc; i++)
267
        {
268
            ufd[i].fd = fdv[i];
269
            ufd[i].events = POLLIN;
270
            ufd[i].revents = 0;
271
272
        }

273
        switch (poll (ufd, fdc, 500))
274
275
276
        {
            case -1:
                goto error;
277

278
279
280
            case 0: // timeout
                continue;
        }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
281

282
        for (unsigned i = 0;; i++)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
283
        {
284
            assert (i < fdc); /* no events found = bug ! */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
285

286
            if (ufd[i].revents == 0)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
287
                continue;
288

Christophe Mutricy's avatar
Christophe Mutricy committed
289
#ifndef POLLRDHUP /* This is nice but non-portable */
290
291
# define POLLRDHUP 0
#endif
292
293
294
            if (i_total > 0)
            {
                // Errors (-1) and EOF (0) will be returned on next run
295
                if (ufd[i].revents & (POLLERR|POLLNVAL|POLLRDHUP))
296
297
298
299
                    return i_total;
            }
            else
            {
300
                if (ufd[i].revents & POLLRDHUP)
301
302
303
304
305
306
                    return 0; // EOF, read() would yield 0
            }

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

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
308
309
            break;
        }
310

311
312
        ssize_t n;
        if (*vsv != NULL)
313
        {
314
            n = (*vsv)->pf_recv ((*vsv)->p_sys, p_buf, i_buflen);
315
        }
316
        else
317
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
318
#ifdef WIN32
319
            n = recv (*fdv, p_buf, i_buflen, 0);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
320
321
322
#else
            n = read (*fdv, p_buf, i_buflen);
#endif
323
        }
324

325
        if (n == -1)
326
327
        {
#if defined(WIN32) || defined(UNDER_CE)
328
            switch (WSAGetLastError ())
329
330
331
332
333
334
335
336
337
338
            {
                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. */
339
340
                    msg_Err (p_this, "Receive error: "
                                     "Increase the mtu size (--mtu option)");
341
342
343
344
345
                    n = i_buflen;
                    break;

                default:
                    goto error;
346
347
            }
#else
348
349
            /* spurious wake-up or TLS did not yield any actual data */
            if (errno == EAGAIN)
350
351
                continue;
            goto error;
352
#endif
353
354
        }

355
356
357
        i_total += n;
        p_buf += n;
        i_buflen -= n;
Rémi Denis-Courmont's avatar
Fixes    
Rémi Denis-Courmont committed
358

359
        if ((n == 0) || !waitall)
360
            break;
361
    }
damienf's avatar
damienf committed
362
    return i_total;
363
364

error:
365
    msg_Err (p_this, "Read error: %s", net_strerror (net_errno));
Rémi Denis-Courmont's avatar
Oups    
Rémi Denis-Courmont committed
366
    return i_total ? (ssize_t)i_total : -1;
367
368
369
}


Laurent Aimar's avatar
   
Laurent Aimar committed
370
371
372
373
/*****************************************************************************
 * __net_Read:
 *****************************************************************************
 * Read from a network socket
374
 * If b_retry is true, then we repeat until we have read the right amount of
375
 * data; in that case, a short count means EOF has been reached.
Laurent Aimar's avatar
   
Laurent Aimar committed
376
 *****************************************************************************/
377
378
379
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
380
{
381
    return net_ReadInner( p_this, 1, &(int){ fd },
382
                          &(const v_socket_t *){ p_vs },
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
383
                          buf, len, b_retry );
Laurent Aimar's avatar
   
Laurent Aimar committed
384
385
}

386

zorglub's avatar
zorglub committed
387
388
389
/*****************************************************************************
 * __net_Select:
 *****************************************************************************
390
 * Read from several sockets. Takes data from the first socket that has some.
zorglub's avatar
zorglub committed
391
 *****************************************************************************/
392
393
ssize_t __net_Select( vlc_object_t *restrict p_this,
                      const int *restrict fds, int nfd,
394
                      uint8_t *restrict buf, size_t len )
zorglub's avatar
zorglub committed
395
{
396
    const v_socket_t *vsv[nfd];
397
    memset( vsv, 0, sizeof (vsv) );
zorglub's avatar
zorglub committed
398

399
    return net_ReadInner( p_this, nfd, fds, vsv,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
400
                          buf, len, VLC_FALSE );
zorglub's avatar
zorglub committed
401
402
403
}


Laurent Aimar's avatar
   
Laurent Aimar committed
404
/* Write exact amount requested */
405
406
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
407
{
408
    size_t i_total = 0;
Laurent Aimar's avatar
   
Laurent Aimar committed
409

410
    while( i_data > 0 )
Laurent Aimar's avatar
   
Laurent Aimar committed
411
    {
412
        if( p_this->b_die )
413
            break;
Laurent Aimar's avatar
   
Laurent Aimar committed
414

415
416
417
418
        struct pollfd ufd[1];
        memset (ufd, 0, sizeof (ufd));
        ufd[0].fd = fd;
        ufd[0].events = POLLOUT;
419

420
421
        int val = poll (ufd, 1, 500);
        switch (val)
Laurent Aimar's avatar
   
Laurent Aimar committed
422
        {
423
            case -1:
424
425
               msg_Err (p_this, "Write error: %s", net_strerror (net_errno));
               goto out;
426
427
428

            case 0:
                continue;
Laurent Aimar's avatar
   
Laurent Aimar committed
429
430
        }

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

434
435
436
        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
437
#ifdef WIN32
zorglub's avatar
zorglub committed
438
            val = send (fd, p_data, i_data, 0);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
439
440
441
#else
            val = write (fd, p_data, i_data);
#endif
442
443

        if (val == -1)
444
445
446
447
        {
            msg_Err (p_this, "Write error: %s", net_strerror (net_errno));
            break;
        }
448
449
450

        p_data += val;
        i_data -= val;
451
        i_total += val;
Laurent Aimar's avatar
   
Laurent Aimar committed
452
    }
453

454
455
456
457
458
out:
    if ((i_total > 0) || (i_data == 0))
        return i_total;

    return -1;
Laurent Aimar's avatar
   
Laurent Aimar committed
459
460
}

461
char *__net_Gets( vlc_object_t *p_this, int fd, const v_socket_t *p_vs )
Laurent Aimar's avatar
   
Laurent Aimar committed
462
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
463
464
    char *psz_line = NULL, *ptr = NULL;
    size_t  i_line = 0, i_max = 0;
Laurent Aimar's avatar
   
Laurent Aimar committed
465
466
467
468


    for( ;; )
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
469
        if( i_line == i_max )
Laurent Aimar's avatar
   
Laurent Aimar committed
470
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
471
472
473
            i_max += 1024;
            psz_line = realloc( psz_line, i_max );
            ptr = psz_line + i_line;
Laurent Aimar's avatar
   
Laurent Aimar committed
474
        }
475

476
        if( net_Read( p_this, fd, p_vs, (uint8_t *)ptr, 1, VLC_TRUE ) != 1 )
Laurent Aimar's avatar
   
Laurent Aimar committed
477
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
478
479
480
481
482
            if( i_line == 0 )
            {
                free( psz_line );
                return NULL;
            }
Laurent Aimar's avatar
   
Laurent Aimar committed
483
484
485
            break;
        }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
486
487
        if ( *ptr == '\n' )
            break;
Laurent Aimar's avatar
   
Laurent Aimar committed
488

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
489
490
        i_line++;
        ptr++;
Laurent Aimar's avatar
   
Laurent Aimar committed
491
492
    }

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

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
495
    if( ( ptr >= psz_line ) && ( *ptr == '\r' ) )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
496
497
        *ptr = '\0';

Laurent Aimar's avatar
   
Laurent Aimar committed
498
499
500
    return psz_line;
}

501
502
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
503
{
504
    int i_ret;
Laurent Aimar's avatar
   
Laurent Aimar committed
505
    va_list args;
506
    va_start( args, psz_fmt );
507
    i_ret = net_vaPrintf( p_this, fd, p_vs, psz_fmt, args );
508
509
510
511
512
    va_end( args );

    return i_ret;
}

513
514
ssize_t __net_vaPrintf( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
                        const char *psz_fmt, va_list args )
515
{
Laurent Aimar's avatar
   
Laurent Aimar committed
516
    char    *psz;
517
    int     i_size, i_ret;
Laurent Aimar's avatar
   
Laurent Aimar committed
518

519
    i_size = vasprintf( &psz, psz_fmt, args );
520
521
    i_ret = __net_Write( p_this, fd, p_vs, (uint8_t *)psz, i_size ) < i_size
        ? -1 : i_size;
522
523
524
    free( psz );

    return i_ret;
Laurent Aimar's avatar
   
Laurent Aimar committed
525
}
526
527


Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
528
529
530
531
532
533
534
535
536
537
538
539
540
/*****************************************************************************
 * 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
541
542
543
544
545
546
#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
547
    char *workaround_for_ill_designed_api = strdup( src );
gbazin's avatar
gbazin committed
548
549
#endif

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
550
551
552
553
554
555
556
557
558
559
560
561
562
    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;
563

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
        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
588
    memcpy( dst, &ipv4, 4 );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
589
590
591
592
# endif /* WIN32 */
    return 0;
}
#endif /* HAVE_INET_PTON */
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643

#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