Skip to content
This repository has been archived by the owner on Dec 16, 2019. It is now read-only.

Commit

Permalink
#776 - socket_recvfrom / socket_sendto support
Browse files Browse the repository at this point in the history
  • Loading branch information
sirsnyder committed Dec 5, 2017
1 parent 83870c8 commit a18b96e
Show file tree
Hide file tree
Showing 2 changed files with 226 additions and 0 deletions.
51 changes: 51 additions & 0 deletions classes/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ PHP_METHOD(Socket, select);
PHP_METHOD(Socket, read);
PHP_METHOD(Socket, write);
PHP_METHOD(Socket, send);
PHP_METHOD(Socket, recvfrom);
PHP_METHOD(Socket, sendto);

PHP_METHOD(Socket, setBlocking);
PHP_METHOD(Socket, getPeerName);
Expand Down Expand Up @@ -85,6 +87,22 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(Socket_send, 0, 3, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, flags, IS_LONG, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(Socket_recvfrom, 0, 0, 4)
ZEND_ARG_TYPE_INFO(1, buffer, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, flags, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(1, name, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(1, port, IS_LONG, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(Socket_sendto, 0, 0, 4)
ZEND_ARG_TYPE_INFO(0, buffer, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, flags, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, addr, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, port, IS_LONG, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(Socket_setBlocking, 0, 1, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO(0, blocking, _IS_BOOL, 0)
ZEND_END_ARG_INFO()
Expand Down Expand Up @@ -124,6 +142,8 @@ zend_function_entry pthreads_socket_methods[] = {
PHP_ME(Socket, read, Socket_read, ZEND_ACC_PUBLIC)
PHP_ME(Socket, write, Socket_write, ZEND_ACC_PUBLIC)
PHP_ME(Socket, send, Socket_send, ZEND_ACC_PUBLIC)
PHP_ME(Socket, recvfrom, Socket_recvfrom, ZEND_ACC_PUBLIC)
PHP_ME(Socket, sendto, Socket_sendto, ZEND_ACC_PUBLIC)
PHP_ME(Socket, setBlocking, Socket_setBlocking, ZEND_ACC_PUBLIC)
PHP_ME(Socket, getPeerName, Socket_getHost, ZEND_ACC_PUBLIC)
PHP_ME(Socket, getSockName, Socket_getHost, ZEND_ACC_PUBLIC)
Expand Down Expand Up @@ -270,6 +290,37 @@ PHP_METHOD(Socket, send) {
pthreads_socket_send(getThis(), buffer, length, flags, return_value);
} /* }}} */

/* {{{ proto bool Socket::recvfrom(string &buf, int length, int flags, string &name [, int &port ]) */
PHP_METHOD(Socket, recvfrom) {
zval *buffer, *name, *port = NULL;
zend_long len, flags;

if (zend_parse_parameters(ZEND_NUM_ARGS(), "z/llz/|z/", &buffer, &len, &flags, &name, &port) == FAILURE) {
return;
}

/* overflow check */
if ((len + 2) < 3) {
RETURN_FALSE;
}

pthreads_socket_recvfrom(getThis(), buffer, len, flags, name, port, return_value);
} /* }}} */

/* {{{ proto bool Socket::sendto(string buf, int length, int flags, string addr [, int port ]) */
PHP_METHOD(Socket, sendto) {
size_t buf_len, addr_len;
zend_long len, flags, port = 0;
char *buf, *addr;
int argc = ZEND_NUM_ARGS();

if (zend_parse_parameters(argc, "slls|l", &buf, &buf_len, &len, &flags, &addr, &addr_len, &port) == FAILURE) {
return;
}

pthreads_socket_sendto(getThis(), argc, buf, buf_len, len, flags, addr, addr_len, port, return_value);
} /* }}} */

/* {{{ proto bool Socket::setBlocking(bool blocking) */
PHP_METHOD(Socket, setBlocking) {
zend_bool blocking = 0;
Expand Down
175 changes: 175 additions & 0 deletions src/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -696,4 +696,179 @@ void pthreads_socket_free(pthreads_socket_t *socket, zend_bool closing) {

efree(socket);
}

void pthreads_socket_recvfrom(zval *object, zval *buffer, zend_long len, zend_long flags, zval *name, zval *port, zval *return_value) {
pthreads_object_t *threaded =
PTHREADS_FETCH_FROM(Z_OBJ_P(object));

struct sockaddr_un s_un;
struct sockaddr_in sin;
#if HAVE_IPV6
struct sockaddr_in6 sin6;
char addr6[INET6_ADDRSTRLEN];
#endif
socklen_t slen;
int retval;
char *address;
zend_string *recv_buf;

recv_buf = zend_string_alloc(len + 1, 0);

switch (threaded->store.sock->type) {
case AF_UNIX:
slen = sizeof(s_un);
s_un.sun_family = AF_UNIX;
retval = recvfrom(threaded->store.sock->fd, ZSTR_VAL(recv_buf), len, flags, (struct sockaddr *)&s_un, (socklen_t *)&slen);

if (retval < 0) {
PHP_SOCKET_ERROR(threaded->store.sock, "unable to recvfrom", errno);
zend_string_free(recv_buf);
RETURN_FALSE;
}
ZSTR_LEN(recv_buf) = retval;
ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0';

zval_dtor(buffer);
zval_dtor(name);

ZVAL_NEW_STR(buffer, recv_buf);
ZVAL_STRING(name, s_un.sun_path);
break;

case AF_INET:
slen = sizeof(sin);
memset(&sin, 0, slen);
sin.sin_family = AF_INET;

if (port == NULL) {
zend_string_free(recv_buf);
WRONG_PARAM_COUNT;
}

retval = recvfrom(threaded->store.sock->fd, ZSTR_VAL(recv_buf), len, flags, (struct sockaddr *)&sin, (socklen_t *)&slen);

if (retval < 0) {
PHP_SOCKET_ERROR(threaded->store.sock, "unable to recvfrom", errno);
zend_string_free(recv_buf);
RETURN_FALSE;
}
ZSTR_LEN(recv_buf) = retval;
ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0';

zval_dtor(buffer);
zval_dtor(name);
zval_dtor(port);

address = inet_ntoa(sin.sin_addr);

ZVAL_NEW_STR(buffer, recv_buf);
ZVAL_STRING(name, address ? address : "0.0.0.0");
ZVAL_LONG(port, ntohs(sin.sin_port));
break;
#if HAVE_IPV6
case AF_INET6:
slen = sizeof(sin6);
memset(&sin6, 0, slen);
sin6.sin6_family = AF_INET6;

if (port == NULL) {
efree(recv_buf);
WRONG_PARAM_COUNT;
}

retval = recvfrom(threaded->store.sock->fd, ZSTR_VAL(recv_buf), len, flags, (struct sockaddr *)&sin6, (socklen_t *)&slen);

if (retval < 0) {
PHP_SOCKET_ERROR(threaded->store.sock, "unable to recvfrom", errno);
zend_string_free(recv_buf);
RETURN_FALSE;
}
ZSTR_LEN(recv_buf) = retval;
ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0';

zval_dtor(buffer);
zval_dtor(name);
zval_dtor(port);

memset(addr6, 0, INET6_ADDRSTRLEN);
inet_ntop(AF_INET6, &sin6.sin6_addr, addr6, INET6_ADDRSTRLEN);

ZVAL_NEW_STR(buffer, recv_buf);
ZVAL_STRING(name, addr6[0] ? addr6 : "::");
ZVAL_LONG(port, ntohs(sin6.sin6_port));
break;
#endif
default:
php_error_docref(NULL, E_WARNING, "Unsupported socket type %d", threaded->store.sock->type);
RETURN_FALSE;
}

RETURN_LONG(retval);
}

void pthreads_socket_sendto(zval *object, int argc, char *buf, size_t buf_len, zend_long len, zend_long flags, char *addr, size_t addr_len, zend_long port, zval *return_value) {
pthreads_object_t *threaded =
PTHREADS_FETCH_FROM(Z_OBJ_P(object));

struct sockaddr_un s_un;
struct sockaddr_in sin;
#if HAVE_IPV6
struct sockaddr_in6 sin6;
char addr6[INET6_ADDRSTRLEN];
#endif
int retval;

switch (threaded->store.sock->type) {
case AF_UNIX:
memset(&s_un, 0, sizeof(s_un));
s_un.sun_family = AF_UNIX;
snprintf(s_un.sun_path, 108, "%s", addr);

retval = sendto(threaded->store.sock->fd, buf, ((size_t)len > buf_len) ? buf_len : (size_t)len, flags, (struct sockaddr *) &s_un, SUN_LEN(&s_un));
break;

case AF_INET:
if (argc != 6) {
WRONG_PARAM_COUNT;
}

memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons((unsigned short) port);

if (! php_set_inet_addr(&sin, addr, threaded->store.sock)) {
RETURN_FALSE;
}

retval = sendto(threaded->store.sock->fd, buf, ((size_t)len > buf_len) ? buf_len : (size_t)len, flags, (struct sockaddr *) &sin, sizeof(sin));
break;
#if 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, threaded->store.sock)) {
RETURN_FALSE;
}

retval = sendto(threaded->store.sock->fd, buf, ((size_t)len > buf_len) ? buf_len : (size_t)len, flags, (struct sockaddr *) &sin6, sizeof(sin6));
break;
#endif
default:
php_error_docref(NULL, E_WARNING, "Unsupported socket type %d", threaded->store.sock->type);
RETURN_FALSE;
}

if (retval == -1) {
PHP_SOCKET_ERROR(threaded->store.sock, "unable to write to socket", errno);
RETURN_FALSE;
}

RETURN_LONG(retval);
}
#endif

0 comments on commit a18b96e

Please sign in to comment.