ok
Direktori : /opt/cloudlinux/alt-php71/root/usr/include/php/ext/swoole/include/ |
Current File : //opt/cloudlinux/alt-php71/root/usr/include/php/ext/swoole/include/coroutine_socket.h |
/* +----------------------------------------------------------------------+ | 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 <mikan.tenny@gmail.com> | +----------------------------------------------------------------------+ */ #pragma once #include "coroutine.h" #include "connection.h" #include "socks5.h" #include <vector> #include <string> #define SW_DEFAULT_SOCKET_CONNECT_TIMEOUT 1 #define SW_DEFAULT_SOCKET_READ_TIMEOUT -1 #define SW_DEFAULT_SOCKET_WRITE_TIMEOUT -1 namespace swoole { enum swTimeout_type { SW_TIMEOUT_CONNECT = 1u << 1, SW_TIMEOUT_READ = 1u << 2, SW_TIMEOUT_WRITE = 1u << 3, SW_TIMEOUT_RDWR = SW_TIMEOUT_READ | SW_TIMEOUT_WRITE, SW_TIMEOUT_ALL = 0xff, }; static constexpr enum swTimeout_type swTimeout_type_list[3] = { SW_TIMEOUT_CONNECT, SW_TIMEOUT_READ, SW_TIMEOUT_WRITE }; } namespace swoole { namespace coroutine { //------------------------------------------------------------------------------- class Socket { public: static double default_connect_timeout; static double default_read_timeout; static double default_write_timeout; swSocket *socket = nullptr; int errCode = 0; const char *errMsg = ""; bool open_length_check = false; bool open_eof_check = false; bool http2 = false; swProtocol protocol = {0}; struct _swSocks5 *socks5_proxy = nullptr; struct _http_proxy* http_proxy = nullptr; #ifdef SW_USE_OPENSSL bool open_ssl = false; swSSL_option ssl_option = {0}; #endif Socket(int domain, int type, int protocol); Socket(int _fd, int _domain, int _type, int _protocol); Socket(enum swSocket_type type = SW_SOCK_TCP); Socket(int _fd, enum swSocket_type _type); ~Socket(); bool connect(std::string host, int port, int flags = 0); bool connect(const struct sockaddr *addr, socklen_t addrlen); bool shutdown(int how = SHUT_RDWR); bool cancel(const enum swEvent_type event); bool close(); inline bool is_connect() { return activated && !closed; } bool check_liveness(); ssize_t peek(void *__buf, size_t __n); ssize_t recv(void *__buf, size_t __n); ssize_t send(const void *__buf, size_t __n); ssize_t read(void *__buf, size_t __n); ssize_t write(const void *__buf, size_t __n); ssize_t recvmsg(struct msghdr *msg, int flags); ssize_t sendmsg(const struct msghdr *msg, int flags); ssize_t recv_all(void *__buf, size_t __n); ssize_t send_all(const void *__buf, size_t __n); ssize_t recv_packet(double timeout = 0); bool poll(enum swEvent_type type); Socket* accept(double timeout = 0); bool bind(std::string address, int port = 0); bool listen(int backlog = 0); bool sendfile(const char *filename, off_t offset, size_t length); ssize_t sendto(const char *address, int port, const void *__buf, size_t __n); ssize_t recvfrom(void *__buf, size_t __n); ssize_t recvfrom(void *__buf, size_t __n, struct sockaddr *_addr, socklen_t *_socklen); #ifdef SW_USE_OPENSSL bool ssl_handshake(); int ssl_verify(bool allow_self_signed); bool ssl_accept(); bool ssl_check_context(); #endif static inline enum swSocket_type convert_to_type(int domain, int type, int protocol = 0) { switch (domain) { case AF_INET: return type == SOCK_STREAM ? SW_SOCK_TCP : SW_SOCK_UDP; case AF_INET6: return type == SOCK_STREAM ? SW_SOCK_TCP6 : SW_SOCK_UDP6; case AF_UNIX: return type == SOCK_STREAM ? SW_SOCK_UNIX_STREAM : SW_SOCK_UNIX_DGRAM; default: return SW_SOCK_TCP; } } static inline enum swSocket_type convert_to_type(std::string &host) { if (host.compare(0, 6, "unix:/", 0, 6) == 0) { host = host.substr(sizeof("unix:") - 1); host.erase(0, host.find_first_not_of('/') - 1); return SW_SOCK_UNIX_STREAM; } else if (host.find(':') != std::string::npos) { return SW_SOCK_TCP6; } else { return SW_SOCK_TCP; } } static inline void init_reactor(swReactor *reactor) { swReactor_set_handler(reactor, SW_FD_CORO_SOCKET | SW_EVENT_READ, readable_event_callback); swReactor_set_handler(reactor, SW_FD_CORO_SOCKET | SW_EVENT_WRITE, writable_event_callback); swReactor_set_handler(reactor, SW_FD_CORO_SOCKET | SW_EVENT_ERROR, error_event_callback); } inline enum swSocket_type get_type() { return type; } inline int get_sock_domain() { return sock_domain; } inline int get_sock_type() { return sock_type; } inline int get_sock_protocol() { return sock_protocol; } inline int get_fd() { return sock_fd; } inline int get_bind_port() { return bind_port; } bool getsockname(); bool getpeername(); const char* get_ip(); int get_port(); inline bool has_bound(const enum swEvent_type event = SW_EVENT_RDWR) { return get_bound_co(event) != nullptr; } inline Coroutine* get_bound_co(const enum swEvent_type event) { if (event & SW_EVENT_READ) { if (read_co) { return read_co; } } if (event & SW_EVENT_WRITE) { if (write_co) { return write_co; } } return nullptr; } inline long get_bound_cid(const enum swEvent_type event = SW_EVENT_RDWR) { Coroutine *co = get_bound_co(event); return co ? co->get_cid() : 0; } inline void check_bound_co(const enum swEvent_type event) { long cid = get_bound_cid(event); if (sw_unlikely(cid)) { swFatalError( SW_ERROR_CO_HAS_BEEN_BOUND, "Socket#%d has already been bound to another coroutine#%ld, " "%s of the same socket in coroutine#%ld at the same time is not allowed", sock_fd, cid, (event == SW_EVENT_READ ? "reading" : (event == SW_EVENT_WRITE ? "writing" : (read_co && write_co ? "reading or writing" : (read_co ? "reading" : "writing")))), Coroutine::get_current_cid() ); } } inline void set_err(int e) { errCode = errno = e; errMsg = e ? swoole_strerror(e) : ""; } inline void set_err(int e, const char *s) { errCode = errno = e; errMsg = s; } /* set connect read write timeout */ inline void set_timeout(double timeout, int type = SW_TIMEOUT_ALL) { if (timeout == 0) { return; } if (type & SW_TIMEOUT_CONNECT) { connect_timeout = timeout; } if (type & SW_TIMEOUT_READ) { read_timeout = timeout; } if (type & SW_TIMEOUT_WRITE) { write_timeout = timeout; } } inline void set_timeout(struct timeval *timeout, int type = SW_TIMEOUT_ALL) { set_timeout((double) timeout->tv_sec + ((double) timeout->tv_usec / 1000 / 1000), type); } inline double get_timeout(enum swTimeout_type type = SW_TIMEOUT_ALL) { SW_ASSERT_1BYTE(type); if (type == SW_TIMEOUT_CONNECT) { return connect_timeout; } else if (type == SW_TIMEOUT_READ) { return read_timeout; } else // if (type == SW_TIMEOUT_WRITE) { return write_timeout; } } inline bool set_option(int level, int optname, int optval) { if (setsockopt(sock_fd, level, optname, &optval, sizeof(optval)) != 0) { swSysWarn("setsockopt(%d, %d, %d, %d) failed", sock_fd, level, optname, optval); return false; } return true; } inline swString* get_read_buffer() { if (sw_unlikely(!read_buffer)) { read_buffer = swString_new(SW_BUFFER_SIZE_BIG); } return read_buffer; } inline swString* get_write_buffer() { if (sw_unlikely(!write_buffer)) { write_buffer = swString_new(SW_BUFFER_SIZE_BIG); } return write_buffer; } #ifdef SW_USE_OPENSSL inline bool is_ssl_enable() { return socket && socket->ssl != NULL; } bool ssl_shutdown(); #endif private: enum swSocket_type type; int sock_domain = 0; int sock_type = 0; int sock_protocol = 0; int sock_fd = -1; Coroutine *read_co = nullptr; Coroutine *write_co = nullptr; #ifdef SW_USE_OPENSSL enum swEvent_type want_event = SW_EVENT_NULL; #endif std::string connect_host; int connect_port = 0; std::string bind_address; int bind_port = 0; int backlog = 0; double connect_timeout = default_connect_timeout; double read_timeout = default_read_timeout; double write_timeout = default_write_timeout; swTimer_node *read_timer = nullptr; swTimer_node *write_timer = nullptr; swString *read_buffer = nullptr; swString *write_buffer = nullptr; swSocketAddress bind_address_info = {{}, 0}; #ifdef SW_USE_OPENSSL std::string ssl_host_name; SSL_CTX *ssl_context = nullptr; #endif bool activated = true; bool shutdown_read = false; bool shutdown_write = false; bool closed = false; static void timer_callback(swTimer *timer, swTimer_node *tnode); static int readable_event_callback(swReactor *reactor, swEvent *event); static int writable_event_callback(swReactor *reactor, swEvent *event); static int error_event_callback(swReactor *reactor, swEvent *event); Socket(int _fd, swSocketAddress *addr, Socket *socket); inline void init_sock_type(enum swSocket_type _type); inline bool init_sock(); void init_reactor_socket(int fd); inline void init_options() { if (type == SW_SOCK_TCP || type == SW_SOCK_TCP6) { set_option(IPPROTO_TCP, TCP_NODELAY, 1); } protocol.package_length_type = 'N'; protocol.package_length_size = 4; protocol.package_body_offset = 0; protocol.package_max_length = SW_BUFFER_INPUT_SIZE; } bool add_event(const enum swEvent_type event); bool wait_event(const enum swEvent_type event, const void **__buf = nullptr, size_t __n = 0); inline bool is_available(const enum swEvent_type event) { if (event != SW_EVENT_NULL) { check_bound_co(event); } if (sw_unlikely(closed)) { set_err(ECONNRESET); return false; } return true; } // TODO: move to client.cc bool socks5_handshake(); bool http_proxy_handshake(); class timer_controller { public: timer_controller(swTimer_node **timer_pp, double timeout, Socket *sock, swTimerCallback callback) : timer_pp(timer_pp), timeout(timeout), socket_(sock), callback(callback) { } bool start() { if (timeout != 0 && !*timer_pp) { enabled = true; if (timeout > 0) { *timer_pp = swoole_timer_add((long) (timeout * 1000), SW_FALSE, callback, socket_); return *timer_pp != nullptr; } else // if (timeout < 0) { *timer_pp = (swTimer_node *) -1; } } return true; } ~timer_controller() { if (enabled && *timer_pp) { if (*timer_pp != (swTimer_node *) -1) { swoole_timer_del(*timer_pp); } *timer_pp = nullptr; } } private: bool enabled = false; swTimer_node** timer_pp; double timeout; Socket *socket_; swTimerCallback callback; }; public: class timeout_setter { public: timeout_setter(Socket *socket, double timeout, const enum swTimeout_type type) : socket_(socket), timeout(timeout), type(type) { if (timeout == 0) { return; } for (uint8_t i = 0; i < SW_ARRAY_SIZE(swTimeout_type_list); i++) { if (type & swTimeout_type_list[i]) { original_timeout[i] = socket->get_timeout(swTimeout_type_list[i]); if (timeout != original_timeout[i]) { socket->set_timeout(timeout, swTimeout_type_list[i]); } } } } ~timeout_setter() { if (timeout == 0) { return; } for (uint8_t i = 0; i < SW_ARRAY_SIZE(swTimeout_type_list); i++) { if (type & swTimeout_type_list[i]) { if (timeout != original_timeout[i]) { socket_->set_timeout(original_timeout[i], swTimeout_type_list[i]); } } } } protected: Socket *socket_; double timeout; enum swTimeout_type type; double original_timeout[sizeof(swTimeout_type_list)] = {0}; }; class timeout_controller: public timeout_setter { public: timeout_controller(Socket *socket, double timeout, const enum swTimeout_type type) : timeout_setter(socket, timeout, type) { } inline bool has_timedout(const enum swTimeout_type type) { SW_ASSERT_1BYTE(type); if (timeout > 0) { if (sw_unlikely(startup_time == 0)) { startup_time = swoole_microtime(); } else { double used_time = swoole_microtime() - startup_time; if (sw_unlikely(timeout - used_time < SW_TIMER_MIN_SEC)) { socket_->set_err(ETIMEDOUT); return true; } socket_->set_timeout(timeout - used_time, type); } } return false; } protected: double startup_time = 0; }; }; std::vector<std::string> dns_lookup(const char *domain, double timeout = 2.0); //------------------------------------------------------------------------------- }}