root/ext/sockets/sockaddr_conv.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_set_inet6_addr
  2. php_set_inet_addr
  3. php_set_inet46_addr

#include <php.h>
#include <php_network.h>
#include "php_sockets.h"

#ifdef PHP_WIN32
#include "windows_common.h"
#else
#include <netdb.h>
#include <arpa/inet.h>
#endif

extern int php_string_to_if_index(const char *val, unsigned *out TSRMLS_DC);

#if HAVE_IPV6
/* Sets addr by hostname, or by ip in string form (AF_INET6) */
int php_set_inet6_addr(struct sockaddr_in6 *sin6, char *string, php_socket *php_sock TSRMLS_DC) /* {{{ */
{
        struct in6_addr tmp;
#if HAVE_GETADDRINFO
        struct addrinfo hints;
        struct addrinfo *addrinfo = NULL;
#endif
        char *scope = strchr(string, '%');

        if (inet_pton(AF_INET6, string, &tmp)) {
                memcpy(&(sin6->sin6_addr.s6_addr), &(tmp.s6_addr), sizeof(struct in6_addr));
        } else {
#if HAVE_GETADDRINFO

                memset(&hints, 0, sizeof(struct addrinfo));
                hints.ai_family = AF_INET6;
#if HAVE_AI_V4MAPPED
                hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
#else
                hints.ai_flags = AI_ADDRCONFIG;
#endif
                getaddrinfo(string, NULL, &hints, &addrinfo);
                if (!addrinfo) {
#ifdef PHP_WIN32
                        PHP_SOCKET_ERROR(php_sock, "Host lookup failed", WSAGetLastError());
#else
                        PHP_SOCKET_ERROR(php_sock, "Host lookup failed", (-10000 - h_errno));
#endif
                        return 0;
                }
                if (addrinfo->ai_family != PF_INET6 || addrinfo->ai_addrlen != sizeof(struct sockaddr_in6)) {
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host lookup failed: Non AF_INET6 domain returned on AF_INET6 socket");
                        freeaddrinfo(addrinfo);
                        return 0;
                }

                memcpy(&(sin6->sin6_addr.s6_addr), ((struct sockaddr_in6*)(addrinfo->ai_addr))->sin6_addr.s6_addr, sizeof(struct in6_addr));
                freeaddrinfo(addrinfo);

#else
                /* No IPv6 specific hostname resolution is available on this system? */
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host lookup failed: getaddrinfo() not available on this system");
                return 0;
#endif

        }

        if (scope++) {
                long lval = 0;
                double dval = 0;
                unsigned scope_id = 0;

                if (IS_LONG == is_numeric_string(scope, strlen(scope), &lval, &dval, 0)) {
                        if (lval > 0 && lval <= UINT_MAX) {
                                scope_id = lval;
                        }
                } else {
                        php_string_to_if_index(scope, &scope_id TSRMLS_CC);
                }

                sin6->sin6_scope_id = scope_id;
        }

        return 1;
}
/* }}} */
#endif

/* Sets addr by hostname, or by ip in string form (AF_INET)  */
int php_set_inet_addr(struct sockaddr_in *sin, char *string, php_socket *php_sock TSRMLS_DC) /* {{{ */
{
        struct in_addr tmp;
        struct hostent *host_entry;

        if (inet_aton(string, &tmp)) {
                sin->sin_addr.s_addr = tmp.s_addr;
        } else {
                if (strlen(string) > MAXFQDNLEN || ! (host_entry = gethostbyname(string))) {
                        /* Note: < -10000 indicates a host lookup error */
#ifdef PHP_WIN32
                        PHP_SOCKET_ERROR(php_sock, "Host lookup failed", WSAGetLastError());
#else
                        PHP_SOCKET_ERROR(php_sock, "Host lookup failed", (-10000 - h_errno));
#endif
                        return 0;
                }
                if (host_entry->h_addrtype != AF_INET) {
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host lookup failed: Non AF_INET domain returned on AF_INET socket");
                        return 0;
                }
                memcpy(&(sin->sin_addr.s_addr), host_entry->h_addr_list[0], host_entry->h_length);
        }

        return 1;
}
/* }}} */

/* Sets addr by hostname or by ip in string form (AF_INET or AF_INET6,
 * depending on the socket) */
int php_set_inet46_addr(php_sockaddr_storage *ss, socklen_t *ss_len, char *string, php_socket *php_sock TSRMLS_DC) /* {{{ */
{
        if (php_sock->type == AF_INET) {
                struct sockaddr_in t = {0};
                if (php_set_inet_addr(&t, string, php_sock TSRMLS_CC)) {
                        memcpy(ss, &t, sizeof t);
                        ss->ss_family = AF_INET;
                        *ss_len = sizeof(t);
                        return 1;
                }
        }
#if HAVE_IPV6
        else if (php_sock->type == AF_INET6) {
                struct sockaddr_in6 t = {0};
                if (php_set_inet6_addr(&t, string, php_sock TSRMLS_CC)) {
                        memcpy(ss, &t, sizeof t);
                        ss->ss_family = AF_INET6;
                        *ss_len = sizeof(t);
                        return 1;
                }
        }
#endif
        else {
                php_error_docref(NULL TSRMLS_CC, E_WARNING,
                        "IP address used in the context of an unexpected type of socket");
        }
        return 0;
}

/* [<][>][^][v][top][bottom][index][help] */