/* 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) /* {{{ */ { 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 = php_network_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, 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; }
int php_do_setsockopt_ipv6_rfc3542(php_socket *php_sock, int level, int optname, zval *arg4) { struct err_s err = {0}; zend_llist *allocations = NULL; void *opt_ptr; socklen_t optlen; int retval; assert(level == IPPROTO_IPV6); switch (optname) { #ifdef IPV6_PKTINFO case IPV6_PKTINFO: #ifdef PHP_WIN32 if (Z_TYPE_P(arg4) == IS_ARRAY) { php_error_docref0(NULL, E_WARNING, "Windows does not " "support sticky IPV6_PKTINFO"); return FAILURE; } else { /* windows has no IPV6_RECVPKTINFO, and uses IPV6_PKTINFO * for the same effect. We define IPV6_RECVPKTINFO to be * IPV6_PKTINFO, so assume the assume user used IPV6_RECVPKTINFO */ return 1; } #endif opt_ptr = from_zval_run_conversions(arg4, php_sock, from_zval_write_in6_pktinfo, sizeof(struct in6_pktinfo), "in6_pktinfo", &allocations, &err); if (err.has_error) { err_msg_dispose(&err); return FAILURE; } optlen = sizeof(struct in6_pktinfo); goto dosockopt; #endif } /* we also support IPV6_TCLASS, but that can be handled by the default * integer optval handling in the caller */ return 1; dosockopt: retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen); if (retval != 0) { PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno); } allocations_dispose(&allocations); return retval != 0 ? FAILURE : SUCCESS; }
int php_do_getsockopt_ipv6_rfc3542(php_socket *php_sock, int level, int optname, zval *result) { struct err_s err = {0}; void *buffer; socklen_t size; int res; to_zval_read_field *reader; assert(level == IPPROTO_IPV6); switch (optname) { #ifdef IPV6_PKTINFO case IPV6_PKTINFO: size = sizeof(struct in6_pktinfo); reader = &to_zval_read_in6_pktinfo; break; #endif default: return 1; } buffer = ecalloc(1, size); res = getsockopt(php_sock->bsd_socket, level, optname, buffer, &size); if (res != 0) { PHP_SOCKET_ERROR(php_sock, "unable to get socket option", errno); } else { zval tmp; zval *zv = to_zval_run_conversions(buffer, reader, "in6_pktinfo", empty_key_value_list, &err, &tmp); if (err.has_error) { err_msg_dispose(&err); res = -1; } else { ZVAL_COPY_VALUE(result, zv); } } efree(buffer); return res == 0 ? SUCCESS : FAILURE; }
int php_do_setsockopt_ipv6_mcast(php_socket *php_sock, int level, int optname, zval *arg4) { unsigned int if_index; void *opt_ptr; socklen_t optlen; int ov; int retval; switch (optname) { case PHP_MCAST_JOIN_GROUP: case PHP_MCAST_LEAVE_GROUP: #ifdef HAS_MCAST_EXT case PHP_MCAST_BLOCK_SOURCE: case PHP_MCAST_UNBLOCK_SOURCE: case PHP_MCAST_JOIN_SOURCE_GROUP: case PHP_MCAST_LEAVE_SOURCE_GROUP: #endif if (php_do_mcast_opt(php_sock, level, optname, arg4) == FAILURE) { return FAILURE; } else { return SUCCESS; } case IPV6_MULTICAST_IF: if (php_get_if_index_from_zval(arg4, &if_index) == FAILURE) { return FAILURE; } opt_ptr = &if_index; optlen = sizeof(if_index); goto dosockopt; case IPV6_MULTICAST_LOOP: convert_to_boolean_ex(arg4); ov = (int) Z_TYPE_P(arg4) == IS_TRUE; goto ipv6_loop_hops; case IPV6_MULTICAST_HOPS: convert_to_long_ex(arg4); if (Z_LVAL_P(arg4) < -1L || Z_LVAL_P(arg4) > 255L) { php_error_docref(NULL, E_WARNING, "Expected a value between -1 and 255"); return FAILURE; } ov = (int) Z_LVAL_P(arg4); ipv6_loop_hops: opt_ptr = &ov; optlen = sizeof(ov); goto dosockopt; } return 1; /* not handled */ dosockopt: retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen); if (retval != 0) { PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno); return FAILURE; } return SUCCESS; }
int php_do_setsockopt_ip_mcast(php_socket *php_sock, int level, int optname, zval *arg4) { unsigned int if_index; struct in_addr if_addr; void *opt_ptr; socklen_t optlen; unsigned char ipv4_mcast_ttl_lback; int retval; switch (optname) { case PHP_MCAST_JOIN_GROUP: case PHP_MCAST_LEAVE_GROUP: #ifdef HAS_MCAST_EXT case PHP_MCAST_BLOCK_SOURCE: case PHP_MCAST_UNBLOCK_SOURCE: case PHP_MCAST_JOIN_SOURCE_GROUP: case PHP_MCAST_LEAVE_SOURCE_GROUP: #endif if (php_do_mcast_opt(php_sock, level, optname, arg4) == FAILURE) { return FAILURE; } else { return SUCCESS; } case IP_MULTICAST_IF: if (php_get_if_index_from_zval(arg4, &if_index) == FAILURE) { return FAILURE; } if (php_if_index_to_addr4(if_index, php_sock, &if_addr) == FAILURE) { return FAILURE; } opt_ptr = &if_addr; optlen = sizeof(if_addr); goto dosockopt; case IP_MULTICAST_LOOP: convert_to_boolean_ex(arg4); ipv4_mcast_ttl_lback = (unsigned char) (Z_TYPE_P(arg4) == IS_TRUE); goto ipv4_loop_ttl; case IP_MULTICAST_TTL: convert_to_long_ex(arg4); if (Z_LVAL_P(arg4) < 0L || Z_LVAL_P(arg4) > 255L) { php_error_docref(NULL, E_WARNING, "Expected a value between 0 and 255"); return FAILURE; } ipv4_mcast_ttl_lback = (unsigned char) Z_LVAL_P(arg4); ipv4_loop_ttl: opt_ptr = &ipv4_mcast_ttl_lback; optlen = sizeof(ipv4_mcast_ttl_lback); goto dosockopt; } return 1; dosockopt: retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen); if (retval != 0) { PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno); return FAILURE; } return SUCCESS; }
static int php_do_mcast_opt(php_socket *php_sock, int level, int optname, zval *arg4) { HashTable *opt_ht; unsigned int if_index; int retval; int (*mcast_req_fun)(php_socket *, int, struct sockaddr *, socklen_t, unsigned); #ifdef HAS_MCAST_EXT int (*mcast_sreq_fun)(php_socket *, int, struct sockaddr *, socklen_t, struct sockaddr *, socklen_t, unsigned); #endif switch (optname) { case PHP_MCAST_JOIN_GROUP: mcast_req_fun = &php_mcast_join; goto mcast_req_fun; case PHP_MCAST_LEAVE_GROUP: { php_sockaddr_storage group = {0}; socklen_t glen; mcast_req_fun = &php_mcast_leave; mcast_req_fun: convert_to_array_ex(arg4); opt_ht = Z_ARRVAL_P(arg4); if (php_get_address_from_array(opt_ht, "group", php_sock, &group, &glen) == FAILURE) { return FAILURE; } if (php_get_if_index_from_array(opt_ht, "interface", php_sock, &if_index) == FAILURE) { return FAILURE; } retval = mcast_req_fun(php_sock, level, (struct sockaddr*)&group, glen, if_index); break; } #ifdef HAS_MCAST_EXT case PHP_MCAST_BLOCK_SOURCE: mcast_sreq_fun = &php_mcast_block_source; goto mcast_sreq_fun; case PHP_MCAST_UNBLOCK_SOURCE: mcast_sreq_fun = &php_mcast_unblock_source; goto mcast_sreq_fun; case PHP_MCAST_JOIN_SOURCE_GROUP: mcast_sreq_fun = &php_mcast_join_source; goto mcast_sreq_fun; case PHP_MCAST_LEAVE_SOURCE_GROUP: { php_sockaddr_storage group = {0}, source = {0}; socklen_t glen, slen; mcast_sreq_fun = &php_mcast_leave_source; mcast_sreq_fun: convert_to_array_ex(arg4); opt_ht = Z_ARRVAL_P(arg4); if (php_get_address_from_array(opt_ht, "group", php_sock, &group, &glen) == FAILURE) { return FAILURE; } if (php_get_address_from_array(opt_ht, "source", php_sock, &source, &slen) == FAILURE) { return FAILURE; } if (php_get_if_index_from_array(opt_ht, "interface", php_sock, &if_index) == FAILURE) { return FAILURE; } retval = mcast_sreq_fun(php_sock, level, (struct sockaddr*)&group, glen, (struct sockaddr*)&source, slen, if_index); break; } #endif default: php_error_docref(NULL, E_WARNING, "unexpected option in php_do_mcast_opt (level %d, option %d). " "This is a bug.", level, optname); return FAILURE; } if (retval != 0) { if (retval != -2) { /* error, but message already emitted */ PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno); } return FAILURE; } return SUCCESS; }
/* 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) /* {{{ */ { 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, 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, E_WARNING, "Host lookup failed: getaddrinfo() not available on this system"); return 0; #endif } if (scope++) { zend_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); } sin6->sin6_scope_id = scope_id; } return 1; }