From 67fdec20726e48ba3a934cb25bb30d47ec4a4f29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yaroslav=20De=20La=20Pe=C3=B1a=20Smirnov?= Date: Wed, 29 Nov 2017 11:44:34 +0300 Subject: Initial commit, version 0.5.3 --- node_modules/uws/src/Node.h | 198 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 node_modules/uws/src/Node.h (limited to 'node_modules/uws/src/Node.h') diff --git a/node_modules/uws/src/Node.h b/node_modules/uws/src/Node.h new file mode 100644 index 0000000..3c4d3be --- /dev/null +++ b/node_modules/uws/src/Node.h @@ -0,0 +1,198 @@ +#ifndef NODE_UWS_H +#define NODE_UWS_H + +#include "Socket.h" +#include +#include + +namespace uS { + +enum ListenOptions : int { + REUSE_PORT = 1, + ONLY_IPV4 = 2 +}; + +class WIN32_EXPORT Node { +private: + template + static void connect_cb(Poll *p, int status, int events) { + C((Socket *) p, status < 0); + } + + template + static void accept_poll_cb(Poll *p, int status, int events) { + ListenSocket *listenData = (ListenSocket *) p; + accept_cb(listenData); + } + + template + static void accept_timer_cb(Timer *p) { + ListenSocket *listenData = (ListenSocket *) p->getData(); + accept_cb(listenData); + } + + template + static void accept_cb(ListenSocket *listenSocket) { + uv_os_sock_t serverFd = listenSocket->getFd(); + Context *netContext = listenSocket->nodeData->netContext; + uv_os_sock_t clientFd = netContext->acceptSocket(serverFd); + if (clientFd == INVALID_SOCKET) { + /* + * If accept is failing, the pending connection won't be removed and the + * polling will cause the server to spin, using 100% cpu. Switch to a timer + * event instead to avoid this. + */ + if (!TIMER && !netContext->wouldBlock()) { + listenSocket->stop(listenSocket->nodeData->loop); + + listenSocket->timer = new Timer(listenSocket->nodeData->loop); + listenSocket->timer->setData(listenSocket); + listenSocket->timer->start(accept_timer_cb, 1000, 1000); + } + return; + } else if (TIMER) { + listenSocket->timer->stop(); + listenSocket->timer->close(); + listenSocket->timer = nullptr; + + listenSocket->setCb(accept_poll_cb); + listenSocket->start(listenSocket->nodeData->loop, listenSocket, UV_READABLE); + } + do { + SSL *ssl = nullptr; + if (listenSocket->sslContext) { + ssl = SSL_new(listenSocket->sslContext.getNativeContext()); + SSL_set_accept_state(ssl); + } + + Socket *socket = new Socket(listenSocket->nodeData, listenSocket->nodeData->loop, clientFd, ssl); + socket->setPoll(UV_READABLE); + A(socket); + } while ((clientFd = netContext->acceptSocket(serverFd)) != INVALID_SOCKET); + } + +protected: + Loop *loop; + NodeData *nodeData; + std::recursive_mutex asyncMutex; + +public: + Node(int recvLength = 1024, int prePadding = 0, int postPadding = 0, bool useDefaultLoop = false); + ~Node(); + void run(); + + Loop *getLoop() { + return loop; + } + + template + Socket *connect(const char *hostname, int port, bool secure, NodeData *nodeData) { + Context *netContext = nodeData->netContext; + + addrinfo hints, *result; + memset(&hints, 0, sizeof(addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + if (getaddrinfo(hostname, std::to_string(port).c_str(), &hints, &result) != 0) { + return nullptr; + } + + uv_os_sock_t fd = netContext->createSocket(result->ai_family, result->ai_socktype, result->ai_protocol); + if (fd == INVALID_SOCKET) { + freeaddrinfo(result); + return nullptr; + } + + ::connect(fd, result->ai_addr, result->ai_addrlen); + freeaddrinfo(result); + + SSL *ssl = nullptr; + if (secure) { + ssl = SSL_new(nodeData->clientContext); + SSL_set_connect_state(ssl); + SSL_set_tlsext_host_name(ssl, hostname); + } + + Socket initialSocket(nodeData, getLoop(), fd, ssl); + uS::Socket *socket = I(&initialSocket); + + socket->setCb(connect_cb); + socket->start(loop, socket, socket->setPoll(UV_WRITABLE)); + return socket; + } + + // todo: hostname, backlog + template + bool listen(const char *host, int port, uS::TLS::Context sslContext, int options, uS::NodeData *nodeData, void *user) { + addrinfo hints, *result; + memset(&hints, 0, sizeof(addrinfo)); + + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + Context *netContext = nodeData->netContext; + + if (getaddrinfo(host, std::to_string(port).c_str(), &hints, &result)) { + return true; + } + + uv_os_sock_t listenFd = SOCKET_ERROR; + addrinfo *listenAddr; + if ((options & uS::ONLY_IPV4) == 0) { + for (addrinfo *a = result; a && listenFd == SOCKET_ERROR; a = a->ai_next) { + if (a->ai_family == AF_INET6) { + listenFd = netContext->createSocket(a->ai_family, a->ai_socktype, a->ai_protocol); + listenAddr = a; + } + } + } + + for (addrinfo *a = result; a && listenFd == SOCKET_ERROR; a = a->ai_next) { + if (a->ai_family == AF_INET) { + listenFd = netContext->createSocket(a->ai_family, a->ai_socktype, a->ai_protocol); + listenAddr = a; + } + } + + if (listenFd == SOCKET_ERROR) { + freeaddrinfo(result); + return true; + } + +#ifdef __linux +#ifdef SO_REUSEPORT + if (options & REUSE_PORT) { + int optval = 1; + setsockopt(listenFd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)); + } +#endif +#endif + + int enabled = true; + setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, &enabled, sizeof(enabled)); + + if (bind(listenFd, listenAddr->ai_addr, listenAddr->ai_addrlen) || ::listen(listenFd, 512)) { + netContext->closeSocket(listenFd); + freeaddrinfo(result); + return true; + } + + ListenSocket *listenSocket = new ListenSocket(nodeData, loop, listenFd, nullptr); + listenSocket->sslContext = sslContext; + listenSocket->nodeData = nodeData; + + listenSocket->setCb(accept_poll_cb); + listenSocket->start(loop, listenSocket, UV_READABLE); + + // should be vector of listen data! one group can have many listeners! + nodeData->user = listenSocket; + + freeaddrinfo(result); + return false; + } +}; + +} + +#endif // NODE_UWS_H -- cgit v1.2.3