blob: 4908b9043edf34c727a7fbd4b335f0338b2f31cf [file] [log] [blame]
Austin Schuh9d823002019-04-14 12:53:17 -07001// Copyright (c) 2013-2017, Matt Godbolt
Austin Schuh24adb6b2015-09-06 17:37:40 -07002// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are met:
6//
7// Redistributions of source code must retain the above copyright notice, this
8// list of conditions and the following disclaimer.
9//
10// Redistributions in binary form must reproduce the above copyright notice,
11// this list of conditions and the following disclaimer in the documentation
12// and/or other materials provided with the distribution.
13//
14// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24// POSSIBILITY OF SUCH DAMAGE.
25
Austin Schuh9d823002019-04-14 12:53:17 -070026#include "internal/Config.h"
Austin Schuh24adb6b2015-09-06 17:37:40 -070027#include "internal/LogStream.h"
28
29#include "seasocks/Connection.h"
30#include "seasocks/Logger.h"
31#include "seasocks/Server.h"
32#include "seasocks/PageHandler.h"
33#include "seasocks/StringUtil.h"
34#include "seasocks/util/Json.h"
35
36#include <netinet/in.h>
37#include <netinet/tcp.h>
38
39#include <sys/epoll.h>
40#include <sys/eventfd.h>
41#include <sys/ioctl.h>
42#include <sys/socket.h>
43#include <sys/syscall.h>
Austin Schuh9d823002019-04-14 12:53:17 -070044#include <sys/un.h>
Austin Schuh24adb6b2015-09-06 17:37:40 -070045
46#include <memory>
47#include <stdexcept>
Austin Schuh9d823002019-04-14 12:53:17 -070048#include <cstring>
Austin Schuh24adb6b2015-09-06 17:37:40 -070049#include <unistd.h>
50
51namespace {
52
53struct EventBits {
54 uint32_t bits;
Austin Schuh9d823002019-04-14 12:53:17 -070055 explicit EventBits(uint32_t b)
56 : bits(b) {
57 }
Austin Schuh24adb6b2015-09-06 17:37:40 -070058};
59
Austin Schuh9d823002019-04-14 12:53:17 -070060std::ostream& operator<<(std::ostream& o, const EventBits& b) {
Austin Schuh24adb6b2015-09-06 17:37:40 -070061 uint32_t bits = b.bits;
Austin Schuh9d823002019-04-14 12:53:17 -070062#define DO_BIT(NAME) \
63 do { \
64 if (bits & (NAME)) { \
65 if (bits != b.bits) { \
66 o << ", "; \
67 } \
68 o << #NAME; \
69 bits &= ~(NAME); \
70 } \
71 } while (0)
Austin Schuh24adb6b2015-09-06 17:37:40 -070072 DO_BIT(EPOLLIN);
73 DO_BIT(EPOLLPRI);
74 DO_BIT(EPOLLOUT);
75 DO_BIT(EPOLLRDNORM);
76 DO_BIT(EPOLLRDBAND);
77 DO_BIT(EPOLLWRNORM);
78 DO_BIT(EPOLLWRBAND);
79 DO_BIT(EPOLLMSG);
80 DO_BIT(EPOLLERR);
81 DO_BIT(EPOLLHUP);
82#ifdef EPOLLRDHUP
83 DO_BIT(EPOLLRDHUP);
84#endif
85 DO_BIT(EPOLLONESHOT);
86 DO_BIT(EPOLLET);
87#undef DO_BIT
88 return o;
89}
90
Austin Schuh9d823002019-04-14 12:53:17 -070091constexpr int EpollTimeoutMillis = 500; // Twice a second is ample.
92constexpr int DefaultLameConnectionTimeoutSeconds = 10;
93pid_t gettid() {
94 return static_cast<pid_t>(syscall(SYS_gettid));
Austin Schuh24adb6b2015-09-06 17:37:40 -070095}
96
97}
98
99namespace seasocks {
100
Austin Schuh9d823002019-04-14 12:53:17 -0700101constexpr size_t Server::DefaultClientBufferSize;
102
Austin Schuh24adb6b2015-09-06 17:37:40 -0700103Server::Server(std::shared_ptr<Logger> logger)
Austin Schuh9d823002019-04-14 12:53:17 -0700104 : _logger(logger), _listenSock(-1), _epollFd(-1), _eventFd(-1),
105 _maxKeepAliveDrops(0),
106 _lameConnectionTimeoutSeconds(DefaultLameConnectionTimeoutSeconds),
107 _clientBufferSize(DefaultClientBufferSize),
108 _nextDeadConnectionCheck(0), _threadId(0), _terminate(false),
109 _expectedTerminate(false) {
Austin Schuh24adb6b2015-09-06 17:37:40 -0700110
111 _epollFd = epoll_create(10);
112 if (_epollFd == -1) {
113 LS_ERROR(_logger, "Unable to create epoll: " << getLastError());
114 return;
115 }
116
117 _eventFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
118 if (_eventFd == -1) {
119 LS_ERROR(_logger, "Unable to create event FD: " << getLastError());
120 return;
121 }
122
Austin Schuh9d823002019-04-14 12:53:17 -0700123 epoll_event eventWake = {EPOLLIN, {&_eventFd}};
Austin Schuh24adb6b2015-09-06 17:37:40 -0700124 if (epoll_ctl(_epollFd, EPOLL_CTL_ADD, _eventFd, &eventWake) == -1) {
125 LS_ERROR(_logger, "Unable to add wake socket to epoll: " << getLastError());
126 return;
127 }
128}
129
130Server::~Server() {
131 LS_INFO(_logger, "Server destruction");
132 shutdown();
133 // Only shut the eventfd and epoll at the very end
134 if (_eventFd != -1) {
135 close(_eventFd);
136 }
137 if (_epollFd != -1) {
138 close(_epollFd);
139 }
140}
141
142void Server::shutdown() {
143 // Stop listening to any further incoming connections.
144 if (_listenSock != -1) {
145 close(_listenSock);
146 _listenSock = -1;
147 }
148 // Disconnect and close any current connections.
149 while (!_connections.empty()) {
150 // Deleting the connection closes it and removes it from 'this'.
151 Connection* toBeClosed = _connections.begin()->first;
152 toBeClosed->setLinger();
153 delete toBeClosed;
154 }
155}
156
157bool Server::makeNonBlocking(int fd) const {
158 int yesPlease = 1;
159 if (ioctl(fd, FIONBIO, &yesPlease) != 0) {
160 LS_ERROR(_logger, "Unable to make FD non-blocking: " << getLastError());
161 return false;
162 }
163 return true;
164}
165
166bool Server::configureSocket(int fd) const {
167 if (!makeNonBlocking(fd)) {
168 return false;
169 }
170 const int yesPlease = 1;
171 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yesPlease, sizeof(yesPlease)) == -1) {
172 LS_ERROR(_logger, "Unable to set reuse socket option: " << getLastError());
173 return false;
174 }
175 if (_maxKeepAliveDrops > 0) {
176 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yesPlease, sizeof(yesPlease)) == -1) {
177 LS_ERROR(_logger, "Unable to enable keepalive: " << getLastError());
178 return false;
179 }
180 const int oneSecond = 1;
181 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &oneSecond, sizeof(oneSecond)) == -1) {
182 LS_ERROR(_logger, "Unable to set idle probe: " << getLastError());
183 return false;
184 }
185 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &oneSecond, sizeof(oneSecond)) == -1) {
186 LS_ERROR(_logger, "Unable to set idle interval: " << getLastError());
187 return false;
188 }
189 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &_maxKeepAliveDrops, sizeof(_maxKeepAliveDrops)) == -1) {
190 LS_ERROR(_logger, "Unable to set keep alive count: " << getLastError());
191 return false;
192 }
193 }
194 return true;
195}
196
197void Server::terminate() {
198 _expectedTerminate = true;
199 _terminate = true;
200 uint64_t one = 1;
201 if (_eventFd != -1 && ::write(_eventFd, &one, sizeof(one)) == -1) {
202 LS_ERROR(_logger, "Unable to post a wake event: " << getLastError());
203 }
204}
205
206bool Server::startListening(int port) {
207 return startListening(INADDR_ANY, port);
208}
209
Austin Schuh9d823002019-04-14 12:53:17 -0700210bool Server::startListening(uint32_t ipInHostOrder, int port) {
Austin Schuh24adb6b2015-09-06 17:37:40 -0700211 if (_epollFd == -1 || _eventFd == -1) {
212 LS_ERROR(_logger, "Unable to serve, did not initialize properly.");
213 return false;
214 }
215
Austin Schuh9d823002019-04-14 12:53:17 -0700216 auto port16 = static_cast<uint16_t>(port);
217 if (port != port16) {
218 LS_ERROR(_logger, "Invalid port: " << port);
219 return false;
220 }
Austin Schuh24adb6b2015-09-06 17:37:40 -0700221 _listenSock = socket(AF_INET, SOCK_STREAM, 0);
222 if (_listenSock == -1) {
223 LS_ERROR(_logger, "Unable to create listen socket: " << getLastError());
224 return false;
225 }
226 if (!configureSocket(_listenSock)) {
227 return false;
228 }
229 sockaddr_in sock;
230 memset(&sock, 0, sizeof(sock));
Austin Schuh9d823002019-04-14 12:53:17 -0700231 sock.sin_port = htons(port16);
232 sock.sin_addr.s_addr = htonl(ipInHostOrder);
Austin Schuh24adb6b2015-09-06 17:37:40 -0700233 sock.sin_family = AF_INET;
234 if (bind(_listenSock, reinterpret_cast<const sockaddr*>(&sock), sizeof(sock)) == -1) {
235 LS_ERROR(_logger, "Unable to bind socket: " << getLastError());
236 return false;
237 }
238 if (listen(_listenSock, 5) == -1) {
239 LS_ERROR(_logger, "Unable to listen on socket: " << getLastError());
240 return false;
241 }
Austin Schuh9d823002019-04-14 12:53:17 -0700242 epoll_event event = {EPOLLIN, {this}};
Austin Schuh24adb6b2015-09-06 17:37:40 -0700243 if (epoll_ctl(_epollFd, EPOLL_CTL_ADD, _listenSock, &event) == -1) {
244 LS_ERROR(_logger, "Unable to add listen socket to epoll: " << getLastError());
245 return false;
246 }
247
248 char buf[1024];
249 ::gethostname(buf, sizeof(buf));
250 LS_INFO(_logger, "Listening on http://" << buf << ":" << port << "/");
251
252 return true;
253}
254
Austin Schuh9d823002019-04-14 12:53:17 -0700255bool Server::startListeningUnix(const char* socketPath) {
256 struct sockaddr_un sock;
257
258 _listenSock = socket(AF_UNIX, SOCK_STREAM, 0);
259 if (_listenSock == -1) {
260 LS_ERROR(_logger, "Unable to create unix listen socket: " << getLastError());
261 return false;
262 }
263 if (!configureSocket(_listenSock)) {
264 return false;
265 }
266
267 memset(&sock, 0, sizeof(struct sockaddr_un));
268 sock.sun_family = AF_UNIX;
269 strncpy(sock.sun_path, socketPath, sizeof(sock.sun_path) - 1);
270
271 if (bind(_listenSock, reinterpret_cast<const sockaddr*>(&sock), sizeof(sock)) == -1) {
272 LS_ERROR(_logger, "Unable to bind unix socket (" << socketPath << "): " << getLastError());
273 return false;
274 }
275
276 if (listen(_listenSock, 5) == -1) {
277 LS_ERROR(_logger, "Unable to listen on unix socket: " << getLastError());
278 return false;
279 }
280
281 epoll_event event = {EPOLLIN, {this}};
282 if (epoll_ctl(_epollFd, EPOLL_CTL_ADD, _listenSock, &event) == -1) {
283 LS_ERROR(_logger, "Unable to add unix listen socket to epoll: " << getLastError());
284 return false;
285 }
286
287 LS_INFO(_logger, "Listening on unix socket: http://unix:" << socketPath);
288
289 return true;
290}
291
Austin Schuh24adb6b2015-09-06 17:37:40 -0700292void Server::handlePipe() {
293 uint64_t dummy;
294 while (::read(_eventFd, &dummy, sizeof(dummy)) != -1) {
295 // Spin, draining the pipe until it returns EWOULDBLOCK or similar.
296 }
297 if (errno != EAGAIN || errno != EWOULDBLOCK) {
298 LS_ERROR(_logger, "Error from wakeFd read: " << getLastError());
299 _terminate = true;
300 }
301 // It's a "wake up" event; this will just cause the epoll loop to wake up.
302}
303
304Server::NewState Server::handleConnectionEvents(Connection* connection, uint32_t events) {
Austin Schuh9d823002019-04-14 12:53:17 -0700305 if (events & ~(EPOLLIN | EPOLLOUT | EPOLLHUP | EPOLLERR)) {
Austin Schuh24adb6b2015-09-06 17:37:40 -0700306 LS_WARNING(_logger, "Got unhandled epoll event (" << EventBits(events) << ") on connection: "
Austin Schuh9d823002019-04-14 12:53:17 -0700307 << formatAddress(connection->getRemoteAddress()));
308 return NewState::Close;
Austin Schuh24adb6b2015-09-06 17:37:40 -0700309 } else if (events & EPOLLERR) {
310 LS_INFO(_logger, "Error on socket (" << EventBits(events) << "): "
Austin Schuh9d823002019-04-14 12:53:17 -0700311 << formatAddress(connection->getRemoteAddress()));
312 return NewState::Close;
Austin Schuh24adb6b2015-09-06 17:37:40 -0700313 } else if (events & EPOLLHUP) {
314 LS_DEBUG(_logger, "Graceful hang-up (" << EventBits(events) << ") of socket: "
Austin Schuh9d823002019-04-14 12:53:17 -0700315 << formatAddress(connection->getRemoteAddress()));
316 return NewState::Close;
Austin Schuh24adb6b2015-09-06 17:37:40 -0700317 } else {
318 if (events & EPOLLOUT) {
319 connection->handleDataReadyForWrite();
320 }
321 if (events & EPOLLIN) {
322 connection->handleDataReadyForRead();
323 }
324 }
Austin Schuh9d823002019-04-14 12:53:17 -0700325 return NewState::KeepOpen;
Austin Schuh24adb6b2015-09-06 17:37:40 -0700326}
327
328void Server::checkAndDispatchEpoll(int epollMillis) {
Austin Schuh9d823002019-04-14 12:53:17 -0700329 constexpr int maxEvents = 256;
Austin Schuh24adb6b2015-09-06 17:37:40 -0700330 epoll_event events[maxEvents];
331
332 std::list<Connection*> toBeDeleted;
333 int numEvents = epoll_wait(_epollFd, events, maxEvents, epollMillis);
334 if (numEvents == -1) {
335 if (errno != EINTR) {
336 LS_ERROR(_logger, "Error from epoll_wait: " << getLastError());
337 }
338 return;
339 }
340 if (numEvents == maxEvents) {
341 static time_t lastWarnTime = 0;
Austin Schuh9d823002019-04-14 12:53:17 -0700342 time_t now = time(nullptr);
Austin Schuh24adb6b2015-09-06 17:37:40 -0700343 if (now - lastWarnTime >= 60) {
344 LS_WARNING(_logger, "Full event queue; may start starving connections. "
Austin Schuh9d823002019-04-14 12:53:17 -0700345 "Will warn at most once a minute");
Austin Schuh24adb6b2015-09-06 17:37:40 -0700346 lastWarnTime = now;
347 }
348 }
349 for (int i = 0; i < numEvents; ++i) {
350 if (events[i].data.ptr == this) {
351 if (events[i].events & ~EPOLLIN) {
352 LS_SEVERE(_logger, "Got unexpected event on listening socket ("
Austin Schuh9d823002019-04-14 12:53:17 -0700353 << EventBits(events[i].events) << ") - terminating");
Austin Schuh24adb6b2015-09-06 17:37:40 -0700354 _terminate = true;
355 break;
356 }
357 handleAccept();
358 } else if (events[i].data.ptr == &_eventFd) {
359 if (events[i].events & ~EPOLLIN) {
360 LS_SEVERE(_logger, "Got unexpected event on management pipe ("
Austin Schuh9d823002019-04-14 12:53:17 -0700361 << EventBits(events[i].events) << ") - terminating");
Austin Schuh24adb6b2015-09-06 17:37:40 -0700362 _terminate = true;
363 break;
364 }
365 handlePipe();
366 } else {
367 auto connection = reinterpret_cast<Connection*>(events[i].data.ptr);
Austin Schuh9d823002019-04-14 12:53:17 -0700368 if (handleConnectionEvents(connection, events[i].events) == NewState::Close) {
Austin Schuh24adb6b2015-09-06 17:37:40 -0700369 toBeDeleted.push_back(connection);
370 }
371 }
372 }
373 // The connections are all deleted at the end so we've processed any other subject's
374 // closes etc before we call onDisconnect().
Austin Schuh9d823002019-04-14 12:53:17 -0700375 for (auto connection : toBeDeleted) {
Austin Schuh24adb6b2015-09-06 17:37:40 -0700376 if (_connections.find(connection) == _connections.end()) {
Austin Schuh9d823002019-04-14 12:53:17 -0700377 LS_SEVERE(_logger, "Attempt to delete connection we didn't know about: " << (void*) connection
378 << formatAddress(connection->getRemoteAddress()));
Austin Schuh24adb6b2015-09-06 17:37:40 -0700379 _terminate = true;
380 break;
381 }
382 LS_DEBUG(_logger, "Deleting connection: " << formatAddress(connection->getRemoteAddress()));
383 delete connection;
384 }
385}
386
387void Server::setStaticPath(const char* staticPath) {
388 LS_INFO(_logger, "Serving content from " << staticPath);
389 _staticPath = staticPath;
390}
391
392bool Server::serve(const char* staticPath, int port) {
393 setStaticPath(staticPath);
394 if (!startListening(port)) {
395 return false;
396 }
397
398 return loop();
399}
400
401bool Server::loop() {
402 if (_listenSock == -1) {
403 LS_ERROR(_logger, "Server not initialised");
404 return false;
405 }
406
407 // Stash away "the" server thread id.
408 _threadId = gettid();
409
410 while (!_terminate) {
411 // Always process events first to catch start up events.
412 processEventQueue();
413 checkAndDispatchEpoll(EpollTimeoutMillis);
414 }
415 // Reasonable effort to ensure anything enqueued during terminate has a chance to run.
416 processEventQueue();
417 LS_INFO(_logger, "Server terminating");
418 shutdown();
419 return _expectedTerminate;
420}
421
422Server::PollResult Server::poll(int millis) {
423 // Grab the thread ID on the first poll.
Austin Schuh9d823002019-04-14 12:53:17 -0700424 if (_threadId == 0)
425 _threadId = gettid();
Austin Schuh24adb6b2015-09-06 17:37:40 -0700426 if (_threadId != gettid()) {
427 LS_ERROR(_logger, "poll() called from the wrong thread");
428 return PollResult::Error;
429 }
430 if (_listenSock == -1) {
431 LS_ERROR(_logger, "Server not initialised");
432 return PollResult::Error;
433 }
434 processEventQueue();
435 checkAndDispatchEpoll(millis);
Austin Schuh9d823002019-04-14 12:53:17 -0700436 if (!_terminate)
437 return PollResult::Continue;
Austin Schuh24adb6b2015-09-06 17:37:40 -0700438
439 // Reasonable effort to ensure anything enqueued during terminate has a chance to run.
440 processEventQueue();
441 LS_INFO(_logger, "Server terminating");
442 shutdown();
443
444 return _expectedTerminate ? PollResult::Terminated : PollResult::Error;
445}
446
447void Server::processEventQueue() {
Austin Schuh9d823002019-04-14 12:53:17 -0700448 runExecutables();
449 time_t now = time(nullptr);
450 if (now < _nextDeadConnectionCheck)
451 return;
452 std::list<Connection*> toRemove;
453 for (auto _connection : _connections) {
454 time_t numSecondsSinceConnection = now - _connection.second;
455 auto connection = _connection.first;
456 if (connection->bytesReceived() == 0 && numSecondsSinceConnection >= _lameConnectionTimeoutSeconds) {
457 LS_INFO(_logger, formatAddress(connection->getRemoteAddress())
458 << " : Killing lame connection - no bytes received after "
459 << numSecondsSinceConnection << "s");
460 toRemove.push_back(connection);
Austin Schuh24adb6b2015-09-06 17:37:40 -0700461 }
462 }
Austin Schuh9d823002019-04-14 12:53:17 -0700463 for (auto& it : toRemove) {
464 delete it;
465 }
466}
467
468void Server::runExecutables() {
469 decltype(_pendingExecutables) copy;
470 std::unique_lock<decltype(_pendingExecutableMutex)> lock(_pendingExecutableMutex);
471 copy.swap(_pendingExecutables);
472 lock.unlock();
473 for (auto&& ex : copy)
474 ex();
Austin Schuh24adb6b2015-09-06 17:37:40 -0700475}
476
477void Server::handleAccept() {
478 sockaddr_in address;
479 socklen_t addrLen = sizeof(address);
480 int fd = ::accept(_listenSock,
Austin Schuh9d823002019-04-14 12:53:17 -0700481 reinterpret_cast<sockaddr*>(&address),
482 &addrLen);
Austin Schuh24adb6b2015-09-06 17:37:40 -0700483 if (fd == -1) {
484 LS_ERROR(_logger, "Unable to accept: " << getLastError());
485 return;
486 }
487 if (!configureSocket(fd)) {
488 ::close(fd);
489 return;
490 }
491 LS_INFO(_logger, formatAddress(address) << " : Accepted on descriptor " << fd);
492 Connection* newConnection = new Connection(_logger, *this, fd, address);
Austin Schuh9d823002019-04-14 12:53:17 -0700493 epoll_event event = {EPOLLIN, {newConnection}};
Austin Schuh24adb6b2015-09-06 17:37:40 -0700494 if (epoll_ctl(_epollFd, EPOLL_CTL_ADD, fd, &event) == -1) {
495 LS_ERROR(_logger, "Unable to add socket to epoll: " << getLastError());
496 delete newConnection;
497 ::close(fd);
498 return;
499 }
Austin Schuh9d823002019-04-14 12:53:17 -0700500 _connections.insert(std::make_pair(newConnection, time(nullptr)));
Austin Schuh24adb6b2015-09-06 17:37:40 -0700501}
502
503void Server::remove(Connection* connection) {
504 checkThread();
Austin Schuh9d823002019-04-14 12:53:17 -0700505 epoll_event event = {0, {connection}};
Austin Schuh24adb6b2015-09-06 17:37:40 -0700506 if (epoll_ctl(_epollFd, EPOLL_CTL_DEL, connection->getFd(), &event) == -1) {
507 LS_ERROR(_logger, "Unable to remove from epoll: " << getLastError());
508 }
509 _connections.erase(connection);
510}
511
512bool Server::subscribeToWriteEvents(Connection* connection) {
Austin Schuh9d823002019-04-14 12:53:17 -0700513 epoll_event event = {EPOLLIN | EPOLLOUT, {connection}};
Austin Schuh24adb6b2015-09-06 17:37:40 -0700514 if (epoll_ctl(_epollFd, EPOLL_CTL_MOD, connection->getFd(), &event) == -1) {
515 LS_ERROR(_logger, "Unable to subscribe to write events: " << getLastError());
516 return false;
517 }
518 return true;
519}
520
521bool Server::unsubscribeFromWriteEvents(Connection* connection) {
Austin Schuh9d823002019-04-14 12:53:17 -0700522 epoll_event event = {EPOLLIN, {connection}};
Austin Schuh24adb6b2015-09-06 17:37:40 -0700523 if (epoll_ctl(_epollFd, EPOLL_CTL_MOD, connection->getFd(), &event) == -1) {
524 LS_ERROR(_logger, "Unable to unsubscribe from write events: " << getLastError());
525 return false;
526 }
527 return true;
528}
529
530void Server::addWebSocketHandler(const char* endpoint, std::shared_ptr<WebSocket::Handler> handler,
Austin Schuh9d823002019-04-14 12:53:17 -0700531 bool allowCrossOriginRequests) {
532 _webSocketHandlerMap[endpoint] = {handler, allowCrossOriginRequests};
Austin Schuh24adb6b2015-09-06 17:37:40 -0700533}
534
535void Server::addPageHandler(std::shared_ptr<PageHandler> handler) {
536 _pageHandlers.emplace_back(handler);
537}
538
Austin Schuh9d823002019-04-14 12:53:17 -0700539bool Server::isCrossOriginAllowed(const std::string& endpoint) const {
Austin Schuh24adb6b2015-09-06 17:37:40 -0700540 auto splits = split(endpoint, '?');
541 auto iter = _webSocketHandlerMap.find(splits[0]);
542 if (iter == _webSocketHandlerMap.end()) {
543 return false;
544 }
545 return iter->second.allowCrossOrigin;
546}
547
548std::shared_ptr<WebSocket::Handler> Server::getWebSocketHandler(const char* endpoint) const {
549 auto splits = split(endpoint, '?');
550 auto iter = _webSocketHandlerMap.find(splits[0]);
551 if (iter == _webSocketHandlerMap.end()) {
552 return std::shared_ptr<WebSocket::Handler>();
553 }
554 return iter->second.handler;
555}
556
557void Server::execute(std::shared_ptr<Runnable> runnable) {
Austin Schuh9d823002019-04-14 12:53:17 -0700558 execute([runnable] { runnable->run(); });
559}
560
561void Server::execute(std::function<void()> toExecute) {
562 std::unique_lock<decltype(_pendingExecutableMutex)> lock(_pendingExecutableMutex);
563 _pendingExecutables.emplace_back(std::move(toExecute));
Austin Schuh24adb6b2015-09-06 17:37:40 -0700564 lock.unlock();
565
566 uint64_t one = 1;
567 if (_eventFd != -1 && ::write(_eventFd, &one, sizeof(one)) == -1) {
568 if (errno != EAGAIN && errno != EWOULDBLOCK) {
569 LS_ERROR(_logger, "Unable to post a wake event: " << getLastError());
570 }
571 }
572}
573
Austin Schuh24adb6b2015-09-06 17:37:40 -0700574std::string Server::getStatsDocument() const {
575 std::ostringstream doc;
Austin Schuh9d823002019-04-14 12:53:17 -0700576 doc << "clear();\n";
577 for (auto _connection : _connections) {
Austin Schuh24adb6b2015-09-06 17:37:40 -0700578 doc << "connection({";
Austin Schuh9d823002019-04-14 12:53:17 -0700579 auto connection = _connection.first;
Austin Schuh24adb6b2015-09-06 17:37:40 -0700580 jsonKeyPairToStream(doc,
Austin Schuh9d823002019-04-14 12:53:17 -0700581 "since", EpochTimeAsLocal(_connection.second),
582 "fd", connection->getFd(),
583 "id", reinterpret_cast<uint64_t>(connection),
584 "uri", connection->getRequestUri(),
585 "addr", formatAddress(connection->getRemoteAddress()),
586 "user", connection->credentials() ? connection->credentials()->username : "(not authed)",
587 "input", connection->inputBufferSize(),
588 "read", connection->bytesReceived(),
589 "output", connection->outputBufferSize(),
590 "written", connection->bytesSent());
591 doc << "});\n";
Austin Schuh24adb6b2015-09-06 17:37:40 -0700592 }
593 return doc.str();
594}
595
596void Server::setLameConnectionTimeoutSeconds(int seconds) {
597 LS_INFO(_logger, "Setting lame connection timeout to " << seconds);
598 _lameConnectionTimeoutSeconds = seconds;
599}
600
601void Server::setMaxKeepAliveDrops(int maxKeepAliveDrops) {
602 LS_INFO(_logger, "Setting max keep alive drops to " << maxKeepAliveDrops);
603 _maxKeepAliveDrops = maxKeepAliveDrops;
604}
605
Austin Schuh9d823002019-04-14 12:53:17 -0700606void Server::setPerMessageDeflateEnabled(bool enabled) {
607 if (!Config::deflateEnabled) {
608 LS_ERROR(_logger, "Ignoring request to enable deflate as Seasocks was compiled without support");
609 return;
610 }
611 LS_INFO(_logger, "Setting per-message deflate to " << (enabled ? "enabled" : "disabled"));
612 _perMessageDeflateEnabled = enabled;
613}
614
Austin Schuh24adb6b2015-09-06 17:37:40 -0700615void Server::checkThread() const {
616 auto thisTid = gettid();
617 if (thisTid != _threadId) {
618 std::ostringstream o;
619 o << "seasocks called on wrong thread : " << thisTid << " instead of " << _threadId;
620 LS_SEVERE(_logger, o.str());
621 throw std::runtime_error(o.str());
622 }
623}
624
Austin Schuh9d823002019-04-14 12:53:17 -0700625std::shared_ptr<Response> Server::handle(const Request& request) {
626 for (const auto& handler : _pageHandlers) {
Austin Schuh24adb6b2015-09-06 17:37:40 -0700627 auto result = handler->handle(request);
Austin Schuh9d823002019-04-14 12:53:17 -0700628 if (result != Response::unhandled())
629 return result;
Austin Schuh24adb6b2015-09-06 17:37:40 -0700630 }
631 return Response::unhandled();
632}
633
Austin Schuh9d823002019-04-14 12:53:17 -0700634void Server::setClientBufferSize(size_t bytesToBuffer) {
635 LS_INFO(_logger, "Setting client buffer size to " << bytesToBuffer << " bytes");
636 _clientBufferSize = bytesToBuffer;
637}
638
639} // namespace seasocks