]> git.sesse.net Git - cubemap/blob - server.h
Make a useful constructor for Client.
[cubemap] / server.h
1 #ifndef _SERVER_H
2 #define _SERVER_H 1
3
4 #include <stdint.h>
5 #include <pthread.h>
6 #include <string>
7 #include <map>
8
9 #define NUM_SERVERS 4
10 #define BACKLOG_SIZE 1048576
11 #define EPOLL_MAX_EVENTS 8192
12 #define EPOLL_TIMEOUT_MS 20
13 #define MAX_CLIENT_REQUEST 16384
14
15 struct Client {
16         Client() {}
17         Client(int sock);
18
19         // The file descriptor associated with this socket.
20         int sock;
21
22         enum State { READING_REQUEST, SENDING_HEADER, SENDING_DATA };
23         State state;
24
25         // The HTTP request, as sent by the client. If we are in READING_REQUEST,
26         // this might not be finished.
27         std::string request;
28
29         // What stream we're connecting to; parsed from <request>.
30         // Not relevant for READING_REQUEST.
31         std::string stream_id;
32
33         // The header we want to send. This is nominally a copy of Stream::header,
34         // but since that might change on reconnects etc., we keep a local copy here.
35         // Only relevant for SENDING_HEADER; blank otherwise.
36         std::string header;
37
38         // Number of bytes we've sent of the header. Only relevant for SENDING_HEADER.
39         size_t header_bytes_sent;
40
41         // Number of bytes we've sent of data. Only relevant for SENDING_DATA.
42         size_t bytes_sent;
43 };
44
45 struct Stream {
46         // The HTTP response header, plus the video stream header (if any).
47         std::string header;
48
49         // The stream data itself, stored in a circular buffer.
50         char data[BACKLOG_SIZE];
51
52         // How many bytes <data> contains. Can very well be larger than BACKLOG_SIZE,
53         // since the buffer wraps.
54         size_t data_size;
55 };
56
57 class Server {
58 public:
59         Server();
60
61         // Start a new thread that handles clients.
62         void run();
63
64         // Stop the thread.
65         void stop();
66
67         void add_client(int sock);
68         void add_stream(const std::string &stream_id);
69         void set_header(const std::string &stream_id, const std::string &header);
70         void add_data(const std::string &stream_id, const char *data, size_t bytes);
71
72 private:
73         pthread_t worker_thread;
74
75         // All variables below this line are protected by the mutex.
76         pthread_mutex_t mutex;
77
78         // If the thread should stop or not.
79         bool should_stop;       
80
81         // Map from stream ID to stream.
82         std::map<std::string, Stream> streams;
83
84         // Map from file descriptor to client.
85         std::map<int, Client> clients;
86
87         // Used for epoll implementation (obviously).
88         int epoll_fd;
89         epoll_event events[EPOLL_MAX_EVENTS];
90
91         // Clients that are in SENDING_DATA, but that we don't listen on,
92         // because we currently don't have any data for them.
93         // See put_client_to_sleep() and wake_up_all_clients().
94         std::vector<int> sleeping_clients;
95
96         // Recover the this pointer, and call do_work().
97         static void *do_work_thunk(void *arg);
98
99         // The actual worker thread.
100         void do_work();
101
102         void process_client(Client *client);
103
104         // Close a given client socket, and clean up after it.
105         void close_client(Client *client);
106
107         // Parse the HTTP request, construct the header, and set the client into
108         // the SENDING_HEADER state.
109         void parse_request(Client *client);
110
111         // Put client to sleep, since there is no more data for it; we will on
112         // longer listen on POLLOUT until we get more data. Also, it will be put
113         // in the list of clients to wake up when we do.
114         void put_client_to_sleep(Client *client);
115
116         // We have more data, so mark all clients that are sleeping as ready to go.
117         void wake_up_all_clients();
118 };
119
120 #endif  // !defined(_SERVER_H)