summaryrefslogtreecommitdiffstats
path: root/socket.cc
diff options
context:
space:
mode:
Diffstat (limited to 'socket.cc')
-rw-r--r--socket.cc1441
1 files changed, 0 insertions, 1441 deletions
diff --git a/socket.cc b/socket.cc
deleted file mode 100644
index 7edb58f..0000000
--- a/socket.cc
+++ /dev/null
@@ -1,1441 +0,0 @@
-#include "socket.h"
-#include "context.h"
-#include "async.h"
-#include "buffer.h"
-
-#include <string>
-#include <iostream>
-#include <sys/stat.h>
-
-using namespace swoole;
-using namespace std;
-
-static int socket_onRead(swReactor *reactor, swEvent *event);
-static int socket_onWrite(swReactor *reactor, swEvent *event);
-static void socket_onTimeout(swTimer *timer, swTimer_node *tnode);
-static void socket_onResolveCompleted(swAio_event *event);
-
-bool Socket::socks5_handshake()
-{
- swSocks5 *ctx = socks5_proxy;
- char *buf = ctx->buf;
- int n;
-
- /**
- * handshake
- */
- swSocks5_pack(buf, socks5_proxy->username == NULL ? 0x00 : 0x02);
- socks5_proxy->state = SW_SOCKS5_STATE_HANDSHAKE;
- if (send(buf, 3) <= 0)
- {
- return false;
- }
- n = recv(buf, sizeof(ctx->buf));
- if (n <= 0)
- {
- return false;
- }
- uchar version = buf[0];
- uchar method = buf[1];
- if (version != SW_SOCKS5_VERSION_CODE)
- {
- swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SOCKS5_UNSUPPORT_VERSION, "SOCKS version is not supported.");
- return SW_ERR;
- }
- if (method != ctx->method)
- {
- swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SOCKS5_UNSUPPORT_METHOD, "SOCKS authentication method not supported.");
- return SW_ERR;
- }
- //authenticate request
- if (method == SW_SOCKS5_METHOD_AUTH)
- {
- buf[0] = 0x01;
- buf[1] = ctx->l_username;
-
- buf += 2;
- memcpy(buf, ctx->username, ctx->l_username);
- buf += ctx->l_username;
- buf[0] = ctx->l_password;
- memcpy(buf + 1, ctx->password, ctx->l_password);
-
- ctx->state = SW_SOCKS5_STATE_AUTH;
-
- if (send(ctx->buf, ctx->l_username + ctx->l_password + 3) < 0)
- {
- return false;
- }
-
- n = recv(buf, sizeof(ctx->buf));
- if (n <= 0)
- {
- return false;
- }
-
- uchar version = buf[0];
- uchar status = buf[1];
- if (version != 0x01)
- {
- swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SOCKS5_UNSUPPORT_VERSION, "SOCKS version is not supported.");
- return false;
- }
- if (status != 0)
- {
- swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SOCKS5_AUTH_FAILED,
- "SOCKS username/password authentication failed.");
- return false;
- }
- goto send_connect_request;
- }
- //send connect request
- else
- {
- send_connect_request: buf[0] = SW_SOCKS5_VERSION_CODE;
- buf[1] = 0x01;
- buf[2] = 0x00;
-
- ctx->state = SW_SOCKS5_STATE_CONNECT;
-
- if (ctx->dns_tunnel)
- {
- buf[3] = 0x03;
- buf[4] = ctx->l_target_host;
- buf += 5;
- memcpy(buf, ctx->target_host, ctx->l_target_host);
- buf += ctx->l_target_host;
- *(uint16_t *) buf = htons(ctx->target_port);
-
- if (send(ctx->buf, ctx->l_target_host + 7) < 0)
- {
- return false;
- }
- }
- else
- {
- buf[3] = 0x01;
- buf += 4;
- *(uint32_t *) buf = htons(ctx->l_target_host);
- buf += 4;
- *(uint16_t *) buf = htons(ctx->target_port);
-
- if (send(ctx->buf, ctx->l_target_host + 7) < 0)
- {
- return false;
- }
- }
-
- /**
- * response
- */
- n = recv(buf, sizeof(ctx->buf));
- if (n <= 0)
- {
- return false;
- }
-
- uchar version = buf[0];
- if (version != SW_SOCKS5_VERSION_CODE)
- {
- swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SOCKS5_UNSUPPORT_VERSION, "SOCKS version is not supported.");
- return false;
- }
- uchar result = buf[1];
-#if 0
- uchar reg = buf[2];
- uchar type = buf[3];
- uint32_t ip = *(uint32_t *) (buf + 4);
- uint16_t port = *(uint16_t *) (buf + 8);
-#endif
- if (result == 0)
- {
- ctx->state = SW_SOCKS5_STATE_READY;
- }
- else
- {
- swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SOCKS5_SERVER_ERROR, "Socks5 server error, reason :%s.",
- swSocks5_strerror(result));
- }
- return result;
- }
-}
-
-bool Socket::http_proxy_handshake()
-{
-#ifdef SW_USE_OPENSSL
- if (socket->ssl)
- {
- if (ssl_handshake() == false)
- {
- return false;
- }
- }
- else
- {
- return true;
- }
-#else
- return true;
-#endif
-
- //CONNECT
- int n = snprintf(http_proxy->buf, sizeof(http_proxy->buf), "CONNECT %*s:%d HTTP/1.1\r\n\r\n",
- http_proxy->l_target_host, http_proxy->target_host, http_proxy->target_port);
- if (send(http_proxy->buf, n) <= 0)
- {
- return false;
- }
-
- n = recv(http_proxy->buf, sizeof(http_proxy->buf));
- if (n <= 0)
- {
- return false;
- }
- char *buf = http_proxy->buf;
- int len = n;
- int state = 0;
- char *p = buf;
- for (p = buf; p < buf + len; p++)
- {
- if (state == 0)
- {
- if (strncasecmp(p, "HTTP/1.1", 8) == 0 || strncasecmp(p, "HTTP/1.0", 8) == 0)
- {
- state = 1;
- p += 8;
- }
- else
- {
- break;
- }
- }
- else if (state == 1)
- {
- if (isspace(*p))
- {
- continue;
- }
- else
- {
- if (strncasecmp(p, "200", 3) == 0)
- {
- state = 2;
- p += 3;
- }
- else
- {
- break;
- }
- }
- }
- else if (state == 2)
- {
- if (isspace(*p))
- {
- continue;
- }
- else
- {
- if (strncasecmp(p, "Connection established", sizeof("Connection established") - 1) == 0)
- {
- return true;
- }
- else
- {
- break;
- }
- }
- }
- }
- return false;
-}
-
-static inline int socket_connect(int fd, struct sockaddr *addr, socklen_t len)
-{
- int retval;
- while (1)
- {
- retval = ::connect(fd, addr, len);
- if (retval < 0)
- {
- if (errno == EINTR)
- {
- continue;
- }
- }
- break;
- }
- return retval;
-}
-
-Socket::Socket(enum swSocket_type _type)
-{
- type = _type;
- switch (type)
- {
- case SW_SOCK_TCP6:
- _sock_domain = AF_INET6;
- _sock_type = SOCK_STREAM;
- break;
- case SW_SOCK_UNIX_STREAM:
- _sock_domain = AF_UNIX;
- _sock_type = SOCK_STREAM;
- break;
- case SW_SOCK_UDP:
- _sock_domain = AF_INET;
- _sock_type = SOCK_DGRAM;
- break;
- case SW_SOCK_UDP6:
- _sock_domain = AF_INET6;
- _sock_type = SOCK_DGRAM;
- break;
- case SW_SOCK_UNIX_DGRAM:
- _sock_domain = AF_UNIX;
- _sock_type = SOCK_DGRAM;
- break;
- case SW_SOCK_TCP:
- default:
- _sock_domain = AF_INET;
- _sock_type = SOCK_STREAM;
- break;
- }
-
-#ifdef SOCK_CLOEXEC
- int sockfd = ::socket(_sock_domain, _sock_type | SOCK_CLOEXEC, 0);
-#else
- int sockfd = ::socket(_sock_domain, _sock_type, 0);
-#endif
- if (sockfd < 0)
- {
- swWarn("socket() failed. Error: %s[%d]", strerror(errno), errno);
- return;
- }
-
- if (swIsMaster() && SwooleTG.type == SW_THREAD_REACTOR)
- {
- reactor = SwooleTG.reactor;
- }
- else
- {
- reactor = SwooleG.main_reactor;
- }
- socket = swReactor_get(reactor, sockfd);
-
- bzero(socket, sizeof(swConnection));
- socket->fd = sockfd;
- socket->object = this;
- socket->socket_type = type;
-
- swSetNonBlock(socket->fd);
- if (!swReactor_handle_isset(reactor, SW_FD_CORO_SOCKET))
- {
- reactor->setHandle(reactor, SW_FD_CORO_SOCKET | SW_EVENT_READ, socket_onRead);
- reactor->setHandle(reactor, SW_FD_CORO_SOCKET | SW_EVENT_WRITE, socket_onWrite);
- reactor->setHandle(reactor, SW_FD_CORO_SOCKET | SW_EVENT_ERROR, socket_onRead);
- }
- init();
-}
-
-Socket::Socket(int _fd, Socket *sock)
-{
- reactor = sock->reactor;
-
- socket = swReactor_get(reactor, _fd);
- bzero(socket, sizeof(swConnection));
- socket->fd = _fd;
- socket->object = this;
- socket->socket_type = sock->type;
-
- _sock_domain = sock->_sock_domain;
- _sock_type = sock->_sock_type;
- init();
-}
-
-bool Socket::connect(string host, int port, int flags)
-{
- //enable socks5 proxy
- if (socks5_proxy)
- {
- socks5_proxy->target_host = (char *) host.c_str();
- socks5_proxy->l_target_host = host.size();
- socks5_proxy->target_port = port;
-
- host = socks5_proxy->host;
- port = socks5_proxy->port;
- }
-
- //enable http proxy
- if (http_proxy)
- {
- http_proxy->target_host = (char *) host.c_str();
- http_proxy->l_target_host = host.size();
- http_proxy->target_port = port;
-
- host = http_proxy->proxy_host;
- port = http_proxy->proxy_port;
- }
-
- if (_sock_domain == AF_INET6 || _sock_domain == AF_INET)
- {
- if (port == -1)
- {
- swWarn("Socket of type AF_INET/AF_INET6 requires port argument");
- return false;
- }
- else if (port == 0 || port >= 65536)
- {
- swWarn("Invalid port argument[%d]", port);
- return false;
- }
- }
-
- if (unlikely(_cid && _cid != coroutine_get_current_cid()))
- {
- swWarn( "socket has already been bound to another coroutine.");
- return false;
- }
-
- int retval = 0;
- _host = host;
- _port = port;
-
- for (int i = 0; i < 2; i++)
- {
- if (_sock_domain == AF_INET)
- {
- socket->info.addr.inet_v4.sin_family = AF_INET;
- socket->info.addr.inet_v4.sin_port = htons(port);
-
- if (!inet_pton(AF_INET, _host.c_str(), & socket->info.addr.inet_v4.sin_addr))
- {
- _host = resolve(_host);
- if (_host.size() == 0)
- {
- return false;
- }
- continue;
- }
- else
- {
- socket->info.len = sizeof( socket->info.addr.inet_v4);
- retval = socket_connect(socket->fd, (struct sockaddr *) &socket->info.addr.inet_v4, socket->info.len);
- break;
- }
- }
- else if (_sock_domain == AF_INET6)
- {
- socket->info.addr.inet_v6.sin6_family = AF_INET6;
- socket->info.addr.inet_v6.sin6_port = htons(port);
-
- if (!inet_pton(AF_INET6, _host.c_str(), &socket->info.addr.inet_v6.sin6_addr))
- {
- _host = resolve(_host);
- if (_host.size() == 0)
- {
- return false;
- }
- continue;
- }
- else
- {
- socket->info.len = sizeof(socket->info.addr.inet_v6);
- retval = socket_connect(socket->fd, (struct sockaddr *) &socket->info.addr.inet_v6, socket->info.len);
- break;
- }
- }
- else if (_sock_domain == AF_UNIX)
- {
- if (_host.size() >= sizeof(socket->info.addr.un.sun_path))
- {
- return false;
- }
- socket->info.addr.un.sun_family = AF_UNIX;
- memcpy(&socket->info.addr.un.sun_path, _host.c_str(), _host.size());
- retval = socket_connect(socket->fd, (struct sockaddr *) &socket->info.addr.un,
- (socklen_t) (offsetof(struct sockaddr_un, sun_path) + _host.size()));
- break;
- }
- else
- {
- return false;
- }
- }
-
- if (retval == -1)
- {
- if (errno != EINPROGRESS)
- {
- _error: errCode = errno;
- return false;
- }
- if (!wait_events(SW_EVENT_WRITE))
- {
- goto _error;
- }
- yield();
- //Connection has timed out
- if (errCode == ETIMEDOUT)
- {
- errMsg = strerror(errCode);
- return false;
- }
- socklen_t len = sizeof(errCode);
- if (getsockopt(socket->fd, SOL_SOCKET, SO_ERROR, &errCode, &len) < 0 || errCode != 0)
- {
- errMsg = strerror(errCode);
- return false;
- }
- }
- socket->active = 1;
- //socks5 proxy
- if (socks5_proxy && socks5_handshake() == false)
- {
- return false;
- }
- //http proxy
- if (http_proxy && http_proxy_handshake() == false)
- {
- return false;
- }
- return true;
-}
-
-static void socket_onResolveCompleted(swAio_event *event)
-{
- Socket *sock = (Socket *) event->object;
- if (event->error != 0)
- {
- sock->errCode = SW_ERROR_DNSLOOKUP_RESOLVE_FAILED;
- }
- sock->resume();
-}
-
-static void socket_onTimeout(swTimer *timer, swTimer_node *tnode)
-{
- Socket *sock = (Socket *) tnode->data;
- sock->timer = NULL;
- sock->errCode = ETIMEDOUT;
- swDebug("socket[%d] timeout", sock->socket->fd);
- sock->reactor->del(sock->reactor, sock->socket->fd);
- sock->resume();
-}
-
-static int socket_onRead(swReactor *reactor, swEvent *event)
-{
- Socket *sock = (Socket *) event->socket->object;
- reactor->del(reactor, event->fd);
- sock->resume();
- return SW_OK;
-}
-
-static int socket_onWrite(swReactor *reactor, swEvent *event)
-{
- Socket *sock = (Socket *) event->socket->object;
- reactor->del(reactor, event->fd);
- sock->resume();
- return SW_OK;
-}
-
-ssize_t Socket::peek(void *__buf, size_t __n)
-{
- return swConnection_peek(socket, __buf, __n, 0);
-}
-
-ssize_t Socket::recv(void *__buf, size_t __n)
-{
- ssize_t retval = swConnection_recv(socket, __buf, __n, 0);
- if (retval >= 0)
- {
- return retval;
- }
-
- if (swConnection_error(errno) != SW_WAIT)
- {
- errCode = errno;
- return -1;
- }
-
- while (true)
- {
- int events = SW_EVENT_READ;
-#ifdef SW_USE_OPENSSL
- if (socket->ssl && socket->ssl_want_write)
- {
- events = SW_EVENT_WRITE;
- }
-#endif
- if (!wait_events(events))
- {
- return -1;
- }
- yield();
- if (errCode == ETIMEDOUT)
- {
- return -1;
- }
- retval = swConnection_recv(socket, __buf, __n, 0);
- if (retval < 0)
- {
- if (swConnection_error(errno) == SW_WAIT)
- {
- continue;
- }
- errCode = errno;
- }
- break;
- }
- return retval;
-}
-
-ssize_t Socket::recv_all(void *__buf, size_t __n)
-{
- ssize_t retval, total_bytes = 0;
- while (true)
- {
- retval = recv((char*) __buf + total_bytes, __n - total_bytes);
- if (retval <= 0)
- {
- if (total_bytes == 0)
- {
- total_bytes = retval;
- }
- break;
- }
- total_bytes += retval;
- if ((size_t) total_bytes == __n)
- {
- break;
- }
- }
- return total_bytes;
-}
-
-ssize_t Socket::send_all(const void *__buf, size_t __n)
-{
- ssize_t retval, total_bytes = 0;
- while (true)
- {
- retval = send((char*) __buf + total_bytes, __n - total_bytes);
- if (retval <= 0)
- {
- if (total_bytes == 0)
- {
- total_bytes = retval;
- }
- break;
- }
- total_bytes += retval;
- if ((size_t) total_bytes == __n)
- {
- break;
- }
- }
- return total_bytes;
-}
-
-ssize_t Socket::send(const void *__buf, size_t __n)
-{
- ssize_t retval = swConnection_send(socket, (void *) __buf, __n, 0);
- if (retval >= 0)
- {
- return retval;
- }
-
- if (swConnection_error(errno) != SW_WAIT)
- {
- errCode = errno;
- return -1;
- }
-
- while (true)
- {
- int events = SW_EVENT_WRITE;
-#ifdef SW_USE_OPENSSL
- if (socket->ssl && socket->ssl_want_read)
- {
- events = SW_EVENT_READ;
- }
-#endif
- if (!wait_events(events))
- {
- return -1;
- }
- yield();
- if (errCode == ETIMEDOUT)
- {
- return -1;
- }
- ssize_t retval = swConnection_send(socket, (void *) __buf, __n, 0);
- if (retval < 0)
- {
- if (swConnection_error(errno) == SW_WAIT)
- {
- continue;
- }
- errCode = errno;
- }
- break;
- }
-
- return retval;
-}
-
-void Socket::yield()
-{
- if (suspending)
- {
- swError("socket has already been bound to another coroutine.");
- }
- errCode = 0;
- if (_timeout > 0)
- {
- int ms = (int) (_timeout * 1000);
- if (SwooleG.timer.fd == 0)
- {
- swTimer_init(ms);
- }
- timer = SwooleG.timer.add(&SwooleG.timer, ms, 0, this, socket_onTimeout);
- }
- _cid = coroutine_get_current_cid();
- if (_cid == -1)
- {
- swError("Socket::yield() must be called in the coroutine.");
- }
- //suspend
- suspending = true;
- coroutine_yield(coroutine_get_by_id(_cid));
- suspending = false;
- //clear timer
- if (timer)
- {
- swTimer_del(&SwooleG.timer, timer);
- timer = nullptr;
- }
-}
-
-void Socket::resume()
-{
- coroutine_resume(coroutine_get_by_id(_cid));
-}
-
-bool Socket::bind(std::string address, int port)
-{
- bind_address = address;
- bind_port = port;
-
- struct sockaddr_storage sa_storage = { 0 };
- struct sockaddr *sock_type = (struct sockaddr*) &sa_storage;
-
- int retval;
- switch (_sock_domain)
- {
- case AF_UNIX:
- {
- struct sockaddr_un *sa = (struct sockaddr_un *) sock_type;
- sa->sun_family = AF_UNIX;
-
- if (bind_address.size() >= sizeof(sa->sun_path))
- {
- return false;
- }
- memcpy(&sa->sun_path, bind_address.c_str(), bind_address.size());
-
- retval = ::bind(socket->fd, (struct sockaddr *) sa,
- offsetof(struct sockaddr_un, sun_path) + bind_address.size());
- break;
- }
-
- case AF_INET:
- {
- struct sockaddr_in *sa = (struct sockaddr_in *) sock_type;
- sa->sin_family = AF_INET;
- sa->sin_port = htons((unsigned short) bind_port);
- if (!inet_aton(bind_address.c_str(), &sa->sin_addr))
- {
- return false;
- }
- retval = ::bind(socket->fd, (struct sockaddr *) sa, sizeof(struct sockaddr_in));
- break;
- }
-
- case AF_INET6:
- {
- struct sockaddr_in6 *sa = (struct sockaddr_in6 *) sock_type;
- sa->sin6_family = AF_INET6;
- sa->sin6_port = htons((unsigned short) bind_port);
-
- if (!inet_pton(AF_INET6, bind_address.c_str(), &sa->sin6_addr))
- {
- return false;
- }
- retval = ::bind(socket->fd, (struct sockaddr *) sa, sizeof(struct sockaddr_in6));
- break;
- }
- default:
- return false;
- }
-
- if (retval != 0)
- {
- errCode = errno;
- return false;
- }
-
- return true;
-}
-
-bool Socket::listen(int backlog)
-{
- _backlog = backlog;
- if (::listen(socket->fd, backlog) != 0)
- {
- errCode = errno;
- return false;
- }
- return true;
-}
-
-Socket* Socket::accept()
-{
- if (!wait_events(SW_EVENT_READ))
- {
- return nullptr;
- }
- yield();
- if (errCode == ETIMEDOUT)
- {
- return nullptr;
- }
- int conn;
- swSocketAddress client_addr;
- socklen_t client_addrlen = sizeof(client_addr);
-
-#ifdef HAVE_ACCEPT4
- conn = ::accept4(socket->fd, (struct sockaddr *) &client_addr, &client_addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
-#else
- conn = ::accept(socket->fd, (struct sockaddr *) &client_addr, &client_addrlen);
- if (conn >= 0)
- {
- swoole_fcntl_set_option(conn, 1, 1);
- }
-#endif
- if (conn >= 0)
- {
- return new Socket(conn, this);
- }
- else
- {
- errCode = errno;
- return nullptr;
- }
-}
-
-string Socket::resolve(string domain_name)
-{
- swAio_event ev;
- bzero(&ev, sizeof(swAio_event));
- ev.nbytes = SW_IP_MAX_LENGTH;
- ev.buf = sw_malloc(ev.nbytes);
- if (!ev.buf)
- {
- errCode = errno;
- return "";
- }
-
- memcpy(ev.buf, domain_name.c_str(), domain_name.size());
- ((char *) ev.buf)[domain_name.size()] = 0;
- ev.flags = _sock_domain;
- ev.type = SW_AIO_GETHOSTBYNAME;
- ev.object = this;
- ev.callback = socket_onResolveCompleted;
-
- if (SwooleAIO.init == 0)
- {
- swAio_init();
- }
-
- if (swAio_dispatch(&ev) < 0)
- {
- errCode = SwooleG.error;
- sw_free(ev.buf);
- return "";
- }
- /**
- * cannot timeout
- */
- double tmp_timeout = _timeout;
- _timeout = -1;
- yield();
- _timeout = tmp_timeout;
-
- if (errCode == SW_ERROR_DNSLOOKUP_RESOLVE_FAILED)
- {
- errMsg = hstrerror(ev.error);
- return "";
- }
- else
- {
- string addr((char *) ev.buf);
- sw_free(ev.buf);
- return addr;
- }
-}
-
-bool Socket::shutdown(int __how)
-{
- if (!socket || socket->closed)
- {
- return false;
- }
- if (__how == SHUT_RD)
- {
- if (shutdown_read || shutdow_rw || ::shutdown(socket->fd, SHUT_RD))
- {
- return false;
- }
- else
- {
- shutdown_read = 1;
- return true;
- }
- }
- else if (__how == SHUT_WR)
- {
- if (shutdown_write || shutdow_rw || ::shutdown(socket->fd, SHUT_RD) < 0)
- {
- return false;
- }
- else
- {
- shutdown_write = 1;
- return true;
- }
- }
- else if (__how == SHUT_RDWR)
- {
- if (shutdow_rw || ::shutdown(socket->fd, SHUT_RDWR) < 0)
- {
- return false;
- }
- else
- {
- shutdown_read = 1;
- return true;
- }
- }
- else
- {
- return false;
- }
-}
-
-bool Socket::close()
-{
- if (socket == NULL || socket->closed)
- {
- return false;
- }
- socket->closed = 1;
-
- int fd = socket->fd;
-
- if (_sock_type == SW_SOCK_UNIX_DGRAM)
- {
- unlink(socket->info.addr.un.sun_path);
- }
-
-#ifdef SW_USE_OPENSSL
- if (open_ssl && ssl_context)
- {
- if (socket->ssl)
- {
- swSSL_close(socket);
- }
- swSSL_free_context(ssl_context);
- if (ssl_option.cert_file)
- {
- sw_free(ssl_option.cert_file);
- }
- if (ssl_option.key_file)
- {
- sw_free(ssl_option.key_file);
- }
- if (ssl_option.passphrase)
- {
- sw_free(ssl_option.passphrase);
- }
-#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
- if (ssl_option.tls_host_name)
- {
- sw_free(ssl_option.tls_host_name);
- }
-#endif
- if (ssl_option.cafile)
- {
- sw_free(ssl_option.cafile);
- }
- if (ssl_option.capath)
- {
- sw_free(ssl_option.capath);
- }
- }
-#endif
- if (_sock_type == SW_SOCK_UNIX_DGRAM)
- {
- unlink(socket->info.addr.un.sun_path);
- }
- if (timer)
- {
- swTimer_del(&SwooleG.timer, timer);
- timer = NULL;
- }
- socket->active = 0;
- ::close(fd);
- return true;
-}
-
-#ifdef SW_USE_OPENSSL
-bool Socket::ssl_handshake()
-{
- if (socket->ssl)
- {
- return false;
- }
-
- ssl_context = swSSL_get_context(&ssl_option);
- if (ssl_context == NULL)
- {
- return false;
- }
-
- if (ssl_option.verify_peer)
- {
- if (swSSL_set_capath(&ssl_option, ssl_context) < 0)
- {
- return false;
- }
- }
-
- socket->ssl_send = 1;
-#if defined(SW_USE_HTTP2) && defined(SW_USE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10002000L
- if (http2)
- {
- if (SSL_CTX_set_alpn_protos(ssl_context, (const unsigned char *) "\x02h2", 3) < 0)
- {
- return false;
- }
- }
-#endif
-
- if (swSSL_create(socket, ssl_context, SW_SSL_CLIENT) < 0)
- {
- return false;
- }
-#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
- if (ssl_option.tls_host_name)
- {
- SSL_set_tlsext_host_name(socket->ssl, ssl_option.tls_host_name);
- }
-#endif
-
- while (true)
- {
- int retval = swSSL_connect(socket);
- if (retval < 0)
- {
- errCode = SwooleG.error;
- return false;
- }
- if (socket->ssl_state == SW_SSL_STATE_WAIT_STREAM)
- {
- int events = socket->ssl_want_write ? SW_EVENT_WRITE : SW_EVENT_READ;
- if (!wait_events(events))
- {
- return false;
- }
- yield();
- if (errCode == ETIMEDOUT)
- {
- return false;
- }
- }
- else if (socket->ssl_state == SW_SSL_STATE_READY)
- {
- return true;
- }
- }
-
- if (socket->ssl_state == SW_SSL_STATE_READY && ssl_option.verify_peer)
- {
- if (ssl_verify(ssl_option.allow_self_signed) < 0)
- {
- return false;
- }
- }
- return true;
-}
-
-int Socket::ssl_verify(bool allow_self_signed)
-{
- if (swSSL_verify(socket, allow_self_signed) < 0)
- {
- return SW_ERR;
- }
- if (ssl_option.tls_host_name && swSSL_check_host(socket, ssl_option.tls_host_name) < 0)
- {
- return SW_ERR;
- }
- return SW_OK;
-}
-#endif
-
-bool Socket::sendfile(char *filename, off_t offset, size_t length)
-{
- int file_fd = open(filename, O_RDONLY);
- if (file_fd < 0)
- {
- swSysError("open(%s) failed.", filename);
- return false;
- }
-
- if (length == 0)
- {
- struct stat file_stat;
- if (::fstat(file_fd, &file_stat) < 0)
- {
- swSysError("fstat(%s) failed.", filename);
- ::close(file_fd);
- return false;
- }
- length = file_stat.st_size;
- }
- else
- {
- // total length of the file
- length = offset + length;
- }
-
- int n, sendn;
- while ((size_t) offset < length)
- {
- sendn = (length - offset > SW_SENDFILE_CHUNK_SIZE) ? SW_SENDFILE_CHUNK_SIZE : length - offset;
-#ifdef SW_USE_OPENSSL
- if (socket->ssl)
- {
- n = swSSL_sendfile(socket, file_fd, &offset, sendn);
- }
- else
-#endif
- {
- n = ::swoole_sendfile(socket->fd, file_fd, &offset, sendn);
- }
- if (n > 0)
- {
- continue;
- }
- else if (n == 0)
- {
- swWarn("sendfile return zero.");
- return false;
- }
- else if (errno != EAGAIN)
- {
- swSysError("sendfile(%d, %s) failed.", socket->fd, filename);
- _error: errCode = errno;
- ::close(file_fd);
- return false;
- }
- if (!wait_events(SW_EVENT_WRITE))
- {
- goto _error;
- }
- yield();
- if (errCode == ETIMEDOUT)
- {
- goto _error;
- }
- }
- ::close(file_fd);
- return true;
-}
-
-int Socket::sendto(char *address, int port, char *data, int len)
-{
- if (type == SW_SOCK_UDP)
- {
- return swSocket_udp_sendto(socket->fd, address, port, data, len);
- }
- else if (type == SW_SOCK_UDP6)
- {
- return swSocket_udp_sendto6(socket->fd, address, port, data, len);
- }
- else
- {
- swWarn("only supports SWOOLE_SOCK_UDP or SWOOLE_SOCK_UDP6.");
- return -1;
- }
-}
-
-int Socket::recvfrom(void *__buf, size_t __n, char *address, int *port)
-{
- socket->info.len = sizeof(socket->info.addr);
- int retval;
-
- _recv: retval = ::recvfrom(socket->fd, __buf, __n, 0, (struct sockaddr *) &socket->info.addr, &socket->info.len);
- if (retval < 0)
- {
- if (errno == EINTR)
- {
- goto _recv;
- }
- else if (swConnection_error(errno) == SW_WAIT)
- {
- if (!wait_events(SW_EVENT_READ))
- {
- return -1;
- }
- yield();
- if (errCode == ETIMEDOUT)
- {
- return -1;
- }
- retval = ::recvfrom(socket->fd, __buf, __n, 0, (struct sockaddr *) &socket->info.addr, &socket->info.len);
- if (retval < 0)
- {
- errCode = errno;
- }
- else
- {
- strcpy(address, swConnection_get_ip(socket));
- *port = swConnection_get_port(socket);
- }
- }
- else
- {
- errCode = errno;
- }
- }
- return retval;
-}
-
-/**
- * recv packet with protocol
- */
-ssize_t Socket::recv_packet()
-{
- get_buffer();
- ssize_t buf_len = SW_BUFFER_SIZE_STD;
- ssize_t retval;
-
- if (open_length_check)
- {
- uint32_t header_len;
-
- _get_header_len: header_len = protocol.package_length_offset + protocol.package_length_size;
- if (buffer->length > 0)
- {
- if (buffer->length < header_len)
- {
- goto _recv_header;
- }
- else
- {
- goto _get_length;
- }
- }
-
- _recv_header: retval = recv(buffer->str + buffer->length, header_len - buffer->length);
- if (retval <= 0)
- {
- return 0;
- }
- else if (retval < 0 || retval != header_len)
- {
- return 0;
- }
- else
- {
- buffer->length += retval;
- }
-
- _get_length: buf_len = protocol.get_package_length(&protocol, socket, buffer->str, (uint32_t) buffer->length);
- swDebug("packet_len=%ld, length=%ld", buf_len, buffer->length);
- //error package
- if (buf_len < 0)
- {
- return 0;
- }
- else if (buf_len == 0)
- {
- header_len = protocol.real_header_length;
- goto _recv_header;
- }
- //empty package
- else if (buf_len == header_len)
- {
- buffer->length = 0;
- return header_len;
- }
- else if (buf_len > protocol.package_max_length)
- {
- swoole_error_log(SW_LOG_WARNING, SW_ERROR_PACKAGE_LENGTH_TOO_LARGE, "packet[length=%d] is too big.", (int )buf_len);
- return 0;
- }
-
- if ((size_t) buf_len == buffer->length)
- {
- buffer->length = 0;
- return buf_len;
- }
- else if ((size_t) buf_len < buffer->length)
- {
- buffer->length = buffer->length - buf_len;
- memmove(buffer->str, buffer->str + buf_len, buffer->length);
- goto _get_header_len;
- }
-
- if ((size_t) buf_len >= buffer->size)
- {
- if (swString_extend(buffer, buf_len) < 0)
- {
- buffer->length = 0;
- return -1;
- }
- }
-
- retval = recv_all(buffer->str + buffer->length, buf_len - buffer->length);
- if (retval > 0)
- {
- buffer->length += retval;
- if (buffer->length != (size_t) buf_len)
- {
- retval = 0;
- }
- else
- {
- buffer->length = 0;
- return buf_len;
- }
- }
- }
- else if (open_eof_check)
- {
- int eof = -1;
- char *buf;
-
- if (buffer->length > 0)
- {
- goto find_eof;
- }
-
- while (1)
- {
- buf = buffer->str + buffer->length;
- buf_len = buffer->size - buffer->length;
-
- if (buf_len > SW_BUFFER_SIZE_BIG)
- {
- buf_len = SW_BUFFER_SIZE_BIG;
- }
-
- retval = recv(buf, buf_len);
- if (retval < 0)
- {
- buffer->length = 0;
- return -1;
- }
- else if (retval == 0)
- {
- buffer->length = 0;
- return 0;
- }
-
- buffer->length += retval;
-
- if (buffer->length < protocol.package_eof_len)
- {
- continue;
- }
-
- find_eof: eof = swoole_strnpos(buffer->str, buffer->length, protocol.package_eof, protocol.package_eof_len);
- if (eof >= 0)
- {
- eof += protocol.package_eof_len;
- if (buffer->length > (uint32_t) eof)
- {
- buffer->length -= eof;
- memmove(buffer->str, buffer->str + eof, buffer->length);
- }
- else
- {
- buffer->length = 0;
- }
- return eof;
- }
- else
- {
- if (buffer->length == protocol.package_max_length)
- {
- swWarn("no package eof");
- buffer->length = 0;
- return -1;
- }
- else if (buffer->length == buffer->size)
- {
- if (buffer->size < protocol.package_max_length)
- {
- size_t new_size = buffer->size * 2;
- if (new_size > protocol.package_max_length)
- {
- new_size = protocol.package_max_length;
- }
- if (swString_extend(buffer, new_size) < 0)
- {
- buffer->length = 0;
- return -1;
- }
- }
- }
- }
- }
- buffer->length = 0;
- }
- else
- {
- return -1;
- }
-
- return retval;
-}
-
-swString* Socket::get_buffer()
-{
- if (unlikely(buffer == nullptr))
- {
- buffer = swString_new(SW_BUFFER_SIZE_STD);
- }
- return buffer;
-}
-
-Socket::~Socket()
-{
- if (!socket->closed)
- {
- close();
- }
- if (socket->out_buffer)
- {
- swBuffer_free(socket->out_buffer);
- socket->out_buffer = NULL;
- }
- if (socket->in_buffer)
- {
- swBuffer_free(socket->in_buffer);
- socket->in_buffer = NULL;
- }
- if (buffer)
- {
- swString_free(buffer);
- }
- bzero(socket, sizeof(swConnection));
- socket->removed = 1;
-}