D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
opt
/
alt
/
php83
/
usr
/
include
/
php
/
ext
/
swoole
/
ext-src
/
Filename :
php_swoole_cxx.h
back
Copy
/* +----------------------------------------------------------------------+ | Swoole | +----------------------------------------------------------------------+ | This source file is subject to version 2.0 of the Apache license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.apache.org/licenses/LICENSE-2.0.html | | If you did not receive a copy of the Apache2.0 license and are unable| | to obtain it through the world-wide-web, please send a note to | | license@swoole.com so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Tianfeng Han <rango@swoole.com> | +----------------------------------------------------------------------+ */ #pragma once #include "php_swoole_private.h" #include "php_swoole_coroutine.h" #include "swoole_util.h" #include <string> // clang-format off //----------------------------------Swoole known string------------------------------------ #define SW_ZEND_KNOWN_STRINGS(_) \ _(SW_ZEND_STR_TYPE, "type") \ _(SW_ZEND_STR_HOST, "host") \ _(SW_ZEND_STR_USER_AGENT, "user-agent") \ _(SW_ZEND_STR_ACCEPT, "accept") \ _(SW_ZEND_STR_CONTENT_TYPE, "content-type") \ _(SW_ZEND_STR_CONTENT_LENGTH, "content-length") \ _(SW_ZEND_STR_AUTHORIZATION, "authorization") \ _(SW_ZEND_STR_CONNECTION, "connection") \ _(SW_ZEND_STR_ACCEPT_ENCODING, "accept-encoding") \ _(SW_ZEND_STR_PORT, "port") \ _(SW_ZEND_STR_SETTING, "setting") \ _(SW_ZEND_STR_ID, "id") \ _(SW_ZEND_STR_FD, "fd") \ _(SW_ZEND_STR_SOCK, "sock") \ _(SW_ZEND_STR_PIPE, "pipe") \ _(SW_ZEND_STR_HEADERS, "headers") \ _(SW_ZEND_STR_REQUEST_METHOD, "requestMethod") \ _(SW_ZEND_STR_REQUEST_HEADERS, "requestHeaders") \ _(SW_ZEND_STR_REQUEST_BODY, "requestBody") \ _(SW_ZEND_STR_UPLOAD_FILES, "uploadFiles") \ _(SW_ZEND_STR_COOKIES, "cookies") \ _(SW_ZEND_STR_DOWNLOAD_FILE, "downloadFile") \ _(SW_ZEND_STR_DOWNLOAD_OFFSET, "downloadOffset") \ _(SW_ZEND_STR_SERVER, "server") \ _(SW_ZEND_STR_HEADER, "header") \ _(SW_ZEND_STR_GET, "get") \ _(SW_ZEND_STR_POST, "post") \ _(SW_ZEND_STR_FILES, "files") \ _(SW_ZEND_STR_TMPFILES, "tmpfiles") \ _(SW_ZEND_STR_COOKIE, "cookie") \ _(SW_ZEND_STR_METHOD, "method") \ _(SW_ZEND_STR_PATH, "path") \ _(SW_ZEND_STR_DATA, "data") \ _(SW_ZEND_STR_PIPELINE, "pipeline") \ _(SW_ZEND_STR_USE_PIPELINE_READ, "usePipelineRead") \ _(SW_ZEND_STR_TRAILER, "trailer") \ _(SW_ZEND_STR_MASTER_PID, "master_pid") \ _(SW_ZEND_STR_CALLBACK, "callback") \ _(SW_ZEND_STR_OPCODE, "opcode") \ _(SW_ZEND_STR_CODE, "code") \ _(SW_ZEND_STR_REASON, "reason") \ _(SW_ZEND_STR_FLAGS, "flags") \ _(SW_ZEND_STR_FINISH, "finish") \ _(SW_ZEND_STR_IN_COROUTINE, "in_coroutine") \ _(SW_ZEND_STR_PRIVATE_DATA, "private_data") \ _(SW_ZEND_STR_CLASS_NAME_RESOLVER, "Swoole\\NameResolver") \ _(SW_ZEND_STR_SOCKET, "socket") \ _(SW_ZEND_STR_ADDR_LOOPBACK_V4, "127.0.0.1") \ _(SW_ZEND_STR_ADDR_LOOPBACK_V6, "::1") \ _(SW_ZEND_STR_REQUEST_METHOD2, "request_method") \ _(SW_ZEND_STR_REQUEST_URI, "request_uri") \ _(SW_ZEND_STR_PATH_INFO, "path_info") \ _(SW_ZEND_STR_REQUEST_TIME, "request_time") \ _(SW_ZEND_STR_REQUEST_TIME_FLOAT, "request_time_float") \ _(SW_ZEND_STR_SERVER_PROTOCOL, "server_protocol") \ _(SW_ZEND_STR_SERVER_PORT, "server_port") \ _(SW_ZEND_STR_REMOTE_PORT, "remote_port") \ _(SW_ZEND_STR_REMOTE_ADDR, "remote_addr") \ _(SW_ZEND_STR_MASTER_TIME, "master_time") \ _(SW_ZEND_STR_HTTP10, "HTTP/1.0") \ _(SW_ZEND_STR_HTTP11, "HTTP/1.1") \ typedef enum sw_zend_known_string_id { #define _SW_ZEND_STR_ID(id, str) id, SW_ZEND_KNOWN_STRINGS(_SW_ZEND_STR_ID) #undef _SW_ZEND_STR_ID SW_ZEND_STR_LAST_KNOWN } sw_zend_known_string_id; // clang-format on #define SW_ZSTR_KNOWN(idx) sw_zend_known_strings[idx] extern zend_string **sw_zend_known_strings; //----------------------------------Swoole known string------------------------------------ #define SW_SET_CLASS_CREATE_WITH_ITS_OWN_HANDLERS(module) \ module##_ce->create_object = [](zend_class_entry *ce) { return sw_zend_create_object(ce, &module##_handlers); } /** * It is safe across coroutines, * add reference count, prevent the socket pointer being released */ #define SW_CLIENT_GET_SOCKET_SAFE(__sock, __zsocket) \ Socket *__sock = nullptr; \ zend::Variable tmp_socket; \ if (ZVAL_IS_OBJECT(__zsocket)) { \ __sock = php_swoole_get_socket(__zsocket); \ tmp_socket.assign(__zsocket); \ } #define SW_CLIENT_PRESERVE_SOCKET(__zsocket) \ zend::Variable tmp_socket; \ if (ZVAL_IS_OBJECT(__zsocket)) { \ tmp_socket.assign(__zsocket); \ } SW_API bool php_swoole_is_enable_coroutine(); SW_API zend_object *php_swoole_create_socket(enum swSocketType type); SW_API zend_object *php_swoole_create_socket_from_fd(int fd, enum swSocketType type); SW_API bool php_swoole_export_socket(zval *zobject, swoole::coroutine::Socket *_socket); SW_API zend_object *php_swoole_dup_socket(int fd, enum swSocketType type); SW_API void php_swoole_init_socket_object(zval *zobject, swoole::coroutine::Socket *socket); SW_API swoole::coroutine::Socket *php_swoole_get_socket(zval *zobject); SW_API bool php_swoole_socket_is_closed(zval *zobject); #ifdef SW_USE_OPENSSL SW_API bool php_swoole_socket_set_ssl(swoole::coroutine::Socket *sock, zval *zset); #endif SW_API bool php_swoole_socket_set_protocol(swoole::coroutine::Socket *sock, zval *zset); SW_API bool php_swoole_socket_set(swoole::coroutine::Socket *cli, zval *zset); SW_API void php_swoole_socket_set_error_properties(zval *zobject, int code); SW_API void php_swoole_socket_set_error_properties(zval *zobject, int code, const char *msg); SW_API void php_swoole_socket_set_error_properties(zval *zobject, swoole::coroutine::Socket *socket); #define php_swoole_client_set php_swoole_socket_set SW_API php_stream *php_swoole_create_stream_from_socket(php_socket_t _fd, int domain, int type, int protocol STREAMS_DC); SW_API php_stream_ops *php_swoole_get_ori_php_stream_stdio_ops(); SW_API void php_swoole_register_rshutdown_callback(swoole::Callback cb, void *private_data); // timer SW_API bool php_swoole_timer_clear(swoole::TimerNode *tnode); SW_API bool php_swoole_timer_clear_all(); static inline bool php_swoole_is_fatal_error() { return PG(last_error_message) && (PG(last_error_type) & E_FATAL_ERRORS); } ssize_t php_swoole_length_func(const swoole::Protocol *, swoole::network::Socket *, swoole::PacketLength *); SW_API zend_long php_swoole_parse_to_size(zval *zv); #ifdef SW_HAVE_ZLIB #define php_swoole_websocket_frame_pack php_swoole_websocket_frame_pack_ex #define php_swoole_websocket_frame_object_pack php_swoole_websocket_frame_object_pack_ex #else #define php_swoole_websocket_frame_pack(buffer, zdata, opcode, flags, mask, allow_compress) \ php_swoole_websocket_frame_pack_ex(buffer, zdata, opcode, flags, mask, 0) #define php_swoole_websocket_frame_object_pack(buffer, zdata, mask, allow_compress) \ php_swoole_websocket_frame_object_pack_ex(buffer, zdata, mask, 0) #endif int php_swoole_websocket_frame_pack_ex( swoole::String *buffer, zval *zdata, zend_long opcode, uint8_t flags, zend_bool mask, zend_bool allow_compress); int php_swoole_websocket_frame_object_pack_ex(swoole::String *buffer, zval *zdata, zend_bool mask, zend_bool allow_compress); void php_swoole_websocket_frame_unpack(swoole::String *data, zval *zframe); void php_swoole_websocket_frame_unpack_ex(swoole::String *data, zval *zframe, uchar allow_uncompress); #ifdef SW_HAVE_ZLIB int php_swoole_zlib_decompress(z_stream *stream, swoole::String *buffer, char *body, int length); #endif swoole::NameResolver::Context *php_swoole_name_resolver_get_context(zval *zobject); std::string php_swoole_name_resolver_lookup(const std::string &name, swoole::NameResolver::Context *ctx, void *_resolver); bool php_swoole_name_resolver_add(zval *zresolver); const swoole::Allocator *sw_php_allocator(); const swoole::Allocator *sw_zend_string_allocator(); static inline bool php_swoole_async(bool blocking, const std::function<void(void)> &fn) { if (!blocking && swoole_coroutine_is_in()) { return swoole::coroutine::async(fn); } else { fn(); return true; } } namespace zend { //-----------------------------------namespace begin-------------------------------------------- class String { public: String() { str = nullptr; } String(const char *_str, size_t len) { str = zend_string_init(_str, len, 0); } String(const std::string &_str) { str = zend_string_init(_str.c_str(), _str.length(), 0); } String(zval *v) { str = zval_get_string(v); } String(zend_string *v, bool copy) { if (copy) { str = zend_string_copy(v); } else { str = v; } } String(const String &o) { str = zend_string_copy(o.str); } String(String &&o) { str = o.str; o.str = nullptr; } void operator=(zval *v) { release(); str = zval_get_string(v); } String &operator=(String &&o) { release(); str = o.str; o.str = nullptr; return *this; } String &operator=(const String &o) { release(); str = zend_string_copy(o.str); return *this; } char *val() { return ZSTR_VAL(str); } size_t len() { return ZSTR_LEN(str); } zend_string *get() { return str; } void rtrim() { ZSTR_LEN(str) = swoole::rtrim(val(), len()); } const std::string to_std_string() { return std::string(val(), len()); } char *dup() { return sw_likely(len() > 0) ? sw_strndup(val(), len()) : nullptr; } char *edup() { return sw_likely(len() > 0) ? estrndup(val(), len()) : nullptr; } void release() { if (str) { zend_string_release(str); str = nullptr; } } ~String() { release(); } private: zend_string *str; }; class KeyValue { public: zend_ulong index; zend_string *key; zval zvalue; KeyValue(zend_ulong _index, zend_string *_key, zval *_zvalue) { index = _index; key = _key ? zend_string_copy(_key) : nullptr; ZVAL_DEREF(_zvalue); zvalue = *_zvalue; Z_TRY_ADDREF(zvalue); } void add_to(zval *zarray) { HashTable *ht = Z_ARRVAL_P(zarray); zval *dest_elem = !key ? zend_hash_index_update(ht, index, &zvalue) : zend_hash_update(ht, key, &zvalue); Z_TRY_ADDREF_P(dest_elem); } ~KeyValue() { if (key) { zend_string_release(key); } zval_ptr_dtor(&zvalue); } }; class ArrayIterator { public: ArrayIterator(Bucket *p) { _ptr = p; _key = _ptr->key; _val = &_ptr->val; _index = _ptr->h; pe = p; } ArrayIterator(Bucket *p, Bucket *_pe) { _ptr = p; _key = _ptr->key; _val = &_ptr->val; _index = _ptr->h; pe = _pe; skipUndefBucket(); } void operator++(int i) { ++_ptr; skipUndefBucket(); } bool operator!=(ArrayIterator b) { return b.ptr() != _ptr; } std::string key() { return std::string(_key->val, _key->len); } zend_ulong index() { return _index; } zval *value() { return _val; } Bucket *ptr() { return _ptr; } private: void skipUndefBucket() { while (_ptr != pe) { _val = &_ptr->val; if (_val && Z_TYPE_P(_val) == IS_INDIRECT) { _val = Z_INDIRECT_P(_val); } if (UNEXPECTED(Z_TYPE_P(_val) == IS_UNDEF)) { ++_ptr; continue; } if (_ptr->key) { _key = _ptr->key; _index = 0; } else { _index = _ptr->h; _key = nullptr; } break; } } zval *_val; zend_string *_key; Bucket *_ptr; Bucket *pe; zend_ulong _index; }; class Array { public: zval *arr; Array(zval *_arr) { assert(Z_TYPE_P(_arr) == IS_ARRAY); arr = _arr; } size_t count() { return zend_hash_num_elements(Z_ARRVAL_P(arr)); } bool set(zend_ulong index, zval *value) { return add_index_zval(arr, index, value) == SUCCESS; } bool append(zval *value) { return add_next_index_zval(arr, value) == SUCCESS; } bool set(zend_ulong index, zend_resource *res) { zval tmp; ZVAL_RES(&tmp, res); return set(index, &tmp); } ArrayIterator begin() { return ArrayIterator(Z_ARRVAL_P(arr)->arData, Z_ARRVAL_P(arr)->arData + Z_ARRVAL_P(arr)->nNumUsed); } ArrayIterator end() { return ArrayIterator(Z_ARRVAL_P(arr)->arData + Z_ARRVAL_P(arr)->nNumUsed); } }; enum PipeType { PIPE_TYPE_NONE = 0, PIPE_TYPE_STREAM = 1, PIPE_TYPE_DGRAM = 2, }; class Process { public: zend_object *zsocket = nullptr; enum PipeType pipe_type; bool enable_coroutine; Process(enum PipeType pipe_type, bool enable_coroutine) : pipe_type(pipe_type), enable_coroutine(enable_coroutine) {} ~Process() { if (zsocket) { OBJ_RELEASE(zsocket); } } }; class Variable { public: zval value; Variable() { value = {}; } Variable(zval *zvalue) { assign(zvalue); } Variable(const char *str, size_t l_str) { ZVAL_STRINGL(&value, str, l_str); } Variable(const char *str) { ZVAL_STRING(&value, str); } Variable(const Variable &&src) { value = src.value; add_ref(); } Variable(Variable &&src) { value = src.value; src.reset(); } void operator=(zval *zvalue) { assign(zvalue); } void operator=(const Variable &src) { value = src.value; add_ref(); } void assign(zval *zvalue) { value = *zvalue; add_ref(); } zval *ptr() { return &value; } void reset() { ZVAL_UNDEF(&value); } void add_ref() { Z_TRY_ADDREF_P(&value); } void del_ref() { Z_TRY_DELREF_P(&value); } ~Variable() { zval_ptr_dtor(&value); } }; class CharPtr { private: char *str_; public: CharPtr() { str_ = nullptr; } CharPtr(char *str) { str_ = estrndup(str, strlen(str)); } CharPtr(char *str, size_t len) { str_ = estrndup(str, len); } void operator=(char *str) { assign(str, strlen(str)); } void release() { if (str_) { efree(str_); str_ = nullptr; } } void assign(char *str, size_t len) { release(); str_ = estrndup(str, len); } void assign_tolower(char *str, size_t len) { release(); str_ = zend_str_tolower_dup(str, len); } ~CharPtr() { release(); } char *get() { return str_; } }; struct Callable { zval zfunc; zend_fcall_info_cache fcc; Callable(zval *_zfunc) { zfunc = *_zfunc; Z_TRY_ADDREF_P(&zfunc); } bool is_callable() { return zend_is_callable_ex(&zfunc, NULL, 0, NULL, &fcc, NULL); } bool call(uint32_t argc, zval *argv, zval *retval) { return sw_zend_call_function_ex(&zfunc, &fcc, argc, argv, retval) == SUCCESS; } ~Callable() { Z_TRY_DELREF_P(&zfunc); } }; namespace function { /* must use this API to call event callbacks to ensure that exceptions are handled correctly */ bool call(zend_fcall_info_cache *fci_cache, uint32_t argc, zval *argv, zval *retval, const bool enable_coroutine); Variable call(const std::string &func_name, int argc, zval *argv); } // namespace function struct Function { zend_fcall_info fci; zend_fcall_info_cache fci_cache; bool call(zval *retval, const bool enable_coroutine) { return function::call(&fci_cache, fci.param_count, fci.params, retval, enable_coroutine); } }; void known_strings_init(void); void known_strings_dtor(void); void unserialize(zval *return_value, const char *buf, size_t buf_len, HashTable *options); void json_decode(zval *return_value, const char *str, size_t str_len, zend_long options, zend_long zend_long); static inline zend_string *fetch_zend_string_by_val(void *val) { return (zend_string *) ((char *) val - XtOffsetOf(zend_string, val)); } static inline void assign_zend_string_by_val(zval *zdata, char *addr, size_t length) { zend_string *zstr = fetch_zend_string_by_val(addr); addr[length] = 0; zstr->len = length; ZVAL_STR(zdata, zstr); } static inline void array_set(zval *arg, const char *key, size_t l_key, zval *zvalue) { Z_TRY_ADDREF_P(zvalue); add_assoc_zval_ex(arg, key, l_key, zvalue); } static inline void array_set(zval *arg, const char *key, size_t l_key, const char *value, size_t l_value) { zval ztmp; ZVAL_STRINGL(&ztmp, value, l_value); add_assoc_zval_ex(arg, key, l_key, &ztmp); } static inline void array_add(zval *arg, zval *zvalue) { Z_TRY_ADDREF_P(zvalue); add_next_index_zval(arg, zvalue); } static inline void array_unset(zval *arg, const char *key, size_t l_key) { zend_hash_str_del(Z_ARRVAL_P(arg), key, l_key); } //-----------------------------------namespace end-------------------------------------------- } // namespace zend static inline zend::Callable *php_swoole_zval_to_callable(zval *zfn, const char *fname, bool allow_null = true) { if (zfn == nullptr || ZVAL_IS_NULL(zfn)) { if (!allow_null) { zend_throw_exception_ex( swoole_exception_ce, SW_ERROR_INVALID_PARAMS, "%s must be of type callable, null given", fname); } return nullptr; } auto cb = new zend::Callable(zfn); if (!cb->is_callable()) { delete cb; zend_throw_exception_ex(swoole_exception_ce, SW_ERROR_INVALID_PARAMS, "%s must be of type callable, %s given", fname, zend_zval_type_name(zfn)); return nullptr; } return cb; } static inline void php_swoole_callable_free(void *ptr) { zend::Callable *cb = (zend::Callable *) ptr; delete cb; }