diff options
Diffstat (limited to 'node_modules/uws/src/Networking.h')
-rw-r--r-- | node_modules/uws/src/Networking.h | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/node_modules/uws/src/Networking.h b/node_modules/uws/src/Networking.h new file mode 100644 index 0000000..7ae88a2 --- /dev/null +++ b/node_modules/uws/src/Networking.h @@ -0,0 +1,259 @@ +// the purpose of this header should be to provide SSL and networking wrapped in a common interface +// it should allow cross-platform networking and SSL and also easy usage of mTCP and similar tech + +#ifndef NETWORKING_UWS_H +#define NETWORKING_UWS_H + +#include <openssl/opensslv.h> +#if OPENSSL_VERSION_NUMBER < 0x10100000L +#define SSL_CTX_up_ref(x) x->references++ +#define SSL_up_ref(x) x->references++ +#endif + +#ifndef __linux +#define MSG_NOSIGNAL 0 +#else +#include <endian.h> +#endif + +#ifdef __APPLE__ +#include <libkern/OSByteOrder.h> +#define htobe64(x) OSSwapHostToBigInt64(x) +#define be64toh(x) OSSwapBigToHostInt64(x) +#endif + +#ifdef _WIN32 +#define NOMINMAX +#include <WinSock2.h> +#include <Ws2tcpip.h> +#pragma comment(lib, "ws2_32.lib") +#define SHUT_WR SD_SEND +#ifdef __MINGW32__ +// Windows has always been tied to LE +#define htobe64(x) __builtin_bswap64(x) +#define be64toh(x) __builtin_bswap64(x) +#else +#define __thread __declspec(thread) +#define htobe64(x) htonll(x) +#define be64toh(x) ntohll(x) +#define pthread_t DWORD +#define pthread_self GetCurrentThreadId +#endif +#define WIN32_EXPORT __declspec(dllexport) + +inline void close(SOCKET fd) {closesocket(fd);} +inline int setsockopt(SOCKET fd, int level, int optname, const void *optval, socklen_t optlen) { + return setsockopt(fd, level, optname, (const char *) optval, optlen); +} + +inline SOCKET dup(SOCKET socket) { + WSAPROTOCOL_INFOW pi; + if (WSADuplicateSocketW(socket, GetCurrentProcessId(), &pi) == SOCKET_ERROR) { + return INVALID_SOCKET; + } + return WSASocketW(pi.iAddressFamily, pi.iSocketType, pi.iProtocol, &pi, 0, WSA_FLAG_OVERLAPPED); +} +#else +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <netdb.h> +#include <unistd.h> +#include <arpa/inet.h> +#include <cstring> +#define SOCKET_ERROR -1 +#define INVALID_SOCKET -1 +#define WIN32_EXPORT +#endif + +#include "Backend.h" +#include <openssl/ssl.h> +#include <csignal> +#include <vector> +#include <string> +#include <mutex> +#include <algorithm> +#include <memory> + +namespace uS { + +// todo: mark sockets nonblocking in these functions +// todo: probably merge this Context with the TLS::Context for same interface for SSL and non-SSL! +struct Context { + +#ifdef USE_MTCP + mtcp_context *mctx; +#endif + + Context() { + // mtcp_create_context +#ifdef USE_MTCP + mctx = mtcp_create_context(0); // cpu index? +#endif + } + + ~Context() { +#ifdef USE_MTCP + mtcp_destroy_context(mctx); +#endif + } + + // returns INVALID_SOCKET on error + uv_os_sock_t acceptSocket(uv_os_sock_t fd) { + uv_os_sock_t acceptedFd; +#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) + // Linux, FreeBSD + acceptedFd = accept4(fd, nullptr, nullptr, SOCK_CLOEXEC | SOCK_NONBLOCK); +#else + // Windows, OS X + acceptedFd = accept(fd, nullptr, nullptr); +#endif + +#ifdef __APPLE__ + if (acceptedFd != INVALID_SOCKET) { + int noSigpipe = 1; + setsockopt(acceptedFd, SOL_SOCKET, SO_NOSIGPIPE, &noSigpipe, sizeof(int)); + } +#endif + return acceptedFd; + } + + // returns INVALID_SOCKET on error + uv_os_sock_t createSocket(int domain, int type, int protocol) { + int flags = 0; +#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) + flags = SOCK_CLOEXEC | SOCK_NONBLOCK; +#endif + + uv_os_sock_t createdFd = socket(domain, type | flags, protocol); + +#ifdef __APPLE__ + if (createdFd != INVALID_SOCKET) { + int noSigpipe = 1; + setsockopt(createdFd, SOL_SOCKET, SO_NOSIGPIPE, &noSigpipe, sizeof(int)); + } +#endif + + return createdFd; + } + + void closeSocket(uv_os_sock_t fd) { +#ifdef _WIN32 + closesocket(fd); +#else + close(fd); +#endif + } + + bool wouldBlock() { +#ifdef _WIN32 + return WSAGetLastError() == WSAEWOULDBLOCK; +#else + return errno == EWOULDBLOCK;// || errno == EAGAIN; +#endif + } +}; + +namespace TLS { + +class WIN32_EXPORT Context { +private: + SSL_CTX *context = nullptr; + std::shared_ptr<std::string> password; + + static int passwordCallback(char *buf, int size, int rwflag, void *u) + { + std::string *password = (std::string *) u; + int length = std::min<int>(size, password->length()); + memcpy(buf, password->data(), length); + buf[length] = '\0'; + return length; + } + +public: + friend Context WIN32_EXPORT createContext(std::string certChainFileName, std::string keyFileName, std::string keyFilePassword); + Context(SSL_CTX *context) : context(context) { + + } + + Context() = default; + Context(const Context &other); + Context &operator=(const Context &other); + ~Context(); + operator bool() { + return context; + } + + SSL_CTX *getNativeContext() { + return context; + } +}; + +Context WIN32_EXPORT createContext(std::string certChainFileName, std::string keyFileName, std::string keyFilePassword = std::string()); + +} + +struct Socket; + +// NodeData is like a Context, maybe merge them? +struct WIN32_EXPORT NodeData { + char *recvBufferMemoryBlock; + char *recvBuffer; + int recvLength; + Loop *loop; + uS::Context *netContext; + void *user = nullptr; + static const int preAllocMaxSize = 1024; + char **preAlloc; + SSL_CTX *clientContext; + + Async *async = nullptr; + pthread_t tid; + + std::recursive_mutex *asyncMutex; + std::vector<Poll *> transferQueue; + std::vector<Poll *> changePollQueue; + static void asyncCallback(Async *async); + + static int getMemoryBlockIndex(size_t length) { + return (length >> 4) + bool(length & 15); + } + + char *getSmallMemoryBlock(int index) { + if (preAlloc[index]) { + char *memory = preAlloc[index]; + preAlloc[index] = nullptr; + return memory; + } else { + return new char[index << 4]; + } + } + + void freeSmallMemoryBlock(char *memory, int index) { + if (!preAlloc[index]) { + preAlloc[index] = memory; + } else { + delete [] memory; + } + } + +public: + void addAsync() { + async = new Async(loop); + async->setData(this); + async->start(NodeData::asyncCallback); + } + + void clearPendingPollChanges(Poll *p) { + asyncMutex->lock(); + changePollQueue.erase( + std::remove(changePollQueue.begin(), changePollQueue.end(), p), + changePollQueue.end() + ); + asyncMutex->unlock(); + } +}; + +} + +#endif // NETWORKING_UWS_H |