Coverage Report

Created: 2022-02-19 20:31

/src/php-src/main/network.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
   +----------------------------------------------------------------------+
3
   | Copyright (c) The PHP Group                                          |
4
   +----------------------------------------------------------------------+
5
   | This source file is subject to version 3.01 of the PHP license,      |
6
   | that is bundled with this package in the file LICENSE, and is        |
7
   | available through the world-wide-web at the following url:           |
8
   | http://www.php.net/license/3_01.txt                                  |
9
   | If you did not receive a copy of the PHP license and are unable to   |
10
   | obtain it through the world-wide-web, please send a note to          |
11
   | license@php.net so we can mail you a copy immediately.               |
12
   +----------------------------------------------------------------------+
13
   | Author: Stig Venaas <venaas@uninett.no>                              |
14
   | Streams work by Wez Furlong <wez@thebrainroom.com>                   |
15
   +----------------------------------------------------------------------+
16
 */
17
18
/*#define DEBUG_MAIN_NETWORK 1*/
19
20
#include "php.h"
21
22
#include <stddef.h>
23
#include <errno.h>
24
25
26
#ifdef PHP_WIN32
27
# include <Ws2tcpip.h>
28
# include "win32/inet.h"
29
# include "win32/winutil.h"
30
# define O_RDONLY _O_RDONLY
31
# include "win32/param.h"
32
#else
33
#include <sys/param.h>
34
#endif
35
36
#include <sys/types.h>
37
#if HAVE_SYS_SOCKET_H
38
#include <sys/socket.h>
39
#endif
40
41
#ifndef _FCNTL_H
42
#include <fcntl.h>
43
#endif
44
45
#ifdef HAVE_SYS_SELECT_H
46
#include <sys/select.h>
47
#endif
48
#if HAVE_POLL_H
49
#include <poll.h>
50
#elif HAVE_SYS_POLL_H
51
#include <sys/poll.h>
52
#endif
53
54
55
#ifndef PHP_WIN32
56
#include <netinet/in.h>
57
#include <netdb.h>
58
#if HAVE_ARPA_INET_H
59
#include <arpa/inet.h>
60
#endif
61
#endif
62
63
#ifndef HAVE_INET_ATON
64
int inet_aton(const char *, struct in_addr *);
65
#endif
66
67
#include "php_network.h"
68
69
#if defined(PHP_WIN32) || defined(__riscos__)
70
#undef AF_UNIX
71
#endif
72
73
#if defined(AF_UNIX)
74
#include <sys/un.h>
75
#endif
76
77
#include "ext/standard/file.h"
78
79
#ifdef PHP_WIN32
80
# include "win32/time.h"
81
# define SOCK_ERR INVALID_SOCKET
82
# define SOCK_CONN_ERR SOCKET_ERROR
83
# define PHP_TIMEOUT_ERROR_VALUE    WSAETIMEDOUT
84
85
#if HAVE_IPV6
86
const struct in6_addr in6addr_any = {0}; /* IN6ADDR_ANY_INIT; */
87
#endif
88
89
#else
90
0
# define SOCK_ERR -1
91
0
# define SOCK_CONN_ERR -1
92
0
# define PHP_TIMEOUT_ERROR_VALUE    ETIMEDOUT
93
#endif
94
95
#if HAVE_GETADDRINFO
96
#ifdef HAVE_GAI_STRERROR
97
0
#  define PHP_GAI_STRERROR(x) (gai_strerror(x))
98
#else
99
#  define PHP_GAI_STRERROR(x) (php_gai_strerror(x))
100
/* {{{ php_gai_strerror */
101
static const char *php_gai_strerror(int code)
102
{
103
        static struct {
104
                int code;
105
                const char *msg;
106
        } values[] = {
107
#  ifdef EAI_ADDRFAMILY
108
                {EAI_ADDRFAMILY, "Address family for hostname not supported"},
109
#  endif
110
                {EAI_AGAIN, "Temporary failure in name resolution"},
111
                {EAI_BADFLAGS, "Bad value for ai_flags"},
112
                {EAI_FAIL, "Non-recoverable failure in name resolution"},
113
                {EAI_FAMILY, "ai_family not supported"},
114
                {EAI_MEMORY, "Memory allocation failure"},
115
#  ifdef EAI_NODATA
116
                {EAI_NODATA, "No address associated with hostname"},
117
#  endif
118
                {EAI_NONAME, "Name or service not known"},
119
                {EAI_SERVICE, "Servname not supported for ai_socktype"},
120
                {EAI_SOCKTYPE, "ai_socktype not supported"},
121
                {EAI_SYSTEM, "System error"},
122
                {0, NULL}
123
        };
124
        int i;
125
126
        for (i = 0; values[i].msg != NULL; i++) {
127
                if (values[i].code == code) {
128
                        return (char *)values[i].msg;
129
                }
130
        }
131
132
        return "Unknown error";
133
}
134
/* }}} */
135
#endif
136
#endif
137
138
/* {{{ php_network_freeaddresses */
139
PHPAPI void php_network_freeaddresses(struct sockaddr **sal)
140
0
{
141
0
  struct sockaddr **sap;
142
143
0
  if (sal == NULL)
144
0
    return;
145
0
  for (sap = sal; *sap != NULL; sap++)
146
0
    efree(*sap);
147
0
  efree(sal);
148
0
}
149
/* }}} */
150
151
/* {{{ php_network_getaddresses
152
 * Returns number of addresses, 0 for none/error
153
 */
154
PHPAPI int php_network_getaddresses(const char *host, int socktype, struct sockaddr ***sal, zend_string **error_string)
155
0
{
156
0
  struct sockaddr **sap;
157
0
  int n;
158
0
#if HAVE_GETADDRINFO
159
0
# if HAVE_IPV6
160
0
  static int ipv6_borked = -1; /* the way this is used *is* thread safe */
161
0
# endif
162
0
  struct addrinfo hints, *res, *sai;
163
#else
164
  struct hostent *host_info;
165
  struct in_addr in;
166
#endif
167
168
0
  if (host == NULL) {
169
0
    return 0;
170
0
  }
171
0
#if HAVE_GETADDRINFO
172
0
  memset(&hints, '\0', sizeof(hints));
173
174
0
  hints.ai_family = AF_INET; /* default to regular inet (see below) */
175
0
  hints.ai_socktype = socktype;
176
177
0
# if HAVE_IPV6
178
  /* probe for a working IPv6 stack; even if detected as having v6 at compile
179
   * time, at runtime some stacks are slow to resolve or have other issues
180
   * if they are not correctly configured.
181
   * static variable use is safe here since simple store or fetch operations
182
   * are atomic and because the actual probe process is not in danger of
183
   * collisions or race conditions. */
184
0
  if (ipv6_borked == -1) {
185
0
    int s;
186
187
0
    s = socket(PF_INET6, SOCK_DGRAM, 0);
188
0
    if (s == SOCK_ERR) {
189
0
      ipv6_borked = 1;
190
0
    } else {
191
0
      ipv6_borked = 0;
192
0
      closesocket(s);
193
0
    }
194
0
  }
195
0
  hints.ai_family = ipv6_borked ? AF_INET : AF_UNSPEC;
196
0
# endif
197
198
0
  if ((n = getaddrinfo(host, NULL, &hints, &res))) {
199
0
    if (error_string) {
200
0
      *error_string = strpprintf(0, "php_network_getaddresses: getaddrinfo failed: %s", PHP_GAI_STRERROR(n));
201
0
      php_error_docref(NULL, E_WARNING, "%s", ZSTR_VAL(*error_string));
202
0
    } else {
203
0
      php_error_docref(NULL, E_WARNING, "php_network_getaddresses: getaddrinfo failed: %s", PHP_GAI_STRERROR(n));
204
0
    }
205
0
    return 0;
206
0
  } else if (res == NULL) {
207
0
    if (error_string) {
208
0
      *error_string = strpprintf(0, "php_network_getaddresses: getaddrinfo failed (null result pointer) errno=%d", errno);
209
0
      php_error_docref(NULL, E_WARNING, "%s", ZSTR_VAL(*error_string));
210
0
    } else {
211
0
      php_error_docref(NULL, E_WARNING, "php_network_getaddresses: getaddrinfo failed (null result pointer)");
212
0
    }
213
0
    return 0;
214
0
  }
215
216
0
  sai = res;
217
0
  for (n = 1; (sai = sai->ai_next) != NULL; n++)
218
0
    ;
219
220
0
  *sal = safe_emalloc((n + 1), sizeof(*sal), 0);
221
0
  sai = res;
222
0
  sap = *sal;
223
224
0
  do {
225
0
    *sap = emalloc(sai->ai_addrlen);
226
0
    memcpy(*sap, sai->ai_addr, sai->ai_addrlen);
227
0
    sap++;
228
0
  } while ((sai = sai->ai_next) != NULL);
229
230
0
  freeaddrinfo(res);
231
#else
232
  if (!inet_aton(host, &in)) {
233
    if(strlen(host) > MAXFQDNLEN) {
234
      host_info = NULL;
235
      errno = E2BIG;
236
    } else {
237
      host_info = php_network_gethostbyname(host);
238
    }
239
    if (host_info == NULL) {
240
      if (error_string) {
241
        *error_string = strpprintf(0, "php_network_getaddresses: gethostbyname failed. errno=%d", errno);
242
        php_error_docref(NULL, E_WARNING, "%s", ZSTR_VAL(*error_string));
243
      } else {
244
        php_error_docref(NULL, E_WARNING, "php_network_getaddresses: gethostbyname failed");
245
      }
246
      return 0;
247
    }
248
    in = *((struct in_addr *) host_info->h_addr);
249
  }
250
251
  *sal = safe_emalloc(2, sizeof(*sal), 0);
252
  sap = *sal;
253
  *sap = emalloc(sizeof(struct sockaddr_in));
254
  (*sap)->sa_family = AF_INET;
255
  ((struct sockaddr_in *)*sap)->sin_addr = in;
256
  sap++;
257
  n = 1;
258
#endif
259
260
0
  *sap = NULL;
261
0
  return n;
262
0
}
263
/* }}} */
264
265
#ifndef O_NONBLOCK
266
#define O_NONBLOCK O_NDELAY
267
#endif
268
269
#ifdef PHP_WIN32
270
typedef u_long php_non_blocking_flags_t;
271
#  define SET_SOCKET_BLOCKING_MODE(sock, save) \
272
     save = TRUE; ioctlsocket(sock, FIONBIO, &save)
273
#  define RESTORE_SOCKET_BLOCKING_MODE(sock, save) \
274
   ioctlsocket(sock, FIONBIO, &save)
275
#else
276
typedef int php_non_blocking_flags_t;
277
#  define SET_SOCKET_BLOCKING_MODE(sock, save) \
278
0
   save = fcntl(sock, F_GETFL, 0); \
279
0
   fcntl(sock, F_SETFL, save | O_NONBLOCK)
280
#  define RESTORE_SOCKET_BLOCKING_MODE(sock, save) \
281
0
   fcntl(sock, F_SETFL, save)
282
#endif
283
284
/* Connect to a socket using an interruptible connect with optional timeout.
285
 * Optionally, the connect can be made asynchronously, which will implicitly
286
 * enable non-blocking mode on the socket.
287
 * */
288
/* {{{ php_network_connect_socket */
289
PHPAPI int php_network_connect_socket(php_socket_t sockfd,
290
    const struct sockaddr *addr,
291
    socklen_t addrlen,
292
    int asynchronous,
293
    struct timeval *timeout,
294
    zend_string **error_string,
295
    int *error_code)
296
0
{
297
0
  php_non_blocking_flags_t orig_flags;
298
0
  int n;
299
0
  int error = 0;
300
0
  socklen_t len;
301
0
  int ret = 0;
302
303
0
  SET_SOCKET_BLOCKING_MODE(sockfd, orig_flags);
304
305
0
  if ((n = connect(sockfd, addr, addrlen)) != 0) {
306
0
    error = php_socket_errno();
307
308
0
    if (error_code) {
309
0
      *error_code = error;
310
0
    }
311
312
0
    if (error != EINPROGRESS) {
313
0
      if (error_string) {
314
0
        *error_string = php_socket_error_str(error);
315
0
      }
316
317
0
      return -1;
318
0
    }
319
0
    if (asynchronous && error == EINPROGRESS) {
320
      /* this is fine by us */
321
0
      return 0;
322
0
    }
323
0
  }
324
325
0
  if (n == 0) {
326
0
    goto ok;
327
0
  }
328
# ifdef PHP_WIN32
329
  /* The documentation for connect() says in case of non-blocking connections
330
   * the select function reports success in the writefds set and failure in
331
   * the exceptfds set. Indeed, using PHP_POLLREADABLE results in select
332
   * failing only due to the timeout and not immediately as would be
333
   * expected when a connection is actively refused. This way,
334
   * php_pollfd_for will return a mask with POLLOUT if the connection
335
   * is successful and with POLLPRI otherwise. */
336
  if ((n = php_pollfd_for(sockfd, POLLOUT|POLLPRI, timeout)) == 0) {
337
#else
338
0
  if ((n = php_pollfd_for(sockfd, PHP_POLLREADABLE|POLLOUT, timeout)) == 0) {
339
0
#endif
340
0
    error = PHP_TIMEOUT_ERROR_VALUE;
341
0
  }
342
343
0
  if (n > 0) {
344
0
    len = sizeof(error);
345
    /*
346
       BSD-derived systems set errno correctly
347
       Solaris returns -1 from getsockopt in case of error
348
       */
349
0
    if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char*)&error, &len) != 0) {
350
0
      ret = -1;
351
0
    }
352
0
  } else {
353
    /* whoops: sockfd has disappeared */
354
0
    ret = -1;
355
0
  }
356
357
0
ok:
358
0
  if (!asynchronous) {
359
    /* back to blocking mode */
360
0
    RESTORE_SOCKET_BLOCKING_MODE(sockfd, orig_flags);
361
0
  }
362
363
0
  if (error_code) {
364
0
    *error_code = error;
365
0
  }
366
367
0
  if (error) {
368
0
    ret = -1;
369
0
    if (error_string) {
370
0
      *error_string = php_socket_error_str(error);
371
0
    }
372
0
  }
373
0
  return ret;
374
0
}
375
/* }}} */
376
377
/* {{{ sub_times */
378
static inline void sub_times(struct timeval a, struct timeval b, struct timeval *result)
379
0
{
380
0
  result->tv_usec = a.tv_usec - b.tv_usec;
381
0
  if (result->tv_usec < 0L) {
382
0
    a.tv_sec--;
383
0
    result->tv_usec += 1000000L;
384
0
  }
385
0
  result->tv_sec = a.tv_sec - b.tv_sec;
386
0
  if (result->tv_sec < 0L) {
387
0
    result->tv_sec++;
388
0
    result->tv_usec -= 1000000L;
389
0
  }
390
0
}
391
/* }}} */
392
393
/* Bind to a local IP address.
394
 * Returns the bound socket, or -1 on failure.
395
 * */
396
/* {{{ php_network_bind_socket_to_local_addr */
397
php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned port,
398
    int socktype, long sockopts, zend_string **error_string, int *error_code
399
    )
400
0
{
401
0
  int num_addrs, n, err = 0;
402
0
  php_socket_t sock;
403
0
  struct sockaddr **sal, **psal, *sa;
404
0
  socklen_t socklen;
405
0
  int sockoptval = 1;
406
407
0
  num_addrs = php_network_getaddresses(host, socktype, &psal, error_string);
408
409
0
  if (num_addrs == 0) {
410
    /* could not resolve address(es) */
411
0
    return -1;
412
0
  }
413
414
0
  for (sal = psal; *sal != NULL; sal++) {
415
0
    sa = *sal;
416
417
    /* create a socket for this address */
418
0
    sock = socket(sa->sa_family, socktype, 0);
419
420
0
    if (sock == SOCK_ERR) {
421
0
      continue;
422
0
    }
423
424
0
    switch (sa->sa_family) {
425
0
#if HAVE_GETADDRINFO && HAVE_IPV6
426
0
      case AF_INET6:
427
0
        ((struct sockaddr_in6 *)sa)->sin6_family = sa->sa_family;
428
0
        ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
429
0
        socklen = sizeof(struct sockaddr_in6);
430
0
        break;
431
0
#endif
432
0
      case AF_INET:
433
0
        ((struct sockaddr_in *)sa)->sin_family = sa->sa_family;
434
0
        ((struct sockaddr_in *)sa)->sin_port = htons(port);
435
0
        socklen = sizeof(struct sockaddr_in);
436
0
        break;
437
0
      default:
438
        /* Unknown family */
439
0
        socklen = 0;
440
0
        sa = NULL;
441
0
    }
442
443
0
    if (sa) {
444
      /* attempt to bind */
445
446
0
#ifdef SO_REUSEADDR
447
0
      setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&sockoptval, sizeof(sockoptval));
448
0
#endif
449
0
#ifdef IPV6_V6ONLY
450
0
      if (sockopts & STREAM_SOCKOP_IPV6_V6ONLY) {
451
0
        int ipv6_val = !!(sockopts & STREAM_SOCKOP_IPV6_V6ONLY_ENABLED);
452
0
        setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6_val, sizeof(sockoptval));
453
0
      }
454
0
#endif
455
0
#ifdef SO_REUSEPORT
456
0
      if (sockopts & STREAM_SOCKOP_SO_REUSEPORT) {
457
0
        setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char*)&sockoptval, sizeof(sockoptval));
458
0
      }
459
0
#endif
460
0
#ifdef SO_BROADCAST
461
0
      if (sockopts & STREAM_SOCKOP_SO_BROADCAST) {
462
0
        setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&sockoptval, sizeof(sockoptval));
463
0
      }
464
0
#endif
465
0
#ifdef TCP_NODELAY
466
0
      if (sockopts & STREAM_SOCKOP_TCP_NODELAY) {
467
0
        setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&sockoptval, sizeof(sockoptval));
468
0
      }
469
0
#endif
470
471
0
      n = bind(sock, sa, socklen);
472
473
0
      if (n != SOCK_CONN_ERR) {
474
0
        goto bound;
475
0
      }
476
477
0
      err = php_socket_errno();
478
0
    }
479
480
0
    closesocket(sock);
481
0
  }
482
0
  sock = -1;
483
484
0
  if (error_code) {
485
0
    *error_code = err;
486
0
  }
487
0
  if (error_string) {
488
0
    *error_string = php_socket_error_str(err);
489
0
  }
490
491
0
bound:
492
493
0
  php_network_freeaddresses(psal);
494
495
0
  return sock;
496
497
0
}
498
/* }}} */
499
500
PHPAPI int php_network_parse_network_address_with_port(const char *addr, zend_long addrlen, struct sockaddr *sa, socklen_t *sl)
501
0
{
502
0
  char *colon;
503
0
  char *tmp;
504
0
  int ret = FAILURE;
505
0
  short port;
506
0
  struct sockaddr_in *in4 = (struct sockaddr_in*)sa;
507
0
  struct sockaddr **psal;
508
0
  int n;
509
0
  zend_string *errstr = NULL;
510
0
#if HAVE_IPV6
511
0
  struct sockaddr_in6 *in6 = (struct sockaddr_in6*)sa;
512
513
0
  memset(in6, 0, sizeof(struct sockaddr_in6));
514
#else
515
  memset(in4, 0, sizeof(struct sockaddr_in));
516
#endif
517
518
0
  if (*addr == '[') {
519
0
    colon = memchr(addr + 1, ']', addrlen-1);
520
0
    if (!colon || colon[1] != ':') {
521
0
      return FAILURE;
522
0
    }
523
0
    port = atoi(colon + 2);
524
0
    addr++;
525
0
  } else {
526
0
    colon = memchr(addr, ':', addrlen);
527
0
    if (!colon) {
528
0
      return FAILURE;
529
0
    }
530
0
    port = atoi(colon + 1);
531
0
  }
532
533
0
  tmp = estrndup(addr, colon - addr);
534
535
  /* first, try interpreting the address as a numeric address */
536
537
0
#if HAVE_IPV6 && HAVE_INET_PTON
538
0
  if (inet_pton(AF_INET6, tmp, &in6->sin6_addr) > 0) {
539
0
    in6->sin6_port = htons(port);
540
0
    in6->sin6_family = AF_INET6;
541
0
    *sl = sizeof(struct sockaddr_in6);
542
0
    ret = SUCCESS;
543
0
    goto out;
544
0
  }
545
0
#endif
546
0
  if (inet_aton(tmp, &in4->sin_addr) > 0) {
547
0
    in4->sin_port = htons(port);
548
0
    in4->sin_family = AF_INET;
549
0
    *sl = sizeof(struct sockaddr_in);
550
0
    ret = SUCCESS;
551
0
    goto out;
552
0
  }
553
554
  /* looks like we'll need to resolve it */
555
0
  n = php_network_getaddresses(tmp, SOCK_DGRAM, &psal, &errstr);
556
557
0
  if (n == 0) {
558
0
    if (errstr) {
559
0
      php_error_docref(NULL, E_WARNING, "Failed to resolve `%s': %s", tmp, ZSTR_VAL(errstr));
560
0
      zend_string_release_ex(errstr, 0);
561
0
    }
562
0
    goto out;
563
0
  }
564
565
  /* copy the details from the first item */
566
0
  switch ((*psal)->sa_family) {
567
0
#if HAVE_GETADDRINFO && HAVE_IPV6
568
0
    case AF_INET6:
569
0
      *in6 = **(struct sockaddr_in6**)psal;
570
0
      in6->sin6_port = htons(port);
571
0
      *sl = sizeof(struct sockaddr_in6);
572
0
      ret = SUCCESS;
573
0
      break;
574
0
#endif
575
0
    case AF_INET:
576
0
      *in4 = **(struct sockaddr_in**)psal;
577
0
      in4->sin_port = htons(port);
578
0
      *sl = sizeof(struct sockaddr_in);
579
0
      ret = SUCCESS;
580
0
      break;
581
0
  }
582
583
0
  php_network_freeaddresses(psal);
584
585
0
out:
586
0
  efree(tmp);
587
0
  return ret;
588
0
}
589
590
591
PHPAPI void php_network_populate_name_from_sockaddr(
592
    /* input address */
593
    struct sockaddr *sa, socklen_t sl,
594
    /* output readable address */
595
    zend_string **textaddr,
596
    /* output address */
597
    struct sockaddr **addr,
598
    socklen_t *addrlen
599
    )
600
0
{
601
0
  if (addr) {
602
0
    *addr = emalloc(sl);
603
0
    memcpy(*addr, sa, sl);
604
0
    *addrlen = sl;
605
0
  }
606
607
0
  if (textaddr) {
608
0
#if HAVE_IPV6 && HAVE_INET_NTOP
609
0
    char abuf[256];
610
0
#endif
611
0
    char *buf = NULL;
612
613
0
    switch (sa->sa_family) {
614
0
      case AF_INET:
615
        /* generally not thread safe, but it *is* thread safe under win32 */
616
0
        buf = inet_ntoa(((struct sockaddr_in*)sa)->sin_addr);
617
0
        if (buf) {
618
0
          *textaddr = strpprintf(0, "%s:%d",
619
0
            buf, ntohs(((struct sockaddr_in*)sa)->sin_port));
620
0
        }
621
622
0
        break;
623
624
0
#if HAVE_IPV6 && HAVE_INET_NTOP
625
0
      case AF_INET6:
626
0
        buf = (char*)inet_ntop(sa->sa_family, &((struct sockaddr_in6*)sa)->sin6_addr, (char *)&abuf, sizeof(abuf));
627
0
        if (buf) {
628
0
          *textaddr = strpprintf(0, "[%s]:%d",
629
0
            buf, ntohs(((struct sockaddr_in6*)sa)->sin6_port));
630
0
        }
631
632
0
        break;
633
0
#endif
634
0
#ifdef AF_UNIX
635
0
      case AF_UNIX:
636
0
        {
637
0
          struct sockaddr_un *ua = (struct sockaddr_un*)sa;
638
639
0
          if (ua->sun_path[0] == '\0') {
640
            /* abstract name */
641
0
            int len = sl - sizeof(sa_family_t);
642
0
            *textaddr = zend_string_init((char*)ua->sun_path, len, 0);
643
0
          } else {
644
0
            int len = strlen(ua->sun_path);
645
0
            *textaddr = zend_string_init((char*)ua->sun_path, len, 0);
646
0
          }
647
0
        }
648
0
        break;
649
0
#endif
650
651
0
    }
652
653
0
  }
654
0
}
655
656
PHPAPI int php_network_get_peer_name(php_socket_t sock,
657
    zend_string **textaddr,
658
    struct sockaddr **addr,
659
    socklen_t *addrlen
660
    )
661
0
{
662
0
  php_sockaddr_storage sa;
663
0
  socklen_t sl = sizeof(sa);
664
0
  memset(&sa, 0, sizeof(sa));
665
666
0
  if (getpeername(sock, (struct sockaddr*)&sa, &sl) == 0) {
667
0
    php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
668
0
        textaddr,
669
0
        addr, addrlen
670
0
        );
671
0
    return 0;
672
0
  }
673
0
  return -1;
674
0
}
675
676
PHPAPI int php_network_get_sock_name(php_socket_t sock,
677
    zend_string **textaddr,
678
    struct sockaddr **addr,
679
    socklen_t *addrlen
680
    )
681
0
{
682
0
  php_sockaddr_storage sa;
683
0
  socklen_t sl = sizeof(sa);
684
0
  memset(&sa, 0, sizeof(sa));
685
686
0
  if (getsockname(sock, (struct sockaddr*)&sa, &sl) == 0) {
687
0
    php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
688
0
        textaddr,
689
0
        addr, addrlen
690
0
        );
691
0
    return 0;
692
0
  }
693
0
  return -1;
694
695
0
}
696
697
698
/* Accept a client connection from a server socket,
699
 * using an optional timeout.
700
 * Returns the peer address in addr/addrlen (it will emalloc
701
 * these, so be sure to efree the result).
702
 * If you specify textaddr, a text-printable
703
 * version of the address will be emalloc'd and returned.
704
 * */
705
706
/* {{{ php_network_accept_incoming */
707
PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock,
708
    zend_string **textaddr,
709
    struct sockaddr **addr,
710
    socklen_t *addrlen,
711
    struct timeval *timeout,
712
    zend_string **error_string,
713
    int *error_code,
714
    int tcp_nodelay
715
    )
716
0
{
717
0
  php_socket_t clisock = -1;
718
0
  int error = 0, n;
719
0
  php_sockaddr_storage sa;
720
0
  socklen_t sl;
721
722
0
  n = php_pollfd_for(srvsock, PHP_POLLREADABLE, timeout);
723
724
0
  if (n == 0) {
725
0
    error = PHP_TIMEOUT_ERROR_VALUE;
726
0
  } else if (n == -1) {
727
0
    error = php_socket_errno();
728
0
  } else {
729
0
    sl = sizeof(sa);
730
731
0
    clisock = accept(srvsock, (struct sockaddr*)&sa, &sl);
732
733
0
    if (clisock != SOCK_ERR) {
734
0
      php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
735
0
          textaddr,
736
0
          addr, addrlen
737
0
          );
738
0
      if (tcp_nodelay) {
739
0
#ifdef TCP_NODELAY
740
0
        setsockopt(clisock, IPPROTO_TCP, TCP_NODELAY, (char*)&tcp_nodelay, sizeof(tcp_nodelay));
741
0
#endif
742
0
      }
743
0
    } else {
744
0
      error = php_socket_errno();
745
0
    }
746
0
  }
747
748
0
  if (error_code) {
749
0
    *error_code = error;
750
0
  }
751
0
  if (error_string) {
752
0
    *error_string = php_socket_error_str(error);
753
0
  }
754
755
0
  return clisock;
756
0
}
757
/* }}} */
758
759
760
/* Connect to a remote host using an interruptible connect with optional timeout.
761
 * Optionally, the connect can be made asynchronously, which will implicitly
762
 * enable non-blocking mode on the socket.
763
 * Returns the connected (or connecting) socket, or -1 on failure.
764
 * */
765
766
/* {{{ php_network_connect_socket_to_host */
767
php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short port,
768
    int socktype, int asynchronous, struct timeval *timeout, zend_string **error_string,
769
    int *error_code, const char *bindto, unsigned short bindport, long sockopts
770
    )
771
0
{
772
0
  int num_addrs, n, fatal = 0;
773
0
  php_socket_t sock;
774
0
  struct sockaddr **sal, **psal, *sa;
775
0
  struct timeval working_timeout;
776
0
  socklen_t socklen;
777
0
#if HAVE_GETTIMEOFDAY
778
0
  struct timeval limit_time, time_now;
779
0
#endif
780
781
0
  num_addrs = php_network_getaddresses(host, socktype, &psal, error_string);
782
783
0
  if (num_addrs == 0) {
784
    /* could not resolve address(es) */
785
0
    return -1;
786
0
  }
787
788
0
  if (timeout) {
789
0
    memcpy(&working_timeout, timeout, sizeof(working_timeout));
790
0
#if HAVE_GETTIMEOFDAY
791
0
    gettimeofday(&limit_time, NULL);
792
0
    limit_time.tv_sec += working_timeout.tv_sec;
793
0
    limit_time.tv_usec += working_timeout.tv_usec;
794
0
    if (limit_time.tv_usec >= 1000000) {
795
0
      limit_time.tv_usec -= 1000000;
796
0
      limit_time.tv_sec++;
797
0
    }
798
0
#endif
799
0
  }
800
801
0
  for (sal = psal; !fatal && *sal != NULL; sal++) {
802
0
    sa = *sal;
803
804
    /* create a socket for this address */
805
0
    sock = socket(sa->sa_family, socktype, 0);
806
807
0
    if (sock == SOCK_ERR) {
808
0
      continue;
809
0
    }
810
811
0
    switch (sa->sa_family) {
812
0
#if HAVE_GETADDRINFO && HAVE_IPV6
813
0
      case AF_INET6:
814
0
        if (!bindto || strchr(bindto, ':')) {
815
0
          ((struct sockaddr_in6 *)sa)->sin6_family = sa->sa_family;
816
0
          ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
817
0
          socklen = sizeof(struct sockaddr_in6);
818
0
        } else {
819
0
          socklen = 0;
820
0
          sa = NULL;
821
0
        }
822
0
        break;
823
0
#endif
824
0
      case AF_INET:
825
0
        ((struct sockaddr_in *)sa)->sin_family = sa->sa_family;
826
0
        ((struct sockaddr_in *)sa)->sin_port = htons(port);
827
0
        socklen = sizeof(struct sockaddr_in);
828
0
        break;
829
0
      default:
830
        /* Unknown family */
831
0
        socklen = 0;
832
0
        sa = NULL;
833
0
    }
834
835
0
    if (sa) {
836
      /* make a connection attempt */
837
838
0
      if (bindto) {
839
0
        struct sockaddr *local_address = NULL;
840
0
        int local_address_len = 0;
841
842
0
        if (sa->sa_family == AF_INET) {
843
0
          if (strchr(bindto,':')) {
844
0
            goto skip_bind;
845
0
          }
846
0
          struct sockaddr_in *in4 = emalloc(sizeof(struct sockaddr_in));
847
848
0
          local_address = (struct sockaddr*)in4;
849
0
          local_address_len = sizeof(struct sockaddr_in);
850
851
0
          in4->sin_family = sa->sa_family;
852
0
          in4->sin_port = htons(bindport);
853
0
          if (!inet_aton(bindto, &in4->sin_addr)) {
854
0
            php_error_docref(NULL, E_WARNING, "Invalid IP Address: %s", bindto);
855
0
            goto skip_bind;
856
0
          }
857
0
          memset(&(in4->sin_zero), 0, sizeof(in4->sin_zero));
858
0
        }
859
0
#if HAVE_IPV6 && HAVE_INET_PTON
860
0
         else { /* IPV6 */
861
0
          struct sockaddr_in6 *in6 = emalloc(sizeof(struct sockaddr_in6));
862
863
0
          local_address = (struct sockaddr*)in6;
864
0
          local_address_len = sizeof(struct sockaddr_in6);
865
866
0
          in6->sin6_family = sa->sa_family;
867
0
          in6->sin6_port = htons(bindport);
868
0
          if (inet_pton(AF_INET6, bindto, &in6->sin6_addr) < 1) {
869
0
            php_error_docref(NULL, E_WARNING, "Invalid IP Address: %s", bindto);
870
0
            goto skip_bind;
871
0
          }
872
0
        }
873
0
#endif
874
875
0
        if (!local_address || bind(sock, local_address, local_address_len)) {
876
0
          php_error_docref(NULL, E_WARNING, "Failed to bind to '%s:%d', system said: %s", bindto, bindport, strerror(errno));
877
0
        }
878
0
skip_bind:
879
0
        if (local_address) {
880
0
          efree(local_address);
881
0
        }
882
0
      }
883
      /* free error string received during previous iteration (if any) */
884
0
      if (error_string && *error_string) {
885
0
        zend_string_release_ex(*error_string, 0);
886
0
        *error_string = NULL;
887
0
      }
888
889
0
#ifdef SO_BROADCAST
890
0
      {
891
0
        int val = 1;
892
0
        if (sockopts & STREAM_SOCKOP_SO_BROADCAST) {
893
0
          setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&val, sizeof(val));
894
0
        }
895
0
      }
896
0
#endif
897
898
0
#ifdef TCP_NODELAY
899
0
      {
900
0
        int val = 1;
901
0
        if (sockopts & STREAM_SOCKOP_TCP_NODELAY) {
902
0
          setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&val, sizeof(val));
903
0
        }
904
0
      }
905
0
#endif
906
0
      n = php_network_connect_socket(sock, sa, socklen, asynchronous,
907
0
          timeout ? &working_timeout : NULL,
908
0
          error_string, error_code);
909
910
0
      if (n != -1) {
911
0
        goto connected;
912
0
      }
913
914
      /* adjust timeout for next attempt */
915
0
#if HAVE_GETTIMEOFDAY
916
0
      if (timeout) {
917
0
        gettimeofday(&time_now, NULL);
918
919
0
        if (!timercmp(&time_now, &limit_time, <)) {
920
          /* time limit expired; don't attempt any further connections */
921
0
          fatal = 1;
922
0
        } else {
923
          /* work out remaining time */
924
0
          sub_times(limit_time, time_now, &working_timeout);
925
0
        }
926
0
      }
927
#else
928
      if (error_code && *error_code == PHP_TIMEOUT_ERROR_VALUE) {
929
        /* Don't even bother trying to connect to the next alternative;
930
         * we have no way to determine how long we have already taken
931
         * and it is quite likely that the next attempt will fail too. */
932
        fatal = 1;
933
      } else {
934
        /* re-use the same initial timeout.
935
         * Not the best thing, but in practice it should be good-enough */
936
        if (timeout) {
937
          memcpy(&working_timeout, timeout, sizeof(working_timeout));
938
        }
939
      }
940
#endif
941
0
    }
942
943
0
    closesocket(sock);
944
0
  }
945
0
  sock = -1;
946
947
0
connected:
948
949
0
  php_network_freeaddresses(psal);
950
951
0
  return sock;
952
0
}
953
/* }}} */
954
955
/* {{{ php_any_addr
956
 * Fills the any (wildcard) address into php_sockaddr_storage
957
 */
958
PHPAPI void php_any_addr(int family, php_sockaddr_storage *addr, unsigned short port)
959
0
{
960
0
  memset(addr, 0, sizeof(php_sockaddr_storage));
961
0
  switch (family) {
962
0
#if HAVE_IPV6
963
0
  case AF_INET6: {
964
0
    struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr;
965
0
    sin6->sin6_family = AF_INET6;
966
0
    sin6->sin6_port = htons(port);
967
0
    sin6->sin6_addr = in6addr_any;
968
0
    break;
969
0
  }
970
0
#endif
971
0
  case AF_INET: {
972
0
    struct sockaddr_in *sin = (struct sockaddr_in *) addr;
973
0
    sin->sin_family = AF_INET;
974
0
    sin->sin_port = htons(port);
975
0
    sin->sin_addr.s_addr = htonl(INADDR_ANY);
976
0
    break;
977
0
  }
978
0
  }
979
0
}
980
/* }}} */
981
982
/* {{{ php_sockaddr_size
983
 * Returns the size of struct sockaddr_xx for the family
984
 */
985
PHPAPI int php_sockaddr_size(php_sockaddr_storage *addr)
986
0
{
987
0
  switch (((struct sockaddr *)addr)->sa_family) {
988
0
  case AF_INET:
989
0
    return sizeof(struct sockaddr_in);
990
0
#if HAVE_IPV6
991
0
  case AF_INET6:
992
0
    return sizeof(struct sockaddr_in6);
993
0
#endif
994
0
#ifdef AF_UNIX
995
0
  case AF_UNIX:
996
0
    return sizeof(struct sockaddr_un);
997
0
#endif
998
0
  default:
999
0
    return 0;
1000
0
  }
1001
0
}
1002
/* }}} */
1003
1004
/* Given a socket error code, if buf == NULL:
1005
 *   emallocs storage for the error message and returns
1006
 * else
1007
 *   sprintf message into provided buffer and returns buf
1008
 */
1009
/* {{{ php_socket_strerror */
1010
PHPAPI char *php_socket_strerror(long err, char *buf, size_t bufsize)
1011
0
{
1012
0
#ifndef PHP_WIN32
1013
0
  char *errstr;
1014
1015
0
  errstr = strerror(err);
1016
0
  if (buf == NULL) {
1017
0
    buf = estrdup(errstr);
1018
0
  } else {
1019
0
    strncpy(buf, errstr, bufsize);
1020
0
    buf[bufsize?(bufsize-1):0] = 0;
1021
0
  }
1022
0
  return buf;
1023
#else
1024
  char *sysbuf = php_win32_error_to_msg(err);
1025
  if (!sysbuf[0]) {
1026
    sysbuf = "Unknown Error";
1027
  }
1028
1029
  if (buf == NULL) {
1030
    buf = estrdup(sysbuf);
1031
  } else {
1032
    strncpy(buf, sysbuf, bufsize);
1033
    buf[bufsize?(bufsize-1):0] = 0;
1034
  }
1035
1036
  php_win32_error_msg_free(sysbuf);
1037
1038
  return buf;
1039
#endif
1040
0
}
1041
/* }}} */
1042
1043
/* {{{ php_socket_error_str */
1044
PHPAPI zend_string *php_socket_error_str(long err)
1045
0
{
1046
0
#ifndef PHP_WIN32
1047
0
  char *errstr;
1048
1049
0
  errstr = strerror(err);
1050
0
  return zend_string_init(errstr, strlen(errstr), 0);
1051
#else
1052
  zend_string *ret;
1053
1054
  char *sysbuf = php_win32_error_to_msg(err);
1055
  if (!sysbuf[0]) {
1056
    sysbuf = "Unknown Error";
1057
  }
1058
1059
  ret = zend_string_init(sysbuf, strlen(sysbuf), 0);
1060
1061
  php_win32_error_msg_free(sysbuf);
1062
1063
  return ret;
1064
#endif
1065
0
}
1066
/* }}} */
1067
1068
/* deprecated */
1069
PHPAPI php_stream *_php_stream_sock_open_from_socket(php_socket_t socket, const char *persistent_id STREAMS_DC)
1070
0
{
1071
0
  php_stream *stream;
1072
0
  php_netstream_data_t *sock;
1073
1074
0
  sock = pemalloc(sizeof(php_netstream_data_t), persistent_id ? 1 : 0);
1075
0
  memset(sock, 0, sizeof(php_netstream_data_t));
1076
1077
0
  sock->is_blocked = 1;
1078
0
  sock->timeout.tv_sec = FG(default_socket_timeout);
1079
0
  sock->timeout.tv_usec = 0;
1080
0
  sock->socket = socket;
1081
1082
0
  stream = php_stream_alloc_rel(&php_stream_generic_socket_ops, sock, persistent_id, "r+");
1083
1084
0
  if (stream == NULL) {
1085
0
    pefree(sock, persistent_id ? 1 : 0);
1086
0
  } else {
1087
0
    stream->flags |= PHP_STREAM_FLAG_AVOID_BLOCKING;
1088
0
  }
1089
1090
0
  return stream;
1091
0
}
1092
1093
PHPAPI php_stream *_php_stream_sock_open_host(const char *host, unsigned short port,
1094
    int socktype, struct timeval *timeout, const char *persistent_id STREAMS_DC)
1095
0
{
1096
0
  char *res;
1097
0
  zend_long reslen;
1098
0
  php_stream *stream;
1099
1100
0
  reslen = spprintf(&res, 0, "tcp://%s:%d", host, port);
1101
1102
0
  stream = php_stream_xport_create(res, reslen, REPORT_ERRORS,
1103
0
      STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, persistent_id, timeout, NULL, NULL, NULL);
1104
1105
0
  efree(res);
1106
1107
0
  return stream;
1108
0
}
1109
1110
PHPAPI int php_set_sock_blocking(php_socket_t socketd, int block)
1111
0
{
1112
0
  int ret = SUCCESS;
1113
1114
#ifdef PHP_WIN32
1115
  u_long flags;
1116
1117
  /* with ioctlsocket, a non-zero sets nonblocking, a zero sets blocking */
1118
  flags = !block;
1119
  if (ioctlsocket(socketd, FIONBIO, &flags) == SOCKET_ERROR) {
1120
    ret = FAILURE;
1121
  }
1122
#else
1123
0
  int myflag = 0;
1124
0
  int flags = fcntl(socketd, F_GETFL);
1125
1126
0
#ifdef O_NONBLOCK
1127
0
  myflag = O_NONBLOCK; /* POSIX version */
1128
#elif defined(O_NDELAY)
1129
  myflag = O_NDELAY;   /* old non-POSIX version */
1130
#endif
1131
0
  if (!block) {
1132
0
    flags |= myflag;
1133
0
  } else {
1134
0
    flags &= ~myflag;
1135
0
  }
1136
0
  if (fcntl(socketd, F_SETFL, flags) == -1) {
1137
0
    ret = FAILURE;
1138
0
  }
1139
0
#endif
1140
0
  return ret;
1141
0
}
1142
1143
PHPAPI void _php_emit_fd_setsize_warning(int max_fd)
1144
0
{
1145
1146
#ifdef PHP_WIN32
1147
  php_error_docref(NULL, E_WARNING,
1148
    "PHP needs to be recompiled with a larger value of FD_SETSIZE.\n"
1149
    "If this binary is from an official www.php.net package, file a bug report\n"
1150
    "at http://bugs.php.net, including the following information:\n"
1151
    "FD_SETSIZE=%d, but you are using %d.\n"
1152
    " --enable-fd-setsize=%d is recommended, but you may want to set it\n"
1153
    "to match to maximum number of sockets each script will work with at\n"
1154
    "one time, in order to avoid seeing this error again at a later date.",
1155
    FD_SETSIZE, max_fd, (max_fd + 128) & ~127);
1156
#else
1157
0
  php_error_docref(NULL, E_WARNING,
1158
0
    "You MUST recompile PHP with a larger value of FD_SETSIZE.\n"
1159
0
    "It is set to %d, but you have descriptors numbered at least as high as %d.\n"
1160
0
    " --enable-fd-setsize=%d is recommended, but you may want to set it\n"
1161
0
    "to equal the maximum number of open files supported by your system,\n"
1162
0
    "in order to avoid seeing this error again at a later date.",
1163
0
    FD_SETSIZE, max_fd, (max_fd + 1024) & ~1023);
1164
0
#endif
1165
0
}
1166
1167
#if defined(PHP_USE_POLL_2_EMULATION)
1168
1169
/* emulate poll(2) using select(2), safely. */
1170
1171
PHPAPI int php_poll2(php_pollfd *ufds, unsigned int nfds, int timeout)
1172
{
1173
  fd_set rset, wset, eset;
1174
  php_socket_t max_fd = SOCK_ERR; /* effectively unused on Windows */
1175
  unsigned int i;
1176
  int n;
1177
  struct timeval tv;
1178
1179
#ifndef PHP_WIN32
1180
  /* check the highest numbered descriptor */
1181
  for (i = 0; i < nfds; i++) {
1182
    if (ufds[i].fd > max_fd)
1183
      max_fd = ufds[i].fd;
1184
  }
1185
#endif
1186
1187
  PHP_SAFE_MAX_FD(max_fd, nfds + 1);
1188
1189
  FD_ZERO(&rset);
1190
  FD_ZERO(&wset);
1191
  FD_ZERO(&eset);
1192
1193
  for (i = 0; i < nfds; i++) {
1194
    if (ufds[i].events & PHP_POLLREADABLE) {
1195
      PHP_SAFE_FD_SET(ufds[i].fd, &rset);
1196
    }
1197
    if (ufds[i].events & POLLOUT) {
1198
      PHP_SAFE_FD_SET(ufds[i].fd, &wset);
1199
    }
1200
    if (ufds[i].events & POLLPRI) {
1201
      PHP_SAFE_FD_SET(ufds[i].fd, &eset);
1202
    }
1203
  }
1204
1205
  if (timeout >= 0) {
1206
    tv.tv_sec = timeout / 1000;
1207
    tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000;
1208
  }
1209
/* Resetting/initializing */
1210
#ifdef PHP_WIN32
1211
  WSASetLastError(0);
1212
#else
1213
  errno = 0;
1214
#endif
1215
  n = select(max_fd + 1, &rset, &wset, &eset, timeout >= 0 ? &tv : NULL);
1216
1217
  if (n >= 0) {
1218
    for (i = 0; i < nfds; i++) {
1219
      ufds[i].revents = 0;
1220
1221
      if (PHP_SAFE_FD_ISSET(ufds[i].fd, &rset)) {
1222
        /* could be POLLERR or POLLHUP but can't tell without probing */
1223
        ufds[i].revents |= POLLIN;
1224
      }
1225
      if (PHP_SAFE_FD_ISSET(ufds[i].fd, &wset)) {
1226
        ufds[i].revents |= POLLOUT;
1227
      }
1228
      if (PHP_SAFE_FD_ISSET(ufds[i].fd, &eset)) {
1229
        ufds[i].revents |= POLLPRI;
1230
      }
1231
    }
1232
  }
1233
  return n;
1234
}
1235
#endif
1236
1237
#if defined(HAVE_GETHOSTBYNAME_R)
1238
#ifdef HAVE_FUNC_GETHOSTBYNAME_R_6
1239
struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen)
1240
0
{
1241
0
  struct hostent *hp;
1242
0
  int herr,res;
1243
1244
0
  if (*hstbuflen == 0) {
1245
0
    *hstbuflen = 1024;
1246
0
    *tmphstbuf = (char *)malloc (*hstbuflen);
1247
0
  }
1248
1249
0
  while (( res =
1250
0
    gethostbyname_r(host,hostbuf,*tmphstbuf,*hstbuflen,&hp,&herr))
1251
0
    && (errno == ERANGE)) {
1252
    /* Enlarge the buffer. */
1253
0
    *hstbuflen *= 2;
1254
0
    *tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen);
1255
0
  }
1256
1257
0
  if (res != SUCCESS) {
1258
0
    return NULL;
1259
0
  }
1260
1261
0
  return hp;
1262
0
}
1263
#endif
1264
#ifdef HAVE_FUNC_GETHOSTBYNAME_R_5
1265
struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen)
1266
{
1267
  struct hostent *hp;
1268
  int herr;
1269
1270
  if (*hstbuflen == 0) {
1271
    *hstbuflen = 1024;
1272
    *tmphstbuf = (char *)malloc (*hstbuflen);
1273
  }
1274
1275
  while ((NULL == ( hp =
1276
    gethostbyname_r(host,hostbuf,*tmphstbuf,*hstbuflen,&herr)))
1277
    && (errno == ERANGE)) {
1278
    /* Enlarge the buffer. */
1279
    *hstbuflen *= 2;
1280
    *tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen);
1281
  }
1282
  return hp;
1283
}
1284
#endif
1285
#ifdef HAVE_FUNC_GETHOSTBYNAME_R_3
1286
struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen)
1287
{
1288
  if (*hstbuflen == 0) {
1289
    *hstbuflen = sizeof(struct hostent_data);
1290
    *tmphstbuf = (char *)malloc (*hstbuflen);
1291
  } else {
1292
    if (*hstbuflen < sizeof(struct hostent_data)) {
1293
      *hstbuflen = sizeof(struct hostent_data);
1294
      *tmphstbuf = (char *)realloc(*tmphstbuf, *hstbuflen);
1295
    }
1296
  }
1297
  memset((void *)(*tmphstbuf),0,*hstbuflen);
1298
1299
  if (SUCCESS != gethostbyname_r(host,hostbuf,(struct hostent_data *)*tmphstbuf)) {
1300
    return NULL;
1301
  }
1302
1303
  return hostbuf;
1304
}
1305
#endif
1306
#endif
1307
1308
0
PHPAPI struct hostent*  php_network_gethostbyname(const char *name) {
1309
#if !defined(HAVE_GETHOSTBYNAME_R)
1310
  return gethostbyname(name);
1311
#else
1312
0
  if (FG(tmp_host_buf)) {
1313
0
    free(FG(tmp_host_buf));
1314
0
  }
1315
1316
0
  FG(tmp_host_buf) = NULL;
1317
0
  FG(tmp_host_buf_len) = 0;
1318
1319
0
  memset(&FG(tmp_host_info), 0, sizeof(struct hostent));
1320
1321
0
  return gethostname_re(name, &FG(tmp_host_info), &FG(tmp_host_buf), &FG(tmp_host_buf_len));
1322
0
#endif
1323
0
}