summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSara Golemon <pollita@php.net>2003-04-17 21:04:47 +0000
committerSara Golemon <pollita@php.net>2003-04-17 21:04:47 +0000
commitd06232a871b159ca93d331c986f42f5109d7e754 (patch)
tree2403ebd7e82ae7c04f84895ee6c38888a178fd27
parent0098ae7dc69ce2c4b1aa53bf6130e5387bbc3b4a (diff)
downloadphp-git-d06232a871b159ca93d331c986f42f5109d7e754.tar.gz
Add IPv6 support to ext/sockets
-rw-r--r--NEWS1
-rw-r--r--TODO1
-rw-r--r--ext/sockets/sockets.c286
3 files changed, 278 insertions, 10 deletions
diff --git a/NEWS b/NEWS
index e07232354c..c057e81042 100644
--- a/NEWS
+++ b/NEWS
@@ -21,6 +21,7 @@ PHP NEWS
- Changed array_search() to accept also objects as a needle. (Moriyoshi)
- Changed ext/mcrypt to require libmcrypt version 2.5.6 or greater. (Derick)
- Changed uniqid() parameters to be optional and allow any prefix length. (Marcus)
+- Added IPv6 support to ext/sockets. (Sara)
- Added context options to http_fopen_wrapper 'method', 'header', 'content'. (Sara)
- Added domdocument->create_document_fragment() and documentfragment->open_mem()
methods to domxml. (Rob Richards, Chregu)
diff --git a/TODO b/TODO
index 860bcfbe06..09f1dfdea4 100644
--- a/TODO
+++ b/TODO
@@ -127,7 +127,6 @@ ext/session
ext/sockets
-----------
- * Implement IPv6
* Review/Fix vectors
ext/standard
diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c
index 672e10430f..a4a0eebf76 100644
--- a/ext/sockets/sockets.c
+++ b/ext/sockets/sockets.c
@@ -370,6 +370,34 @@ static char *php_strerror(int error TSRMLS_DC) {
return (buf ? (char *) buf : "");
}
+#ifdef 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;
+ struct hostent *host_entry;
+
+ if (inet_pton(AF_INET6, string, &tmp)) {
+ memcpy(&(sin6->sin6_addr.s6_addr), &(tmp.s6_addr), sizeof(struct in6_addr));
+ } else {
+ if (! (host_entry = gethostbyname2(string, AF_INET6))) {
+#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_INET6) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host lookup failed: Non AF_INET6 domain returned on AF_INET6 socket");
+ return 0;
+ }
+ memcpy(&(sin6->sin6_addr.s6_addr), host_entry->h_addr_list[0], host_entry->h_length);
+ }
+
+ 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;
@@ -417,6 +445,9 @@ PHP_MINIT_FUNCTION(sockets)
REGISTER_LONG_CONSTANT("AF_UNIX", AF_UNIX, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("AF_INET", AF_INET, CONST_CS | CONST_PERSISTENT);
+#ifdef HAVE_IPV6
+ REGISTER_LONG_CONSTANT("AF_INET6", AF_INET6, CONST_CS | CONST_PERSISTENT);
+#endif
REGISTER_LONG_CONSTANT("SOCK_STREAM", SOCK_STREAM, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOCK_DGRAM", SOCK_DGRAM, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOCK_RAW", SOCK_RAW, CONST_CS | CONST_PERSISTENT);
@@ -825,6 +856,10 @@ PHP_FUNCTION(socket_getsockname)
php_socket *php_sock;
struct sockaddr *sa;
struct sockaddr_in *sin;
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 *sin6;
+ char addr6[INET6_ADDRSTRLEN+1];
+#endif
struct sockaddr_un *s_un;
char *addr_string;
socklen_t salen = sizeof(php_sockaddr_storage);
@@ -842,6 +877,20 @@ PHP_FUNCTION(socket_getsockname)
}
switch (sa->sa_family) {
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *) sa;
+ inet_ntop(AF_INET6, &sin6->sin6_addr, addr6, INET6_ADDRSTRLEN);
+ zval_dtor(addr);
+ ZVAL_STRING(addr, addr6, 1);
+
+ if (port != NULL) {
+ zval_dtor(port);
+ ZVAL_LONG(port, htons(sin6->sin6_port));
+ }
+ RETURN_TRUE;
+ break;
+#endif
case AF_INET:
sin = (struct sockaddr_in *) sa;
while (inet_ntoa_lock == 1);
@@ -857,6 +906,7 @@ PHP_FUNCTION(socket_getsockname)
ZVAL_LONG(port, htons(sin->sin_port));
}
RETURN_TRUE;
+ break;
case AF_UNIX:
s_un = (struct sockaddr_un *) sa;
@@ -864,6 +914,7 @@ PHP_FUNCTION(socket_getsockname)
zval_dtor(addr);
ZVAL_STRING(addr, s_un->sun_path, 1);
RETURN_TRUE;
+ break;
default:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported address family %d", sa->sa_family);
@@ -881,6 +932,10 @@ PHP_FUNCTION(socket_getpeername)
php_socket *php_sock;
struct sockaddr *sa;
struct sockaddr_in *sin;
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 *sin6;
+ char addr6[INET6_ADDRSTRLEN+1];
+#endif
struct sockaddr_un *s_un;
char *addr_string;
socklen_t salen = sizeof(php_sockaddr_storage);
@@ -898,6 +953,21 @@ PHP_FUNCTION(socket_getpeername)
}
switch (sa->sa_family) {
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *) sa;
+ inet_ntop(AF_INET6, &sin6->sin6_addr, addr6, INET6_ADDRSTRLEN);
+ zval_dtor(arg2);
+ ZVAL_STRING(arg2, addr6, 1);
+
+ if (arg3 != NULL) {
+ zval_dtor(arg3);
+ ZVAL_LONG(arg3, htons(sin6->sin6_port));
+ }
+
+ RETURN_TRUE;
+ break;
+#endif
case AF_INET:
sin = (struct sockaddr_in *) sa;
while (inet_ntoa_lock == 1);
@@ -914,6 +984,7 @@ PHP_FUNCTION(socket_getpeername)
}
RETURN_TRUE;
+ break;
case AF_UNIX:
s_un = (struct sockaddr_un *) sa;
@@ -921,6 +992,7 @@ PHP_FUNCTION(socket_getpeername)
zval_dtor(arg2);
ZVAL_STRING(arg2, s_un->sun_path, 1);
RETURN_TRUE;
+ break;
default:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported address family %d", sa->sa_family);
@@ -941,7 +1013,11 @@ PHP_FUNCTION(socket_create)
return;
}
- if (arg1 != AF_UNIX && arg1 != AF_INET) {
+ if (arg1 != AF_UNIX
+#ifdef HAVE_IPV6
+ && arg1 != AF_INET6
+#endif
+ && arg1 != AF_INET) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid socket domain [%d] specified for argument 1, assuming AF_INET", arg1);
arg1 = AF_INET;
}
@@ -972,19 +1048,40 @@ PHP_FUNCTION(socket_connect)
zval *arg1;
php_socket *php_sock;
struct sockaddr_in sin;
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 sin6;
+#endif
struct sockaddr_un s_un;
char *addr;
int retval, addr_len;
- long port;
+ long port;
+ int argc = ZEND_NUM_ARGS();
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l", &arg1, &addr, &addr_len, &port) == FAILURE)
+ if (zend_parse_parameters(argc TSRMLS_CC, "rs|l", &arg1, &addr, &addr_len, &port) == FAILURE)
return;
ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
switch(php_sock->type) {
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ if (argc != 3) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Socket of type AF_INET6 requires 3 arguments");
+ RETURN_FALSE;
+ }
+
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_port = htons((unsigned short int)port);
+
+ if (! php_set_inet6_addr(&sin6, addr, php_sock TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+
+ retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin6, sizeof(struct sockaddr_in6));
+ break;
+#endif
case AF_INET:
- if (ZEND_NUM_ARGS() != 3) {
+ if (argc != 3) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Socket of type AF_INET requires 3 arguments");
RETURN_FALSE;
}
@@ -1077,9 +1174,26 @@ PHP_FUNCTION(socket_bind)
retval = bind(php_sock->bsd_socket, (struct sockaddr *)sa, sizeof(struct sockaddr_in));
break;
}
-
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sa = (struct sockaddr_in6 *) sock_type;
+
+ memset(sa, 0, sizeof(sa_storage)); /* Apparently, Mac OSX needs this */
+
+ sa->sin6_family = AF_INET6;
+ sa->sin6_port = htons((unsigned short) port);
+
+ if (! php_set_inet6_addr(sa, addr, php_sock TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+
+ retval = bind(php_sock->bsd_socket, (struct sockaddr *)sa, sizeof(struct sockaddr_in6));
+ break;
+ }
+#endif
default:
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "unsupported socket type '%d', must be AF_UNIX or AF_INET", php_sock->type);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "unsupported socket type '%d', must be AF_UNIX, AF_INET, or AF_INET6", php_sock->type);
RETURN_FALSE;
}
@@ -1392,6 +1506,10 @@ PHP_FUNCTION(socket_recvfrom)
php_socket *php_sock;
struct sockaddr_un s_un;
struct sockaddr_in sin;
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 sin6;
+ char addr6[INET6_ADDRSTRLEN];
+#endif
socklen_t slen;
int retval;
long arg3, arg4;
@@ -1451,7 +1569,35 @@ PHP_FUNCTION(socket_recvfrom)
ZVAL_STRING(arg5, address ? address : "0.0.0.0", 1);
ZVAL_LONG(arg6, ntohs(sin.sin_port));
break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ slen = sizeof(sin6);
+ memset(&sin6, 0, slen);
+ sin6.sin6_family = AF_INET6;
+
+ if (arg6 == NULL) {
+ WRONG_PARAM_COUNT;
+ }
+
+ retval = recvfrom(php_sock->bsd_socket, recv_buf, arg3, arg4, (struct sockaddr *)&sin6, (socklen_t *)&slen);
+
+ if (retval < 0) {
+ efree(recv_buf);
+ PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
+ RETURN_FALSE;
+ }
+
+ zval_dtor(arg2);
+ zval_dtor(arg5);
+ zval_dtor(arg6);
+
+ inet_ntop(AF_INET6, &sin6.sin6_addr, addr6, INET6_ADDRSTRLEN);
+ ZVAL_STRINGL(arg2, recv_buf, retval, 0);
+ ZVAL_STRING(arg5, addr6 ? addr6 : "::", 1);
+ ZVAL_LONG(arg6, ntohs(sin6.sin6_port));
+ break;
+#endif
default:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported socket type %d", php_sock->type);
RETURN_FALSE;
@@ -1469,11 +1615,15 @@ PHP_FUNCTION(socket_sendto)
php_socket *php_sock;
struct sockaddr_un s_un;
struct sockaddr_in sin;
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 sin6;
+#endif
int retval, buf_len, addr_len;
long len, flags, port = 0;
char *buf, *addr;
+ int argc = ZEND_NUM_ARGS();
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rslls|l", &arg1, &buf, &buf_len, &len, &flags, &addr, &addr_len, &port) == FAILURE)
+ if (zend_parse_parameters(argc TSRMLS_CC, "rslls|l", &arg1, &buf, &buf_len, &len, &flags, &addr, &addr_len, &port) == FAILURE)
return;
ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
@@ -1489,7 +1639,7 @@ PHP_FUNCTION(socket_sendto)
break;
case AF_INET:
- if (ZEND_NUM_ARGS() != 6) {
+ if (argc != 6) {
WRONG_PARAM_COUNT;
}
@@ -1503,7 +1653,23 @@ PHP_FUNCTION(socket_sendto)
retval = sendto(php_sock->bsd_socket, buf, (len > buf_len) ? buf_len : len, flags, (struct sockaddr *) &sin, sizeof(sin));
break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ if (argc != 6) {
+ WRONG_PARAM_COUNT;
+ }
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_port = htons((unsigned short) port);
+
+ if (! php_set_inet6_addr(&sin6, addr, php_sock TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+
+ retval = sendto(php_sock->bsd_socket, buf, (len > buf_len) ? buf_len : len, flags, (struct sockaddr *) &sin, sizeof(sin));
+ break;
+#endif
default:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported socket type %d", php_sock->type);
RETURN_FALSE;
@@ -1531,6 +1697,9 @@ PHP_FUNCTION(socket_recvmsg)
struct cmsghdr *ctl_buf;
struct sockaddr *sa = (struct sockaddr *) &sa_storage;
struct sockaddr_in *sin = (struct sockaddr_in *) sa;
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
+#endif
struct sockaddr_un *s_un = (struct sockaddr_un *) sa;
socklen_t salen = sizeof(sa_storage);
@@ -1548,6 +1717,65 @@ PHP_FUNCTION(socket_recvmsg)
ctl_buf = (Z_LVAL_P(arg4) > sizeof(struct cmsghdr)) ? (struct cmsghdr*)emalloc(Z_LVAL_P(arg4)) : NULL;
switch (sa->sa_family) {
+#ifdef HAVE_IPV6
+ case AF_INET6:
+
+ if (arg7 == NULL) {
+ efree(ctl_buf);
+ WRONG_PARAM_COUNT;
+ }
+
+ memset(sa, 0, sizeof(sa_storage));
+ hdr.msg_name = (void *) sin6;
+ hdr.msg_namelen = sizeof(sa_storage);
+ hdr.msg_iov = iov->iov_array;
+ hdr.msg_iovlen = iov->count;
+
+ hdr.msg_control = ctl_buf ? (void *) ctl_buf : NULL;
+ hdr.msg_controllen = ctl_buf ? Z_LVAL_P(arg4) : 0;
+#ifndef MISSING_MSGHDR_MSGFLAGS
+ hdr.msg_flags = 0;
+#endif
+
+ if (recvmsg(php_sock->bsd_socket, &hdr, Z_LVAL_P(arg5)) < 0) {
+ PHP_SOCKET_ERROR(php_sock, "unable to receive message", errno);
+ RETURN_FALSE;
+ } else {
+ struct cmsghdr *mhdr = (struct cmsghdr *) hdr.msg_control;
+
+ zval_dtor(arg3);
+ zval_dtor(arg4);
+ zval_dtor(arg5);
+ zval_dtor(arg6);
+ zval_dtor(arg7);
+
+ ZVAL_LONG(arg4, hdr.msg_controllen);
+#ifndef MISSING_MSGHDR_MSGFLAGS
+ ZVAL_LONG(arg5, hdr.msg_flags);
+#endif
+ ZVAL_LONG(arg7, ntohs(sin6->sin6_port));
+
+ array_init(arg3);
+
+ if (mhdr != NULL) {
+ add_assoc_long(arg3, "cmsg_level", mhdr->cmsg_level);
+ add_assoc_long(arg3, "cmsg_type", mhdr->cmsg_type);
+ add_assoc_string(arg3, "cmsg_data", CMSG_DATA(mhdr), 1);
+ }
+
+ {
+ char tmp[INET6_ADDRSTRLEN+1];
+ if (inet_ntop(AF_INET6, &sin6->sin6_addr, tmp, INET6_ADDRSTRLEN)) {
+ ZVAL_STRING(arg6, tmp, 1);
+ } else {
+ ZVAL_STRING(arg6, "::", 1);
+ }
+ }
+
+ RETURN_TRUE;
+ }
+ break;
+#endif
case AF_INET:
if (arg7 == NULL) {
@@ -1604,6 +1832,7 @@ PHP_FUNCTION(socket_recvmsg)
RETURN_TRUE;
}
+ break;
case AF_UNIX:
memset(sa, 0, sizeof(sa_storage));
@@ -1653,6 +1882,7 @@ PHP_FUNCTION(socket_recvmsg)
ZVAL_STRING(arg6, s_un->sun_path, 1);
RETURN_TRUE;
}
+ break;
default:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported address family %d", sa->sa_family);
@@ -1688,6 +1918,38 @@ PHP_FUNCTION(socket_sendmsg)
}
switch(sa.sa_family) {
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ {
+ struct msghdr hdr;
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &sa;
+
+ set_h_errno(0);
+ set_errno(0);
+
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.msg_name = (void *) &sa;
+ hdr.msg_namelen = sizeof(sa);
+ hdr.msg_iov = iov->iov_array;
+ hdr.msg_iovlen = iov->count;
+
+ memset(sin6, 0, sizeof(sa));
+
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = htons((unsigned short)port);
+
+ if (! php_set_inet6_addr(sin6, addr, php_sock TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+
+ if (sendmsg(php_sock->bsd_socket, &hdr, flags) == -1) {
+ PHP_SOCKET_ERROR(php_sock, "unable to send message", errno);
+ }
+
+ RETURN_TRUE;
+ }
+ break;
+#endif
case AF_INET:
{
struct msghdr hdr;
@@ -1717,6 +1979,7 @@ PHP_FUNCTION(socket_sendmsg)
RETURN_TRUE;
}
+ break;
case AF_UNIX:
{
@@ -1740,6 +2003,7 @@ PHP_FUNCTION(socket_sendmsg)
RETURN_TRUE;
}
+ break;
default:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported address family %d", sa.sa_family);
@@ -1918,7 +2182,11 @@ PHP_FUNCTION(socket_create_pair)
php_sock[0] = (php_socket*)emalloc(sizeof(php_socket));
php_sock[1] = (php_socket*)emalloc(sizeof(php_socket));
- if (domain != AF_INET && domain != AF_UNIX) {
+ if (domain != AF_INET
+#ifdef HAVE_IPV6
+ && domain != AF_INET6
+#endif
+ && domain != AF_UNIX) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid socket domain [%d] specified for argument 1, assuming AF_INET", domain);
domain = AF_INET;
}