summaryrefslogtreecommitdiff
path: root/ext/sockets/sockaddr_conv.c
diff options
context:
space:
mode:
authorGustavo Lopes <glopes@nebm.ist.utl.pt>2012-11-01 20:38:42 +0100
committerGustavo Lopes <glopes@nebm.ist.utl.pt>2013-02-02 16:38:05 +0100
commit5e51c851431189677aa80f7a3a863699488678cd (patch)
treeb98fb2a402a9a4cda1fdda646b2653544fcef27c /ext/sockets/sockaddr_conv.c
parentac47448abb477be99963f0b38fe82ffe78c21a8b (diff)
downloadphp-git-5e51c851431189677aa80f7a3a863699488678cd.tar.gz
Wrap recvmsg() and sendmsg()
This introduces two new functions: int socket_recvmsg(resource $socket, array &$msghdr, int $flags) int socket_sendmsg(resource $socket, array $msghdr, int $flags) The arrays representing struct msghdr follow the native counterpart closely: structs are mapped to arrays, fields to array elements whose key is the name of the field without the prefix (e.g. "name" instead of "msg_name") and array are mapped to sequential numeric PHP arrays. Right now the only type of ancillary data supported is fot the level/type pair IPPROTO_IPV6/IPV6_PKTINFO. I also refactored out the name resolution functions and made sockets_strerror() a global function.
Diffstat (limited to 'ext/sockets/sockaddr_conv.c')
-rw-r--r--ext/sockets/sockaddr_conv.c119
1 files changed, 119 insertions, 0 deletions
diff --git a/ext/sockets/sockaddr_conv.c b/ext/sockets/sockaddr_conv.c
new file mode 100644
index 0000000000..19c61740d0
--- /dev/null
+++ b/ext/sockets/sockaddr_conv.c
@@ -0,0 +1,119 @@
+#include <php.h>
+#include <php_network.h>
+#include "php_sockets.h"
+
+#ifdef PHP_WIN32
+#include <Ws2tcpip.h>
+#else
+#include <netdb.h>
+#include <arpa/inet.h>
+#endif
+
+#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
+
+ 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;
+ hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
+ 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
+
+ }
+
+ 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 (! (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;
+}