Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 54 additions & 50 deletions ext/sockets/sockets.c
Original file line number Diff line number Diff line change
Expand Up @@ -1497,52 +1497,52 @@ PHP_FUNCTION(socket_send)
/* {{{ Receives data from a socket, connected or not */
PHP_FUNCTION(socket_recvfrom)
{
zval *arg1, *arg2, *arg5, *arg6 = NULL;
zval *zsocket, *zdata, *zaddr, *zport = NULL;
php_socket *php_sock;
struct sockaddr_un s_un;
struct sockaddr_in sin;
#ifdef HAVE_IPV6
struct sockaddr_in6 sin6;
#endif
#ifdef AF_PACKET
//struct sockaddr_ll sll;
struct sockaddr_ll sll;
#endif
char addrbuf[INET6_ADDRSTRLEN];
socklen_t slen;
int retval;
zend_long arg3, arg4;
zend_long length, flags;
const char *address;
zend_string *recv_buf;

ZEND_PARSE_PARAMETERS_START(5, 6)
Z_PARAM_OBJECT_OF_CLASS(arg1, socket_ce)
Z_PARAM_ZVAL(arg2)
Z_PARAM_LONG(arg3)
Z_PARAM_LONG(arg4)
Z_PARAM_ZVAL(arg5)
Z_PARAM_OBJECT_OF_CLASS(zsocket, socket_ce)
Z_PARAM_ZVAL(zdata)
Z_PARAM_LONG(length)
Z_PARAM_LONG(flags)
Z_PARAM_ZVAL(zaddr)
Z_PARAM_OPTIONAL
Z_PARAM_ZVAL(arg6)
Z_PARAM_ZVAL(zport)
ZEND_PARSE_PARAMETERS_END();

php_sock = Z_SOCKET_P(arg1);
php_sock = Z_SOCKET_P(zsocket);
ENSURE_SOCKET_VALID(php_sock);

/* overflow check */
/* Shouldthrow ? */

if (arg3 <= 0 || arg3 > ZEND_LONG_MAX - 1) {
if (length <= 0 || length > ZEND_LONG_MAX - 1) {
RETURN_FALSE;
}

recv_buf = zend_string_alloc(arg3 + 1, 0);
recv_buf = zend_string_alloc(length + 1, 0);

switch (php_sock->type) {
case AF_UNIX:
slen = sizeof(s_un);
memset(&s_un, 0, slen);
s_un.sun_family = AF_UNIX;

retval = recvfrom(php_sock->bsd_socket, ZSTR_VAL(recv_buf), arg3, arg4, (struct sockaddr *)&s_un, (socklen_t *)&slen);
retval = recvfrom(php_sock->bsd_socket, ZSTR_VAL(recv_buf), length, flags, (struct sockaddr *)&s_un, (socklen_t *)&slen);

if (retval < 0) {
PHP_SOCKET_ERROR(php_sock, "Unable to recvfrom", errno);
Expand All @@ -1552,16 +1552,16 @@ PHP_FUNCTION(socket_recvfrom)
ZSTR_LEN(recv_buf) = retval;
ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0';

ZEND_TRY_ASSIGN_REF_NEW_STR(arg2, recv_buf);
ZEND_TRY_ASSIGN_REF_STRING(arg5, s_un.sun_path);
ZEND_TRY_ASSIGN_REF_NEW_STR(zdata, recv_buf);
ZEND_TRY_ASSIGN_REF_STRING(zaddr, s_un.sun_path);
break;

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

if (arg6 == NULL) {
if (zport == NULL) {
zend_string_efree(recv_buf);
zend_throw_exception(
zend_ce_argument_count_error,
Expand All @@ -1570,7 +1570,7 @@ PHP_FUNCTION(socket_recvfrom)
RETURN_THROWS();
}

retval = recvfrom(php_sock->bsd_socket, ZSTR_VAL(recv_buf), arg3, arg4, (struct sockaddr *)&sin, (socklen_t *)&slen);
retval = recvfrom(php_sock->bsd_socket, ZSTR_VAL(recv_buf), length, flags, (struct sockaddr *)&sin, (socklen_t *)&slen);

if (retval < 0) {
PHP_SOCKET_ERROR(php_sock, "Unable to recvfrom", errno);
Expand All @@ -1582,17 +1582,17 @@ PHP_FUNCTION(socket_recvfrom)

address = inet_ntop(AF_INET, &sin.sin_addr, addrbuf, sizeof(addrbuf));

ZEND_TRY_ASSIGN_REF_NEW_STR(arg2, recv_buf);
ZEND_TRY_ASSIGN_REF_STRING(arg5, address ? address : "0.0.0.0");
ZEND_TRY_ASSIGN_REF_LONG(arg6, ntohs(sin.sin_port));
ZEND_TRY_ASSIGN_REF_NEW_STR(zdata, recv_buf);
ZEND_TRY_ASSIGN_REF_STRING(zaddr, address ? address : "0.0.0.0");
ZEND_TRY_ASSIGN_REF_LONG(zport, 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) {
if (zport == NULL) {
zend_string_efree(recv_buf);
zend_throw_exception(
zend_ce_argument_count_error,
Expand All @@ -1601,7 +1601,7 @@ PHP_FUNCTION(socket_recvfrom)
RETURN_THROWS();
}

retval = recvfrom(php_sock->bsd_socket, ZSTR_VAL(recv_buf), arg3, arg4, (struct sockaddr *)&sin6, (socklen_t *)&slen);
retval = recvfrom(php_sock->bsd_socket, ZSTR_VAL(recv_buf), length, flags, (struct sockaddr *)&sin6, (socklen_t *)&slen);

if (retval < 0) {
PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
Expand All @@ -1613,22 +1613,20 @@ PHP_FUNCTION(socket_recvfrom)

inet_ntop(AF_INET6, &sin6.sin6_addr, addrbuf, sizeof(addrbuf));

ZEND_TRY_ASSIGN_REF_NEW_STR(arg2, recv_buf);
ZEND_TRY_ASSIGN_REF_STRING(arg5, addrbuf[0] ? addrbuf : "::");
ZEND_TRY_ASSIGN_REF_LONG(arg6, ntohs(sin6.sin6_port));
ZEND_TRY_ASSIGN_REF_NEW_STR(zdata, recv_buf);
ZEND_TRY_ASSIGN_REF_STRING(zaddr, addrbuf[0] ? addrbuf : "::");
ZEND_TRY_ASSIGN_REF_LONG(zport, ntohs(sin6.sin6_port));
break;
#endif
#ifdef AF_PACKET
/*
case AF_PACKET:
// TODO expose and use proper ethernet frame type instead i.e. src mac, dst mac and payload to userland
// ditto for socket_sendto
case AF_PACKET: {
char ifrname[IFNAMSIZ];

slen = sizeof(sll);
memset(&sll, 0, sizeof(sll));
memset(&sll, 0, slen);
sll.sll_family = AF_PACKET;
char ifrname[IFNAMSIZ];

retval = recvfrom(php_sock->bsd_socket, ZSTR_VAL(recv_buf), arg3, arg4, (struct sockaddr *)&sll, (socklen_t *)&slen);
retval = recvfrom(php_sock->bsd_socket, ZSTR_VAL(recv_buf), length, flags, (struct sockaddr *)&sll, (socklen_t *)&slen);

if (retval < 0) {
PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
Expand All @@ -1644,14 +1642,17 @@ PHP_FUNCTION(socket_recvfrom)
RETURN_FALSE;
}

ZEND_TRY_ASSIGN_REF_NEW_STR(arg2, recv_buf);
ZEND_TRY_ASSIGN_REF_STRING(arg5, ifrname);
ZEND_TRY_ASSIGN_REF_LONG(arg6, sll.sll_ifindex);
ZEND_TRY_ASSIGN_REF_NEW_STR(zdata, recv_buf);
ZEND_TRY_ASSIGN_REF_STRING(zaddr, ifrname);

if (zport) {
ZEND_TRY_ASSIGN_REF_LONG(zport, sll.sll_ifindex);
}
break;
*/
}
#endif
default:
zend_argument_value_error(1, "must be one of AF_UNIX, AF_INET, or AF_INET6");
zend_argument_value_error(1, "must be one of AF_UNIX, AF_PACKET, AF_INET, or AF_INET6");
RETURN_THROWS();
}

Expand All @@ -1662,15 +1663,15 @@ PHP_FUNCTION(socket_recvfrom)
/* {{{ Sends a message to a socket, whether it is connected or not */
PHP_FUNCTION(socket_sendto)
{
zval *arg1;
zval *zsocket;
php_socket *php_sock;
struct sockaddr_un s_un;
struct sockaddr_in sin;
#ifdef HAVE_IPV6
struct sockaddr_in6 sin6;
#endif
#ifdef AF_PACKET
//struct sockaddr_ll sll;
struct sockaddr_ll sll;
#endif
int retval;
size_t buf_len;
Expand All @@ -1680,7 +1681,7 @@ PHP_FUNCTION(socket_sendto)
zend_string *addr;

ZEND_PARSE_PARAMETERS_START(5, 6)
Z_PARAM_OBJECT_OF_CLASS(arg1, socket_ce)
Z_PARAM_OBJECT_OF_CLASS(zsocket, socket_ce)
Z_PARAM_STRING(buf, buf_len)
Z_PARAM_LONG(len)
Z_PARAM_LONG(flags)
Expand All @@ -1689,14 +1690,19 @@ PHP_FUNCTION(socket_sendto)
Z_PARAM_LONG_OR_NULL(port, port_is_null)
ZEND_PARSE_PARAMETERS_END();

php_sock = Z_SOCKET_P(arg1);
php_sock = Z_SOCKET_P(zsocket);
ENSURE_SOCKET_VALID(php_sock);

if (port < 0 || port > USHRT_MAX) {
zend_argument_value_error(6, "must be between 0 and %u", USHRT_MAX);
RETURN_THROWS();
#ifdef AF_PACKET
if (php_sock->type != AF_PACKET) {
#endif
if (port < 0 || port > USHRT_MAX) {
zend_argument_value_error(6, "must be between 0 and %u", USHRT_MAX);
RETURN_THROWS();
}
#ifdef AF_PACKET
}

#endif

if (len < 0) {
zend_argument_value_error(3, "must be greater than or equal to 0");
Expand Down Expand Up @@ -1753,7 +1759,6 @@ PHP_FUNCTION(socket_sendto)
break;
#endif
#ifdef AF_PACKET
/*
case AF_PACKET:
if (port_is_null) {
zend_argument_value_error(6, "cannot be null when the socket type is AF_PACKET");
Expand All @@ -1762,14 +1767,13 @@ PHP_FUNCTION(socket_sendto)

memset(&sll, 0, sizeof(sll));
sll.sll_family = AF_PACKET;
sll.sll_ifindex = port;
sll.sll_ifindex = (int)port;

retval = sendto(php_sock->bsd_socket, buf, ((size_t)len > buf_len) ? buf_len : (size_t)len, flags, (struct sockaddr *) &sin, sizeof(sin));
retval = sendto(php_sock->bsd_socket, buf, ((size_t)len > buf_len) ? buf_len : (size_t)len, flags, (struct sockaddr *)&sll, sizeof(sll));
break;
*/
#endif
default:
zend_argument_value_error(1, "must be one of AF_UNIX, AF_INET, or AF_INET6");
zend_argument_value_error(1, "must be one of AF_UNIX, AF_PACKET, AF_INET, or AF_INET6");
RETURN_THROWS();
}

Expand Down
44 changes: 44 additions & 0 deletions ext/sockets/tests/socket_recvfrom_afpacket_no_port.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
--TEST--
AF_PACKET socket_recvfrom() without optional port argument
--EXTENSIONS--
sockets
posix
--SKIPIF--
<?php
if (!defined("AF_PACKET")) {
die('SKIP AF_PACKET not supported on this platform.');
}
if (!defined("ETH_P_ALL")) {
die('SKIP ETH_P_ALL not available on this platform.');
}
if (!function_exists("posix_getuid") || posix_getuid() != 0) {
die('SKIP AF_PACKET requires root permissions.');
}
?>
--FILE--
<?php
$s_send = socket_create(AF_PACKET, SOCK_RAW, ETH_P_ALL);
$s_recv = socket_create(AF_PACKET, SOCK_RAW, ETH_P_ALL);

socket_bind($s_send, 'lo');
socket_bind($s_recv, 'lo');

$dst_mac = "\xff\xff\xff\xff\xff\xff";
$src_mac = "\x00\x00\x00\x00\x00\x00";
$ethertype = pack("n", 0x9000);
$payload = "no port test";
$frame = str_pad($dst_mac . $src_mac . $ethertype . $payload, 60, "\x00");

socket_sendto($s_send, $frame, strlen($frame), 0, "lo", 1);

// recvfrom without the optional 6th argument (port/ifindex).
$bytes = socket_recvfrom($s_recv, $buf, 65536, 0, $addr);
var_dump($bytes >= 60);
var_dump($addr === 'lo');

socket_close($s_send);
socket_close($s_recv);
?>
--EXPECT--
bool(true)
bool(true)
Loading
Loading