Skip to content
This repository was archived by the owner on Dec 16, 2019. It is now read-only.
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
14 changes: 14 additions & 0 deletions classes/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ PHP_METHOD(Socket, getLastError);
PHP_METHOD(Socket, clearError);
PHP_METHOD(Socket, strerror);

PHP_METHOD(Socket, createListen);

PHP_METHOD(Socket, close);

ZEND_BEGIN_ARG_INFO_EX(Socket___construct, 0, 0, 3)
Expand Down Expand Up @@ -164,6 +166,7 @@ zend_function_entry pthreads_socket_methods[] = {
PHP_ME(Socket, close, Socket_void, ZEND_ACC_PUBLIC)
PHP_ME(Socket, getLastError, Socket_getLastError, ZEND_ACC_PUBLIC)
PHP_ME(Socket, clearError, Socket_void, ZEND_ACC_PUBLIC)
PHP_ME(Socket, createListen, Socket_void, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't look right. A separate arginfo needs to be defined for this.

PHP_ME(Socket, strerror, Socket_strerror, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
{NULL, NULL, NULL}
};
Expand Down Expand Up @@ -388,6 +391,17 @@ PHP_METHOD(Socket, clearError) {
pthreads_socket_clear_error(getThis());
} /* }}} */

/* {{{ proto Socket Socket::createListen(int port[, int backlog = 128]) */
PHP_METHOD(Socket, createListen) {
zend_long port, backlog = 128;

if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &port, &backlog) == FAILURE) {
return;
}

pthreads_socket_create_listen(port, backlog, return_value);
} /* }}} */

/* {{{ proto string|null Socket::strerror(int error) */
PHP_METHOD(Socket, strerror) {
zend_long error = 0;
Expand Down
2 changes: 2 additions & 0 deletions examples/stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,8 @@ public function accept($class = self::class){}
public function connect(string $host, int $port = 0) : bool{}

public static function select(array &$read, array &$write, array &$except, ?int $sec, int $usec = 0, int &$error = null){}

public static function createListen(int $port, int $backlog = 128) : self{}

public function read(int $length, int $flags = 0, int $type = self::BINARY_READ){}

Expand Down
50 changes: 50 additions & 0 deletions src/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,56 @@ void pthreads_socket_get_last_error(zval *object, zend_bool clear, zval *return_
}
}

void pthreads_socket_create_listen(zend_long port, zend_long backlog, zval *return_value) {
struct sockaddr_in la;
struct hostent *hp;
pthreads_object_t *created;
pthreads_socket_t *sock;

object_init_ex(return_value, pthreads_socket_entry);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can return FAILURE. It's not immediately clear to me if any such paths exists where this can fail (from a quick look through the source code), but it may be worthwhile checking its return value for failure just in case I've missed some psychotic edge case.


created = PTHREADS_FETCH_FROM(Z_OBJ_P(return_value));
sock = created->store.sock;

#ifndef PHP_WIN32
if ((hp = php_network_gethostbyname("0.0.0.0")) == NULL) {
#else
if ((hp = php_network_gethostbyname("localhost")) == NULL) {
#endif
zval_ptr_dtor(return_value);
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tpunt is zval_ptr_dtor used correctly at this point and below?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks fine to me. Technically, zval_dtor could be used, since we know that the newly created socket object will not contain a cycle (so there's no need to place it into the GC root buffer). But it doesn't really matter.

RETURN_FALSE;
}

memcpy((char *) &la.sin_addr, hp->h_addr, hp->h_length);
la.sin_family = hp->h_addrtype;
la.sin_port = htons((unsigned short) port);

sock->fd = socket(AF_INET, SOCK_STREAM, 0);
sock->blocking = 1;

if (PTHREADS_IS_INVALID_SOCKET(sock)) {
PTHREADS_SOCKET_ERROR(sock, "Unable to create listening socket", errno);
zval_ptr_dtor(return_value);
RETURN_FALSE;
}

sock->domain = AF_INET;

if (bind(sock->fd, (struct sockaddr *)&la, sizeof(la)) != 0) {
PTHREADS_SOCKET_ERROR(sock, "Unable to bind to given address", errno);
zval_ptr_dtor(return_value);
RETURN_FALSE;
}

if (listen(sock->fd, backlog) != 0) {
PTHREADS_SOCKET_ERROR(sock, "Unable to listen on socket", errno);
zval_ptr_dtor(return_value);
RETURN_FALSE;
}

sock->error = 0;
}

void pthreads_socket_strerror(zend_long error, zval *return_value) {
char *errstr;
errstr = php_socket_strerror(error, NULL, 0);
Expand Down
1 change: 1 addition & 0 deletions src/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ void pthreads_socket_free(pthreads_socket_t *socket, zend_bool closing);
void pthreads_socket_recvfrom(zval *object, zval *buffer, zend_long len, zend_long flags, zval *name, zval *port, zval *return_value);
void pthreads_socket_sendto(zval *object, int argc, zend_string *buf, zend_long len, zend_long flags, zend_string *addr, zend_long port, zval *return_value);
void pthreads_socket_get_last_error(zval *object, zend_bool clear, zval *return_value);
void pthreads_socket_create_listen(zend_long port, zend_long backlog, zval *return_value);
void pthreads_socket_strerror(zend_long error, zval *return_value);
void pthreads_socket_clear_error(zval *object);

Expand Down
34 changes: 34 additions & 0 deletions tests/socket-createlisten.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
--TEST--
Basic test of Socket::createListen()
--FILE--
<?php
$port = 31330 + rand(1,999);

try {
\Socket::createListen();
} catch(Exception $exception) { var_dump($exception); }

$socket = \Socket::createListen($port);
$sockName = $socket->getSockName();

$client = new \Socket(\Socket::AF_INET, \Socket::SOCK_STREAM, \Socket::SOL_TCP);
$client->connect($sockName['host'], $sockName['port']);

var_dump($client->getPeerName(), $client->getPeerName(false));

$client->close();
$socket->close();
?>
--EXPECTF--

Warning: Socket::createListen() expects at least 1 parameter, 0 given in %s on line %i
array(2) {
["host"]=>
string(9) "127.0.0.1"
["port"]=>
int(%i)
}
array(1) {
["host"]=>
string(9) "127.0.0.1"
}