archive
This commit is contained in:
commit
9f3a47020d
|
@ -0,0 +1,26 @@
|
|||
sudo: required
|
||||
dist: trusty
|
||||
group: edge
|
||||
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 7.0
|
||||
- 7.1
|
||||
- 7.2
|
||||
- nightly
|
||||
|
||||
before_install:
|
||||
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq g++-6
|
||||
- sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-6 90
|
||||
- sudo apt-get install libboost1.55-all-dev
|
||||
|
||||
script:
|
||||
- phpize
|
||||
- ./configure --enable-asio-strand
|
||||
- make
|
||||
|
||||
after_success:
|
||||
- make test
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017-2018 CismonX
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -0,0 +1,28 @@
|
|||
# php-asio
|
||||
|
||||
[![Travis-CI](https://travis-ci.org/CismonX/php-asio.svg?branch=master)](https://travis-ci.org/CismonX/php-asio)
|
||||
[![MIT license](https://img.shields.io/badge/licence-MIT-blue.svg)](https://opensource.org/licenses/MIT)
|
||||
|
||||
## 1. About
|
||||
|
||||
This extension is a PHP wrapper for the Boost.Asio library, which provides a high-performance event-driven model for network I/O.
|
||||
|
||||
Now php-asio is **in development**, do not use it in production.
|
||||
|
||||
Bug reports and pull requests are welcome.
|
||||
|
||||
## 2. Documentation
|
||||
|
||||
See the [Wiki](https://github.com/CismonX/php-asio/wiki) page for documentation.
|
||||
|
||||
Signatures of classes and functions can be found within [stubs/](stubs/) directory, with PHPDoc.
|
||||
|
||||
There are also some test cases in the [tests/](tests/) directory.
|
||||
|
||||
## 3. TODO list
|
||||
|
||||
* Fix memory leak. (Priority: **high**)
|
||||
* Multi-threading support. (Priority: **medium**)
|
||||
* Add support for serial ports. (Priority: **low**)
|
||||
* Add socket `onReadable()` `onWritable()` `onError()` methods (with Boost version 1.66 and above). (Priority: **low**)
|
||||
* Add support for Windows. (Priority: **low**)
|
|
@ -0,0 +1,43 @@
|
|||
PHP_ARG_ENABLE(asio, for asio support,
|
||||
[ --enable-asio Enable asio support ])
|
||||
|
||||
PHP_ARG_ENABLE(asio-coroutine, for coroutine support,
|
||||
[ --disable-asio-coroutine Disable coroutine support ], yes, no)
|
||||
|
||||
PHP_ARG_ENABLE(asio-strand, for strand support,
|
||||
[ --enable-asio-strand Enable strand support ], no, no)
|
||||
|
||||
PHP_ARG_ENABLE(asio-null-buffers, for null buffer support,
|
||||
[ --enable-asio-null-buffers Enable null buffers ], no, no)
|
||||
|
||||
if test "$PHP_ASIO" != "no"; then
|
||||
PHP_REQUIRE_CXX()
|
||||
|
||||
PHP_ASIO_SRC="src/php_asio.cpp \
|
||||
src/service.cpp \
|
||||
src/wrapped_handler.cpp \
|
||||
src/future.cpp \
|
||||
src/strand.cpp \
|
||||
src/timer.cpp \
|
||||
src/signal.cpp \
|
||||
src/resolver.cpp \
|
||||
src/socket.cpp \
|
||||
src/acceptor.cpp \
|
||||
src/stream_descriptor.cpp"
|
||||
|
||||
PHP_NEW_EXTENSION(asio, $PHP_ASIO_SRC, $ext_shared, cli, -std=c++14, yes)
|
||||
|
||||
if test "$PHP_ASIO_COROUTINE" != "no"; then
|
||||
AC_DEFINE(ENABLE_COROUTINE, 1, [ ])
|
||||
fi
|
||||
if test "$PHP_ASIO_STRAND" != "no"; then
|
||||
AC_DEFINE(ENABLE_STRAND, 1, [ ])
|
||||
fi
|
||||
if test "$PHP_ASIO_NULL_BUFFERS" != "no"; then
|
||||
AC_DEFINE(ENABLE_NULL_BUFFERS, 1, [ ])
|
||||
fi
|
||||
|
||||
PHP_ADD_LIBRARY(boost_system, 1, ASIO_SHARED_LIBADD)
|
||||
PHP_ADD_LIBRARY(boost_filesystem, 1, ASIO_SHARED_LIBADD)
|
||||
PHP_SUBST(ASIO_SHARED_LIBADD)
|
||||
fi
|
|
@ -0,0 +1,171 @@
|
|||
/**
|
||||
* php-asio/acceptor.cpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#include "acceptor.hpp"
|
||||
#include "future.hpp"
|
||||
#include "io.hpp"
|
||||
|
||||
namespace asio
|
||||
{
|
||||
template <typename Protocol>
|
||||
zval* acceptor<Protocol>::handler(const boost::system::error_code& error,
|
||||
socket<Protocol>* const socket, zval* callback, zval* argument)
|
||||
{
|
||||
PHP_ASIO_INVOKE_CALLBACK_START(4)
|
||||
ZVAL_OBJ(&arguments[1], p3::to_zend_object(socket));
|
||||
PHP_ASIO_INVOKE_CALLBACK();
|
||||
PHP_ASIO_INVOKE_CALLBACK_END();
|
||||
CORO_RETURN(ZVAL_OBJ, p3::to_zend_object(socket));
|
||||
}
|
||||
|
||||
/* {{{ proto int TcpAcceptor::accept(bool inet6);
|
||||
* Open socket acceptor. */
|
||||
template <>
|
||||
P3_METHOD(tcp_acceptor, open)
|
||||
{
|
||||
zend_bool inet6;
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||
Z_PARAM_BOOL(inet6)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
boost::system::error_code ec;
|
||||
acceptor_.open(inet6 ? tcp::v6() : tcp::v4(), ec);
|
||||
RETVAL_EC(ec)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int UnixAcceptor::accept(void);
|
||||
* Open socket acceptor. */
|
||||
template <>
|
||||
P3_METHOD(unix_acceptor, open)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
acceptor_.open(unix(), ec);
|
||||
RETVAL_EC(ec)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int TcpAcceptor::assign(bool inet6, int|resource fd);
|
||||
* Assign an existing native socket to the acceptor. */
|
||||
template <>
|
||||
P3_METHOD(tcp_acceptor, assign)
|
||||
{
|
||||
PHP_ASIO_INET_ASSIGN(acceptor_, tcp);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int UnixAcceptor::assign(int|resource fd);
|
||||
* Assign an existing native socket to the acceptor. */
|
||||
template <>
|
||||
P3_METHOD(unix_acceptor, assign)
|
||||
{
|
||||
PHP_ASIO_LOCAL_ASSIGN(acceptor_, unix);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int TcpAcceptor::bind(string address, int port);
|
||||
* Bind the acceptor to the specified local endpoint. */
|
||||
template <>
|
||||
P3_METHOD(tcp_acceptor, bind)
|
||||
{
|
||||
zend_string* address;
|
||||
zend_long port_num;
|
||||
ZEND_PARSE_PARAMETERS_START(2, 2);
|
||||
Z_PARAM_STR(address)
|
||||
Z_PARAM_LONG(port_num)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
boost::system::error_code ec;
|
||||
acceptor_.bind({ boost::asio::ip::address::from_string(ZSTR_VAL(address)),
|
||||
static_cast<unsigned short>(port_num) }, ec);
|
||||
RETVAL_EC(ec);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int TcpAcceptor::bind(string path);
|
||||
* Bind the acceptor to the specified local endpoint. */
|
||||
template <>
|
||||
P3_METHOD(unix_acceptor, bind)
|
||||
{
|
||||
zend_string* socket_path;
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1);
|
||||
Z_PARAM_STR(socket_path)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
namespace fs = boost::filesystem;
|
||||
if (fs::status(ZSTR_VAL(socket_path)).type() == fs::socket_file)
|
||||
fs::remove(ZSTR_VAL(socket_path));
|
||||
boost::system::error_code ec;
|
||||
acceptor_.bind({ ZSTR_VAL(socket_path) }, ec);
|
||||
RETVAL_EC(ec);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int Acceptor::listen([int backlog]);
|
||||
* Put the acceptor into the state where it may accept new connections. */
|
||||
template <typename Protocol>
|
||||
P3_METHOD(acceptor<Protocol>, listen)
|
||||
{
|
||||
zend_long backlog = 0;
|
||||
ZEND_PARSE_PARAMETERS_START(0, 1)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_LONG(backlog)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
boost::system::error_code ec;
|
||||
acceptor_.listen(backlog ? static_cast<int>(backlog) :
|
||||
Protocol::socket::max_connections, ec);
|
||||
RETVAL_EC(ec);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int Acceptor::accept([callable callback], [mixed argument]);
|
||||
* Asynchronously accept a new connection into a socket. */
|
||||
template <typename Protocol>
|
||||
P3_METHOD(acceptor<Protocol>, accept)
|
||||
{
|
||||
zval* callback = nullptr;
|
||||
zval* argument = nullptr;
|
||||
ZEND_PARSE_PARAMETERS_START(0, 2)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_ZVAL(callback)
|
||||
Z_PARAM_ZVAL(argument)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
PHP_ASIO_OBJ_ALLOC(accepted_socket, socket<Protocol>, io_service_);
|
||||
PHP_ASIO_FUTURE_INIT();
|
||||
auto asio_socket = p3::to_object<socket<Protocol>>(accepted_socket);
|
||||
future->template on_resolve<NOARG>(boost::bind(
|
||||
&acceptor::handler, this, _1, asio_socket, cb, args));
|
||||
acceptor_.async_accept(asio_socket->get_socket(), STRAND_RESOLVE(ASYNC_HANDLER_SINGLE_ARG));
|
||||
FUTURE_RETURN();
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int Acceptor::cancel(void);
|
||||
* Cancel all asynchronous operations on this acceptor. */
|
||||
template <typename Protocol>
|
||||
P3_METHOD(acceptor<Protocol>, cancel)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
RETVAL_EC(acceptor_.cancel(ec));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int Acceptor::close(void);
|
||||
* Stop the acceptor. */
|
||||
template <typename Protocol>
|
||||
P3_METHOD(acceptor<Protocol>, close)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
RETVAL_EC(acceptor_.close(ec));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
template <typename Protocol>
|
||||
zend_class_entry* acceptor<Protocol>::class_entry;
|
||||
|
||||
template <typename Protocol>
|
||||
zend_object_handlers acceptor<Protocol>::handlers;
|
||||
|
||||
template class acceptor<tcp>;
|
||||
template class acceptor<unix>;
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
* php-asio/acceptor.hpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.hpp"
|
||||
#include "base.hpp"
|
||||
#include "socket.hpp"
|
||||
|
||||
namespace asio
|
||||
{
|
||||
/// Wrapper for Boost.Asio stream socket acceptor.
|
||||
/// Provide TCP services.
|
||||
template <typename Protocol>
|
||||
class acceptor : public base
|
||||
{
|
||||
/// Boost.Asio acceptor instance.
|
||||
typename Protocol::acceptor acceptor_;
|
||||
|
||||
/// Accept handler.
|
||||
zval* handler(const boost::system::error_code& error,
|
||||
socket<Protocol>* socket, zval* callback, zval* argument);
|
||||
|
||||
public:
|
||||
/// Constructor.
|
||||
explicit acceptor(
|
||||
boost::asio::io_service& io_service
|
||||
) : base(io_service), acceptor_(io_service) {}
|
||||
|
||||
P3_METHOD_DECLARE(open);
|
||||
|
||||
P3_METHOD_DECLARE(assign);
|
||||
|
||||
P3_METHOD_DECLARE(bind);
|
||||
|
||||
P3_METHOD_DECLARE(listen);
|
||||
|
||||
P3_METHOD_DECLARE(accept);
|
||||
|
||||
P3_METHOD_DECLARE(cancel);
|
||||
|
||||
P3_METHOD_DECLARE(close);
|
||||
|
||||
PHP_ASIO_CE_DECLARE();
|
||||
};
|
||||
|
||||
using tcp_acceptor = acceptor<tcp>;
|
||||
using unix_acceptor = acceptor<unix>;
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* php-asio/base.hpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef ZTS
|
||||
#include <atomic>
|
||||
#define HANDLER_COUNT_TYPE std::atomic<unsigned short>
|
||||
#else
|
||||
#define HANDLER_COUNT_TYPE unsigned short
|
||||
#endif // ZTS
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
namespace asio
|
||||
{
|
||||
/// A base class for all I/O objects.
|
||||
class base
|
||||
{
|
||||
protected:
|
||||
/// IO service of this object.
|
||||
boost::asio::io_service& io_service_;
|
||||
|
||||
/// Count of pending async handlers.
|
||||
HANDLER_COUNT_TYPE handler_count_;
|
||||
|
||||
/// Constructor.
|
||||
explicit base(boost::asio::io_service& io_service) : io_service_(io_service) {}
|
||||
|
||||
public:
|
||||
/// Deleted default constructor.
|
||||
base() = delete;
|
||||
|
||||
/// Default destructor.
|
||||
~base() = default;
|
||||
|
||||
/// Deleted copy constructor.
|
||||
base(const base&) = delete;
|
||||
|
||||
/// Deleted copy assignment operator.
|
||||
base& operator=(const base&) = delete;
|
||||
|
||||
/// Increment handler count.
|
||||
unsigned short handler_count_inc()
|
||||
{
|
||||
return ++handler_count_;
|
||||
}
|
||||
|
||||
/// Decrement handler count.
|
||||
unsigned short handler_count_dec()
|
||||
{
|
||||
return --handler_count_;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
/**
|
||||
* php-asio/common.hpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "p3.hpp"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
// Compatible with PHP 7.3
|
||||
#if PHP_VERSION_ID < 70300
|
||||
#define GC_ADDREF(p) ++GC_REFCOUNT(p)
|
||||
#define GC_DELREF(p) --GC_REFCOUNT(p)
|
||||
#endif
|
||||
|
||||
#if PHP_VERSION_ID < 70115 || (PHP_VERSION_ID > 70200 && PHP_VERSION_ID < 70203)
|
||||
|
||||
#if PHP_VERSION_ID < 70100
|
||||
#define _zend_wrong_parameters_count_error(throw, ...) zend_wrong_paramers_count_error(__VA_ARGS__)
|
||||
#elif PHP_VERSION_ID < 70200
|
||||
#define _zend_wrong_parameters_count_error(throw, ...) zend_wrong_parameters_count_error(__VA_ARGS__)
|
||||
#else
|
||||
#define _zend_wrong_parameters_count_error(...) zend_wrong_parameters_count_error(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
// See https://externals.io/message/101364 for details.
|
||||
#undef ZEND_PARSE_PARAMETERS_START_EX
|
||||
#define ZEND_PARSE_PARAMETERS_START_EX(flags, min_num_args, max_num_args) do { \
|
||||
const int _flags = (flags); \
|
||||
int _min_num_args = (min_num_args); \
|
||||
int _max_num_args = (max_num_args); \
|
||||
int _num_args = EX_NUM_ARGS(); \
|
||||
int _i; \
|
||||
zval *_real_arg, *_arg = NULL; \
|
||||
zend_expected_type _expected_type = Z_EXPECTED_LONG; \
|
||||
char *_error = NULL; \
|
||||
zend_bool _dummy; \
|
||||
zend_bool _optional = 0; \
|
||||
int error_code = ZPP_ERROR_OK; \
|
||||
((void)_i); \
|
||||
((void)_real_arg); \
|
||||
((void)_arg); \
|
||||
((void)_expected_type); \
|
||||
((void)_error); \
|
||||
((void)_dummy); \
|
||||
((void)_optional); \
|
||||
do { \
|
||||
if (UNEXPECTED(_num_args < _min_num_args) || \
|
||||
(UNEXPECTED(_num_args > _max_num_args) && \
|
||||
EXPECTED(_max_num_args >= 0))) { \
|
||||
if (!(_flags & ZEND_PARSE_PARAMS_QUIET)) { \
|
||||
_zend_wrong_parameters_count_error(_flags & ZEND_PARSE_PARAMS_THROW, \
|
||||
_num_args, _min_num_args, _max_num_args); \
|
||||
} \
|
||||
error_code = ZPP_ERROR_FAILURE; \
|
||||
break; \
|
||||
} \
|
||||
_i = 0; \
|
||||
_real_arg = ZEND_CALL_ARG(execute_data, 0);
|
||||
|
||||
#endif
|
||||
|
||||
#define PHP_ASIO_OBJ_ALLOC(obj, type, arg) \
|
||||
auto obj = p3::alloc_object<type>(type::class_entry, [this](type* ptr) { \
|
||||
new(ptr) type(arg); \
|
||||
})
|
||||
|
||||
#define PHP_ASIO_OBJ_DTOR(obj) GC_DELREF(p3::to_zend_object(obj))
|
||||
|
||||
#define ZVAL_ALLOC(name) name = static_cast<zval*>(emalloc(sizeof(zval)))
|
||||
#define ZVAL_PTR_INIT(name) auto ZVAL_ALLOC(name)
|
||||
#define ZVAL_INIT(name) zval name = {{ 0 }}
|
||||
|
||||
#define RETVAL_EC(ec) RETVAL_LONG(static_cast<zend_long>((ec).value()))
|
||||
|
||||
#define PHP_ASIO_ERROR(type, msg) php_error_docref(nullptr, type, msg)
|
||||
|
||||
#define PHP_ASIO_CE_DECLARE() \
|
||||
static zend_class_entry* class_entry; \
|
||||
static zend_object_handlers handlers
|
||||
#define PHP_ASIO_CE_DEFINE(type) \
|
||||
zend_class_entry* type::class_entry; \
|
||||
zend_object_handlers type::handlers
|
||||
|
||||
// Handlers with one argument is treated as ones with two arguments.
|
||||
#define NOARG int
|
||||
#define ASYNC_HANDLER_SINGLE_ARG \
|
||||
std::function<void(const boost::system::error_code&)>(boost::bind( \
|
||||
&future::resolve<std::remove_pointer_t<decltype(this)>, NOARG>, \
|
||||
future, boost::asio::placeholders::error, 0))
|
||||
#define ASYNC_HANDLER_DOUBLE_ARG(obj_type) \
|
||||
std::function<void(const boost::system::error_code&, obj_type)>(boost::bind( \
|
||||
&future::resolve<std::remove_pointer_t<decltype(this)>, obj_type>, \
|
||||
future, boost::asio::placeholders::error, _2))
|
||||
|
||||
// If you don't need coroutines, you can turn it off for better performance.
|
||||
#ifdef ENABLE_COROUTINE
|
||||
#define CORO_REGISTER(value) future::coroutine(value)
|
||||
#define FUTURE_INIT() \
|
||||
zend_object* obj; \
|
||||
auto future = future::add(this, obj);
|
||||
#define FUTURE_RETURN() RETVAL_OBJ(obj)
|
||||
#define INIT_RETVAL() \
|
||||
ZVAL_PTR_INIT(retval); \
|
||||
ZVAL_NULL(retval)
|
||||
#define PASS_RETVAL retval
|
||||
#else
|
||||
#define CORO_REGISTER(value)
|
||||
#define FUTURE_INIT() auto future = future::add(this)
|
||||
#define FUTURE_RETURN()
|
||||
#define INIT_RETVAL() ZVAL_INIT(retval)
|
||||
#define PASS_RETVAL &retval
|
||||
#endif // ENABLE_COROUTINE
|
||||
|
||||
#define CORO_RETURN_NULL() \
|
||||
ZVAL_PTR_INIT(retval); \
|
||||
ZVAL_NULL(retval); \
|
||||
return retval
|
||||
#define CORO_RETURN(type, value) \
|
||||
ZVAL_PTR_INIT(retval); \
|
||||
type(retval, value); \
|
||||
return retval
|
||||
|
||||
// If you don't need multi-threading support for I/O objects, you can disable Strand for better performance.
|
||||
#if defined(ENABLE_STRAND) && !defined(ZTS)
|
||||
#undef ENABLE_STRAND
|
||||
#endif
|
||||
#ifdef ENABLE_STRAND
|
||||
#define STRAND_UNWRAP() \
|
||||
callback = future->handle_strand(callback); \
|
||||
if (future->get_strand()) \
|
||||
ZVAL_COPY_VALUE(cb, callback); \
|
||||
else
|
||||
#define STRAND_RESOLVE(arg) future->get_strand() ? future->get_strand()->wrap(arg) : arg
|
||||
#else
|
||||
#define STRAND_UNWRAP()
|
||||
#define STRAND_RESOLVE(arg) arg
|
||||
#endif // ENABLE_STRAND
|
||||
|
||||
#define PHP_ASIO_INVOKE_CALLBACK_START(argc) \
|
||||
const auto _argc = argc; \
|
||||
if (callback && zend_is_callable(callback, 0, nullptr)) { \
|
||||
zval arguments[_argc] = {{{ 0 }}}; \
|
||||
ZVAL_OBJ(&arguments[0], p3::to_zend_object(this));
|
||||
|
||||
#define PHP_ASIO_INVOKE_CALLBACK() \
|
||||
ZVAL_LONG(&arguments[_argc - 2], static_cast<zend_long>(error.value())); \
|
||||
if (argument) \
|
||||
ZVAL_COPY(&arguments[_argc - 1], argument); \
|
||||
else \
|
||||
ZVAL_NULL(&arguments[_argc - 1]); \
|
||||
INIT_RETVAL(); \
|
||||
call_user_function(CG(function_table), nullptr, callback, PASS_RETVAL, _argc, arguments)
|
||||
|
||||
#define PHP_ASIO_INVOKE_CALLBACK_END() \
|
||||
CORO_REGISTER(retval); \
|
||||
zval_ptr_dtor(callback); \
|
||||
efree(callback); \
|
||||
} \
|
||||
if (argument) { \
|
||||
zval_ptr_dtor(argument); \
|
||||
efree(argument); \
|
||||
}
|
||||
|
||||
#define PHP_ASIO_INC_HANDLER_COUNT() \
|
||||
if (handler_count_inc() == 1) \
|
||||
GC_ADDREF(p3::to_zend_object(this))
|
||||
|
||||
#define PHP_ASIO_DEC_HANDLER_COUNT() \
|
||||
if (handler_count_dec() == 0) \
|
||||
PHP_ASIO_OBJ_DTOR(this)
|
||||
|
||||
// To ensure the callback and the extra arg is still alive when async operation resolves,
|
||||
// We shall allocate new memory on the heap.
|
||||
#define PHP_ASIO_FUTURE_INIT() \
|
||||
PHP_ASIO_INC_HANDLER_COUNT(); \
|
||||
FUTURE_INIT(); \
|
||||
zval* cb = nullptr; \
|
||||
if (callback) { \
|
||||
ZVAL_ALLOC(cb); \
|
||||
STRAND_UNWRAP() \
|
||||
ZVAL_COPY(cb, callback); \
|
||||
} \
|
||||
zval* args = nullptr; \
|
||||
if (argument) { \
|
||||
ZVAL_ALLOC(args); \
|
||||
ZVAL_COPY(args, argument); \
|
||||
}
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
using boost::asio::ip::udp;
|
||||
using unix = boost::asio::local::stream_protocol;
|
||||
using udg = boost::asio::local::datagram_protocol;
|
|
@ -0,0 +1,133 @@
|
|||
/**
|
||||
* php-asio/future.cpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#include "future.hpp"
|
||||
#include "generator.hpp"
|
||||
#include "timer.hpp"
|
||||
#include "signal.hpp"
|
||||
#include "resolver.hpp"
|
||||
#include "socket.hpp"
|
||||
#include "acceptor.hpp"
|
||||
#include "stream_descriptor.hpp"
|
||||
|
||||
namespace asio
|
||||
{
|
||||
future* future::add(
|
||||
void* io_object
|
||||
#ifdef ENABLE_COROUTINE
|
||||
, zend_object*& obj)
|
||||
{
|
||||
obj = p3::alloc_object<future>(class_entry,
|
||||
[io_object](future* ptr) {
|
||||
new(ptr) future(io_object);
|
||||
});
|
||||
GC_ADDREF(obj);
|
||||
return p3::to_object<future>(obj);
|
||||
#else
|
||||
) {
|
||||
return new future(io_object);
|
||||
#endif // ENABLE_COROUTINE
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void future::on_resolve(const ASYNC_CALLBACK(T)&& callback)
|
||||
{
|
||||
callback_ = new ASYNC_CALLBACK(T)(std::move(callback));
|
||||
}
|
||||
|
||||
template <typename V, typename T>
|
||||
void future::resolve(const boost::system::error_code& ec, T arg)
|
||||
{
|
||||
auto callback = static_cast<ASYNC_CALLBACK(T)*>(callback_);
|
||||
send_ = (*callback)(ec, arg);
|
||||
#ifdef ENABLE_COROUTINE
|
||||
if (yield_) {
|
||||
last_error_ = static_cast<int64_t>(ec.value());
|
||||
generator_send(reinterpret_cast<zend_generator*>(Z_OBJ_P(generator_)), send_);
|
||||
coroutine(generator_);
|
||||
}
|
||||
#endif // ENABLE_COROUTINE
|
||||
zval_ptr_dtor(send_);
|
||||
efree(send_);
|
||||
delete callback;
|
||||
auto io_object = static_cast<V*>(io_object_);
|
||||
if (io_object->handler_count_dec() == 0)
|
||||
PHP_ASIO_OBJ_DTOR(io_object);
|
||||
#ifdef ENABLE_STRAND
|
||||
if (strand_ && strand_->handler_count_dec() == 0)
|
||||
PHP_ASIO_OBJ_DTOR(strand_);
|
||||
#endif // ENABLE_STRAND
|
||||
#ifdef ENABLE_COROUTINE
|
||||
PHP_ASIO_OBJ_DTOR(this);
|
||||
#else
|
||||
delete this;
|
||||
#endif // ENABLE_COROUTINE
|
||||
}
|
||||
|
||||
#ifdef ENABLE_STRAND
|
||||
zval* future::handle_strand(zval* callable)
|
||||
{
|
||||
if (callable && Z_TYPE_P(callable) == IS_OBJECT &&
|
||||
instanceof_function(Z_OBJCE_P(callable), wrapped_handler::class_entry)) {
|
||||
const auto wrapped_hander = p3::to_object<wrapped_handler>(callable);
|
||||
strand_ = wrapped_hander->strand_;
|
||||
return wrapped_hander->callback_;
|
||||
}
|
||||
return callable;
|
||||
}
|
||||
#endif // ENABLE_STRAND
|
||||
|
||||
#ifdef ENABLE_COROUTINE
|
||||
void future::coroutine(zval* value)
|
||||
{
|
||||
if (Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), zend_ce_generator)) {
|
||||
const auto generator = reinterpret_cast<zend_generator*>(Z_OBJ_P(value));
|
||||
if (generator_valid(generator)) {
|
||||
const auto ret = generator_current(generator);
|
||||
if (ret && instanceof_function(Z_OBJCE_P(ret), class_entry)) {
|
||||
const auto future = p3::to_object<asio::future>(ret);
|
||||
future->generator_ = value;
|
||||
future->yield_ = true;
|
||||
return;
|
||||
}
|
||||
PHP_ASIO_ERROR(E_WARNING, "Invalid yield value. Future expected.");
|
||||
}
|
||||
}
|
||||
zval_ptr_dtor(value);
|
||||
efree(value);
|
||||
}
|
||||
|
||||
P3_METHOD(future, lastError)
|
||||
{
|
||||
RETVAL_LONG(last_error_)
|
||||
}
|
||||
|
||||
thread_local int64_t future::last_error_ = 0;
|
||||
|
||||
PHP_ASIO_CE_DEFINE(future);
|
||||
#endif // ENABLE_COROUTINE
|
||||
|
||||
template void future::on_resolve(const ASYNC_CALLBACK(int)&&);
|
||||
template void future::on_resolve(const ASYNC_CALLBACK(size_t)&&);
|
||||
template void future::on_resolve(const ASYNC_CALLBACK(tcp::resolver::iterator)&&);
|
||||
template void future::on_resolve(const ASYNC_CALLBACK(udp::resolver::iterator)&&);
|
||||
|
||||
template void future::resolve<timer>(const boost::system::error_code&, int);
|
||||
template void future::resolve<signal>(const boost::system::error_code&, int);
|
||||
template void future::resolve<resolver<tcp>>(
|
||||
const boost::system::error_code&, tcp::resolver::iterator);
|
||||
template void future::resolve<resolver<udp>>(
|
||||
const boost::system::error_code&, udp::resolver::iterator);
|
||||
template void future::resolve<socket<tcp>>(const boost::system::error_code&, int);
|
||||
template void future::resolve<socket<tcp>>(const boost::system::error_code&, size_t);
|
||||
template void future::resolve<socket<unix>>(const boost::system::error_code&, int);
|
||||
template void future::resolve<socket<unix>>(const boost::system::error_code&, size_t);
|
||||
template void future::resolve<socket<udp>>(const boost::system::error_code&, size_t);
|
||||
template void future::resolve<socket<udg>>(const boost::system::error_code&, size_t);
|
||||
template void future::resolve<acceptor<tcp>>(const boost::system::error_code&, int);
|
||||
template void future::resolve<acceptor<unix>>(const boost::system::error_code&, int);
|
||||
template void future::resolve<stream_descriptor>(const boost::system::error_code&, size_t);
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/**
|
||||
* php-asio/future.hpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.hpp"
|
||||
#include "wrapped_handler.hpp"
|
||||
|
||||
#define ASYNC_CALLBACK(type) std::function<zval*(const boost::system::error_code&, type)>
|
||||
|
||||
namespace asio
|
||||
{
|
||||
/// Class Future.
|
||||
/// When an asynchronous operation completes, its Future will be resolved.
|
||||
/// And the corresponding coroutine will resume (if Future was yielded by a Generator).
|
||||
class future
|
||||
{
|
||||
/// Handler callback of the async operation.
|
||||
void* callback_ = nullptr;
|
||||
|
||||
/// Pointer to the I/O object which created this Future.
|
||||
void* io_object_;
|
||||
|
||||
#ifdef ENABLE_COROUTINE
|
||||
/// Last error code emitted by yielded async operations of this thread.
|
||||
static thread_local int64_t last_error_;
|
||||
|
||||
/// Generator instance which yielded this Future.
|
||||
zval* generator_ = nullptr;
|
||||
|
||||
/// Whether this future is yielded by a Generator.
|
||||
bool yield_ = false;
|
||||
#endif // ENABLE_COROUTINE
|
||||
|
||||
/// Value which will be sent back to the Generator.
|
||||
zval* send_ = nullptr;
|
||||
|
||||
#ifdef ENABLE_STRAND
|
||||
/// Pointer to Strand which wrapped this Future.
|
||||
strand* strand_ = nullptr;
|
||||
#endif // ENABLE_STRAND
|
||||
|
||||
/// Constructor.
|
||||
explicit future(void* io_object) : io_object_(io_object) {}
|
||||
|
||||
public:
|
||||
/// Create a new Future instance.
|
||||
static future* add(
|
||||
void* io_object
|
||||
#ifdef ENABLE_COROUTINE
|
||||
, zend_object*& obj
|
||||
#endif // ENABLE_COROUTINE
|
||||
);
|
||||
|
||||
/// Deleted default constructor.
|
||||
explicit future() = delete;
|
||||
|
||||
/// Deleted copy constructor.
|
||||
future(const future&) = delete;
|
||||
|
||||
/// Deleted copy assignment operator.
|
||||
future& operator=(const future&) = delete;
|
||||
|
||||
/// Set future resolver callback.
|
||||
template <typename T>
|
||||
void on_resolve(const ASYNC_CALLBACK(T)&& callback);
|
||||
|
||||
/// Resolve the Future upon operation completion.
|
||||
template <typename V, typename T>
|
||||
void resolve(const boost::system::error_code& ec, T arg);
|
||||
|
||||
#ifdef ENABLE_STRAND
|
||||
zval* handle_strand(zval* callable);
|
||||
|
||||
/// Get the pointer to the strand which wrapped this Future.
|
||||
boost::asio::strand* get_strand() const
|
||||
{
|
||||
return strand_ ? strand_->implmentation() : nullptr;
|
||||
}
|
||||
#endif // ENABLE_STRAND
|
||||
|
||||
#ifdef ENABLE_COROUTINE
|
||||
/// Attempt to start/resume a coroutine with a PHP Generator.
|
||||
static void coroutine(zval* value);
|
||||
|
||||
/// Get last error emitted by handler callback within yielded Future.
|
||||
static P3_METHOD_DECLARE(lastError);
|
||||
|
||||
PHP_ASIO_CE_DECLARE();
|
||||
#endif // ENABLE_COROUTINE
|
||||
};
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
* php-asio/generator.hpp
|
||||
*
|
||||
* Several functions copied from zend_generators.c,
|
||||
* which provides PHP's generator functionalities.
|
||||
* Used by Future when coroutine is enabled.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
#include <zend_generators.h>
|
||||
|
||||
#ifdef ENABLE_COROUTINE
|
||||
namespace asio
|
||||
{
|
||||
/// Ensure that the generator is initialized.
|
||||
inline void zend_generator_ensure_initialized(zend_generator* generator)
|
||||
{
|
||||
if (UNEXPECTED(Z_TYPE(generator->value) == IS_UNDEF) &&
|
||||
EXPECTED(generator->execute_data) &&
|
||||
EXPECTED(generator->node.parent == nullptr)) {
|
||||
generator->flags |= ZEND_GENERATOR_DO_INIT;
|
||||
zend_generator_resume(generator);
|
||||
generator->flags &= ~ZEND_GENERATOR_DO_INIT;
|
||||
generator->flags |= ZEND_GENERATOR_AT_FIRST_YIELD;
|
||||
}
|
||||
}
|
||||
|
||||
/// Check whether the generator is valid.
|
||||
inline bool generator_valid(zend_generator* generator)
|
||||
{
|
||||
zend_generator_ensure_initialized(generator);
|
||||
zend_generator_get_current(generator);
|
||||
return EXPECTED(generator->execute_data != nullptr);
|
||||
}
|
||||
|
||||
/// Get current yield value of the generator.
|
||||
inline zval* generator_current(zend_generator* generator)
|
||||
{
|
||||
zend_generator_ensure_initialized(generator);
|
||||
const auto root = zend_generator_get_current(generator);
|
||||
if (EXPECTED(generator->execute_data != NULL && Z_TYPE(root->value) != IS_UNDEF))
|
||||
return &root->value;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// Send a value to the generator.
|
||||
inline void generator_send(zend_generator* generator, zval* value)
|
||||
{
|
||||
zend_generator_ensure_initialized(generator);
|
||||
if (UNEXPECTED(!generator->execute_data))
|
||||
return;
|
||||
const auto root = zend_generator_get_current(generator);
|
||||
if (root->send_target)
|
||||
ZVAL_COPY(root->send_target, value);
|
||||
zend_generator_resume(generator);
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_COROUTINE
|
|
@ -0,0 +1,178 @@
|
|||
/**
|
||||
* php-asio/io.hpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
#define PHP_ASIO_INET_ASSIGN(obj, p) \
|
||||
zend_bool inet6; \
|
||||
zval* fd; \
|
||||
ZEND_PARSE_PARAMETERS_START(2, 2) \
|
||||
Z_PARAM_BOOL(inet6) \
|
||||
Z_PARAM_ZVAL(fd) \
|
||||
ZEND_PARSE_PARAMETERS_END(); \
|
||||
boost::system::error_code ec; \
|
||||
const auto protocol = inet6 ? p::v6() : p::v4(); \
|
||||
if (UNEXPECTED(Z_TYPE_P(fd) == IS_LONG)) \
|
||||
(obj).assign(protocol, Z_LVAL_P(fd), ec); \
|
||||
else \
|
||||
(obj).assign(protocol, resource_to_fd(fd), ec); \
|
||||
RETVAL_EC(ec)
|
||||
|
||||
#define PHP_ASIO_LOCAL_ASSIGN(obj, p) \
|
||||
zval* fd; \
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1) \
|
||||
Z_PARAM_ZVAL(fd) \
|
||||
ZEND_PARSE_PARAMETERS_END(); \
|
||||
boost::system::error_code ec; \
|
||||
if (UNEXPECTED(Z_TYPE_P(fd) == IS_LONG)) \
|
||||
(obj).assign(p(), Z_LVAL_P(fd), ec); \
|
||||
else \
|
||||
(obj).assign(p(), resource_to_fd(fd), ec); \
|
||||
RETVAL_EC(ec)
|
||||
|
||||
#if defined(ENABLE_NULL_BUFFERS) && BOOST_VERSION >= 106600
|
||||
// Null buffers are deprecated as of Boost 1.66.
|
||||
// Method `async_wait()` on sockets and stream descriptors is preferred.
|
||||
#undef ENABLE_NULL_BUFFERS
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_NULL_BUFFERS
|
||||
#define PHP_ASIO_BUFFER_LEN_VALIDATE() \
|
||||
if (UNEXPECTED(length < 0)) { \
|
||||
PHP_ASIO_ERROR(E_WARNING, "Non-negative integer expected."); \
|
||||
RETURN_NULL(); \
|
||||
}
|
||||
#define PHP_ASIO_EMPTY_READ_BUFFER length == 0 ? ZSTR_EMPTY_ALLOC() :
|
||||
#define PHP_ASIO_ON_READABLE(obj) \
|
||||
if (length == 0) \
|
||||
if (read_some) \
|
||||
(obj).async_read_some(boost::asio::null_buffers(), \
|
||||
STRAND_RESOLVE(ASYNC_HANDLER_DOUBLE_ARG(size_t))); \
|
||||
else \
|
||||
async_read(obj, boost::asio::null_buffers(), \
|
||||
STRAND_RESOLVE(ASYNC_HANDLER_DOUBLE_ARG(size_t))); \
|
||||
else
|
||||
#define PHP_ASIO_EMPTY_WRITE_BUFFER ZSTR_LEN(data) == 0 ? nullptr :
|
||||
#define PHP_ASIO_ON_WRITABLE(obj) \
|
||||
if (ZSTR_LEN(data) == 0) \
|
||||
if (write_some) \
|
||||
(obj).async_write_some(boost::asio::null_buffers(), \
|
||||
STRAND_RESOLVE(ASYNC_HANDLER_DOUBLE_ARG(size_t))); \
|
||||
else \
|
||||
async_write(obj, boost::asio::null_buffers(), \
|
||||
STRAND_RESOLVE(ASYNC_HANDLER_DOUBLE_ARG(size_t))); \
|
||||
else
|
||||
#else
|
||||
#define PHP_ASIO_BUFFER_LEN_VALIDATE() \
|
||||
if (UNEXPECTED(length <= 0)) { \
|
||||
PHP_ASIO_ERROR(E_WARNING, "Positive integer expected."); \
|
||||
RETURN_NULL(); \
|
||||
}
|
||||
#define PHP_ASIO_EMPTY_READ_BUFFER
|
||||
#define PHP_ASIO_ON_READABLE(obj)
|
||||
#define PHP_ASIO_EMPTY_WRITE_BUFFER
|
||||
#define PHP_ASIO_ON_WRITABLE(obj)
|
||||
#endif // ENABLE_NULL_BUFFERS
|
||||
|
||||
#define PHP_ASIO_READ(type, obj) \
|
||||
zend_long length; \
|
||||
zend_bool read_some = 1; \
|
||||
zval* callback = nullptr; \
|
||||
zval* argument = nullptr; \
|
||||
ZEND_PARSE_PARAMETERS_START(1, 4) \
|
||||
Z_PARAM_LONG(length) \
|
||||
Z_PARAM_OPTIONAL \
|
||||
Z_PARAM_BOOL(read_some) \
|
||||
Z_PARAM_ZVAL(callback) \
|
||||
Z_PARAM_ZVAL(argument) \
|
||||
ZEND_PARSE_PARAMETERS_END(); \
|
||||
PHP_ASIO_BUFFER_LEN_VALIDATE(); \
|
||||
auto buffer_container = PHP_ASIO_EMPTY_READ_BUFFER \
|
||||
zend_string_alloc(static_cast<size_t>(length), 0); \
|
||||
PHP_ASIO_FUTURE_INIT(); \
|
||||
future->template on_resolve<size_t>(boost::bind(&type::read_handler, \
|
||||
this, _1, _2, buffer_container, cb, args)); \
|
||||
PHP_ASIO_ON_READABLE(obj) \
|
||||
if (read_some) \
|
||||
(obj).async_read_some(mutable_buffer(buffer_container), \
|
||||
STRAND_RESOLVE(ASYNC_HANDLER_DOUBLE_ARG(size_t))); \
|
||||
else \
|
||||
async_read(obj, mutable_buffer(buffer_container), \
|
||||
STRAND_RESOLVE(ASYNC_HANDLER_DOUBLE_ARG(size_t))); \
|
||||
FUTURE_RETURN()
|
||||
|
||||
#define PHP_ASIO_WRITE(type, obj) \
|
||||
zend_string* data; \
|
||||
zend_bool write_some = 0; \
|
||||
zval* callback = nullptr; \
|
||||
zval* argument = nullptr; \
|
||||
ZEND_PARSE_PARAMETERS_START(1, 4) \
|
||||
Z_PARAM_STR(data) \
|
||||
Z_PARAM_OPTIONAL \
|
||||
Z_PARAM_BOOL(write_some) \
|
||||
Z_PARAM_ZVAL(callback) \
|
||||
Z_PARAM_ZVAL(argument) \
|
||||
ZEND_PARSE_PARAMETERS_END(); \
|
||||
auto buffer_container = PHP_ASIO_EMPTY_WRITE_BUFFER \
|
||||
zend_string_copy(data); \
|
||||
PHP_ASIO_FUTURE_INIT(); \
|
||||
future->template on_resolve<size_t>(boost::bind(&type::write_handler, \
|
||||
this, _1, _2, buffer_container, cb, args)); \
|
||||
PHP_ASIO_ON_WRITABLE(obj) \
|
||||
if (write_some) \
|
||||
(obj).async_write_some(mutable_buffer(buffer_container), \
|
||||
STRAND_RESOLVE(ASYNC_HANDLER_DOUBLE_ARG(size_t))); \
|
||||
else \
|
||||
async_write(obj, mutable_buffer(buffer_container), \
|
||||
STRAND_RESOLVE(ASYNC_HANDLER_DOUBLE_ARG(size_t))); \
|
||||
FUTURE_RETURN()
|
||||
|
||||
namespace asio
|
||||
{
|
||||
/// Wrap a zend string into const buffer.
|
||||
inline auto const_buffer(const zend_string* str)
|
||||
{
|
||||
return boost::asio::const_buffers_1(boost::asio::const_buffer(
|
||||
ZSTR_LEN(str) ? ZSTR_VAL(str) : nullptr, ZSTR_LEN(str)
|
||||
));
|
||||
}
|
||||
|
||||
/// Wrap a zend string into mutable buffer.
|
||||
inline auto mutable_buffer(zend_string* str)
|
||||
{
|
||||
return boost::asio::mutable_buffers_1(boost::asio::mutable_buffer(
|
||||
ZSTR_LEN(str) ? ZSTR_VAL(str) : nullptr, ZSTR_LEN(str)
|
||||
));
|
||||
}
|
||||
|
||||
/// Extract a valid poll fd from a PHP resource.
|
||||
inline int resource_to_fd(zval* resource)
|
||||
{
|
||||
// The following code is copied from php-uv.
|
||||
// See https://github.com/bwoebi/php-uv/blob/master/php_uv.c#L401
|
||||
if (UNEXPECTED(Z_TYPE_P(resource) != IS_RESOURCE))
|
||||
return -1;
|
||||
const auto stream = static_cast<php_stream*>(
|
||||
zend_fetch_resource_ex(resource, nullptr, php_file_le_stream()));
|
||||
if (stream == nullptr)
|
||||
return -1;
|
||||
if (stream->wrapper && !strcmp(stream->wrapper->wops->label, "PHP") &&
|
||||
(!stream->orig_path ||
|
||||
strncmp(stream->orig_path, "php://std", sizeof "php://std" - 1) &&
|
||||
strncmp(stream->orig_path, "php://fd", sizeof "php://fd" - 1)))
|
||||
return -1;
|
||||
auto fd = -1;
|
||||
if (php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL,
|
||||
reinterpret_cast<void**>(&fd), 1) == SUCCESS && fd >= 0) {
|
||||
if (stream->wrapper && !strcmp(stream->wrapper->wops->label, "plainfile"))
|
||||
return -1;
|
||||
return fd;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
/**
|
||||
* php-asio/p3.hpp
|
||||
*
|
||||
* This header is a simple helper for wrapping C++ classes,
|
||||
* which is borrowed from https://github.com/phplang/p3.
|
||||
* The casting/cloning/comparing functionalities are removed,
|
||||
* because they are not needed by php-asio.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include <php.h>
|
||||
#include <zend_exceptions.h>
|
||||
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
|
||||
#define P3_METHOD_DECLARE(name) \
|
||||
void zim_##name(INTERNAL_FUNCTION_PARAMETERS)
|
||||
|
||||
#define P3_METHOD(cls, name) \
|
||||
void cls::zim_##name(INTERNAL_FUNCTION_PARAMETERS)
|
||||
|
||||
#define P3_ME(cls, name, meth, arginfo, flags) \
|
||||
ZEND_FENTRY(name, [](INTERNAL_FUNCTION_PARAMETERS) { \
|
||||
::p3::to_object<cls>(getThis())->zim_##meth(INTERNAL_FUNCTION_PARAM_PASSTHRU); \
|
||||
}, arginfo, flags)
|
||||
|
||||
#define P3_ME_D(cls, meth, arginfo, flags) \
|
||||
P3_ME(cls, meth, meth, arginfo, flags)
|
||||
|
||||
#define P3_STATIC_ME(cls, meth, arginfo, flags) \
|
||||
ZEND_FENTRY(meth, &cls::zim_##meth, arginfo, flags | ZEND_ACC_STATIC)
|
||||
|
||||
#define P3_ABSTRACT_ME(name, arginfo) \
|
||||
PHP_ABSTRACT_ME("", name, arginfo)
|
||||
|
||||
namespace p3 {
|
||||
/// Native object to Zend object.
|
||||
template <class T>
|
||||
zend_object* to_zend_object(T* obj)
|
||||
{
|
||||
return reinterpret_cast<zend_object*>(obj + 1);
|
||||
}
|
||||
|
||||
/// Zend object to native object.
|
||||
template <class T>
|
||||
T* to_object(zend_object* obj)
|
||||
{
|
||||
return reinterpret_cast<T*>(obj) - 1;
|
||||
}
|
||||
|
||||
/// Zval to native object.
|
||||
template <class T>
|
||||
T* to_object(zval* obj)
|
||||
{
|
||||
return reinterpret_cast<T*>(Z_OBJ_P(obj)) - 1;
|
||||
}
|
||||
|
||||
/// Allocate new object.
|
||||
template <class T, typename InitFunc>
|
||||
zend_object* alloc_object(zend_class_entry* ce, InitFunc init)
|
||||
{
|
||||
auto ptr = reinterpret_cast<T*>(ecalloc(1, sizeof(T) +
|
||||
sizeof(zend_object) + zend_object_properties_size(ce)));
|
||||
init(ptr);
|
||||
auto zobj = to_zend_object(ptr);
|
||||
zend_object_std_init(zobj, ce);
|
||||
zobj->handlers = &T::handlers;
|
||||
return zobj;
|
||||
}
|
||||
|
||||
/// Allocate new object with default constructor.
|
||||
template <class T>
|
||||
typename std::enable_if<std::is_constructible<T>::value, zend_object*>::type
|
||||
create_object(zend_class_entry* ce)
|
||||
{
|
||||
return alloc_object<T>(ce, [](T* ptr) {
|
||||
new(ptr) T();
|
||||
});
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename std::enable_if<!std::is_constructible<T>::value, zend_object*>::type
|
||||
create_object(zend_class_entry* ce)
|
||||
{
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// Destroy an object.
|
||||
template <class T>
|
||||
void dtor_object(zend_object *obj)
|
||||
{
|
||||
zend_object_std_dtor(obj);
|
||||
to_object<T>(obj)->~T();
|
||||
}
|
||||
|
||||
/// Fail to create object if there's no default constructor.
|
||||
inline zend_object* create_object_fail(zend_class_entry* ce) {
|
||||
php_error_docref(nullptr, E_ERROR,
|
||||
"%s should not be directly instantiated.", ZSTR_VAL(ce->name));
|
||||
return zend_objects_new(ce);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
zend_class_entry* class_init(const char* name, const zend_function_entry* methods)
|
||||
{
|
||||
zend_class_entry ce;
|
||||
INIT_CLASS_ENTRY_EX(ce, name, strlen(name), methods);
|
||||
T::class_entry = zend_register_internal_class(&ce);
|
||||
T::class_entry->create_object =
|
||||
std::is_constructible<T>::value ? create_object<T> : create_object_fail;
|
||||
memcpy(&T::handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
|
||||
T::handlers.offset = sizeof(T);
|
||||
T::handlers.free_obj = dtor_object<T>;
|
||||
T::handlers.clone_obj = nullptr;
|
||||
return T::class_entry;
|
||||
}
|
||||
|
||||
inline zend_class_entry* interface_init(const char* name, const zend_function_entry* methods)
|
||||
{
|
||||
zend_class_entry ce;
|
||||
INIT_CLASS_ENTRY_EX(ce, name, strlen(name), methods);
|
||||
return zend_register_internal_interface(&ce);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,519 @@
|
|||
/**
|
||||
* php-asio/php_asio.cpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#include <php.h>
|
||||
#include <ext/standard/info.h>
|
||||
|
||||
#include "php_asio.hpp"
|
||||
#include "p3.hpp"
|
||||
#include "service.hpp"
|
||||
#include "wrapped_handler.hpp"
|
||||
|
||||
/* {{{ arg_info */
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(service_run_arginfo, 0)
|
||||
ZEND_ARG_INFO(1, ec)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(service_run_one_arginfo, 0)
|
||||
ZEND_ARG_INFO(1, ec)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(service_poll_arginfo, 0)
|
||||
ZEND_ARG_INFO(1, ec)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(service_poll_one_arginfo, 0)
|
||||
ZEND_ARG_INFO(1, ec)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(service_dispatch_arginfo, 0)
|
||||
ZEND_ARG_CALLABLE_INFO(0, callback, 0)
|
||||
ZEND_ARG_INFO(0, argument)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#ifdef ENABLE_STRAND
|
||||
ZEND_BEGIN_ARG_INFO(strand_dispatch_arginfo, 0)
|
||||
ZEND_ARG_CALLABLE_INFO(0, callback, 0)
|
||||
ZEND_ARG_INFO(0, argument)
|
||||
ZEND_END_ARG_INFO()
|
||||
#endif // ENABLE_STRAND
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(strand_wrap_arginfo, 0)
|
||||
ZEND_ARG_CALLABLE_INFO(0, callback, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(timer_expires_from_now_arginfo, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, duration, IS_LONG, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(timer_expires_at_arginfo, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, timestamp, IS_LONG, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(timer_wait_arginfo, 0)
|
||||
ZEND_ARG_CALLABLE_INFO(0, callback, 0)
|
||||
ZEND_ARG_INFO(0, argument)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(signal_add_arginfo, 0)
|
||||
ZEND_ARG_VARIADIC_INFO(0, sig_num)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(signal_remove_arginfo, 0)
|
||||
ZEND_ARG_VARIADIC_INFO(0, sig_num)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(signal_wait_arginfo, 0)
|
||||
ZEND_ARG_CALLABLE_INFO(0, callback, 0)
|
||||
ZEND_ARG_INFO(0, argument)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(resolver_resolve_arginfo, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, host, IS_STRING, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, service, IS_STRING, 0)
|
||||
ZEND_ARG_CALLABLE_INFO(0, callback, 0)
|
||||
ZEND_ARG_INFO(0, argument)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(socket_available_arginfo, 0)
|
||||
ZEND_ARG_INFO(1, ec)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(socket_at_mark_arginfo, 0)
|
||||
ZEND_ARG_INFO(1, ec)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(inet_socket_open_arginfo, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, inet6, _IS_BOOL, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(inet_socket_bind_arginfo, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, address, IS_STRING, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, port, IS_LONG, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(inet_socket_assign_arginfo, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, inet6, _IS_BOOL, 0)
|
||||
ZEND_ARG_INFO(0, native_handle)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(local_socket_assign_arginfo, 0)
|
||||
ZEND_ARG_INFO(0, native_handle)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(stream_socket_read_arginfo, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, read_some, _IS_BOOL, 0)
|
||||
ZEND_ARG_CALLABLE_INFO(0, callback, 0)
|
||||
ZEND_ARG_INFO(0, argument)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(stream_socket_write_arginfo, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, write_some, _IS_BOOL, 0)
|
||||
ZEND_ARG_CALLABLE_INFO(0, callback, 0)
|
||||
ZEND_ARG_INFO(0, argument)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(local_socket_bind_arginfo, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, path, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(datagram_socket_recv_from_arginfo, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 0)
|
||||
ZEND_ARG_CALLABLE_INFO(0, callback, 0)
|
||||
ZEND_ARG_INFO(0, argument)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(tcp_socket_connect_arginfo, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, address, IS_STRING, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, port, IS_LONG, 0)
|
||||
ZEND_ARG_CALLABLE_INFO(0, callback, 0)
|
||||
ZEND_ARG_INFO(0, argument)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(unix_socket_connect_arginfo, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, path, IS_STRING, 0)
|
||||
ZEND_ARG_CALLABLE_INFO(0, callback, 0)
|
||||
ZEND_ARG_INFO(0, argument)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(udp_socket_send_to_arginfo, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, address, IS_STRING, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, port, IS_LONG, 0)
|
||||
ZEND_ARG_CALLABLE_INFO(0, callback, 0)
|
||||
ZEND_ARG_INFO(0, argument)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(udg_socket_send_to_arginfo, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, path, IS_STRING, 0)
|
||||
ZEND_ARG_CALLABLE_INFO(0, callback, 0)
|
||||
ZEND_ARG_INFO(0, argument)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(acceptor_listen_arginfo, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, backlog, IS_LONG, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(acceptor_accept_arginfo, 0)
|
||||
ZEND_ARG_CALLABLE_INFO(0, callback, 0)
|
||||
ZEND_ARG_INFO(0, argument)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(stream_descriptor_assign_arginfo, 0)
|
||||
ZEND_ARG_INFO(0, native_handle)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ function_entry */
|
||||
|
||||
static zend_function_entry service_methods[] = {
|
||||
P3_ME_D(asio::service, addTimer, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::service, addSignal, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::service, addTcpResolver, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::service, addUdpResolver, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::service, addTcpSocket, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::service, addUdpSocket, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::service, addUnixSocket, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::service, addUdgSocket, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::service, addTcpAcceptor, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::service, addUnixAcceptor, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::service, addStreamDescriptor, nullptr, ZEND_ACC_PUBLIC)
|
||||
#ifdef ENABLE_STRAND
|
||||
P3_ME_D(asio::service, addStrand, nullptr, ZEND_ACC_PUBLIC)
|
||||
#endif // ENABLE_STRAND
|
||||
P3_ME_D(asio::service, run, service_run_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::service, runOne, service_run_one_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::service, poll, service_poll_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::service, pollOne, service_poll_one_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::service, stop, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::service, reset, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::service, stopped, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::service, post, service_dispatch_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::service, dispatch, service_dispatch_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::service, forkPrepare, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::service, forkParent, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::service, forkChild, nullptr, ZEND_ACC_PUBLIC)
|
||||
#ifdef ENABLE_COROUTINE
|
||||
P3_STATIC_ME(asio::future, lastError, nullptr, ZEND_ACC_PUBLIC)
|
||||
#endif // ENABLE_COROUTINE
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
#ifdef ENABLE_STRAND
|
||||
static zend_function_entry strand_methods[] = {
|
||||
P3_ME_D(asio::strand, dispatch, strand_dispatch_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::strand, post, strand_dispatch_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::strand, runningInThisThread, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::strand, wrap, strand_wrap_arginfo, ZEND_ACC_PUBLIC)
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
static zend_function_entry wrapped_handler_methods[] = {
|
||||
P3_ME_D(asio::wrapped_handler, __invoke, nullptr, ZEND_ACC_PUBLIC)
|
||||
PHP_FE_END
|
||||
};
|
||||
#endif // ENABLE_STRAND
|
||||
|
||||
static zend_function_entry io_object_method[] = {
|
||||
P3_ABSTRACT_ME(cancel, nullptr)
|
||||
P3_ABSTRACT_ME(destroy, nullptr)
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
static zend_function_entry timer_methods[] = {
|
||||
P3_ME_D(asio::timer, expiresFromNow, timer_expires_from_now_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::timer, expiresAt, timer_expires_at_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::timer, wait, timer_wait_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::timer, cancel, nullptr, ZEND_ACC_PUBLIC)
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
static zend_function_entry signal_methods[] = {
|
||||
P3_ME_D(asio::signal, add, signal_add_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::signal, remove, signal_remove_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::signal, wait, signal_wait_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::signal, clear, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::signal, cancel, nullptr, ZEND_ACC_PUBLIC)
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
static zend_function_entry resolver_methods[] = {
|
||||
P3_ABSTRACT_ME(resolve, resolver_resolve_arginfo)
|
||||
P3_ABSTRACT_ME(cancel, nullptr)
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
static zend_function_entry tcp_resolver_methods[] = {
|
||||
P3_ME_D(asio::tcp_resolver, resolve, resolver_resolve_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::tcp_resolver, cancel, nullptr, ZEND_ACC_PUBLIC)
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
static zend_function_entry udp_resolver_methods[] = {
|
||||
P3_ME_D(asio::udp_resolver, resolve, resolver_resolve_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::udp_resolver, cancel, nullptr, ZEND_ACC_PUBLIC)
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
static zend_function_entry socket_methods[] = {
|
||||
P3_ABSTRACT_ME(available, socket_available_arginfo)
|
||||
P3_ABSTRACT_ME(atMark, socket_at_mark_arginfo)
|
||||
P3_ABSTRACT_ME(close, nullptr)
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
static zend_function_entry inet_socket_methods[] = {
|
||||
P3_ABSTRACT_ME(open, inet_socket_open_arginfo)
|
||||
P3_ABSTRACT_ME(assign, inet_socket_assign_arginfo)
|
||||
P3_ABSTRACT_ME(bind, inet_socket_bind_arginfo)
|
||||
P3_ABSTRACT_ME(remoteAddr, nullptr)
|
||||
P3_ABSTRACT_ME(remotePort, nullptr)
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
static zend_function_entry local_socket_methods[] = {
|
||||
P3_ABSTRACT_ME(open, nullptr)
|
||||
P3_ABSTRACT_ME(assign, local_socket_assign_arginfo)
|
||||
P3_ABSTRACT_ME(bind, local_socket_bind_arginfo)
|
||||
P3_ABSTRACT_ME(remotePath, nullptr)
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
static zend_function_entry stream_socket_methods[] = {
|
||||
P3_ABSTRACT_ME(read, stream_socket_read_arginfo)
|
||||
P3_ABSTRACT_ME(write, stream_socket_write_arginfo)
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
static zend_function_entry datagram_socket_methods[] = {
|
||||
P3_ABSTRACT_ME(recvFrom, datagram_socket_recv_from_arginfo)
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
static zend_function_entry tcp_socket_methods[] = {
|
||||
P3_ME(asio::tcp_socket, open, open_inet, inet_socket_open_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME(asio::tcp_socket, assign, assign_inet, inet_socket_assign_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME(asio::tcp_socket, bind, bind_inet, inet_socket_bind_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::tcp_socket, connect, tcp_socket_connect_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::tcp_socket, read, stream_socket_read_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::tcp_socket, write, stream_socket_write_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::tcp_socket, remoteAddr, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::tcp_socket, remotePort, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::tcp_socket, available, socket_available_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::tcp_socket, atMark, socket_at_mark_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::tcp_socket, cancel, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::tcp_socket, close, nullptr, ZEND_ACC_PUBLIC)
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
static zend_function_entry udp_socket_methods[] = {
|
||||
P3_ME(asio::udp_socket, open, open_inet, inet_socket_open_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME(asio::udp_socket, assign, assign_inet, inet_socket_assign_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME(asio::udp_socket, bind, bind_inet, inet_socket_bind_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::udp_socket, sendTo, udp_socket_send_to_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::udp_socket, recvFrom, datagram_socket_recv_from_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::udp_socket, remoteAddr, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::udp_socket, remotePort, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::udp_socket, available, socket_available_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::udp_socket, atMark, socket_at_mark_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::udp_socket, cancel, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::udp_socket, close, nullptr, ZEND_ACC_PUBLIC)
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
static zend_function_entry unix_socket_methods[] = {
|
||||
P3_ME(asio::unix_socket, open, open_local, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME(asio::unix_socket, assign, assign_local, local_socket_assign_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME(asio::unix_socket, bind, bind_local, local_socket_bind_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::unix_socket, connect, unix_socket_connect_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::unix_socket, read, stream_socket_read_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::unix_socket, write, stream_socket_write_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::unix_socket, remotePath, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::unix_socket, available, socket_available_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::unix_socket, atMark, socket_at_mark_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::unix_socket, cancel, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::unix_socket, close, nullptr, ZEND_ACC_PUBLIC)
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
static zend_function_entry udg_socket_methods[] = {
|
||||
P3_ME(asio::udg_socket, open, open_local, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME(asio::udg_socket, assign, assign_local, local_socket_assign_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME(asio::udg_socket, bind, bind_local, local_socket_bind_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::udg_socket, sendTo, udg_socket_send_to_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::udg_socket, recvFrom, datagram_socket_recv_from_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::udg_socket, remotePath, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::udg_socket, available, socket_available_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::udg_socket, atMark, socket_at_mark_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::udg_socket, cancel, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::udg_socket, close, nullptr, ZEND_ACC_PUBLIC)
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
static zend_function_entry acceptor_methods[] = {
|
||||
P3_ABSTRACT_ME(listen, acceptor_listen_arginfo)
|
||||
P3_ABSTRACT_ME(accept, acceptor_accept_arginfo)
|
||||
P3_ABSTRACT_ME(close, nullptr)
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
static zend_function_entry tcp_acceptor_methods[] = {
|
||||
P3_ME_D(asio::tcp_acceptor, open, inet_socket_open_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::tcp_acceptor, assign, inet_socket_assign_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::tcp_acceptor, bind, inet_socket_bind_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::tcp_acceptor, listen, acceptor_listen_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::tcp_acceptor, accept, acceptor_accept_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::tcp_acceptor, cancel, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::tcp_acceptor, close, nullptr, ZEND_ACC_PUBLIC)
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
static zend_function_entry unix_acceptor_methods[] = {
|
||||
P3_ME_D(asio::unix_acceptor, open, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::unix_acceptor, assign, local_socket_assign_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::unix_acceptor, bind, local_socket_bind_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::unix_acceptor, listen, acceptor_listen_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::unix_acceptor, accept, acceptor_accept_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::unix_acceptor, cancel, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::unix_acceptor, close, nullptr, ZEND_ACC_PUBLIC)
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
static zend_function_entry stream_descriptor_methods[] = {
|
||||
P3_ME_D(asio::stream_descriptor, assign, stream_descriptor_assign_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::stream_descriptor, isOpen, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::stream_descriptor, read, stream_socket_read_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::stream_descriptor, write, stream_socket_write_arginfo, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::stream_descriptor, release, nullptr, ZEND_ACC_PUBLIC)
|
||||
P3_ME_D(asio::stream_descriptor, cancel, nullptr, ZEND_ACC_PUBLIC)
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ interfaces class_entry */
|
||||
|
||||
auto io_object_ce = p3::interface_init("Asio\\IoObject", io_object_method);
|
||||
auto resolver_ce = p3::interface_init("Asio\\Resolver", resolver_methods);
|
||||
auto socket_ce = p3::interface_init("Asio\\Socket", socket_methods);
|
||||
auto inet_socket_ce = p3::interface_init("Asio\\InetSocket", inet_socket_methods);
|
||||
auto local_socket_ce = p3::interface_init("Asio\\LocalSocket", local_socket_methods);
|
||||
auto stream_socket_ce = p3::interface_init("Asio\\StreamSocket", stream_socket_methods);
|
||||
auto datagram_socket_ce = p3::interface_init("Asio\\DatagramSocket", datagram_socket_methods);
|
||||
auto acceptor_ce = p3::interface_init("Asio\\Acceptor", acceptor_methods);
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ PHP_MINIT_FUNCTION */
|
||||
PHP_MINIT_FUNCTION(asio)
|
||||
{
|
||||
socket_ce->parent = io_object_ce;
|
||||
resolver_ce->parent = io_object_ce;
|
||||
acceptor_ce->parent = io_object_ce;
|
||||
inet_socket_ce->parent = socket_ce;
|
||||
local_socket_ce->parent = socket_ce;
|
||||
stream_socket_ce->parent = socket_ce;
|
||||
datagram_socket_ce->parent = socket_ce;
|
||||
p3::class_init<asio::service>("Asio\\Service", service_methods);
|
||||
auto ce = p3::class_init<asio::timer>("Asio\\Timer", timer_methods);
|
||||
zend_class_implements(ce, 1, io_object_ce);
|
||||
ce->ce_flags |= ZEND_ACC_FINAL;
|
||||
ce = p3::class_init<asio::signal>("Asio\\Signal", signal_methods);
|
||||
zend_class_implements(ce, 1, io_object_ce);
|
||||
ce->ce_flags |= ZEND_ACC_FINAL;
|
||||
ce = p3::class_init<asio::tcp_resolver>("Asio\\TcpResolver", tcp_resolver_methods);
|
||||
zend_class_implements(ce, 1, resolver_ce);
|
||||
ce->ce_flags |= ZEND_ACC_FINAL;
|
||||
ce = p3::class_init<asio::udp_resolver>("Asio\\UdpResolver", udp_resolver_methods);
|
||||
zend_class_implements(ce, 1, resolver_ce);
|
||||
ce->ce_flags |= ZEND_ACC_FINAL;
|
||||
ce = p3::class_init<asio::tcp_socket>("Asio\\TcpSocket", tcp_socket_methods);
|
||||
zend_class_implements(ce, 2, inet_socket_ce, stream_socket_ce);
|
||||
ce->ce_flags |= ZEND_ACC_FINAL;
|
||||
ce = p3::class_init<asio::udp_socket>("Asio\\UdpSocket", udp_socket_methods);
|
||||
zend_class_implements(ce, 2, inet_socket_ce, datagram_socket_ce);
|
||||
ce->ce_flags |= ZEND_ACC_FINAL;
|
||||
ce = p3::class_init<asio::unix_socket>("Asio\\UnixSocket", unix_socket_methods);
|
||||
zend_class_implements(ce, 2, local_socket_ce, stream_socket_ce);
|
||||
ce->ce_flags |= ZEND_ACC_FINAL;
|
||||
ce = p3::class_init<asio::udg_socket>("Asio\\UdgSocket", udg_socket_methods);
|
||||
zend_class_implements(ce, 2, local_socket_ce, datagram_socket_ce);
|
||||
ce->ce_flags |= ZEND_ACC_FINAL;
|
||||
ce = p3::class_init<asio::tcp_acceptor>("Asio\\TcpAcceptor", tcp_acceptor_methods);
|
||||
zend_class_implements(ce, 1, acceptor_ce);
|
||||
ce->ce_flags |= ZEND_ACC_FINAL;
|
||||
ce = p3::class_init<asio::unix_acceptor>("Asio\\UnixAcceptor", unix_acceptor_methods);
|
||||
zend_class_implements(ce, 1, acceptor_ce);
|
||||
ce->ce_flags |= ZEND_ACC_FINAL;
|
||||
ce = p3::class_init<asio::stream_descriptor>("Asio\\StreamDescriptor", stream_descriptor_methods);
|
||||
zend_class_implements(ce, 1, io_object_ce);
|
||||
ce->ce_flags |= ZEND_ACC_FINAL;
|
||||
#ifdef ENABLE_COROUTINE
|
||||
ce = p3::class_init<asio::future>("Asio\\Future", nullptr);
|
||||
ce->ce_flags |= ZEND_ACC_FINAL;
|
||||
#endif // ENABLE_COROUTINE
|
||||
#ifdef ENABLE_STRAND
|
||||
ce = p3::class_init<asio::strand>("Asio\\Strand", strand_methods);
|
||||
ce->ce_flags |= ZEND_ACC_FINAL;
|
||||
ce = p3::class_init<asio::wrapped_handler>("Asio\\WrappedHandler", wrapped_handler_methods);
|
||||
ce->ce_flags |= ZEND_ACC_FINAL;
|
||||
#endif // ENABLE_STRAND
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ PHP_MINFO_FUNCTION */
|
||||
PHP_MINFO_FUNCTION(asio)
|
||||
{
|
||||
php_info_print_table_start();
|
||||
php_info_print_table_header(2, "Coroutine support",
|
||||
#ifdef ENABLE_COROUTINE
|
||||
"enabled"
|
||||
#else
|
||||
"disabled"
|
||||
#endif // ENABLE_COROUTINE
|
||||
);
|
||||
php_info_print_table_header(2, "Strand support",
|
||||
#ifdef ENABLE_STRAND
|
||||
"enabled"
|
||||
#else
|
||||
"disabled"
|
||||
#endif // ENABLE_STRAND
|
||||
);
|
||||
php_info_print_table_header(2, "Null buffers support",
|
||||
#ifdef ENABLE_NULL_BUFFERS
|
||||
"enabled"
|
||||
#else
|
||||
"disabled"
|
||||
#endif // ENABLE_NULL_BUFFERS
|
||||
);
|
||||
php_info_print_table_end();
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ asio_module_entry */
|
||||
zend_module_entry asio_module_entry = {
|
||||
STANDARD_MODULE_HEADER,
|
||||
"asio",
|
||||
nullptr,
|
||||
PHP_MINIT(asio),
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
PHP_MINFO(asio),
|
||||
PHP_ASIO_VERSION,
|
||||
STANDARD_MODULE_PROPERTIES
|
||||
};
|
||||
/* }}} */
|
||||
|
||||
#ifdef COMPILE_DL_ASIO
|
||||
ZEND_GET_MODULE(asio)
|
||||
#endif // COMPILE_DL_ASIO
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* php-asio/php_asio.hpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern zend_module_entry asio_module_entry;
|
||||
#define phpext_asio_ptr &asio_module_entry
|
||||
|
||||
#define PHP_ASIO_VERSION "0.1.5"
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 4
|
||||
#define PHP_ASIO_API __attribute__ ((visibility("default")))
|
||||
#else
|
||||
#define PHP_ASIO_API
|
||||
#endif
|
||||
|
||||
#ifdef ZTS
|
||||
#include "TSRM.h"
|
||||
#endif
|
||||
|
||||
#if defined(ZTS) && defined(COMPILE_DL_ASIO)
|
||||
ZEND_TSRMLS_CACHE_EXTERN()
|
||||
#endif
|
|
@ -0,0 +1,70 @@
|
|||
/**
|
||||
* php-asio/resolver.cpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#include "resolver.hpp"
|
||||
#include "future.hpp"
|
||||
|
||||
namespace asio
|
||||
{
|
||||
template <typename Protocol>
|
||||
zval* resolver<Protocol>::handler(const boost::system::error_code& error,
|
||||
iterator iter, zval* callback, zval* argument)
|
||||
{
|
||||
iterator end;
|
||||
ZVAL_INIT(addr_list);
|
||||
ZVAL_NEW_ARR(&addr_list);
|
||||
zend_hash_init(Z_ARR(addr_list), 0, nullptr, ZVAL_PTR_DTOR, 0);
|
||||
ZVAL_INIT(addr_val);
|
||||
while (iter != end) {
|
||||
auto addr = (*iter++).endpoint().address().to_string();
|
||||
ZVAL_STR(&addr_val, zend_string_init(addr.c_str(), addr.length(), 0));
|
||||
zend_hash_next_index_insert(Z_ARR(addr_list), &addr_val);
|
||||
}
|
||||
PHP_ASIO_INVOKE_CALLBACK_START(4)
|
||||
ZVAL_ARR(&arguments[1], Z_ARR(addr_list));
|
||||
PHP_ASIO_INVOKE_CALLBACK();
|
||||
PHP_ASIO_INVOKE_CALLBACK_END();
|
||||
CORO_RETURN(ZVAL_ARR, Z_ARR(addr_list));
|
||||
}
|
||||
|
||||
template <typename Protocol>
|
||||
P3_METHOD(resolver<Protocol>, resolve)
|
||||
{
|
||||
zend_string* host;
|
||||
zend_string* service = nullptr;
|
||||
zval* callback = nullptr;
|
||||
zval* argument = nullptr;
|
||||
ZEND_PARSE_PARAMETERS_START(1, 4)
|
||||
Z_PARAM_STR(host)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_STR(service)
|
||||
Z_PARAM_ZVAL(callback)
|
||||
Z_PARAM_ZVAL(argument)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
PHP_ASIO_FUTURE_INIT();
|
||||
future->template on_resolve<iterator>(boost::bind(
|
||||
&resolver::handler, this, _1, _2, cb, args));
|
||||
resolver_.async_resolve({ ZSTR_VAL(host), service ? ZSTR_VAL(service) : "" },
|
||||
STRAND_RESOLVE(ASYNC_HANDLER_DOUBLE_ARG(iterator)));
|
||||
FUTURE_RETURN();
|
||||
}
|
||||
|
||||
template <typename Protocol>
|
||||
P3_METHOD(resolver<Protocol>, cancel)
|
||||
{
|
||||
resolver_.cancel();
|
||||
RETVAL_LONG(0);
|
||||
}
|
||||
|
||||
template <typename Protocol>
|
||||
zend_class_entry* resolver<Protocol>::class_entry;
|
||||
|
||||
template <typename Protocol>
|
||||
zend_object_handlers resolver<Protocol>::handlers;
|
||||
|
||||
template class resolver<tcp>;
|
||||
template class resolver<udp>;
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* php-asio/resolver.hpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.hpp"
|
||||
#include "base.hpp"
|
||||
|
||||
namespace asio
|
||||
{
|
||||
/// Wrapper for Boost.Asio resolver.
|
||||
/// Provides hostname resolution.
|
||||
template <typename Protocol>
|
||||
class resolver : public base
|
||||
{
|
||||
/// Resolver iterator which holds an endpoint.
|
||||
using iterator = typename Protocol::resolver::iterator;
|
||||
|
||||
/// Boost.Asio resolver instance.
|
||||
typename Protocol::resolver resolver_;
|
||||
|
||||
/// Resolve handler.
|
||||
zval* handler(const boost::system::error_code& error,
|
||||
iterator iter, zval* callback, zval* argument);
|
||||
|
||||
public:
|
||||
/// Constructor.
|
||||
explicit resolver(
|
||||
boost::asio::io_service& io_service
|
||||
) : base(io_service), resolver_(io_service) {}
|
||||
|
||||
/* {{{ proto Future Resolver::resolve(string host, [string service = ""],
|
||||
* [callable callback], [mixed argument]);
|
||||
* Initiate an asynchronous resolve against the resolver. */
|
||||
P3_METHOD_DECLARE(resolve);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int Resolver::cancel(void);
|
||||
* Cancel all asynchronous operations on this resolver. */
|
||||
P3_METHOD_DECLARE(cancel);
|
||||
/* }}} */
|
||||
|
||||
PHP_ASIO_CE_DECLARE();
|
||||
};
|
||||
|
||||
using tcp_resolver = resolver<tcp>;
|
||||
using udp_resolver = resolver<udp>;
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
/**
|
||||
* php-asio/service.cpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#include "service.hpp"
|
||||
|
||||
#define PHP_ASIO_RUN_LOOP(meth) \
|
||||
zval* error = nullptr; \
|
||||
ZEND_PARSE_PARAMETERS_START(0, 1) \
|
||||
Z_PARAM_OPTIONAL \
|
||||
Z_PARAM_ZVAL(error) \
|
||||
ZEND_PARSE_PARAMETERS_END(); \
|
||||
boost::system::error_code ec; \
|
||||
auto handler_count = meth(ec); \
|
||||
if (error) { \
|
||||
ZVAL_DEREF(error); \
|
||||
ZVAL_LONG(error, static_cast<zend_long>(ec.value())); \
|
||||
} \
|
||||
RETVAL_LONG(static_cast<zend_long>(handler_count))
|
||||
|
||||
#define PHP_ASIO_NOTIFY_FORK(ev) \
|
||||
try { \
|
||||
io_service_.notify_fork(boost::asio::io_service::ev); \
|
||||
} catch (const boost::system::system_error& err) { \
|
||||
RETURN_LONG(static_cast<zend_long>(err.code().value())); \
|
||||
} \
|
||||
RETVAL_LONG(0)
|
||||
|
||||
#define SERVICE_DISPATCH_CALLBACK(meth) PHP_ASIO_DISPATCH_CALLBACK(meth) })
|
||||
|
||||
namespace asio
|
||||
{
|
||||
P3_METHOD(service, addTimer)
|
||||
{
|
||||
PHP_ASIO_OBJ_ALLOC(timer, asio::timer, io_service_);
|
||||
RETVAL_OBJ(timer);
|
||||
}
|
||||
|
||||
P3_METHOD(service, addSignal)
|
||||
{
|
||||
PHP_ASIO_OBJ_ALLOC(signal, asio::signal, io_service_);
|
||||
RETVAL_OBJ(signal);
|
||||
}
|
||||
|
||||
P3_METHOD(service, addTcpResolver)
|
||||
{
|
||||
PHP_ASIO_OBJ_ALLOC(resolver, tcp_resolver, io_service_);
|
||||
RETVAL_OBJ(resolver);
|
||||
}
|
||||
|
||||
P3_METHOD(service, addUdpResolver)
|
||||
{
|
||||
PHP_ASIO_OBJ_ALLOC(resolver, udp_resolver, io_service_);
|
||||
RETVAL_OBJ(resolver);
|
||||
}
|
||||
|
||||
P3_METHOD(service, addTcpSocket)
|
||||
{
|
||||
PHP_ASIO_OBJ_ALLOC(socket, tcp_socket, io_service_);
|
||||
RETVAL_OBJ(socket);
|
||||
}
|
||||
|
||||
P3_METHOD(service, addUdpSocket)
|
||||
{
|
||||
PHP_ASIO_OBJ_ALLOC(socket, udp_socket, io_service_);
|
||||
RETVAL_OBJ(socket);
|
||||
}
|
||||
|
||||
P3_METHOD(service, addUnixSocket)
|
||||
{
|
||||
PHP_ASIO_OBJ_ALLOC(socket, unix_socket, io_service_);
|
||||
RETVAL_OBJ(socket);
|
||||
}
|
||||
|
||||
P3_METHOD(service, addUdgSocket)
|
||||
{
|
||||
PHP_ASIO_OBJ_ALLOC(socket, udg_socket, io_service_);
|
||||
RETVAL_OBJ(socket);
|
||||
}
|
||||
|
||||
P3_METHOD(service, addTcpAcceptor)
|
||||
{
|
||||
PHP_ASIO_OBJ_ALLOC(acceptor, tcp_acceptor, io_service_);
|
||||
RETVAL_OBJ(acceptor);
|
||||
}
|
||||
|
||||
P3_METHOD(service, addUnixAcceptor)
|
||||
{
|
||||
PHP_ASIO_OBJ_ALLOC(acceptor, unix_acceptor, io_service_);
|
||||
RETVAL_OBJ(acceptor);
|
||||
}
|
||||
|
||||
P3_METHOD(service, addStreamDescriptor)
|
||||
{
|
||||
PHP_ASIO_OBJ_ALLOC(descriptor, stream_descriptor, io_service_);
|
||||
RETVAL_OBJ(descriptor);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_STRAND
|
||||
P3_METHOD(service, addStrand)
|
||||
{
|
||||
PHP_ASIO_OBJ_ALLOC(strand, asio::strand, io_service_);
|
||||
RETVAL_OBJ(strand);
|
||||
}
|
||||
#endif // ENABLE_STRAND
|
||||
|
||||
P3_METHOD(service, run)
|
||||
{
|
||||
PHP_ASIO_RUN_LOOP(io_service_.run);
|
||||
}
|
||||
|
||||
P3_METHOD(service, runOne)
|
||||
{
|
||||
PHP_ASIO_RUN_LOOP(io_service_.run_one);
|
||||
}
|
||||
|
||||
P3_METHOD(service, poll)
|
||||
{
|
||||
PHP_ASIO_RUN_LOOP(io_service_.poll);
|
||||
}
|
||||
|
||||
P3_METHOD(service, pollOne)
|
||||
{
|
||||
PHP_ASIO_RUN_LOOP(io_service_.poll_one);
|
||||
}
|
||||
|
||||
P3_METHOD(service, stop)
|
||||
{
|
||||
io_service_.stop();
|
||||
}
|
||||
|
||||
P3_METHOD(service, reset)
|
||||
{
|
||||
io_service_.reset();
|
||||
}
|
||||
|
||||
P3_METHOD(service, stopped) const
|
||||
{
|
||||
RETVAL_BOOL(io_service_.stopped());
|
||||
}
|
||||
|
||||
P3_METHOD(service, post)
|
||||
{
|
||||
SERVICE_DISPATCH_CALLBACK(io_service_.post);
|
||||
}
|
||||
|
||||
P3_METHOD(service, dispatch)
|
||||
{
|
||||
SERVICE_DISPATCH_CALLBACK(io_service_.dispatch);
|
||||
}
|
||||
|
||||
P3_METHOD(service, forkPrepare)
|
||||
{
|
||||
PHP_ASIO_NOTIFY_FORK(fork_prepare);
|
||||
}
|
||||
|
||||
P3_METHOD(service, forkParent)
|
||||
{
|
||||
PHP_ASIO_NOTIFY_FORK(fork_parent);
|
||||
}
|
||||
|
||||
P3_METHOD(service, forkChild)
|
||||
{
|
||||
PHP_ASIO_NOTIFY_FORK(fork_child);
|
||||
}
|
||||
|
||||
PHP_ASIO_CE_DEFINE(service);
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
/**
|
||||
* php-asio/service.hpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.hpp"
|
||||
#include "future.hpp"
|
||||
#include "timer.hpp"
|
||||
#include "signal.hpp"
|
||||
#include "resolver.hpp"
|
||||
#include "socket.hpp"
|
||||
#include "acceptor.hpp"
|
||||
#include "stream_descriptor.hpp"
|
||||
#include "strand.hpp"
|
||||
#include "php_asio.hpp"
|
||||
|
||||
namespace asio
|
||||
{
|
||||
/// Wrapper for Boost.Asio io_service.
|
||||
/// Provide access to instantiation of I/O objects.
|
||||
class service
|
||||
{
|
||||
/// The io_service of all I/O objects in current instance.
|
||||
boost::asio::io_service io_service_;
|
||||
|
||||
public:
|
||||
/// Default constructor.
|
||||
service() = default;
|
||||
|
||||
/// Deleted copy constructor.
|
||||
service(const service&) = delete;
|
||||
|
||||
/// Default destructor.
|
||||
virtual ~service() = default;
|
||||
|
||||
/// Deleted copy assignment operator.
|
||||
service& operator=(const service&) = delete;
|
||||
|
||||
/* {{{ proto Timer Service::addTimer(void);
|
||||
* Add a new timer. */
|
||||
P3_METHOD_DECLARE(addTimer);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto Signal Service::addSignal(void);
|
||||
* Add a new signal set. */
|
||||
P3_METHOD_DECLARE(addSignal);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto TcpResolver Service::addTcpResolver(void);
|
||||
* Add a new TCP resolver. */
|
||||
P3_METHOD_DECLARE(addTcpResolver);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto UdpResolver Service::addUdpResolver(void);
|
||||
* Add a new UDP resolver.*/
|
||||
P3_METHOD_DECLARE(addUdpResolver);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto TcpSocket Service::addUdpSocket(void);
|
||||
* Add a new TCP socket. */
|
||||
P3_METHOD_DECLARE(addTcpSocket);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto UdpSocket Service::addUdpSocket(void);
|
||||
* Add a new UDP socket. */
|
||||
P3_METHOD_DECLARE(addUdpSocket);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto UnixSocket Service::addUnixSocket(void);
|
||||
* Add a new UNIX domain socket (SOCK_STREAM). */
|
||||
P3_METHOD_DECLARE(addUnixSocket);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto UdgSocket Service::addUdgSocket(void);
|
||||
* Add a new UNIX domain socket (SOCK_DGRAM). */
|
||||
P3_METHOD_DECLARE(addUdgSocket);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto TcpAcceptor Service::addTcpAcceptor(void);
|
||||
* Add a new TCP acceptor. */
|
||||
P3_METHOD_DECLARE(addTcpAcceptor);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto UnixAcceptor Service::addUnixAcceptor(void);
|
||||
* Add a new UNIX domain socket acceptor (SOCK_STREAM). */
|
||||
P3_METHOD_DECLARE(addUnixAcceptor);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto StreamDescriptor Service::addStreamDescriptor(void);
|
||||
* Add a new stream descriptor. */
|
||||
P3_METHOD_DECLARE(addStreamDescriptor);
|
||||
/* }}} */
|
||||
|
||||
#ifdef ENABLE_STRAND
|
||||
/* {{{ proto Strand Service::addStrand(void);
|
||||
* Add a new strand object. */
|
||||
P3_METHOD_DECLARE(addStrand);
|
||||
/* }}} */
|
||||
#endif // ENABLE_STRAND
|
||||
|
||||
/* {{{ proto int run([int &ec]);
|
||||
* Run the event loop until stopped or no more work. */
|
||||
P3_METHOD_DECLARE(run);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int runOne([int &ec]);
|
||||
* Run until stopped or one operation is performed. */
|
||||
P3_METHOD_DECLARE(runOne);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int poll([int &ec]);
|
||||
* Poll for operations without blocking. */
|
||||
P3_METHOD_DECLARE(poll);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int pollOne([int &ec]);
|
||||
* Poll for one operation without blocking. */
|
||||
P3_METHOD_DECLARE(pollOne);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto void stop(void);
|
||||
* Stop the event processing loop. */
|
||||
P3_METHOD_DECLARE(stop);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto void stop(void);
|
||||
* Reset in preparation for a subsequent run invocation. */
|
||||
P3_METHOD_DECLARE(reset);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto bool stopped(void);
|
||||
* Determine whether the io_service is stopped. */
|
||||
P3_METHOD_DECLARE(stopped) const;
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto void Service::post(callable callback, [mixed argument]);
|
||||
* Request invocation of the given handler and return immediately. */
|
||||
P3_METHOD_DECLARE(post);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto void Service::dispatch(callable callback, [mixed argument]);
|
||||
* Request invocation of the given handler. */
|
||||
P3_METHOD_DECLARE(dispatch);
|
||||
|
||||
/* {{{ proto int Service::forkPrepare(void);
|
||||
* Notify all services of a fork event. (prepare to fork) */
|
||||
P3_METHOD_DECLARE(forkPrepare);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int Service::forkParent(void);
|
||||
* Notify all services of a fork event. (fork parent) */
|
||||
P3_METHOD_DECLARE(forkParent);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int Service::forkChild(void);
|
||||
* Notify all services of a fork event. (fork child) */
|
||||
P3_METHOD_DECLARE(forkChild);
|
||||
|
||||
/// Get io_service by reference.
|
||||
/// Can be used when working on another extension based on Boost.Asio.
|
||||
PHP_ASIO_API boost::asio::io_service& get_io_service()
|
||||
{
|
||||
return io_service_;
|
||||
}
|
||||
|
||||
PHP_ASIO_CE_DECLARE();
|
||||
};
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/**
|
||||
* php-asio/signal.cpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#include "signal.hpp"
|
||||
#include "future.hpp"
|
||||
|
||||
namespace asio
|
||||
{
|
||||
zval* signal::handler(const boost::system::error_code& error,
|
||||
int signal, zval* callback, zval* argument)
|
||||
{
|
||||
PHP_ASIO_INVOKE_CALLBACK_START(4);
|
||||
ZVAL_LONG(&arguments[1], static_cast<zend_long>(signal));
|
||||
PHP_ASIO_INVOKE_CALLBACK();
|
||||
PHP_ASIO_INVOKE_CALLBACK_END();
|
||||
CORO_RETURN(ZVAL_LONG, static_cast<zend_long>(signal));
|
||||
}
|
||||
|
||||
P3_METHOD(signal, add)
|
||||
{
|
||||
size_t sig_len = 0;
|
||||
zval* sig_num = nullptr;
|
||||
ZEND_PARSE_PARAMETERS_START(1, -1)
|
||||
Z_PARAM_VARIADIC('+', sig_num, sig_len)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
boost::system::error_code ec;
|
||||
for (size_t i = 0; i < sig_len; i++) {
|
||||
if (Z_TYPE(sig_num[i]) != IS_LONG) {
|
||||
PHP_ASIO_ERROR(E_NOTICE, "Integer value expected.");
|
||||
continue;
|
||||
}
|
||||
signal_.add(static_cast<int>(Z_LVAL(sig_num[i])), ec);
|
||||
if (ec)
|
||||
break;
|
||||
}
|
||||
RETVAL_EC(ec);
|
||||
}
|
||||
|
||||
P3_METHOD(signal, remove)
|
||||
{
|
||||
size_t sig_len = 0;
|
||||
zval* sig_num = nullptr;
|
||||
ZEND_PARSE_PARAMETERS_START(1, -1)
|
||||
Z_PARAM_VARIADIC('+', sig_num, sig_len)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
boost::system::error_code ec;
|
||||
for (size_t i = 0; i < sig_len; i++) {
|
||||
if (Z_TYPE(sig_num[i]) != IS_LONG) {
|
||||
PHP_ASIO_ERROR(E_NOTICE, "Integer value expected.");
|
||||
continue;
|
||||
}
|
||||
signal_.remove(static_cast<int>(Z_LVAL(sig_num[i])), ec);
|
||||
if (ec)
|
||||
break;
|
||||
}
|
||||
RETVAL_EC(ec);
|
||||
}
|
||||
|
||||
P3_METHOD(signal, wait)
|
||||
{
|
||||
zval* callback = nullptr;
|
||||
zval* argument = nullptr;
|
||||
ZEND_PARSE_PARAMETERS_START(0, 2)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_ZVAL(callback)
|
||||
Z_PARAM_ZVAL(argument)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
PHP_ASIO_FUTURE_INIT();
|
||||
future->on_resolve<int>(boost::bind(&signal::handler, this, _1, _2, cb, args));
|
||||
signal_.async_wait(STRAND_RESOLVE(ASYNC_HANDLER_DOUBLE_ARG(int)));
|
||||
FUTURE_RETURN();
|
||||
}
|
||||
|
||||
P3_METHOD(signal, clear)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
RETVAL_EC(signal_.clear(ec));
|
||||
}
|
||||
|
||||
P3_METHOD(signal, cancel)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
RETVAL_EC(signal_.cancel(ec));
|
||||
}
|
||||
|
||||
PHP_ASIO_CE_DEFINE(signal);
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* php-asio/signal.hpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.hpp"
|
||||
#include "base.hpp"
|
||||
|
||||
namespace asio
|
||||
{
|
||||
/// Wrapper for Boost.Asio signal_set.
|
||||
/// Provides functionalities for signal handling.
|
||||
class signal : public base
|
||||
{
|
||||
/// Boost.Asio signal_set instance.
|
||||
boost::asio::signal_set signal_;
|
||||
|
||||
/// Signal handler callback.
|
||||
zval* handler(const boost::system::error_code& error,
|
||||
int signal, zval* callback, zval* argument);
|
||||
|
||||
public:
|
||||
/// Constructor.
|
||||
explicit signal(
|
||||
boost::asio::io_service& io_service
|
||||
) : base(io_service), signal_(io_service) {}
|
||||
|
||||
/* {{{ proto int Signal::add(int sig_num, [int ...]);
|
||||
* Add the specified signal(s) to the signal set. */
|
||||
P3_METHOD_DECLARE(add);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int Signal::remove(int sig_num, [int ...]);
|
||||
* Remove the specified signal(s) from the signal set. */
|
||||
P3_METHOD_DECLARE(remove);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto Future Signal::wait([callable callback], [mixed argument]);
|
||||
* Initiate an asynchronous wait against the signal set. */
|
||||
P3_METHOD_DECLARE(wait);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int Signal::clear(void);
|
||||
* Remove all signals from the signal set. */
|
||||
P3_METHOD_DECLARE(clear);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int Signal::cancel(void);
|
||||
* Cancel current signal set. */
|
||||
P3_METHOD_DECLARE(cancel);
|
||||
/* }}} */
|
||||
|
||||
PHP_ASIO_CE_DECLARE();
|
||||
};
|
||||
}
|
|
@ -0,0 +1,480 @@
|
|||
/**
|
||||
* php-asio/socket.cpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#include "socket.hpp"
|
||||
#include "future.hpp"
|
||||
#include "io.hpp"
|
||||
|
||||
namespace asio
|
||||
{
|
||||
template <typename Protocol>
|
||||
zval* socket<Protocol>::connect_handler(const boost::system::error_code& error,
|
||||
zval* callback, zval* argument)
|
||||
{
|
||||
PHP_ASIO_INVOKE_CALLBACK_START(3)
|
||||
PHP_ASIO_INVOKE_CALLBACK();
|
||||
PHP_ASIO_INVOKE_CALLBACK_END();
|
||||
CORO_RETURN_NULL();
|
||||
}
|
||||
|
||||
template <typename Protocol> template <typename, typename>
|
||||
zval* socket<Protocol>::read_handler(const boost::system::error_code& error,
|
||||
size_t length, zend_string* buffer, zval* callback, zval* argument)
|
||||
{
|
||||
// Zend strings have to be zero-terminated.
|
||||
// Otherwise you'll get E_WARNING on zval dtor.
|
||||
ZSTR_VAL(buffer)[length] = '\0';
|
||||
ZSTR_LEN(buffer) = length;
|
||||
PHP_ASIO_INVOKE_CALLBACK_START(4)
|
||||
ZVAL_STR(&arguments[1], buffer);
|
||||
PHP_ASIO_INVOKE_CALLBACK();
|
||||
PHP_ASIO_INVOKE_CALLBACK_END();
|
||||
CORO_RETURN(ZVAL_STR, buffer);
|
||||
}
|
||||
|
||||
template <typename Protocol>
|
||||
zval* socket<Protocol>::write_handler(const boost::system::error_code& error,
|
||||
size_t length, zend_string* buffer, zval* callback, zval* argument)
|
||||
{
|
||||
#ifdef ENABLE_NULL_BUFFERS
|
||||
if (buffer)
|
||||
#endif //ENABLE_NULL_BUFFERS
|
||||
zend_string_release(buffer);
|
||||
PHP_ASIO_INVOKE_CALLBACK_START(4)
|
||||
ZVAL_LONG(&arguments[1], static_cast<zend_long>(length));
|
||||
PHP_ASIO_INVOKE_CALLBACK();
|
||||
PHP_ASIO_INVOKE_CALLBACK_END();
|
||||
CORO_RETURN(ZVAL_LONG, static_cast<zend_long>(length));
|
||||
}
|
||||
|
||||
template <>
|
||||
zval* udp_socket::recv_handler(const boost::system::error_code& error,
|
||||
size_t length, zend_string* buffer, udp::endpoint* endpoint,
|
||||
zval* callback, zval* argument)
|
||||
{
|
||||
ZSTR_VAL(buffer)[length] = '\0';
|
||||
ZSTR_LEN(buffer) = length;
|
||||
#ifdef ENABLE_COROUTINE
|
||||
last_addr_<> = endpoint->address().to_string();
|
||||
last_port_<> = endpoint->port();
|
||||
#endif // ENABLE_COROUTINE
|
||||
PHP_ASIO_INVOKE_CALLBACK_START(6)
|
||||
ZVAL_STR(&arguments[1], buffer);
|
||||
#ifdef ENABLE_COROUTINE
|
||||
ZVAL_STRING(&arguments[2], last_addr_<>.data());
|
||||
ZVAL_LONG(&arguments[3], static_cast<zend_long>(last_port_<>));
|
||||
#else
|
||||
ZVAL_STRING(&arguments[2], endpoint->address().to_string().data());
|
||||
ZVAL_LONG(&arguments[3], static_cast<zend_long>(endpoint->port()));
|
||||
#endif // ENABLE_COROUTINE
|
||||
PHP_ASIO_INVOKE_CALLBACK();
|
||||
zval_ptr_dtor(&arguments[2]);
|
||||
PHP_ASIO_INVOKE_CALLBACK_END();
|
||||
delete endpoint;
|
||||
CORO_RETURN(ZVAL_STR, buffer);
|
||||
}
|
||||
|
||||
template <>
|
||||
zval* udg_socket::recv_handler(const boost::system::error_code& error,
|
||||
size_t length, zend_string* buffer, udg::endpoint* endpoint,
|
||||
zval* callback, zval* argument)
|
||||
{
|
||||
ZSTR_VAL(buffer)[length] = '\0';
|
||||
ZSTR_LEN(buffer) = length;
|
||||
#ifdef ENABLE_COROUTINE
|
||||
last_path_<> = endpoint->path();
|
||||
#endif // ENABLE_COROUTINE
|
||||
PHP_ASIO_INVOKE_CALLBACK_START(5)
|
||||
ZVAL_STR(&arguments[1], buffer);
|
||||
#ifdef ENABLE_COROUTINE
|
||||
ZVAL_STRING(&arguments[2], last_path_<>.data());
|
||||
#else
|
||||
ZVAL_STRING(&arguments[2], endpoint->path().data());
|
||||
#endif // ENABLE_COROUTINE
|
||||
PHP_ASIO_INVOKE_CALLBACK();
|
||||
zval_ptr_dtor(&arguments[2]);
|
||||
PHP_ASIO_INVOKE_CALLBACK_END();
|
||||
delete endpoint;
|
||||
CORO_RETURN(ZVAL_STR, buffer);
|
||||
}
|
||||
|
||||
template <typename Protocol> template <typename P, ENABLE_IF_INET(P)>
|
||||
P3_METHOD(socket<Protocol>, open_inet)
|
||||
{
|
||||
zend_bool inet6;
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||
Z_PARAM_BOOL(inet6)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
boost::system::error_code ec;
|
||||
socket_.open(inet6 ? Protocol::v6() : Protocol::v4(), ec);
|
||||
RETVAL_EC(ec);
|
||||
}
|
||||
|
||||
template <typename Protocol> template <typename P, ENABLE_IF_LOCAL(P)>
|
||||
P3_METHOD(socket<Protocol>, open_local)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
socket_.open(Protocol(), ec);
|
||||
RETVAL_EC(ec);
|
||||
}
|
||||
|
||||
template <typename Protocol> template <typename P, ENABLE_IF_INET(P)>
|
||||
P3_METHOD(socket<Protocol>, assign_inet)
|
||||
{
|
||||
PHP_ASIO_INET_ASSIGN(socket_, Protocol);
|
||||
}
|
||||
|
||||
template <typename Protocol> template <typename P, ENABLE_IF_LOCAL(P)>
|
||||
P3_METHOD(socket<Protocol>, assign_local)
|
||||
{
|
||||
PHP_ASIO_LOCAL_ASSIGN(socket_, Protocol);
|
||||
}
|
||||
|
||||
template <typename Protocol> template <typename P, ENABLE_IF_INET(P)>
|
||||
P3_METHOD(socket<Protocol>, bind_inet)
|
||||
{
|
||||
zend_string* address;
|
||||
zend_long port_num;
|
||||
ZEND_PARSE_PARAMETERS_START(2, 2);
|
||||
Z_PARAM_STR(address)
|
||||
Z_PARAM_LONG(port_num)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
boost::system::error_code ec;
|
||||
socket_.bind({ boost::asio::ip::address::from_string(ZSTR_VAL(address)),
|
||||
static_cast<unsigned short>(port_num) }, ec);
|
||||
RETVAL_EC(ec);
|
||||
}
|
||||
|
||||
template <typename Protocol> template <typename P, ENABLE_IF_LOCAL(P)>
|
||||
P3_METHOD(socket<Protocol>, bind_local)
|
||||
{
|
||||
zend_string* socket_path;
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1);
|
||||
Z_PARAM_STR(socket_path)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
namespace fs = boost::filesystem;
|
||||
if (fs::status(ZSTR_VAL(socket_path)).type() == fs::socket_file)
|
||||
fs::remove(ZSTR_VAL(socket_path));
|
||||
boost::system::error_code ec;
|
||||
socket_.bind({ ZSTR_VAL(socket_path) }, ec);
|
||||
RETVAL_EC(ec);
|
||||
}
|
||||
|
||||
/* {{{ proto Future TcpSocket::connect(string address, int port,
|
||||
* [callable callback], [mixed argument]);
|
||||
* Asynchronously connect to a remote endpoint. */
|
||||
template <>
|
||||
P3_METHOD(tcp_socket, connect)
|
||||
{
|
||||
zend_string* address;
|
||||
zend_long port;
|
||||
zval* callback = nullptr;
|
||||
zval* argument = nullptr;
|
||||
ZEND_PARSE_PARAMETERS_START(2, 4)
|
||||
Z_PARAM_STR(address)
|
||||
Z_PARAM_LONG(port)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_ZVAL(callback)
|
||||
Z_PARAM_ZVAL(argument)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
PHP_ASIO_FUTURE_INIT();
|
||||
future->on_resolve<NOARG>(boost::bind(&socket::connect_handler, this, _1, cb, args));
|
||||
socket_.async_connect({ boost::asio::ip::address::from_string(ZSTR_VAL(address)),
|
||||
static_cast<unsigned short>(port) }, STRAND_RESOLVE(ASYNC_HANDLER_SINGLE_ARG));
|
||||
FUTURE_RETURN();
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto Future UnixSocket::connect(string path, [callable callback], [mixed argument]);
|
||||
* Asynchronously connect to a remote endpoint. */
|
||||
template <>
|
||||
P3_METHOD(unix_socket, connect)
|
||||
{
|
||||
zend_string* path;
|
||||
zval* callback = nullptr;
|
||||
zval* argument = nullptr;
|
||||
ZEND_PARSE_PARAMETERS_START(1, 3)
|
||||
Z_PARAM_STR(path)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_ZVAL(callback)
|
||||
Z_PARAM_ZVAL(argument)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
PHP_ASIO_FUTURE_INIT();
|
||||
future->on_resolve<NOARG>(boost::bind(&socket::connect_handler, this, _1, cb, args));
|
||||
socket_.async_connect({ ZSTR_VAL(path) }, STRAND_RESOLVE(ASYNC_HANDLER_SINGLE_ARG));
|
||||
FUTURE_RETURN();
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
template <typename Protocol> template <typename, typename>
|
||||
P3_METHOD(socket<Protocol>, read)
|
||||
{
|
||||
PHP_ASIO_READ(socket, socket_);
|
||||
}
|
||||
|
||||
template <typename Protocol> template <typename, typename>
|
||||
P3_METHOD(socket<Protocol>, write)
|
||||
{
|
||||
PHP_ASIO_WRITE(socket, socket_);
|
||||
}
|
||||
|
||||
template <typename Protocol> template <typename, typename>
|
||||
P3_METHOD(socket<Protocol>, recvFrom)
|
||||
{
|
||||
zend_long length;
|
||||
zval* callback = nullptr;
|
||||
zval* argument = nullptr;
|
||||
ZEND_PARSE_PARAMETERS_START(1, 3);
|
||||
Z_PARAM_LONG(length)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_ZVAL(callback)
|
||||
Z_PARAM_ZVAL(argument)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
PHP_ASIO_BUFFER_LEN_VALIDATE();
|
||||
auto buffer_container =
|
||||
#ifdef ENABLE_NULL_BUFFERS
|
||||
length == 0 ? ZSTR_EMPTY_ALLOC() :
|
||||
#endif //ENABLE_NULL_BUFFERS
|
||||
zend_string_alloc(static_cast<size_t>(length), 0);
|
||||
auto endpoint = new typename Protocol::endpoint;
|
||||
PHP_ASIO_FUTURE_INIT();
|
||||
future->template on_resolve<size_t>(boost::bind(&socket::recv_handler,
|
||||
this, _1, _2, buffer_container, endpoint, cb, args));
|
||||
#ifdef ENABLE_NULL_BUFFERS
|
||||
if (length == 0)
|
||||
socket_.async_receive_from(boost::asio::null_buffers(),
|
||||
*endpoint, STRAND_RESOLVE(ASYNC_HANDLER_DOUBLE_ARG(size_t)));
|
||||
else
|
||||
#endif // ENABLE_NULL_BUFFERS
|
||||
socket_.async_receive_from(mutable_buffer(buffer_container),
|
||||
*endpoint, STRAND_RESOLVE(ASYNC_HANDLER_DOUBLE_ARG(size_t)));
|
||||
FUTURE_RETURN();
|
||||
}
|
||||
|
||||
/* {{{ proto Future UdpSocket::sendTo(string data, string address, int port,
|
||||
* [callable callback], [mixed argument]);
|
||||
* Send asynchronously to UDP socket. */
|
||||
template <> template <>
|
||||
P3_METHOD(udp_socket, sendTo)
|
||||
{
|
||||
zend_string* data;
|
||||
zend_string* address;
|
||||
zend_long port;
|
||||
zval* callback = nullptr;
|
||||
zval* argument = nullptr;
|
||||
ZEND_PARSE_PARAMETERS_START(3, 5)
|
||||
Z_PARAM_STR(data)
|
||||
Z_PARAM_STR(address)
|
||||
Z_PARAM_LONG(port)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_ZVAL(callback)
|
||||
Z_PARAM_ZVAL(argument)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
const udp::endpoint endpoint(boost::asio::ip::address::from_string(ZSTR_VAL(address)),
|
||||
static_cast<unsigned short>(port));
|
||||
const auto buffer_container =
|
||||
#ifdef ENABLE_NULL_BUFFERS
|
||||
ZSTR_LEN(data) == 0 ? nullptr :
|
||||
#endif //ENABLE_NULL_BUFFERS
|
||||
zend_string_copy(data);
|
||||
PHP_ASIO_FUTURE_INIT();
|
||||
future->on_resolve<size_t>(boost::bind(&socket::write_handler,
|
||||
this, _1, _2, buffer_container, cb, args));
|
||||
#ifdef ENABLE_NULL_BUFFERS
|
||||
if (ZSTR_LEN(data) == 0)
|
||||
socket_.async_send_to(boost::asio::null_buffers(),
|
||||
endpoint, STRAND_RESOLVE(ASYNC_HANDLER_DOUBLE_ARG(size_t)));
|
||||
else
|
||||
#endif // ENABLE_NULL_BUFFERS
|
||||
socket_.async_send_to(const_buffer(buffer_container),
|
||||
endpoint, STRAND_RESOLVE(ASYNC_HANDLER_DOUBLE_ARG(size_t)));
|
||||
FUTURE_RETURN();
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto Future UdgSocket::sendTo(string data, string path,
|
||||
* [callable callback], [mixed argument]);
|
||||
* Send asynchronously to UNIX datagram socket. */
|
||||
template <> template <>
|
||||
P3_METHOD(udg_socket, sendTo)
|
||||
{
|
||||
zend_string* data;
|
||||
zend_string* path;
|
||||
zval* callback = nullptr;
|
||||
zval* argument = nullptr;
|
||||
ZEND_PARSE_PARAMETERS_START(2, 4)
|
||||
Z_PARAM_STR(data)
|
||||
Z_PARAM_STR(path)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_ZVAL(callback)
|
||||
Z_PARAM_ZVAL(argument)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
const auto buffer_container =
|
||||
#ifdef ENABLE_NULL_BUFFERS
|
||||
ZSTR_LEN(data) == 0 ? nullptr :
|
||||
#endif //ENABLE_NULL_BUFFERS
|
||||
zend_string_copy(data);
|
||||
PHP_ASIO_FUTURE_INIT();
|
||||
future->on_resolve<size_t>(boost::bind(
|
||||
&socket::write_handler, this, _1, _2, buffer_container, cb, args));
|
||||
#ifdef ENABLE_NULL_BUFFERS
|
||||
if (ZSTR_LEN(data) == 0)
|
||||
socket_.async_send_to(boost::asio::null_buffers(), { ZSTR_VAL(path) },
|
||||
STRAND_RESOLVE(ASYNC_HANDLER_DOUBLE_ARG(size_t)));
|
||||
else
|
||||
#endif //ENABLE_NULL_BUFFERS
|
||||
socket_.async_send_to(const_buffer(buffer_container), { ZSTR_VAL(path) },
|
||||
STRAND_RESOLVE(ASYNC_HANDLER_DOUBLE_ARG(size_t)));
|
||||
FUTURE_RETURN();
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
template <> template <>
|
||||
P3_METHOD(tcp_socket, remoteAddr) const
|
||||
{
|
||||
RETVAL_STRING(socket_.remote_endpoint().address().to_string().c_str());
|
||||
}
|
||||
|
||||
template <> template <>
|
||||
P3_METHOD(tcp_socket, remotePort) const
|
||||
{
|
||||
RETVAL_LONG(static_cast<zend_long>(socket_.remote_endpoint().port()));
|
||||
}
|
||||
|
||||
template <> template <>
|
||||
P3_METHOD(unix_socket, remotePath) const
|
||||
{
|
||||
RETVAL_STRING(socket_.remote_endpoint().path().c_str());
|
||||
}
|
||||
|
||||
template <> template <>
|
||||
P3_METHOD(udp_socket, remoteAddr) const
|
||||
{
|
||||
#ifdef ENABLE_COROUTINE
|
||||
RETVAL_STRING(last_addr_<>.data());
|
||||
#else
|
||||
PHP_ASIO_ERROR(E_WARNING, "Not available without coroutine support.");
|
||||
RETVAL_NULL();
|
||||
#endif // ENABLE_COROUTINE
|
||||
}
|
||||
|
||||
template <> template <>
|
||||
P3_METHOD(udp_socket, remotePort) const
|
||||
{
|
||||
#ifdef ENABLE_COROUTINE
|
||||
RETVAL_LONG(static_cast<zend_long>(last_port_<>));
|
||||
#else
|
||||
PHP_ASIO_ERROR(E_WARNING, "Not available without coroutine support.");
|
||||
RETVAL_NULL();
|
||||
#endif // ENABLE_COROUTINE
|
||||
}
|
||||
|
||||
template <> template <>
|
||||
P3_METHOD(udg_socket, remotePath) const
|
||||
{
|
||||
#ifdef ENABLE_COROUTINE
|
||||
RETVAL_STRING(last_path_<>.data());
|
||||
#else
|
||||
PHP_ASIO_ERROR(E_WARNING, "Not available without coroutine support.");
|
||||
RETVAL_NULL();
|
||||
#endif // ENABLE_COROUTINE
|
||||
}
|
||||
|
||||
template <typename Protocol>
|
||||
P3_METHOD(socket<Protocol>, available) const
|
||||
{
|
||||
zval* error = nullptr;
|
||||
ZEND_PARSE_PARAMETERS_START(0, 1)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_ZVAL(error)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
boost::system::error_code ec;
|
||||
auto bytes = socket_.available(ec);
|
||||
if (error) {
|
||||
ZVAL_DEREF(error);
|
||||
ZVAL_LONG(error, static_cast<zend_long>(ec.value()));
|
||||
}
|
||||
RETVAL_LONG(static_cast<zend_long>(bytes));
|
||||
}
|
||||
|
||||
template <typename Protocol>
|
||||
P3_METHOD(socket<Protocol>, atMark) const
|
||||
{
|
||||
zval* error = nullptr;
|
||||
ZEND_PARSE_PARAMETERS_START(0, 1)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_ZVAL(error)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
boost::system::error_code ec;
|
||||
auto at_mark = socket_.at_mark(ec);
|
||||
if (error) {
|
||||
ZVAL_DEREF(error);
|
||||
ZVAL_LONG(error, static_cast<zend_long>(ec.value()));
|
||||
}
|
||||
RETVAL_BOOL(at_mark);
|
||||
}
|
||||
|
||||
template <typename Protocol>
|
||||
P3_METHOD(socket<Protocol>, cancel)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
RETVAL_EC(socket_.cancel(ec));
|
||||
}
|
||||
|
||||
template <typename Protocol>
|
||||
P3_METHOD(socket<Protocol>, close)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
RETVAL_EC(socket_.close(ec));
|
||||
}
|
||||
|
||||
template <typename Protocol>
|
||||
zend_class_entry* socket<Protocol>::class_entry;
|
||||
|
||||
template <typename Protocol>
|
||||
zend_object_handlers socket<Protocol>::handlers;
|
||||
|
||||
#ifdef ENABLE_COROUTINE
|
||||
template <typename Protocol> template <typename, typename>
|
||||
thread_local std::string socket<Protocol>::last_addr_;
|
||||
|
||||
template <typename Protocol> template <typename, typename>
|
||||
thread_local unsigned short socket<Protocol>::last_port_;
|
||||
|
||||
template <typename Protocol> template <typename, typename>
|
||||
thread_local std::string socket<Protocol>::last_path_;
|
||||
#endif // ENABLE_COROUTINE
|
||||
|
||||
template class socket<tcp>;
|
||||
template P3_METHOD(tcp_socket, open_inet);
|
||||
template P3_METHOD(tcp_socket, assign_inet);
|
||||
template P3_METHOD(tcp_socket, bind_inet);
|
||||
template zval* tcp_socket::read_handler(const boost::system::error_code&,
|
||||
size_t, zend_string*, zval*, zval*);
|
||||
template P3_METHOD(tcp_socket, read);
|
||||
template P3_METHOD(tcp_socket, write);
|
||||
|
||||
template class socket<unix>;
|
||||
template P3_METHOD(unix_socket, open_local);
|
||||
template P3_METHOD(unix_socket, assign_local);
|
||||
template P3_METHOD(unix_socket, bind_local);
|
||||
template zval* unix_socket::read_handler(const boost::system::error_code&,
|
||||
size_t, zend_string*, zval*, zval*);
|
||||
template P3_METHOD(unix_socket, read);
|
||||
template P3_METHOD(unix_socket, write);
|
||||
|
||||
template class socket<udp>;
|
||||
template P3_METHOD(udp_socket, open_inet);
|
||||
template P3_METHOD(udp_socket, assign_inet);
|
||||
template P3_METHOD(udp_socket, bind_inet);
|
||||
template P3_METHOD(udp_socket, recvFrom);
|
||||
|
||||
template class socket<udg>;
|
||||
template P3_METHOD(udg_socket, open_local);
|
||||
template P3_METHOD(udg_socket, assign_local);
|
||||
template P3_METHOD(udg_socket, bind_local);
|
||||
template P3_METHOD(udg_socket, recvFrom);
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
/**
|
||||
* php-asio/socket.hpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.hpp"
|
||||
#include "base.hpp"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#define ENABLE_IF_INET(P) std::string(P::endpoint::*port)()
|
||||
#define ENABLE_IF_LOCAL(P) std::string(P::endpoint::*path)()
|
||||
|
||||
namespace asio
|
||||
{
|
||||
/// Wrapper for Boost.Asio socket.
|
||||
template <typename Protocol>
|
||||
class socket : public base
|
||||
{
|
||||
/// Boost.Asio socket instance.
|
||||
typename Protocol::socket socket_;
|
||||
|
||||
template <typename T1, typename T2>
|
||||
using enable_if_same = std::enable_if_t<std::is_same<T1, T2>::value>;
|
||||
|
||||
#ifdef ENABLE_COROUTINE
|
||||
/// Address of client who sent the last request.
|
||||
template <typename P = Protocol, typename = enable_if_same<P, udp>>
|
||||
static thread_local std::string last_addr_;
|
||||
|
||||
/// Port of client who sent the last request.
|
||||
template <typename P = Protocol, typename = enable_if_same<P, udp>>
|
||||
static thread_local unsigned short last_port_;
|
||||
|
||||
/// Socket path of client who sent the last request.
|
||||
template <typename P = Protocol, typename = enable_if_same<P, udg>>
|
||||
static thread_local std::string last_path_;
|
||||
#endif // ENABLE_COROUTINE
|
||||
|
||||
/// Connect handler.
|
||||
zval* connect_handler(const boost::system::error_code& error,
|
||||
zval* callback, zval* argument);
|
||||
|
||||
/// Read handler for stream socket.
|
||||
template <typename P = Protocol, typename =
|
||||
enable_if_same<boost::asio::basic_stream_socket<P>, typename P::socket>>
|
||||
zval* read_handler(const boost::system::error_code& error,
|
||||
size_t length, zend_string* buffer, zval* callback, zval* argument);
|
||||
|
||||
/// Write/send handler for socket.
|
||||
zval* write_handler(const boost::system::error_code& error,
|
||||
size_t length, zend_string* buffer, zval* callback, zval* argument);
|
||||
|
||||
/// Receive handler for datagram socket.
|
||||
zval* recv_handler(const boost::system::error_code& error, size_t length,
|
||||
zend_string* buffer, typename Protocol::endpoint* endpoint,
|
||||
zval* callback, zval* argument);
|
||||
|
||||
public:
|
||||
/// Constructor.
|
||||
explicit socket(
|
||||
boost::asio::io_service& io_service
|
||||
) : base(io_service), socket_(io_service) {}
|
||||
|
||||
/// Get reference of socket.
|
||||
typename Protocol::socket& get_socket()
|
||||
{
|
||||
return socket_;
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
using inet_p = typename P::endpoint::port;
|
||||
|
||||
/* {{{ proto int InetSocket::open(bool inet6);
|
||||
* Open INET socket (AF_INET or AF_INET6). */
|
||||
template <typename P = Protocol, ENABLE_IF_INET(P) = nullptr>
|
||||
P3_METHOD_DECLARE(open_inet);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int LocalSocket::open(void);
|
||||
* Open UNIX domain socket. */
|
||||
template <typename P = Protocol, ENABLE_IF_LOCAL(P) = nullptr>
|
||||
P3_METHOD_DECLARE(open_local);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int InetSocket::assign(bool inet6, int|resource fd);
|
||||
* Assign an existing native socket to the socket. */
|
||||
template <typename P = Protocol, ENABLE_IF_INET(P) = nullptr>
|
||||
P3_METHOD_DECLARE(assign_inet);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int LocalSocket::assign(int|resource fd);
|
||||
* Assign an existing native socket to the socket. */
|
||||
template <typename P = Protocol, ENABLE_IF_LOCAL(P) = nullptr>
|
||||
P3_METHOD_DECLARE(assign_local);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int InetSocket::bind(string address, int port);
|
||||
* Bind socket to a local endpoint (AF_INET or AF_INET6). */
|
||||
template <typename P = Protocol, ENABLE_IF_INET(P) = nullptr>
|
||||
P3_METHOD_DECLARE(bind_inet);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int LocalSocket::bind(string path);
|
||||
* Bind socket to a local endpoint (AF_UNIX). */
|
||||
template <typename P = Protocol, ENABLE_IF_LOCAL(P) = nullptr>
|
||||
P3_METHOD_DECLARE(bind_local);
|
||||
/* }}} */
|
||||
|
||||
P3_METHOD_DECLARE(connect);
|
||||
|
||||
/* {{{ proto Future StreamSocket::read(int length, [bool read_some = true],
|
||||
* [callable callback], [mixed argument]);
|
||||
* Read asynchronously from stream socket. */
|
||||
template <typename P = Protocol, typename =
|
||||
enable_if_same<boost::asio::basic_stream_socket<P>, typename P::socket>>
|
||||
P3_METHOD_DECLARE(read);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto Future StreamSocket::write(string data, [bool write_some = false],
|
||||
* [callable callback], [mixed argument]);
|
||||
* Write asynchronously to stream socket. */
|
||||
template <typename P = Protocol, typename =
|
||||
enable_if_same<boost::asio::basic_stream_socket<P>, typename P::socket>>
|
||||
P3_METHOD_DECLARE(write);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto Future DatagramSocket::recvFrom(int length,
|
||||
* [callable callback], [mixed argument]);
|
||||
* Receive asynchronously from datagram socket.*/
|
||||
template <typename P = Protocol, typename =
|
||||
enable_if_same<boost::asio::basic_datagram_socket<P>, typename P::socket>>
|
||||
P3_METHOD_DECLARE(recvFrom);
|
||||
/* }}} */
|
||||
|
||||
template <typename P = Protocol, typename =
|
||||
enable_if_same<boost::asio::basic_datagram_socket<P>, typename P::socket>>
|
||||
P3_METHOD_DECLARE(sendTo);
|
||||
|
||||
/* {{{ proto string InetSocket::remoteAddr(void);
|
||||
* Get remote address (AF_INET or AF_INET6). */
|
||||
template <typename P = Protocol, ENABLE_IF_INET(P) = nullptr>
|
||||
P3_METHOD_DECLARE(remoteAddr) const;
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int InetSocket::remotePort(void);
|
||||
* Get remote port (AF_INET or AF_INET6). */
|
||||
template <typename P = Protocol, ENABLE_IF_INET(P) = nullptr>
|
||||
P3_METHOD_DECLARE(remotePort) const;
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto string LocalSocket::remotePath(void);
|
||||
* Get socket file path of remote endpoint (AF_UNIX). */
|
||||
template <typename P = Protocol, ENABLE_IF_LOCAL(P) = nullptr>
|
||||
P3_METHOD_DECLARE(remotePath) const;
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int Socket::available([int &ec]);
|
||||
* Determine the number of bytes available for reading. */
|
||||
P3_METHOD_DECLARE(available) const;
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto bool Socket::atMark([int &ec]);
|
||||
* Determine whether the socket is at the out-of-band data mark. */
|
||||
P3_METHOD_DECLARE(atMark) const;
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int Socket::cancel(void);
|
||||
* Cancel all asynchronous operations on the socket. */
|
||||
P3_METHOD_DECLARE(cancel);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int Socket::close(void);
|
||||
* Close the socket. */
|
||||
P3_METHOD_DECLARE(close);
|
||||
/* }}} */
|
||||
|
||||
PHP_ASIO_CE_DECLARE();
|
||||
};
|
||||
|
||||
using tcp_socket = socket<tcp>;
|
||||
using unix_socket = socket<unix>;
|
||||
using udp_socket = socket<udp>;
|
||||
using udg_socket = socket<udg>;
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* php-asio/strand.cpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#include "strand.hpp"
|
||||
#include "future.hpp"
|
||||
|
||||
#ifdef ENABLE_STRAND
|
||||
|
||||
#define STRAND_DISPATCH_CALLBACK(meth) \
|
||||
PHP_ASIO_DISPATCH_CALLBACK(meth) PHP_ASIO_DEC_HANDLER_COUNT(); })
|
||||
|
||||
namespace asio
|
||||
{
|
||||
P3_METHOD(strand, dispatch)
|
||||
{
|
||||
PHP_ASIO_INC_HANDLER_COUNT();
|
||||
STRAND_DISPATCH_CALLBACK(strand_.dispatch);
|
||||
}
|
||||
|
||||
P3_METHOD(strand, post)
|
||||
{
|
||||
PHP_ASIO_INC_HANDLER_COUNT();
|
||||
STRAND_DISPATCH_CALLBACK(strand_.post);
|
||||
}
|
||||
|
||||
P3_METHOD(strand, runningInThisThread) const
|
||||
{
|
||||
RETVAL_BOOL(strand_.running_in_this_thread());
|
||||
}
|
||||
|
||||
P3_METHOD(strand, wrap)
|
||||
{
|
||||
zval* callback;
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||
Z_PARAM_ZVAL(callback)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
PHP_ASIO_INC_HANDLER_COUNT();
|
||||
RETVAL_OBJ(p3::alloc_object<wrapped_handler>(wrapped_handler::class_entry,
|
||||
[this, callback](wrapped_handler* ptr) {
|
||||
new(ptr) wrapped_handler(this, callback);
|
||||
}));
|
||||
}
|
||||
|
||||
PHP_ASIO_CE_DEFINE(strand);
|
||||
}
|
||||
|
||||
#endif // ENABLE_STRAND
|
|
@ -0,0 +1,87 @@
|
|||
/**
|
||||
* php-asio/strand.hpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.hpp"
|
||||
#include "base.hpp"
|
||||
|
||||
#define PHP_ASIO_DISPATCH_CALLBACK(meth) \
|
||||
zval* callback; \
|
||||
zval* argument = nullptr; \
|
||||
ZEND_PARSE_PARAMETERS_START(1, 2) \
|
||||
Z_PARAM_ZVAL(callback) \
|
||||
Z_PARAM_OPTIONAL \
|
||||
Z_PARAM_ZVAL(argument) \
|
||||
ZEND_PARSE_PARAMETERS_END(); \
|
||||
ZVAL_PTR_INIT(cb); \
|
||||
ZVAL_COPY(cb, callback); \
|
||||
ZVAL_PTR_INIT(args); \
|
||||
if (argument) \
|
||||
ZVAL_COPY(args, argument); \
|
||||
else \
|
||||
ZVAL_NULL(args); \
|
||||
meth([this, cb, args]() { \
|
||||
INIT_RETVAL(); \
|
||||
call_user_function(CG(function_table), nullptr, cb, PASS_RETVAL, 1, args); \
|
||||
CORO_REGISTER(retval); \
|
||||
zval_ptr_dtor(cb); \
|
||||
zval_ptr_dtor(args); \
|
||||
efree(cb); \
|
||||
efree(args); \
|
||||
|
||||
#ifdef ENABLE_STRAND
|
||||
namespace asio
|
||||
{
|
||||
/// Wrapper for Boost.Asio strand.
|
||||
/// Provides serialized handler execution.
|
||||
class strand : public base
|
||||
{
|
||||
/// Boost.Asio strand instance.
|
||||
boost::asio::strand strand_;
|
||||
|
||||
public:
|
||||
/// Constructor.
|
||||
explicit strand(
|
||||
boost::asio::io_service& io_service
|
||||
) : base(io_service), strand_(io_service) {}
|
||||
|
||||
/// Deleted default constructor.
|
||||
strand() = delete;
|
||||
|
||||
/// Deleted copy constructor.
|
||||
strand(const strand&) = delete;
|
||||
|
||||
/* {{{ proto void Strand::dispatch(callable callback, [mixed argument]);
|
||||
* Request the strand to invoke the given handler. */
|
||||
P3_METHOD_DECLARE(dispatch);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto void Strand::post(callable callback, [mixed argument]);
|
||||
* Request the strand to invoke the given handler. */
|
||||
P3_METHOD_DECLARE(post);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto bool Strand::runningInThisThread(void);
|
||||
* Determine whether the strand is running in the current thread. */
|
||||
P3_METHOD_DECLARE(runningInThisThread) const;
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto WrappedHandler wrap([callable callback]);
|
||||
* Create a new handler that automatically dispatches the wrapped handler on the strand. */
|
||||
P3_METHOD_DECLARE(wrap);
|
||||
/* }}} */
|
||||
|
||||
/// Returns the wrapped Boost.Asio strand.
|
||||
boost::asio::strand* implmentation()
|
||||
{
|
||||
return &strand_;
|
||||
}
|
||||
|
||||
PHP_ASIO_CE_DECLARE();
|
||||
};
|
||||
}
|
||||
#endif // ENABLE_STRAND
|
|
@ -0,0 +1,86 @@
|
|||
/**
|
||||
* php-asio/stream_descriptor.cpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#include "stream_descriptor.hpp"
|
||||
#include "future.hpp"
|
||||
#include "io.hpp"
|
||||
|
||||
namespace asio
|
||||
{
|
||||
zval* stream_descriptor::read_handler(const boost::system::error_code& error,
|
||||
size_t length, zend_string* buffer, zval* callback, zval* argument)
|
||||
{
|
||||
ZSTR_VAL(buffer)[length] = '\0';
|
||||
ZSTR_LEN(buffer) = length;
|
||||
PHP_ASIO_INVOKE_CALLBACK_START(4)
|
||||
ZVAL_STR(&arguments[1], buffer);
|
||||
PHP_ASIO_INVOKE_CALLBACK();
|
||||
PHP_ASIO_INVOKE_CALLBACK_END();
|
||||
CORO_RETURN(ZVAL_STR, buffer);
|
||||
}
|
||||
|
||||
zval* stream_descriptor::write_handler(const boost::system::error_code& error,
|
||||
size_t length, zend_string* buffer, zval* callback, zval* argument)
|
||||
{
|
||||
#ifdef ENABLE_NULL_BUFFERS
|
||||
if (buffer)
|
||||
#endif //ENABLE_NULL_BUFFERS
|
||||
zend_string_release(buffer);
|
||||
PHP_ASIO_INVOKE_CALLBACK_START(4)
|
||||
ZVAL_LONG(&arguments[1], static_cast<zend_long>(length));
|
||||
PHP_ASIO_INVOKE_CALLBACK();
|
||||
PHP_ASIO_INVOKE_CALLBACK_END();
|
||||
CORO_RETURN(ZVAL_LONG, static_cast<zend_long>(length));
|
||||
}
|
||||
|
||||
P3_METHOD(stream_descriptor, assign)
|
||||
{
|
||||
zval* fd;
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||
Z_PARAM_ZVAL(fd)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
boost::system::error_code ec;
|
||||
if (UNEXPECTED(Z_TYPE_P(fd) == IS_LONG))
|
||||
stream_descriptor_.assign(Z_LVAL_P(fd), ec);
|
||||
else
|
||||
stream_descriptor_.assign(resource_to_fd(fd), ec);
|
||||
RETVAL_EC(ec);
|
||||
}
|
||||
|
||||
P3_METHOD(stream_descriptor, isOpen)
|
||||
{
|
||||
RETVAL_BOOL(stream_descriptor_.is_open());
|
||||
}
|
||||
|
||||
P3_METHOD(stream_descriptor, read)
|
||||
{
|
||||
PHP_ASIO_READ(stream_descriptor, stream_descriptor_);
|
||||
}
|
||||
|
||||
P3_METHOD(stream_descriptor, write)
|
||||
{
|
||||
PHP_ASIO_WRITE(stream_descriptor, stream_descriptor_);
|
||||
}
|
||||
|
||||
P3_METHOD(stream_descriptor, release)
|
||||
{
|
||||
stream_descriptor_.release();
|
||||
}
|
||||
|
||||
P3_METHOD(stream_descriptor, cancel)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
RETVAL_EC(stream_descriptor_.cancel(ec));
|
||||
}
|
||||
|
||||
P3_METHOD(stream_descriptor, close)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
RETVAL_EC(stream_descriptor_.close(ec));
|
||||
}
|
||||
|
||||
PHP_ASIO_CE_DEFINE(stream_descriptor);
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* php-asio/stream_descriptor.hpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.hpp"
|
||||
#include "base.hpp"
|
||||
|
||||
namespace asio
|
||||
{
|
||||
/// Wrapper for Boost.Asio stream descriptor.
|
||||
class stream_descriptor : public base
|
||||
{
|
||||
/// Boost.Asio stream descriptor instance.
|
||||
boost::asio::posix::stream_descriptor stream_descriptor_;
|
||||
|
||||
/// Read handler for stream descriptor.
|
||||
zval* read_handler(const boost::system::error_code& error,
|
||||
size_t length, zend_string* buffer, zval* callback, zval* argument);
|
||||
|
||||
/// Write handler for socket.
|
||||
zval* write_handler(const boost::system::error_code& error,
|
||||
size_t length, zend_string* buffer, zval* callback, zval* argument);
|
||||
|
||||
public:
|
||||
/// Constructor.
|
||||
explicit stream_descriptor(
|
||||
boost::asio::io_service& io_service
|
||||
) : base(io_service), stream_descriptor_(io_service) {}
|
||||
|
||||
/* {{{ proto int StreamDescriptor::bind(int|resource fd);
|
||||
* Opens the descriptor to hold an existing native descriptor. */
|
||||
P3_METHOD_DECLARE(assign);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto bool StreamDescriptor::isOpen(void);
|
||||
* Determine whether the descriptor is open. */
|
||||
P3_METHOD_DECLARE(isOpen);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto Future StreamDescriptor::read(int length, [bool read_some = true],
|
||||
* [callable callback], [mixed argument]);
|
||||
* Read asynchronously from stream descriptor. */
|
||||
P3_METHOD_DECLARE(read);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto Future StreamDescriptor::write(string data, [bool write_some = false],
|
||||
* [callable callback], [mixed argument]);
|
||||
* Write asynchronously to stream socket. */
|
||||
P3_METHOD_DECLARE(write);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto void StreamDescriptor::release(void);
|
||||
* Release ownership of the native descriptor implementation. */
|
||||
P3_METHOD_DECLARE(release);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int StreamDescriptor::cancel(void);
|
||||
* Cancel all asynchronous operations on the descriptor. */
|
||||
P3_METHOD_DECLARE(cancel);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int StreamDescriptor::close(void);
|
||||
* Close the descriptor. */
|
||||
P3_METHOD_DECLARE(close);
|
||||
/* }}} */
|
||||
|
||||
PHP_ASIO_CE_DECLARE();
|
||||
};
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/**
|
||||
* php-asio/timer.cpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#include <boost/date_time.hpp>
|
||||
|
||||
#include "timer.hpp"
|
||||
#include "future.hpp"
|
||||
|
||||
namespace asio
|
||||
{
|
||||
zval* timer::handler(const boost::system::error_code& error,
|
||||
zval* callback, zval* argument)
|
||||
{
|
||||
PHP_ASIO_INVOKE_CALLBACK_START(3)
|
||||
PHP_ASIO_INVOKE_CALLBACK();
|
||||
PHP_ASIO_INVOKE_CALLBACK_END();
|
||||
CORO_RETURN_NULL();
|
||||
}
|
||||
|
||||
P3_METHOD(timer, expiresFromNow)
|
||||
{
|
||||
zend_long duration;
|
||||
ZEND_PARSE_PARAMETERS_START(1, 2)
|
||||
Z_PARAM_LONG(duration)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
boost::system::error_code ec;
|
||||
timer_.expires_from_now(boost::posix_time::millisec(duration), ec);
|
||||
RETVAL_EC(ec);
|
||||
}
|
||||
|
||||
P3_METHOD(timer, expiresAt)
|
||||
{
|
||||
zend_long timestamp;
|
||||
ZEND_PARSE_PARAMETERS_START(1, 2)
|
||||
Z_PARAM_LONG(timestamp)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
boost::system::error_code ec;
|
||||
timer_.expires_at(boost::posix_time::from_time_t(timestamp / 1000) +
|
||||
boost::posix_time::millisec(timestamp % 1000), ec);
|
||||
RETVAL_EC(ec);
|
||||
}
|
||||
|
||||
P3_METHOD(timer, wait)
|
||||
{
|
||||
zval* callback = nullptr;
|
||||
zval* argument = nullptr;
|
||||
ZEND_PARSE_PARAMETERS_START(0, 2)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_ZVAL(callback)
|
||||
Z_PARAM_ZVAL(argument)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
PHP_ASIO_FUTURE_INIT();
|
||||
future->on_resolve<NOARG>(boost::bind(&timer::handler, this, _1, cb, args));
|
||||
timer_.async_wait(STRAND_RESOLVE(ASYNC_HANDLER_SINGLE_ARG));
|
||||
FUTURE_RETURN();
|
||||
}
|
||||
|
||||
P3_METHOD(timer, cancel)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
timer_.cancel(ec);
|
||||
RETVAL_EC(ec);
|
||||
}
|
||||
|
||||
PHP_ASIO_CE_DEFINE(timer);
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
* php-asio/timer.hpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.hpp"
|
||||
#include "base.hpp"
|
||||
|
||||
namespace asio
|
||||
{
|
||||
/// Wrapper for Boost.Asio deadline timer.
|
||||
class timer : public base
|
||||
{
|
||||
/// Boost.Asio timer instance.
|
||||
boost::asio::deadline_timer timer_;
|
||||
|
||||
/// Handler for timer callback.
|
||||
zval* handler(const boost::system::error_code& error,
|
||||
zval* callback, zval* argument);
|
||||
|
||||
public:
|
||||
/// Constructor.
|
||||
explicit timer(
|
||||
boost::asio::io_service& io_service
|
||||
) : base(io_service), timer_(io_service) {}
|
||||
|
||||
/* {{{ proto int Timer::expiresFromNow(int duration);
|
||||
* Set the timer's expiry time relative to now. */
|
||||
P3_METHOD_DECLARE(expiresFromNow);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int Timer::expiresFromNow(int timestamp);
|
||||
* Set the timer's expiry time as an absolute time. */
|
||||
P3_METHOD_DECLARE(expiresAt);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto Future Timer::wait([callable callback], [mixed argument]);
|
||||
* Initiate an asynchronous wait against the timer. */
|
||||
P3_METHOD_DECLARE(wait);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int Timer::cancel(void);
|
||||
* Cancel timer. */
|
||||
P3_METHOD_DECLARE(cancel);
|
||||
/* }}} */
|
||||
|
||||
PHP_ASIO_CE_DECLARE();
|
||||
};
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
/**
|
||||
* php-asio/wrapped_handler.cpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#include "wrapped_handler.hpp"
|
||||
|
||||
#ifdef ENABLE_STRAND
|
||||
namespace asio
|
||||
{
|
||||
PHP_ASIO_CE_DEFINE(wrapped_handler);
|
||||
}
|
||||
#endif // ENABLE_STRAND
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* php-asio/wrapped_handler.hpp
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.hpp"
|
||||
#include "strand.hpp"
|
||||
|
||||
#ifdef ENABLE_STRAND
|
||||
namespace asio
|
||||
{
|
||||
/// Async handler callback wrapped by strand.
|
||||
class wrapped_handler
|
||||
{
|
||||
/// Strand object for this wrapped handler.
|
||||
strand* strand_;
|
||||
|
||||
/// Wrapped handler callback.
|
||||
zval* callback_;
|
||||
|
||||
// Future has access to Strand and handler callback.
|
||||
friend class future;
|
||||
|
||||
public:
|
||||
/// Constructor.
|
||||
explicit wrapped_handler(
|
||||
strand* strand, zval* callback
|
||||
) : strand_(strand), callback_(callback)
|
||||
{
|
||||
GC_ADDREF(Z_COUNTED_P(callback_));
|
||||
}
|
||||
|
||||
/// Deleted default constructor.
|
||||
wrapped_handler() = delete;
|
||||
|
||||
/// Deleted copy constructor.
|
||||
wrapped_handler(const wrapped_handler&) = delete;
|
||||
|
||||
/// Make this object callable.
|
||||
P3_METHOD_DECLARE(__invoke) {}
|
||||
|
||||
PHP_ASIO_CE_DECLARE();
|
||||
};
|
||||
}
|
||||
#endif // ENABLE_STRAND
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
/**
|
||||
* php-asio/stubs/Acceptor.php
|
||||
*
|
||||
* This file is a stub of php-asio, which is implemented in extension asio.so.
|
||||
* For source code of asio.so, see src/ directory.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
namespace Asio;
|
||||
|
||||
/**
|
||||
* Interface Acceptor
|
||||
*
|
||||
* @package Asio
|
||||
*/
|
||||
interface Acceptor extends IoObject
|
||||
{
|
||||
/**
|
||||
* Put the acceptor into the state where it may accept new connections.
|
||||
*
|
||||
* @param int $backlog[optional] : The maximum length of the queue of pending connections.
|
||||
* Default to `boost::asio::socket_base::max_connections`.
|
||||
* @return int : Error code
|
||||
*/
|
||||
function listen(int $backlog);
|
||||
|
||||
/**
|
||||
* Asynchronously accept a new connection into a socket.
|
||||
*
|
||||
* @param callable $callback[optional] : Acceptor callback
|
||||
* @param mixed $argument
|
||||
* @return Future : Resolves Socket.
|
||||
*/
|
||||
function accept(callable $callback, $argument = null);
|
||||
|
||||
/**
|
||||
* Close the acceptor.
|
||||
*
|
||||
* @return int : Error code
|
||||
*/
|
||||
function close();
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
/**
|
||||
* php-asio/stubs/DatagramSocket.php
|
||||
*
|
||||
* This file is a stub of php-asio, which is implemented in extension asio.so.
|
||||
* For source code of asio.so, see src/ directory.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
namespace Asio;
|
||||
|
||||
/**
|
||||
* Interface DatagramSocket
|
||||
*
|
||||
* @package Asio
|
||||
*/
|
||||
interface DatagramSocket extends Socket
|
||||
{
|
||||
/**
|
||||
* Receive asynchronously from datagram socket.
|
||||
*
|
||||
* @param int $length
|
||||
* @param callable $callback[optional] : Receive handler callback
|
||||
* @param mixed $argument
|
||||
* @return Future
|
||||
*/
|
||||
function recvFrom(int $length, callable $callback, $argument = null);
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
/**
|
||||
* php-asio/stubs/Future.php
|
||||
*
|
||||
* This file is a stub of php-asio, which is implemented in extension asio.so.
|
||||
* For source code of asio.so, see src/ directory.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
namespace Asio;
|
||||
|
||||
/**
|
||||
* Class Future
|
||||
*
|
||||
* When an asynchronous operation completes, its Future will be resolved,
|
||||
* resuming the corresponding coroutine (if Future was yielded by a Generator).
|
||||
*
|
||||
* @package Asio
|
||||
*/
|
||||
final class Future
|
||||
{
|
||||
/**
|
||||
* This class can only be instantiated by asynchronous operations.
|
||||
*/
|
||||
private function __construct() {}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
/**
|
||||
* php-asio/stubs/InetSocket.php
|
||||
*
|
||||
* This file is a stub of php-asio, which is implemented in extension asio.so.
|
||||
* For source code of asio.so, see src/ directory.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
namespace Asio;
|
||||
|
||||
/**
|
||||
* Interface InetSocket
|
||||
*
|
||||
* @package Asio
|
||||
*/
|
||||
interface InetSocket extends Socket
|
||||
{
|
||||
/**
|
||||
* Open socket.
|
||||
*
|
||||
* @param bool $inet6 : True for AF_INET6, false for AF_INET
|
||||
* @return int : Error code
|
||||
*/
|
||||
function open(bool $inet6);
|
||||
|
||||
/**
|
||||
* Assign an existing native socket to the socket.
|
||||
*
|
||||
* @param bool $inet6
|
||||
* @param int|resource $native_handle
|
||||
* @return int : Error code
|
||||
*/
|
||||
function assign(bool $inet6, $native_handle);
|
||||
|
||||
/**
|
||||
* Bind socket to a local endpoint.
|
||||
*
|
||||
* @param string $address
|
||||
* @param int $port
|
||||
* @return int : Error code
|
||||
*/
|
||||
function bind(string $address, int $port);
|
||||
|
||||
/**
|
||||
* Get remote endpoint address.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function remoteAddr();
|
||||
|
||||
/**
|
||||
* Get remote endpoint port.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function remotePort();
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/**
|
||||
* php-asio/stubs/IoObject.php
|
||||
*
|
||||
* This file is a stub of php-asio, which is implemented in extension asio.so.
|
||||
* For source code of asio.so, see src/ directory.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
namespace Asio;
|
||||
|
||||
/**
|
||||
* Interface IoObject
|
||||
*
|
||||
* Base class of all I/O objects.
|
||||
*
|
||||
* @package Asio
|
||||
*/
|
||||
interface IoObject
|
||||
{
|
||||
/**
|
||||
* Cancel all asynchronous operations on this I/O object.
|
||||
*
|
||||
* @return int : Error code
|
||||
*/
|
||||
function cancel();
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
/**
|
||||
* php-asio/stubs/LocalSocket.php
|
||||
*
|
||||
* This file is a stub of php-asio, which is implemented in extension asio.so.
|
||||
* For source code of asio.so, see src/ directory.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
namespace Asio;
|
||||
|
||||
/**
|
||||
* Interface LocalSocket
|
||||
*
|
||||
* @package Asio
|
||||
*/
|
||||
interface LocalSocket extends Socket
|
||||
{
|
||||
/**
|
||||
* Open socket.
|
||||
*
|
||||
* @return int : Error code
|
||||
*/
|
||||
function open();
|
||||
|
||||
/**
|
||||
* Assign an existing native socket to the socket.
|
||||
*
|
||||
* @param int|resource $native_handle
|
||||
* @return int : Error code
|
||||
*/
|
||||
function assign($native_handle);
|
||||
|
||||
/**
|
||||
* Bind socket to a local endpoint.
|
||||
*
|
||||
* @param string $path : Path to socket file
|
||||
* @return mixed
|
||||
*/
|
||||
function bind(string $path);
|
||||
|
||||
/**
|
||||
* Get remote endpoint path.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function remotePath();
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
/**
|
||||
* php-asio/stubs/Resolver.php
|
||||
*
|
||||
* This file is a stub of php-asio, which is implemented in extension asio.so.
|
||||
* For source code of asio.so, see src/ directory.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
namespace Asio;
|
||||
|
||||
/**
|
||||
* Interface Resolver
|
||||
*
|
||||
* @package Asio
|
||||
*/
|
||||
interface Resolver extends IoObject
|
||||
{
|
||||
/**
|
||||
* Initiate an asynchronous resolve against the resolver.
|
||||
*
|
||||
* @param string $host : Host name
|
||||
* @param string $service
|
||||
* @param callable $callback[optional] : Resolver callback
|
||||
* @param mixed $argument
|
||||
* @return Future
|
||||
*/
|
||||
function resolve(string $host, string $service = '', callable $callback, $argument = null);
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
<?php
|
||||
/**
|
||||
* php-asio/stubs/Service.php
|
||||
*
|
||||
* This file is a stub of php-asio, which is implemented in extension asio.so.
|
||||
* For source code of asio.so, see src/ directory.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
namespace Asio;
|
||||
|
||||
/**
|
||||
* Class Service
|
||||
*
|
||||
* Provide access to instantiation of I/O objects.
|
||||
*
|
||||
* @package Asio
|
||||
*/
|
||||
class Service
|
||||
{
|
||||
/**
|
||||
* Add a new timer.
|
||||
*
|
||||
* @return Timer
|
||||
*/
|
||||
function addTimer() {}
|
||||
|
||||
/**
|
||||
* Add a new TCP acceptor.
|
||||
*
|
||||
* @return TcpAcceptor
|
||||
*/
|
||||
function addTcpAcceptor() {}
|
||||
|
||||
/**
|
||||
* Add a new UNIX domain socket acceptor (SOCK_STREAM).
|
||||
*
|
||||
* @return UnixAcceptor
|
||||
*/
|
||||
function addUnixAcceptor() {}
|
||||
|
||||
/**
|
||||
* Add a TCP resolver.
|
||||
*
|
||||
* @return TcpResolver
|
||||
*/
|
||||
function addTcpResolver() {}
|
||||
|
||||
/**
|
||||
* Add a UDP resolver.
|
||||
*
|
||||
* @return UdpResolver
|
||||
*/
|
||||
function addUdpResolver() {}
|
||||
|
||||
/**
|
||||
* Add a new TCP socket.
|
||||
*
|
||||
* @return TcpSocket
|
||||
*/
|
||||
function addTcpSocket() {}
|
||||
|
||||
/**
|
||||
* Add a new UDP socket.
|
||||
*
|
||||
* @return UdpSocket
|
||||
*/
|
||||
function addUdpSocket() {}
|
||||
|
||||
/**
|
||||
* Add a new UNIX domain socket (SOCK_STREAM).
|
||||
*
|
||||
* @return UnixSocket
|
||||
*/
|
||||
function addUnixSocket() {}
|
||||
|
||||
/**
|
||||
* Add a new UNIX domain socket (SOCK_DGRAM).
|
||||
*
|
||||
* @return UdgSocket
|
||||
*/
|
||||
function addUdgSocket() {}
|
||||
|
||||
/**
|
||||
* Add new signal set.
|
||||
*
|
||||
* @return Signal
|
||||
*/
|
||||
function addSignal() {}
|
||||
|
||||
/**
|
||||
* Add new stream descriptor.
|
||||
*
|
||||
* @return StreamDescriptor
|
||||
*/
|
||||
function addStreamDescriptor() {}
|
||||
|
||||
/**
|
||||
* Add new strand.
|
||||
*
|
||||
* @return Strand
|
||||
*/
|
||||
function addStrand() {}
|
||||
|
||||
/**
|
||||
* Run the event loop until stopped or no more work.
|
||||
*
|
||||
* @param int $ec[optional] : Error code
|
||||
* @return int : The number of handlers executed
|
||||
*/
|
||||
function run(int &$ec) {}
|
||||
|
||||
/**
|
||||
* Run until stopped or one operation is performed.
|
||||
*
|
||||
* @param int $ec[optional] : Error code
|
||||
* @return int : The number of handlers executed
|
||||
*/
|
||||
function runOne(int &$ec) {}
|
||||
|
||||
/**
|
||||
* Poll for operations without blocking.
|
||||
*
|
||||
* @param int $ec[optional] : Error code
|
||||
* @return int : The number of handlers executed
|
||||
*/
|
||||
function poll(int &$ec) {}
|
||||
|
||||
/**
|
||||
* Poll for one operation without blocking.
|
||||
*
|
||||
* @param int $ec[optional] : Error code
|
||||
* @return int : The number of handlers executed
|
||||
*/
|
||||
function pollOne(int &$ec) {}
|
||||
|
||||
/**
|
||||
* Request invocation of the given handler and return immediately.
|
||||
*
|
||||
* @param callable $callback
|
||||
* @param mixed $argument
|
||||
* @return int : The number of handlers executed
|
||||
*/
|
||||
function post(callable $callback, $argument = null) {}
|
||||
|
||||
/**
|
||||
* Request invocation of the given handler.
|
||||
*
|
||||
* @param callable $callback
|
||||
* @param mixed $argument
|
||||
* @return int : The number of handlers executed
|
||||
*/
|
||||
function dispatch(callable $callback, $argument = null) {}
|
||||
|
||||
/**
|
||||
* Notify all services of a fork event. (prepare to fork)
|
||||
*
|
||||
* @return int : Error code
|
||||
*/
|
||||
function forkPrepare() {}
|
||||
|
||||
/**
|
||||
* Notify all services of a fork event. (fork parent)
|
||||
*
|
||||
* @return int : Error code
|
||||
*/
|
||||
function forkParent() {}
|
||||
|
||||
/**
|
||||
* Notify all services of a fork event. (fork child)
|
||||
*
|
||||
* @return int : Error code
|
||||
*/
|
||||
function forkChild() {}
|
||||
|
||||
/**
|
||||
* Stop the event processing loop.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function stop() {}
|
||||
|
||||
/**
|
||||
* Reset in preparation for a subsequent run invocation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function reset() {}
|
||||
|
||||
/**
|
||||
* Determine whether the io_service is stopped.
|
||||
*/
|
||||
function stopped() {}
|
||||
|
||||
/**
|
||||
* Get last error code emitted by yielded async operations of this thread.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
static function lastError() {}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
/**
|
||||
* php-asio/stubs/Signal.php
|
||||
*
|
||||
* This file is a stub of php-asio, which is implemented in extension asio.so.
|
||||
* For source code of asio.so, see src/ directory.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
namespace Asio;
|
||||
|
||||
/**
|
||||
* Class Signal
|
||||
*
|
||||
* Provides signal handling functionality.
|
||||
*
|
||||
* @package Asio
|
||||
*/
|
||||
final class Signal implements IoObject
|
||||
{
|
||||
/**
|
||||
* This class can only be instantiated using `Service::addSignal()`.
|
||||
*/
|
||||
private function __construct() {}
|
||||
|
||||
/**
|
||||
* Add the specified signal(s) to the signal set.
|
||||
*
|
||||
* @param int[] ...$signals[optional]
|
||||
* @return int : Error code
|
||||
*/
|
||||
function add(int... $signals) {}
|
||||
|
||||
/**
|
||||
* Initiate an asynchronous wait against the signal set.
|
||||
*
|
||||
* @param callable $callback[optional]
|
||||
* @param mixed $argument
|
||||
* @return Future
|
||||
*/
|
||||
function wait(callable $callback, $argument = null) {}
|
||||
|
||||
/**
|
||||
* Remove the specified signal(s) from the signal set.
|
||||
*
|
||||
* @param int[] ...$signals[optional]
|
||||
* @return int : Error code
|
||||
*/
|
||||
function remove(int... $signals) {}
|
||||
|
||||
/**
|
||||
* Remove all signals from the signal set.
|
||||
*
|
||||
* @return int : Error code
|
||||
*/
|
||||
function clear() {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function cancel() {}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* php-asio/stubs/Socket.php
|
||||
*
|
||||
* This file is a stub of php-asio, which is implemented in extension asio.so.
|
||||
* For source code of asio.so, see src/ directory.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
namespace Asio;
|
||||
|
||||
/**
|
||||
* Interface Socket
|
||||
*
|
||||
* @package Asio
|
||||
*/
|
||||
interface Socket extends IoObject
|
||||
{
|
||||
/**
|
||||
* Determine the number of bytes available for reading.
|
||||
*
|
||||
* @param int $ec[optional] : Error code
|
||||
* @return int
|
||||
*/
|
||||
function available(int &$ec);
|
||||
|
||||
/**
|
||||
* Determine whether the socket is at the out-of-band data mark.
|
||||
*
|
||||
* @param int $ec[optional] : Error code
|
||||
* @return bool
|
||||
*/
|
||||
function atMark(int &$ec);
|
||||
|
||||
/**
|
||||
* Close socket.
|
||||
*
|
||||
* @return int : Error code
|
||||
*/
|
||||
function close();
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
/**
|
||||
* php-asio/stubs/Strand.php
|
||||
*
|
||||
* This file is a stub of php-asio, which is implemented in extension asio.so.
|
||||
* For source code of asio.so, see src/ directory.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
namespace Asio;
|
||||
|
||||
/**
|
||||
* Class Strand
|
||||
*
|
||||
* Provides serialized handler execution.
|
||||
*
|
||||
* @package Asio
|
||||
*/
|
||||
final class Strand
|
||||
{
|
||||
/**
|
||||
* This class can only be instantiated using `Service::addStrand()`.
|
||||
*/
|
||||
private function __construct() {}
|
||||
|
||||
/**
|
||||
* Request the strand to invoke the given handler.
|
||||
*
|
||||
* @param callable $callback
|
||||
* @param mixed $argument
|
||||
* @return void
|
||||
*/
|
||||
function dispatch(callable $callback, $argument = null) {}
|
||||
|
||||
/**
|
||||
* Request the strand to invoke the given handler and return immediately.
|
||||
*
|
||||
* @param callable $callback
|
||||
* @param mixed $argument
|
||||
* @return void
|
||||
*/
|
||||
function post(callable $callback, $argument = null) {}
|
||||
|
||||
/**
|
||||
* Determine whether the strand is running in the current thread.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function runningInThisThread() {}
|
||||
|
||||
/**
|
||||
* Create a new handler that automatically dispatches the wrapped handler on the strand.
|
||||
*
|
||||
* @param callable $callback[optional]
|
||||
* @return WrappedHandler
|
||||
*/
|
||||
function wrap(callable $callback) {}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
/**
|
||||
* php-asio/stubs/StreamDescriptor.php
|
||||
*
|
||||
* This file is a stub of php-asio, which is implemented in extension asio.so.
|
||||
* For source code of asio.so, see src/ directory.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
namespace Asio;
|
||||
|
||||
/**
|
||||
* Class StreamDescriptor
|
||||
*
|
||||
* Provides stream-oriented descriptor functionality.
|
||||
*
|
||||
* @package Asio
|
||||
*/
|
||||
final class StreamDescriptor implements IoObject
|
||||
{
|
||||
/**
|
||||
* This class can only be instantiated using `Service::addStreamDescriptor()`.
|
||||
*/
|
||||
private function __construct() {}
|
||||
|
||||
/**
|
||||
* Opens the descriptor to hold an existing native descriptor.
|
||||
*
|
||||
* @param int|resource $native_handle
|
||||
* @return int : Error code
|
||||
*/
|
||||
function assign($native_handle) {}
|
||||
|
||||
/**
|
||||
* Determine whether the descriptor is open.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function isOpen() {}
|
||||
|
||||
/**
|
||||
* Read asynchronously from stream descriptor.
|
||||
*
|
||||
* @param int $length : Max number of bytes to be read
|
||||
* @param bool $read_some
|
||||
* @param callable $callback[optional] : Read handler callback
|
||||
* @param mixed $argument
|
||||
* @return Future : Resolves received data(string)
|
||||
*/
|
||||
function read(int $length, bool $read_some = true, callable $callback, $argument = null) {}
|
||||
|
||||
/**
|
||||
* Write asynchronously to stream descriptor.
|
||||
*
|
||||
* @param string $data : Write buffer
|
||||
* @param bool $write_some
|
||||
* @param callable $callback[optional] : Write handler callback
|
||||
* @param mixed $argument
|
||||
* @return Future : Resolves bytes transferred(int)
|
||||
*/
|
||||
function write(string $data, bool $write_some = false, callable $callback, $argument = null) {}
|
||||
|
||||
/**
|
||||
* Release ownership of the native descriptor implementation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function release() {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function cancel() {}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
/**
|
||||
* php-asio/stubs/StreamSocket.php
|
||||
*
|
||||
* This file is a stub of php-asio, which is implemented in extension asio.so.
|
||||
* For source code of asio.so, see src/ directory.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
namespace Asio;
|
||||
|
||||
/**
|
||||
* Interface StreamSocket
|
||||
*
|
||||
* @package Asio
|
||||
*/
|
||||
interface StreamSocket extends Socket
|
||||
{
|
||||
/**
|
||||
* Read asynchronously from stream socket.
|
||||
*
|
||||
* @param int $length : Max number of bytes to be read
|
||||
* @param bool $read_some
|
||||
* @param callable $callback[optional] : Read handler callback
|
||||
* @param mixed $argument
|
||||
* @return Future : Resolves received data(string)
|
||||
*/
|
||||
function read(int $length, bool $read_some = true, callable $callback, $argument = null);
|
||||
|
||||
/**
|
||||
* Write asynchronously to stream socket.
|
||||
*
|
||||
* @param string $data : Write buffer
|
||||
* @param bool $write_some
|
||||
* @param callable $callback[optional] : Write handler callback
|
||||
* @param mixed $argument
|
||||
* @return Future : Resolves bytes transferred(int)
|
||||
*/
|
||||
function write(string $data, bool $write_some = false, callable $callback, $argument = null);
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
/**
|
||||
* php-asio/stubs/TcpAcceptor.php
|
||||
*
|
||||
* This file is a stub of php-asio, which is implemented in extension asio.so.
|
||||
* For source code of asio.so, see src/ directory.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
namespace Asio;
|
||||
|
||||
/**
|
||||
* Class TcpAcceptor
|
||||
*
|
||||
* Used for accepting new TCP connections.
|
||||
*
|
||||
* @package Asio
|
||||
*/
|
||||
final class TcpAcceptor implements Acceptor
|
||||
{
|
||||
/**
|
||||
* This class can only be instantiated using `Service::addTcpAcceptor()`.
|
||||
*/
|
||||
private function __construct() {}
|
||||
|
||||
/**
|
||||
* Open acceptor.
|
||||
*
|
||||
* @param bool $use_ipv6 : True for AF_INET6, false for AF_INET
|
||||
* @return int : Error code
|
||||
*/
|
||||
function open(bool $use_ipv6) {}
|
||||
|
||||
/**
|
||||
* Assign an existing native socket to the acceptor.
|
||||
*
|
||||
* @param bool $inet6
|
||||
* @param int|resource $native_handle
|
||||
* @return int : Error code
|
||||
*/
|
||||
function assign(bool $inet6, $native_handle) {}
|
||||
|
||||
/**
|
||||
* Bind acceptor to local endpoint.
|
||||
*
|
||||
* @param string $address
|
||||
* @param int $port
|
||||
* @return int : Error code
|
||||
*/
|
||||
function bind(string $address, int $port) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function listen(int $backlog = null) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function accept(callable $callback = null, $argument = null) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function cancel() {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function close() {}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
/**
|
||||
* php-asio/stubs/TcpResolver.php
|
||||
*
|
||||
* This file is a stub of php-asio, which is implemented in extension asio.so.
|
||||
* For source code of asio.so, see src/ directory.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
namespace Asio;
|
||||
|
||||
/**
|
||||
* Class TcpResolver
|
||||
*
|
||||
* Provides the ability to resolve a query to an array of endpoints.
|
||||
* Remote service should use TCP as transport protocol.
|
||||
*
|
||||
* @package Asio
|
||||
*/
|
||||
final class TcpResolver implements Resolver
|
||||
{
|
||||
/**
|
||||
* This class can only be instantiated using `Service::addTcpResolver()`.
|
||||
*/
|
||||
private function __construct() {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function resolve(string $host, string $service = '', callable $callback = null, $argument = null) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function cancel() {}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
/**
|
||||
* php-asio/stubs/TcpSocket.php
|
||||
*
|
||||
* This file is a stub of php-asio, which is implemented in extension asio.so.
|
||||
* For source code of asio.so, see src/ directory.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
namespace Asio;
|
||||
|
||||
/**
|
||||
* Class TcpSocket
|
||||
*
|
||||
* Provides operations on TCP sockets.
|
||||
*
|
||||
* @package Asio
|
||||
*/
|
||||
final class TcpSocket implements StreamSocket, InetSocket
|
||||
{
|
||||
/**
|
||||
* This class can only be instantiated using `Service::addTcpSocket()` and `TcpAcceptor::Accept()`.
|
||||
*/
|
||||
private function __construct() {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function open(bool $inet6) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function assign(bool $inet6, $native_handle) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function bind(string $address, int $port) {}
|
||||
|
||||
/**
|
||||
* Connect to a remote endpoint.
|
||||
*
|
||||
* @param string $address : Remote address
|
||||
* @param int $port : Remote port
|
||||
* @param callable $callback[optional]
|
||||
* @param mixed $argument
|
||||
*/
|
||||
function connect(string $address, int $port, callable $callback, $argument = null) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function read(int $length, bool $read_some = true, callable $callback = null, $argument = null) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function write(string $data, bool $write_some = false, callable $callback = null, $argument = null) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function remoteAddr() {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function remotePort() {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function available(int &$ec = null) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function atMark(int &$ec = null) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function cancel() {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function close() {}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
/**
|
||||
* php-asio/stubs/Timer.php
|
||||
*
|
||||
* This file is a stub of php-asio, which is implemented in extension asio.so.
|
||||
* For source code of asio.so, see src/ directory.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
namespace Asio;
|
||||
|
||||
/**
|
||||
* Wrapper for Boost.Asio deadline_timer.
|
||||
*
|
||||
* @package Asio
|
||||
*/
|
||||
final class Timer implements IoObject
|
||||
{
|
||||
/**
|
||||
* This class can only be instantiated using "Service::addTimer()".
|
||||
*/
|
||||
private function __construct() {}
|
||||
|
||||
/**
|
||||
* Set the timer's expiry time relative to now.
|
||||
*
|
||||
* @param int $duration : Milliseconds from now.
|
||||
* @return int : Error code.
|
||||
*/
|
||||
function expiresFromNow(int $duration) {}
|
||||
|
||||
/**
|
||||
* Set the timer's expiry time as an absolute time.
|
||||
*
|
||||
* @param int $timestamp : UNIX timestamp(in milliseconds).
|
||||
* @return int : Error code.
|
||||
*/
|
||||
function expiresAt(int $timestamp) {}
|
||||
|
||||
/**
|
||||
* Initiate an asynchronous wait against the timer.
|
||||
*
|
||||
* @param callable $callback[optional]
|
||||
* @param mixed $argument
|
||||
* @return Future : Resolves null
|
||||
*/
|
||||
function wait(callable $callback, $argument = null) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function cancel() {}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* php-asio/stubs/UdgSocket.php
|
||||
*
|
||||
* This file is a stub of php-asio, which is implemented in extension asio.so.
|
||||
* For source code of asio.so, see src/ directory.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
namespace Asio;
|
||||
|
||||
/**
|
||||
* Class UdgSocket
|
||||
*
|
||||
*
|
||||
* @package Asio
|
||||
*/
|
||||
final class UdgSocket implements DatagramSocket, LocalSocket
|
||||
{
|
||||
/**
|
||||
* This class can only be instantiated using `Service::addUdgSocket()`.
|
||||
*/
|
||||
private function __construct() {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function open() {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function assign($native_handle) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function bind(string $path) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function recvFrom(int $length, callable $callback = null, $argument = null) {}
|
||||
|
||||
/**
|
||||
* Send asynchronously to UNIX datagram socket.
|
||||
*
|
||||
* @param string $data : Data to send to datagram socket.
|
||||
* @param string $path : Socket path of remote endpoint.
|
||||
* @param callable $callback[optional]
|
||||
* @param mixed $argument
|
||||
* @return Future
|
||||
*/
|
||||
function sendTo(string $data, string $path, callable $callback, $argument = null) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function remotePath() {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function available(int &$ec = null) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function atMark(int &$ec = null) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function cancel() {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function close() {}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
/**
|
||||
* php-asio/stubs/UdpResolver.php
|
||||
*
|
||||
* This file is a stub of php-asio, which is implemented in extension asio.so.
|
||||
* For source code of asio.so, see src/ directory.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
namespace Asio;
|
||||
|
||||
/**
|
||||
* Class UdpResolver
|
||||
*
|
||||
* Provides the ability to resolve a query to an array of endpoints.
|
||||
* Remote service should use UDP as transport protocol.
|
||||
*
|
||||
* @package Asio
|
||||
*/
|
||||
final class UdpResolver implements Resolver
|
||||
{
|
||||
/**
|
||||
* This class can only be instantiated using `Service::addTcpResolver()`.
|
||||
*/
|
||||
private function __construct() {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function resolve(string $host, string $service = '', callable $callback = null, $argument = null) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function cancel() {}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* php-asio/stubs/UdpSocket.php
|
||||
*
|
||||
* This file is a stub of php-asio, which is implemented in extension asio.so.
|
||||
* For source code of asio.so, see src/ directory.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
namespace Asio;
|
||||
|
||||
/**
|
||||
* Class UdpSocket
|
||||
*
|
||||
* Provides operations on UDP sockets.
|
||||
*
|
||||
* @package Asio
|
||||
*/
|
||||
final class UdpSocket implements InetSocket, DatagramSocket
|
||||
{
|
||||
/**
|
||||
* This class can only be instantiated using `Service::addUdpSocket()`.
|
||||
*/
|
||||
private function __construct() {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function open(bool $inet6) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function assign(bool $inet6, $native_handle) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function bind(string $address, int $port) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function recvFrom(int $length, callable $callback = null, $argument = null) {}
|
||||
|
||||
/**
|
||||
* Send asynchronously to UNIX datagram socket.
|
||||
*
|
||||
* @param string $data : Data to send to datagram socket.
|
||||
* @param string $address : Remote address
|
||||
* @param int $port : Remote port
|
||||
* @param callable $callback[optional]
|
||||
* @param mixed $argument
|
||||
* @return Future
|
||||
*/
|
||||
function sendTo(string $data, string $address, int $port, callable $callback, $argument = null) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function remoteAddr() {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function remotePort() {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function available(int &$ec = null) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function atMark(int &$ec = null) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function cancel() {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function close() {}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
/**
|
||||
* php-asio/stubs/UnixAcceptor.php
|
||||
*
|
||||
* This file is a stub of php-asio, which is implemented in extension asio.so.
|
||||
* For source code of asio.so, see src/ directory.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
namespace Asio;
|
||||
|
||||
/**
|
||||
* Class UnixAcceptor
|
||||
*
|
||||
* Used for accepting new UNIX domain socket connections.
|
||||
*
|
||||
* @package Asio
|
||||
*/
|
||||
final class UnixAcceptor implements Acceptor
|
||||
{
|
||||
/**
|
||||
* This class can only be instantiated using `Service::addUnixAcceptor()`.
|
||||
*/
|
||||
private function __construct() {}
|
||||
|
||||
/**
|
||||
* Open acceptor.
|
||||
*
|
||||
* @return int : Error code.
|
||||
*/
|
||||
function open() {}
|
||||
|
||||
/**
|
||||
* Assign an existing native socket to the acceptor.
|
||||
*
|
||||
* @param int|resource $native_handle
|
||||
* @return int : Error code
|
||||
*/
|
||||
function assign($native_handle) {}
|
||||
|
||||
/**
|
||||
* Bind acceptor to local endpoint.
|
||||
*
|
||||
* @param string $path
|
||||
* @return int : Error code.
|
||||
*/
|
||||
function bind(string $path) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function listen(int $backlog = null) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function accept(callable $callback = null, $argument = null) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function cancel() {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function close() {}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
/**
|
||||
* php-asio/stubs/UnixSocket.php
|
||||
*
|
||||
* This file is a stub of php-asio, which is implemented in extension asio.so.
|
||||
* For source code of asio.so, see src/ directory.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
namespace Asio;
|
||||
|
||||
/**
|
||||
* Class UnixSocket
|
||||
*
|
||||
* Provides operations on UNIX domain sockets (SOCK_STREAM).
|
||||
*
|
||||
* @package Asio
|
||||
*/
|
||||
final class UnixSocket implements StreamSocket, LocalSocket
|
||||
{
|
||||
/**
|
||||
* This class can only be instantiated using `Service::addUnixSocket()` and `UnixAcceptor::Accept()`.
|
||||
*/
|
||||
private function __construct() {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function open() {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function assign($native_handle) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function bind(string $path) {}
|
||||
|
||||
/**
|
||||
* Connect to a remote endpoint.
|
||||
*
|
||||
* @param string $path : Remote socket file path
|
||||
* @param callable $callback[optional]
|
||||
* @param mixed $argument
|
||||
* @return int : Error code
|
||||
*/
|
||||
function connect(string $path, callable $callback, $argument = null) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function read(int $length, bool $read_some = true, callable $callback = null, $argument = null) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function write(string $data, bool $write_some = false, callable $callback = null, $argument = null) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function remotePath() {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function available(int &$ec = null) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function atMark(int &$ec = null) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function cancel() {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function close() {}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
/**
|
||||
* php-asio/stubs/WrappedHandler.php
|
||||
*
|
||||
* This file is a stub of php-asio, which is implemented in extension asio.so.
|
||||
* For source code of asio.so, see src/ directory.
|
||||
*
|
||||
* @author CismonX<admin@cismon.net>
|
||||
*/
|
||||
|
||||
namespace Asio;
|
||||
|
||||
/**
|
||||
* Class WrappedHandler
|
||||
*
|
||||
* Async handler callback wrapped by strand.
|
||||
*
|
||||
* @package Asio
|
||||
*/
|
||||
final class WrappedHandler
|
||||
{
|
||||
/**
|
||||
* This class can only be instantiated using `Strand::wrap()`.
|
||||
*/
|
||||
private function __construct() {}
|
||||
|
||||
/**
|
||||
* Making object callable.
|
||||
*
|
||||
* Note: Calling directly has no effect.
|
||||
*/
|
||||
function __invoke() {}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
--TEST--
|
||||
Check for whether php-asio is loaded.
|
||||
--FILE--
|
||||
<?php
|
||||
if (!extension_loaded('asio'))
|
||||
echo 'php-asio not loaded.'
|
||||
?>
|
||||
--EXPECT--
|
|
@ -0,0 +1,18 @@
|
|||
--TEST--
|
||||
Test for `Service`.
|
||||
--FILE--
|
||||
<?php
|
||||
$service = new Asio\Service();
|
||||
$service->dispatch(function () use ($service) {
|
||||
echo 'Service::dispatch()', PHP_EOL;
|
||||
$service->post(function ($arg) use ($service) {
|
||||
echo "Service::post($arg)";
|
||||
}, 'foo');
|
||||
});
|
||||
$service->run($ec);
|
||||
if ($ec)
|
||||
echo 'Error on Service::run(). ', posix_strerror($ec);
|
||||
?>
|
||||
--EXPECT--
|
||||
Service::dispatch()
|
||||
Service::post(foo)
|
|
@ -0,0 +1,22 @@
|
|||
--TEST--
|
||||
Test for `Timer`.
|
||||
--FILE--
|
||||
<?php
|
||||
$service = new Asio\Service;
|
||||
$timer = $service->addTimer();
|
||||
if ($ec = $timer->expiresFromNow(200))
|
||||
die('Timer::expire() failed. '.posix_strerror($ec));
|
||||
$start_time = microtime(true);
|
||||
$timer->wait(function ($timer, $ec) use ($start_time) {
|
||||
if ($ec) {
|
||||
echo 'Error on Timer::wait(). ', posix_strerror($ec);
|
||||
return;
|
||||
}
|
||||
$end_time = microtime(true);
|
||||
$duration = intval(1000 * ($end_time - $start_time));
|
||||
if ($duration != 200)
|
||||
echo "Bad duration. Expected 200ms, got ${duration}ms";
|
||||
});
|
||||
$service->run($ec);
|
||||
?>
|
||||
--EXPECT--
|
|
@ -0,0 +1,23 @@
|
|||
--TEST--
|
||||
Test for `Signal`.
|
||||
--FILE--
|
||||
<?php
|
||||
$service = new Asio\Service;
|
||||
$signal = $service->addSignal();
|
||||
if ($ec = $signal->add(SIGINT))
|
||||
die('Signal::add() failed. '.posix_strerror($ec));
|
||||
$signal->wait(function ($signal, $sig_num, $ec) use ($service) {
|
||||
if ($ec) {
|
||||
echo 'Error on Timer::wait(). ', posix_strerror($ec);
|
||||
return;
|
||||
}
|
||||
echo $sig_num;
|
||||
});
|
||||
$service->post(function () {
|
||||
if (!posix_kill(posix_getpid(), SIGINT))
|
||||
exit;
|
||||
});
|
||||
$service->run();
|
||||
?>
|
||||
--EXPECT--
|
||||
2
|
|
@ -0,0 +1,46 @@
|
|||
--TEST--
|
||||
Test for binding socket to an endpoint and opening socket.
|
||||
--ENV--
|
||||
SOCK_FILE=/tmp/test-asio-socket-bind.sock
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!stream_socket_server('tcp://127.0.0.1:21348', $ec))
|
||||
echo 'skip ', posix_strerror($ec);
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
$service = new Asio\Service;
|
||||
|
||||
$socket = $service->addTcpSocket();
|
||||
if ($ec = $socket->open(false))
|
||||
die('TcpSocket::open() failed. '.posix_strerror($ec));
|
||||
if ($ec = $socket->bind('127.0.0.1', 21348))
|
||||
die('TcpSocket::bind() failed. '.posix_strerror($ec));
|
||||
$socket->close();
|
||||
|
||||
$socket = $service->addUdpSocket();
|
||||
if ($ec = $socket->open(false))
|
||||
die('UdpSocket::open() failed. '.posix_strerror($ec));
|
||||
if ($ec = $socket->bind('127.0.0.1', 21348))
|
||||
die('UdpSocket::bind() failed. '.posix_strerror($ec));
|
||||
$socket->close();
|
||||
|
||||
$socket = $service->addUnixSocket();
|
||||
if ($ec = $socket->open())
|
||||
die('UnixSocket::open() failed. '.posix_strerror($ec));
|
||||
if ($ec = $socket->bind(getenv('SOCK_FILE')))
|
||||
die('UnixSocket::bind() failed. '.posix_strerror($ec));
|
||||
$socket->close();
|
||||
|
||||
$socket = $service->addUdgSocket();
|
||||
if ($ec = $socket->open())
|
||||
die('UdgSocket::open() failed. '.posix_strerror($ec));
|
||||
if ($ec = $socket->bind(getenv('SOCK_FILE')))
|
||||
die('UdgSocket::bind() failed. '.posix_strerror($ec));
|
||||
$socket->close();
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
unlink(getenv('SOCK_FILE'));
|
||||
?>
|
||||
--EXPECT--
|
|
@ -0,0 +1,63 @@
|
|||
--TEST--
|
||||
Test for `Acceptor`.
|
||||
--ENV--
|
||||
SOCK_FILE=/tmp/test-asio-socket-bind.sock
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!stream_socket_server('tcp://127.0.0.1:21348', $ec))
|
||||
echo 'skip ', posix_strerror($ec);
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
$service = new Asio\Service;
|
||||
$acceptor = $service->addTcpAcceptor();
|
||||
if ($ec = $acceptor->open(false))
|
||||
die('TcpAcceptor::open() failed. '.posix_strerror($ec));
|
||||
if ($ec = $acceptor->bind('127.0.0.1', 21348))
|
||||
die('TcpAcceptor::bind() failed. '.posix_strerror($ec));
|
||||
if ($ec = $acceptor->listen())
|
||||
die('TcpAcceptor::listen() failed. '.posix_strerror($ec));
|
||||
$acceptor->accept(function ($acceptor, $socket, $ec) use ($service) {
|
||||
if ($ec) {
|
||||
echo 'Error on TcpAcceptor::accept. ', posix_strerror($ec);
|
||||
return;
|
||||
}
|
||||
echo 'Accepted', PHP_EOL;
|
||||
$service->post(function () use ($service) {
|
||||
$acceptor = $service->addUnixAcceptor();
|
||||
if ($ec = $acceptor->open())
|
||||
die('UnixAcceptor::open() failed. '.posix_strerror($ec));
|
||||
if ($ec = $acceptor->bind(getenv('SOCK_FILE')))
|
||||
die('UnixAcceptor::bind() failed. '.posix_strerror($ec));
|
||||
if ($ec = $acceptor->listen())
|
||||
die('UnixAcceptor::listen() failed. '.posix_strerror($ec));
|
||||
$acceptor->accept(function ($acceptor, $socket, $ec) {
|
||||
if ($ec) {
|
||||
echo 'Error on UnixAcceptor::accept. ', posix_strerror($ec);
|
||||
return;
|
||||
}
|
||||
echo 'Accepted';
|
||||
});
|
||||
$service->post(function () use ($service) {
|
||||
if ($handle = stream_socket_client('unix://'.getenv('SOCK_FILE')))
|
||||
fclose($handle);
|
||||
else
|
||||
exit;
|
||||
});
|
||||
});
|
||||
});
|
||||
$service->post(function () use ($service) {
|
||||
if ($handle = stream_socket_client('tcp://127.0.0.1:21348'))
|
||||
fclose($handle);
|
||||
else
|
||||
exit;
|
||||
});
|
||||
$service->run();
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
unlink(getenv('SOCK_FILE'));
|
||||
?>
|
||||
--EXPECT--
|
||||
Accepted
|
||||
Accepted
|
|
@ -0,0 +1,53 @@
|
|||
--TEST--
|
||||
Test for `DatagramSocket::sendTo()` and `DatagramSocket::recvFrom()`.
|
||||
--ENV--
|
||||
SOCK_FILE_1=/tmp/test-asio-socket-bind-1.sock
|
||||
SOCK_FILE_2=/tmp/test-asio-socket-bind-2.sock
|
||||
--FILE--
|
||||
<?php
|
||||
$service = new Asio\Service;
|
||||
$service->post(function () use ($service) {
|
||||
$socket = $service->addUdgSocket();
|
||||
$socket->open();
|
||||
$socket->bind(getenv('SOCK_FILE_1'));
|
||||
$socket->recvFrom(100,
|
||||
function ($socket, $data, $remote_path, $ec) {
|
||||
if ($ec) {
|
||||
echo 'UdgSocket::recvFrom() failed. ', posix_strerror($ec);
|
||||
$socket->close();
|
||||
return;
|
||||
}
|
||||
echo $data;
|
||||
$socket->sendTo('world', $remote_path, function ($socket, $length, $ec) {
|
||||
if ($ec) {
|
||||
echo 'UdgSocket::sendTo() failed. ', posix_strerror($ec);
|
||||
$socket->close();
|
||||
return;
|
||||
}
|
||||
$socket->close();
|
||||
});
|
||||
});
|
||||
$socket = $service->addUdgSocket();
|
||||
$socket->open();
|
||||
$socket->bind(getenv('SOCK_FILE_2'));
|
||||
$socket->sendTo('hello', getenv('SOCK_FILE_1'), function ($socket) {
|
||||
$socket->recvFrom(100, function ($socket, $data, $remote_path, $ec) {
|
||||
if ($ec) {
|
||||
echo 'UdgSocket::recvFrom() failed. ', posix_strerror($ec);
|
||||
$socket->close();
|
||||
return;
|
||||
}
|
||||
echo $data;
|
||||
$socket->close();
|
||||
});
|
||||
});
|
||||
});
|
||||
$service->run();
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
unlink(getenv('SOCK_FILE_1'));
|
||||
unlink(getenv('SOCK_FILE_2'));
|
||||
?>
|
||||
--EXPECT--
|
||||
helloworld
|
|
@ -0,0 +1,22 @@
|
|||
--TEST--
|
||||
Test for `Future` and `Service::lastError()`.
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!class_exists('Asio\Future'))
|
||||
echo 'skip coroutine is disabled';
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
$service = new Asio\Service;
|
||||
$service->post(function () use ($service) {
|
||||
$signal = $service->addSignal();
|
||||
$signal->add(SIGINT);
|
||||
$service->post(function () {
|
||||
posix_kill(posix_getpid(), SIGINT);
|
||||
});
|
||||
echo yield $signal->wait();
|
||||
});
|
||||
$service->run();
|
||||
?>
|
||||
--EXPECT--
|
||||
2
|
|
@ -0,0 +1,41 @@
|
|||
--TEST--
|
||||
Test for `assign()` on `Socket`, `Acceptor` and `StreamDescriptor`.
|
||||
Test for `StreamSocket::read()` and `StreamSocket::write()`.
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!stream_socket_server('tcp://127.0.0.1:21348', $ec))
|
||||
echo 'skip ', posix_strerror($ec);
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
$handle = stream_socket_server('tcp://127.0.0.1:21348');
|
||||
$service = new Asio\Service;
|
||||
$acceptor = $service->addTcpAcceptor();
|
||||
if ($ec = $acceptor->assign(false, $handle))
|
||||
die('Acceptor::assign() failed. '.posix_strerror($ec));
|
||||
$acceptor->accept(function ($acceptor, $socket, $ec) use ($service) {
|
||||
if ($ec) {
|
||||
echo 'Error on TcpAcceptor::accept(). ', posix_strerror($ec);
|
||||
return;
|
||||
}
|
||||
$socket->read(5, false, function ($socket, $data, $ec) use ($service) {
|
||||
if ($ec) {
|
||||
echo 'TcpSocket::read() failed.', posix_strerror($ec);
|
||||
return;
|
||||
}
|
||||
echo $data;
|
||||
$stream_descriptor = $service->addStreamDescriptor();
|
||||
$stream_descriptor->assign(STDOUT);
|
||||
$stream_descriptor->write('world');
|
||||
});
|
||||
});
|
||||
$service->post(function () use ($service) {
|
||||
$handle = stream_socket_client('tcp://127.0.0.1:21348');
|
||||
$socket = $service->addTcpSocket();
|
||||
$socket->assign(false, $handle);
|
||||
$socket->write('hello');
|
||||
});
|
||||
$service->run();
|
||||
?>
|
||||
--EXPECT--
|
||||
helloworld
|
|
@ -0,0 +1,19 @@
|
|||
--TEST--
|
||||
Test for `Resolver`.
|
||||
--FILE--
|
||||
<?php
|
||||
$service = new Asio\Service;
|
||||
$service->post(function () use ($service) {
|
||||
$resolver = $service->addTcpResolver();
|
||||
$resolver->resolve('github.com', 'http', function ($resolver, $arr, $ec) {
|
||||
if ($ec = Asio\Service::lastError()) {
|
||||
echo 'Resolver::resolve() failed. ', posix_strerror($ec);
|
||||
return;
|
||||
}
|
||||
echo boolval(count($arr));
|
||||
});
|
||||
});
|
||||
$service->run();
|
||||
?>
|
||||
--EXPECT--
|
||||
1
|
|
@ -0,0 +1,38 @@
|
|||
--TEST--
|
||||
Test for forking.
|
||||
--FILE--
|
||||
<?php
|
||||
$service = new Asio\Service;
|
||||
function fork_worker($service, $signal)
|
||||
{
|
||||
if ($ec = $service->forkPrepare())
|
||||
die('Service::forkParent() failed. '. posix_strerror($ec));
|
||||
if (pcntl_fork()) {
|
||||
if ($ec = $service->forkParent())
|
||||
die('Service::forkParent() failed. '. posix_strerror($ec));
|
||||
$signal->wait(function () {
|
||||
if (pcntl_wait($status, WUNTRACED) < 1)
|
||||
die('An error occurred during wait().');
|
||||
echo $status;
|
||||
});
|
||||
echo 'parent ';
|
||||
} else {
|
||||
if ($ec = $service->forkChild())
|
||||
die('Service::forkParent() failed. '. posix_strerror($ec));
|
||||
$signal->cancel();
|
||||
$timer = $service->addTimer();
|
||||
$timer->expiresFromNow(100);
|
||||
$timer->wait($timer_cb = function ($timer) use (&$timer_cb) {
|
||||
echo 'child ';
|
||||
});
|
||||
}
|
||||
}
|
||||
$service->post(function () use ($service) {
|
||||
$signal = $service->addSignal();
|
||||
$signal->add(SIGCHLD);
|
||||
fork_worker($service, $signal);
|
||||
});
|
||||
$service->run();
|
||||
?>
|
||||
--EXPECT--
|
||||
parent child 0
|
|
@ -0,0 +1,24 @@
|
|||
--TEST--
|
||||
Test for `Strand`.
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!class_exists(Asio\Strand::class))
|
||||
echo 'skip Strand is not enabled';
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
// Just test whether Strand works.
|
||||
// We do not test multi-threading because is not yet supported.
|
||||
$service = new Asio\Service;
|
||||
$strand = $service->addStrand();
|
||||
$strand->post(function () use ($service, $strand) {
|
||||
$timer = $service->addTimer();
|
||||
$timer->expiresFromNow(100);
|
||||
$timer->wait($strand->wrap(function () {
|
||||
echo 'ok';
|
||||
}));
|
||||
});
|
||||
$service->run();
|
||||
?>
|
||||
--EXPECT--
|
||||
ok
|
Reference in New Issue