network.c 33 KB

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