Commit d8c542d1 authored by Alex Hultman's avatar Alex Hultman

Restore listen timer fix

parent fd7a2911
......@@ -137,23 +137,19 @@ Group<isServer>::Group(int extensionOptions, Hub *hub, uS::NodeData *nodeData) :
template <bool isServer>
void Group<isServer>::stopListening() {
if (isServer) {
uS::ListenData *listenData = (uS::ListenData *) user;
if (listenData) {
if (listenData) {
uS::Socket *s = (uS::Socket *) listenData;
s->closeSocket<uS::ListenData>();
} else if (listenData->listenTimer) {
uv_os_sock_t fd = listenData->sock;
listenData->listenTimer->stop();
listenData->nodeData->netContext->closeSocket(fd);
SSL *ssl = listenData->ssl;
if (ssl) {
SSL_free(ssl);
}
if (user) {
// todo: we should allow one group to listen to many ports!
uS::ListenSocket *listenSocket = (uS::ListenSocket *) user;
listenData->listenTimer->close();
if (listenSocket->timer) {
listenSocket->timer->stop();
listenSocket->timer->close();
}
listenSocket->closeSocket<uS::ListenSocket>();
// mark as stopped listening (extra care?)
user = nullptr;
}
}
......
// 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
......@@ -75,6 +78,7 @@ inline SOCKET dup(SOCKET socket) {
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
......@@ -96,13 +100,22 @@ struct Context {
// 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
return accept4(fd, nullptr, nullptr, SOCK_CLOEXEC | SOCK_NONBLOCK);
acceptedFd = accept4(fd, nullptr, nullptr, SOCK_CLOEXEC | SOCK_NONBLOCK);
#else
// Windows, OS X
return accept(fd, nullptr, nullptr);
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
......@@ -112,7 +125,16 @@ struct Context {
flags = SOCK_CLOEXEC | SOCK_NONBLOCK;
#endif
return socket(domain, type | flags, protocol);
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) {
......@@ -173,6 +195,7 @@ Context createContext(std::string certChainFileName, std::string keyFileName, st
struct Socket;
// NodeData is like a Context, maybe merge them?
struct WIN32_EXPORT NodeData {
char *recvBufferMemoryBlock;
char *recvBuffer;
......
......@@ -34,6 +34,8 @@ public:
template <uS::Socket *I(Socket *s), void C(Socket *p, bool error)>
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;
......@@ -42,16 +44,11 @@ public:
return nullptr;
}
uv_os_sock_t fd = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (fd == -1) {
uv_os_sock_t fd = netContext->createSocket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (fd == INVALID_SOCKET) {
return nullptr;
}
#ifdef __APPLE__
int noSigpipe = 1;
setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &noSigpipe, sizeof(int));
#endif
::connect(fd, result->ai_addr, result->ai_addrlen);
freeaddrinfo(result);
......@@ -72,62 +69,51 @@ public:
template <void A(Socket *s)>
static void accept_poll_cb(Poll *p, int status, int events) {
ListenData *listenData = (ListenData *) p;
ListenSocket *listenData = (ListenSocket *) p;
accept_cb<A, false>(listenData);
}
template <void A(Socket *s)>
static void accept_timer_cb(Timer *p) {
ListenData *listenData = (ListenData *) p->getData();
ListenSocket *listenData = (ListenSocket *) p->getData();
accept_cb<A, true>(listenData);
}
template <void A(Socket *s), bool TIMER>
static void accept_cb(ListenData *listenData) {
uv_os_sock_t serverFd = listenData->sock;
Context *netContext = listenData->nodeData->netContext;
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()) {
// listenData->listenPoll->stop(listenData->nodeData->loop);
// listenData->listenPoll->close(listenData->nodeData->loop);
// listenData->listenPoll = nullptr;
// listenData->listenTimer = new Timer(listenData->nodeData->loop);
// listenData->listenTimer->setData(listenData);
// listenData->listenTimer->start(accept_timer_cb<A>, 1000, 1000);
// }
// return;
// } else if (TIMER) {
// listenData->listenTimer->stop();
// listenData->listenTimer->close();
// listenData->listenTimer = nullptr;
// // todo: broken
// //listenData->listenPoll = new Poll(listenData->nodeData->loop, serverFd);
// //listenData->listenPoll->setData(listenData);
// listenData->listenPoll->setCb(accept_poll_cb<A>);
// listenData->listenPoll->start(listenData->nodeData->loop, listenData, UV_READABLE);
// }
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<A>, 1000, 1000);
}
return;
} else if (TIMER) {
listenSocket->timer->stop();
listenSocket->timer->close();
listenSocket->timer = nullptr;
listenSocket->setCb(accept_poll_cb<A>);
listenSocket->start(listenSocket->nodeData->loop, listenSocket, UV_READABLE);
}
do {
#ifdef __APPLE__
int noSigpipe = 1;
setsockopt(clientFd, SOL_SOCKET, SO_NOSIGPIPE, &noSigpipe, sizeof(int));
#endif
SSL *ssl = nullptr;
if (listenData->sslContext) {
ssl = SSL_new(listenData->sslContext.getNativeContext());
if (listenSocket->sslContext) {
ssl = SSL_new(listenSocket->sslContext.getNativeContext());
SSL_set_accept_state(ssl);
}
Socket *socket = new Socket(listenData->nodeData, listenData->nodeData->loop, clientFd, 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);
......@@ -190,21 +176,16 @@ public:
return true;
}
ListenData *listenData = new ListenData(nodeData, loop, listenFd, nullptr);
listenData->sslContext = sslContext;
listenData->nodeData = nodeData;
listenData->setCb(accept_poll_cb<A>);
listenData->start(loop, listenData, UV_READABLE);
ListenSocket *listenSocket = new ListenSocket(nodeData, loop, listenFd, nullptr);
listenSocket->sslContext = sslContext;
listenSocket->nodeData = nodeData;
// why is this needed?
listenData->sock = listenFd;
listenData->ssl = nullptr;
listenSocket->setCb(accept_poll_cb<A>);
listenSocket->start(loop, listenSocket, UV_READABLE);
// should be vector of listen data! one group can have many listeners!
nodeData->user = listenData;
nodeData->user = listenSocket;
freeaddrinfo(result);
return false;
}
......
......@@ -473,14 +473,13 @@ struct WIN32_EXPORT Socket : Poll {
}
};
struct ListenData : Socket {
struct ListenSocket : Socket {
ListenData(NodeData *nodeData, Loop *loop, uv_os_sock_t fd, SSL *ssl) : Socket(nodeData, loop, fd, ssl) {
ListenSocket(NodeData *nodeData, Loop *loop, uv_os_sock_t fd, SSL *ssl) : Socket(nodeData, loop, fd, ssl) {
}
Timer *listenTimer = nullptr;
uv_os_sock_t sock;
Timer *timer = nullptr;
uS::TLS::Context sslContext;
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment