io.c 16.7 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 the VideoLAN team
5
 * $Id$
Laurent Aimar's avatar
 
Laurent Aimar committed
6
7
 *
 * Authors: Laurent Aimar <fenrir@videolan.org>
8
 *          Rémi Denis-Courmont <rem # videolan.org>
Laurent Aimar's avatar
 
Laurent Aimar committed
9
10
11
12
13
14
15
16
17
18
19
20
21
 *
 * 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
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
Laurent Aimar's avatar
 
Laurent Aimar committed
23
24
25
26
27
28
29
30
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>
#include <vlc/vlc.h>

31
#include <errno.h>
Laurent Aimar's avatar
 
Laurent Aimar committed
32
33
34
35
36
37
38

#ifdef HAVE_FCNTL_H
#   include <fcntl.h>
#endif
#ifdef HAVE_SYS_TIME_H
#    include <sys/time.h>
#endif
gbazin's avatar
gbazin committed
39
40
41
42
#ifdef HAVE_UNISTD_H
#   include <unistd.h>
#endif

Laurent Aimar's avatar
 
Laurent Aimar committed
43
44
#include "network.h"

45
46
47
48
49
50
51
#ifndef INADDR_ANY
#   define INADDR_ANY  0x00000000
#endif
#ifndef INADDR_NONE
#   define INADDR_NONE 0xFFFFFFFF
#endif

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
52
53
int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype,
                int i_protocol )
54
55
56
57
58
59
60
{
    int fd, i_val;

    fd = socket( i_family, i_socktype, i_protocol );
    if( fd == -1 )
    {
#if defined(WIN32) || defined(UNDER_CE)
61
        if( WSAGetLastError ( ) != WSAEAFNOSUPPORT )
62
#else
63
        if( errno != EAFNOSUPPORT )
64
#endif
65
66
            msg_Warn( p_this, "cannot create socket: %s",
                      net_strerror(net_errno) );
67
68
69
70
71
72
73
74
75
76
        return -1;
    }

#if defined( WIN32 ) || defined( UNDER_CE )
    {
        unsigned long i_dummy = 1;
        if( ioctlsocket( fd, FIONBIO, &i_dummy ) != 0 )
            msg_Err( p_this, "cannot set socket to non-blocking mode" );
    }
#else
77
78
79
80
81
82
83
    if( fd >= FD_SETSIZE )
    {
        /* We don't want to overflow select() fd_set */
        msg_Err( p_this, "cannot create socket (too many already in use)" );
        net_Close( fd );
        return -1;
    }
84

85
86
87
    fcntl( fd, F_SETFD, FD_CLOEXEC );
    i_val = fcntl( fd, F_GETFL, 0 );
    fcntl( fd, F_SETFL, ((i_val != -1) ? i_val : 0) | O_NONBLOCK );
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#endif

    i_val = 1;
    setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (void *)&i_val,
                sizeof( i_val ) );

#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
     */
    if( i_family == AF_INET6 )
        setsockopt( fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&i_val,
                    sizeof( i_val ) );
#endif

#if defined( WIN32 ) || defined( UNDER_CE )
109
110
111
# ifndef IPV6_PROTECTION_LEVEL
#  define IPV6_PROTECTION_LEVEL 23
# endif
112
113
    if( i_family == AF_INET6 )
    {
114
        i_val = 30 /*PROTECTION_LEVEL_UNRESTRICTED*/;
115
116
        setsockopt( fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL,
                   (const char*)&i_val, sizeof( i_val ) );
117
118
119
120
121
    }
#endif
    return fd;
}

Laurent Aimar's avatar
Laurent Aimar committed
122

Laurent Aimar's avatar
 
Laurent Aimar committed
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*****************************************************************************
 * __net_Close:
 *****************************************************************************
 * Close a network handle
 *****************************************************************************/
void net_Close( int fd )
{
#ifdef UNDER_CE
    CloseHandle( (HANDLE)fd );
#elif defined( WIN32 )
    closesocket( fd );
#else
    close( fd );
#endif
}

/*****************************************************************************
 * __net_Read:
 *****************************************************************************
 * Read from a network socket
143
 * If b_retry is true, then we repeat until we have read the right amount of
Laurent Aimar's avatar
 
Laurent Aimar committed
144
145
 * data
 *****************************************************************************/
146
147
int __net_Read( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
                uint8_t *p_data, int i_data, vlc_bool_t b_retry )
Laurent Aimar's avatar
 
Laurent Aimar committed
148
149
{
    struct timeval  timeout;
150
    fd_set          fds_r, fds_e;
Laurent Aimar's avatar
 
Laurent Aimar committed
151
152
153
    int             i_recv;
    int             i_total = 0;
    int             i_ret;
154
    vlc_bool_t      b_die = p_this->b_die;
Laurent Aimar's avatar
 
Laurent Aimar committed
155
156
157
158
159

    while( i_data > 0 )
    {
        do
        {
160
            if( p_this->b_die != b_die )
Laurent Aimar's avatar
 
Laurent Aimar committed
161
162
163
164
165
            {
                return 0;
            }

            /* Initialize file descriptor set */
166
167
168
169
            FD_ZERO( &fds_r );
            FD_SET( fd, &fds_r );
            FD_ZERO( &fds_e );
            FD_SET( fd, &fds_e );
Laurent Aimar's avatar
 
Laurent Aimar committed
170
171
172
173

            /* We'll wait 0.5 second if nothing happens */
            timeout.tv_sec = 0;
            timeout.tv_usec = 500000;
174
175
176

        } while( (i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout)) == 0
                 || ( i_ret < 0 && errno == EINTR ) );
Laurent Aimar's avatar
 
Laurent Aimar committed
177
178
179

        if( i_ret < 0 )
        {
180
181
            msg_Err( p_this, "network select error (%s)",
                     net_strerror(net_errno) );
Laurent Aimar's avatar
 
Laurent Aimar committed
182
183
184
            return i_total > 0 ? i_total : -1;
        }

185
186
187
        if( ( i_recv = (p_vs != NULL)
              ? p_vs->pf_recv( p_vs->p_sys, p_data, i_data )
              : recv( fd, p_data, i_data, 0 ) ) < 0 )
Laurent Aimar's avatar
 
Laurent Aimar committed
188
        {
gbazin's avatar
gbazin committed
189
#if defined(WIN32) || defined(UNDER_CE)
190
191
192
193
194
            if( WSAGetLastError() == WSAEWOULDBLOCK )
            {
                /* only happens with p_vs (SSL) - not really an error */
            }
            else
Laurent Aimar's avatar
Laurent Aimar committed
195
196
197
198
            /* For udp only */
            /* On win32 recv() will fail if the datagram doesn't fit inside
             * the passed buffer, even though the buffer will be filled with
             * the first part of the datagram. */
zorglub's avatar
zorglub committed
199
            if( WSAGetLastError() == WSAEMSGSIZE )
Laurent Aimar's avatar
Laurent Aimar committed
200
            {
gbazin's avatar
gbazin committed
201
                msg_Err( p_this, "recv() failed. "
Laurent Aimar's avatar
Laurent Aimar committed
202
                         "Increase the mtu size (--mtu option)" );
203
                i_total += i_data;
Laurent Aimar's avatar
Laurent Aimar committed
204
            }
205
            else if( WSAGetLastError() == WSAEINTR ) continue;
206
#else
207
            /* EAGAIN only happens with p_vs (TLS) and it's not an error */
208
            if( errno != EAGAIN )
209
#endif
210
                msg_Err( p_this, "recv failed: %s", net_strerror(net_errno) );
Laurent Aimar's avatar
 
Laurent Aimar committed
211
212
            return i_total > 0 ? i_total : -1;
        }
213
214
215
216
217
        else if( i_recv == 0 )
        {
            /* Connection closed */
            b_retry = VLC_FALSE;
        }
Laurent Aimar's avatar
 
Laurent Aimar committed
218
219
220
221
222
223
224
225
226
227
228
229

        p_data += i_recv;
        i_data -= i_recv;
        i_total+= i_recv;
        if( !b_retry )
        {
            break;
        }
    }
    return i_total;
}

zorglub's avatar
zorglub committed
230
231
232
233
234
/*****************************************************************************
 * __net_ReadNonBlock:
 *****************************************************************************
 * Read from a network socket, non blocking mode (with timeout)
 *****************************************************************************/
235
236
int __net_ReadNonBlock( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
                        uint8_t *p_data, int i_data, mtime_t i_wait)
zorglub's avatar
zorglub committed
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
{
    struct timeval  timeout;
    fd_set          fds_r, fds_e;
    int             i_recv;
    int             i_ret;

    /* Initialize file descriptor set */
    FD_ZERO( &fds_r );
    FD_SET( fd, &fds_r );
    FD_ZERO( &fds_e );
    FD_SET( fd, &fds_e );

    timeout.tv_sec = 0;
    timeout.tv_usec = i_wait;

    i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout);

    if( i_ret < 0 && errno == EINTR )
    {
        return 0;
    }
    else if( i_ret < 0 )
    {
gbazin's avatar
gbazin committed
260
#if defined(WIN32) || defined(UNDER_CE)
261
        msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
gbazin's avatar
gbazin committed
262
#else
zorglub's avatar
zorglub committed
263
        msg_Err( p_this, "network select error (%s)", strerror(errno) );
gbazin's avatar
gbazin committed
264
#endif
zorglub's avatar
zorglub committed
265
266
267
268
269
270
271
272
        return -1;
    }
    else if( i_ret == 0)
    {
        return 0;
    }
    else
    {
gbazin's avatar
gbazin committed
273
274
275
#if !defined(UNDER_CE)
        if( fd == 0/*STDIN_FILENO*/ ) i_recv = read( fd, p_data, i_data ); else
#endif
276
277
        if( ( i_recv = (p_vs != NULL)
              ? p_vs->pf_recv( p_vs->p_sys, p_data, i_data )
278
              : recv( fd, p_data, i_data, 0 ) ) < 0 )
zorglub's avatar
zorglub committed
279
        {
gbazin's avatar
gbazin committed
280
#if defined(WIN32) || defined(UNDER_CE)
zorglub's avatar
zorglub committed
281
282
283
284
285
286
287
288
289
            /* For udp only */
            /* On win32 recv() will fail if the datagram doesn't fit inside
             * the passed buffer, even though the buffer will be filled with
             * the first part of the datagram. */
            if( WSAGetLastError() == WSAEMSGSIZE )
            {
                msg_Err( p_this, "recv() failed. "
                         "Increase the mtu size (--mtu option)" );
            }
290
            else msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
zorglub's avatar
zorglub committed
291
292
293
294
295
#else
            msg_Err( p_this, "recv failed (%s)", strerror(errno) );
#endif
            return -1;
        }
296
297

        return i_recv ? i_recv : -1;  /* !i_recv -> connection closed if tcp */
zorglub's avatar
zorglub committed
298
    }
299

zorglub's avatar
zorglub committed
300
301
302
303
    /* We will never be here */
    return -1;
}

zorglub's avatar
zorglub committed
304
305
306
/*****************************************************************************
 * __net_Select:
 *****************************************************************************
307
308
 * Read from several sockets (with timeout). Takes data from the first socket
 * that has some.
zorglub's avatar
zorglub committed
309
 *****************************************************************************/
310
311
int __net_Select( vlc_object_t *p_this, int *pi_fd, v_socket_t **pp_vs,
                  int i_fd, uint8_t *p_data, int i_data, mtime_t i_wait )
zorglub's avatar
zorglub committed
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
{
    struct timeval  timeout;
    fd_set          fds_r, fds_e;
    int             i_recv;
    int             i_ret;
    int             i;
    int             i_max_fd = 0;

    /* Initialize file descriptor set */
    FD_ZERO( &fds_r );
    FD_ZERO( &fds_e );

    for( i = 0 ; i < i_fd ; i++)
    {
        if( pi_fd[i] > i_max_fd ) i_max_fd = pi_fd[i];
        FD_SET( pi_fd[i], &fds_r );
        FD_SET( pi_fd[i], &fds_e );
    }

    timeout.tv_sec = 0;
    timeout.tv_usec = i_wait;

    i_ret = select( i_max_fd + 1, &fds_r, NULL, &fds_e, &timeout );

    if( i_ret < 0 && errno == EINTR )
    {
        return 0;
    }
    else if( i_ret < 0 )
    {
342
        msg_Err( p_this, "network selection error (%s)", strerror(errno) );
zorglub's avatar
zorglub committed
343
344
345
346
347
348
349
350
351
352
353
354
        return -1;
    }
    else if( i_ret == 0 )
    {
        return 0;
    }
    else
    {
        for( i = 0 ; i < i_fd ; i++)
        {
            if( FD_ISSET( pi_fd[i], &fds_r ) )
            {
355
356
357
                i_recv = ((pp_vs != NULL) && (pp_vs[i] != NULL))
                         ? pp_vs[i]->pf_recv( pp_vs[i]->p_sys, p_data, i_data )
                         : recv( pi_fd[i], p_data, i_data, 0 );
358
                if( i_recv < 0 )
zorglub's avatar
zorglub committed
359
360
361
362
363
364
365
366
367
368
369
                {
#ifdef WIN32
                    /* For udp only */
                    /* On win32 recv() will fail if the datagram doesn't
                     * fit inside the passed buffer, even though the buffer
                     *  will be filled with the first part of the datagram. */
                    if( WSAGetLastError() == WSAEMSGSIZE )
                    {
                        msg_Err( p_this, "recv() failed. "
                             "Increase the mtu size (--mtu option)" );
                    }
370
371
                    else msg_Err( p_this, "recv failed (%i)",
                                  WSAGetLastError() );
zorglub's avatar
zorglub committed
372
#else
373
                    msg_Err( p_this, "recv failed (%s)", strerror(errno) );
zorglub's avatar
zorglub committed
374
375
376
377
378
379
380
381
382
383
384
385
386
387
#endif
                    return VLC_EGENERIC;
                }

                return i_recv;
            }
        }
    }

    /* We will never be here */
    return -1;
}


Laurent Aimar's avatar
 
Laurent Aimar committed
388
/* Write exact amount requested */
389
int __net_Write( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
390
                 const uint8_t *p_data, int i_data )
Laurent Aimar's avatar
 
Laurent Aimar committed
391
392
{
    struct timeval  timeout;
393
    fd_set          fds_w, fds_e;
Laurent Aimar's avatar
 
Laurent Aimar committed
394
395
396
397
    int             i_send;
    int             i_total = 0;
    int             i_ret;

398
399
    vlc_bool_t      b_die = p_this->b_die;

Laurent Aimar's avatar
 
Laurent Aimar committed
400
401
402
403
    while( i_data > 0 )
    {
        do
        {
404
            if( p_this->b_die != b_die )
Laurent Aimar's avatar
 
Laurent Aimar committed
405
406
407
408
409
            {
                return 0;
            }

            /* Initialize file descriptor set */
410
411
412
413
            FD_ZERO( &fds_w );
            FD_SET( fd, &fds_w );
            FD_ZERO( &fds_e );
            FD_SET( fd, &fds_e );
Laurent Aimar's avatar
 
Laurent Aimar committed
414
415
416
417

            /* We'll wait 0.5 second if nothing happens */
            timeout.tv_sec = 0;
            timeout.tv_usec = 500000;
418
419
420

        } while( (i_ret = select(fd + 1, NULL, &fds_w, &fds_e, &timeout)) == 0
                 || ( i_ret < 0 && errno == EINTR ) );
Laurent Aimar's avatar
 
Laurent Aimar committed
421
422
423

        if( i_ret < 0 )
        {
gbazin's avatar
gbazin committed
424
#if defined(WIN32) || defined(UNDER_CE)
425
            msg_Err( p_this, "network selection error (%d)", WSAGetLastError() );
gbazin's avatar
gbazin committed
426
#else
427
            msg_Err( p_this, "network selection error (%s)", strerror(errno) );
gbazin's avatar
gbazin committed
428
#endif
Laurent Aimar's avatar
 
Laurent Aimar committed
429
430
431
            return i_total > 0 ? i_total : -1;
        }

432
433
434
        if( ( i_send = (p_vs != NULL)
                       ? p_vs->pf_send( p_vs->p_sys, p_data, i_data )
                       : send( fd, p_data, i_data, 0 ) ) < 0 )
Laurent Aimar's avatar
 
Laurent Aimar committed
435
        {
436
437
438
            /* XXX With udp for example, it will issue a message if the host
             * isn't listening */
            /* msg_Err( p_this, "send failed (%s)", strerror(errno) ); */
Laurent Aimar's avatar
 
Laurent Aimar committed
439
440
441
442
443
444
445
446
447
448
            return i_total > 0 ? i_total : -1;
        }

        p_data += i_send;
        i_data -= i_send;
        i_total+= i_send;
    }
    return i_total;
}

449
char *__net_Gets( vlc_object_t *p_this, int fd, v_socket_t *p_vs )
Laurent Aimar's avatar
 
Laurent Aimar committed
450
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
451
452
    char *psz_line = NULL, *ptr = NULL;
    size_t  i_line = 0, i_max = 0;
Laurent Aimar's avatar
 
Laurent Aimar committed
453
454
455
456


    for( ;; )
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
457
        if( i_line == i_max )
Laurent Aimar's avatar
 
Laurent Aimar committed
458
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
459
460
461
            i_max += 1024;
            psz_line = realloc( psz_line, i_max );
            ptr = psz_line + i_line;
Laurent Aimar's avatar
 
Laurent Aimar committed
462
        }
463

464
        if( net_Read( p_this, fd, p_vs, (uint8_t *)ptr, 1, VLC_TRUE ) != 1 )
Laurent Aimar's avatar
 
Laurent Aimar committed
465
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
466
467
468
469
470
            if( i_line == 0 )
            {
                free( psz_line );
                return NULL;
            }
Laurent Aimar's avatar
 
Laurent Aimar committed
471
472
473
            break;
        }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
474
475
        if ( *ptr == '\n' )
            break;
Laurent Aimar's avatar
 
Laurent Aimar committed
476

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
477
478
        i_line++;
        ptr++;
Laurent Aimar's avatar
 
Laurent Aimar committed
479
480
    }

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

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
483
    if( ( ptr >= psz_line ) && ( *ptr == '\r' ) )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
484
485
        *ptr = '\0';

Laurent Aimar's avatar
 
Laurent Aimar committed
486
487
488
    return psz_line;
}

489
490
int net_Printf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
                const char *psz_fmt, ... )
Laurent Aimar's avatar
 
Laurent Aimar committed
491
{
492
    int i_ret;
Laurent Aimar's avatar
 
Laurent Aimar committed
493
    va_list args;
494
    va_start( args, psz_fmt );
495
    i_ret = net_vaPrintf( p_this, fd, p_vs, psz_fmt, args );
496
497
498
499
500
    va_end( args );

    return i_ret;
}

501
502
int __net_vaPrintf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
                    const char *psz_fmt, va_list args )
503
{
Laurent Aimar's avatar
 
Laurent Aimar committed
504
    char    *psz;
505
    int     i_size, i_ret;
Laurent Aimar's avatar
 
Laurent Aimar committed
506

507
    i_size = vasprintf( &psz, psz_fmt, args );
508
509
    i_ret = __net_Write( p_this, fd, p_vs, (uint8_t *)psz, i_size ) < i_size
        ? -1 : i_size;
510
511
512
    free( psz );

    return i_ret;
Laurent Aimar's avatar
 
Laurent Aimar committed
513
}
514
515


Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
516
517
518
519
520
521
522
523
524
525
526
527
528
/*****************************************************************************
 * 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
529
530
531
532
533
534
#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
535
    char *workaround_for_ill_designed_api = strdup( src );
gbazin's avatar
gbazin committed
536
537
#endif

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
538
539
540
541
542
543
544
545
546
547
548
549
550
    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;
551

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
        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
576
    memcpy( dst, &ipv4, 4 );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
577
578
579
580
# endif /* WIN32 */
    return 0;
}
#endif /* HAVE_INET_PTON */