1184 lines
35 KiB
C
Executable File
1184 lines
35 KiB
C
Executable File
/*
|
|
+----------------------------------------------------------------------+
|
|
| Swoole |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2012-2018 The Swoole Group |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 2.0 of the Apache license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.apache.org/licenses/LICENSE-2.0.html |
|
|
| If you did not receive a copy of the Apache2.0 license and are unable|
|
|
| to obtain it through the world-wide-web, please send a note to |
|
|
| license@swoole.com so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#include "php_swoole.h"
|
|
|
|
#ifdef SW_COROUTINE
|
|
#include "swoole_coroutine.h"
|
|
|
|
static zend_class_entry swoole_socket_coro_ce;
|
|
static zend_class_entry *swoole_socket_coro_class_entry_ptr;
|
|
static zend_object_handlers swoole_socket_coro_handlers;
|
|
|
|
static zend_class_entry swoole_socket_coro_exception_ce;
|
|
static zend_class_entry *swoole_socket_coro_exception_class_entry_ptr;
|
|
|
|
enum socket_opcode
|
|
{
|
|
SW_SOCKET_OPCODE_ACCEPT,
|
|
SW_SOCKET_OPCODE_CONNECT,
|
|
SW_SOCKET_OPCODE_RECV,
|
|
SW_SOCKET_OPCODE_RECVFROM,
|
|
SW_SOCKET_OPCODE_SEND,
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
zval object;
|
|
int fd;
|
|
int domain;
|
|
int type;
|
|
int cid;
|
|
enum socket_opcode opcode;
|
|
php_context context;
|
|
swTimer_node *timer;
|
|
#ifdef SWOOLE_SOCKETS_SUPPORT
|
|
zval *resource;
|
|
#endif
|
|
zend_object std;
|
|
} socket_coro;
|
|
|
|
static PHP_METHOD(swoole_socket_coro, __construct);
|
|
static PHP_METHOD(swoole_socket_coro, bind);
|
|
static PHP_METHOD(swoole_socket_coro, listen);
|
|
static PHP_METHOD(swoole_socket_coro, accept);
|
|
static PHP_METHOD(swoole_socket_coro, connect);
|
|
static PHP_METHOD(swoole_socket_coro, recv);
|
|
static PHP_METHOD(swoole_socket_coro, send);
|
|
static PHP_METHOD(swoole_socket_coro, recvfrom);
|
|
static PHP_METHOD(swoole_socket_coro, sendto);
|
|
static PHP_METHOD(swoole_socket_coro, getpeername);
|
|
static PHP_METHOD(swoole_socket_coro, getsockname);
|
|
static PHP_METHOD(swoole_socket_coro, close);
|
|
#ifdef SWOOLE_SOCKETS_SUPPORT
|
|
static PHP_METHOD(swoole_socket_coro, getSocket);
|
|
#endif
|
|
|
|
static int swoole_socket_connect(socket_coro *sock, char *host, size_t l_host, int port);
|
|
static void socket_onTimeout(swTimer *timer, swTimer_node *tnode);
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_socket_coro_construct, 0, 0, 3)
|
|
ZEND_ARG_INFO(0, domain)
|
|
ZEND_ARG_INFO(0, type)
|
|
ZEND_ARG_INFO(0, protocol)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_socket_coro_bind, 0, 0, 1)
|
|
ZEND_ARG_INFO(0, address)
|
|
ZEND_ARG_INFO(0, port)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_socket_coro_listen, 0, 0, 0)
|
|
ZEND_ARG_INFO(0, backlog)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_socket_coro_accept, 0, 0, 0)
|
|
ZEND_ARG_INFO(0, timeout)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_socket_coro_recv, 0, 0, 0)
|
|
ZEND_ARG_INFO(0, timeout)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_socket_coro_send, 0, 0, 1)
|
|
ZEND_ARG_INFO(0, data)
|
|
ZEND_ARG_INFO(0, timeout)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_socket_coro_recvfrom, 0, 0, 1)
|
|
ZEND_ARG_INFO(1, peername)
|
|
ZEND_ARG_INFO(0, timeout)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_socket_coro_sendto, 0, 0, 3)
|
|
ZEND_ARG_INFO(0, addr)
|
|
ZEND_ARG_INFO(0, port)
|
|
ZEND_ARG_INFO(0, data)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_socket_coro_connect, 0, 0, 1)
|
|
ZEND_ARG_INFO(0, host)
|
|
ZEND_ARG_INFO(0, port)
|
|
ZEND_ARG_INFO(0, timeout)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_void, 0, 0, 0)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
static const zend_function_entry swoole_socket_coro_methods[] =
|
|
{
|
|
PHP_ME(swoole_socket_coro, __construct, arginfo_swoole_socket_coro_construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
|
|
PHP_ME(swoole_socket_coro, bind, arginfo_swoole_socket_coro_bind, ZEND_ACC_PUBLIC)
|
|
PHP_ME(swoole_socket_coro, listen, arginfo_swoole_socket_coro_listen, ZEND_ACC_PUBLIC)
|
|
PHP_ME(swoole_socket_coro, accept, arginfo_swoole_socket_coro_accept, ZEND_ACC_PUBLIC)
|
|
PHP_ME(swoole_socket_coro, connect, arginfo_swoole_socket_coro_connect, ZEND_ACC_PUBLIC)
|
|
PHP_ME(swoole_socket_coro, recv, arginfo_swoole_socket_coro_recv, ZEND_ACC_PUBLIC)
|
|
PHP_ME(swoole_socket_coro, send, arginfo_swoole_socket_coro_send, ZEND_ACC_PUBLIC)
|
|
PHP_ME(swoole_socket_coro, recvfrom, arginfo_swoole_socket_coro_recvfrom, ZEND_ACC_PUBLIC)
|
|
PHP_ME(swoole_socket_coro, sendto, arginfo_swoole_socket_coro_sendto, ZEND_ACC_PUBLIC)
|
|
PHP_ME(swoole_socket_coro, getpeername, arginfo_swoole_void, ZEND_ACC_PUBLIC)
|
|
PHP_ME(swoole_socket_coro, getsockname, arginfo_swoole_void, ZEND_ACC_PUBLIC)
|
|
#ifdef SWOOLE_SOCKETS_SUPPORT
|
|
PHP_ME(swoole_socket_coro, getSocket, arginfo_swoole_void, ZEND_ACC_PUBLIC)
|
|
#endif
|
|
PHP_ME(swoole_socket_coro, close, arginfo_swoole_void, ZEND_ACC_PUBLIC)
|
|
PHP_FE_END
|
|
};
|
|
|
|
static inline socket_coro * sw_socket_coro_fetch_object(zend_object *obj)
|
|
{
|
|
return (socket_coro *) ((char *) obj - XtOffsetOf(socket_coro, std));
|
|
}
|
|
|
|
#define Z_SOCKET_CORO_OBJ_P(zv) sw_socket_coro_fetch_object(Z_OBJ_P(zv));
|
|
|
|
|
|
static void swoole_socket_coro_free_storage(zend_object *object)
|
|
{
|
|
socket_coro *sock = (socket_coro *) sw_socket_coro_fetch_object(object);
|
|
if (sock->fd >= 0)
|
|
{
|
|
SwooleG.main_reactor->close(SwooleG.main_reactor, sock->fd);
|
|
}
|
|
zend_object_std_dtor(&sock->std);
|
|
}
|
|
|
|
static zend_object *swoole_socket_coro_create(zend_class_entry *ce TSRMLS_DC)
|
|
{
|
|
socket_coro *sock = ecalloc(1, sizeof(socket_coro) + zend_object_properties_size(ce));
|
|
zend_object_std_init(&sock->std, ce TSRMLS_CC);
|
|
object_properties_init(&sock->std, ce);
|
|
sock->std.handlers = &swoole_socket_coro_handlers;
|
|
|
|
return &sock->std;
|
|
}
|
|
|
|
void swoole_socket_coro_init(int module_number TSRMLS_DC)
|
|
{
|
|
INIT_CLASS_ENTRY(swoole_socket_coro_ce, "Swoole\\Coroutine\\Socket", swoole_socket_coro_methods);
|
|
|
|
swoole_socket_coro_class_entry_ptr = zend_register_internal_class(&swoole_socket_coro_ce TSRMLS_CC);
|
|
swoole_socket_coro_class_entry_ptr->ce_flags |= ZEND_ACC_FINAL;
|
|
swoole_socket_coro_class_entry_ptr->create_object = swoole_socket_coro_create;
|
|
swoole_socket_coro_class_entry_ptr->serialize = zend_class_serialize_deny;
|
|
swoole_socket_coro_class_entry_ptr->unserialize = zend_class_unserialize_deny;
|
|
zend_declare_property_long(swoole_socket_coro_class_entry_ptr, SW_STRL("errCode") - 1, 0, ZEND_ACC_PUBLIC TSRMLS_CC);
|
|
|
|
memcpy(&swoole_socket_coro_handlers, zend_get_std_object_handlers(), sizeof(swoole_socket_coro_handlers));
|
|
swoole_socket_coro_handlers.free_obj = swoole_socket_coro_free_storage;
|
|
swoole_socket_coro_handlers.clone_obj = NULL;
|
|
swoole_socket_coro_handlers.offset = XtOffsetOf(socket_coro, std);
|
|
|
|
INIT_CLASS_ENTRY(swoole_socket_coro_exception_ce, "Swoole\\Coroutine\\Socket\\Exception", NULL);
|
|
swoole_socket_coro_exception_class_entry_ptr = sw_zend_register_internal_class_ex(&swoole_socket_coro_exception_ce,
|
|
zend_exception_get_default(TSRMLS_C), NULL TSRMLS_CC);
|
|
|
|
if (SWOOLE_G(use_shortname))
|
|
{
|
|
sw_zend_register_class_alias("Co\\Socket", swoole_socket_coro_class_entry_ptr);
|
|
sw_zend_register_class_alias("Co\\Socket\\Exception", swoole_socket_coro_exception_class_entry_ptr);
|
|
}
|
|
}
|
|
|
|
static int socket_onReadable(swReactor *reactor, swEvent *event)
|
|
{
|
|
socket_coro *sock = (socket_coro *) event->socket->object;
|
|
php_context *context = &sock->context;
|
|
|
|
zval *retval = NULL;
|
|
zval result;
|
|
|
|
swSocketAddress client_addr;
|
|
socklen_t client_addrlen = sizeof(client_addr);
|
|
|
|
reactor->del(reactor, sock->fd);
|
|
|
|
if (sock->timer)
|
|
{
|
|
swTimer_del(&SwooleG.timer, sock->timer);
|
|
sock->timer = NULL;
|
|
}
|
|
|
|
switch (sock->opcode)
|
|
{
|
|
case SW_SOCKET_OPCODE_ACCEPT:
|
|
{
|
|
int conn;
|
|
#ifdef HAVE_ACCEPT4
|
|
conn = accept4(sock->fd, (struct sockaddr *) &client_addr, &client_addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
|
|
#else
|
|
conn = accept(event->fd, (struct sockaddr *) &client_addr, &client_addrlen);
|
|
if (conn >= 0)
|
|
{
|
|
swoole_fcntl_set_option(conn, 1, 1);
|
|
}
|
|
#endif
|
|
if (conn >= 0)
|
|
{
|
|
zend_object *client;
|
|
client = swoole_socket_coro_create(swoole_socket_coro_class_entry_ptr);
|
|
socket_coro *client_sock = (socket_coro *) sw_socket_coro_fetch_object(client);
|
|
ZVAL_OBJ(&result, &client_sock->std);
|
|
client_sock->fd = conn;
|
|
client_sock->domain = sock->domain;
|
|
client_sock->object = result;
|
|
// zend_object_std_dtor(&client_sock->std);
|
|
}
|
|
else
|
|
{
|
|
zend_update_property_long(swoole_socket_coro_class_entry_ptr, &sock->object, ZEND_STRL("errCode"), errno TSRMLS_CC);
|
|
ZVAL_FALSE(&result);
|
|
}
|
|
break;
|
|
}
|
|
case SW_SOCKET_OPCODE_RECV:
|
|
{
|
|
zend_string *buf = zend_string_alloc(SW_BUFFER_SIZE_BIG, 0);
|
|
int bytes = 0;
|
|
|
|
while (1)
|
|
{
|
|
int n = recv(sock->fd, ZSTR_VAL(buf) + bytes, ZSTR_LEN(buf) - bytes - 1, MSG_DONTWAIT);
|
|
if (n < 0)
|
|
{
|
|
if (errno == EINTR)
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if (bytes == 0)
|
|
{
|
|
bytes = -1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else if (n == 0)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
bytes += n;
|
|
if (sock->type != SOCK_STREAM)
|
|
{
|
|
break;
|
|
}
|
|
if (ZSTR_LEN(buf) - 1 == bytes)
|
|
{
|
|
zend_string_realloc(buf, ZSTR_LEN(buf) + SW_BUFFER_SIZE_BIG, 0);
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
if (bytes < 0)
|
|
{
|
|
zend_update_property_long(swoole_socket_coro_class_entry_ptr, &sock->object, ZEND_STRL("errCode"), errno TSRMLS_CC);
|
|
zend_string_free(buf);
|
|
ZVAL_FALSE(&result);
|
|
}
|
|
else if (bytes == 0)
|
|
{
|
|
zend_string_free(buf);
|
|
ZVAL_EMPTY_STRING(&result);
|
|
}
|
|
else
|
|
{
|
|
ZVAL_NEW_STR(&result, buf);
|
|
ZSTR_LEN(buf) = bytes;
|
|
ZSTR_VAL(buf)[bytes] = 0;
|
|
}
|
|
break;
|
|
}
|
|
case SW_SOCKET_OPCODE_RECVFROM:
|
|
{
|
|
zend_string *buf = zend_string_alloc(SW_BUFFER_SIZE_BIG, 0);
|
|
swSocketAddress info;
|
|
zval *peername = Z_REFVAL(context->coro_params);
|
|
info.len = sizeof(info.addr);
|
|
int bytes = recvfrom(sock->fd, ZSTR_VAL(buf), ZSTR_LEN(buf) - 1, 0, (struct sockaddr *) &info.addr, &info.len);
|
|
if (bytes < 0)
|
|
{
|
|
zend_update_property_long(swoole_socket_coro_class_entry_ptr, &sock->object, ZEND_STRL("errCode"), errno TSRMLS_CC);
|
|
zend_string_free(buf);
|
|
ZVAL_FALSE(&result);
|
|
}
|
|
else if (bytes == 0)
|
|
{
|
|
zend_string_free(buf);
|
|
ZVAL_EMPTY_STRING(&result);
|
|
}
|
|
else
|
|
{
|
|
array_init(peername);
|
|
if (sock->domain == AF_INET)
|
|
{
|
|
add_assoc_long(peername, "port", ntohs(info.addr.inet_v4.sin_port));
|
|
add_assoc_string(peername, "address", inet_ntoa(info.addr.inet_v4.sin_addr));
|
|
}
|
|
else if (sock->domain == AF_INET6)
|
|
{
|
|
add_assoc_long(peername, "port", ntohs(info.addr.inet_v6.sin6_port));
|
|
char tmp[INET6_ADDRSTRLEN];
|
|
if (inet_ntop(AF_INET6, &info.addr.inet_v6.sin6_addr, tmp, sizeof(tmp)))
|
|
{
|
|
sw_add_assoc_string(peername, "address", tmp, 1);
|
|
}
|
|
else
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "inet_ntop() failed.");
|
|
}
|
|
}
|
|
else if (sock->domain == AF_UNIX)
|
|
{
|
|
add_assoc_string(peername, "address", info.addr.un.sun_path);
|
|
}
|
|
ZVAL_NEW_STR(&result, buf);
|
|
ZSTR_LEN(buf) = bytes;
|
|
ZSTR_VAL(buf)[bytes] = 0;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//unbind coroutine
|
|
sock->cid = 0;
|
|
int ret = coro_resume(context, &result, &retval);
|
|
zval_ptr_dtor(&result);
|
|
if (ret == CORO_END && retval)
|
|
{
|
|
zval_ptr_dtor(retval);
|
|
}
|
|
return SW_OK;
|
|
}
|
|
|
|
static int socket_onWritable(swReactor *reactor, swEvent *event)
|
|
{
|
|
socket_coro *sock = (socket_coro *) event->socket->object;
|
|
php_context *context = &sock->context;
|
|
|
|
zval *retval = NULL;
|
|
zval result;
|
|
|
|
reactor->del(reactor, sock->fd);
|
|
|
|
if (sock->timer)
|
|
{
|
|
swTimer_del(&SwooleG.timer, sock->timer);
|
|
sock->timer = NULL;
|
|
}
|
|
|
|
switch (sock->opcode)
|
|
{
|
|
case SW_SOCKET_OPCODE_SEND:
|
|
{
|
|
int n = send(sock->fd, Z_STRVAL(context->coro_params), Z_STRLEN(context->coro_params), MSG_DONTWAIT);
|
|
if (n < 0)
|
|
{
|
|
zend_update_property_long(swoole_socket_coro_class_entry_ptr, &sock->object, ZEND_STRL("errCode"), ETIMEDOUT TSRMLS_CC);
|
|
ZVAL_FALSE(&result);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
ZVAL_LONG(&result, n);
|
|
}
|
|
break;
|
|
}
|
|
case SW_SOCKET_OPCODE_CONNECT:
|
|
{
|
|
socklen_t len = sizeof(SwooleG.error);
|
|
if (getsockopt(event->fd, SOL_SOCKET, SO_ERROR, &SwooleG.error, &len) < 0)
|
|
{
|
|
zend_update_property_long(swoole_socket_coro_class_entry_ptr, &sock->object, ZEND_STRL("errCode"), errno TSRMLS_CC);
|
|
ZVAL_FALSE(&result);
|
|
break;
|
|
}
|
|
if (SwooleG.error == 0)
|
|
{
|
|
ZVAL_TRUE(&result);
|
|
}
|
|
else
|
|
{
|
|
zend_update_property_long(swoole_socket_coro_class_entry_ptr, &sock->object, ZEND_STRL("errCode"), SwooleG.error TSRMLS_CC);
|
|
ZVAL_FALSE(&result);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//unbind coroutine
|
|
sock->cid = 0;
|
|
int ret = coro_resume(context, &result, &retval);
|
|
zval_ptr_dtor(&result);
|
|
if (ret == CORO_END && retval)
|
|
{
|
|
zval_ptr_dtor(retval);
|
|
}
|
|
return SW_OK;
|
|
}
|
|
|
|
static void socket_onResolveCompleted(swAio_event *event)
|
|
{
|
|
socket_coro *sock = (socket_coro *) event->object;
|
|
php_context *context = &sock->context;
|
|
|
|
zval *retval = NULL;
|
|
zval result;
|
|
|
|
if (event->error == 0)
|
|
{
|
|
int ret = swoole_socket_connect(sock, event->buf, strlen(event->buf), Z_LVAL(context->coro_params));
|
|
if (ret == -1 && errno == EINPROGRESS)
|
|
{
|
|
efree(event->buf);
|
|
if (context->private_data)
|
|
{
|
|
int ms = (int) (Z_DVAL_P((zval *) context->private_data) * 1000);
|
|
php_swoole_check_timer(ms);
|
|
sock->timer = SwooleG.timer.add(&SwooleG.timer, ms, 0, sock, socket_onTimeout);
|
|
efree(context->private_data);
|
|
context->private_data = NULL;
|
|
}
|
|
if (SwooleG.main_reactor->add(SwooleG.main_reactor, sock->fd, PHP_SWOOLE_FD_SOCKET | SW_EVENT_WRITE) < 0)
|
|
{
|
|
goto _error;
|
|
}
|
|
else
|
|
{
|
|
swConnection *_socket = swReactor_get(SwooleG.main_reactor, sock->fd);
|
|
_socket->object = sock;
|
|
return;
|
|
}
|
|
}
|
|
else if (ret == 0)
|
|
{
|
|
ZVAL_TRUE(&result);
|
|
sock->cid = 0;
|
|
int ret = coro_resume(context, &result, &retval);
|
|
if (ret == CORO_END && retval)
|
|
{
|
|
sw_zval_ptr_dtor(&retval);
|
|
}
|
|
}
|
|
goto _error;
|
|
}
|
|
else
|
|
{
|
|
_error:
|
|
ZVAL_FALSE(&result);
|
|
//unbind coroutine
|
|
sock->cid = 0;
|
|
int ret = coro_resume(context, &result, &retval);
|
|
if (ret == CORO_END && retval)
|
|
{
|
|
sw_zval_ptr_dtor(&retval);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void socket_onTimeout(swTimer *timer, swTimer_node *tnode)
|
|
{
|
|
socket_coro *sock = (socket_coro *) tnode->data;
|
|
php_context *context = &sock->context;
|
|
sock->timer = NULL;
|
|
SwooleG.main_reactor->del(SwooleG.main_reactor, sock->fd);
|
|
|
|
zval *retval = NULL;
|
|
zval result;
|
|
if (sock->opcode == SW_SOCKET_OPCODE_RECV)
|
|
{
|
|
zend_update_property_long(swoole_socket_coro_class_entry_ptr, &sock->object, ZEND_STRL("errCode"), EAGAIN TSRMLS_CC);
|
|
}
|
|
else
|
|
{
|
|
zend_update_property_long(swoole_socket_coro_class_entry_ptr, &sock->object, ZEND_STRL("errCode"), ETIMEDOUT TSRMLS_CC);
|
|
}
|
|
ZVAL_FALSE(&result);
|
|
|
|
//unbind coroutine
|
|
sock->cid = 0;
|
|
int ret = coro_resume(context, &result, &retval);
|
|
zval_ptr_dtor(&result);
|
|
if (ret == CORO_END && retval)
|
|
{
|
|
zval_ptr_dtor(retval);
|
|
}
|
|
}
|
|
|
|
static int swoole_socket_connect(socket_coro *sock, char *host, size_t l_host, int port)
|
|
{
|
|
switch (sock->domain)
|
|
{
|
|
case AF_INET:
|
|
{
|
|
struct sockaddr_in addr;
|
|
addr.sin_family = AF_INET;
|
|
addr.sin_port = htons(port);
|
|
socklen_t len = sizeof(addr);
|
|
|
|
if (!inet_pton(AF_INET, host, &addr.sin_addr))
|
|
{
|
|
return -2;
|
|
}
|
|
else
|
|
{
|
|
return connect(sock->fd, (struct sockaddr *) &addr, len);
|
|
}
|
|
}
|
|
case AF_INET6:
|
|
{
|
|
struct sockaddr_in6 addr;
|
|
addr.sin6_family = AF_INET6;
|
|
addr.sin6_port = htons(port);
|
|
socklen_t len = sizeof(addr);
|
|
|
|
if (!inet_pton(AF_INET6, host, &addr.sin6_addr))
|
|
{
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
return connect(sock->fd, (struct sockaddr *) &addr, len);
|
|
}
|
|
}
|
|
case AF_UNIX:
|
|
{
|
|
struct sockaddr_un s_un = { 0 };
|
|
if (l_host >= sizeof(s_un.sun_path))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
s_un.sun_family = AF_UNIX;
|
|
memcpy(&s_un.sun_path, host, l_host);
|
|
return connect(sock->fd, (struct sockaddr *) &s_un, (socklen_t) (XtOffsetOf(struct sockaddr_un, sun_path) + l_host));
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return -3;
|
|
}
|
|
|
|
static PHP_METHOD(swoole_socket_coro, __construct)
|
|
{
|
|
zend_long domain, type, protocol;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(3, 3)
|
|
Z_PARAM_LONG(domain);
|
|
Z_PARAM_LONG(type);
|
|
Z_PARAM_LONG(protocol);
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
socket_coro *sock = (socket_coro *) Z_SOCKET_CORO_OBJ_P(getThis());
|
|
sock->fd = socket(domain, type, protocol);
|
|
sock->domain = domain;
|
|
sock->type = type;
|
|
sock->object = *getThis();
|
|
|
|
if (sock->fd < 0)
|
|
{
|
|
zend_throw_exception_ex(swoole_socket_coro_exception_class_entry_ptr, errno, "Unable to create socket [%d]: %s",
|
|
strerror(errno), errno TSRMLS_CC);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
php_swoole_check_reactor();
|
|
if (!swReactor_handle_isset(SwooleG.main_reactor, PHP_SWOOLE_FD_SOCKET))
|
|
{
|
|
SwooleG.main_reactor->setHandle(SwooleG.main_reactor, PHP_SWOOLE_FD_SOCKET | SW_EVENT_READ, socket_onReadable);
|
|
SwooleG.main_reactor->setHandle(SwooleG.main_reactor, PHP_SWOOLE_FD_SOCKET | SW_EVENT_WRITE, socket_onWritable);
|
|
}
|
|
|
|
swSetNonBlock(sock->fd);
|
|
}
|
|
|
|
static PHP_METHOD(swoole_socket_coro, bind)
|
|
{
|
|
char *address;
|
|
size_t l_address;
|
|
zend_long port = 0;
|
|
|
|
struct sockaddr_storage sa_storage = {0};
|
|
struct sockaddr *sock_type = (struct sockaddr*) &sa_storage;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 2)
|
|
Z_PARAM_STRING(address, l_address);
|
|
Z_PARAM_OPTIONAL
|
|
Z_PARAM_LONG(port);
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
int retval;
|
|
|
|
socket_coro *sock = (socket_coro *) Z_SOCKET_CORO_OBJ_P(getThis());
|
|
switch (sock->domain)
|
|
{
|
|
case AF_UNIX:
|
|
{ struct sockaddr_un *sa = (struct sockaddr_un *) sock_type;
|
|
sa->sun_family = AF_UNIX;
|
|
|
|
if (l_address >= sizeof(sa->sun_path))
|
|
{
|
|
swoole_php_error(E_WARNING, "invalid path: too long (maximum size is %d)", (int )sizeof(sa->sun_path) - 1);
|
|
RETURN_FALSE;
|
|
}
|
|
memcpy(&sa->sun_path, address, l_address);
|
|
|
|
retval = bind(sock->fd, (struct sockaddr *) sa,
|
|
offsetof(struct sockaddr_un, sun_path) + l_address);
|
|
break;
|
|
}
|
|
|
|
case AF_INET:
|
|
{
|
|
struct sockaddr_in *sa = (struct sockaddr_in *) sock_type;
|
|
sa->sin_family = AF_INET;
|
|
sa->sin_port = htons((unsigned short) port);
|
|
if (!inet_aton(address, &sa->sin_addr))
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
retval = bind(sock->fd, (struct sockaddr *) sa, sizeof(struct sockaddr_in));
|
|
break;
|
|
}
|
|
|
|
case AF_INET6:
|
|
{
|
|
struct sockaddr_in6 *sa = (struct sockaddr_in6 *) sock_type;
|
|
sa->sin6_family = AF_INET6;
|
|
sa->sin6_port = htons((unsigned short) port);
|
|
|
|
if (!inet_pton(AF_INET6, address, &sa->sin6_addr))
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
retval = bind(sock->fd, (struct sockaddr *)sa, sizeof(struct sockaddr_in6));
|
|
break;
|
|
}
|
|
default:
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (retval != 0)
|
|
{
|
|
zend_update_property_long(swoole_socket_coro_class_entry_ptr, getThis(), ZEND_STRL("errCode"), errno TSRMLS_CC);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
RETURN_TRUE;
|
|
}
|
|
|
|
static PHP_METHOD(swoole_socket_coro, listen)
|
|
{
|
|
zend_long backlog = 0;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(0, 1)
|
|
Z_PARAM_OPTIONAL
|
|
Z_PARAM_LONG(backlog);
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
socket_coro *sock = (socket_coro *) Z_SOCKET_CORO_OBJ_P(getThis());
|
|
if (listen(sock->fd, backlog) != 0)
|
|
{
|
|
zend_update_property_long(swoole_socket_coro_class_entry_ptr, getThis(), ZEND_STRL("errCode"), errno TSRMLS_CC);
|
|
RETURN_FALSE;
|
|
}
|
|
RETURN_TRUE;
|
|
}
|
|
|
|
static PHP_METHOD(swoole_socket_coro, accept)
|
|
{
|
|
coro_check(TSRMLS_C);
|
|
|
|
double timeout = -1;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(0, 1)
|
|
Z_PARAM_OPTIONAL
|
|
Z_PARAM_DOUBLE(timeout);
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
socket_coro *sock = (socket_coro *) Z_SOCKET_CORO_OBJ_P(getThis());
|
|
if (unlikely(sock->cid && sock->cid != sw_get_current_cid()))
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "socket has already been bound to another coroutine.");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (SwooleG.main_reactor->add(SwooleG.main_reactor, sock->fd, PHP_SWOOLE_FD_SOCKET | SW_EVENT_READ) < 0)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
swConnection *_socket = swReactor_get(SwooleG.main_reactor, sock->fd);
|
|
_socket->object = sock;
|
|
|
|
php_context *context = &sock->context;
|
|
context->state = SW_CORO_CONTEXT_RUNNING;
|
|
context->onTimeout = NULL;
|
|
sock->opcode = SW_SOCKET_OPCODE_ACCEPT;
|
|
|
|
if (timeout > 0)
|
|
{
|
|
int ms = (int) (timeout * 1000);
|
|
php_swoole_check_timer(ms);
|
|
sock->timer = SwooleG.timer.add(&SwooleG.timer, ms, 0, sock, socket_onTimeout);
|
|
}
|
|
|
|
coro_save(context);
|
|
coro_yield();
|
|
}
|
|
|
|
static PHP_METHOD(swoole_socket_coro, recv)
|
|
{
|
|
coro_check(TSRMLS_C);
|
|
|
|
double timeout = -1;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(0, 1)
|
|
Z_PARAM_OPTIONAL
|
|
Z_PARAM_DOUBLE(timeout);
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
socket_coro *sock = (socket_coro *) Z_SOCKET_CORO_OBJ_P(getThis());
|
|
if (unlikely(sock->cid && sock->cid != sw_get_current_cid()))
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "socket has already been bound to another coroutine.");
|
|
RETURN_FALSE;
|
|
}
|
|
if (SwooleG.main_reactor->add(SwooleG.main_reactor, sock->fd, PHP_SWOOLE_FD_SOCKET | SW_EVENT_READ) < 0)
|
|
{
|
|
zend_update_property_long(swoole_socket_coro_class_entry_ptr, getThis(), ZEND_STRL("errCode"), errno TSRMLS_CC);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
swConnection *_socket = swReactor_get(SwooleG.main_reactor, sock->fd);
|
|
_socket->object = sock;
|
|
|
|
php_context *context = &sock->context;
|
|
context->state = SW_CORO_CONTEXT_RUNNING;
|
|
context->onTimeout = NULL;
|
|
sock->opcode = SW_SOCKET_OPCODE_RECV;
|
|
|
|
if (timeout > 0)
|
|
{
|
|
int ms = (int) (timeout * 1000);
|
|
php_swoole_check_timer(ms);
|
|
sock->timer = SwooleG.timer.add(&SwooleG.timer, ms, 0, sock, socket_onTimeout);
|
|
}
|
|
|
|
coro_save(context);
|
|
coro_yield();
|
|
}
|
|
|
|
static PHP_METHOD(swoole_socket_coro, recvfrom)
|
|
{
|
|
coro_check(TSRMLS_C);
|
|
|
|
zval *peername;
|
|
double timeout = -1;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 2)
|
|
Z_PARAM_ZVAL(peername);
|
|
Z_PARAM_OPTIONAL
|
|
Z_PARAM_DOUBLE(timeout);
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
socket_coro *sock = (socket_coro *) Z_SOCKET_CORO_OBJ_P(getThis());
|
|
if (unlikely(sock->cid && sock->cid != sw_get_current_cid()))
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "socket has already been bound to another coroutine.");
|
|
RETURN_FALSE;
|
|
}
|
|
if (SwooleG.main_reactor->add(SwooleG.main_reactor, sock->fd, PHP_SWOOLE_FD_SOCKET | SW_EVENT_READ) < 0)
|
|
{
|
|
zend_update_property_long(swoole_socket_coro_class_entry_ptr, getThis(), ZEND_STRL("errCode"), errno TSRMLS_CC);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
swConnection *_socket = swReactor_get(SwooleG.main_reactor, sock->fd);
|
|
_socket->object = sock;
|
|
|
|
php_context *context = &sock->context;
|
|
context->state = SW_CORO_CONTEXT_RUNNING;
|
|
context->onTimeout = NULL;
|
|
context->coro_params = *peername;
|
|
sock->opcode = SW_SOCKET_OPCODE_RECVFROM;
|
|
|
|
if (timeout > 0)
|
|
{
|
|
int ms = (int) (timeout * 1000);
|
|
php_swoole_check_timer(ms);
|
|
sock->timer = SwooleG.timer.add(&SwooleG.timer, ms, 0, sock, socket_onTimeout);
|
|
}
|
|
|
|
coro_save(context);
|
|
coro_yield();
|
|
}
|
|
|
|
static PHP_METHOD(swoole_socket_coro, send)
|
|
{
|
|
coro_check(TSRMLS_C);
|
|
|
|
double timeout = -1;
|
|
zval *data;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 2)
|
|
Z_PARAM_ZVAL(data);
|
|
Z_PARAM_OPTIONAL
|
|
Z_PARAM_DOUBLE(timeout);
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
if (Z_TYPE_P(data) != IS_STRING)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
socket_coro *sock = (socket_coro *) Z_SOCKET_CORO_OBJ_P(getThis());
|
|
if (unlikely(sock->cid && sock->cid != sw_get_current_cid()))
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "socket has already been bound to another coroutine.");
|
|
RETURN_FALSE;
|
|
}
|
|
int ret = send(sock->fd, Z_STRVAL_P(data), Z_STRLEN_P(data), MSG_DONTWAIT);
|
|
if (ret < 0)
|
|
{
|
|
if (errno == EAGAIN)
|
|
{
|
|
goto _yield;
|
|
}
|
|
zend_update_property_long(swoole_socket_coro_class_entry_ptr, getThis(), ZEND_STRL("errCode"), errno TSRMLS_CC);
|
|
RETURN_FALSE;
|
|
}
|
|
else
|
|
{
|
|
RETURN_LONG(ret);
|
|
}
|
|
|
|
swConnection *_socket = swReactor_get(SwooleG.main_reactor, sock->fd);
|
|
_socket->object = sock;
|
|
|
|
_yield:
|
|
if (SwooleG.main_reactor->add(SwooleG.main_reactor, sock->fd, PHP_SWOOLE_FD_SOCKET | SW_EVENT_WRITE) < 0)
|
|
{
|
|
zend_update_property_long(swoole_socket_coro_class_entry_ptr, getThis(), ZEND_STRL("errCode"), errno TSRMLS_CC);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
php_context *context = &sock->context;
|
|
context->state = SW_CORO_CONTEXT_RUNNING;
|
|
context->onTimeout = NULL;
|
|
context->coro_params = *data;
|
|
sock->opcode = SW_SOCKET_OPCODE_SEND;
|
|
|
|
if (timeout > 0)
|
|
{
|
|
int ms = (int) (timeout * 1000);
|
|
php_swoole_check_timer(ms);
|
|
sock->timer = SwooleG.timer.add(&SwooleG.timer, ms, 0, sock, socket_onTimeout);
|
|
}
|
|
|
|
coro_save(context);
|
|
coro_yield();
|
|
}
|
|
|
|
static PHP_METHOD(swoole_socket_coro, sendto)
|
|
{
|
|
char *data;
|
|
size_t l_data;
|
|
char *addr;
|
|
size_t l_addr;
|
|
zend_long port = 0;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(3, 3)
|
|
Z_PARAM_STRING(addr, l_addr);
|
|
Z_PARAM_LONG(port);
|
|
Z_PARAM_STRING(data, l_data);
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
socket_coro *sock = (socket_coro *) Z_SOCKET_CORO_OBJ_P(getThis());
|
|
|
|
int ret;
|
|
if (sock->domain == AF_INET)
|
|
{
|
|
ret = swSocket_udp_sendto(sock->fd, addr, port, data, l_data);
|
|
}
|
|
else if (sock->domain == AF_INET6)
|
|
{
|
|
ret = swSocket_udp_sendto6(sock->fd, addr, port, data, l_data);
|
|
}
|
|
else if (sock->domain == AF_UNIX)
|
|
{
|
|
ret = swSocket_unix_sendto(sock->fd, addr, data, l_data);
|
|
}
|
|
else
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (ret < 0)
|
|
{
|
|
zend_update_property_long(swoole_socket_coro_class_entry_ptr, getThis(), ZEND_STRL("errCode"), errno TSRMLS_CC);
|
|
RETURN_FALSE;
|
|
}
|
|
else
|
|
{
|
|
RETURN_LONG(ret);
|
|
}
|
|
}
|
|
|
|
static PHP_METHOD(swoole_socket_coro, close)
|
|
{
|
|
coro_check(TSRMLS_C);
|
|
|
|
socket_coro *sock = (socket_coro *) Z_SOCKET_CORO_OBJ_P(getThis());
|
|
if (sock->fd < 0)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
if (unlikely(sock->cid && sock->cid != sw_get_current_cid()))
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "socket has already been bound to another coroutine.");
|
|
RETURN_FALSE;
|
|
}
|
|
int ret = SwooleG.main_reactor->close(SwooleG.main_reactor, sock->fd);
|
|
sock->fd = -1;
|
|
SW_CHECK_RETURN(ret);
|
|
}
|
|
|
|
static PHP_METHOD(swoole_socket_coro, getsockname)
|
|
{
|
|
socket_coro *sock = (socket_coro *) Z_SOCKET_CORO_OBJ_P(getThis());
|
|
array_init(return_value);
|
|
|
|
swSocketAddress info;
|
|
char addr_str[INET6_ADDRSTRLEN + 1];
|
|
|
|
if (getsockname(sock->fd, (struct sockaddr *) &info.addr.inet_v4, &info.len) != 0)
|
|
{
|
|
zend_update_property_long(swoole_socket_coro_class_entry_ptr, getThis(), ZEND_STRL("errCode"), errno TSRMLS_CC);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
switch (sock->domain)
|
|
{
|
|
case AF_INET6:
|
|
inet_ntop(AF_INET6, &info.addr.inet_v6.sin6_addr, addr_str, INET6_ADDRSTRLEN);
|
|
add_assoc_string(return_value, "address", addr_str);
|
|
add_assoc_long(return_value, "port", htons(info.addr.inet_v6.sin6_port));
|
|
break;
|
|
case AF_INET:
|
|
inet_ntop(AF_INET, &info.addr.inet_v4.sin_addr, addr_str, INET_ADDRSTRLEN);
|
|
add_assoc_string(return_value, "address", addr_str);
|
|
add_assoc_long(return_value, "port", htons(info.addr.inet_v4.sin_port));
|
|
break;
|
|
case AF_UNIX:
|
|
add_assoc_string(return_value, "address", info.addr.un.sun_path);
|
|
break;
|
|
default:
|
|
swoole_php_error(E_WARNING, "Unsupported address family %d", sock->domain);
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
|
|
static PHP_METHOD(swoole_socket_coro, getpeername)
|
|
{
|
|
socket_coro *sock = (socket_coro *) Z_SOCKET_CORO_OBJ_P(getThis());
|
|
array_init(return_value);
|
|
|
|
swSocketAddress info;
|
|
char addr_str[INET6_ADDRSTRLEN + 1];
|
|
|
|
if (getpeername(sock->fd, (struct sockaddr *) &info.addr.inet_v4, &info.len) != 0)
|
|
{
|
|
zend_update_property_long(swoole_socket_coro_class_entry_ptr, getThis(), ZEND_STRL("errCode"), errno TSRMLS_CC);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
switch (sock->domain)
|
|
{
|
|
case AF_INET6:
|
|
inet_ntop(AF_INET6, &info.addr.inet_v6.sin6_addr, addr_str, INET6_ADDRSTRLEN);
|
|
add_assoc_string(return_value, "address", addr_str);
|
|
add_assoc_long(return_value, "port", htons(info.addr.inet_v6.sin6_port));
|
|
break;
|
|
case AF_INET:
|
|
inet_ntop(AF_INET, &info.addr.inet_v4.sin_addr, addr_str, INET_ADDRSTRLEN);
|
|
add_assoc_string(return_value, "address", addr_str);
|
|
add_assoc_long(return_value, "port", htons(info.addr.inet_v4.sin_port));
|
|
break;
|
|
case AF_UNIX:
|
|
add_assoc_string(return_value, "address", info.addr.un.sun_path);
|
|
break;
|
|
default:
|
|
swoole_php_error(E_WARNING, "Unsupported address family %d", sock->domain);
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
|
|
static PHP_METHOD(swoole_socket_coro, connect)
|
|
{
|
|
coro_check(TSRMLS_C);
|
|
|
|
socket_coro *sock = (socket_coro *) Z_SOCKET_CORO_OBJ_P(getThis());
|
|
char *host;
|
|
size_t l_host;
|
|
zend_long port = 0;
|
|
double timeout = SW_CLIENT_DEFAULT_TIMEOUT;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 3)
|
|
Z_PARAM_STRING(host, l_host);
|
|
Z_PARAM_OPTIONAL
|
|
Z_PARAM_LONG(port);
|
|
Z_PARAM_DOUBLE(timeout);
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
if (sock->domain == AF_INET6 || sock->domain == AF_INET)
|
|
{
|
|
if (ZEND_NUM_ARGS() == 1)
|
|
{
|
|
swoole_php_error(E_WARNING, "Socket of type AF_INET/AF_INET6 requires port argument");
|
|
RETURN_FALSE;
|
|
}
|
|
else if (port == 0 || port >= 65536)
|
|
{
|
|
swoole_php_error(E_WARNING, "Invalid port argument[%d]", port);
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
if (unlikely(sock->cid && sock->cid != sw_get_current_cid()))
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "socket has already been bound to another coroutine.");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
int retval = swoole_socket_connect(sock, host, l_host, port);
|
|
if (retval == -2)
|
|
{
|
|
swAio_event ev;
|
|
bzero(&ev, sizeof(swAio_event));
|
|
|
|
ev.nbytes = l_host < SW_IP_MAX_LENGTH ? SW_IP_MAX_LENGTH : l_host + 1;
|
|
ev.buf = emalloc(ev.nbytes);
|
|
if (!ev.buf)
|
|
{
|
|
swWarn("malloc failed.");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
memcpy(ev.buf, host, l_host);
|
|
((char *) ev.buf)[l_host] = 0;
|
|
ev.flags = sock->domain;
|
|
ev.type = SW_AIO_GETHOSTBYNAME;
|
|
ev.object = sock;
|
|
ev.callback = socket_onResolveCompleted;
|
|
|
|
php_swoole_check_aio();
|
|
|
|
if (swAio_dispatch(&ev) < 0)
|
|
{
|
|
efree(ev.buf);
|
|
RETURN_FALSE
|
|
}
|
|
else
|
|
{
|
|
ZVAL_LONG(&sock->context.coro_params, port);
|
|
zval *ztimeout;
|
|
if (timeout > 0)
|
|
{
|
|
ztimeout = emalloc(sizeof(zval));
|
|
ZVAL_DOUBLE(ztimeout, timeout);
|
|
sock->context.private_data = ztimeout;
|
|
}
|
|
else
|
|
{
|
|
sock->context.private_data = NULL;
|
|
}
|
|
goto _yield;
|
|
}
|
|
}
|
|
else if (retval == -1)
|
|
{
|
|
if (errno == EINPROGRESS)
|
|
{
|
|
if (SwooleG.main_reactor->add(SwooleG.main_reactor, sock->fd, PHP_SWOOLE_FD_SOCKET | SW_EVENT_WRITE) < 0)
|
|
{
|
|
goto _error;
|
|
}
|
|
|
|
swConnection *_socket = swReactor_get(SwooleG.main_reactor, sock->fd);
|
|
_socket->object = sock;
|
|
|
|
if (timeout > 0)
|
|
{
|
|
int ms = (int) (timeout * 1000);
|
|
php_swoole_check_timer(ms);
|
|
sock->timer = SwooleG.timer.add(&SwooleG.timer, ms, 0, sock, socket_onTimeout);
|
|
}
|
|
|
|
php_context *context;
|
|
_yield: context = &sock->context;
|
|
context->state = SW_CORO_CONTEXT_RUNNING;
|
|
context->onTimeout = NULL;
|
|
sock->opcode = SW_SOCKET_OPCODE_CONNECT;
|
|
|
|
coro_save(context);
|
|
coro_yield();
|
|
}
|
|
else
|
|
{
|
|
_error: zend_update_property_long(swoole_socket_coro_class_entry_ptr, getThis(), ZEND_STRL("errCode"),
|
|
errno TSRMLS_CC);
|
|
}
|
|
}
|
|
else if (retval == 0)
|
|
{
|
|
RETURN_TRUE;
|
|
}
|
|
else
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
|
|
#ifdef SWOOLE_SOCKETS_SUPPORT
|
|
static PHP_METHOD(swoole_socket_coro, getSocket)
|
|
{
|
|
socket_coro *sock = (socket_coro *) Z_SOCKET_CORO_OBJ_P(getThis());
|
|
if (sock->fd < 0)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
php_socket *socket_object = swoole_convert_to_socket(sock->fd);
|
|
if (!socket_object)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
SW_ZEND_REGISTER_RESOURCE(return_value, (void * ) socket_object, php_sockets_le_socket());
|
|
zval *zsocket = sw_zval_dup(return_value);
|
|
sw_zval_add_ref(&zsocket);
|
|
sock->resource = zsocket;
|
|
}
|
|
#endif
|
|
#endif
|