├── .gitignore ├── .gitmodules ├── .travis.scripts └── compile.sh ├── .travis.yml ├── LICENSE ├── Makefile.thirdparty ├── README.md ├── common.h ├── config.m4 ├── php_ext_uv.c ├── php_ext_uv.h ├── src ├── fcall.h ├── fcall_info.h ├── ssl_verify.c ├── ssl_verify.h ├── util.h ├── uv_idle.c ├── uv_idle.h ├── uv_loop.c ├── uv_loop.h ├── uv_loop_resource.h ├── uv_pipe.c ├── uv_pipe.h ├── uv_process.c ├── uv_process.h ├── uv_resolver.c ├── uv_resolver.h ├── uv_signal.c ├── uv_signal.h ├── uv_ssl.c ├── uv_ssl.h ├── uv_ssl_constant.h ├── uv_tcp.c ├── uv_tcp.h ├── uv_timer.c ├── uv_timer.h ├── uv_udp.c ├── uv_udp.h ├── uv_util.c ├── uv_util.h ├── uv_worker.c └── uv_worker.h └── tests ├── cert ├── server.crt └── server.key ├── circular_reference_gc ├── UVIdle.phpt ├── UVPipe.phpt ├── UVResolver.phpt ├── UVSSL_01.phpt ├── UVSSL_02.phpt ├── UVSignal.phpt ├── UVTcp.phpt ├── UVTimer_01.phpt ├── UVTimer_02.phpt └── UVUdp.phpt ├── custom_loop ├── 001.phpt ├── UVIdle.phpt ├── UVPipe.phpt ├── UVResolver.phpt ├── UVSSL_01.phpt ├── UVSSL_02.phpt ├── UVSignal.phpt ├── UVTcp.phpt ├── UVTimer_01.phpt ├── UVTimer_02.phpt └── UVUdp.phpt ├── default_loop ├── UVIdle.phpt ├── UVLoopSingleton.phpt ├── UVPipe.phpt ├── UVResolver.phpt ├── UVSSL_01.phpt ├── UVSSL_02.phpt ├── UVSignal.phpt ├── UVTcp.phpt ├── UVTimer_01.phpt ├── UVTimer_02.phpt └── UVUdp.phpt ├── default_loop_empty ├── UVIdle.phpt ├── UVPipe.phpt ├── UVResolver.phpt ├── UVSSL_01.phpt ├── UVSSL_02.phpt ├── UVSignal.phpt ├── UVTcp.phpt ├── UVTimer_01.phpt ├── UVTimer_02.phpt └── UVUdp.phpt ├── default_loop_null ├── UVIdle.phpt ├── UVPipe.phpt ├── UVResolver.phpt ├── UVSSL_01.phpt ├── UVSSL_02.phpt ├── UVSignal.phpt ├── UVTcp.phpt ├── UVTimer_01.phpt ├── UVTimer_02.phpt └── UVUdp.phpt ├── replace_callback_gc ├── UVIdle.phpt ├── UVPipe.phpt ├── UVPipe_listen_twice.phpt ├── UVSignal.phpt ├── UVTcp.phpt ├── UVTcp_listen_twice.phpt └── UVUdp.phpt └── typecheck ├── UVIdle.phpt ├── UVPipe.phpt ├── UVResolver.phpt ├── UVSSL.phpt ├── UVSignal.phpt ├── UVTcp.phpt ├── UVTimer.phpt ├── UVUdp.phpt └── error_handler.php /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.o 3 | *.os 4 | *.lo 5 | *.so 6 | *.dylib 7 | *.la 8 | *.lai 9 | *.libs 10 | *.sw* 11 | Makefile 12 | Makefile.fragments 13 | Makefile.global 14 | Makefile.objects 15 | build 16 | config.* 17 | configure 18 | configure.in 19 | doc 20 | CVS 21 | .sconf_temp 22 | .sconsign.dblite 23 | .deps 24 | ac*.m4 25 | mkinstalldirs 26 | run-tests.php 27 | install-sh 28 | libtool 29 | ltmain.sh 30 | missing 31 | 32 | output.0 33 | requests 34 | traces.0 35 | 36 | *.phpt.diff 37 | *.phpt.exp 38 | *.phpt.out 39 | *.phpt.log 40 | *.phpt.php 41 | 42 | .svn 43 | \#* 44 | 45 | 46 | *.diff 47 | *.exp 48 | *.log 49 | *.out 50 | *.mem 51 | tests/*/*/*.php 52 | tests/*/*/*.sh 53 | tests/*/*.sh 54 | php.ini 55 | tmp-php.ini 56 | 57 | tests/utils/cfg.inc 58 | 59 | .coverage 60 | coverage 61 | 62 | thirdparty -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "thirdparty/libuv"] 2 | path = thirdparty/libuv 3 | url = https://github.com/libuv/libuv.git 4 | -------------------------------------------------------------------------------- /.travis.scripts/compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sudo apt-get -y install check pkg-config 3 | 4 | currentpwd=`pwd` 5 | 6 | thirdparty="$currentpwd/thirdparty" 7 | 8 | cd "$thirdparty/r3" && \ 9 | ./autogen.sh && \ 10 | CFLAGS="-O2 -fPIC" ./configure --prefix="$thirdparty/build" && make clean install 11 | 12 | cd "$thirdparty/libuv" && \ 13 | ./autogen.sh && \ 14 | CFLAGS="-O2 -fPIC" ./configure --prefix="$thirdparty/build" && make clean install 15 | 16 | cd $currentpwd 17 | 18 | phpize 19 | ./configure 20 | make all 21 | sudo make install 22 | sudo echo "extension=php_ext_uv.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"` 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | sudo: required 4 | 5 | php: 6 | - 7 7 | 8 | compiler: 9 | - gcc 10 | 11 | before_script: 12 | - git submodule update --init 13 | script: 14 | - phpize 15 | - ./configure 16 | - make all 17 | - NO_INTERACTION=1 make test 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Ricky Su 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Makefile.thirdparty: -------------------------------------------------------------------------------- 1 | thirdparty/build/lib/libuv.a: 2 | @echo "Build libuv" 3 | mkdir .tmp; \ 4 | mv ar-lib compile config.guess config.h.in config.sub configure.in depcomp install-sh ltmain.sh .tmp/; \ 5 | cd thirdparty/libuv && \ 6 | ./autogen.sh && \ 7 | CFLAGS="$(CFLAGS) -fPIC -g -O2" ./configure --prefix="$(srcdir)/thirdparty/build" && \ 8 | make install; \ 9 | mv $(srcdir)/.tmp/* $(srcdir); \ 10 | rmdir $(srcdir)/.tmp 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | php_ext_uv 2 | ================ 3 | 4 | [![Build Status](https://travis-ci.org/RickySu/php_ext_uv.svg?branch=master)](https://travis-ci.org/RickySu/php_ext_uv) 5 | 6 | php_ext_uv is a [libuv](https://github.com/joyent/libuv) 7 | extension for [PHP](http://php.net/) 8 | with high performance asynchronous I/O. 9 | 10 | ## Feature highlights 11 | 12 | * Asynchronous TCP and UDP sockets 13 | 14 | * Asynchronous DNS resolution 15 | 16 | * Signal handling 17 | 18 | * SSL support 19 | 20 | * TLS [SNI](https://en.wikipedia.org/wiki/Server_Name_Indication) support 21 | 22 | ## Build Requirement 23 | 24 | * autoconf 25 | * automake 26 | * check 27 | * pkg-config 28 | * pcre 29 | 30 | 31 | Example 32 | -------------------- 33 | 34 | 35 | ```php 36 | // TCP Echo Server 37 | $loop = new UVLoop(); 38 | $server = new UVTcp($loop); 39 | $server->listen($host, $port, function($server){ 40 | $client = $server->accept(); 41 | $client->setCallback(function($client, $recv){ 42 | //on receive 43 | $client->write($recv); 44 | }, function($client, $status){ 45 | //on data sent 46 | $client->close(); 47 | }, function(){ 48 | //on error maybe client disconnect. 49 | $client->close(); 50 | }); 51 | }); 52 | $loop->run(); 53 | ``` 54 | 55 | ```php 56 | //SSL Echo Server 57 | $loop = new UVLoop(); 58 | $server = new UVSSL($loop); 59 | $server->setCert(file_get_contents("server.crt")); //PEM format 60 | $server->setPrivateKey(file_get_contents("server.key")); //PEM format 61 | $server->listen($host, $port, function($server){ 62 | $client = $server->accept(); 63 | $client->setSSLHandshakeCallback(function($client){ 64 | echo "ssl handshake ok\n"; 65 | }); 66 | $client->setCallback(function($client, $recv){ 67 | //on receive if ssl handshake finished. 68 | //otherwise you won't receive any data before ssl handshake finished 69 | $client->write($recv); 70 | }, function($client, $status){ 71 | //on data sent 72 | $client->close(); 73 | }, function(){ 74 | //on error maybe client disconnect. 75 | $client->close(); 76 | }); 77 | }); 78 | $loop->run(); 79 | ``` 80 | 81 | [Server Name Indication(SNI)](http://en.wikipedia.org/wiki/Server_Name_Indication) 82 | 83 | ```php 84 | //SSL Echo Server with SNI support 85 | //SNI is an extension to the TLS 86 | $loop = new UVLoop(); 87 | $server = new UVSSL($loop, UVSSL::SSL_METHOD_TLSV1, 2); //with 2 certs 88 | $server->setCert(file_get_contents("server0.crt"), 0); //PEM format cert 0 89 | $server->setPrivateKey(file_get_contents("server0.key"), 0); //PEM format cert 0 90 | $server->setCert(file_get_contents("server1.crt"), 1); //PEM format cert 1 91 | $server->setPrivateKey(file_get_contents("server1.key"), 1); //PEM format cert 1 92 | $server->setSSLServerNameCallback(function($servername){ //regist Server Name Indication callback 93 | if($servername == 'server1'){ 94 | return 1; //use cert1 95 | } 96 | return 0; //default use cert0 97 | }); 98 | $server->listen($host, $port, function($server){ 99 | $client = $server->accept(); 100 | $client->setSSLHandshakeCallback(function($client){ 101 | echo "ssl handshake ok\n"; 102 | }); 103 | $client->setCallback(function($client, $recv){ 104 | //on receive if ssl handshake finished. 105 | //otherwise you won't receive any data before ssl handshake finished 106 | $client->write($recv); 107 | }, function($client, $status){ 108 | //on data sent 109 | $client->close(); 110 | }, function(){ 111 | //on error maybe client disconnect. 112 | $client->close(); 113 | }); 114 | }); 115 | $loop->run(); 116 | ``` 117 | 118 | ## LICENSE 119 | 120 | This software is released under MIT License. 121 | -------------------------------------------------------------------------------- /common.h: -------------------------------------------------------------------------------- 1 | #ifndef _COMMON_H 2 | #define _COMMON_H 3 | 4 | #define CLASS_ENTRY(name) uv_ce_##name 5 | 6 | #define OBJECT_HANDLER(name) object_handler_##name 7 | 8 | #define CLASS_ENTRY_FUNCTION_D(name) \ 9 | void init_uv_ce_##name() 10 | 11 | #define CLASS_ENTRY_FUNCTION_C(name) \ 12 | init_uv_ce_##name() 13 | 14 | #define DECLARE_CLASS_ENTRY(name) \ 15 | zend_object_handlers OBJECT_HANDLER(name); \ 16 | zend_class_entry *CLASS_ENTRY(name); \ 17 | CLASS_ENTRY_FUNCTION_D(name) 18 | 19 | #define FUNCTION_ENTRY(name) \ 20 | uv_fe_##name 21 | 22 | #define DECLARE_FUNCTION_ENTRY(name) \ 23 | static zend_function_entry FUNCTION_ENTRY(name)[] 24 | 25 | #define REGISTER_INTERNAL_CLASS(name) \ 26 | CLASS_ENTRY(name) = zend_register_internal_class_ex(&ce, NULL) 27 | 28 | #define REGISTER_INTERNAL_CLASS_EX(name, base) \ 29 | CLASS_ENTRY(name) = zend_register_internal_class_ex(&ce, CLASS_ENTRY(base)) 30 | 31 | #define INIT_CLASS_WITH_OBJECT_NEW(name, create_function) \ 32 | zend_class_entry ce; \ 33 | INIT_CLASS_ENTRY(ce, #name, FUNCTION_ENTRY(name)); \ 34 | memcpy(&OBJECT_HANDLER(name), zend_get_std_object_handlers(), sizeof(zend_object_handlers)) 35 | 36 | #define REGISTER_CLASS_WITH_OBJECT_NEW(name, create_function) \ 37 | INIT_CLASS_WITH_OBJECT_NEW(name, create_function); \ 38 | REGISTER_INTERNAL_CLASS(name); \ 39 | CLASS_ENTRY(name)->create_object = create_function 40 | 41 | #define EXTENDS_CLASS_WITH_OBJECT_NEW(name, create_function, base) \ 42 | INIT_CLASS_WITH_OBJECT_NEW(name, create_function); \ 43 | REGISTER_INTERNAL_CLASS_EX(name, base); \ 44 | CLASS_ENTRY(name)->create_object = create_function 45 | 46 | #define REGISTER_CLASS(name) \ 47 | zend_class_entry ce; \ 48 | INIT_CLASS_ENTRY(ce, #name, FUNCTION_ENTRY(name)); \ 49 | REGISTER_INTERNAL_CLASS(name) 50 | 51 | #define EXTENDS_CLASS(name, base) \ 52 | zend_class_entry ce; \ 53 | INIT_CLASS_ENTRY(ce, #name, FUNCTION_ENTRY(name)); \ 54 | REGISTER_INTERNAL_CLASS_EX(name, base) 55 | 56 | #define ARGINFO(classname, method) \ 57 | arginfo_##classname##_##method 58 | 59 | #define FETCH_RESOURCE(pointer, type) (type *) ((void *)pointer - XtOffsetOf(type, zo)) 60 | 61 | #define FETCH_RESOURCE_FROM_EXTEND(pointer, item, type) (type *) ((void *)pointer - XtOffsetOf(type, item)) 62 | 63 | #define FETCH_OBJECT_RESOURCE(object, type) FETCH_RESOURCE(Z_OBJ_P(object), type) 64 | #define FETCH_UV_LOOP() ((uv_loop_ext_t *)FETCH_OBJECT_RESOURCE(loop, uv_loop_ext_t))->loop 65 | 66 | #define REGISTER_CLASS_CONSTANT_LONG(class, name) \ 67 | zend_declare_class_constant_long(CLASS_ENTRY(class), ZEND_STRL(#name), name) 68 | 69 | #define ALLOC_RESOURCE(x) ecalloc(1, sizeof(x) + zend_object_properties_size(ce)) 70 | 71 | #define Z_DELREF_AND_DTOR_P(o) \ 72 | do{ \ 73 | if(Z_REFCOUNT_P(o) == 1){ \ 74 | zval_dtor(o); \ 75 | } \ 76 | else{ \ 77 | Z_DELREF_P(o); \ 78 | }\ 79 | }while(0) 80 | 81 | #endif 82 | 83 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | THIRDPARTY_BUILD_DIR="$srcdir/thirdparty/build" 2 | 3 | PHP_ADD_INCLUDE("$srcdir/thirdparty/libuv/include") 4 | 5 | PHP_ARG_ENABLE(php_ext_uv, whether to enable php_ext_uv support, 6 | Make sure that the comment is aligned: 7 | [ --enable-php_ext_uv Enable php_ext_uv support]) 8 | 9 | PHP_ARG_WITH(openssl, for OpenSSL support in event, 10 | [ --with-openssl Include OpenSSL support], yes, no) 11 | 12 | PHP_ARG_WITH(openssl-dir, for OpenSSL installation prefix, 13 | [ --with-openssl-dir[=DIR] openssl installation prefix], no, no) 14 | 15 | if test "$PHP_PHP_EXT_UV" != "no"; then 16 | 17 | MODULES=" 18 | php_ext_uv.c 19 | src/uv_loop.c 20 | src/uv_signal.c 21 | src/uv_timer.c 22 | src/uv_udp.c 23 | src/uv_tcp.c 24 | src/uv_resolver.c 25 | src/uv_idle.c 26 | src/uv_util.c 27 | src/uv_pipe.c 28 | src/uv_process.c 29 | src/uv_worker.c 30 | " 31 | 32 | dnl {{{ --with-event-openssl 33 | if test "$PHP_OPENSSL" != "no"; then 34 | test -z "$PHP_OPENSSL" && PHP_OPENSSL=no 35 | 36 | if test -z "$PHP_OPENSSL_DIR" || test $PHP_OPENSSL_DIR == "no"; then 37 | PHP_OPENSSL_DIR=yes 38 | fi 39 | 40 | PHP_SETUP_OPENSSL(PHP_EXT_UV_SHARED_LIBADD, [ 41 | AC_DEFINE(HAVE_OPENSSL,1,[ ]) 42 | ], [ 43 | AC_MSG_ERROR([OpenSSL libraries not found. 44 | 45 | Check the path given to --with-openssl-dir and output in config.log) 46 | ]) 47 | ]) 48 | MODULES="$MODULES src/uv_ssl.c src/ssl_verify.c" 49 | PHP_ADD_LIBRARY(ssl, PHP_EXT_UV_SHARED_LIBADD) 50 | fi 51 | dnl }}} 52 | 53 | 54 | PHP_NEW_EXTENSION(php_ext_uv, $MODULES, $ext_shared) 55 | 56 | fi 57 | 58 | PHP_EXT_UV_SHARED_LIBADD="-lrt -lpthread $PHP_EXT_UV_SHARED_LIBADD" 59 | PHP_ADD_MAKEFILE_FRAGMENT([Makefile.thirdparty]) 60 | 61 | shared_objects_php_ext_uv="$THIRDPARTY_BUILD_DIR/lib/libuv.a $shared_objects_php_ext_uv" 62 | PHP_SUBST(PHP_EXT_UV_SHARED_LIBADD) 63 | -------------------------------------------------------------------------------- /php_ext_uv.c: -------------------------------------------------------------------------------- 1 | #include "php_ext_uv.h" 2 | 3 | PHP_MINIT_FUNCTION(php_ext_uv); 4 | PHP_MSHUTDOWN_FUNCTION(php_ext_uv); 5 | PHP_MINFO_FUNCTION(php_ext_uv); 6 | 7 | zend_module_entry php_ext_uv_module_entry = { 8 | #if ZEND_MODULE_API_NO >= 20010901 9 | STANDARD_MODULE_HEADER, 10 | #endif 11 | "php_ext_uv", 12 | NULL, 13 | PHP_MINIT(php_ext_uv), 14 | PHP_MSHUTDOWN(php_ext_uv), 15 | NULL, 16 | NULL, 17 | PHP_MINFO(php_ext_uv), 18 | #if ZEND_MODULE_API_NO >= 20010901 19 | "0.1", 20 | #endif 21 | STANDARD_MODULE_PROPERTIES 22 | }; 23 | 24 | #if COMPILE_DL_PHP_EXT_UV 25 | ZEND_GET_MODULE(php_ext_uv) 26 | #endif 27 | 28 | PHP_MINIT_FUNCTION(php_ext_uv) { 29 | CLASS_ENTRY_FUNCTION_C(UVLoop); 30 | CLASS_ENTRY_FUNCTION_C(UVSignal); 31 | CLASS_ENTRY_FUNCTION_C(UVTimer); 32 | CLASS_ENTRY_FUNCTION_C(UVUdp); 33 | CLASS_ENTRY_FUNCTION_C(UVTcp); 34 | CLASS_ENTRY_FUNCTION_C(UVPipe); 35 | CLASS_ENTRY_FUNCTION_C(UVIdle); 36 | CLASS_ENTRY_FUNCTION_C(UVProcess); 37 | CLASS_ENTRY_FUNCTION_C(UVWorker); 38 | #ifdef HAVE_OPENSSL 39 | CLASS_ENTRY_FUNCTION_C(UVSSL); 40 | #endif 41 | CLASS_ENTRY_FUNCTION_C(UVResolver); 42 | CLASS_ENTRY_FUNCTION_C(UVUtil); 43 | return SUCCESS; 44 | } 45 | 46 | PHP_MSHUTDOWN_FUNCTION(php_ext_uv) { 47 | return SUCCESS; 48 | } 49 | 50 | PHP_MINFO_FUNCTION(php_ext_uv) { 51 | php_info_print_table_start(); 52 | php_info_print_table_header(2, "php_ext_uv support", "enabled"); 53 | php_info_print_table_end(); 54 | } 55 | -------------------------------------------------------------------------------- /php_ext_uv.h: -------------------------------------------------------------------------------- 1 | #ifndef _PHP_EXT_UV_H 2 | #define _PHP_EXT_UV_H 3 | 4 | #ifdef HAVE_CONFIG_H 5 | #include "config.h" 6 | #endif 7 | 8 | #ifdef ZTS 9 | #warning php_ext_uv module will *NEVER* be thread-safe 10 | #include 11 | #endif 12 | 13 | #include 14 | #include 15 | #include "common.h" 16 | #include "src/util.h" 17 | 18 | extern zend_module_entry php_ext_uv_module_entry; 19 | 20 | DECLARE_CLASS_ENTRY(UVLoop); 21 | DECLARE_CLASS_ENTRY(UVSignal); 22 | DECLARE_CLASS_ENTRY(UVTimer); 23 | DECLARE_CLASS_ENTRY(UVUdp); 24 | DECLARE_CLASS_ENTRY(UVTcp); 25 | DECLARE_CLASS_ENTRY(UVPipe); 26 | DECLARE_CLASS_ENTRY(UVIdle); 27 | DECLARE_CLASS_ENTRY(UVProcess); 28 | DECLARE_CLASS_ENTRY(UVWorker); 29 | #ifdef HAVE_OPENSSL 30 | DECLARE_CLASS_ENTRY(UVSSL); 31 | #endif 32 | DECLARE_CLASS_ENTRY(UVResolver); 33 | DECLARE_CLASS_ENTRY(UVUtil); 34 | #endif 35 | -------------------------------------------------------------------------------- /src/fcall.h: -------------------------------------------------------------------------------- 1 | #ifndef _FCALL_INFO_H 2 | #define _FCALL_INFO_H 3 | 4 | #define FCI_ADDREF(x) Z_TRY_ADDREF(x.fci.function_name) 5 | #define FCI_PARSE_PARAMETERS_CC(x) &x.fci, &x.fcc 6 | #define FCI_ISNULL(x) (x.fci.size == 0) 7 | #define FCI_FREE(x) freeFunctionCache(&x) 8 | #define FCI_GC_TABLE(res, pn) \ 9 | do{ \ 10 | if(res->pn.fci.size){ \ 11 | ZVAL_COPY_VALUE(&res->gc_table.pn, &res->pn.fci.function_name); \ 12 | } \ 13 | } while(0) 14 | 15 | #define FCI_GC_TABLE_EX(res, pn, index) FCI_GC_TABLE_EX_FROM_EXTEND(res, res, pn, index) 16 | 17 | #define FCI_GC_TABLE_EX_FROM_EXTEND(res, extres, pn, index) \ 18 | do{ \ 19 | if(extres->pn.fci.size){ \ 20 | ZVAL_COPY_VALUE(&res->gc_table[index], &extres->pn.fci.function_name); \ 21 | index++; \ 22 | } \ 23 | } while(0) 24 | 25 | #define FCI_GC_TABLE_SIZE(x) sizeof(x) / sizeof(zval) 26 | 27 | typedef struct fcall_info_s { 28 | zend_fcall_info fci; 29 | zend_fcall_info_cache fcc; 30 | } fcall_info_t; 31 | 32 | static zend_always_inline int fci_call_function(fcall_info_t *fcall, zval *retval, uint32_t param_count, zval *params) { 33 | if(fcall->fci.size == 0){ 34 | return FAILURE; 35 | } 36 | fcall->fci.params = params; 37 | fcall->fci.retval = retval; 38 | fcall->fci.param_count = param_count; 39 | return zend_call_function(&fcall->fci, &fcall->fcc); 40 | } 41 | 42 | static zend_always_inline void freeFunctionCache(fcall_info_t *fcall){ 43 | if(fcall->fci.size > 0){ 44 | if(Z_REFCOUNTED(fcall->fci.function_name)){ 45 | zval_dtor(&fcall->fci.function_name); 46 | } 47 | fcall->fci.size = 0; 48 | } 49 | } 50 | #endif -------------------------------------------------------------------------------- /src/fcall_info.h: -------------------------------------------------------------------------------- 1 | #ifndef _FCALL_INFO_H 2 | #define _FCALL_INFO_H 3 | 4 | typedef struct fcall_info_s { 5 | zval func; 6 | zend_fcall_info fci; 7 | zend_fcall_info_cache fcc; 8 | } fcall_info_t; 9 | 10 | static zend_always_inline int fci_call_function(fcall_info_t *fcall_into, zval *retval, uint32_t param_count, zval *params) { 11 | if(fcall_into->fci.size == 0){ 12 | return FAILURE; 13 | } 14 | fcall_into->fci.params = params; 15 | fcall_into->fci.retval = retval; 16 | fcall_into->fci.param_count = param_count; 17 | return zend_call_function(&fcall_into->fci, &fcall_into->fcc); 18 | } 19 | 20 | static zend_always_inline void freeFunctionCache(fcall_info_t *fcall){ 21 | if(fcall->fci.size > 0){ 22 | zval_dtor(&fcall->fci.function_name); 23 | zval_dtor(&fcall->func); 24 | fcall->fci.size = 0; 25 | } 26 | } 27 | 28 | static zend_always_inline void registerFunctionCache(fcall_info_t *fcall_into, zval *cb) { 29 | char *errstr = NULL; 30 | freeFunctionCache(fcall_into); 31 | if (zend_fcall_info_init(cb, 0, &fcall_into->fci, &fcall_into->fcc, NULL, &errstr) == FAILURE) { 32 | php_error_docref(NULL, E_WARNING, "param cb is not callable"); 33 | return; 34 | } 35 | Z_ADDREF(fcall_into->fci.function_name); 36 | Z_ADDREF_P(cb); 37 | ZVAL_COPY_VALUE(&fcall_into->func ,cb); 38 | } 39 | 40 | 41 | 42 | #endif -------------------------------------------------------------------------------- /src/ssl_verify.c: -------------------------------------------------------------------------------- 1 | #include "ssl_verify.h" 2 | 3 | int matches_wildcard_name(const char *subjectname, const char *certname) { 4 | int match = (strcmp(subjectname, certname) == 0); 5 | if (!match && strlen(certname) > 3 && certname[0] == '*' && certname[1] == '.') { 6 | /* Try wildcard */ 7 | if (strchr(certname+2, '.')){ 8 | const char* cnmatch_str = subjectname; 9 | const char *tmp = strstr(cnmatch_str, certname+1); 10 | match = tmp && strcmp(tmp, certname+2) && tmp == strchr(cnmatch_str, '.'); 11 | } 12 | } 13 | return match; 14 | } 15 | 16 | int matches_san_list(X509 *peer, const char *subject_name) { 17 | int i, len; 18 | unsigned char *cert_name = NULL; 19 | char ipbuffer[64]; 20 | 21 | GENERAL_NAMES *alt_names = X509_get_ext_d2i(peer, NID_subject_alt_name, 0, 0); 22 | int alt_name_count = sk_GENERAL_NAME_num(alt_names); 23 | 24 | for (i = 0; i < alt_name_count; i++) { 25 | GENERAL_NAME *san = sk_GENERAL_NAME_value(alt_names, i); 26 | 27 | if (san->type == GEN_DNS) { 28 | ASN1_STRING_to_UTF8(&cert_name, san->d.dNSName); 29 | if (ASN1_STRING_length(san->d.dNSName) != strlen((const char*)cert_name)) { 30 | OPENSSL_free(cert_name); 31 | /* prevent null-byte poisoning*/ 32 | continue; 33 | } 34 | 35 | /* accommodate valid FQDN entries ending in "." */ 36 | len = strlen((const char*)cert_name); 37 | if (len && strcmp((const char *)&cert_name[len-1], ".") == 0) { 38 | cert_name[len-1] = '\0'; 39 | } 40 | 41 | if (matches_wildcard_name(subject_name, (const char *)cert_name)) { 42 | OPENSSL_free(cert_name); 43 | return 1; 44 | } 45 | OPENSSL_free(cert_name); 46 | } else if (san->type == GEN_IPADD) { 47 | if (san->d.iPAddress->length == 4) { 48 | sprintf(ipbuffer, "%d.%d.%d.%d", 49 | san->d.iPAddress->data[0], 50 | san->d.iPAddress->data[1], 51 | san->d.iPAddress->data[2], 52 | san->d.iPAddress->data[3] 53 | ); 54 | if (strcasecmp(subject_name, (const char*)ipbuffer) == 0) { 55 | return 1; 56 | } 57 | } 58 | /* No, we aren't bothering to check IPv6 addresses. Why? 59 | * * Because IP SAN names are officially deprecated and are 60 | * * not allowed by CAs starting in 2015. Deal with it. 61 | * */ 62 | } 63 | } 64 | 65 | return 0; 66 | } 67 | 68 | int matches_common_name(X509 *peer, const char *subject_name) { 69 | char buf[1024]; 70 | X509_NAME *cert_name; 71 | int cert_name_len; 72 | 73 | cert_name = X509_get_subject_name(peer); 74 | cert_name_len = X509_NAME_get_text_by_NID(cert_name, NID_commonName, buf, sizeof(buf)); 75 | if (cert_name_len == -1) { 76 | return 0; 77 | } 78 | 79 | if (cert_name_len != strlen(buf)) { 80 | return 0; 81 | } 82 | if (!strcmp(subject_name, buf) && !matches_wildcard_name(subject_name, buf)) { 83 | return 0; 84 | } 85 | return 1; 86 | } 87 | -------------------------------------------------------------------------------- /src/ssl_verify.h: -------------------------------------------------------------------------------- 1 | #ifndef SSL_VERIFY_H 2 | #define SSL_VERIFY_H 3 | 4 | #include 5 | #include 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | int matches_wildcard_name(const char *subjectname, const char *certname); 12 | 13 | int matches_san_list(X509 *peer, const char *subject_name); 14 | 15 | int matches_common_name(X509 *peer, const char *subject_name); 16 | 17 | #ifdef __cplusplus 18 | } 19 | #endif 20 | 21 | #endif -------------------------------------------------------------------------------- /src/util.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_H 2 | #define UTIL_H 3 | #include "../php_ext_uv.h" 4 | 5 | #define TIMEVAL_SET(tv, t) \ 6 | do { \ 7 | tv.tv_sec = (long) t; \ 8 | tv.tv_usec = (long) ((t - tv.tv_sec) * 1e6); \ 9 | } while (0) 10 | 11 | #define TIMEVAL_TO_DOUBLE(tv) (tv.tv_sec + tv.tv_usec * 1e-6) 12 | 13 | static zend_always_inline char *sock_addr(struct sockaddr *addr) { 14 | struct sockaddr_in addr_in = *(struct sockaddr_in *) addr; 15 | char *ip = emalloc(20); 16 | uv_ip4_name(&addr_in, ip, 20); 17 | return ip; 18 | } 19 | 20 | static zend_always_inline int sock_port(struct sockaddr *addr) { 21 | struct sockaddr_in addr_in = *(struct sockaddr_in *) addr; 22 | return ntohs(addr_in.sin_port); 23 | } 24 | 25 | #define COPY_C_STR(c_str, str, str_len) \ 26 | memcpy(c_str, str, str_len); \ 27 | c_str[str_len] = '\0' 28 | 29 | #define MAKE_C_STR(c_str, str, str_len) \ 30 | c_str = emalloc(str_len + 1); \ 31 | COPY_C_STR(c_str, str, str_len) 32 | 33 | int check_zval_type(zend_class_entry *call_ce, const char * function_name, uint function_name_len, zend_class_entry *instance_ce, zval *val); 34 | #endif /* UTIL_H */ 35 | -------------------------------------------------------------------------------- /src/uv_idle.c: -------------------------------------------------------------------------------- 1 | #include "uv_idle.h" 2 | 3 | CLASS_ENTRY_FUNCTION_D(UVIdle){ 4 | REGISTER_CLASS_WITH_OBJECT_NEW(UVIdle, createUVIdleResource); 5 | OBJECT_HANDLER(UVIdle).offset = XtOffsetOf(uv_idle_ext_t, zo); 6 | OBJECT_HANDLER(UVIdle).clone_obj = NULL; 7 | OBJECT_HANDLER(UVIdle).free_obj = freeUVIdleResource; 8 | OBJECT_HANDLER(UVIdle).get_gc = get_gc_UVIdleResource; 9 | zend_declare_property_null(CLASS_ENTRY(UVIdle), ZEND_STRL("loop"), ZEND_ACC_PRIVATE); 10 | } 11 | 12 | static void idle_handle_callback(uv_idle_ext_t *idle_handle){ 13 | zval retval; 14 | fci_call_function(&idle_handle->callback, &retval, 1, &idle_handle->object); 15 | zval_ptr_dtor(&retval); 16 | } 17 | 18 | static zend_object *createUVIdleResource(zend_class_entry *ce) { 19 | uv_idle_ext_t *resource; 20 | resource = ALLOC_RESOURCE(uv_idle_ext_t); 21 | zend_object_std_init(&resource->zo, ce); 22 | object_properties_init(&resource->zo, ce); 23 | resource->zo.handlers = &OBJECT_HANDLER(UVIdle); 24 | return &resource->zo; 25 | } 26 | 27 | static HashTable *get_gc_UVIdleResource(zval *obj, zval **table, int *n) { 28 | uv_idle_ext_t *resource; 29 | resource = FETCH_OBJECT_RESOURCE(obj, uv_idle_ext_t); 30 | FCI_GC_TABLE(resource, callback); 31 | *table = (zval *) &resource->gc_table; 32 | *n = FCI_GC_TABLE_SIZE(resource->gc_table); 33 | return zend_std_get_properties(obj); 34 | } 35 | 36 | void freeUVIdleResource(zend_object *object) { 37 | uv_idle_ext_t *resource; 38 | resource = FETCH_RESOURCE(object, uv_idle_ext_t); 39 | if(resource->start){ 40 | uv_idle_stop((uv_idle_t *) resource); 41 | } 42 | uv_unref((uv_handle_t *) resource); 43 | freeFunctionCache(&resource->callback); 44 | zend_object_std_dtor(&resource->zo); 45 | } 46 | 47 | PHP_METHOD(UVIdle, __construct){ 48 | zval *loop = NULL; 49 | zval *self = getThis(); 50 | zend_function *fptr; 51 | uv_idle_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_idle_ext_t); 52 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|z", &loop)) { 53 | return; 54 | } 55 | 56 | if(NULL == loop || ZVAL_IS_NULL(loop)){ 57 | uv_idle_init(uv_default_loop(), (uv_idle_t *) resource); 58 | return; 59 | } 60 | 61 | zend_update_property(CLASS_ENTRY(UVIdle), self, ZEND_STRL("loop"), loop); 62 | uv_idle_init(FETCH_UV_LOOP(), (uv_idle_t *) resource); 63 | } 64 | 65 | PHP_METHOD(UVIdle, start){ 66 | long ret; 67 | zval *self = getThis(); 68 | uv_idle_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_idle_ext_t); 69 | FCI_FREE(resource->callback); 70 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "f", FCI_PARSE_PARAMETERS_CC(resource->callback))) { 71 | return; 72 | } 73 | FCI_ADDREF(resource->callback); 74 | 75 | if(ret = uv_idle_start((uv_idle_t *) resource, (uv_idle_cb) idle_handle_callback)){ 76 | FCI_FREE(resource->callback); 77 | RETURN_LONG(ret); 78 | } 79 | 80 | resource->start = 1; 81 | ZVAL_COPY_VALUE(&resource->object, self); 82 | RETURN_LONG(ret); 83 | } 84 | 85 | PHP_METHOD(UVIdle, stop){ 86 | long ret; 87 | zval *self = getThis(); 88 | uv_idle_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_idle_ext_t); 89 | if(!resource->start){ 90 | RETURN_LONG(-1); 91 | } 92 | 93 | ret = uv_idle_stop((uv_idle_t *) resource); 94 | if(ret == 0){ 95 | resource->start = 0; 96 | zval_dtor(&resource->object); 97 | } 98 | RETURN_LONG(ret); 99 | } 100 | -------------------------------------------------------------------------------- /src/uv_idle.h: -------------------------------------------------------------------------------- 1 | #ifndef _UV_IDLE_H 2 | #define _UV_IDLE_H 3 | #include "../php_ext_uv.h" 4 | #include "uv_loop_resource.h" 5 | #include "fcall.h" 6 | 7 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVIdle, __construct), 0) 8 | ZEND_ARG_OBJ_INFO(0, loop, UVLoop, 1) 9 | ZEND_END_ARG_INFO() 10 | 11 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVIdle, start), 0) 12 | ZEND_ARG_INFO(0, idle_cb) 13 | ZEND_END_ARG_INFO() 14 | 15 | typedef struct uv_idle_ext_s{ 16 | uv_idle_t uv_idle; 17 | int start; 18 | struct { 19 | zval callback; 20 | } gc_table; 21 | fcall_info_t callback; 22 | zval object; 23 | zend_object zo; 24 | } uv_idle_ext_t; 25 | 26 | static zend_object *createUVIdleResource(zend_class_entry *class_type); 27 | static void idle_handle_callback(uv_idle_ext_t *idle_handle); 28 | void freeUVIdleResource(zend_object *object); 29 | static HashTable *get_gc_UVIdleResource(zval *obj, zval **table, int *n); 30 | 31 | PHP_METHOD(UVIdle, __construct); 32 | PHP_METHOD(UVIdle, start); 33 | PHP_METHOD(UVIdle, stop); 34 | 35 | DECLARE_FUNCTION_ENTRY(UVIdle) = { 36 | PHP_ME(UVIdle, __construct, ARGINFO(UVIdle, __construct), ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) 37 | PHP_ME(UVIdle, start, ARGINFO(UVIdle, start), ZEND_ACC_PUBLIC) 38 | PHP_ME(UVIdle, stop, NULL, ZEND_ACC_PUBLIC) 39 | PHP_FE_END 40 | }; 41 | #endif 42 | -------------------------------------------------------------------------------- /src/uv_loop.c: -------------------------------------------------------------------------------- 1 | #include "uv_loop.h" 2 | 3 | CLASS_ENTRY_FUNCTION_D(UVLoop){ 4 | REGISTER_CLASS_WITH_OBJECT_NEW(UVLoop, createUVLoopResource); 5 | OBJECT_HANDLER(UVLoop).offset = XtOffsetOf(uv_loop_ext_t, zo); 6 | OBJECT_HANDLER(UVLoop).clone_obj = NULL; 7 | OBJECT_HANDLER(UVLoop).free_obj = freeUVLoopResource; 8 | REGISTER_CLASS_CONSTANT_LONG(UVLoop, RUN_DEFAULT); 9 | REGISTER_CLASS_CONSTANT_LONG(UVLoop, RUN_ONCE); 10 | REGISTER_CLASS_CONSTANT_LONG(UVLoop, RUN_NOWAIT); 11 | zend_declare_property_null(CLASS_ENTRY(UVLoop), ZEND_STRL("loop"), ZEND_ACC_PRIVATE|ZEND_ACC_STATIC); 12 | } 13 | 14 | static zend_object *createUVLoopResource(zend_class_entry *ce) { 15 | uv_loop_ext_t *resource; 16 | resource = ALLOC_RESOURCE(uv_loop_ext_t); 17 | resource->loop = (uv_loop_t *) resource; 18 | uv_loop_init(resource->loop); 19 | zend_object_std_init(&resource->zo, ce); 20 | object_properties_init(&resource->zo, ce); 21 | resource->zo.handlers = &OBJECT_HANDLER(UVLoop); 22 | return &resource->zo; 23 | } 24 | 25 | void freeUVLoopResource(zend_object *object) { 26 | uv_loop_ext_t *resource; 27 | resource = FETCH_RESOURCE(object, uv_loop_ext_t); 28 | if((uv_loop_t *)resource == resource->loop){ 29 | uv_loop_close((uv_loop_t *) resource); 30 | } 31 | zend_object_std_dtor(&resource->zo); 32 | efree(resource); 33 | } 34 | 35 | PHP_METHOD(UVLoop, run){ 36 | long option = RUN_DEFAULT; 37 | uv_run_mode mode; 38 | zval *self = getThis(); 39 | uv_loop_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_loop_ext_t); 40 | if(zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &option) == FAILURE) { 41 | return; 42 | } 43 | switch(option){ 44 | case RUN_DEFAULT: 45 | mode = UV_RUN_DEFAULT; 46 | break; 47 | case RUN_ONCE: 48 | mode = UV_RUN_ONCE; 49 | break; 50 | case RUN_NOWAIT: 51 | mode = UV_RUN_NOWAIT; 52 | break; 53 | default: 54 | mode = UV_RUN_DEFAULT; 55 | } 56 | uv_run(resource->loop, mode); 57 | } 58 | 59 | PHP_METHOD(UVLoop, stop) { 60 | zval *self = getThis(); 61 | uv_loop_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_loop_ext_t); 62 | uv_stop(resource->loop); 63 | } 64 | 65 | PHP_METHOD(UVLoop, alive) { 66 | zval *self = getThis(); 67 | uv_loop_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_loop_ext_t); 68 | RETURN_LONG(uv_loop_alive(resource->loop)); 69 | } 70 | 71 | PHP_METHOD(UVLoop, updateTime) { 72 | zval *self = getThis(); 73 | uv_loop_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_loop_ext_t); 74 | uv_update_time(resource->loop); 75 | } 76 | 77 | PHP_METHOD(UVLoop, now) { 78 | zval *self = getThis(); 79 | uv_loop_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_loop_ext_t); 80 | RETURN_LONG(uv_now(resource->loop)); 81 | } 82 | 83 | PHP_METHOD(UVLoop, backendFd) { 84 | zval *self = getThis(); 85 | uv_loop_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_loop_ext_t); 86 | RETURN_LONG(uv_backend_fd(resource->loop)); 87 | } 88 | 89 | PHP_METHOD(UVLoop, backendTimeout) { 90 | zval *self = getThis(); 91 | uv_loop_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_loop_ext_t); 92 | RETURN_LONG(uv_backend_timeout(resource->loop)); 93 | } 94 | 95 | PHP_METHOD(UVLoop, defaultLoop) { 96 | zval *instance = zend_read_static_property(CLASS_ENTRY(UVLoop), ZEND_STRL("loop"), 1); 97 | if(Z_ISNULL_P(instance)) { 98 | object_init_ex(instance, CLASS_ENTRY(UVLoop)); 99 | zend_update_static_property(CLASS_ENTRY(UVLoop), ZEND_STRL("loop"), instance); 100 | uv_loop_ext_t *resource = FETCH_OBJECT_RESOURCE(instance, uv_loop_ext_t); 101 | resource->loop = uv_default_loop(); 102 | } 103 | RETURN_ZVAL(instance, 1, 0); 104 | } 105 | -------------------------------------------------------------------------------- /src/uv_loop.h: -------------------------------------------------------------------------------- 1 | #ifndef _UV_LOOP_H 2 | #define _UV_LOOP_H 3 | #include "../php_ext_uv.h" 4 | #include "uv_loop_resource.h" 5 | 6 | #define RUN_DEFAULT 0 7 | #define RUN_ONCE 1 8 | #define RUN_NOWAIT 2 9 | 10 | 11 | CLASS_ENTRY_FUNCTION_D(UVLoop); 12 | 13 | static zend_object *createUVLoopResource(zend_class_entry *class_type); 14 | void freeUVLoopResource(zend_object *object); 15 | 16 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVLoop, run), 0) 17 | ZEND_ARG_INFO(0, option) 18 | ZEND_END_ARG_INFO() 19 | 20 | PHP_METHOD(UVLoop, defaultLoop); 21 | PHP_METHOD(UVLoop, run); 22 | PHP_METHOD(UVLoop, stop); 23 | PHP_METHOD(UVLoop, alive); 24 | PHP_METHOD(UVLoop, updateTime); 25 | PHP_METHOD(UVLoop, now); 26 | PHP_METHOD(UVLoop, backendFd); 27 | PHP_METHOD(UVLoop, backendTimeout); 28 | 29 | DECLARE_FUNCTION_ENTRY(UVLoop) = { 30 | PHP_ME(UVLoop, defaultLoop, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) 31 | PHP_ME(UVLoop, run, ARGINFO(UVLoop, run), ZEND_ACC_PUBLIC) 32 | PHP_ME(UVLoop, stop, NULL, ZEND_ACC_PUBLIC) 33 | PHP_ME(UVLoop, alive, NULL, ZEND_ACC_PUBLIC) 34 | PHP_ME(UVLoop, updateTime, NULL, ZEND_ACC_PUBLIC) 35 | PHP_ME(UVLoop, now, NULL, ZEND_ACC_PUBLIC) 36 | PHP_ME(UVLoop, backendFd, NULL, ZEND_ACC_PUBLIC) 37 | PHP_ME(UVLoop, backendTimeout, NULL, ZEND_ACC_PUBLIC) 38 | PHP_FE_END 39 | }; 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/uv_loop_resource.h: -------------------------------------------------------------------------------- 1 | #ifndef _UV_LOOP_RESOURCE_H 2 | #define _UV_LOOP_RESOURCE_H 3 | 4 | typedef struct uv_loop_ext_s{ 5 | uv_loop_t __loop__; 6 | uv_loop_t *loop; 7 | zend_object zo; 8 | } uv_loop_ext_t; 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/uv_pipe.c: -------------------------------------------------------------------------------- 1 | #include "uv_pipe.h" 2 | 3 | void pipe_close_socket(uv_pipe_ext_t *handle){ 4 | if(handle->flag & UV_PIPE_CLOSING_START){ 5 | return; 6 | } 7 | handle->flag |= UV_PIPE_CLOSING_START; 8 | uv_close((uv_handle_t *) handle, pipe_close_cb); 9 | } 10 | 11 | void setSelfReference(uv_pipe_ext_t *resource) 12 | { 13 | if(resource->flag & UV_PIPE_HANDLE_INTERNAL_REF){ 14 | return; 15 | } 16 | Z_ADDREF(resource->object); 17 | resource->flag |= UV_PIPE_HANDLE_INTERNAL_REF; 18 | } 19 | 20 | CLASS_ENTRY_FUNCTION_D(UVPipe){ 21 | REGISTER_CLASS_WITH_OBJECT_NEW(UVPipe, createUVPipeResource); 22 | OBJECT_HANDLER(UVPipe).offset = XtOffsetOf(uv_pipe_ext_t, zo); 23 | OBJECT_HANDLER(UVPipe).clone_obj = NULL; 24 | OBJECT_HANDLER(UVPipe).free_obj = freeUVPipeResource; 25 | OBJECT_HANDLER(UVPipe).get_gc = get_gc_UVPipeResource; 26 | zend_declare_property_null(CLASS_ENTRY(UVPipe), ZEND_STRL("loop"), ZEND_ACC_PRIVATE); 27 | } 28 | 29 | HashTable *get_gc_UVPipeResource(zval *obj, zval **table, int *n) { 30 | uv_pipe_ext_t *resource = FETCH_OBJECT_RESOURCE(obj, uv_pipe_ext_t); 31 | *table = &resource->gc_table[0]; 32 | int index = 0; 33 | FCI_GC_TABLE_EX(resource, readCallback, index); 34 | FCI_GC_TABLE_EX(resource, writeCallback, index); 35 | FCI_GC_TABLE_EX(resource, errorCallback, index); 36 | FCI_GC_TABLE_EX(resource, connectCallback, index); 37 | FCI_GC_TABLE_EX(resource, shutdownCallback, index); 38 | *n = index; 39 | return zend_std_get_properties(obj); 40 | } 41 | 42 | void releaseResource(uv_pipe_ext_t *resource){ 43 | if(resource->sockAddr != NULL){ 44 | efree(resource->sockAddr); 45 | resource->sockAddr = NULL; 46 | } 47 | 48 | if(resource->peerAddr != NULL){ 49 | efree(resource->peerAddr); 50 | resource->peerAddr = NULL; 51 | } 52 | 53 | if(resource->flag & UV_PIPE_READ_START){ 54 | resource->flag &= ~UV_PIPE_READ_START; 55 | uv_read_stop((uv_stream_t *) &resource->uv_pipe); 56 | } 57 | 58 | if(resource->flag & UV_PIPE_HANDLE_START){ 59 | resource->flag &= ~UV_PIPE_HANDLE_START; 60 | uv_unref((uv_handle_t *) &resource->uv_pipe); 61 | } 62 | 63 | if(resource->flag & UV_PIPE_HANDLE_INTERNAL_REF){ 64 | resource->flag &= ~UV_PIPE_HANDLE_INTERNAL_REF; 65 | zval_ptr_dtor(&resource->object); 66 | } 67 | } 68 | 69 | static void shutdown_cb(uv_shutdown_t* req, int status) { 70 | uv_pipe_ext_t *resource = (uv_pipe_ext_t *) req->handle; 71 | zval retval; 72 | zval params[2]; 73 | params[0] = resource->object; 74 | if(!FCI_ISNULL(resource->shutdownCallback)){ 75 | ZVAL_LONG(¶ms[1], status); 76 | fci_call_function(&resource->shutdownCallback, &retval, 2, params); 77 | zval_ptr_dtor(&retval); 78 | } 79 | } 80 | 81 | static void pipe_close_cb(uv_handle_t* handle) { 82 | releaseResource((uv_pipe_ext_t *) handle); 83 | } 84 | 85 | static void write_cb(uv_write_t *wr, int status){ 86 | zval retval; 87 | write_req_t *req = (write_req_t *) wr; 88 | uv_pipe_ext_t *resource = (uv_pipe_ext_t *) req->uv_write.handle; 89 | zval params[3]; 90 | params[0] = resource->object; 91 | 92 | if(resource->flag & UV_PIPE_WRITE_CALLBACK_ENABLE && !FCI_ISNULL(resource->writeCallback)){ 93 | ZVAL_LONG(¶ms[1], status); 94 | ZVAL_LONG(¶ms[2], req->buf.len); 95 | fci_call_function(&resource->writeCallback, &retval, 3, params); 96 | zval_ptr_dtor(&retval); 97 | } 98 | efree(req->buf.base); 99 | efree(req); 100 | } 101 | 102 | static void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { 103 | buf->base = emalloc(suggested_size); 104 | buf->len = suggested_size; 105 | } 106 | 107 | static void read_cb(uv_pipe_ext_t *resource, ssize_t nread, const uv_buf_t* buf) { 108 | zval retval; 109 | zval params[2]; 110 | params[0] = resource->object; 111 | 112 | if(nread > 0){ 113 | if(!FCI_ISNULL(resource->readCallback)){ 114 | ZVAL_STRINGL(¶ms[1], buf->base, nread); 115 | fci_call_function(&resource->readCallback, &retval, 2, params); 116 | zval_ptr_dtor(¶ms[1]); 117 | zval_ptr_dtor(&retval); 118 | } 119 | } 120 | else{ 121 | if(!FCI_ISNULL(resource->errorCallback)){ 122 | ZVAL_LONG(¶ms[1], nread); 123 | fci_call_function(&resource->errorCallback, &retval, 2, params); 124 | zval_ptr_dtor(&retval); 125 | } 126 | pipe_close_socket((uv_pipe_ext_t *) &resource->uv_pipe); 127 | } 128 | efree(buf->base); 129 | } 130 | 131 | static void ipc_read_cb(uv_pipe_ext_t *resource, ssize_t nread, const uv_buf_t* buf) { 132 | if(nread > 0){ 133 | while (uv_pipe_pending_count((uv_pipe_t*) resource) != 0) { 134 | if(uv_pipe_pending_type((uv_pipe_t*) resource) == UV_TCP){ 135 | connection_cb(resource, 0); 136 | } 137 | } 138 | } 139 | efree(buf->base); 140 | } 141 | 142 | 143 | static void client_connection_cb(uv_connect_t* req, int status) { 144 | zval retval; 145 | uv_pipe_ext_t *resource = (uv_pipe_ext_t *) req->handle; 146 | zval params[2]; 147 | params[0] = resource->object; 148 | ZVAL_NULL(&retval); 149 | ZVAL_LONG(¶ms[1], status); 150 | 151 | if(uv_read_start((uv_stream_t *) resource, alloc_cb, (uv_read_cb) read_cb)){ 152 | return; 153 | } 154 | resource->flag |= (UV_PIPE_HANDLE_START|UV_PIPE_READ_START); 155 | 156 | fci_call_function(&resource->connectCallback, &retval, 2, params); 157 | zval_ptr_dtor(&retval); 158 | } 159 | 160 | static void connection_cb(uv_pipe_ext_t *resource, int status) { 161 | zval retval; 162 | zval params[2]; 163 | params[0] = resource->object; 164 | ZVAL_NULL(&retval); 165 | ZVAL_LONG(¶ms[1], status); 166 | fci_call_function(&resource->connectCallback, &retval, 2, params); 167 | zval_ptr_dtor(&retval); 168 | } 169 | 170 | static zend_object *createUVPipeResource(zend_class_entry *ce) { 171 | uv_pipe_ext_t *resource; 172 | resource = ALLOC_RESOURCE(uv_pipe_ext_t); 173 | zend_object_std_init(&resource->zo, ce); 174 | object_properties_init(&resource->zo, ce); 175 | resource->zo.handlers = &OBJECT_HANDLER(UVPipe); 176 | return &resource->zo; 177 | } 178 | 179 | static void freeUVPipeResource(zend_object *object) { 180 | uv_pipe_ext_t *resource; 181 | resource = FETCH_RESOURCE(object, uv_pipe_ext_t); 182 | releaseResource(resource); 183 | releaseUVPipeFunctionCache(resource); 184 | zend_object_std_dtor(object); 185 | } 186 | 187 | static zend_always_inline void resolveSocket(uv_pipe_ext_t *resource){ 188 | size_t addrlen = UV_PIPE_SOCKENAME_SIZE; 189 | char *addr; 190 | if(resource->sockAddr == NULL){ 191 | addr = emalloc(addrlen); 192 | if(uv_pipe_getsockname(&resource->uv_pipe, addr, &addrlen)){ 193 | efree(addr); 194 | return; 195 | } 196 | resource->sockAddr = addr; 197 | } 198 | } 199 | 200 | static zend_always_inline void resolvePeerSocket(uv_pipe_ext_t *resource){ 201 | size_t addrlen = UV_PIPE_SOCKENAME_SIZE; 202 | char *addr; 203 | if(resource->peerAddr == NULL){ 204 | addr = emalloc(addrlen); 205 | if(uv_pipe_getpeername(&resource->uv_pipe, addr, &addrlen)){ 206 | efree(addr); 207 | return; 208 | } 209 | resource->peerAddr = addr; 210 | } 211 | } 212 | 213 | PHP_METHOD(UVPipe, getSockname){ 214 | zval *self = getThis(); 215 | uv_pipe_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_pipe_ext_t); 216 | resolveSocket(resource); 217 | if(resource->sockAddr == NULL){ 218 | RETURN_FALSE; 219 | } 220 | RETURN_STRING(resource->sockAddr); 221 | } 222 | 223 | PHP_METHOD(UVPipe, getPeername){ 224 | zval *self = getThis(); 225 | uv_pipe_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_pipe_ext_t); 226 | resolvePeerSocket(resource); 227 | if(resource->peerAddr == NULL){ 228 | RETURN_FALSE; 229 | } 230 | RETURN_STRING(resource->peerAddr); 231 | } 232 | 233 | PHP_METHOD(UVPipe, accept){ 234 | long ret; 235 | zval *self = getThis(); 236 | const char *host; 237 | int host_len; 238 | char cstr_host[30]; 239 | struct sockaddr_in addr; 240 | uv_pipe_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_pipe_ext_t); 241 | uv_pipe_ext_t *client_resource; 242 | 243 | object_init_ex(return_value, CLASS_ENTRY(UVPipe)); 244 | if(!make_accepted_uv_pipe_object(resource, return_value)){ 245 | RETURN_FALSE; 246 | } 247 | 248 | client_resource = FETCH_OBJECT_RESOURCE(return_value, uv_pipe_ext_t); 249 | if(uv_read_start((uv_stream_t *) client_resource, alloc_cb, (uv_read_cb) read_cb)){ 250 | RETURN_FALSE; 251 | } 252 | } 253 | 254 | PHP_METHOD(UVPipe, listen){ 255 | long ret; 256 | zval *self = getThis(); 257 | const char *host = NULL; 258 | size_t host_len; 259 | struct sockaddr_in addr; 260 | 261 | uv_pipe_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_pipe_ext_t); 262 | 263 | if(((uv_pipe_ext_t *) &resource->uv_pipe)->flag & UV_PIPE_HANDLE_START){ 264 | RETURN_LONG(-1); 265 | } 266 | 267 | FCI_FREE(resource->connectCallback); 268 | 269 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "sf", &host, &host_len, FCI_PARSE_PARAMETERS_CC(resource->connectCallback))) { 270 | return; 271 | } 272 | 273 | if(host_len == 0){ 274 | RETURN_LONG(-1); 275 | } 276 | 277 | if((ret = uv_pipe_bind(&resource->uv_pipe, host)) != 0){ 278 | RETURN_LONG(ret); 279 | } 280 | 281 | if((ret = uv_listen((uv_stream_t *) &resource->uv_pipe, SOMAXCONN, (uv_connection_cb) connection_cb)) != 0){ 282 | RETURN_LONG(ret); 283 | } 284 | 285 | FCI_ADDREF(resource->connectCallback); 286 | setSelfReference(resource); 287 | resource->flag |= UV_PIPE_HANDLE_START; 288 | RETURN_LONG(ret); 289 | } 290 | 291 | PHP_METHOD(UVPipe, setCallback){ 292 | long ret; 293 | zval *self = getThis(); 294 | uv_pipe_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_pipe_ext_t); 295 | 296 | FCI_FREE(resource->readCallback); 297 | FCI_FREE(resource->writeCallback); 298 | FCI_FREE(resource->errorCallback); 299 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "fff", FCI_PARSE_PARAMETERS_CC(resource->readCallback), FCI_PARSE_PARAMETERS_CC(resource->writeCallback), FCI_PARSE_PARAMETERS_CC(resource->errorCallback))) { 300 | return; 301 | } 302 | 303 | FCI_ADDREF(resource->readCallback); 304 | FCI_ADDREF(resource->writeCallback); 305 | FCI_ADDREF(resource->errorCallback); 306 | setSelfReference(resource); 307 | RETURN_LONG(ret); 308 | } 309 | 310 | PHP_METHOD(UVPipe, close){ 311 | long ret; 312 | zval *self = getThis(); 313 | uv_pipe_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_pipe_ext_t); 314 | pipe_close_socket((uv_pipe_ext_t *) &resource->uv_pipe); 315 | } 316 | 317 | PHP_METHOD(UVPipe, __construct){ 318 | zval *loop = NULL; 319 | zval *self = getThis(); 320 | int ipc = 0; 321 | uv_pipe_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_pipe_ext_t); 322 | 323 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|zb", &loop, &ipc)) { 324 | return; 325 | } 326 | 327 | ZVAL_COPY_VALUE(&resource->object, self); 328 | 329 | if(NULL == loop || ZVAL_IS_NULL(loop)){ 330 | uv_pipe_init(uv_default_loop(), (uv_pipe_t *) resource, ipc); 331 | return; 332 | } 333 | zend_update_property(CLASS_ENTRY(UVPipe), self, ZEND_STRL("loop"), loop); 334 | uv_pipe_init(FETCH_UV_LOOP(), (uv_pipe_t *) resource, ipc); 335 | } 336 | 337 | PHP_METHOD(UVPipe, write){ 338 | long ret; 339 | zval *self = getThis(); 340 | const char *buf = NULL; 341 | size_t buf_len; 342 | uv_pipe_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_pipe_ext_t); 343 | 344 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &buf, &buf_len)) { 345 | return; 346 | } 347 | resource->flag |= UV_PIPE_WRITE_CALLBACK_ENABLE; 348 | ret = pipe_write_raw((uv_stream_t *) &resource->uv_pipe, buf, buf_len); 349 | RETURN_LONG(ret); 350 | } 351 | 352 | int pipe_write_raw(uv_stream_t * handle, const char *message, int size) { 353 | write_req_t *req; 354 | req = emalloc(sizeof(write_req_t)); 355 | req->buf.base = emalloc(size); 356 | req->buf.len = size; 357 | memcpy(req->buf.base, message, size); 358 | return uv_write((uv_write_t *) req, handle, &req->buf, 1, write_cb); 359 | } 360 | 361 | PHP_METHOD(UVPipe, shutdown){ 362 | long ret; 363 | zval *self = getThis(); 364 | char *buf; 365 | int buf_len; 366 | uv_pipe_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_pipe_ext_t); 367 | 368 | FCI_FREE(resource->shutdownCallback); 369 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "f", FCI_PARSE_PARAMETERS_CC(resource->shutdownCallback))) { 370 | return; 371 | } 372 | FCI_ADDREF(resource->shutdownCallback); 373 | 374 | if(ret = uv_shutdown(&resource->shutdown_req, (uv_stream_t *) &resource->uv_pipe, shutdown_cb)){ 375 | RETURN_LONG(ret); 376 | } 377 | 378 | setSelfReference(resource); 379 | RETURN_LONG(ret); 380 | } 381 | 382 | PHP_METHOD(UVPipe, connect){ 383 | long ret; 384 | zval *self = getThis(); 385 | const char *host = NULL; 386 | size_t host_len; 387 | 388 | uv_pipe_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_pipe_ext_t); 389 | 390 | FCI_FREE(resource->connectCallback); 391 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "sf", &host, &host_len, FCI_PARSE_PARAMETERS_CC(resource->connectCallback))) { 392 | return; 393 | } 394 | FCI_ADDREF(resource->connectCallback); 395 | 396 | if(host_len == 0){ 397 | FCI_FREE(resource->connectCallback); 398 | RETURN_LONG(-1); 399 | } 400 | 401 | uv_pipe_connect(&resource->connect_req, &resource->uv_pipe, host, client_connection_cb); 402 | 403 | setSelfReference(resource); 404 | resource->flag |= UV_PIPE_HANDLE_START; 405 | RETURN_LONG(ret); 406 | } 407 | 408 | PHP_METHOD(UVPipe, attachIPC){ 409 | long ret; 410 | zval *self = getThis(); 411 | uv_pipe_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_pipe_ext_t); 412 | 413 | if(ret = uv_pipe_open(&resource->uv_pipe, 0)){ 414 | RETURN_LONG(ret); 415 | } 416 | 417 | FCI_FREE(resource->connectCallback); 418 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "f", FCI_PARSE_PARAMETERS_CC(resource->connectCallback))) { 419 | RETURN_LONG(-1); 420 | } 421 | 422 | FCI_ADDREF(resource->connectCallback); 423 | 424 | if(ret = uv_read_start((uv_stream_t *) &resource->uv_pipe, alloc_cb, (uv_read_cb) ipc_read_cb)){ 425 | RETURN_LONG(ret); 426 | } 427 | 428 | setSelfReference(resource); 429 | resource->flag |= (UV_PIPE_HANDLE_START|UV_PIPE_READ_START); 430 | RETURN_LONG(ret); 431 | } 432 | 433 | zend_bool make_accepted_uv_pipe_object(uv_pipe_ext_t *server_resource, zval *client){ 434 | zval rv; 435 | uv_pipe_ext_t *client_resource; 436 | client_resource = FETCH_OBJECT_RESOURCE(client, uv_pipe_ext_t); 437 | zval *loop = zend_read_property(CLASS_ENTRY(UVPipe), &server_resource->object, ZEND_STRL("loop"), 1, &rv); 438 | zend_update_property(CLASS_ENTRY(UVPipe), client, ZEND_STRL("loop"), loop); 439 | uv_pipe_init(ZVAL_IS_NULL(loop)?uv_default_loop():FETCH_UV_LOOP(), (uv_pipe_t *) client_resource, 0); 440 | 441 | if(uv_accept((uv_stream_t *) &server_resource->uv_pipe, (uv_stream_t *) &client_resource->uv_pipe)) { 442 | zval_ptr_dtor(client); 443 | return 0; 444 | } 445 | 446 | client_resource->flag |= (UV_PIPE_HANDLE_START|UV_PIPE_READ_START); 447 | ZVAL_COPY_VALUE(&client_resource->object, client); 448 | return 1; 449 | } 450 | -------------------------------------------------------------------------------- /src/uv_pipe.h: -------------------------------------------------------------------------------- 1 | #ifndef _UV_TCP_H 2 | #define _UV_TCP_H 3 | #include "../php_ext_uv.h" 4 | #include "uv_loop_resource.h" 5 | #include "fcall.h" 6 | 7 | #define UV_PIPE_HANDLE_INTERNAL_REF 1 8 | #define UV_PIPE_HANDLE_START (1<<1) 9 | #define UV_PIPE_READ_START (1<<2) 10 | #define UV_PIPE_CLOSING_START (1<<3) 11 | #define UV_PIPE_WRITE_CALLBACK_ENABLE (1<<4) 12 | #define UV_PIPE_SOCKENAME_SIZE 200 13 | 14 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVPipe, __construct), 0) 15 | ZEND_ARG_OBJ_INFO(0, loop, UVLoop, 1) 16 | ZEND_ARG_INFO(0, ipc) 17 | ZEND_END_ARG_INFO() 18 | 19 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVPipe, setCallback), 0) 20 | ZEND_ARG_INFO(0, onRecvCallback) 21 | ZEND_ARG_INFO(0, onSendCallback) 22 | ZEND_ARG_INFO(0, onErrorCallback) 23 | ZEND_END_ARG_INFO() 24 | 25 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVPipe, listen), 0) 26 | ZEND_ARG_INFO(0, host) 27 | ZEND_ARG_INFO(0, onConnectCallback) 28 | ZEND_END_ARG_INFO() 29 | 30 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVPipe, connect), 0) 31 | ZEND_ARG_INFO(0, host) 32 | ZEND_ARG_INFO(0, onConnectCallback) 33 | ZEND_END_ARG_INFO() 34 | 35 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVPipe, attachIPC), 0) 36 | ZEND_ARG_INFO(0, onConnectCallback) 37 | ZEND_END_ARG_INFO() 38 | 39 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVPipe, shutdown), 0) 40 | ZEND_ARG_INFO(0, onShutdownCallback) 41 | ZEND_END_ARG_INFO() 42 | 43 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVPipe, write), 0) 44 | ZEND_ARG_INFO(0, buf) 45 | ZEND_END_ARG_INFO() 46 | 47 | typedef struct uv_pipe_ext_s{ 48 | uv_pipe_t uv_pipe; 49 | uint flag; 50 | uv_connect_t connect_req; 51 | uv_shutdown_t shutdown_req; 52 | char *sockAddr; 53 | char *peerAddr; 54 | zval gc_table[5]; 55 | fcall_info_t readCallback; 56 | fcall_info_t writeCallback; 57 | fcall_info_t errorCallback; 58 | fcall_info_t connectCallback; 59 | fcall_info_t shutdownCallback; 60 | zval object; 61 | zend_object zo; 62 | } uv_pipe_ext_t; 63 | 64 | typedef struct write_req_s{ 65 | uv_write_t uv_write; 66 | uv_buf_t buf; 67 | } write_req_t; 68 | 69 | static zend_always_inline void releaseUVPipeFunctionCache(uv_pipe_ext_t *resource){ 70 | freeFunctionCache(&resource->readCallback); 71 | freeFunctionCache(&resource->writeCallback); 72 | freeFunctionCache(&resource->errorCallback); 73 | freeFunctionCache(&resource->connectCallback); 74 | freeFunctionCache(&resource->shutdownCallback); 75 | } 76 | 77 | static zend_object *createUVPipeResource(zend_class_entry *class_type); 78 | static void freeUVPipeResource(zend_object *object); 79 | HashTable *get_gc_UVPipeResource(zval *obj, zval **table, int *n); 80 | static void releaseResource(uv_pipe_ext_t *resource); 81 | int pipe_write_raw(uv_stream_t * handle, const char *message, int size); 82 | zend_bool make_accepted_uv_pipe_object(uv_pipe_ext_t *server_resource, zval *client); 83 | static void pipe_close_cb(uv_handle_t* handle); 84 | void pipe_close_socket(uv_pipe_ext_t *handle); 85 | static void setSelfReference(uv_pipe_ext_t *resource); 86 | static void client_connection_cb(uv_connect_t* req, int status); 87 | static void connection_cb(uv_pipe_ext_t *resource, int status); 88 | 89 | PHP_METHOD(UVPipe, getSockname); 90 | PHP_METHOD(UVPipe, getPeername); 91 | PHP_METHOD(UVPipe, listen); 92 | PHP_METHOD(UVPipe, accept); 93 | PHP_METHOD(UVPipe, write); 94 | PHP_METHOD(UVPipe, setCallback); 95 | PHP_METHOD(UVPipe, close); 96 | PHP_METHOD(UVPipe, shutdown); 97 | PHP_METHOD(UVPipe, __construct); 98 | PHP_METHOD(UVPipe, connect); 99 | PHP_METHOD(UVPipe, open); 100 | PHP_METHOD(UVPipe, attachIPC); 101 | 102 | DECLARE_FUNCTION_ENTRY(UVPipe) = { 103 | PHP_ME(UVPipe, __construct, ARGINFO(UVPipe, __construct), ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) 104 | PHP_ME(UVPipe, getSockname, NULL, ZEND_ACC_PUBLIC) 105 | PHP_ME(UVPipe, getPeername, NULL, ZEND_ACC_PUBLIC) 106 | PHP_ME(UVPipe, listen, NULL, ZEND_ACC_PUBLIC) 107 | PHP_ME(UVPipe, accept, NULL, ZEND_ACC_PUBLIC) 108 | PHP_ME(UVPipe, setCallback, ARGINFO(UVPipe, setCallback), ZEND_ACC_PUBLIC) 109 | PHP_ME(UVPipe, write, ARGINFO(UVPipe, write), ZEND_ACC_PUBLIC) 110 | PHP_ME(UVPipe, close, NULL, ZEND_ACC_PUBLIC) 111 | PHP_ME(UVPipe, shutdown, ARGINFO(UVPipe, shutdown), ZEND_ACC_PUBLIC) 112 | PHP_ME(UVPipe, connect, ARGINFO(UVPipe, connect), ZEND_ACC_PUBLIC) 113 | PHP_ME(UVPipe, attachIPC, ARGINFO(UVPipe, attachIPC), ZEND_ACC_PUBLIC) 114 | PHP_FE_END 115 | }; 116 | #endif 117 | -------------------------------------------------------------------------------- /src/uv_process.c: -------------------------------------------------------------------------------- 1 | #include "uv_process.h" 2 | 3 | CLASS_ENTRY_FUNCTION_D(UVProcess){ 4 | REGISTER_CLASS_WITH_OBJECT_NEW(UVProcess, createUVProcessResource); 5 | OBJECT_HANDLER(UVProcess).offset = XtOffsetOf(uv_process_ext_t, zo); 6 | OBJECT_HANDLER(UVProcess).clone_obj = NULL; 7 | OBJECT_HANDLER(UVProcess).free_obj = freeUVProcessResource; 8 | zend_declare_property_null(CLASS_ENTRY(UVProcess), ZEND_STRL("loop"), ZEND_ACC_PRIVATE); 9 | } 10 | 11 | static zend_object *createUVProcessResource(zend_class_entry *ce) { 12 | uv_process_ext_t *resource; 13 | resource = ALLOC_RESOURCE(uv_process_ext_t); 14 | zend_object_std_init(&resource->zo, ce); 15 | object_properties_init(&resource->zo, ce); 16 | resource->zo.handlers = &OBJECT_HANDLER(UVProcess); 17 | return &resource->zo; 18 | } 19 | 20 | void freeUVProcessResource(zend_object *object) { 21 | uv_process_ext_t *resource; 22 | resource = FETCH_RESOURCE(object, uv_process_ext_t); 23 | zend_object_std_dtor(&resource->zo); 24 | } 25 | 26 | PHP_METHOD(UVProcess, __construct){ 27 | zval *loop = NULL; 28 | zval *self = getThis(); 29 | 30 | uv_process_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_process_ext_t); 31 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|z", &loop)) { 32 | return; 33 | } 34 | 35 | if(NULL == loop || ZVAL_IS_NULL(loop)){ 36 | resource->loop = uv_default_loop(); 37 | return; 38 | } 39 | 40 | zend_update_property(CLASS_ENTRY(UVProcess), self, ZEND_STRL("loop"), loop); 41 | resource->loop = FETCH_UV_LOOP(); 42 | } 43 | 44 | PHP_METHOD(UVProcess, spawn){ 45 | char **args; 46 | zval *self = getThis(); 47 | zval *zargs, *tmp; 48 | HashTable *htargs; 49 | int i, n, retval; 50 | uv_process_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_process_ext_t); 51 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "a", &zargs)) { 52 | return; 53 | } 54 | 55 | htargs = Z_ARRVAL_P(zargs); 56 | n = zend_array_count(htargs); 57 | args = ecalloc(n + 1, sizeof(char *)); 58 | for(i=0; iloop, args, return_value); 68 | if(retval){ 69 | freeStringArray(args); 70 | RETURN_LONG(retval); 71 | } 72 | freeStringArray(args); 73 | } 74 | 75 | static void freeStringArray(char *args[]) { 76 | int i = 0; 77 | for(;;){ 78 | if(args[i] == NULL){ 79 | break; 80 | } 81 | efree(args[i++]); 82 | } 83 | efree(args); 84 | } -------------------------------------------------------------------------------- /src/uv_process.h: -------------------------------------------------------------------------------- 1 | #ifndef _UV_PROCESS_H 2 | #define _UV_PROCESS_H 3 | #include "../php_ext_uv.h" 4 | #include "uv_loop_resource.h" 5 | #include "fcall.h" 6 | 7 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVProcess, __construct), 0) 8 | ZEND_ARG_OBJ_INFO(0, loop, UVLoop, 1) 9 | ZEND_END_ARG_INFO() 10 | 11 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVProcess, spawn), 0) 12 | ZEND_ARG_INFO(0, args) 13 | ZEND_END_ARG_INFO() 14 | 15 | typedef struct uv_process_ext_s{ 16 | uv_loop_t *loop; 17 | zval object; 18 | zend_object zo; 19 | } uv_process_ext_t; 20 | 21 | static zend_object *createUVProcessResource(zend_class_entry *class_type); 22 | static void process_handle_callback(uv_process_ext_t *process_handle); 23 | void freeUVProcessResource(zend_object *object); 24 | static void freeStringArray(char *args[]); 25 | 26 | PHP_METHOD(UVProcess, __construct); 27 | PHP_METHOD(UVProcess, spawn); 28 | 29 | DECLARE_FUNCTION_ENTRY(UVProcess) = { 30 | PHP_ME(UVProcess, __construct, ARGINFO(UVProcess, __construct), ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) 31 | PHP_ME(UVProcess, spawn, ARGINFO(UVProcess, spawn), ZEND_ACC_PUBLIC) 32 | PHP_FE_END 33 | }; 34 | #endif 35 | -------------------------------------------------------------------------------- /src/uv_resolver.c: -------------------------------------------------------------------------------- 1 | #include "uv_resolver.h" 2 | 3 | CLASS_ENTRY_FUNCTION_D(UVResolver){ 4 | REGISTER_CLASS(UVResolver); 5 | OBJECT_HANDLER(UVResolver).clone_obj = NULL; 6 | zend_declare_property_null(CLASS_ENTRY(UVResolver), ZEND_STRL("loop"), ZEND_ACC_PRIVATE); 7 | } 8 | 9 | static void on_addrinfo_resolved(uv_getaddrinfo_ext_t *info, int status, struct addrinfo *res) { 10 | zval retval; 11 | zval params[2]; 12 | char addr[17] = {'\0'}; 13 | ZVAL_LONG(¶ms[0], status); 14 | ZVAL_NULL(¶ms[1]); 15 | if(status == 0){ 16 | uv_ip4_name((struct sockaddr_in*) res->ai_addr, addr, 16); 17 | ZVAL_STRING(¶ms[1], addr); 18 | uv_freeaddrinfo(res); 19 | } 20 | fci_call_function(&info->callback, &retval, 2, params); 21 | zval_ptr_dtor(¶ms[1]); 22 | zval_ptr_dtor(&retval); 23 | RELEASE_INFO(info); 24 | } 25 | 26 | static void on_nameinfo_resolved(uv_getnameinfo_ext_t *info, int status, const char *hostname, const char *service) { 27 | zval retval; 28 | zval params[3]; 29 | ZVAL_NULL(&retval); 30 | ZVAL_LONG(¶ms[0], status); 31 | ZVAL_NULL(¶ms[1]); 32 | ZVAL_NULL(¶ms[2]); 33 | if(status == 0){ 34 | ZVAL_STRING(¶ms[1], hostname); 35 | ZVAL_STRING(¶ms[2], service); 36 | } 37 | fci_call_function(&info->callback, &retval, 3, params); 38 | zval_ptr_dtor(¶ms[1]); 39 | zval_ptr_dtor(¶ms[2]); 40 | zval_ptr_dtor(&retval); 41 | RELEASE_INFO(info); 42 | } 43 | 44 | PHP_METHOD(UVResolver, __construct){ 45 | zval *loop = NULL; 46 | zval *self = getThis(); 47 | 48 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|z", &loop)) { 49 | return; 50 | } 51 | 52 | if(NULL == loop || ZVAL_IS_NULL(loop)){ 53 | return; 54 | } 55 | 56 | zend_update_property(CLASS_ENTRY(UVResolver), self, ZEND_STRL("loop"), loop); 57 | } 58 | 59 | PHP_METHOD(UVResolver, getnameinfo){ 60 | long ret; 61 | zval *self = getThis(); 62 | const char *addr = NULL; 63 | size_t addr_len; 64 | zval *loop, rv; 65 | static struct sockaddr_in addr4; 66 | char cstr_addr[30]; 67 | uv_getnameinfo_ext_t *info; 68 | loop = zend_read_property(CLASS_ENTRY(UVResolver), self, ZEND_STRL("loop"), 1, &rv); 69 | 70 | INIT_INFO(info, uv_getnameinfo_ext_t, self); 71 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "sf", &addr, &addr_len, FCI_PARSE_PARAMETERS_CC(info->callback))) { 72 | efree(info); 73 | return; 74 | } 75 | FCI_ADDREF(info->callback); 76 | 77 | COPY_C_STR(cstr_addr, addr, addr_len); 78 | if((ret = uv_ip4_addr(addr, 0, &addr4)) !=0){ 79 | RELEASE_INFO(info); 80 | RETURN_LONG(ret); 81 | } 82 | 83 | if((ret = uv_getnameinfo(ZVAL_IS_NULL(loop)?uv_default_loop():FETCH_UV_LOOP(), (uv_getnameinfo_t *) info, (uv_getnameinfo_cb) on_nameinfo_resolved, (const struct sockaddr*) &addr4, 0)) != 0) { 84 | RELEASE_INFO(info); 85 | } 86 | 87 | RETURN_LONG(ret); 88 | } 89 | 90 | PHP_METHOD(UVResolver, getaddrinfo){ 91 | long ret; 92 | zval *self = getThis(); 93 | const char *node = NULL, *service = NULL; 94 | char *c_node, *c_service; 95 | size_t node_len, service_len; 96 | zval *loop, rv; 97 | static struct sockaddr_in addr4; 98 | char cstr_addr[30]; 99 | uv_getaddrinfo_ext_t *info; 100 | 101 | loop = zend_read_property(CLASS_ENTRY(UVResolver), self, ZEND_STRL("loop"), 1, &rv); 102 | 103 | INIT_INFO(info, uv_getaddrinfo_ext_t, self); 104 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "ssf", &node, &node_len, &service, &service_len, FCI_PARSE_PARAMETERS_CC(info->callback))) { 105 | efree(info); 106 | return; 107 | } 108 | FCI_ADDREF(info->callback); 109 | 110 | MAKE_C_STR(c_node, node, node_len); 111 | MAKE_C_STR(c_service, service, service_len); 112 | 113 | if((ret = uv_getaddrinfo(ZVAL_IS_NULL(loop)?uv_default_loop():FETCH_UV_LOOP(), (uv_getaddrinfo_t *) info, (uv_getaddrinfo_cb) on_addrinfo_resolved, c_node, c_service, NULL)) != 0) { 114 | RELEASE_INFO(info); 115 | } 116 | 117 | efree(c_node); 118 | efree(c_service); 119 | RETURN_LONG(ret); 120 | } -------------------------------------------------------------------------------- /src/uv_resolver.h: -------------------------------------------------------------------------------- 1 | #ifndef _UV_RESOLVER_H 2 | #define _UV_RESOLVER_H 3 | #include "../php_ext_uv.h" 4 | #include "uv_loop_resource.h" 5 | #include "fcall.h" 6 | 7 | #define INIT_INFO(i, t, o) \ 8 | i = ecalloc(1, sizeof(t)); \ 9 | ZVAL_COPY(&i->object, o) 10 | 11 | #define RELEASE_INFO(info) \ 12 | FCI_FREE(info->callback); \ 13 | zval_dtor(&info->object); \ 14 | efree(info) 15 | 16 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVResolver, __construct), 0) 17 | ZEND_ARG_OBJ_INFO(0, loop, UVLoop, 1) 18 | ZEND_END_ARG_INFO() 19 | 20 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVResolver, getaddrinfo), 0) 21 | ZEND_ARG_INFO(0, node) 22 | ZEND_ARG_INFO(0, service) 23 | ZEND_ARG_INFO(0, callback) 24 | ZEND_END_ARG_INFO() 25 | 26 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVResolver, getnameinfo), 0) 27 | ZEND_ARG_INFO(0, addr) 28 | ZEND_ARG_INFO(0, callback) 29 | ZEND_END_ARG_INFO() 30 | 31 | typedef struct uv_getaddrinfo_ext_s{ 32 | uv_getaddrinfo_t uv_getaddrinfo; 33 | fcall_info_t callback; 34 | zval object; 35 | } uv_getaddrinfo_ext_t; 36 | 37 | typedef struct uv_getnameinfo_ext_s{ 38 | uv_getnameinfo_t uv_getnameinfo; 39 | fcall_info_t callback; 40 | zval object; 41 | } uv_getnameinfo_ext_t; 42 | 43 | PHP_METHOD(UVResolver, __construct); 44 | PHP_METHOD(UVResolver, getnameinfo); 45 | PHP_METHOD(UVResolver, getaddrinfo); 46 | 47 | DECLARE_FUNCTION_ENTRY(UVResolver) = { 48 | PHP_ME(UVResolver, __construct, ARGINFO(UVResolver, __construct), ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) 49 | PHP_ME(UVResolver, getaddrinfo, ARGINFO(UVResolver, getaddrinfo), ZEND_ACC_PUBLIC) 50 | PHP_ME(UVResolver, getnameinfo, ARGINFO(UVResolver, getnameinfo), ZEND_ACC_PUBLIC) 51 | PHP_FE_END 52 | }; 53 | #endif 54 | -------------------------------------------------------------------------------- /src/uv_signal.c: -------------------------------------------------------------------------------- 1 | #include "uv_signal.h" 2 | 3 | CLASS_ENTRY_FUNCTION_D(UVSignal){ 4 | REGISTER_CLASS_WITH_OBJECT_NEW(UVSignal, createUVSignalResource); 5 | OBJECT_HANDLER(UVSignal).offset = XtOffsetOf(uv_signal_ext_t, zo); 6 | OBJECT_HANDLER(UVSignal).clone_obj = NULL; 7 | OBJECT_HANDLER(UVSignal).free_obj = freeUVSignalResource; 8 | OBJECT_HANDLER(UVIdle).get_gc = get_gc_UVSignalResource; 9 | zend_declare_property_null(CLASS_ENTRY(UVSignal), ZEND_STRL("loop"), ZEND_ACC_PRIVATE); 10 | } 11 | 12 | static HashTable *get_gc_UVSignalResource(zval *obj, zval **table, int *n) { 13 | uv_signal_ext_t *resource; 14 | resource = FETCH_OBJECT_RESOURCE(obj, uv_signal_ext_t); 15 | FCI_GC_TABLE(resource, callback); 16 | *table = (zval *) &resource->gc_table; 17 | *n = FCI_GC_TABLE_SIZE(resource->gc_table); 18 | return zend_std_get_properties(obj); 19 | } 20 | 21 | static void signal_handle_callback(uv_signal_ext_t *signal_handle, int signo){ 22 | zval retval; 23 | zval params[2]; 24 | params[0] = signal_handle->object; 25 | ZVAL_LONG(¶ms[1], signo); 26 | fci_call_function(&signal_handle->callback, &retval, 2, params); 27 | zval_ptr_dtor(&retval); 28 | } 29 | 30 | static zend_object *createUVSignalResource(zend_class_entry *ce) { 31 | uv_signal_ext_t *resource; 32 | resource = ALLOC_RESOURCE(uv_signal_ext_t); 33 | zend_object_std_init(&resource->zo, ce); 34 | object_properties_init(&resource->zo, ce); 35 | resource->zo.handlers = &OBJECT_HANDLER(UVSignal); 36 | return &resource->zo; 37 | } 38 | 39 | void freeUVSignalResource(zend_object *object) { 40 | uv_signal_ext_t *resource; 41 | resource = FETCH_RESOURCE(object, uv_signal_ext_t); 42 | if(resource->start){ 43 | uv_signal_stop((uv_signal_t *) resource); 44 | FCI_FREE(resource->callback); 45 | } 46 | uv_unref((uv_handle_t *) resource); 47 | zend_object_std_dtor(&resource->zo); 48 | } 49 | 50 | PHP_METHOD(UVSignal, __construct){ 51 | zval *loop = NULL; 52 | zval *self = getThis(); 53 | uv_signal_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_signal_ext_t); 54 | 55 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|z", &loop)) { 56 | return; 57 | } 58 | 59 | if(NULL == loop || ZVAL_IS_NULL(loop)){ 60 | uv_signal_init(uv_default_loop(), (uv_signal_t *) resource); 61 | return; 62 | } 63 | 64 | zend_update_property(CLASS_ENTRY(UVSignal), self, ZEND_STRL("loop"), loop); 65 | uv_signal_init(FETCH_UV_LOOP(), (uv_signal_t *) resource); 66 | } 67 | 68 | PHP_METHOD(UVSignal, start){ 69 | zval *signal_cb; 70 | long signo, ret; 71 | zval *self = getThis(); 72 | uv_signal_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_signal_ext_t); 73 | 74 | FCI_FREE(resource->callback); 75 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "fl", FCI_PARSE_PARAMETERS_CC(resource->callback), &signo)) { 76 | return; 77 | } 78 | Z_ADDREF(resource->callback.fci.function_name); 79 | 80 | if(ret = uv_signal_start((uv_signal_t *) resource, (uv_signal_cb) signal_handle_callback, signo)){ 81 | FCI_FREE(resource->callback); 82 | } 83 | resource->start = 1; 84 | ZVAL_COPY_VALUE(&resource->object, self); 85 | RETURN_LONG(ret); 86 | } 87 | 88 | PHP_METHOD(UVSignal, stop){ 89 | long ret; 90 | zval *self = getThis(); 91 | uv_signal_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_signal_ext_t); 92 | 93 | if(!resource->start){ 94 | RETURN_LONG(-1); 95 | } 96 | 97 | ret = uv_signal_stop((uv_signal_t *) resource); 98 | if(ret == 0){ 99 | resource->start = 0; 100 | FCI_FREE(resource->callback); 101 | zval_dtor(&resource->object); 102 | } 103 | RETURN_LONG(ret); 104 | } 105 | -------------------------------------------------------------------------------- /src/uv_signal.h: -------------------------------------------------------------------------------- 1 | #ifndef _UV_SIGNAL_H 2 | #define _UV_SIGNAL_H 3 | #include "../php_ext_uv.h" 4 | #include "uv_loop_resource.h" 5 | #include "fcall.h" 6 | 7 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVSignal, __construct), 0) 8 | ZEND_ARG_OBJ_INFO(0, loop, UVLoop, 1) 9 | ZEND_END_ARG_INFO() 10 | 11 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVSignal, start), 0) 12 | ZEND_ARG_INFO(0, signal_cb) 13 | ZEND_ARG_INFO(0, signo) 14 | ZEND_END_ARG_INFO() 15 | 16 | typedef struct uv_signal_ext_s{ 17 | uv_signal_t uv_signal; 18 | int start; 19 | struct { 20 | zval callback; 21 | } gc_table; 22 | fcall_info_t callback; 23 | zval object; 24 | zend_object zo; 25 | } uv_signal_ext_t; 26 | 27 | static zend_object *createUVSignalResource(zend_class_entry *class_type); 28 | static void signal_handle_callback(uv_signal_ext_t *signal_handle, int signo); 29 | void freeUVSignalResource(zend_object *object); 30 | static HashTable *get_gc_UVSignalResource(zval *obj, zval **table, int *n); 31 | 32 | PHP_METHOD(UVSignal, __construct); 33 | PHP_METHOD(UVSignal, start); 34 | PHP_METHOD(UVSignal, stop); 35 | 36 | DECLARE_FUNCTION_ENTRY(UVSignal) = { 37 | PHP_ME(UVSignal, __construct, ARGINFO(UVSignal, __construct), ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) 38 | PHP_ME(UVSignal, start, ARGINFO(UVSignal, start), ZEND_ACC_PUBLIC) 39 | PHP_ME(UVSignal, stop, NULL, ZEND_ACC_PUBLIC) 40 | PHP_FE_END 41 | }; 42 | #endif 43 | -------------------------------------------------------------------------------- /src/uv_ssl.h: -------------------------------------------------------------------------------- 1 | #ifndef _UV_SSL_H 2 | #define _UV_SSL_H 3 | #include "uv_tcp.h" 4 | #include "ssl_verify.h" 5 | #include "uv_ssl_constant.h" 6 | 7 | #define SSL_METHOD_SSLV2 0 8 | #define SSL_METHOD_SSLV3 1 9 | #define SSL_METHOD_SSLV23 2 10 | #define SSL_METHOD_TLSV1 3 11 | #define SSL_METHOD_TLSV1_1 4 12 | #define SSL_METHOD_TLSV1_2 5 13 | #define OPENSSL_DEFAULT_STREAM_VERIFY_DEPTH 9 14 | 15 | ZEND_BEGIN_ARG_INFO_EX(ARGINFO(UVSSL, __construct), 0, 0, 1) 16 | ZEND_ARG_OBJ_INFO(0, loop, UVLoop, 1) 17 | ZEND_ARG_INFO(0, sslMethod) 18 | ZEND_ARG_INFO(0, nContexts) 19 | ZEND_END_ARG_INFO() 20 | 21 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVSSL, setSSLServerNameCallback), 0) 22 | ZEND_ARG_INFO(0, callback) 23 | ZEND_END_ARG_INFO() 24 | 25 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVSSL, setSSLHandshakeCallback), 0) 26 | ZEND_ARG_INFO(0, callback) 27 | ZEND_END_ARG_INFO() 28 | 29 | ZEND_BEGIN_ARG_INFO_EX(ARGINFO(UVSSL, setCert), 0, 0, 1) 30 | ZEND_ARG_INFO(0, cert) 31 | ZEND_ARG_INFO(0, n) 32 | ZEND_END_ARG_INFO() 33 | 34 | ZEND_BEGIN_ARG_INFO_EX(ARGINFO(UVSSL, setPrivateKey), 0, 0, 1) 35 | ZEND_ARG_INFO(0, privateKey) 36 | ZEND_ARG_INFO(0, n) 37 | ZEND_END_ARG_INFO() 38 | 39 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVSSL, write), 0) 40 | ZEND_ARG_INFO(0, message) 41 | ZEND_END_ARG_INFO() 42 | 43 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVSSL, connect), 0) 44 | ZEND_ARG_INFO(0, host) 45 | ZEND_ARG_INFO(0, port) 46 | ZEND_ARG_INFO(0, onConnectCallback) 47 | ZEND_END_ARG_INFO() 48 | 49 | typedef struct uv_ssl_ext_s{ 50 | uv_tcp_ext_t uv_tcp_ext; 51 | const SSL_METHOD *ssl_method; 52 | SSL_CTX** ctx; 53 | int nctx; 54 | SSL* ssl; 55 | BIO* read_bio; 56 | BIO* write_bio; 57 | char *sniConnectHostname; 58 | int clientMode; 59 | fcall_info_t sslServerNameCallback; 60 | fcall_info_t sslHandshakeCallback; 61 | } uv_ssl_ext_t; 62 | 63 | typedef struct uv_getaddrinfo_ext_s{ 64 | uv_getaddrinfo_t addrinfo; 65 | int port; 66 | uv_ssl_ext_t *ssl_handle; 67 | } uv_getaddrinfo_ext_t; 68 | 69 | static zend_always_inline void releaseUVSSLFunctionCache(uv_ssl_ext_t *resource){ 70 | freeFunctionCache(&resource->sslServerNameCallback); 71 | freeFunctionCache(&resource->sslHandshakeCallback); 72 | } 73 | static zend_object *createUVSSLResource(zend_class_entry *class_type); 74 | void freeUVSSLResource(zend_object *object); 75 | static HashTable *get_gc_UVSSLResource(zval *obj, zval **table, int *n); 76 | static int write_bio_to_socket(uv_ssl_ext_t *resource); 77 | 78 | PHP_METHOD(UVSSL, __construct); 79 | PHP_METHOD(UVSSL, setSSLServerNameCallback); 80 | PHP_METHOD(UVSSL, setSSLHandshakeCallback); 81 | PHP_METHOD(UVSSL, setCert); 82 | PHP_METHOD(UVSSL, setPrivateKey); 83 | PHP_METHOD(UVSSL, accept); 84 | PHP_METHOD(UVSSL, write); 85 | PHP_METHOD(UVSSL, connect); 86 | 87 | DECLARE_FUNCTION_ENTRY(UVSSL) = { 88 | PHP_ME(UVSSL, __construct, ARGINFO(UVSSL, __construct), ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) 89 | PHP_ME(UVSSL, setSSLServerNameCallback, ARGINFO(UVSSL, setSSLServerNameCallback), ZEND_ACC_PUBLIC) 90 | PHP_ME(UVSSL, setSSLHandshakeCallback, ARGINFO(UVSSL, setSSLHandshakeCallback), ZEND_ACC_PUBLIC) 91 | PHP_ME(UVSSL, setCert, ARGINFO(UVSSL, setCert), ZEND_ACC_PUBLIC) 92 | PHP_ME(UVSSL, setPrivateKey, ARGINFO(UVSSL, setPrivateKey), ZEND_ACC_PUBLIC) 93 | PHP_ME(UVSSL, accept, NULL, ZEND_ACC_PUBLIC) 94 | PHP_ME(UVSSL, write, ARGINFO(UVSSL, write), ZEND_ACC_PUBLIC) 95 | PHP_ME(UVSSL, connect, ARGINFO(UVSSL, connect), ZEND_ACC_PUBLIC) 96 | PHP_FE_END 97 | }; 98 | 99 | #define FETCH_SSL_RESOURCE(zo) \ 100 | ((uv_ssl_ext_t *) FETCH_RESOURCE_FROM_EXTEND(FETCH_RESOURCE(zo, uv_tcp_ext_t), uv_tcp_ext, uv_ssl_ext_t)) 101 | 102 | #define FETCH_OBJECT_SSL_RESOURCE(object) \ 103 | (FETCH_RESOURCE_FROM_EXTEND(FETCH_OBJECT_RESOURCE(object, uv_tcp_ext_t), uv_tcp_ext, uv_ssl_ext_t)) 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /src/uv_ssl_constant.h: -------------------------------------------------------------------------------- 1 | #ifndef UV_SSL_CONSTANT_H 2 | #define UV_SSL_CONSTANT_H 3 | #define REGISTER_UV_SSL_X509_CONSTANT() \ 4 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_OK); \ 5 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT); \ 6 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_UNABLE_TO_GET_CRL); \ 7 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE); \ 8 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE); \ 9 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY); \ 10 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_CERT_SIGNATURE_FAILURE); \ 11 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_CRL_SIGNATURE_FAILURE); \ 12 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_CERT_NOT_YET_VALID); \ 13 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_CERT_HAS_EXPIRED); \ 14 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_CRL_NOT_YET_VALID); \ 15 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_CRL_HAS_EXPIRED); \ 16 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD); \ 17 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD); \ 18 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD); \ 19 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD); \ 20 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_OUT_OF_MEM); \ 21 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT); \ 22 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN); \ 23 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY); \ 24 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE); \ 25 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_CERT_CHAIN_TOO_LONG); \ 26 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_CERT_REVOKED); \ 27 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_INVALID_CA); \ 28 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_PATH_LENGTH_EXCEEDED); \ 29 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_INVALID_PURPOSE); \ 30 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_CERT_UNTRUSTED); \ 31 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_CERT_REJECTED); \ 32 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_SUBJECT_ISSUER_MISMATCH); \ 33 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_AKID_SKID_MISMATCH); \ 34 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH); \ 35 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_KEYUSAGE_NO_CERTSIGN); \ 36 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER); \ 37 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION); \ 38 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_KEYUSAGE_NO_CRL_SIGN); \ 39 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION); \ 40 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_INVALID_NON_CA); \ 41 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED); \ 42 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE); \ 43 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED); \ 44 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_INVALID_EXTENSION); \ 45 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_INVALID_POLICY_EXTENSION); \ 46 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_NO_EXPLICIT_POLICY); \ 47 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_DIFFERENT_CRL_SCOPE); \ 48 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE); \ 49 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_UNNESTED_RESOURCE); \ 50 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_PERMITTED_VIOLATION); \ 51 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_EXCLUDED_VIOLATION); \ 52 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_SUBTREE_MINMAX); \ 53 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE); \ 54 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX); \ 55 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_UNSUPPORTED_NAME_SYNTAX); \ 56 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_CRL_PATH_VALIDATION_ERROR); \ 57 | REGISTER_CLASS_CONSTANT_LONG(UVSSL, X509_V_ERR_APPLICATION_VERIFICATION); 58 | 59 | #endif -------------------------------------------------------------------------------- /src/uv_tcp.c: -------------------------------------------------------------------------------- 1 | #include "uv_tcp.h" 2 | 3 | void tcp_close_socket(uv_tcp_ext_t *handle){ 4 | if(handle->flag & UV_TCP_CLOSING_START){ 5 | return; 6 | } 7 | handle->flag |= UV_TCP_CLOSING_START; 8 | uv_close((uv_handle_t *) handle, tcp_close_cb); 9 | } 10 | 11 | void setSelfReference(uv_tcp_ext_t *resource) 12 | { 13 | if(resource->flag & UV_TCP_HANDLE_INTERNAL_REF){ 14 | return; 15 | } 16 | Z_ADDREF(resource->object); 17 | resource->flag |= UV_TCP_HANDLE_INTERNAL_REF; 18 | } 19 | 20 | CLASS_ENTRY_FUNCTION_D(UVTcp){ 21 | REGISTER_CLASS_WITH_OBJECT_NEW(UVTcp, createUVTcpResource); 22 | OBJECT_HANDLER(UVTcp).offset = XtOffsetOf(uv_tcp_ext_t, zo); 23 | OBJECT_HANDLER(UVTcp).clone_obj = NULL; 24 | OBJECT_HANDLER(UVTcp).free_obj = freeUVTcpResource; 25 | OBJECT_HANDLER(UVTcp).get_gc = get_gc_UVTcpResource; 26 | zend_declare_property_null(CLASS_ENTRY(UVTcp), ZEND_STRL("loop"), ZEND_ACC_PRIVATE); 27 | } 28 | 29 | HashTable *get_gc_UVTcpResource(zval *obj, zval **table, int *n) { 30 | uv_tcp_ext_t *resource = FETCH_OBJECT_RESOURCE(obj, uv_tcp_ext_t); 31 | *table = &resource->gc_table[0]; 32 | int index = 0; 33 | FCI_GC_TABLE_EX(resource, readCallback, index); 34 | FCI_GC_TABLE_EX(resource, writeCallback, index); 35 | FCI_GC_TABLE_EX(resource, errorCallback, index); 36 | FCI_GC_TABLE_EX(resource, connectCallback, index); 37 | FCI_GC_TABLE_EX(resource, shutdownCallback, index); 38 | *n = index; 39 | return zend_std_get_properties(obj); 40 | } 41 | 42 | void releaseResource(uv_tcp_ext_t *resource){ 43 | if(resource->sockPort != 0){ 44 | resource->sockPort = 0; 45 | efree(resource->sockAddr); 46 | resource->sockAddr = NULL; 47 | } 48 | 49 | if(resource->peerPort != 0){ 50 | resource->peerPort = 0; 51 | efree(resource->peerAddr); 52 | resource->peerAddr = NULL; 53 | } 54 | 55 | if(resource->flag & UV_TCP_READ_START){ 56 | resource->flag &= ~UV_TCP_READ_START; 57 | uv_read_stop((uv_stream_t *) &resource->uv_tcp); 58 | } 59 | 60 | if(resource->flag & UV_TCP_HANDLE_START){ 61 | resource->flag &= ~UV_TCP_HANDLE_START; 62 | uv_unref((uv_handle_t *) &resource->uv_tcp); 63 | } 64 | 65 | if(resource->flag & UV_TCP_HANDLE_INTERNAL_REF){ 66 | resource->flag &= ~UV_TCP_HANDLE_INTERNAL_REF; 67 | zval_ptr_dtor(&resource->object); 68 | } 69 | } 70 | 71 | static void shutdown_cb(uv_shutdown_t* req, int status) { 72 | uv_tcp_ext_t *resource = (uv_tcp_ext_t *) req->handle; 73 | zval retval; 74 | zval params[2]; 75 | params[0] = resource->object; 76 | if(!FCI_ISNULL(resource->shutdownCallback)){ 77 | ZVAL_LONG(¶ms[1], status); 78 | fci_call_function(&resource->shutdownCallback, &retval, 2, params); 79 | zval_ptr_dtor(&retval); 80 | } 81 | } 82 | 83 | static void tcp_close_cb(uv_handle_t* handle) { 84 | releaseResource((uv_tcp_ext_t *) handle); 85 | } 86 | 87 | static void write_cb(uv_write_t *wr, int status){ 88 | zval retval; 89 | write_req_t *req = (write_req_t *) wr; 90 | uv_tcp_ext_t *resource = (uv_tcp_ext_t *) req->uv_write.handle; 91 | zval params[3]; 92 | params[0] = resource->object; 93 | 94 | if(resource->flag & UV_TCP_WRITE_CALLBACK_ENABLE && !FCI_ISNULL(resource->writeCallback)){ 95 | ZVAL_LONG(¶ms[1], status); 96 | ZVAL_LONG(¶ms[2], req->buf.len); 97 | fci_call_function(&resource->writeCallback, &retval, 3, params); 98 | zval_ptr_dtor(&retval); 99 | } 100 | efree(req->buf.base); 101 | efree(req); 102 | } 103 | 104 | static void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { 105 | buf->base = emalloc(suggested_size); 106 | buf->len = suggested_size; 107 | } 108 | 109 | static void read_cb(uv_tcp_ext_t *resource, ssize_t nread, const uv_buf_t* buf) { 110 | zval retval; 111 | zval params[2]; 112 | params[0] = resource->object; 113 | 114 | if(nread > 0){ 115 | if(!FCI_ISNULL(resource->readCallback)){ 116 | ZVAL_STRINGL(¶ms[1], buf->base, nread); 117 | fci_call_function(&resource->readCallback, &retval, 2, params); 118 | zval_ptr_dtor(¶ms[1]); 119 | zval_ptr_dtor(&retval); 120 | } 121 | } 122 | else{ 123 | if(!FCI_ISNULL(resource->errorCallback)){ 124 | ZVAL_LONG(¶ms[1], nread); 125 | fci_call_function(&resource->errorCallback, &retval, 2, params); 126 | zval_ptr_dtor(&retval); 127 | } 128 | tcp_close_socket((uv_tcp_ext_t *) &resource->uv_tcp); 129 | } 130 | efree(buf->base); 131 | } 132 | 133 | static void client_connection_cb(uv_connect_t* req, int status) { 134 | zval retval; 135 | uv_tcp_ext_t *resource = (uv_tcp_ext_t *) req->handle; 136 | zval params[2]; 137 | params[0] = resource->object; 138 | ZVAL_NULL(&retval); 139 | ZVAL_LONG(¶ms[1], status); 140 | 141 | if(uv_read_start((uv_stream_t *) resource, alloc_cb, (uv_read_cb) read_cb)){ 142 | return; 143 | } 144 | resource->flag |= (UV_TCP_HANDLE_START|UV_TCP_READ_START); 145 | 146 | fci_call_function(&resource->connectCallback, &retval, 2, params); 147 | zval_ptr_dtor(&retval); 148 | } 149 | 150 | static void connection_cb(uv_tcp_ext_t *resource, int status) { 151 | zval retval; 152 | zval params[2]; 153 | params[0] = resource->object; 154 | ZVAL_NULL(&retval); 155 | ZVAL_LONG(¶ms[1], status); 156 | fci_call_function(&resource->connectCallback, &retval, 2, params); 157 | zval_ptr_dtor(&retval); 158 | } 159 | 160 | 161 | static zend_object *createUVTcpResource(zend_class_entry *ce) { 162 | uv_tcp_ext_t *resource; 163 | resource = ALLOC_RESOURCE(uv_tcp_ext_t); 164 | zend_object_std_init(&resource->zo, ce); 165 | object_properties_init(&resource->zo, ce); 166 | resource->zo.handlers = &OBJECT_HANDLER(UVTcp); 167 | return &resource->zo; 168 | } 169 | 170 | static void freeUVTcpResource(zend_object *object) { 171 | uv_tcp_ext_t *resource; 172 | resource = FETCH_RESOURCE(object, uv_tcp_ext_t); 173 | releaseResource(resource); 174 | releaseUVTcpFunctionCache(resource); 175 | zend_object_std_dtor(object); 176 | } 177 | 178 | static zend_always_inline void resolveSocket(uv_tcp_ext_t *resource){ 179 | struct sockaddr addr; 180 | int addrlen; 181 | int ret; 182 | if(resource->sockPort == 0){ 183 | addrlen = sizeof addr; 184 | if(ret = uv_tcp_getsockname(&resource->uv_tcp, &addr, &addrlen)){ 185 | return; 186 | } 187 | resource->sockPort = sock_port(&addr); 188 | resource->sockAddr = sock_addr(&addr); 189 | } 190 | } 191 | 192 | static zend_always_inline void resolvePeerSocket(uv_tcp_ext_t *resource){ 193 | struct sockaddr addr; 194 | int addrlen; 195 | int ret; 196 | if(resource->peerPort == 0){ 197 | addrlen = sizeof addr; 198 | if(ret = uv_tcp_getpeername(&resource->uv_tcp, &addr, &addrlen)){ 199 | return; 200 | } 201 | resource->peerPort = sock_port(&addr); 202 | resource->peerAddr = sock_addr(&addr); 203 | } 204 | } 205 | 206 | PHP_METHOD(UVTcp, getSockname){ 207 | zval *self = getThis(); 208 | uv_tcp_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_tcp_ext_t); 209 | resolveSocket(resource); 210 | if(resource->sockPort == 0){ 211 | RETURN_FALSE; 212 | } 213 | RETURN_STRING(resource->sockAddr); 214 | } 215 | 216 | PHP_METHOD(UVTcp, getSockport){ 217 | zval *self = getThis(); 218 | uv_tcp_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_tcp_ext_t); 219 | resolveSocket(resource); 220 | if(resource->sockPort == 0){ 221 | RETURN_FALSE; 222 | } 223 | RETURN_LONG(resource->sockPort); 224 | } 225 | 226 | PHP_METHOD(UVTcp, getPeername){ 227 | zval *self = getThis(); 228 | uv_tcp_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_tcp_ext_t); 229 | resolvePeerSocket(resource); 230 | if(resource->peerPort == 0){ 231 | RETURN_FALSE; 232 | } 233 | RETURN_STRING(resource->peerAddr); 234 | } 235 | 236 | PHP_METHOD(UVTcp, getPeerport){ 237 | zval *self = getThis(); 238 | uv_tcp_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_tcp_ext_t); 239 | resolvePeerSocket(resource); 240 | if(resource->peerPort == 0){ 241 | RETURN_FALSE; 242 | } 243 | RETURN_LONG(resource->peerPort); 244 | } 245 | 246 | PHP_METHOD(UVTcp, accept){ 247 | long ret, port; 248 | zval *self = getThis(); 249 | const char *host; 250 | int host_len; 251 | char cstr_host[30]; 252 | struct sockaddr_in addr; 253 | uv_tcp_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_tcp_ext_t); 254 | uv_tcp_ext_t *client_resource; 255 | 256 | object_init_ex(return_value, CLASS_ENTRY(UVTcp)); 257 | if(!make_accepted_uv_tcp_object(resource, return_value)){ 258 | RETURN_FALSE; 259 | } 260 | 261 | client_resource = FETCH_OBJECT_RESOURCE(return_value, uv_tcp_ext_t); 262 | if(uv_read_start((uv_stream_t *) client_resource, alloc_cb, (uv_read_cb) read_cb)){ 263 | RETURN_FALSE; 264 | } 265 | } 266 | 267 | PHP_METHOD(UVTcp, listen){ 268 | long ret, port; 269 | zval *self = getThis(); 270 | const char *host = NULL; 271 | size_t host_len; 272 | char cstr_host[30]; 273 | struct sockaddr_in addr; 274 | 275 | uv_tcp_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_tcp_ext_t); 276 | 277 | if(((uv_tcp_ext_t *) &resource->uv_tcp)->flag & UV_TCP_HANDLE_START){ 278 | RETURN_LONG(-1); 279 | } 280 | 281 | FCI_FREE(resource->connectCallback); 282 | 283 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "slf", &host, &host_len, &port, FCI_PARSE_PARAMETERS_CC(resource->connectCallback))) { 284 | return; 285 | } 286 | 287 | if(host_len == 0 || host_len >= 30){ 288 | RETURN_LONG(-1); 289 | } 290 | 291 | memcpy(cstr_host, host, host_len); 292 | cstr_host[host_len] = '\0'; 293 | if((ret = uv_ip4_addr(cstr_host, port&0xffff, &addr)) != 0){ 294 | RETURN_LONG(ret); 295 | } 296 | 297 | if((ret = uv_tcp_bind(&resource->uv_tcp, (const struct sockaddr*) &addr, 0)) != 0){ 298 | RETURN_LONG(ret); 299 | } 300 | 301 | if((ret = uv_listen((uv_stream_t *) &resource->uv_tcp, SOMAXCONN, (uv_connection_cb) connection_cb)) != 0){ 302 | RETURN_LONG(ret); 303 | } 304 | 305 | FCI_ADDREF(resource->connectCallback); 306 | setSelfReference(resource); 307 | resource->flag |= UV_TCP_HANDLE_START; 308 | RETURN_LONG(ret); 309 | } 310 | 311 | PHP_METHOD(UVTcp, setCallback){ 312 | long ret; 313 | zval *self = getThis(); 314 | uv_tcp_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_tcp_ext_t); 315 | 316 | FCI_FREE(resource->readCallback); 317 | FCI_FREE(resource->writeCallback); 318 | FCI_FREE(resource->errorCallback); 319 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "fff", FCI_PARSE_PARAMETERS_CC(resource->readCallback), FCI_PARSE_PARAMETERS_CC(resource->writeCallback), FCI_PARSE_PARAMETERS_CC(resource->errorCallback))) { 320 | return; 321 | } 322 | 323 | FCI_ADDREF(resource->readCallback); 324 | FCI_ADDREF(resource->writeCallback); 325 | FCI_ADDREF(resource->errorCallback); 326 | setSelfReference(resource); 327 | RETURN_LONG(ret); 328 | } 329 | 330 | PHP_METHOD(UVTcp, close){ 331 | long ret; 332 | zval *self = getThis(); 333 | uv_tcp_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_tcp_ext_t); 334 | tcp_close_socket((uv_tcp_ext_t *) &resource->uv_tcp); 335 | } 336 | 337 | PHP_METHOD(UVTcp, __construct){ 338 | zval *loop = NULL; 339 | zval *self = getThis(); 340 | uv_tcp_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_tcp_ext_t); 341 | 342 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|z", &loop)) { 343 | return; 344 | } 345 | 346 | ZVAL_COPY_VALUE(&resource->object, self); 347 | 348 | if(NULL == loop || ZVAL_IS_NULL(loop)){ 349 | uv_tcp_init(uv_default_loop(), (uv_tcp_t *) resource); 350 | return; 351 | } 352 | 353 | zend_update_property(CLASS_ENTRY(UVTcp), self, ZEND_STRL("loop"), loop); 354 | uv_tcp_init(FETCH_UV_LOOP(), (uv_tcp_t *) resource); 355 | } 356 | 357 | PHP_METHOD(UVTcp, write){ 358 | long ret; 359 | zval *self = getThis(); 360 | const char *buf = NULL; 361 | size_t buf_len; 362 | uv_tcp_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_tcp_ext_t); 363 | 364 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &buf, &buf_len)) { 365 | return; 366 | } 367 | resource->flag |= UV_TCP_WRITE_CALLBACK_ENABLE; 368 | ret = tcp_write_raw((uv_stream_t *) &resource->uv_tcp, buf, buf_len); 369 | RETURN_LONG(ret); 370 | } 371 | 372 | int tcp_write_raw(uv_stream_t * handle, const char *message, int size) { 373 | write_req_t *req; 374 | req = emalloc(sizeof(write_req_t)); 375 | req->buf.base = emalloc(size); 376 | req->buf.len = size; 377 | memcpy(req->buf.base, message, size); 378 | return uv_write((uv_write_t *) req, handle, &req->buf, 1, write_cb); 379 | } 380 | 381 | PHP_METHOD(UVTcp, shutdown){ 382 | long ret; 383 | zval *self = getThis(); 384 | char *buf; 385 | int buf_len; 386 | uv_tcp_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_tcp_ext_t); 387 | 388 | FCI_FREE(resource->shutdownCallback); 389 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "f", FCI_PARSE_PARAMETERS_CC(resource->shutdownCallback))) { 390 | return; 391 | } 392 | FCI_ADDREF(resource->shutdownCallback); 393 | 394 | if(ret = uv_shutdown(&resource->shutdown_req, (uv_stream_t *) &resource->uv_tcp, shutdown_cb)){ 395 | RETURN_LONG(ret); 396 | } 397 | 398 | setSelfReference(resource); 399 | RETURN_LONG(ret); 400 | } 401 | 402 | PHP_METHOD(UVTcp, connect){ 403 | long ret, port; 404 | zval *self = getThis(); 405 | const char *host = NULL; 406 | size_t host_len; 407 | char cstr_host[30]; 408 | struct sockaddr_in addr; 409 | 410 | uv_tcp_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_tcp_ext_t); 411 | 412 | FCI_FREE(resource->connectCallback); 413 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "slf", &host, &host_len, &port, FCI_PARSE_PARAMETERS_CC(resource->connectCallback))) { 414 | return; 415 | } 416 | FCI_ADDREF(resource->connectCallback); 417 | 418 | if(host_len == 0 || host_len >= 30){ 419 | FCI_FREE(resource->connectCallback); 420 | RETURN_LONG(-1); 421 | } 422 | 423 | memcpy(cstr_host, host, host_len); 424 | cstr_host[host_len] = '\0'; 425 | if((ret = uv_ip4_addr(cstr_host, port&0xffff, &addr)) != 0){ 426 | FCI_FREE(resource->connectCallback); 427 | RETURN_LONG(ret); 428 | } 429 | 430 | if((ret = uv_tcp_connect(&resource->connect_req, &resource->uv_tcp, (const struct sockaddr *) &addr, client_connection_cb)) != 0){ 431 | FCI_FREE(resource->connectCallback); 432 | RETURN_LONG(ret); 433 | } 434 | 435 | setSelfReference(resource); 436 | resource->flag |= UV_TCP_HANDLE_START; 437 | RETURN_LONG(ret); 438 | } 439 | 440 | zend_bool make_accepted_uv_tcp_object(uv_tcp_ext_t *server_resource, zval *client){ 441 | zval rv; 442 | uv_tcp_ext_t *client_resource; 443 | client_resource = FETCH_OBJECT_RESOURCE(client, uv_tcp_ext_t); 444 | zval *loop = zend_read_property(CLASS_ENTRY(UVTcp), &server_resource->object, ZEND_STRL("loop"), 1, &rv); 445 | zend_update_property(CLASS_ENTRY(UVTcp), client, ZEND_STRL("loop"), loop); 446 | uv_tcp_init(ZVAL_IS_NULL(loop)?uv_default_loop():FETCH_UV_LOOP(), (uv_tcp_t *) client_resource); 447 | 448 | if(uv_accept((uv_stream_t *) &server_resource->uv_tcp, (uv_stream_t *) &client_resource->uv_tcp)) { 449 | zval_ptr_dtor(client); 450 | return 0; 451 | } 452 | 453 | client_resource->flag |= (UV_TCP_HANDLE_START|UV_TCP_READ_START); 454 | ZVAL_COPY_VALUE(&client_resource->object, client); 455 | return 1; 456 | } 457 | -------------------------------------------------------------------------------- /src/uv_tcp.h: -------------------------------------------------------------------------------- 1 | #ifndef _UV_TCP_H 2 | #define _UV_TCP_H 3 | #include "../php_ext_uv.h" 4 | #include "uv_loop_resource.h" 5 | #include "fcall.h" 6 | 7 | #define UV_TCP_HANDLE_INTERNAL_REF 1 8 | #define UV_TCP_HANDLE_START (1<<1) 9 | #define UV_TCP_READ_START (1<<2) 10 | #define UV_TCP_CLOSING_START (1<<3) 11 | #define UV_TCP_WRITE_CALLBACK_ENABLE (1<<4) 12 | 13 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVTcp, __construct), 0) 14 | ZEND_ARG_OBJ_INFO(0, loop, UVLoop, 1) 15 | ZEND_END_ARG_INFO() 16 | 17 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVTcp, setCallback), 0) 18 | ZEND_ARG_INFO(0, onRecvCallback) 19 | ZEND_ARG_INFO(0, onSendCallback) 20 | ZEND_ARG_INFO(0, onErrorCallback) 21 | ZEND_END_ARG_INFO() 22 | 23 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVTcp, listen), 0) 24 | ZEND_ARG_INFO(0, host) 25 | ZEND_ARG_INFO(0, port) 26 | ZEND_ARG_INFO(0, onConnectCallback) 27 | ZEND_END_ARG_INFO() 28 | 29 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVTcp, connect), 0) 30 | ZEND_ARG_INFO(0, host) 31 | ZEND_ARG_INFO(0, port) 32 | ZEND_ARG_INFO(0, onConnectCallback) 33 | ZEND_END_ARG_INFO() 34 | 35 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVTcp, shutdown), 0) 36 | ZEND_ARG_INFO(0, onShutdownCallback) 37 | ZEND_END_ARG_INFO() 38 | 39 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVTcp, write), 0) 40 | ZEND_ARG_INFO(0, buf) 41 | ZEND_END_ARG_INFO() 42 | 43 | typedef struct uv_tcp_ext_s{ 44 | uv_tcp_t uv_tcp; 45 | uint flag; 46 | uv_connect_t connect_req; 47 | uv_shutdown_t shutdown_req; 48 | char *sockAddr; 49 | int sockPort; 50 | char *peerAddr; 51 | int peerPort; 52 | zval gc_table[7]; 53 | fcall_info_t readCallback; 54 | fcall_info_t writeCallback; 55 | fcall_info_t errorCallback; 56 | fcall_info_t connectCallback; 57 | fcall_info_t shutdownCallback; 58 | zval object; 59 | zend_object zo; 60 | } uv_tcp_ext_t; 61 | 62 | typedef struct write_req_s{ 63 | uv_write_t uv_write; 64 | uv_buf_t buf; 65 | } write_req_t; 66 | 67 | static zend_always_inline void releaseUVTcpFunctionCache(uv_tcp_ext_t *resource){ 68 | freeFunctionCache(&resource->readCallback); 69 | freeFunctionCache(&resource->writeCallback); 70 | freeFunctionCache(&resource->errorCallback); 71 | freeFunctionCache(&resource->connectCallback); 72 | freeFunctionCache(&resource->shutdownCallback); 73 | } 74 | 75 | static zend_object *createUVTcpResource(zend_class_entry *class_type); 76 | static void freeUVTcpResource(zend_object *object); 77 | HashTable *get_gc_UVTcpResource(zval *obj, zval **table, int *n); 78 | void releaseResource(uv_tcp_ext_t *resource); 79 | int tcp_write_raw(uv_stream_t * handle, const char *message, int size); 80 | zend_bool make_accepted_uv_tcp_object(uv_tcp_ext_t *server_resource, zval *client); 81 | static void tcp_close_cb(uv_handle_t* handle); 82 | void tcp_close_socket(uv_tcp_ext_t *handle); 83 | void setSelfReference(uv_tcp_ext_t *resource); 84 | 85 | PHP_METHOD(UVTcp, getSockname); 86 | PHP_METHOD(UVTcp, getSockport); 87 | PHP_METHOD(UVTcp, getPeername); 88 | PHP_METHOD(UVTcp, getPeerport); 89 | PHP_METHOD(UVTcp, listen); 90 | PHP_METHOD(UVTcp, accept); 91 | PHP_METHOD(UVTcp, write); 92 | PHP_METHOD(UVTcp, setCallback); 93 | PHP_METHOD(UVTcp, close); 94 | PHP_METHOD(UVTcp, shutdown); 95 | PHP_METHOD(UVTcp, __construct); 96 | PHP_METHOD(UVTcp, connect); 97 | 98 | DECLARE_FUNCTION_ENTRY(UVTcp) = { 99 | PHP_ME(UVTcp, __construct, ARGINFO(UVTcp, __construct), ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) 100 | PHP_ME(UVTcp, getSockname, NULL, ZEND_ACC_PUBLIC) 101 | PHP_ME(UVTcp, getSockport, NULL, ZEND_ACC_PUBLIC) 102 | PHP_ME(UVTcp, getPeername, NULL, ZEND_ACC_PUBLIC) 103 | PHP_ME(UVTcp, getPeerport, NULL, ZEND_ACC_PUBLIC) 104 | PHP_ME(UVTcp, listen, NULL, ZEND_ACC_PUBLIC) 105 | PHP_ME(UVTcp, accept, NULL, ZEND_ACC_PUBLIC) 106 | PHP_ME(UVTcp, setCallback, ARGINFO(UVTcp, setCallback), ZEND_ACC_PUBLIC) 107 | PHP_ME(UVTcp, write, ARGINFO(UVTcp, write), ZEND_ACC_PUBLIC) 108 | PHP_ME(UVTcp, close, NULL, ZEND_ACC_PUBLIC) 109 | PHP_ME(UVTcp, shutdown, ARGINFO(UVTcp, shutdown), ZEND_ACC_PUBLIC) 110 | PHP_ME(UVTcp, connect, ARGINFO(UVTcp, connect), ZEND_ACC_PUBLIC) 111 | PHP_FE_END 112 | }; 113 | #endif 114 | -------------------------------------------------------------------------------- /src/uv_timer.c: -------------------------------------------------------------------------------- 1 | #include "uv_timer.h" 2 | 3 | CLASS_ENTRY_FUNCTION_D(UVTimer){ 4 | REGISTER_CLASS_WITH_OBJECT_NEW(UVTimer, createUVTimerResource); 5 | OBJECT_HANDLER(UVTimer).offset = XtOffsetOf(uv_timer_ext_t, zo); 6 | OBJECT_HANDLER(UVTimer).clone_obj = NULL; 7 | OBJECT_HANDLER(UVTimer).free_obj = freeUVTimerResource; 8 | OBJECT_HANDLER(UVTimer).get_gc = get_gc_UVTimerResource; 9 | zend_declare_property_null(CLASS_ENTRY(UVTimer), ZEND_STRL("loop"), ZEND_ACC_PRIVATE); 10 | } 11 | 12 | static HashTable *get_gc_UVTimerResource(zval *obj, zval **table, int *n) { 13 | uv_timer_ext_t *resource; 14 | resource = FETCH_OBJECT_RESOURCE(obj, uv_timer_ext_t); 15 | FCI_GC_TABLE(resource, callback); 16 | *table = (zval *) &resource->gc_table; 17 | *n = FCI_GC_TABLE_SIZE(resource->gc_table); 18 | return zend_std_get_properties(obj); 19 | } 20 | 21 | static void timer_handle_callback(uv_timer_ext_t *timer_handle){ 22 | zval retval; 23 | fci_call_function(&timer_handle->callback, &retval, 1, &timer_handle->object); 24 | zval_ptr_dtor(&retval); 25 | } 26 | 27 | static zend_object *createUVTimerResource(zend_class_entry *ce) { 28 | uv_timer_ext_t *resource; 29 | resource = ALLOC_RESOURCE(uv_timer_ext_t); 30 | 31 | zend_object_std_init(&resource->zo, ce); 32 | object_properties_init(&resource->zo, ce); 33 | 34 | resource->zo.handlers = &OBJECT_HANDLER(UVTimer); 35 | return &resource->zo; 36 | } 37 | 38 | void freeUVTimerResource(zend_object *object) { 39 | uv_timer_ext_t *resource; 40 | resource = FETCH_RESOURCE(object, uv_timer_ext_t); 41 | if(resource->start){ 42 | uv_timer_stop((uv_timer_t *) resource); 43 | FCI_FREE(resource->callback); 44 | } 45 | uv_unref((uv_handle_t *) resource); 46 | zend_object_std_dtor(&resource->zo); 47 | } 48 | 49 | PHP_METHOD(UVTimer, __construct){ 50 | zval *loop = NULL; 51 | zval *self = getThis(); 52 | uv_timer_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_timer_ext_t); 53 | 54 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|z", &loop)) { 55 | return; 56 | } 57 | 58 | if(NULL == loop || ZVAL_IS_NULL(loop)){ 59 | uv_timer_init(uv_default_loop(), (uv_timer_t *) resource); 60 | return; 61 | } 62 | 63 | zend_update_property(CLASS_ENTRY(UVTimer), self, ZEND_STRL("loop"), loop); 64 | uv_timer_init(FETCH_UV_LOOP(), (uv_timer_t *) resource); 65 | } 66 | 67 | PHP_METHOD(UVTimer, start){ 68 | long start, repeat = 0, ret; 69 | zval *self = getThis(); 70 | uv_timer_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_timer_ext_t); 71 | 72 | FCI_FREE(resource->callback); 73 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "fl|l", FCI_PARSE_PARAMETERS_CC(resource->callback), &start, &repeat)) { 74 | return; 75 | } 76 | FCI_ADDREF(resource->callback); 77 | 78 | if(ret = uv_timer_start((uv_timer_t *) resource, (uv_timer_cb) timer_handle_callback, start, repeat)){ 79 | FCI_FREE(resource->callback); 80 | RETURN_LONG(ret); 81 | } 82 | 83 | resource->start = 1; 84 | ZVAL_COPY(&resource->object, self); 85 | RETURN_LONG(ret); 86 | } 87 | 88 | PHP_METHOD(UVTimer, stop){ 89 | long ret; 90 | zval *self = getThis(); 91 | uv_timer_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_timer_ext_t); 92 | 93 | if(!resource->start){ 94 | RETURN_LONG(-1); 95 | } 96 | 97 | ret = uv_timer_stop((uv_timer_t *) resource); 98 | if(ret == 0){ 99 | resource->start = 0; 100 | FCI_FREE(resource->callback); 101 | zval_dtor(&resource->object); 102 | } 103 | RETURN_LONG(ret); 104 | } 105 | -------------------------------------------------------------------------------- /src/uv_timer.h: -------------------------------------------------------------------------------- 1 | #ifndef _UV_TIMER_H 2 | #define _UV_TIMER_H 3 | #include "../php_ext_uv.h" 4 | #include "uv_loop_resource.h" 5 | #include "fcall.h" 6 | 7 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVTimer, __construct), 0) 8 | ZEND_ARG_OBJ_INFO(0, loop, UVLoop, 1) 9 | ZEND_END_ARG_INFO() 10 | 11 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVTimer, start), 0) 12 | ZEND_ARG_INFO(0, timer_cb) 13 | ZEND_ARG_INFO(0, start) 14 | ZEND_ARG_INFO(0, repeat) 15 | ZEND_END_ARG_INFO() 16 | 17 | typedef struct uv_timer_ext_s{ 18 | uv_timer_t uv_timer; 19 | int start; 20 | struct { 21 | zval callback; 22 | } gc_table; 23 | fcall_info_t callback; 24 | zval object; 25 | zend_object zo; 26 | } uv_timer_ext_t; 27 | 28 | static zend_object *createUVTimerResource(zend_class_entry *class_type); 29 | static void timer_handle_callback(uv_timer_ext_t *timer_handle); 30 | static HashTable *get_gc_UVTimerResource(zval *obj, zval **table, int *n); 31 | void freeUVTimerResource(zend_object *object); 32 | 33 | PHP_METHOD(UVTimer, __construct); 34 | PHP_METHOD(UVTimer, start); 35 | PHP_METHOD(UVTimer, stop); 36 | 37 | DECLARE_FUNCTION_ENTRY(UVTimer) = { 38 | PHP_ME(UVTimer, __construct, ARGINFO(UVTimer, __construct), ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) 39 | PHP_ME(UVTimer, start, ARGINFO(UVTimer, start), ZEND_ACC_PUBLIC) 40 | PHP_ME(UVTimer, stop, NULL, ZEND_ACC_PUBLIC) 41 | PHP_FE_END 42 | }; 43 | #endif 44 | -------------------------------------------------------------------------------- /src/uv_udp.c: -------------------------------------------------------------------------------- 1 | #include "uv_udp.h" 2 | 3 | CLASS_ENTRY_FUNCTION_D(UVUdp){ 4 | REGISTER_CLASS_WITH_OBJECT_NEW(UVUdp, createUVUdpResource); 5 | OBJECT_HANDLER(UVUdp).offset = XtOffsetOf(uv_udp_ext_t, zo);; 6 | OBJECT_HANDLER(UVUdp).clone_obj = NULL; 7 | OBJECT_HANDLER(UVUdp).free_obj = freeUVUdpResource; 8 | OBJECT_HANDLER(UVUdp).get_gc = get_gc_UVUdpResource; 9 | zend_declare_property_null(CLASS_ENTRY(UVUdp), ZEND_STRL("loop"), ZEND_ACC_PRIVATE); 10 | } 11 | 12 | static HashTable *get_gc_UVUdpResource(zval *obj, zval **table, int *n) { 13 | uv_udp_ext_t *resource = FETCH_OBJECT_RESOURCE(obj, uv_udp_ext_t); 14 | *table = &resource->gc_table; 15 | int index = 0; 16 | FCI_GC_TABLE_EX(resource, recvCallback, index); 17 | FCI_GC_TABLE_EX(resource, sendCallback, index); 18 | FCI_GC_TABLE_EX(resource, errorCallback, index); 19 | *n = index; 20 | return zend_std_get_properties(obj); 21 | } 22 | 23 | static void release(uv_udp_ext_t *resource){ 24 | 25 | if(resource->sockPort != 0){ 26 | resource->sockPort = 0; 27 | efree(resource->sockAddr); 28 | resource->sockAddr = NULL; 29 | } 30 | 31 | if(resource->flag & UV_UDP_READ_START){ 32 | resource->flag &= ~UV_UDP_READ_START; 33 | uv_udp_recv_stop(&resource->uv_udp); 34 | } 35 | 36 | if(resource->flag & UV_UDP_HANDLE_START){ 37 | resource->flag &= ~UV_UDP_HANDLE_START; 38 | uv_udp_recv_stop(&resource->uv_udp); 39 | } 40 | 41 | if(resource->flag & UV_UDP_HANDLE_INTERNAL_REF){ 42 | resource->flag &= ~UV_UDP_HANDLE_INTERNAL_REF; 43 | zval_ptr_dtor(&resource->object); 44 | } 45 | } 46 | 47 | static void close_cb(uv_handle_t* handle) { 48 | release((uv_udp_ext_t *) handle); 49 | } 50 | 51 | static void send_cb(uv_udp_send_t* sr, int status) { 52 | send_req_t *req = (send_req_t *) sr; 53 | uv_udp_ext_t *resource = (uv_udp_ext_t *) sr->handle; 54 | char *s_addr; 55 | zval retval; 56 | zval params[4]; 57 | params[0] = resource->object; 58 | 59 | if(!FCI_ISNULL(resource->sendCallback)){ 60 | s_addr = sock_addr((struct sockaddr *) &req->addr); 61 | ZVAL_STRING(¶ms[1], s_addr); 62 | ZVAL_LONG(¶ms[2], sock_port((struct sockaddr *) &req->addr)); 63 | ZVAL_LONG(¶ms[3], status); 64 | 65 | fci_call_function(&resource->sendCallback, &retval, 4, params); 66 | 67 | zval_ptr_dtor(¶ms[1]); 68 | zval_ptr_dtor(&retval); 69 | efree(s_addr); 70 | } 71 | efree(req->buf.base); 72 | efree(req); 73 | } 74 | 75 | static void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { 76 | buf->base = emalloc(suggested_size); 77 | buf->len = suggested_size; 78 | } 79 | 80 | static void recv_cb(uv_udp_ext_t* resource, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned int flags) { 81 | char *s_addr; 82 | zval params[5]; 83 | zval retval; 84 | params[0] = resource->object; 85 | if(nread > 0){ 86 | if(!FCI_ISNULL(resource->recvCallback)){ 87 | s_addr = sock_addr((struct sockaddr *) addr); 88 | ZVAL_STRING(¶ms[1], s_addr); 89 | ZVAL_LONG(¶ms[2], sock_port((struct sockaddr *) addr)); 90 | ZVAL_STRINGL(¶ms[3], buf->base, nread); 91 | ZVAL_LONG(¶ms[4], flags); 92 | 93 | fci_call_function(&resource->recvCallback, &retval, 5, params); 94 | 95 | zval_ptr_dtor(¶ms[1]); 96 | zval_ptr_dtor(¶ms[3]); 97 | zval_ptr_dtor(&retval); 98 | efree(s_addr); 99 | } 100 | } 101 | else{ 102 | if(!FCI_ISNULL(resource->errorCallback)){ 103 | ZVAL_LONG(¶ms[1], nread); 104 | ZVAL_LONG(¶ms[2], flags); 105 | 106 | fci_call_function(&resource->errorCallback, &retval, 3, params); 107 | 108 | zval_ptr_dtor(&retval); 109 | } 110 | } 111 | efree(buf->base); 112 | } 113 | 114 | static zend_object *createUVUdpResource(zend_class_entry *ce) { 115 | uv_udp_ext_t *resource; 116 | resource = ALLOC_RESOURCE(uv_udp_ext_t); 117 | zend_object_std_init(&resource->zo, ce); 118 | object_properties_init(&resource->zo, ce); 119 | resource->zo.handlers = &OBJECT_HANDLER(UVUdp); 120 | return &resource->zo; 121 | } 122 | 123 | void freeUVUdpResource(zend_object *object) { 124 | uv_udp_ext_t *resource; 125 | resource = FETCH_RESOURCE(object, uv_udp_ext_t); 126 | release(resource); 127 | releaseUVUdpFunctionCache(resource); 128 | zend_object_std_dtor(&resource->zo); 129 | } 130 | 131 | static zend_always_inline void resolveSocket(uv_udp_ext_t *resource){ 132 | struct sockaddr addr; 133 | int addrlen; 134 | int ret; 135 | if(resource->sockPort == 0){ 136 | addrlen = sizeof addr; 137 | if(ret = uv_udp_getsockname(&resource->uv_udp, &addr, &addrlen)){ 138 | return; 139 | } 140 | resource->sockPort = sock_port(&addr); 141 | resource->sockAddr = sock_addr(&addr); 142 | } 143 | } 144 | 145 | PHP_METHOD(UVUdp, __construct){ 146 | zval *loop = NULL; 147 | zval *self = getThis(); 148 | uv_udp_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_udp_ext_t); 149 | 150 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|z", &loop)) { 151 | return; 152 | } 153 | 154 | if(NULL == loop || ZVAL_IS_NULL(loop)){ 155 | uv_udp_init(uv_default_loop(), (uv_udp_t *) resource); 156 | return; 157 | } 158 | 159 | zend_update_property(CLASS_ENTRY(UVUdp), self, ZEND_STRL("loop"), loop); 160 | uv_udp_init(FETCH_UV_LOOP(), (uv_udp_t *) resource); 161 | } 162 | 163 | PHP_METHOD(UVUdp, getSockname){ 164 | zval *self = getThis(); 165 | uv_udp_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_udp_ext_t); 166 | resolveSocket(resource); 167 | if(resource->sockPort == 0){ 168 | RETURN_FALSE; 169 | } 170 | RETURN_STRING(resource->sockAddr); 171 | } 172 | 173 | PHP_METHOD(UVUdp, getSockport){ 174 | zval *self = getThis(); 175 | uv_udp_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_udp_ext_t); 176 | resolveSocket(resource); 177 | if(resource->sockPort == 0){ 178 | RETURN_FALSE; 179 | } 180 | RETURN_LONG(resource->sockPort); 181 | } 182 | 183 | PHP_METHOD(UVUdp, bind){ 184 | long ret, port; 185 | zval *self = getThis(); 186 | const char *host = NULL; 187 | size_t host_len; 188 | char cstr_host[30]; 189 | struct sockaddr_in addr; 190 | 191 | uv_udp_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_udp_ext_t); 192 | 193 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "sl", &host, &host_len, &port)) { 194 | return; 195 | } 196 | 197 | if(host_len == 0 || host_len >= 30){ 198 | RETURN_LONG(-1); 199 | } 200 | 201 | memcpy(cstr_host, host, host_len); 202 | cstr_host[host_len] = '\0'; 203 | if((ret = uv_ip4_addr(cstr_host, port&0xffff, &addr)) != 0){ 204 | RETURN_LONG(ret); 205 | } 206 | 207 | if((ret = uv_udp_bind(&resource->uv_udp, (const struct sockaddr*) &addr, 0)) != 0){ 208 | RETURN_LONG(ret); 209 | } 210 | 211 | resource->flag |= UV_UDP_HANDLE_START; 212 | 213 | RETURN_LONG(ret); 214 | } 215 | 216 | PHP_METHOD(UVUdp, setCallback){ 217 | long ret; 218 | zval *self = getThis(); 219 | uv_udp_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_udp_ext_t); 220 | 221 | if(resource->flag & UV_UDP_READ_START){ 222 | RETURN_LONG(-1); 223 | } 224 | 225 | FCI_FREE(resource->recvCallback); 226 | FCI_FREE(resource->sendCallback); 227 | FCI_FREE(resource->errorCallback); 228 | 229 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "fff", FCI_PARSE_PARAMETERS_CC(resource->recvCallback), FCI_PARSE_PARAMETERS_CC(resource->sendCallback), FCI_PARSE_PARAMETERS_CC(resource->errorCallback))) { 230 | return; 231 | } 232 | 233 | if(ret = uv_udp_recv_start(&resource->uv_udp, alloc_cb, (uv_udp_recv_cb) recv_cb)){ 234 | RETURN_LONG(ret); 235 | } 236 | 237 | FCI_ADDREF(resource->recvCallback); 238 | FCI_ADDREF(resource->sendCallback); 239 | FCI_ADDREF(resource->errorCallback); 240 | resource->flag |= (UV_UDP_HANDLE_INTERNAL_REF|UV_UDP_HANDLE_START|UV_UDP_READ_START); 241 | ZVAL_COPY(&resource->object, self); 242 | RETURN_LONG(ret); 243 | } 244 | 245 | PHP_METHOD(UVUdp, sendTo){ 246 | char *dest = NULL, *message = NULL; 247 | char cstr_dest[30]; 248 | size_t dest_len, message_len; 249 | long port, ret; 250 | send_req_t *req; 251 | zval *self = getThis(); 252 | uv_udp_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_udp_ext_t); 253 | 254 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "sls", &dest, &dest_len, &port, &message, &message_len)) { 255 | return; 256 | } 257 | 258 | if(dest_len == 0 || dest_len >= 30){ 259 | RETURN_LONG(-1); 260 | } 261 | 262 | req = emalloc(sizeof(send_req_t)); 263 | cstr_dest[dest_len] = '\0'; 264 | memcpy(cstr_dest, dest, dest_len); 265 | if((ret = uv_ip4_addr(cstr_dest, port&0xffff, &req->addr)) != 0){ 266 | efree(req); 267 | RETURN_LONG(ret); 268 | } 269 | 270 | req->buf.base = emalloc(message_len); 271 | req->buf.len = message_len; 272 | memcpy(req->buf.base, message, message_len); 273 | ret = uv_udp_send( 274 | (uv_udp_send_t *)req, 275 | &resource->uv_udp, 276 | &req->buf, 277 | 1, 278 | (const struct sockaddr *) &req->addr, 279 | send_cb 280 | ); 281 | RETURN_LONG(ret); 282 | } 283 | 284 | PHP_METHOD(UVUdp, close){ 285 | zval *self = getThis(); 286 | uv_udp_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_udp_ext_t); 287 | uv_close((uv_handle_t *) &resource->uv_udp, close_cb); 288 | } 289 | -------------------------------------------------------------------------------- /src/uv_udp.h: -------------------------------------------------------------------------------- 1 | #ifndef _UV_UDP_H 2 | #define _UV_UDP_H 3 | #include "../php_ext_uv.h" 4 | #include "uv_loop_resource.h" 5 | #include "fcall.h" 6 | 7 | #define UV_UDP_HANDLE_INTERNAL_REF 1 8 | #define UV_UDP_HANDLE_START (1<<1) 9 | #define UV_UDP_READ_START (1<<2) 10 | 11 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVUdp, __construct), 0) 12 | ZEND_ARG_OBJ_INFO(0, loop, UVLoop, 1) 13 | ZEND_END_ARG_INFO() 14 | 15 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVUdp, bind), 0) 16 | ZEND_ARG_INFO(0, host) 17 | ZEND_ARG_INFO(0, port) 18 | ZEND_END_ARG_INFO() 19 | 20 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVUdp, setCallback), 0) 21 | ZEND_ARG_INFO(0, onRecvCallback) 22 | ZEND_ARG_INFO(0, onSendCallback) 23 | ZEND_ARG_INFO(0, onErrorCallback) 24 | ZEND_END_ARG_INFO() 25 | 26 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVUdp, sendTo), 0) 27 | ZEND_ARG_INFO(0, dest) 28 | ZEND_ARG_INFO(0, port) 29 | ZEND_ARG_INFO(0, message) 30 | ZEND_END_ARG_INFO() 31 | 32 | typedef struct uv_udp_ext_s{ 33 | uv_udp_t uv_udp; 34 | uint flag; 35 | char *sockAddr; 36 | int sockPort; 37 | zval gc_table[3]; 38 | fcall_info_t recvCallback; 39 | fcall_info_t sendCallback; 40 | fcall_info_t errorCallback; 41 | zval object; 42 | zend_object zo; 43 | } uv_udp_ext_t; 44 | 45 | typedef struct send_req_s{ 46 | uv_udp_send_t uv_udp_send; 47 | uv_buf_t buf; 48 | struct sockaddr_in addr; 49 | } send_req_t; 50 | 51 | static zend_object *createUVUdpResource(zend_class_entry *class_type); 52 | static HashTable *get_gc_UVUdpResource(zval *obj, zval **table, int *n); 53 | void freeUVUdpResource(zend_object *object); 54 | 55 | PHP_METHOD(UVUdp, __construct); 56 | PHP_METHOD(UVUdp, getSockname); 57 | PHP_METHOD(UVUdp, getSockport); 58 | PHP_METHOD(UVUdp, bind); 59 | PHP_METHOD(UVUdp, setCallback); 60 | PHP_METHOD(UVUdp, close); 61 | PHP_METHOD(UVUdp, sendTo); 62 | 63 | DECLARE_FUNCTION_ENTRY(UVUdp) = { 64 | PHP_ME(UVUdp, __construct, ARGINFO(UVUdp, __construct), ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) 65 | PHP_ME(UVUdp, getSockname, NULL, ZEND_ACC_PUBLIC) 66 | PHP_ME(UVUdp, getSockport, NULL, ZEND_ACC_PUBLIC) 67 | PHP_ME(UVUdp, close, NULL, ZEND_ACC_PUBLIC) 68 | PHP_ME(UVUdp, bind, ARGINFO(UVUdp, bind), ZEND_ACC_PUBLIC) 69 | PHP_ME(UVUdp, sendTo, ARGINFO(UVUdp, sendTo), ZEND_ACC_PUBLIC) 70 | PHP_ME(UVUdp, setCallback, ARGINFO(UVUdp, setCallback), ZEND_ACC_PUBLIC) 71 | PHP_FE_END 72 | }; 73 | 74 | static zend_always_inline void releaseUVUdpFunctionCache(uv_udp_ext_t *resource){ 75 | freeFunctionCache(&resource->recvCallback); 76 | freeFunctionCache(&resource->sendCallback); 77 | freeFunctionCache(&resource->errorCallback); 78 | } 79 | #endif 80 | -------------------------------------------------------------------------------- /src/uv_util.c: -------------------------------------------------------------------------------- 1 | #include "uv_util.h" 2 | 3 | CLASS_ENTRY_FUNCTION_D(UVUtil){ 4 | REGISTER_CLASS(UVUtil); 5 | OBJECT_HANDLER(UVUtil).clone_obj = NULL; 6 | } 7 | 8 | PHP_METHOD(UVUtil, __construct){ 9 | } 10 | 11 | PHP_METHOD(UVUtil, version) { 12 | RETURN_LONG(uv_version()); 13 | } 14 | 15 | PHP_METHOD(UVUtil, versionString) { 16 | RETURN_STRING(uv_version_string()); 17 | } 18 | 19 | PHP_METHOD(UVUtil, errorMessage) { 20 | long err; 21 | if(zend_parse_parameters(ZEND_NUM_ARGS(), "l", &err) == FAILURE) { 22 | return; 23 | } 24 | RETURN_STRING(uv_strerror(err)); 25 | } 26 | 27 | PHP_METHOD(UVUtil, cpuinfo) { 28 | zval retval, times; 29 | uv_cpu_info_t *info; 30 | int cpu_count; 31 | uv_cpu_info(&info, &cpu_count); 32 | array_init(&retval); 33 | array_init(×); 34 | add_assoc_long(×, "user", info->cpu_times.user); 35 | add_assoc_long(×, "nice", info->cpu_times.nice); 36 | add_assoc_long(×, "sys", info->cpu_times.sys); 37 | add_assoc_long(×, "idle", info->cpu_times.idle); 38 | add_assoc_long(×, "irq", info->cpu_times.irq); 39 | add_assoc_long(&retval, "count", cpu_count); 40 | add_assoc_string(&retval, "model", info->model); 41 | add_assoc_long(&retval, "speed", info->speed); 42 | add_assoc_zval(&retval, "times", ×); 43 | uv_free_cpu_info(info, cpu_count); 44 | RETURN_ZVAL(&retval, 0, 0); 45 | } 46 | -------------------------------------------------------------------------------- /src/uv_util.h: -------------------------------------------------------------------------------- 1 | #ifndef _UV_UTIL_H 2 | #define _UV_UTIL_H 3 | #include "../php_ext_uv.h" 4 | 5 | CLASS_ENTRY_FUNCTION_D(UVUtil); 6 | 7 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVUtil, errorMessage), 0) 8 | ZEND_ARG_INFO(0, err) 9 | ZEND_END_ARG_INFO() 10 | 11 | PHP_METHOD(UVUtil, version); 12 | PHP_METHOD(UVUtil, versionString); 13 | PHP_METHOD(UVUtil, errorMessage); 14 | PHP_METHOD(UVUtil, __construct); 15 | PHP_METHOD(UVUtil, cpuinfo); 16 | 17 | DECLARE_FUNCTION_ENTRY(UVUtil) = { 18 | PHP_ME(UVUtil, __construct, NULL, ZEND_ACC_PRIVATE | ZEND_ACC_FINAL) 19 | PHP_ME(UVUtil, errorMessage, ARGINFO(UVUtil, errorMessage), ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) 20 | PHP_ME(UVUtil, version, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) 21 | PHP_ME(UVUtil, versionString, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) 22 | PHP_ME(UVUtil, cpuinfo, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) 23 | PHP_FE_END 24 | }; 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/uv_worker.c: -------------------------------------------------------------------------------- 1 | #include "uv_worker.h" 2 | 3 | CLASS_ENTRY_FUNCTION_D(UVWorker){ 4 | REGISTER_CLASS_WITH_OBJECT_NEW(UVWorker, createUVWorkerResource); 5 | OBJECT_HANDLER(UVWorker).offset = XtOffsetOf(uv_worker_ext_t, zo); 6 | OBJECT_HANDLER(UVWorker).clone_obj = NULL; 7 | OBJECT_HANDLER(UVWorker).free_obj = freeUVWorkerResource; 8 | OBJECT_HANDLER(UVWorker).get_gc = get_gc_UVWorkerResource; 9 | zend_declare_property_null(CLASS_ENTRY(UVWorker), ZEND_STRL("loop"), ZEND_ACC_PRIVATE); 10 | } 11 | 12 | static zend_object *createUVWorkerResource(zend_class_entry *ce) { 13 | uv_worker_ext_t *resource; 14 | resource = ALLOC_RESOURCE(uv_worker_ext_t); 15 | zend_object_std_init(&resource->zo, ce); 16 | object_properties_init(&resource->zo, ce); 17 | resource->zo.handlers = &OBJECT_HANDLER(UVWorker); 18 | return &resource->zo; 19 | } 20 | 21 | static HashTable *get_gc_UVWorkerResource(zval *obj, zval **table, int *n) { 22 | uv_worker_ext_t *resource; 23 | resource = FETCH_OBJECT_RESOURCE(obj, uv_worker_ext_t); 24 | FCI_GC_TABLE(resource, closeCallback); 25 | *table = (zval *) &resource->gc_table; 26 | *n = FCI_GC_TABLE_SIZE(resource->gc_table); 27 | return zend_std_get_properties(obj); 28 | } 29 | 30 | void freeUVWorkerResource(zend_object *object) { 31 | uv_worker_ext_t *resource; 32 | resource = FETCH_RESOURCE(object, uv_worker_ext_t); 33 | freeFunctionCache(&resource->closeCallback); 34 | zend_object_std_dtor(&resource->zo); 35 | } 36 | 37 | PHP_METHOD(UVWorker, __construct){ 38 | } 39 | 40 | PHP_METHOD(UVWorker, kill){ 41 | long signum; 42 | zval *self = getThis(); 43 | uv_worker_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_worker_ext_t); 44 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "l", &signum)) { 45 | return; 46 | } 47 | 48 | RETURN_LONG(uv_process_kill(&resource->process, signum)); 49 | } 50 | 51 | PHP_METHOD(UVWorker, getPid){ 52 | zval *self = getThis(); 53 | uv_worker_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_worker_ext_t); 54 | RETURN_LONG(resource->process.pid); 55 | } 56 | 57 | int make_worker(uv_loop_t *loop, char *args[], zval *worker) { 58 | int retval; 59 | uv_stdio_container_t child_stdio[3]; 60 | uv_worker_ext_t *resource = FETCH_OBJECT_RESOURCE(worker, uv_worker_ext_t); 61 | ZVAL_COPY_VALUE(&resource->object, worker); 62 | uv_pipe_init(loop, &resource->pipe, 1); 63 | child_stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; 64 | child_stdio[0].data.stream = (uv_stream_t*) &resource->pipe; 65 | child_stdio[1].flags = UV_IGNORE; 66 | child_stdio[2].flags = UV_INHERIT_FD; 67 | child_stdio[2].data.fd = 2; 68 | 69 | resource->options.stdio = child_stdio; 70 | resource->options.stdio_count = 3; 71 | 72 | resource->options.exit_cb = close_process_handle; 73 | resource->options.file = args[0]; 74 | resource->options.args = args; 75 | if((retval = uv_spawn(loop, &resource->process, &resource->options))==0){ 76 | Z_ADDREF(resource->object); 77 | } 78 | resource->loop = loop; 79 | return retval; 80 | } 81 | 82 | static void close_process_handle(uv_process_t *process, int64_t exit_status, int term_signal) { 83 | uv_worker_ext_t *resource = (uv_worker_ext_t *) process; 84 | zval retval; 85 | zval params[3]; 86 | params[0] = resource->object; 87 | if(!FCI_ISNULL(resource->closeCallback)){ 88 | ZVAL_LONG(¶ms[1], exit_status); 89 | ZVAL_LONG(¶ms[2], term_signal); 90 | fci_call_function(&resource->closeCallback, &retval, 3, params); 91 | zval_ptr_dtor(&retval); 92 | } 93 | uv_close((uv_handle_t*) process, NULL); 94 | zval_ptr_dtor(&resource->object); 95 | } 96 | 97 | PHP_METHOD(UVWorker, setCloseCallback){ 98 | long ret; 99 | zval *self = getThis(); 100 | uv_worker_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_worker_ext_t); 101 | 102 | FCI_FREE(resource->closeCallback); 103 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "f", FCI_PARSE_PARAMETERS_CC(resource->closeCallback))) { 104 | return; 105 | } 106 | FCI_ADDREF(resource->closeCallback); 107 | } 108 | 109 | static void tcp_close_cb(uv_handle_t* handle) { 110 | efree(handle); 111 | } 112 | 113 | static void write2_cb(write2_req_t* req, int status) { 114 | uv_close(req->client, tcp_close_cb); 115 | efree(req); 116 | } 117 | 118 | PHP_METHOD(UVWorker, attach){ 119 | zval *self = getThis(); 120 | zval *stream = NULL; 121 | uv_worker_ext_t *resource = FETCH_OBJECT_RESOURCE(self, uv_worker_ext_t); 122 | uv_tcp_ext_t *stream_resource; 123 | write2_req_t *write2_req; 124 | int r; 125 | 126 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "z", &stream)) { 127 | return; 128 | } 129 | 130 | stream_resource = FETCH_OBJECT_RESOURCE(stream, uv_tcp_ext_t); 131 | write2_req = (write2_req_t*) emalloc(sizeof(write2_req_t)); 132 | write2_req->client = (uv_tcp_t*) emalloc(sizeof(uv_tcp_t)); 133 | uv_tcp_init(resource->loop, write2_req->client); 134 | 135 | if(uv_accept(&stream_resource->uv_tcp, write2_req->client) == 0){ 136 | resource->dummy_buf = uv_buf_init("a", 1); 137 | uv_write2(&write2_req->req, (uv_stream_t*) &resource->pipe, &resource->dummy_buf, 1, (uv_stream_t*) write2_req->client, write2_cb); 138 | return; 139 | } 140 | efree(write2_req->client); 141 | efree(write2_req); 142 | } 143 | -------------------------------------------------------------------------------- /src/uv_worker.h: -------------------------------------------------------------------------------- 1 | #ifndef _UV_WORKER_H 2 | #define _UV_WORKER_H 3 | #include "../php_ext_uv.h" 4 | #include "uv_loop_resource.h" 5 | #include "fcall.h" 6 | #include "uv_tcp.h" 7 | 8 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVWorker, setCloseCallback), 0) 9 | ZEND_ARG_INFO(0, close_cb) 10 | ZEND_END_ARG_INFO() 11 | 12 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVWorker, kill), 0) 13 | ZEND_ARG_INFO(0, signum) 14 | ZEND_END_ARG_INFO() 15 | 16 | ZEND_BEGIN_ARG_INFO(ARGINFO(UVWorker, attach), 0) 17 | ZEND_ARG_OBJ_INFO(0, stream, UVTcp, 1) 18 | ZEND_END_ARG_INFO() 19 | 20 | typedef struct { 21 | uv_write_t req; 22 | uv_tcp_t *client; 23 | } write2_req_t; 24 | 25 | typedef struct uv_worker_ext_s{ 26 | uv_process_t process; 27 | uv_process_options_t options; 28 | uv_pipe_t pipe; 29 | uv_loop_t *loop; 30 | uv_buf_t dummy_buf; 31 | struct { 32 | zval closeCallback; 33 | } gc_table; 34 | fcall_info_t closeCallback; 35 | zval object; 36 | zend_object zo; 37 | } uv_worker_ext_t; 38 | 39 | static zend_object *createUVWorkerResource(zend_class_entry *class_type); 40 | void freeUVWorkerResource(zend_object *object); 41 | static HashTable *get_gc_UVWorkerResource(zval *obj, zval **table, int *n); 42 | static void close_process_handle(uv_process_t *req, int64_t exit_status, int term_signal); 43 | int make_worker(uv_loop_t *loop, char *args[], zval *worker); 44 | 45 | PHP_METHOD(UVWorker, __construct); 46 | PHP_METHOD(UVWorker, kill); 47 | PHP_METHOD(UVWorker, getPid); 48 | PHP_METHOD(UVWorker, setCloseCallback); 49 | PHP_METHOD(UVWorker, attach); 50 | 51 | DECLARE_FUNCTION_ENTRY(UVWorker) = { 52 | PHP_ME(UVWorker, __construct, NULL, ZEND_ACC_PRIVATE | ZEND_ACC_FINAL) 53 | PHP_ME(UVWorker, kill, ARGINFO(UVWorker, kill), ZEND_ACC_PUBLIC) 54 | PHP_ME(UVWorker, getPid, NULL, ZEND_ACC_PUBLIC) 55 | PHP_ME(UVWorker, setCloseCallback, ARGINFO(UVWorker, setCloseCallback), ZEND_ACC_PUBLIC) 56 | PHP_ME(UVWorker, attach, ARGINFO(UVWorker, attach), ZEND_ACC_PUBLIC) 57 | PHP_FE_END 58 | }; 59 | #endif 60 | -------------------------------------------------------------------------------- /tests/cert/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFQDCCAygCAQEwDQYJKoZIhvcNAQELBQAwZjELMAkGA1UEBhMCVFcxDzANBgNV 3 | BAgMBlRhaXdhbjEPMA0GA1UEBwwGVGFpcGVpMSEwHwYDVQQKDBhJbnRlcm5ldCBX 4 | aWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xNDA5MTExNDMz 5 | NTdaFw0yNDA5MDgxNDMzNTdaMGYxCzAJBgNVBAYTAlRXMQ8wDQYDVQQIDAZUYWl3 6 | YW4xDzANBgNVBAcMBlRhaXBlaTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ 7 | dHkgTHRkMRIwEAYDVQQDDAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEBAQUAA4IC 8 | DwAwggIKAoICAQD1a63I0V1XpKz2tYFW8HmLXu1y6kCOtlzQWSHfT4UVn06G0aRs 9 | KWKbAlGLz88SUksfk34QEFShXHO17waB+OWfmNt0hSwACATjaJX1nj7IsnuKbrqj 10 | k/D9R91LdNF/j7XN9aXVgADoyF2mIT/Fkom01izbyKoWtMY9wEd2jdTvHFwwv472 11 | 0Rl+2IZaxW3C1bstMxZABCqBpBs+k8sGTNdEjwz1HhTOKwpFfiUAwHkNjhgRidKe 12 | CdKnrzJESVR6LlgmZCS8Pu9J5FyYaMWtAEjztRLKS8ScWD6HVMe/ZUPuX1++XqiF 13 | Z78skvbsXgfr1kYH2VKFhB+wMyG7/ZJpgMKOWht4VIkrQBF6IwHjBCkk3RSNST6r 14 | lwJt7EdZQNJa1q5QP2fjq8n33oG0vq10QX4Xmvp5XRSEZ1MSs9KNJV0i05dIQRXB 15 | g+6aZUAUtWtJZWB1qXQ0VBh9SKUxbkAYa64rZWYz28x3gllQ2JwKeVdT7ry9NOHt 16 | Qjp52LzdHDTp5cxnWaioan4rcoHs2jkuf+Hz+pJxh/Q3gYE8Kxvw/m4s4aB6U69n 17 | 036bxFBIaGTvrXAPhLq90MLBm8lTEU5YWDq9FTjAFzj/CB2E6Ls+pGXULbP/0iWB 18 | d3gATSYaWe2KgINyuq69C+SwGhWo03g8d17GcqEmm1j+Ld6Cd48r4whzCwIDAQAB 19 | MA0GCSqGSIb3DQEBCwUAA4ICAQAgCrPa7Qo+p7sFh2R5l0Uj2TDKUr2oDVRVK6Ej 20 | jlwA/59EUw6y/e2XReGN9w1laYxQYBH9h7iLDfV6O1Wn6JkHpC2e62jCDMuIEA2+ 21 | aw9qUE1pOivOYu9r1VLd4WC4QsMIbbtwMPKfYdJgubLEl82vW/mubd/7A9/ecSKd 22 | hgfFPy/GyW2j+K7p5i8CPH1I0u+fDrY1hzOhppvycL2nhAn+CmLVU13grBWeVYc+ 23 | oIMp4isfAHCxxGDy8LYswQD274qD8mszAtCXGlLx8rlHk/TDM9cGkiJng3M8kLul 24 | KDa/N+3TCFn/TWkkVvVOaa/n/+WM4cuXozdwSXNGkwnHPwKl/wvDNRrdsSQw3Qaz 25 | w4MxOQs7ckbYTIhkzYJK8mO+MWmyQcQOqoJJ1hnI8j1hx8j9QevGUyyl42a/CJE6 26 | eYDLwJ+dIi4h5q+BpXw2x8Y0CpI5uo8oLZg7ECVrjiBZEfk1NchzVPRnG3MJAQ2h 27 | kOqBY3exTCEBujbc6xMoGvpn5aNyHVsgPsBd4ZEtPir+DgzDCRL6nOD5VmaB+aVm 28 | 3rXXeGMBWp2rz6ITGFeaBW0dnrGdUw/ytmWp8/rT1nYQVL68Uohxut/t19YAA7rq 29 | Re8Nlsj6Ns7i4Mdr2JPU2yVlAY96sXQ3jdYVcMAKaTqVQdx40MBeKZ27Y1PW44Fp 30 | fezYcA== 31 | -----END CERTIFICATE----- 32 | -------------------------------------------------------------------------------- /tests/cert/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIJKQIBAAKCAgEA9WutyNFdV6Ss9rWBVvB5i17tcupAjrZc0Fkh30+FFZ9OhtGk 3 | bClimwJRi8/PElJLH5N+EBBUoVxzte8Ggfjln5jbdIUsAAgE42iV9Z4+yLJ7im66 4 | o5Pw/UfdS3TRf4+1zfWl1YAA6MhdpiE/xZKJtNYs28iqFrTGPcBHdo3U7xxcML+O 5 | 9tEZftiGWsVtwtW7LTMWQAQqgaQbPpPLBkzXRI8M9R4UzisKRX4lAMB5DY4YEYnS 6 | ngnSp68yRElUei5YJmQkvD7vSeRcmGjFrQBI87USykvEnFg+h1THv2VD7l9fvl6o 7 | hWe/LJL27F4H69ZGB9lShYQfsDMhu/2SaYDCjlobeFSJK0AReiMB4wQpJN0UjUk+ 8 | q5cCbexHWUDSWtauUD9n46vJ996BtL6tdEF+F5r6eV0UhGdTErPSjSVdItOXSEEV 9 | wYPummVAFLVrSWVgdal0NFQYfUilMW5AGGuuK2VmM9vMd4JZUNicCnlXU+68vTTh 10 | 7UI6edi83Rw06eXMZ1moqGp+K3KB7No5Ln/h8/qScYf0N4GBPCsb8P5uLOGgelOv 11 | Z9N+m8RQSGhk761wD4S6vdDCwZvJUxFOWFg6vRU4wBc4/wgdhOi7PqRl1C2z/9Il 12 | gXd4AE0mGlntioCDcrquvQvksBoVqNN4PHdexnKhJptY/i3egnePK+MIcwsCAwEA 13 | AQKCAgEA8tkUZAzYQquPA6ljTPY0L3dFm1q1ewJ1IS2x2NlFJbo36Cx2eRkSm7RV 14 | oPWHP+fyslIughLGy81CKptVYzM5dQ26yrgka/uDasvI5/0ov0vt93POd6Mi6l48 15 | WjhEPeekzSLwcC1zuOTb1lI8WnLAlRMB3JHZzRIgwGYN0QBT3i/AAfTrsMwEYII9 16 | oICQNiVsTDOrJrl4nkQXOXrhgWBz+0FaXwrfJ4trZIyIbRAIOSOMKX6pzPyHWKqC 17 | IRQ25ZgKXiLmPug/vGyeO6ohQSlxBsb8yvTinpqrdRqtdXTtHWl+wk/Ejg21HJRo 18 | hkgdqn6jWYzwnXG6MY7HKNCoGoHxAR+OXP69DrF+GtmNvQGyrovxH9E92PslDAKw 19 | JIeR7npCRYdPnLoU5DJ5tAZhFO6ZAiYxMMHNNKhSt9uNyW7TbcUo9vsU0cGTtYDm 20 | I1XFvN1/rqYsQx7xNIzZLceMAhPu8aGOMw0pDWcj9gWOadot6NGmkULcA5+eCVoj 21 | p9dYgy66jb51JDjfOzbxUgsbeVBGAzl7490J9EyqYDaXNU1JLp0UPfe+VStCbpXE 22 | 3S6wQ2XX0C3NMw0HPVS/FzahBJyv3vndyZJT8x09k2Xn9z/uUDlHjh9CwqG9m9+2 23 | 2cz7M7mmSWGCQIg7G8/m7UI+mR0xHZBNgcFgC8Ukzz+lhKKtCxECggEBAP1BnO/e 24 | i1lHkgYuNiUoM/J9hSU2cZZ+Bg374H5i5RlNojg7p4TlD57mSj2N1Gi5+A3jj6mf 25 | k2YxQHcwhzxr5uGmohd9a4m3lCPJDTerZOqEXkp0qO3+0TnoTz2DUZbxT+zfncwc 26 | JXvlemvHp4IkC8P51WBcqoYqZWp50qUK/6gh82znc8NQtof31388B9GeTFA0T1Nk 27 | wgMvO0T2rT0bEVv/knuRIIWVtGPBKB+b4KIlCdokrozW66p322KfAK+yrdWtyqZo 28 | UJKG62ChVYHaGVMa90l5fFtKPKLpPLqE319uNUb3N1q2tHHaeA8IwR56zNo97QaQ 29 | lIrBa0EOYPkT31cCggEBAPgUVYri/YMV74D5c4nvS2JkZK+ot9i/z+dXj/DXWhcY 30 | WGgm+ACUntN9zKQEBI72aZA39U2N6XVh9e4Br0QmyNjs4e20C2Py5Jqudctq8jZs 31 | J0O7kfR21jeoz8aqwOjt8XDmUf3snQc+mJeenXde+kJu8/OTM5vmO1JNG3WzpMhM 32 | NObchzBVij2B4GCYqPmqYXCwdXa8+iEflu00w2Tc2r3GgY4HcTKUEC+2yZz7O2gQ 33 | aJQGOPl2A9xg7ysmpBmqvoeBB2TO/Hl0ROXTs9fX/Qxiq3Ru53IwAAq0pRQOPhwX 34 | 229D9fuZxHFDJvDu3VWtIeDqggoQ5Le9yW+hGzj2nW0CggEARVRx9wSQV0eNhR2f 35 | evqPhgGwsmg+HjmvxKJAabj/CLdFAmnqSSo/5XsbtdAe5vCKJJs4V/I0ctRm1no1 36 | e2f6k6l/VDjkeJYF+unuMWA9RyonefCH0mdgtZ6QGsHZUx4KiEkLNLY72LgQlHLa 37 | u3jMs8CwFiooEISIsOZasQ3awRdSQWz3Nu/gmEZT+yPe7BaOw6IeWTELH74NVqrE 38 | 8CZ50Rqc6jDnm0pJUMmvB0Av9ZN4J/zEwA+SAl+/cjcfA/pBNm7WPEnwTLycsR5Z 39 | fyvKpQKL0dRtI7yl7t803cbEM6bC9QN2ZuH/ce+h0FPQMlzhuZkcSyDHWVjr2Kps 40 | B6PWDwKCAQAhOkgC5EhkaGm98quBDCYitaOuy4BkbbyhFd9XuOB+O2qL+Lw7B60G 41 | UtE4HrmllGerQ3N9wcZFTKuuB1e8Xx2DwKa6OeVUq9HmzftFFbv/ghj4P4VbIxeq 42 | ONgrme9gw44VOyQ8SJb3w3CYzkv1EymeAFJ4i3zcIshLS7yj1T36/goP6fXJiYuM 43 | lXrCNXBckG+gsmHpV4KBMUP73ZdWSSabSJ1Nsr18ssxAN9FlT1kzpQ781KCI+T+n 44 | Iuyl8PUF4xLF/4hH/llewy3/Qo3SGUHxiL3CSKCDcN5wkKWTvByhkqh3jLjDzGK9 45 | cOskVjobIadqAr8MLhsUaT0z0HZe+Nk5AoIBAQDUd6u36PgRIqdlEmcro2s2BiLQ 46 | u9+BXRs7DyAECffdqGihPukIwKuHGqSVkLIQiiPWF8t+uOwphVPQNkdjvQZ/FL7L 47 | ltpqlpoCwxLN+Cn6SkwAqhqHeGtMEN5OV6pukeb1+zWrJvoEu18WmQcOvj36wv3B 48 | S2XdoyXE36E2xSdb0zjo6YegNC7zT/uGvuwhumzAR5163f3vpLMzxGucWqZQ9OZp 49 | 07yAnrQkwrjALVVIpQuuy7tqV3TpNJZ1k5Pb6Q3ScfKZ0sA6S+dRLqY3Ri2Q3e5S 50 | 7LMNKhSNuCgokdn+IKEnkggoSrNwHyRdfp0F8NwuFVFi/mR/D7D2wbl+WgrN 51 | -----END RSA PRIVATE KEY----- 52 | -------------------------------------------------------------------------------- /tests/circular_reference_gc/UVIdle.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVIdle 3 | --FILE-- 4 | start(function($idle) use(&$count, $idle){ 9 | if($count++ > 10){ 10 | $idle->stop(); 11 | } 12 | }); 13 | $loop->run(); 14 | if($count > 10){ 15 | echo "UVIdle ok"; 16 | } 17 | ?> 18 | --EXPECT-- 19 | UVIdle ok 20 | -------------------------------------------------------------------------------- /tests/circular_reference_gc/UVPipe.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVPipe 3 | --FILE-- 4 | listen($socketName, function($pipe2, $status) use($pipe){ 12 | echo "on connect $status\n"; 13 | var_dump($pipe === $pipe2); 14 | $client = $pipe->accept(); 15 | $client->setCallback(function($clientTest, $data) use($client){ 16 | echo "server recv: $data\n"; 17 | $client->write($data); 18 | }, function($clientTest, $status, $len) use($pipe, $client){ 19 | echo "server write:$len\n"; 20 | $client->shutdown(function($clientTest) use($pipe, $client){ 21 | echo "client shutdown end\n"; 22 | $client->close(); 23 | $pipe->close(); 24 | }); 25 | }, function($clientTest, $status) use($client){ 26 | echo "server recv error\n"; 27 | $client->close(); 28 | 29 | }); 30 | }); 31 | echo "server: {$pipe->getSockname()}\n"; 32 | 33 | $pipe2 = new UVPipe($loop); 34 | $pipe2->connect($socketName, function($pipe2, $status){ 35 | $pipe2->setCallback(function($pipe2Test, $data) use($pipe2){ 36 | echo "Server response: $data\n"; 37 | }, function($pipe2Test, $status, $len) use($pipe2){ 38 | echo "client send $len\n"; 39 | }, function($pipe2Test, $status) use($pipe2){ 40 | echo "client recv error\n"; 41 | $pipe2->close(); 42 | }); 43 | $pipe2->write("client send some data"); 44 | }); 45 | $loop->run(); 46 | ?> 47 | --EXPECT-- 48 | server: uvpipe.test.sock 49 | on connect 0 50 | bool(true) 51 | client send 21 52 | server recv: client send some data 53 | server write:21 54 | client shutdown end 55 | Server response: client send some data 56 | client recv error 57 | -------------------------------------------------------------------------------- /tests/circular_reference_gc/UVResolver.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVResolver 3 | --FILE-- 4 | getnameinfo($rootServerAIP, function($status, $host, $service) use(&$result, $resolver, $rootServerAIP){ 11 | $result[$rootServerAIP] = "$status $host $service"; 12 | }); 13 | $resolver->getaddrinfo($rootServerA, null, function($status, $host) use(&$result, $resolver, $rootServerA){ 14 | $result[$rootServerA] = "$status $host"; 15 | }); 16 | $loop->run(); 17 | echo "{$result[$rootServerAIP]}\n"; 18 | echo "{$result[$rootServerA]}\n"; 19 | ?> 20 | --EXPECT-- 21 | 0 a.root-servers.net 0 22 | 0 198.41.0.4 23 | -------------------------------------------------------------------------------- /tests/circular_reference_gc/UVSSL_01.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVSSL Server 3 | --FILE-- 4 | array( 15 | 'verify_peer' => false, 16 | 'verify_peer_name' => false, 17 | ), 18 | ); 19 | $sslContext = stream_context_create($contextOptions); 20 | $fp = stream_socket_client("ssl://$host:$port", $errno, $errstr, ini_get("default_socket_timeout"), STREAM_CLIENT_CONNECT, $sslContext); 21 | return $fp; 22 | } 23 | if($pid){ 24 | usleep(100000); 25 | $fp = createSSLSocketClient($host, $port); 26 | $randomData = sha1(rand()); 27 | fwrite($fp, $randomData); 28 | Equal($randomData, fread($fp, 1000), "Echo Server"); 29 | fclose($fp); 30 | 31 | $fp = createSSLSocketClient($host, $port); 32 | fclose($fp); 33 | 34 | $fp = createSSLSocketClient($host, $port); 35 | Equal('client closed', $a = fread($fp, 1000), "Client close Trigger"); 36 | fclose($fp); 37 | 38 | $fp = createSSLSocketClient($host, $port); 39 | fwrite($fp, '!close!'); 40 | fclose($fp); 41 | 42 | pcntl_waitpid($pid, $status); 43 | exit; 44 | } 45 | 46 | $loop = new UVLoop(); 47 | $server = new UVSSL($loop); 48 | $server->setCert(file_get_contents(__DIR__."/../cert/server.crt")); 49 | $server->setPrivateKey(file_get_contents(__DIR__."/../cert/server.key")); 50 | $server->clientCloseTriggered = false; 51 | Equal(0, $server->listen($host, $port, function($server) use($server){ 52 | 53 | $client = $server->accept(); 54 | $client->setSSLHandshakeCallback(function($clientTest, $status) use($server, $client){ 55 | if($server->clientCloseTriggered){ 56 | $client->write("client closed"); 57 | $server->clientCloseTriggered = false; 58 | } 59 | return true; 60 | }); 61 | $client->setCallback(function($clientTest, $recv) use($server, $client){ 62 | $client->write($recv); 63 | if($recv == '!close!'){ 64 | $server->close(); 65 | } 66 | }, function($clientTest, $status) use($client){ 67 | $client->close(); 68 | }, function($clientTest) use($server, $client){ 69 | $server->clientCloseTriggered = true; 70 | $client->close(); 71 | }); 72 | 73 | 74 | }), "Server listen"); 75 | $loop->run(); 76 | ?> 77 | --EXPECT-- 78 | Server listen: ok 79 | Echo Server: ok 80 | Client close Trigger: ok 81 | -------------------------------------------------------------------------------- /tests/circular_reference_gc/UVSSL_02.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVSSL Connect 3 | --FILE-- 4 | connect($host, 443, function($ssl) use(&$html){ 10 | $ssl->setSSLHandshakeCallback(function($ssl2, $status) use(&$html, $ssl){ 11 | echo "handshake: ok\n"; 12 | $request = "GET /RickySu/php_ext_uv HTTP/1.0\r\nUser-Agent: UVSSL\r\nAccept: */*\r\nHost: github.com\r\n\r\n"; 13 | $ssl->write($request); 14 | return true; 15 | }); 16 | }); 17 | $ssl->setCallback(function($ssl2, $recv) use(&$html, $ssl){ 18 | $html.=$recv; 19 | }, function($ssl2) use($ssl){ 20 | }, function($ssl2) use(&$html, $ssl){ 21 | if(($pos = strpos($html, "\r\n\r\n")) !== false){ 22 | $header = substr($html, 0, $pos); 23 | preg_match('/Status:\s(\d+)/i', $header, $match); 24 | echo "http status: {$match[1]}\n"; 25 | } 26 | $ssl->close(); 27 | }); 28 | $loop->run(); 29 | ?> 30 | --EXPECT-- 31 | handshake: ok 32 | http status: 200 33 | -------------------------------------------------------------------------------- /tests/circular_reference_gc/UVSignal.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVSignal 3 | --FILE-- 4 | start(function($signal2, $signno) use($signal){ 8 | echo "receive signal\n"; 9 | echo "signal object is "; 10 | var_dump($signal === $signal2); 11 | $signal->stop(); 12 | echo "signal stop"; 13 | }, SIGUSR1); 14 | if($pid = pcntl_fork()){ 15 | $signal->stop(); 16 | posix_kill($pid, SIGUSR1); 17 | pcntl_wait($status); 18 | } 19 | else{ 20 | $loop->run(); 21 | } 22 | ?> 23 | --EXPECT-- 24 | receive signal 25 | signal object is bool(true) 26 | signal stop -------------------------------------------------------------------------------- /tests/circular_reference_gc/UVTcp.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVTcp 3 | --FILE-- 4 | listen('127.0.0.1', 54321, function($tcp2, $status) use($tcp){ 8 | echo "on connect $status\n"; 9 | var_dump($tcp === $tcp2); 10 | $client = $tcp->accept(); 11 | $peerHostPortOK = "{$client->getPeername()}:{$client->getPeerport()}" != ":"; 12 | echo "client connected: $peerHostPortOK\n"; 13 | $client->setCallback(function($clientTest, $data) use($client){ 14 | echo "server recv: $data\n"; 15 | $client->write($data); 16 | }, function($clientTest, $status, $len) use($tcp, $client){ 17 | echo "server write:$len\n"; 18 | $client->shutdown(function($clientTest) use($tcp, $client){ 19 | echo "client shutdown end\n"; 20 | $client->close(); 21 | $tcp->close(); 22 | }); 23 | }, function($clientTest, $status) use($client){ 24 | echo "server recv error\n"; 25 | $client->close(); 26 | 27 | }); 28 | }); 29 | echo "server: {$tcp->getSockname()}:{$tcp->getSockport()}\n"; 30 | 31 | $tcp2 = new UVTcp($loop); 32 | $tcp2->connect('127.0.0.1', 54321, function($tcp2, $status){ 33 | $tcp2->setCallback(function($tcp2Test, $data) use($tcp2){ 34 | echo "Server response: $data\n"; 35 | }, function($tcp2Test, $status, $len) use($tcp2){ 36 | echo "client send $len\n"; 37 | }, function($tcp2Test, $status) use($tcp2){ 38 | echo "client recv error\n"; 39 | $tcp2->close(); 40 | }); 41 | $tcp2->write("client send some data"); 42 | }); 43 | $loop->run(); 44 | ?> 45 | --EXPECT-- 46 | server: 127.0.0.1:54321 47 | on connect 0 48 | bool(true) 49 | client connected: 1 50 | client send 21 51 | server recv: client send some data 52 | server write:21 53 | client shutdown end 54 | Server response: client send some data 55 | client recv error 56 | -------------------------------------------------------------------------------- /tests/circular_reference_gc/UVTimer_01.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVTime once 3 | --FILE-- 4 | start(function($timer) use($timer, $time){ 9 | $timediff = time() - $time; 10 | echo "timer alerm after $timediff secs\n"; 11 | }, 2000); 12 | $loop->run(); 13 | $timer->stop(); 14 | ?> 15 | --EXPECT-- 16 | timer alerm after 2 secs 17 | -------------------------------------------------------------------------------- /tests/circular_reference_gc/UVTimer_02.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVTime repeat 3 | --FILE-- 4 | start(function($timer) use($timer, $time){ 9 | $timediff = time() - $time; 10 | echo "timer alerm after $timediff secs\n"; 11 | if($timediff>=5){ 12 | $timer->stop(); 13 | } 14 | }, 2000, 1000); 15 | $loop->run(); 16 | ?> 17 | --EXPECT-- 18 | timer alerm after 2 secs 19 | timer alerm after 3 secs 20 | timer alerm after 4 secs 21 | timer alerm after 5 secs 22 | -------------------------------------------------------------------------------- /tests/circular_reference_gc/UVUdp.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVUdp 3 | --FILE-- 4 | bind($host, $port); 25 | $setCallbackResult = $server->setCallback( 26 | function ($serverTest, $clientIP, $clientPort, $data, $flag) use($server){ 27 | $server->sendTo($clientIP, $clientPort, $data); 28 | echo "Recv Server "; 29 | var_dump($serverTest === $server); 30 | }, 31 | function ($serverTest, $clientIP, $clientPort, $status) use($server){ 32 | echo "Server Send "; 33 | var_dump($status == 0); 34 | $server->close(); 35 | echo "Send Server "; 36 | var_dump($serverTest === $server); 37 | }, 38 | function ($serverTest) use($server){ 39 | } 40 | ); 41 | 42 | echo "Server Bind: $bindResult\n"; 43 | echo "{$server->getSockname()}:{$server->getSockport()}\n"; 44 | echo "setCallback: $setCallbackResult\n"; 45 | $loop->run(); 46 | ?> 47 | --EXPECT-- 48 | Server Bind: 0 49 | 127.0.0.1:8888 50 | setCallback: 0 51 | Recv Server bool(true) 52 | Server Send bool(true) 53 | Send Server bool(true) 54 | Client Echo Recv bool(true) 55 | -------------------------------------------------------------------------------- /tests/custom_loop/001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for php_ext_uv presence 3 | --FILE-- 4 | 8 | --EXPECT-- 9 | php_ext_uv extension is available -------------------------------------------------------------------------------- /tests/custom_loop/UVIdle.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVIdle 3 | --FILE-- 4 | start(function($idle) use(&$count){ 9 | if($count++ > 10){ 10 | $idle->stop(); 11 | } 12 | }); 13 | $loop->run(); 14 | if($count > 10){ 15 | echo "UVIdle ok"; 16 | } 17 | ?> 18 | --EXPECT-- 19 | UVIdle ok 20 | -------------------------------------------------------------------------------- /tests/custom_loop/UVPipe.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVPipe 3 | --FILE-- 4 | listen($socketName, function($pipe, $status){ 12 | echo "on connect $status\n"; 13 | $client = $pipe->accept(); 14 | $client->setCallback(function($clientTest, $data) use($client){ 15 | echo "server recv: $data\n"; 16 | $client->write($data); 17 | }, function($clientTest, $status, $len) use($pipe, $client){ 18 | echo "server write:$len\n"; 19 | $client->shutdown(function($clientTest) use($pipe, $client){ 20 | echo "client shutdown end\n"; 21 | $client->close(); 22 | $pipe->close(); 23 | }); 24 | }, function($clientTest, $status) use($client){ 25 | echo "server recv error\n"; 26 | $client->close(); 27 | }); 28 | }); 29 | echo "server: {$pipe->getSockname()}\n"; 30 | 31 | $pipe2 = new UVPipe($loop); 32 | $pipe2->connect($socketName, function($pipe2, $status){ 33 | $pipe2->setCallback(function($pipe2Test, $data) use($pipe2){ 34 | echo "Server response: $data\n"; 35 | }, function($pipe2Test, $status, $len) use($pipe2){ 36 | echo "client send $len\n"; 37 | }, function($pipe2Test, $status) use($pipe2){ 38 | echo "client recv error\n"; 39 | $pipe2->close(); 40 | }); 41 | $pipe2->write("client send some data"); 42 | }); 43 | $loop->run(); 44 | ?> 45 | --EXPECT-- 46 | server: uvpipe.test.sock 47 | on connect 0 48 | client send 21 49 | server recv: client send some data 50 | server write:21 51 | client shutdown end 52 | Server response: client send some data 53 | client recv error 54 | -------------------------------------------------------------------------------- /tests/custom_loop/UVResolver.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVResolver 3 | --FILE-- 4 | getnameinfo($rootServerAIP, function($status, $host, $service) use(&$result, $rootServerAIP){ 11 | $result[$rootServerAIP] = "$status $host $service"; 12 | }); 13 | $resolver->getaddrinfo($rootServerA, null, function($status, $host) use(&$result, $rootServerA){ 14 | $result[$rootServerA] = "$status $host"; 15 | }); 16 | $loop->run(); 17 | echo "{$result[$rootServerAIP]}\n"; 18 | echo "{$result[$rootServerA]}\n"; 19 | ?> 20 | --EXPECT-- 21 | 0 a.root-servers.net 0 22 | 0 198.41.0.4 23 | -------------------------------------------------------------------------------- /tests/custom_loop/UVSSL_01.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVSSL Server 3 | --FILE-- 4 | array( 15 | 'verify_peer' => false, 16 | 'verify_peer_name' => false, 17 | ), 18 | ); 19 | $sslContext = stream_context_create($contextOptions); 20 | $fp = stream_socket_client("ssl://$host:$port", $errno, $errstr, ini_get("default_socket_timeout"), STREAM_CLIENT_CONNECT, $sslContext); 21 | return $fp; 22 | } 23 | if($pid){ 24 | usleep(100000); 25 | $fp = createSSLSocketClient($host, $port); 26 | $randomData = sha1(rand()); 27 | fwrite($fp, $randomData); 28 | Equal($randomData, fread($fp, 1000), "Echo Server"); 29 | fclose($fp); 30 | 31 | $fp = createSSLSocketClient($host, $port); 32 | fclose($fp); 33 | 34 | $fp = createSSLSocketClient($host, $port); 35 | Equal('client closed', $a = fread($fp, 1000), "Client close Trigger"); 36 | fclose($fp); 37 | 38 | $fp = createSSLSocketClient($host, $port); 39 | fwrite($fp, '!close!'); 40 | fclose($fp); 41 | 42 | pcntl_waitpid($pid, $status); 43 | exit; 44 | } 45 | 46 | $loop = new UVLoop(); 47 | $server = new UVSSL($loop); 48 | $server->setCert(file_get_contents(__DIR__."/../cert/server.crt")); 49 | $server->setPrivateKey(file_get_contents(__DIR__."/../cert/server.key")); 50 | $server->clientCloseTriggered = false; 51 | Equal(0, $server->listen($host, $port, function($server) { 52 | 53 | $client = $server->accept(); 54 | $client->setSSLHandshakeCallback(function($client, $status) use($server){ 55 | if($server->clientCloseTriggered){ 56 | $client->write("client closed"); 57 | $server->clientCloseTriggered = false; 58 | } 59 | return true; 60 | }); 61 | $client->setCallback(function($client, $recv) use($server){ 62 | $client->write($recv); 63 | if($recv == '!close!'){ 64 | $server->close(); 65 | } 66 | }, function($client, $status){ 67 | $client->close(); 68 | }, function($client) use($server){ 69 | $server->clientCloseTriggered = true; 70 | $client->close(); 71 | }); 72 | 73 | 74 | }), "Server listen"); 75 | $loop->run(); 76 | ?> 77 | --EXPECT-- 78 | Server listen: ok 79 | Echo Server: ok 80 | Client close Trigger: ok 81 | -------------------------------------------------------------------------------- /tests/custom_loop/UVSSL_02.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVSSL Connect 3 | --FILE-- 4 | connect($host, 443, function($ssl) use(&$html){ 10 | $ssl->setSSLHandshakeCallback(function($ssl, $status) use(&$html){ 11 | echo "handshake: ok\n"; 12 | $request = "GET /RickySu/php_ext_uv HTTP/1.0\r\nUser-Agent: UVSSL\r\nAccept: */*\r\nHost: github.com\r\n\r\n"; 13 | $ssl->write($request); 14 | return true; 15 | }); 16 | }); 17 | $ssl->setCallback(function($ssl, $recv) use(&$html){ 18 | $html.=$recv; 19 | }, function(){}, function($ssl) use(&$html){ 20 | if(($pos = strpos($html, "\r\n\r\n")) !== false){ 21 | $header = substr($html, 0, $pos); 22 | preg_match('/Status:\s(\d+)/i', $header, $match); 23 | echo "http status: {$match[1]}\n"; 24 | } 25 | $ssl->close(); 26 | }); 27 | $loop->run(); 28 | ?> 29 | --EXPECT-- 30 | handshake: ok 31 | http status: 200 32 | -------------------------------------------------------------------------------- /tests/custom_loop/UVSignal.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVSignal 3 | --FILE-- 4 | start(function($signal2, $signno) use($signal){ 8 | echo "receive signal\n"; 9 | echo "signal object is "; 10 | var_dump($signal === $signal2); 11 | $signal->stop(); 12 | echo "signal stop"; 13 | }, SIGUSR1); 14 | if($pid = pcntl_fork()){ 15 | $signal->stop(); 16 | posix_kill($pid, SIGUSR1); 17 | pcntl_wait($status); 18 | } 19 | else{ 20 | $loop->run(); 21 | } 22 | ?> 23 | --EXPECT-- 24 | receive signal 25 | signal object is bool(true) 26 | signal stop -------------------------------------------------------------------------------- /tests/custom_loop/UVTcp.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVTcp 3 | --FILE-- 4 | listen('127.0.0.1', 54321, function($tcp2, $status) use($tcp){ 8 | echo "on connect $status\n"; 9 | var_dump($tcp === $tcp2); 10 | $client = $tcp->accept(); 11 | $peerHostPortOK = "{$client->getPeername()}:{$client->getPeerport()}" != ":"; 12 | echo "client connected: $peerHostPortOK\n"; 13 | $client->setCallback(function($client, $data){ 14 | echo "server recv: $data\n"; 15 | $client->write($data); 16 | }, function($client, $status, $len) use($tcp){ 17 | echo "server write:$len\n"; 18 | $client->shutdown(function($client) use($tcp){ 19 | echo "client shutdown end\n"; 20 | $client->close(); 21 | $tcp->close(); 22 | }); 23 | }, function($client, $status){ 24 | echo "server recv error\n"; 25 | $client->close(); 26 | 27 | }); 28 | }); 29 | echo "server: {$tcp->getSockname()}:{$tcp->getSockport()}\n"; 30 | 31 | $tcp2 = new UVTcp($loop); 32 | $tcp2->connect('127.0.0.1', 54321, function($tcp2, $status){ 33 | $tcp2->setCallback(function($tcp2, $data){ 34 | echo "Server response: $data\n"; 35 | }, function($tcp2, $status, $len){ 36 | echo "client send $len\n"; 37 | }, function($tcp2, $status){ 38 | echo "client recv error\n"; 39 | $tcp2->close(); 40 | }); 41 | $tcp2->write("client send some data"); 42 | }); 43 | $loop->run(); 44 | ?> 45 | --EXPECT-- 46 | server: 127.0.0.1:54321 47 | on connect 0 48 | bool(true) 49 | client connected: 1 50 | client send 21 51 | server recv: client send some data 52 | server write:21 53 | client shutdown end 54 | Server response: client send some data 55 | client recv error 56 | -------------------------------------------------------------------------------- /tests/custom_loop/UVTimer_01.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVTime once 3 | --FILE-- 4 | start(function($timer2) use($timer, $time){ 9 | $timediff = time() - $time; 10 | echo "timer alerm after $timediff secs\n"; 11 | echo "timer object is "; 12 | var_dump($timer === $timer2); 13 | }, 2000); 14 | $loop->run(); 15 | $timer->stop(); 16 | ?> 17 | --EXPECT-- 18 | timer alerm after 2 secs 19 | timer object is bool(true) -------------------------------------------------------------------------------- /tests/custom_loop/UVTimer_02.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVTime repeat 3 | --FILE-- 4 | start(function($timer2) use($timer, $time){ 9 | $timediff = time() - $time; 10 | echo "timer alerm after $timediff secs\n"; 11 | if($timediff>=5){ 12 | $timer->stop(); 13 | } 14 | }, 2000, 1000); 15 | $loop->run(); 16 | ?> 17 | --EXPECT-- 18 | timer alerm after 2 secs 19 | timer alerm after 3 secs 20 | timer alerm after 4 secs 21 | timer alerm after 5 secs 22 | -------------------------------------------------------------------------------- /tests/custom_loop/UVUdp.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVUdp 3 | --FILE-- 4 | sendTo($clientIP, $clientPort, $data); 24 | } 25 | 26 | function sendCallback($server, $clientIP, $clientPort, $status){ 27 | echo "Server Send "; 28 | var_dump($status == 0); 29 | $server->close(); 30 | } 31 | 32 | function errorCallback(){ 33 | } 34 | 35 | $loop = new UVLoop(); 36 | $server = new UVUdp($loop); 37 | echo "Server Bind: {$server->bind($host, $port)}\n"; 38 | echo "{$server->getSockname()}:{$server->getSockport()}\n"; 39 | echo "setCallback: {$server->setCallback('recvCallback', 'sendCallback', 'errorCallback')}\n"; 40 | $loop->run(); 41 | ?> 42 | --EXPECT-- 43 | Server Bind: 0 44 | 127.0.0.1:8888 45 | setCallback: 0 46 | Server Send bool(true) 47 | Client Echo Recv bool(true) 48 | -------------------------------------------------------------------------------- /tests/default_loop/UVIdle.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVIdle 3 | --FILE-- 4 | start(function($idle) use(&$count){ 9 | if($count++ > 10){ 10 | $idle->stop(); 11 | } 12 | }); 13 | $loop->run(); 14 | if($count > 10){ 15 | echo "UVIdle ok"; 16 | } 17 | ?> 18 | --EXPECT-- 19 | UVIdle ok 20 | -------------------------------------------------------------------------------- /tests/default_loop/UVLoopSingleton.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVLoop Singleton 3 | --FILE-- 4 | 8 | --EXPECT-- 9 | UVLoop ok -------------------------------------------------------------------------------- /tests/default_loop/UVPipe.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVPipe 3 | --FILE-- 4 | listen($socketName, function($pipe, $status){ 12 | echo "on connect $status\n"; 13 | $client = $pipe->accept(); 14 | $client->setCallback(function($clientTest, $data) use($client){ 15 | echo "server recv: $data\n"; 16 | $client->write($data); 17 | }, function($clientTest, $status, $len) use($pipe, $client){ 18 | echo "server write:$len\n"; 19 | $client->shutdown(function($clientTest) use($pipe, $client){ 20 | echo "client shutdown end\n"; 21 | $client->close(); 22 | $pipe->close(); 23 | }); 24 | }, function($clientTest, $status) use($client){ 25 | echo "server recv error\n"; 26 | $client->close(); 27 | }); 28 | }); 29 | echo "server: {$pipe->getSockname()}\n"; 30 | 31 | $pipe2 = new UVPipe($loop); 32 | $pipe2->connect($socketName, function($pipe2, $status){ 33 | $pipe2->setCallback(function($pipe2Test, $data) use($pipe2){ 34 | echo "Server response: $data\n"; 35 | }, function($pipe2Test, $status, $len) use($pipe2){ 36 | echo "client send $len\n"; 37 | }, function($pipe2Test, $status) use($pipe2){ 38 | echo "client recv error\n"; 39 | $pipe2->close(); 40 | }); 41 | $pipe2->write("client send some data"); 42 | }); 43 | $loop->run(); 44 | ?> 45 | --EXPECT-- 46 | server: uvpipe.test.sock 47 | on connect 0 48 | client send 21 49 | server recv: client send some data 50 | server write:21 51 | client shutdown end 52 | Server response: client send some data 53 | client recv error 54 | -------------------------------------------------------------------------------- /tests/default_loop/UVResolver.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVResolver 3 | --FILE-- 4 | getnameinfo($rootServerAIP, function($status, $host, $service) use(&$result, $rootServerAIP){ 11 | $result[$rootServerAIP] = "$status $host $service"; 12 | }); 13 | $resolver->getaddrinfo($rootServerA, null, function($status, $host) use(&$result, $rootServerA){ 14 | $result[$rootServerA] = "$status $host"; 15 | }); 16 | $loop->run(); 17 | echo "{$result[$rootServerAIP]}\n"; 18 | echo "{$result[$rootServerA]}\n"; 19 | ?> 20 | --EXPECT-- 21 | 0 a.root-servers.net 0 22 | 0 198.41.0.4 23 | -------------------------------------------------------------------------------- /tests/default_loop/UVSSL_01.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVSSL Server 3 | --FILE-- 4 | array( 15 | 'verify_peer' => false, 16 | 'verify_peer_name' => false, 17 | ), 18 | ); 19 | $sslContext = stream_context_create($contextOptions); 20 | $fp = stream_socket_client("ssl://$host:$port", $errno, $errstr, ini_get("default_socket_timeout"), STREAM_CLIENT_CONNECT, $sslContext); 21 | return $fp; 22 | } 23 | if($pid){ 24 | usleep(100000); 25 | $fp = createSSLSocketClient($host, $port); 26 | $randomData = sha1(rand()); 27 | fwrite($fp, $randomData); 28 | Equal($randomData, fread($fp, 1000), "Echo Server"); 29 | fclose($fp); 30 | 31 | $fp = createSSLSocketClient($host, $port); 32 | fclose($fp); 33 | 34 | $fp = createSSLSocketClient($host, $port); 35 | Equal('client closed', $a = fread($fp, 1000), "Client close Trigger"); 36 | fclose($fp); 37 | 38 | $fp = createSSLSocketClient($host, $port); 39 | fwrite($fp, '!close!'); 40 | fclose($fp); 41 | 42 | pcntl_waitpid($pid, $status); 43 | exit; 44 | } 45 | 46 | $loop = UVLoop::defaultLoop(); 47 | $server = new UVSSL($loop); 48 | $server->setCert(file_get_contents(__DIR__."/../cert/server.crt")); 49 | $server->setPrivateKey(file_get_contents(__DIR__."/../cert/server.key")); 50 | $server->clientCloseTriggered = false; 51 | Equal(0, $server->listen($host, $port, function($server) { 52 | 53 | $client = $server->accept(); 54 | $client->setSSLHandshakeCallback(function($client, $status) use($server){ 55 | if($server->clientCloseTriggered){ 56 | $client->write("client closed"); 57 | $server->clientCloseTriggered = false; 58 | } 59 | return true; 60 | }); 61 | $client->setCallback(function($client, $recv) use($server){ 62 | $client->write($recv); 63 | if($recv == '!close!'){ 64 | $server->close(); 65 | } 66 | }, function($client, $status){ 67 | $client->close(); 68 | }, function($client) use($server){ 69 | $server->clientCloseTriggered = true; 70 | $client->close(); 71 | }); 72 | 73 | 74 | }), "Server listen"); 75 | $loop->run(); 76 | ?> 77 | --EXPECT-- 78 | Server listen: ok 79 | Echo Server: ok 80 | Client close Trigger: ok 81 | -------------------------------------------------------------------------------- /tests/default_loop/UVSSL_02.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVSSL Connect 3 | --FILE-- 4 | connect($host, 443, function($ssl) use(&$html){ 10 | $ssl->setSSLHandshakeCallback(function($ssl, $status) use(&$html){ 11 | echo "handshake: ok\n"; 12 | $request = "GET /RickySu/php_ext_uv HTTP/1.0\r\nUser-Agent: UVSSL\r\nAccept: */*\r\nHost: github.com\r\n\r\n"; 13 | $ssl->write($request); 14 | return true; 15 | }); 16 | }); 17 | $ssl->setCallback(function($ssl, $recv) use(&$html){ 18 | $html.=$recv; 19 | }, function(){}, function($ssl) use(&$html){ 20 | if(($pos = strpos($html, "\r\n\r\n")) !== false){ 21 | $header = substr($html, 0, $pos); 22 | preg_match('/Status:\s(\d+)/i', $header, $match); 23 | echo "http status: {$match[1]}\n"; 24 | } 25 | $ssl->close(); 26 | }); 27 | $loop->run(); 28 | ?> 29 | --EXPECT-- 30 | handshake: ok 31 | http status: 200 32 | -------------------------------------------------------------------------------- /tests/default_loop/UVSignal.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVSignal 3 | --FILE-- 4 | start(function($signal2, $signno) use($signal){ 8 | echo "receive signal\n"; 9 | echo "signal object is "; 10 | var_dump($signal === $signal2); 11 | $signal->stop(); 12 | echo "signal stop"; 13 | }, SIGUSR1); 14 | if($pid = pcntl_fork()){ 15 | $signal->stop(); 16 | posix_kill($pid, SIGUSR1); 17 | pcntl_wait($status); 18 | } 19 | else{ 20 | $loop->run(); 21 | } 22 | ?> 23 | --EXPECT-- 24 | receive signal 25 | signal object is bool(true) 26 | signal stop -------------------------------------------------------------------------------- /tests/default_loop/UVTcp.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVTcp 3 | --FILE-- 4 | listen('127.0.0.1', 54321, function($tcp2, $status) use($tcp){ 8 | echo "on connect $status\n"; 9 | var_dump($tcp === $tcp2); 10 | $client = $tcp->accept(); 11 | $peerHostPortOK = "{$client->getPeername()}:{$client->getPeerport()}" != ":"; 12 | echo "client connected: $peerHostPortOK\n"; 13 | $client->setCallback(function($client, $data){ 14 | echo "server recv: $data\n"; 15 | $client->write($data); 16 | }, function($client, $status, $len) use($tcp){ 17 | echo "server write:$len\n"; 18 | $client->shutdown(function($client) use($tcp){ 19 | echo "client shutdown end\n"; 20 | $client->close(); 21 | $tcp->close(); 22 | }); 23 | }, function($client, $status){ 24 | echo "server recv error\n"; 25 | $client->close(); 26 | 27 | }); 28 | }); 29 | echo "server: {$tcp->getSockname()}:{$tcp->getSockport()}\n"; 30 | 31 | $tcp2 = new UVTcp($loop); 32 | $tcp2->connect('127.0.0.1', 54321, function($tcp2, $status){ 33 | $tcp2->setCallback(function($tcp2, $data){ 34 | echo "Server response: $data\n"; 35 | }, function($tcp2, $status, $len){ 36 | echo "client send $len\n"; 37 | }, function($tcp2, $status){ 38 | echo "client recv error\n"; 39 | $tcp2->close(); 40 | }); 41 | $tcp2->write("client send some data"); 42 | }); 43 | $loop->run(); 44 | ?> 45 | --EXPECT-- 46 | server: 127.0.0.1:54321 47 | on connect 0 48 | bool(true) 49 | client connected: 1 50 | client send 21 51 | server recv: client send some data 52 | server write:21 53 | client shutdown end 54 | Server response: client send some data 55 | client recv error 56 | -------------------------------------------------------------------------------- /tests/default_loop/UVTimer_01.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVTime once 3 | --FILE-- 4 | start(function($timer2) use($timer, $time){ 9 | $timediff = time() - $time; 10 | echo "timer alerm after $timediff secs\n"; 11 | echo "timer object is "; 12 | var_dump($timer === $timer2); 13 | }, 2000); 14 | $loop->run(); 15 | $timer->stop(); 16 | ?> 17 | --EXPECT-- 18 | timer alerm after 2 secs 19 | timer object is bool(true) -------------------------------------------------------------------------------- /tests/default_loop/UVTimer_02.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVTime repeat 3 | --FILE-- 4 | start(function($timer2) use($timer, $time){ 9 | $timediff = time() - $time; 10 | echo "timer alerm after $timediff secs\n"; 11 | if($timediff>=5){ 12 | $timer->stop(); 13 | } 14 | }, 2000, 1000); 15 | $loop->run(); 16 | ?> 17 | --EXPECT-- 18 | timer alerm after 2 secs 19 | timer alerm after 3 secs 20 | timer alerm after 4 secs 21 | timer alerm after 5 secs 22 | -------------------------------------------------------------------------------- /tests/default_loop/UVUdp.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVUdp 3 | --FILE-- 4 | sendTo($clientIP, $clientPort, $data); 24 | } 25 | 26 | function sendCallback($server, $clientIP, $clientPort, $status){ 27 | echo "Server Send "; 28 | var_dump($status == 0); 29 | $server->close(); 30 | } 31 | 32 | function errorCallback(){ 33 | } 34 | 35 | $loop = UVLoop::defaultLoop(); 36 | $server = new UVUdp($loop); 37 | echo "Server Bind: {$server->bind($host, $port)}\n"; 38 | echo "{$server->getSockname()}:{$server->getSockport()}\n"; 39 | echo "setCallback: {$server->setCallback('recvCallback', 'sendCallback', 'errorCallback')}\n"; 40 | $loop->run(); 41 | ?> 42 | --EXPECT-- 43 | Server Bind: 0 44 | 127.0.0.1:8888 45 | setCallback: 0 46 | Server Send bool(true) 47 | Client Echo Recv bool(true) 48 | -------------------------------------------------------------------------------- /tests/default_loop_empty/UVIdle.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVIdle 3 | --FILE-- 4 | start(function($idle) use(&$count){ 9 | if($count++ > 10){ 10 | $idle->stop(); 11 | } 12 | }); 13 | $loop->run(); 14 | if($count > 10){ 15 | echo "UVIdle ok"; 16 | } 17 | ?> 18 | --EXPECT-- 19 | UVIdle ok 20 | -------------------------------------------------------------------------------- /tests/default_loop_empty/UVPipe.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVPipe 3 | --FILE-- 4 | listen($socketName, function($pipe, $status){ 12 | echo "on connect $status\n"; 13 | $client = $pipe->accept(); 14 | $client->setCallback(function($clientTest, $data) use($client){ 15 | echo "server recv: $data\n"; 16 | $client->write($data); 17 | }, function($clientTest, $status, $len) use($pipe, $client){ 18 | echo "server write:$len\n"; 19 | $client->shutdown(function($clientTest) use($pipe, $client){ 20 | echo "client shutdown end\n"; 21 | $client->close(); 22 | $pipe->close(); 23 | }); 24 | }, function($clientTest, $status) use($client){ 25 | echo "server recv error\n"; 26 | $client->close(); 27 | }); 28 | }); 29 | echo "server: {$pipe->getSockname()}\n"; 30 | 31 | $pipe2 = new UVPipe($loop); 32 | $pipe2->connect($socketName, function($pipe2, $status){ 33 | $pipe2->setCallback(function($pipe2Test, $data) use($pipe2){ 34 | echo "Server response: $data\n"; 35 | }, function($pipe2Test, $status, $len) use($pipe2){ 36 | echo "client send $len\n"; 37 | }, function($pipe2Test, $status) use($pipe2){ 38 | echo "client recv error\n"; 39 | $pipe2->close(); 40 | }); 41 | $pipe2->write("client send some data"); 42 | }); 43 | $loop->run(); 44 | ?> 45 | --EXPECT-- 46 | server: uvpipe.test.sock 47 | on connect 0 48 | client send 21 49 | server recv: client send some data 50 | server write:21 51 | client shutdown end 52 | Server response: client send some data 53 | client recv error 54 | -------------------------------------------------------------------------------- /tests/default_loop_empty/UVResolver.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVResolver 3 | --FILE-- 4 | getnameinfo($rootServerAIP, function($status, $host, $service) use(&$result, $rootServerAIP){ 11 | $result[$rootServerAIP] = "$status $host $service"; 12 | }); 13 | $resolver->getaddrinfo($rootServerA, null, function($status, $host) use(&$result, $rootServerA){ 14 | $result[$rootServerA] = "$status $host"; 15 | }); 16 | $loop->run(); 17 | echo "{$result[$rootServerAIP]}\n"; 18 | echo "{$result[$rootServerA]}\n"; 19 | ?> 20 | --EXPECT-- 21 | 0 a.root-servers.net 0 22 | 0 198.41.0.4 23 | -------------------------------------------------------------------------------- /tests/default_loop_empty/UVSSL_01.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVSSL Server 3 | --FILE-- 4 | array( 15 | 'verify_peer' => false, 16 | 'verify_peer_name' => false, 17 | ), 18 | ); 19 | $sslContext = stream_context_create($contextOptions); 20 | $fp = stream_socket_client("ssl://$host:$port", $errno, $errstr, ini_get("default_socket_timeout"), STREAM_CLIENT_CONNECT, $sslContext); 21 | return $fp; 22 | } 23 | if($pid){ 24 | usleep(100000); 25 | $fp = createSSLSocketClient($host, $port); 26 | $randomData = sha1(rand()); 27 | fwrite($fp, $randomData); 28 | Equal($randomData, fread($fp, 1000), "Echo Server"); 29 | fclose($fp); 30 | 31 | $fp = createSSLSocketClient($host, $port); 32 | fclose($fp); 33 | 34 | $fp = createSSLSocketClient($host, $port); 35 | Equal('client closed', $a = fread($fp, 1000), "Client close Trigger"); 36 | fclose($fp); 37 | 38 | $fp = createSSLSocketClient($host, $port); 39 | fwrite($fp, '!close!'); 40 | fclose($fp); 41 | 42 | pcntl_waitpid($pid, $status); 43 | exit; 44 | } 45 | 46 | $loop = UVLoop::defaultLoop(); 47 | $server = new UVSSL(); 48 | $server->setCert(file_get_contents(__DIR__."/../cert/server.crt")); 49 | $server->setPrivateKey(file_get_contents(__DIR__."/../cert/server.key")); 50 | $server->clientCloseTriggered = false; 51 | Equal(0, $server->listen($host, $port, function($server) { 52 | 53 | $client = $server->accept(); 54 | $client->setSSLHandshakeCallback(function($client, $status) use($server){ 55 | if($server->clientCloseTriggered){ 56 | $client->write("client closed"); 57 | $server->clientCloseTriggered = false; 58 | } 59 | return true; 60 | }); 61 | $client->setCallback(function($client, $recv) use($server){ 62 | $client->write($recv); 63 | if($recv == '!close!'){ 64 | $server->close(); 65 | } 66 | }, function($client, $status){ 67 | $client->close(); 68 | }, function($client) use($server){ 69 | $server->clientCloseTriggered = true; 70 | $client->close(); 71 | }); 72 | 73 | 74 | }), "Server listen"); 75 | $loop->run(); 76 | ?> 77 | --EXPECT-- 78 | Server listen: ok 79 | Echo Server: ok 80 | Client close Trigger: ok 81 | -------------------------------------------------------------------------------- /tests/default_loop_empty/UVSSL_02.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVSSL Connect 3 | --FILE-- 4 | connect($host, 443, function($ssl) use(&$html){ 10 | $ssl->setSSLHandshakeCallback(function($ssl, $status) use(&$html){ 11 | echo "handshake: ok\n"; 12 | $request = "GET /RickySu/php_ext_uv HTTP/1.0\r\nUser-Agent: UVSSL\r\nAccept: */*\r\nHost: github.com\r\n\r\n"; 13 | $ssl->write($request); 14 | return true; 15 | }); 16 | }); 17 | $ssl->setCallback(function($ssl, $recv) use(&$html){ 18 | $html.=$recv; 19 | }, function(){}, function($ssl) use(&$html){ 20 | if(($pos = strpos($html, "\r\n\r\n")) !== false){ 21 | $header = substr($html, 0, $pos); 22 | preg_match('/Status:\s(\d+)/i', $header, $match); 23 | echo "http status: {$match[1]}\n"; 24 | } 25 | $ssl->close(); 26 | }); 27 | $loop->run(); 28 | ?> 29 | --EXPECT-- 30 | handshake: ok 31 | http status: 200 32 | -------------------------------------------------------------------------------- /tests/default_loop_empty/UVSignal.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVSignal 3 | --FILE-- 4 | start(function($signal2, $signno) use($signal){ 8 | echo "receive signal\n"; 9 | echo "signal object is "; 10 | var_dump($signal === $signal2); 11 | $signal->stop(); 12 | echo "signal stop"; 13 | }, SIGUSR1); 14 | if($pid = pcntl_fork()){ 15 | $signal->stop(); 16 | posix_kill($pid, SIGUSR1); 17 | pcntl_wait($status); 18 | } 19 | else{ 20 | $loop->run(); 21 | } 22 | ?> 23 | --EXPECT-- 24 | receive signal 25 | signal object is bool(true) 26 | signal stop -------------------------------------------------------------------------------- /tests/default_loop_empty/UVTcp.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVTcp 3 | --FILE-- 4 | listen('127.0.0.1', 54321, function($tcp2, $status) use($tcp){ 8 | echo "on connect $status\n"; 9 | var_dump($tcp === $tcp2); 10 | $client = $tcp->accept(); 11 | $peerHostPortOK = "{$client->getPeername()}:{$client->getPeerport()}" != ":"; 12 | echo "client connected: $peerHostPortOK\n"; 13 | $client->setCallback(function($client, $data){ 14 | echo "server recv: $data\n"; 15 | $client->write($data); 16 | }, function($client, $status, $len) use($tcp){ 17 | echo "server write:$len\n"; 18 | $client->shutdown(function($client) use($tcp){ 19 | echo "client shutdown end\n"; 20 | $client->close(); 21 | $tcp->close(); 22 | }); 23 | }, function($client, $status){ 24 | echo "server recv error\n"; 25 | $client->close(); 26 | 27 | }); 28 | }); 29 | echo "server: {$tcp->getSockname()}:{$tcp->getSockport()}\n"; 30 | 31 | $tcp2 = new UVTcp(); 32 | $tcp2->connect('127.0.0.1', 54321, function($tcp2, $status){ 33 | $tcp2->setCallback(function($tcp2, $data){ 34 | echo "Server response: $data\n"; 35 | }, function($tcp2, $status, $len){ 36 | echo "client send $len\n"; 37 | }, function($tcp2, $status){ 38 | echo "client recv error\n"; 39 | $tcp2->close(); 40 | }); 41 | $tcp2->write("client send some data"); 42 | }); 43 | $loop->run(); 44 | ?> 45 | --EXPECT-- 46 | server: 127.0.0.1:54321 47 | on connect 0 48 | bool(true) 49 | client connected: 1 50 | client send 21 51 | server recv: client send some data 52 | server write:21 53 | client shutdown end 54 | Server response: client send some data 55 | client recv error 56 | -------------------------------------------------------------------------------- /tests/default_loop_empty/UVTimer_01.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVTime once 3 | --FILE-- 4 | start(function($timer2) use($timer, $time){ 9 | $timediff = time() - $time; 10 | echo "timer alerm after $timediff secs\n"; 11 | echo "timer object is "; 12 | var_dump($timer === $timer2); 13 | }, 2000); 14 | $loop->run(); 15 | $timer->stop(); 16 | ?> 17 | --EXPECT-- 18 | timer alerm after 2 secs 19 | timer object is bool(true) -------------------------------------------------------------------------------- /tests/default_loop_empty/UVTimer_02.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVTime repeat 3 | --FILE-- 4 | start(function($timer2) use($timer, $time){ 9 | $timediff = time() - $time; 10 | echo "timer alerm after $timediff secs\n"; 11 | if($timediff>=5){ 12 | $timer->stop(); 13 | } 14 | }, 2000, 1000); 15 | $loop->run(); 16 | ?> 17 | --EXPECT-- 18 | timer alerm after 2 secs 19 | timer alerm after 3 secs 20 | timer alerm after 4 secs 21 | timer alerm after 5 secs 22 | -------------------------------------------------------------------------------- /tests/default_loop_empty/UVUdp.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVUdp 3 | --FILE-- 4 | sendTo($clientIP, $clientPort, $data); 24 | } 25 | 26 | function sendCallback($server, $clientIP, $clientPort, $status){ 27 | echo "Server Send "; 28 | var_dump($status == 0); 29 | $server->close(); 30 | } 31 | 32 | function errorCallback(){ 33 | } 34 | 35 | $loop = UVLoop::defaultLoop(); 36 | $server = new UVUdp(); 37 | echo "Server Bind: {$server->bind($host, $port)}\n"; 38 | echo "{$server->getSockname()}:{$server->getSockport()}\n"; 39 | echo "setCallback: {$server->setCallback('recvCallback', 'sendCallback', 'errorCallback')}\n"; 40 | $loop->run(); 41 | ?> 42 | --EXPECT-- 43 | Server Bind: 0 44 | 127.0.0.1:8888 45 | setCallback: 0 46 | Server Send bool(true) 47 | Client Echo Recv bool(true) 48 | -------------------------------------------------------------------------------- /tests/default_loop_null/UVIdle.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVIdle 3 | --FILE-- 4 | start(function($idle) use(&$count){ 9 | if($count++ > 10){ 10 | $idle->stop(); 11 | } 12 | }); 13 | $loop->run(); 14 | if($count > 10){ 15 | echo "UVIdle ok"; 16 | } 17 | ?> 18 | --EXPECT-- 19 | UVIdle ok 20 | -------------------------------------------------------------------------------- /tests/default_loop_null/UVPipe.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVPipe 3 | --FILE-- 4 | listen($socketName, function($pipe, $status){ 12 | echo "on connect $status\n"; 13 | $client = $pipe->accept(); 14 | $client->setCallback(function($clientTest, $data) use($client){ 15 | echo "server recv: $data\n"; 16 | $client->write($data); 17 | }, function($clientTest, $status, $len) use($pipe, $client){ 18 | echo "server write:$len\n"; 19 | $client->shutdown(function($clientTest) use($pipe, $client){ 20 | echo "client shutdown end\n"; 21 | $client->close(); 22 | $pipe->close(); 23 | }); 24 | }, function($clientTest, $status) use($client){ 25 | echo "server recv error\n"; 26 | $client->close(); 27 | }); 28 | }); 29 | echo "server: {$pipe->getSockname()}\n"; 30 | 31 | $pipe2 = new UVPipe($loop); 32 | $pipe2->connect($socketName, function($pipe2, $status){ 33 | $pipe2->setCallback(function($pipe2Test, $data) use($pipe2){ 34 | echo "Server response: $data\n"; 35 | }, function($pipe2Test, $status, $len) use($pipe2){ 36 | echo "client send $len\n"; 37 | }, function($pipe2Test, $status) use($pipe2){ 38 | echo "client recv error\n"; 39 | $pipe2->close(); 40 | }); 41 | $pipe2->write("client send some data"); 42 | }); 43 | $loop->run(); 44 | ?> 45 | --EXPECT-- 46 | server: uvpipe.test.sock 47 | on connect 0 48 | client send 21 49 | server recv: client send some data 50 | server write:21 51 | client shutdown end 52 | Server response: client send some data 53 | client recv error 54 | -------------------------------------------------------------------------------- /tests/default_loop_null/UVResolver.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVResolver 3 | --FILE-- 4 | getnameinfo($rootServerAIP, function($status, $host, $service) use(&$result, $rootServerAIP){ 11 | $result[$rootServerAIP] = "$status $host $service"; 12 | }); 13 | $resolver->getaddrinfo($rootServerA, null, function($status, $host) use(&$result, $rootServerA){ 14 | $result[$rootServerA] = "$status $host"; 15 | }); 16 | $loop->run(); 17 | echo "{$result[$rootServerAIP]}\n"; 18 | echo "{$result[$rootServerA]}\n"; 19 | ?> 20 | --EXPECT-- 21 | 0 a.root-servers.net 0 22 | 0 198.41.0.4 23 | -------------------------------------------------------------------------------- /tests/default_loop_null/UVSSL_01.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVSSL Server 3 | --FILE-- 4 | array( 15 | 'verify_peer' => false, 16 | 'verify_peer_name' => false, 17 | ), 18 | ); 19 | $sslContext = stream_context_create($contextOptions); 20 | $fp = stream_socket_client("ssl://$host:$port", $errno, $errstr, ini_get("default_socket_timeout"), STREAM_CLIENT_CONNECT, $sslContext); 21 | return $fp; 22 | } 23 | if($pid){ 24 | usleep(100000); 25 | $fp = createSSLSocketClient($host, $port); 26 | $randomData = sha1(rand()); 27 | fwrite($fp, $randomData); 28 | Equal($randomData, fread($fp, 1000), "Echo Server"); 29 | fclose($fp); 30 | 31 | $fp = createSSLSocketClient($host, $port); 32 | fclose($fp); 33 | 34 | $fp = createSSLSocketClient($host, $port); 35 | Equal('client closed', $a = fread($fp, 1000), "Client close Trigger"); 36 | fclose($fp); 37 | 38 | $fp = createSSLSocketClient($host, $port); 39 | fwrite($fp, '!close!'); 40 | fclose($fp); 41 | 42 | pcntl_waitpid($pid, $status); 43 | exit; 44 | } 45 | 46 | $loop = UVLoop::defaultLoop(); 47 | $server = new UVSSL(null); 48 | $server->setCert(file_get_contents(__DIR__."/../cert/server.crt")); 49 | $server->setPrivateKey(file_get_contents(__DIR__."/../cert/server.key")); 50 | $server->clientCloseTriggered = false; 51 | Equal(0, $server->listen($host, $port, function($server) { 52 | 53 | $client = $server->accept(); 54 | $client->setSSLHandshakeCallback(function($client, $status) use($server){ 55 | if($server->clientCloseTriggered){ 56 | $client->write("client closed"); 57 | $server->clientCloseTriggered = false; 58 | } 59 | return true; 60 | }); 61 | $client->setCallback(function($client, $recv) use($server){ 62 | $client->write($recv); 63 | if($recv == '!close!'){ 64 | $server->close(); 65 | } 66 | }, function($client, $status){ 67 | $client->close(); 68 | }, function($client) use($server){ 69 | $server->clientCloseTriggered = true; 70 | $client->close(); 71 | }); 72 | 73 | 74 | }), "Server listen"); 75 | $loop->run(); 76 | ?> 77 | --EXPECT-- 78 | Server listen: ok 79 | Echo Server: ok 80 | Client close Trigger: ok 81 | -------------------------------------------------------------------------------- /tests/default_loop_null/UVSSL_02.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVSSL Connect 3 | --FILE-- 4 | connect($host, 443, function($ssl) use(&$html){ 10 | $ssl->setSSLHandshakeCallback(function($ssl, $status) use(&$html){ 11 | echo "handshake: ok\n"; 12 | $request = "GET /RickySu/php_ext_uv HTTP/1.0\r\nUser-Agent: UVSSL\r\nAccept: */*\r\nHost: github.com\r\n\r\n"; 13 | $ssl->write($request); 14 | return true; 15 | }); 16 | }); 17 | $ssl->setCallback(function($ssl, $recv) use(&$html){ 18 | $html.=$recv; 19 | }, function(){}, function($ssl) use(&$html){ 20 | if(($pos = strpos($html, "\r\n\r\n")) !== false){ 21 | $header = substr($html, 0, $pos); 22 | preg_match('/Status:\s(\d+)/i', $header, $match); 23 | echo "http status: {$match[1]}\n"; 24 | } 25 | $ssl->close(); 26 | }); 27 | $loop->run(); 28 | ?> 29 | --EXPECT-- 30 | handshake: ok 31 | http status: 200 32 | -------------------------------------------------------------------------------- /tests/default_loop_null/UVSignal.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVSignal 3 | --FILE-- 4 | start(function($signal2, $signno) use($signal){ 8 | echo "receive signal\n"; 9 | echo "signal object is "; 10 | var_dump($signal === $signal2); 11 | $signal->stop(); 12 | echo "signal stop"; 13 | }, SIGUSR1); 14 | if($pid = pcntl_fork()){ 15 | $signal->stop(); 16 | posix_kill($pid, SIGUSR1); 17 | pcntl_wait($status); 18 | } 19 | else{ 20 | $loop->run(); 21 | } 22 | ?> 23 | --EXPECT-- 24 | receive signal 25 | signal object is bool(true) 26 | signal stop -------------------------------------------------------------------------------- /tests/default_loop_null/UVTcp.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVTcp 3 | --FILE-- 4 | listen('127.0.0.1', 54321, function($tcp2, $status) use($tcp){ 8 | echo "on connect $status\n"; 9 | var_dump($tcp === $tcp2); 10 | $client = $tcp->accept(); 11 | $peerHostPortOK = "{$client->getPeername()}:{$client->getPeerport()}" != ":"; 12 | echo "client connected: $peerHostPortOK\n"; 13 | $client->setCallback(function($client, $data){ 14 | echo "server recv: $data\n"; 15 | $client->write($data); 16 | }, function($client, $status, $len) use($tcp){ 17 | echo "server write:$len\n"; 18 | $client->shutdown(function($client) use($tcp){ 19 | echo "client shutdown end\n"; 20 | $client->close(); 21 | $tcp->close(); 22 | }); 23 | }, function($client, $status){ 24 | echo "server recv error\n"; 25 | $client->close(); 26 | 27 | }); 28 | }); 29 | echo "server: {$tcp->getSockname()}:{$tcp->getSockport()}\n"; 30 | 31 | $tcp2 = new UVTcp(null); 32 | $tcp2->connect('127.0.0.1', 54321, function($tcp2, $status){ 33 | $tcp2->setCallback(function($tcp2, $data){ 34 | echo "Server response: $data\n"; 35 | }, function($tcp2, $status, $len){ 36 | echo "client send $len\n"; 37 | }, function($tcp2, $status){ 38 | echo "client recv error\n"; 39 | $tcp2->close(); 40 | }); 41 | $tcp2->write("client send some data"); 42 | }); 43 | $loop->run(); 44 | ?> 45 | --EXPECT-- 46 | server: 127.0.0.1:54321 47 | on connect 0 48 | bool(true) 49 | client connected: 1 50 | client send 21 51 | server recv: client send some data 52 | server write:21 53 | client shutdown end 54 | Server response: client send some data 55 | client recv error 56 | -------------------------------------------------------------------------------- /tests/default_loop_null/UVTimer_01.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVTime once 3 | --FILE-- 4 | start(function($timer2) use($timer, $time){ 9 | $timediff = time() - $time; 10 | echo "timer alerm after $timediff secs\n"; 11 | echo "timer object is "; 12 | var_dump($timer === $timer2); 13 | }, 2000); 14 | $loop->run(); 15 | $timer->stop(); 16 | ?> 17 | --EXPECT-- 18 | timer alerm after 2 secs 19 | timer object is bool(true) -------------------------------------------------------------------------------- /tests/default_loop_null/UVTimer_02.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVTime repeat 3 | --FILE-- 4 | start(function($timer2) use($timer, $time){ 9 | $timediff = time() - $time; 10 | echo "timer alerm after $timediff secs\n"; 11 | if($timediff>=5){ 12 | $timer->stop(); 13 | } 14 | }, 2000, 1000); 15 | $loop->run(); 16 | ?> 17 | --EXPECT-- 18 | timer alerm after 2 secs 19 | timer alerm after 3 secs 20 | timer alerm after 4 secs 21 | timer alerm after 5 secs 22 | -------------------------------------------------------------------------------- /tests/default_loop_null/UVUdp.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVUdp 3 | --FILE-- 4 | sendTo($clientIP, $clientPort, $data); 24 | } 25 | 26 | function sendCallback($server, $clientIP, $clientPort, $status){ 27 | echo "Server Send "; 28 | var_dump($status == 0); 29 | $server->close(); 30 | } 31 | 32 | function errorCallback(){ 33 | } 34 | 35 | $loop = UVLoop::defaultLoop(); 36 | $server = new UVUdp(null); 37 | echo "Server Bind: {$server->bind($host, $port)}\n"; 38 | echo "{$server->getSockname()}:{$server->getSockport()}\n"; 39 | echo "setCallback: {$server->setCallback('recvCallback', 'sendCallback', 'errorCallback')}\n"; 40 | $loop->run(); 41 | ?> 42 | --EXPECT-- 43 | Server Bind: 0 44 | 127.0.0.1:8888 45 | setCallback: 0 46 | Server Send bool(true) 47 | Client Echo Recv bool(true) 48 | -------------------------------------------------------------------------------- /tests/replace_callback_gc/UVIdle.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVIdle 3 | --FILE-- 4 | start(function($idle) use(&$count, $idle){ 9 | if($count++ > 10){ 10 | $idle->stop(); 11 | } 12 | }); 13 | $idle->start(function($idle) use(&$count, $idle){ 14 | if($count++ > 10){ 15 | $idle->stop(); 16 | } 17 | }); 18 | $loop->run(); 19 | if($count > 10){ 20 | echo "UVIdle ok"; 21 | } 22 | ?> 23 | --EXPECT-- 24 | UVIdle ok 25 | -------------------------------------------------------------------------------- /tests/replace_callback_gc/UVPipe.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVPipe 3 | --FILE-- 4 | listen($socketName, function($pipe2, $status) use($pipe){ 12 | echo "on connect $status\n"; 13 | var_dump($pipe === $pipe2); 14 | $client = $pipe->accept(); 15 | $client->setCallback(function($clientTest, $data) use($client){ 16 | echo "server recv: $data\n"; 17 | $client->write($data); 18 | }, function($clientTest, $status, $len) use($pipe, $client){ 19 | echo "server write:$len\n"; 20 | $client->shutdown(function($clientTest) use($pipe, $client){ 21 | echo "client shutdown end\n"; 22 | $client->close(); 23 | $pipe->close(); 24 | }); 25 | }, function($clientTest, $status) use($client){ 26 | echo "server recv error\n"; 27 | $client->close(); 28 | }); 29 | 30 | $client->setCallback(function($clientTest, $data) use($client){ 31 | echo "server recv: $data\n"; 32 | $client->write($data); 33 | }, function($clientTest, $status, $len) use($pipe, $client){ 34 | echo "server write:$len\n"; 35 | $client->shutdown(function($clientTest) use($pipe, $client){ 36 | echo "client shutdown end\n"; 37 | $client->close(); 38 | $pipe->close(); 39 | }); 40 | $client->shutdown(function($clientTest) use($pipe, $client){ 41 | echo "client shutdown end\n"; 42 | $client->close(); 43 | $pipe->close(); 44 | }); 45 | }, function($clientTest, $status) use($client){ 46 | echo "server recv error\n"; 47 | $client->close(); 48 | }); 49 | }); 50 | echo "server: {$pipe->getSockname()}\n"; 51 | 52 | $pipe2 = new UVPipe($loop); 53 | $pipe2->connect($socketName, function($pipe2, $status){ 54 | $pipe2->setCallback(function($pipe2Test, $data) use($pipe2){ 55 | echo "Server response: $data\n"; 56 | }, function($pipe2Test, $status, $len) use($pipe2){ 57 | echo "client send $len\n"; 58 | }, function($pipe2Test, $status) use($pipe2){ 59 | echo "client recv error\n"; 60 | $pipe2->close(); 61 | }); 62 | $pipe2->write("client send some data"); 63 | }); 64 | $loop->run(); 65 | ?> 66 | --EXPECT-- 67 | server: uvpipe.test.sock 68 | on connect 0 69 | bool(true) 70 | client send 21 71 | server recv: client send some data 72 | server write:21 73 | client shutdown end 74 | Server response: client send some data 75 | client recv error 76 | -------------------------------------------------------------------------------- /tests/replace_callback_gc/UVPipe_listen_twice.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVPipe 3 | --FILE-- 4 | listen($socketName, function($pipe2, $status) use($pipe){ 12 | echo "on connect $status\n"; 13 | var_dump($pipe === $pipe2); 14 | $client = $pipe->accept(); 15 | $client->setCallback(function($clientTest, $data) use($client){ 16 | echo "server recv: $data\n"; 17 | $client->write($data); 18 | }, function($clientTest, $status, $len) use($pipe, $client){ 19 | echo "server write:$len\n"; 20 | $client->shutdown(function($clientTest) use($pipe, $client){ 21 | echo "client shutdown end\n"; 22 | $client->close(); 23 | $pipe->close(); 24 | }); 25 | }, function($clientTest, $status) use($client){ 26 | echo "server recv error\n"; 27 | $client->close(); 28 | }); 29 | 30 | $client->setCallback(function($clientTest, $data) use($client){ 31 | echo "server recv: $data\n"; 32 | $client->write($data); 33 | }, function($clientTest, $status, $len) use($pipe, $client){ 34 | echo "server write:$len\n"; 35 | $client->shutdown(function($clientTest) use($pipe, $client){ 36 | echo "client shutdown end\n"; 37 | $client->close(); 38 | $pipe->close(); 39 | }); 40 | $client->shutdown(function($clientTest) use($pipe, $client){ 41 | echo "client shutdown end\n"; 42 | $client->close(); 43 | $pipe->close(); 44 | }); 45 | }, function($clientTest, $status) use($client){ 46 | echo "server recv error\n"; 47 | $client->close(); 48 | }); 49 | }); 50 | $result = $pipe->listen($socketName, function($pipe2, $status) use($pipe){ 51 | echo "on connect $status\n"; 52 | var_dump($pipe === $pipe2); 53 | $client = $pipe->accept(); 54 | $client->setCallback(function($clientTest, $data) use($client){ 55 | echo "server recv: $data\n"; 56 | $client->write($data); 57 | }, function($clientTest, $status, $len) use($pipe, $client){ 58 | echo "server write:$len\n"; 59 | $client->shutdown(function($clientTest) use($pipe, $client){ 60 | echo "client shutdown end\n"; 61 | $client->close(); 62 | $pipe->close(); 63 | }); 64 | }, function($clientTest, $status) use($client){ 65 | echo "server recv error\n"; 66 | $client->close(); 67 | }); 68 | 69 | $client->setCallback(function($clientTest, $data) use($client){ 70 | echo "server recv: $data\n"; 71 | $client->write($data); 72 | }, function($clientTest, $status, $len) use($pipe, $client){ 73 | echo "server write:$len\n"; 74 | $client->shutdown(function($clientTest) use($pipe, $client){ 75 | echo "client shutdown end\n"; 76 | $client->close(); 77 | $pipe->close(); 78 | }); 79 | $client->shutdown(function($clientTest) use($pipe, $client){ 80 | echo "client shutdown end\n"; 81 | $client->close(); 82 | $pipe->close(); 83 | }); 84 | }, function($clientTest, $status) use($client){ 85 | echo "server recv error\n"; 86 | $client->close(); 87 | }); 88 | }); 89 | echo "server: {$pipe->getSockname()}\n"; 90 | echo "listen twice $result\n"; 91 | $pipe2 = new UVPipe($loop); 92 | $pipe2->connect($socketName, function($pipe2, $status){ 93 | $pipe2->setCallback(function($pipe2Test, $data) use($pipe2){ 94 | echo "Server response: $data\n"; 95 | }, function($pipe2Test, $status, $len) use($pipe2){ 96 | echo "client send $len\n"; 97 | }, function($pipe2Test, $status) use($pipe2){ 98 | echo "client recv error\n"; 99 | $pipe2->close(); 100 | }); 101 | $pipe2->write("client send some data"); 102 | }); 103 | $loop->run(); 104 | ?> 105 | --EXPECT-- 106 | server: uvpipe.test.sock 107 | listen twice -1 108 | on connect 0 109 | bool(true) 110 | client send 21 111 | server recv: client send some data 112 | server write:21 113 | client shutdown end 114 | Server response: client send some data 115 | client recv error 116 | -------------------------------------------------------------------------------- /tests/replace_callback_gc/UVSignal.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVSignal 3 | --FILE-- 4 | start(function($signal2, $signno) use($signal){ 8 | echo "receive signal\n"; 9 | echo "signal object is "; 10 | var_dump($signal === $signal2); 11 | $signal->stop(); 12 | echo "signal stop"; 13 | }, SIGUSR1); 14 | $signal->start(function($signal2, $signno) use($signal){ 15 | echo "receive signal\n"; 16 | echo "signal object is "; 17 | var_dump($signal === $signal2); 18 | $signal->stop(); 19 | echo "signal stop"; 20 | }, SIGUSR1); 21 | if($pid = pcntl_fork()){ 22 | $signal->stop(); 23 | posix_kill($pid, SIGUSR1); 24 | pcntl_wait($status); 25 | } 26 | else{ 27 | $loop->run(); 28 | } 29 | ?> 30 | --EXPECT-- 31 | receive signal 32 | signal object is bool(true) 33 | signal stop -------------------------------------------------------------------------------- /tests/replace_callback_gc/UVTcp.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVTcp 3 | --FILE-- 4 | listen('127.0.0.1', 54321, function($tcp2, $status) use($tcp){ 8 | echo "on connect $status\n"; 9 | var_dump($tcp === $tcp2); 10 | $client = $tcp->accept(); 11 | $peerHostPortOK = "{$client->getPeername()}:{$client->getPeerport()}" != ":"; 12 | echo "client connected: $peerHostPortOK\n"; 13 | $client->setCallback(function($clientTest, $data) use($client){ 14 | echo "server recv: $data\n"; 15 | $client->write($data); 16 | }, function($clientTest, $status, $len) use($tcp, $client){ 17 | echo "server write:$len\n"; 18 | $client->shutdown(function($clientTest) use($tcp, $client){ 19 | echo "client shutdown end\n"; 20 | $client->close(); 21 | $tcp->close(); 22 | }); 23 | }, function($clientTest, $status) use($client){ 24 | echo "server recv error\n"; 25 | $client->close(); 26 | }); 27 | 28 | $client->setCallback(function($clientTest, $data) use($client){ 29 | echo "server recv: $data\n"; 30 | $client->write($data); 31 | }, function($clientTest, $status, $len) use($tcp, $client){ 32 | echo "server write:$len\n"; 33 | $client->shutdown(function($clientTest) use($tcp, $client){ 34 | echo "client shutdown end\n"; 35 | $client->close(); 36 | $tcp->close(); 37 | }); 38 | $client->shutdown(function($clientTest) use($tcp, $client){ 39 | echo "client shutdown end\n"; 40 | $client->close(); 41 | $tcp->close(); 42 | }); 43 | }, function($clientTest, $status) use($client){ 44 | echo "server recv error\n"; 45 | $client->close(); 46 | }); 47 | }); 48 | echo "server: {$tcp->getSockname()}:{$tcp->getSockport()}\n"; 49 | 50 | $tcp2 = new UVTcp($loop); 51 | $tcp2->connect('127.0.0.1', 54321, function($tcp2, $status){ 52 | $tcp2->setCallback(function($tcp2Test, $data) use($tcp2){ 53 | echo "Server response: $data\n"; 54 | }, function($tcp2Test, $status, $len) use($tcp2){ 55 | echo "client send $len\n"; 56 | }, function($tcp2Test, $status) use($tcp2){ 57 | echo "client recv error\n"; 58 | $tcp2->close(); 59 | }); 60 | $tcp2->write("client send some data"); 61 | }); 62 | $loop->run(); 63 | ?> 64 | --EXPECT-- 65 | server: 127.0.0.1:54321 66 | on connect 0 67 | bool(true) 68 | client connected: 1 69 | client send 21 70 | server recv: client send some data 71 | server write:21 72 | client shutdown end 73 | Server response: client send some data 74 | client recv error 75 | -------------------------------------------------------------------------------- /tests/replace_callback_gc/UVTcp_listen_twice.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVTcp 3 | --FILE-- 4 | listen('127.0.0.1', 54321, function($tcp2, $status) use($tcp){ 8 | echo "on connect $status\n"; 9 | var_dump($tcp === $tcp2); 10 | $client = $tcp->accept(); 11 | $peerHostPortOK = "{$client->getPeername()}:{$client->getPeerport()}" != ":"; 12 | echo "client connected: $peerHostPortOK\n"; 13 | $client->setCallback(function($clientTest, $data) use($client){ 14 | echo "server recv: $data\n"; 15 | $client->write($data); 16 | }, function($clientTest, $status, $len) use($tcp, $client){ 17 | echo "server write:$len\n"; 18 | $client->shutdown(function($clientTest) use($tcp, $client){ 19 | echo "client shutdown end\n"; 20 | $client->close(); 21 | $tcp->close(); 22 | }); 23 | }, function($clientTest, $status) use($client){ 24 | echo "server recv error\n"; 25 | $client->close(); 26 | 27 | }); 28 | }); 29 | 30 | $result = $tcp->listen('127.0.0.1', 54321, function($tcp2, $status) use($tcp){ 31 | echo "on connect $status\n"; 32 | var_dump($tcp === $tcp2); 33 | $client = $tcp->accept(); 34 | $peerHostPortOK = "{$client->getPeername()}:{$client->getPeerport()}" != ":"; 35 | echo "client connected: $peerHostPortOK\n"; 36 | $client->setCallback(function($clientTest, $data) use($client){ 37 | echo "server recv: $data\n"; 38 | $client->write($data); 39 | }, function($clientTest, $status, $len) use($tcp, $client){ 40 | echo "server write:$len\n"; 41 | $client->shutdown(function($clientTest) use($tcp, $client){ 42 | echo "client shutdown end\n"; 43 | $client->close(); 44 | $tcp->close(); 45 | }); 46 | }, function($clientTest, $status) use($client){ 47 | echo "server recv error\n"; 48 | $client->close(); 49 | 50 | }); 51 | }); 52 | 53 | echo "server: {$tcp->getSockname()}:{$tcp->getSockport()}\n"; 54 | echo "listen twice $result\n"; 55 | $tcp2 = new UVTcp($loop); 56 | $tcp2->connect('127.0.0.1', 54321, function($tcp2, $status){ 57 | $tcp2->setCallback(function($tcp2Test, $data) use($tcp2){ 58 | echo "Server response: $data\n"; 59 | }, function($tcp2Test, $status, $len) use($tcp2){ 60 | echo "client send $len\n"; 61 | }, function($tcp2Test, $status) use($tcp2){ 62 | echo "client recv error\n"; 63 | $tcp2->close(); 64 | }); 65 | $tcp2->write("client send some data"); 66 | }); 67 | $loop->run(); 68 | ?> 69 | --EXPECT-- 70 | server: 127.0.0.1:54321 71 | listen twice -1 72 | on connect 0 73 | bool(true) 74 | client connected: 1 75 | client send 21 76 | server recv: client send some data 77 | server write:21 78 | client shutdown end 79 | Server response: client send some data 80 | client recv error 81 | -------------------------------------------------------------------------------- /tests/replace_callback_gc/UVUdp.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVUdp 3 | --FILE-- 4 | bind($host, $port); 25 | $setCallbackResult = $server->setCallback( 26 | function ($serverTest, $clientIP, $clientPort, $data, $flag) use($server){ 27 | $server->sendTo($clientIP, $clientPort, $data); 28 | echo "Recv Server "; 29 | var_dump($serverTest === $server); 30 | }, 31 | function ($serverTest, $clientIP, $clientPort, $status) use($server){ 32 | echo "Server Send "; 33 | var_dump($status == 0); 34 | $server->close(); 35 | echo "Send Server "; 36 | var_dump($serverTest === $server); 37 | }, 38 | function ($serverTest) use($server){ 39 | } 40 | ); 41 | 42 | $setCallbackResult1 = $server->setCallback( 43 | function ($serverTest, $clientIP, $clientPort, $data, $flag) use($server){ 44 | $server->sendTo($clientIP, $clientPort, $data); 45 | echo "Recv Server "; 46 | var_dump($serverTest === $server); 47 | }, 48 | function ($serverTest, $clientIP, $clientPort, $status) use($server){ 49 | echo "Server Send "; 50 | var_dump($status == 0); 51 | $server->close(); 52 | echo "Send Server "; 53 | var_dump($serverTest === $server); 54 | }, 55 | function ($serverTest) use($server){ 56 | } 57 | ); 58 | 59 | echo "Server Bind: $bindResult\n"; 60 | echo "{$server->getSockname()}:{$server->getSockport()}\n"; 61 | echo "setCallback: $setCallbackResult $setCallbackResult1\n"; 62 | $loop->run(); 63 | ?> 64 | --EXPECT-- 65 | Server Bind: 0 66 | 127.0.0.1:8888 67 | setCallback: 0 -1 68 | Recv Server bool(true) 69 | Server Send bool(true) 70 | Send Server bool(true) 71 | Client Echo Recv bool(true) 72 | -------------------------------------------------------------------------------- /tests/typecheck/UVIdle.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVIdle 3 | --FILE-- 4 | 8 | --EXPECT-- 9 | UVIdle ok 10 | -------------------------------------------------------------------------------- /tests/typecheck/UVPipe.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVPipe 3 | --FILE-- 4 | 8 | --EXPECT-- 9 | UVPipe ok 10 | -------------------------------------------------------------------------------- /tests/typecheck/UVResolver.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVResolver 3 | --FILE-- 4 | 8 | --EXPECT-- 9 | UVResolver ok 10 | -------------------------------------------------------------------------------- /tests/typecheck/UVSSL.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVSSL 3 | --FILE-- 4 | 8 | --EXPECT-- 9 | UVSSL ok 10 | -------------------------------------------------------------------------------- /tests/typecheck/UVSignal.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVSignal 3 | --FILE-- 4 | 8 | --EXPECT-- 9 | UVSignal ok 10 | -------------------------------------------------------------------------------- /tests/typecheck/UVTcp.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVTcp 3 | --FILE-- 4 | 8 | --EXPECT-- 9 | UVTcp ok 10 | -------------------------------------------------------------------------------- /tests/typecheck/UVTimer.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVTimer 3 | --FILE-- 4 | 8 | --EXPECT-- 9 | UVTimer ok 10 | -------------------------------------------------------------------------------- /tests/typecheck/UVUdp.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for UVUdp 3 | --FILE-- 4 | 8 | --EXPECT-- 9 | UVUdp ok 10 | -------------------------------------------------------------------------------- /tests/typecheck/error_handler.php: -------------------------------------------------------------------------------- 1 | getMessage() == "Argument 1 passed to $class::__construct() must be an instance of UVLoop, instance of stdClass given"?'ok':'fail'; 7 | echo "$class $status"; 8 | } --------------------------------------------------------------------------------