blob: 4629a4329a15c8bb94e770b5374dced274f8309b [file] [log] [blame]
Austin Schuh24adb6b2015-09-06 17:37:40 -07001// Copyright (c) 2013, Matt Godbolt
2// 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
26#pragma once
27
28#include "seasocks/ServerImpl.h"
29#include "seasocks/WebSocket.h"
30
31#include <sys/types.h>
32
33#include <atomic>
34#include <cstdint>
35#include <list>
36#include <map>
37#include <memory>
38#include <mutex>
39#include <string>
40#include <unordered_map>
41
42namespace seasocks {
43
44class Connection;
45class Logger;
46class PageHandler;
47class Request;
48class Response;
49
50class Server : private ServerImpl {
51public:
52 Server(std::shared_ptr<Logger> logger);
53 virtual ~Server();
54
55 void addPageHandler(std::shared_ptr<PageHandler> handler);
56
57 void addWebSocketHandler(const char* endpoint, std::shared_ptr<WebSocket::Handler> handler,
58 bool allowCrossOriginRequests = false);
59
60 // If we haven't heard anything ever on a connection for this long, kill it.
61 // This is possibly caused by bad WebSocket implementation in Chrome.
62 void setLameConnectionTimeoutSeconds(int seconds);
63
64 // Sets the maximum number of TCP level keepalives that we can miss before
65 // we let the OS consider the connection dead. We configure keepalives every second,
66 // so this is also the minimum number of seconds it takes to notice a badly-behaved
67 // dead connection, e.g. a laptop going into sleep mode or a hard-crashed machine.
68 // A value of 0 disables keep alives, which is the default.
69 void setMaxKeepAliveDrops(int maxKeepAliveDrops);
70
71 // Serves static content from the given port on the current thread, until terminate is called.
72 // Roughly equivalent to startListening(port); setStaticPath(staticPath); loop();
73 // Returns whether exiting was expected.
74 bool serve(const char* staticPath, int port);
75
76 // Starts listening on a given interface (in host order) and port.
77 // Returns true if all was ok.
78 bool startListening(uint32_t ipInHostOrder, int port);
79
80 // Starts listening on a port on all interfaces.
81 // Returns true if all was ok.
82 bool startListening(int port);
83
84 // Sets the path to server static content from.
85 void setStaticPath(const char* staticPath);
86
87 // Loop (until terminate called from another thread).
88 // Returns true if terminate() was used to exit the loop, false if there
89 // was an error.
90 bool loop();
91
92 // Runs a single iteration of the main loop, blocking for a given time.
93 // Returns immediately if terminate() has been called. Must be consistently
94 // called from the same thread. Returns an enum describing why it returned.
95 enum class PollResult {
96 Continue,
97 Terminated,
98 Error,
99 };
100 PollResult poll(int millisToBlock);
101
102 // Returns a file descriptor that can be polled for changes (e.g. by
103 // placing it in an epoll set. The poll() method above only need be called
104 // when this file descriptor is readable.
105 int fd() const { return _epollFd; }
106
107 // Terminate any loop() or poll(). May be called from any thread.
108 void terminate();
109
110 class Runnable {
111 public:
112 virtual ~Runnable() {}
113 virtual void run() = 0;
114 };
115 // Execute a task on the SeaSocks thread.
116 void execute(std::shared_ptr<Runnable> runnable);
117
118private:
119 // From ServerImpl
120 virtual void remove(Connection* connection) override;
121 virtual bool subscribeToWriteEvents(Connection* connection) override;
122 virtual bool unsubscribeFromWriteEvents(Connection* connection) override;
123 virtual const std::string& getStaticPath() const override { return _staticPath; }
124 virtual std::shared_ptr<WebSocket::Handler> getWebSocketHandler(const char* endpoint) const override;
125 virtual bool isCrossOriginAllowed(const std::string &endpoint) const override;
126 virtual std::shared_ptr<Response> handle(const Request &request) override;
127 virtual std::string getStatsDocument() const override;
128 virtual void checkThread() const override;
129
130 bool makeNonBlocking(int fd) const;
131 bool configureSocket(int fd) const;
132 void handleAccept();
133 std::shared_ptr<Runnable> popNextRunnable();
134 void processEventQueue();
135
136 void shutdown();
137
138 void checkAndDispatchEpoll(int epollMillis);
139 void handlePipe();
140 enum NewState { KeepOpen, Close };
141 NewState handleConnectionEvents(Connection* connection, uint32_t events);
142
143 // Connections, mapped to initial connection time.
144 std::map<Connection*, time_t> _connections;
145 std::shared_ptr<Logger> _logger;
146 int _listenSock;
147 int _epollFd;
148 int _eventFd;
149 int _maxKeepAliveDrops;
150 int _lameConnectionTimeoutSeconds;
151 time_t _nextDeadConnectionCheck;
152
153 struct WebSocketHandlerEntry {
154 std::shared_ptr<WebSocket::Handler> handler;
155 bool allowCrossOrigin;
156 };
157 typedef std::unordered_map<std::string, WebSocketHandlerEntry> WebSocketHandlerMap;
158 WebSocketHandlerMap _webSocketHandlerMap;
159
160 std::list<std::shared_ptr<PageHandler>> _pageHandlers;
161
162 std::mutex _pendingRunnableMutex;
163 std::list<std::shared_ptr<Runnable>> _pendingRunnables;
164
165 pid_t _threadId;
166
167 std::string _staticPath;
168 std::atomic<bool> _terminate;
169 std::atomic<bool> _expectedTerminate;
170};
171
172} // namespace seasocks