/** * php-asio/acceptor.cpp * * @author CismonX */ #include "acceptor.hpp" #include "future.hpp" #include "io.hpp" namespace asio { template zval* acceptor::handler(const boost::system::error_code& error, socket* 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(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 P3_METHOD(acceptor, 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(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 P3_METHOD(acceptor, 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, io_service_); PHP_ASIO_FUTURE_INIT(); auto asio_socket = p3::to_object>(accepted_socket); future->template on_resolve(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 P3_METHOD(acceptor, cancel) { boost::system::error_code ec; RETVAL_EC(acceptor_.cancel(ec)); } /* }}} */ /* {{{ proto int Acceptor::close(void); * Stop the acceptor. */ template P3_METHOD(acceptor, close) { boost::system::error_code ec; RETVAL_EC(acceptor_.close(ec)); } /* }}} */ template zend_class_entry* acceptor::class_entry; template zend_object_handlers acceptor::handlers; template class acceptor; template class acceptor; }