1 |
|
|
#include <errno.h> /* errno */ |
2 |
|
|
#include <unistd.h> /* close */ |
3 |
|
|
#include <stdlib.h> /* EXIT_SUCCESS, EXIT_FAILURE */ |
4 |
|
|
#include <signal.h> /* signal */ |
5 |
|
|
#include <stdio.h> |
6 |
|
|
#include <poll.h> |
7 |
|
|
#include <sys/time.h> |
8 |
|
|
#include <sys/resource.h> |
9 |
|
|
|
10 |
|
|
#include "server.h" |
11 |
|
|
#include "frame.h" |
12 |
|
|
#include "event.h" |
13 |
|
|
#include "log.h" |
14 |
|
|
#include "session.h" |
15 |
|
|
#include "alloc.h" |
16 |
|
|
#include "socket.h" |
17 |
|
|
#include "pool.h" /* threadpool_add, threadpool_strerror */ |
18 |
|
|
#include "worker.h" |
19 |
|
|
#include "http.h" |
20 |
|
|
#include "error.h" |
21 |
|
|
#include "config.h" |
22 |
|
|
#include "subprotocols.h" |
23 |
|
|
#include "extensions.h" |
24 |
|
|
#include "predict.h" |
25 |
|
|
#include "ssl.h" |
26 |
|
|
|
27 |
|
|
/** |
28 |
|
|
* Global state of server |
29 |
|
|
*/ |
30 |
|
|
wss_server_state_t state; |
31 |
|
|
|
32 |
|
|
/** |
33 |
|
|
* Global servers available |
34 |
|
|
*/ |
35 |
|
|
wss_servers_t servers; |
36 |
|
|
|
37 |
|
|
/** |
38 |
|
|
* Global variable holding current timestamp |
39 |
|
|
*/ |
40 |
|
|
struct timespec now; |
41 |
|
|
|
42 |
|
|
static inline void write_control_frame(wss_frame_t *frame, wss_session_t *session) { |
43 |
|
|
size_t j; |
44 |
|
|
char *message; |
45 |
|
|
size_t message_length; |
46 |
|
|
int n = 0; |
47 |
|
|
int fd = session->fd; |
48 |
|
|
|
49 |
|
|
// Use extensions |
50 |
|
|
for (j = 0; likely(j < session->header->ws_extensions_count); j++) { |
51 |
|
|
session->header->ws_extensions[j]->ext->outframes( |
52 |
|
|
fd, |
53 |
|
|
&frame, |
54 |
|
|
1); |
55 |
|
|
|
56 |
|
|
session->header->ws_extensions[j]->ext->outframe( |
57 |
|
|
fd, |
58 |
|
|
frame); |
59 |
|
|
} |
60 |
|
|
|
61 |
|
|
if (0 == (message_length = WSS_stringify_frame(frame, &message))) { |
62 |
|
|
WSS_log_fatal("Unable to represent frame as bytes"); |
63 |
|
|
WSS_free_frame(frame); |
64 |
|
|
return; |
65 |
|
|
} |
66 |
|
|
|
67 |
|
|
WSS_free_frame(frame); |
68 |
|
|
|
69 |
|
|
if (session->ssl_connected) { |
70 |
|
|
WSS_ssl_write(session, message, message_length); |
71 |
|
|
} else { |
72 |
|
|
size_t written = 0; |
73 |
|
|
do { |
74 |
|
|
n = write(fd, message+written, message_length-written); |
75 |
|
|
if ( unlikely(n < 0) ) { |
76 |
|
|
if ( likely(errno == EINTR) ) { |
77 |
|
|
errno = 0; |
78 |
|
|
n = 0; |
79 |
|
|
continue; |
80 |
|
|
} |
81 |
|
|
break; |
82 |
|
|
} |
83 |
|
|
written += n; |
84 |
|
|
} while ( written < message_length ); |
85 |
|
|
} |
86 |
|
|
|
87 |
|
|
WSS_free((void **) &message); |
88 |
|
|
} |
89 |
|
|
|
90 |
|
|
static void cleanup_session(wss_session_t *session) { |
91 |
|
|
wss_error_t err; |
92 |
|
|
wss_frame_t *frame; |
93 |
|
|
long unsigned int ms; |
94 |
|
|
int fd = session->fd; |
95 |
|
|
wss_server_t *server = servers.http; |
96 |
|
|
bool dc; |
97 |
|
|
|
98 |
|
|
if (! session->handshaked) { |
99 |
|
|
return; |
100 |
|
|
} |
101 |
|
|
|
102 |
|
|
if (NULL != session->ssl && session->ssl_connected) { |
103 |
|
|
server = servers.https; |
104 |
|
|
} |
105 |
|
|
|
106 |
|
|
ms = (((now.tv_sec - session->alive.tv_sec)*1000)+(now.tv_nsec/1000000)) - (session->alive.tv_nsec/1000000); |
107 |
|
|
|
108 |
|
|
WSS_log_info("Check timeout %d ms", ms); |
109 |
|
|
|
110 |
|
|
// Session timed out |
111 |
|
|
if ( unlikely(server->config->timeout_client >= 0 && ms >= (long unsigned int)server->config->timeout_client) ) { |
112 |
|
|
WSS_session_is_disconnecting(session, &dc); |
113 |
|
|
if (dc) { |
114 |
|
|
return; |
115 |
|
|
} |
116 |
|
|
|
117 |
|
|
WSS_session_jobs_wait(session); |
118 |
|
|
|
119 |
|
|
WSS_log_info("Session %d has timedout last active %d ms ago", fd, ms); |
120 |
|
|
|
121 |
|
|
session->closing = true; |
122 |
|
|
session->state = CLOSING; |
123 |
|
|
|
124 |
|
|
if (! session->ssl_connected) { |
125 |
|
|
WSS_log_trace("Session %d disconnected from ip: %s:%d using HTTP request, due to timing out", session->fd, session->ip, session->port); |
126 |
|
|
} else { |
127 |
|
|
WSS_log_trace("Session %d disconnected from ip: %s:%d using HTTPS request, due to timing out", session->fd, session->ip, session->port); |
128 |
|
|
} |
129 |
|
|
|
130 |
|
|
WSS_log_trace("Informing subprotocol of client with file descriptor %d disconnecting", session->fd); |
131 |
|
|
|
132 |
|
|
if ( NULL != session->header && session->header->ws_protocol != NULL ) { |
133 |
|
|
WSS_log_trace("Informing subprotocol about session close"); |
134 |
|
|
session->header->ws_protocol->close(session->fd); |
135 |
|
|
} |
136 |
|
|
|
137 |
|
|
WSS_log_trace("Removing poll filedescriptor from eventlist"); |
138 |
|
|
|
139 |
|
|
WSS_poll_remove(server, fd); |
140 |
|
|
|
141 |
|
|
WSS_log_trace("Sending close frame", fd); |
142 |
|
|
|
143 |
|
|
frame = WSS_closing_frame(CLOSE_TRY_AGAIN, NULL); |
144 |
|
|
|
145 |
|
|
write_control_frame(frame, session); |
146 |
|
|
|
147 |
|
|
WSS_log_trace("Deleting client session"); |
148 |
|
|
|
149 |
|
|
if ( unlikely(WSS_SUCCESS != (err = WSS_session_delete_no_lock(session))) ) { |
150 |
|
|
switch (err) { |
151 |
|
|
case WSS_SSL_SHUTDOWN_READ_ERROR: |
152 |
|
|
WSS_poll_set_read(server, fd); |
153 |
|
|
return; |
154 |
|
|
case WSS_SSL_SHUTDOWN_WRITE_ERROR: |
155 |
|
|
WSS_poll_set_write(server, fd); |
156 |
|
|
return; |
157 |
|
|
default: |
158 |
|
|
break; |
159 |
|
|
} |
160 |
|
|
WSS_log_error("Unable to delete client session, received error code: %d", err); |
161 |
|
|
return; |
162 |
|
|
} |
163 |
|
|
|
164 |
|
|
WSS_log_info("Client with session %d disconnected", fd); |
165 |
|
|
|
166 |
|
|
// Ping session to keep it alive |
167 |
|
|
} else if (server->config->timeout_pings > 0 ) { |
168 |
|
|
WSS_log_info("Pinging session %d", fd); |
169 |
|
|
|
170 |
|
|
frame = WSS_ping_frame(); |
171 |
|
|
if (session->pong != NULL) { |
172 |
|
|
WSS_free((void **) &session->pong); |
173 |
|
|
session->pong_length = 0; |
174 |
|
|
} |
175 |
|
|
|
176 |
|
|
if (NULL == (session->pong = WSS_malloc(frame->applicationDataLength))) { |
177 |
|
|
WSS_free_frame(frame); |
178 |
|
|
return; |
179 |
|
|
} |
180 |
|
|
session->pong_length = frame->applicationDataLength; |
181 |
|
|
|
182 |
|
|
memcpy(session->pong, frame->payload+frame->extensionDataLength, frame->applicationDataLength); |
183 |
|
|
|
184 |
|
|
write_control_frame(frame, session); |
185 |
|
|
} |
186 |
|
|
} |
187 |
|
|
|
188 |
|
|
/** |
189 |
|
|
* Function that updates the state of the server. |
190 |
|
|
* |
191 |
|
|
* @param s [wss_state_t *] "A state_t value describing the servers state" |
192 |
|
|
* @return [void] |
193 |
|
|
*/ |
194 |
|
|
void WSS_server_set_state(wss_state_t s) { |
195 |
|
|
pthread_mutex_lock(&state.lock); |
196 |
|
|
state.state = s; |
197 |
|
|
pthread_mutex_unlock(&state.lock); |
198 |
|
|
} |
199 |
|
|
|
200 |
|
|
/** |
201 |
|
|
* Sets the maximal file descriptor seen by the server |
202 |
|
|
* |
203 |
|
|
* @param server [wss_server_t *] "The server object" |
204 |
|
|
* @param fd [int] "The file descriptor seen" |
205 |
|
|
* @return [void] |
206 |
|
|
*/ |
207 |
|
|
void WSS_server_set_max_fd(wss_server_t *server, int fd) { |
208 |
|
|
pthread_mutex_lock(&server->lock); |
209 |
|
|
if (server->max_fd < fd) { |
210 |
|
|
server->max_fd = fd; |
211 |
|
|
} |
212 |
|
|
pthread_mutex_unlock(&server->lock); |
213 |
|
|
} |
214 |
|
|
|
215 |
|
|
/** |
216 |
|
|
* Cleanup client sessions, that is, closes connections to clients which is |
217 |
|
|
* timedout based on the servers timeout_client setting. |
218 |
|
|
* |
219 |
|
|
* @return pthread_exit [void *] "0 if successfull and otherwise <0" |
220 |
|
|
*/ |
221 |
|
|
void *WSS_cleanup() { |
222 |
|
|
int n; |
223 |
|
|
wss_error_t err; |
224 |
|
|
struct pollfd fds[1]; |
225 |
|
|
wss_server_t *server = servers.http; |
226 |
|
|
long int timeout = server->config->timeout_client; |
227 |
|
|
|
228 |
|
|
#ifdef USE_RPMALLOC |
229 |
|
|
rpmalloc_thread_initialize(); |
230 |
|
|
#endif |
231 |
|
|
|
232 |
|
|
fds[0].fd = close_pipefd[0]; |
233 |
|
|
fds[0].events = POLLIN | POLLPRI; |
234 |
|
|
|
235 |
|
|
WSS_log_info("Cleanup thread started with %ld", timeout); |
236 |
|
|
|
237 |
|
|
if (timeout >= 0 && server->config->timeout_pings > 0) { |
238 |
|
|
timeout = timeout/server->config->timeout_pings; |
239 |
|
|
WSS_log_info("Cleanup thread will run every %ld milliseconds", timeout); |
240 |
|
|
} |
241 |
|
|
|
242 |
|
|
while ( likely(state.state == RUNNING) ) { |
243 |
|
|
n = poll(fds, 1, timeout); |
244 |
|
|
if ( unlikely(n < 0 && errno != EINTR) ) { |
245 |
|
|
#ifdef USE_RPMALLOC |
246 |
|
|
rpmalloc_thread_finalize(); |
247 |
|
|
#endif |
248 |
|
|
pthread_exit( ((void *) ((uintptr_t)WSS_CLEANUP_ERROR)) ); |
249 |
|
|
} else if ( likely(n == 0) ) { |
250 |
|
|
WSS_log_info("Pings clients and cleanup timedout ones"); |
251 |
|
|
|
252 |
|
|
clock_gettime(CLOCK_MONOTONIC, &now); |
253 |
|
|
if ( unlikely(WSS_SUCCESS != (err = WSS_session_all(cleanup_session))) ) { |
254 |
|
|
#ifdef USE_RPMALLOC |
255 |
|
|
rpmalloc_thread_finalize(); |
256 |
|
|
#endif |
257 |
|
|
pthread_exit( ((void *) &err) ); |
258 |
|
|
} |
259 |
|
|
} |
260 |
|
|
} |
261 |
|
|
|
262 |
|
|
WSS_log_info("Cleanup thread shutting down"); |
263 |
|
|
|
264 |
|
|
#ifdef USE_RPMALLOC |
265 |
|
|
rpmalloc_thread_finalize(); |
266 |
|
|
#endif |
267 |
|
|
pthread_exit( ((void *) ((uintptr_t)WSS_SUCCESS)) ); |
268 |
|
|
} |
269 |
|
|
|
270 |
|
|
/** |
271 |
|
|
* Function that loops over poll events and distribute the events to different |
272 |
|
|
* threadpools. |
273 |
|
|
* |
274 |
|
|
* @param arg [void *] "Is in fact a wss_server_t instance" |
275 |
|
|
* @return pthread_exit [void *] "0 if successfull and otherwise <0" |
276 |
|
|
*/ |
277 |
|
|
void *WSS_server_run(void *arg) { |
278 |
|
|
wss_error_t err; |
279 |
|
|
wss_server_t *server = (wss_server_t *) arg; |
280 |
|
|
|
281 |
|
|
#ifdef USE_RPMALLOC |
282 |
|
|
rpmalloc_thread_initialize(); |
283 |
|
|
#endif |
284 |
|
|
|
285 |
|
|
if (server->ssl_ctx != NULL) { |
286 |
|
|
WSS_log_trace("Running HTTPS server"); |
287 |
|
|
} else { |
288 |
|
|
WSS_log_trace("Running HTTP server"); |
289 |
|
|
} |
290 |
|
|
|
291 |
|
|
// Listen for poll events |
292 |
|
|
while ( likely(state.state == RUNNING) ) { |
293 |
|
|
err = WSS_poll_delegate(server); |
294 |
|
|
if ( unlikely(err != WSS_SUCCESS) ) { |
295 |
|
|
#ifdef USE_RPMALLOC |
296 |
|
|
rpmalloc_thread_finalize(); |
297 |
|
|
#endif |
298 |
|
|
pthread_exit( ((void *) err) ); |
299 |
|
|
} |
300 |
|
|
} |
301 |
|
|
|
302 |
|
|
if (server->ssl_ctx != NULL) { |
303 |
|
|
WSS_log_trace("Stopping HTTPS server"); |
304 |
|
|
} else { |
305 |
|
|
WSS_log_trace("Stopping HTTP server"); |
306 |
|
|
} |
307 |
|
|
|
308 |
|
|
#ifdef USE_RPMALLOC |
309 |
|
|
rpmalloc_thread_finalize(); |
310 |
|
|
#endif |
311 |
|
|
|
312 |
|
|
pthread_exit( ((void *) ((uintptr_t)WSS_SUCCESS)) ); |
313 |
|
|
} |
314 |
|
|
|
315 |
|
|
/** |
316 |
|
|
* Handler to call when some specific interrupts are happening. This function |
317 |
|
|
* shuts down the server in a safe way or ignore certain interrupts. |
318 |
|
|
* |
319 |
|
|
* @param sig [int] "The integer value of the interrupt" |
320 |
|
|
* @return [void] |
321 |
|
|
*/ |
322 |
|
|
static void WSS_server_interrupt(int sig) { |
323 |
|
|
int n; |
324 |
|
|
switch (sig) { |
325 |
|
|
case SIGINT: |
326 |
|
|
case SIGSEGV: |
327 |
|
|
case SIGILL: |
328 |
|
|
case SIGFPE: |
329 |
|
|
if (state.state != HALTING && state.state != HALT_ERROR) { |
330 |
|
|
WSS_log_trace("Server is shutting down gracefully"); |
331 |
|
|
WSS_server_set_state(HALTING); |
332 |
|
|
if (close_pipefd[0] != -1 && close_pipefd[1] != -1) { |
333 |
|
|
do { |
334 |
|
|
errno = 0; |
335 |
|
|
n = write(close_pipefd[1], "HALT", 5); |
336 |
|
|
if ( unlikely(n < 0) ) { |
337 |
|
|
if ( unlikely(errno != EINTR) ) { |
338 |
|
|
WSS_log_fatal("Unable to write halting message through pipe"); |
339 |
|
|
} |
340 |
|
|
} |
341 |
|
|
} while ( unlikely(errno == EINTR) ); |
342 |
|
|
} |
343 |
|
|
} |
344 |
|
|
break; |
345 |
|
|
case SIGPIPE: |
346 |
|
|
break; |
347 |
|
|
default: |
348 |
|
|
return; |
349 |
|
|
} |
350 |
|
|
} |
351 |
|
|
|
352 |
|
|
/** |
353 |
|
|
* Function that frees all memory that the server has allocated |
354 |
|
|
* |
355 |
|
|
* @return [int] "EXIT_SUCCESS if successfull or EXIT_FAILURE on error" |
356 |
|
|
*/ |
357 |
|
|
static int WSS_server_free(wss_server_t *server) { |
358 |
|
|
int result = EXIT_SUCCESS; |
359 |
|
|
|
360 |
|
|
if ( unlikely(WSS_SUCCESS != WSS_http_server_free(server)) ) { |
361 |
|
|
result = EXIT_FAILURE; |
362 |
|
|
} |
363 |
|
|
|
364 |
|
|
if ( unlikely(WSS_SUCCESS != pthread_mutex_destroy(&server->lock)) ) { |
365 |
|
|
result = EXIT_FAILURE; |
366 |
|
|
} |
367 |
|
|
|
368 |
|
|
/** |
369 |
|
|
* Freeing memory from server instance |
370 |
|
|
*/ |
371 |
|
|
if ( likely(NULL != server) ) { |
372 |
|
|
WSS_free((void **) &server); |
373 |
|
|
} |
374 |
|
|
|
375 |
|
|
return result; |
376 |
|
|
} |
377 |
|
|
|
378 |
|
|
/** |
379 |
|
|
* Starts the websocket server. |
380 |
|
|
* |
381 |
|
|
* @param config [wss_config_t *] "The configuration of the server" |
382 |
|
|
* @return [int] "EXIT_SUCCESS if successfull or EXIT_FAILURE on error" |
383 |
|
|
*/ |
384 |
|
|
int WSS_server_start(wss_config_t *config) { |
385 |
|
|
int err; |
386 |
|
|
struct rlimit limits; |
387 |
|
|
struct sigaction sa; |
388 |
|
|
int ret = EXIT_SUCCESS; |
389 |
|
|
wss_server_t *http = NULL; |
390 |
|
|
pthread_t cleanup_thread_id; |
391 |
|
|
wss_server_t *https = NULL; |
392 |
|
|
bool ssl = NULL != config->ssl_cert && NULL != config->ssl_key && (NULL != config->ssl_ca_file || NULL != config->ssl_ca_path); |
393 |
|
|
|
394 |
|
|
if ( unlikely(0 != (err = pthread_mutex_init(&state.lock, NULL))) ) { |
395 |
|
|
WSS_log_fatal("Failed initializing state lock: %s", strerror(err)); |
396 |
|
|
|
397 |
|
|
return EXIT_FAILURE; |
398 |
|
|
} |
399 |
|
|
|
400 |
|
|
if ( getrlimit(RLIMIT_NOFILE, &limits) < 0 ) { |
401 |
|
|
WSS_log_fatal("Failed to get kernel file descriptor limits: %s", strerror(err)); |
402 |
|
|
|
403 |
|
|
return EXIT_FAILURE; |
404 |
|
|
} |
405 |
|
|
|
406 |
|
|
WSS_log_info("Setting max amount of filedescriptors available for server to: %d", limits.rlim_max); |
407 |
|
|
limits.rlim_cur = limits.rlim_max; |
408 |
|
|
|
409 |
|
|
if ( setrlimit(RLIMIT_NOFILE, &limits) < 0 ) { |
410 |
|
|
WSS_log_fatal("Failed to set kernel file descriptor limits: %s", strerror(err)); |
411 |
|
|
|
412 |
|
|
return EXIT_FAILURE; |
413 |
|
|
} |
414 |
|
|
|
415 |
|
|
// Load extensions available |
416 |
|
|
WSS_load_extensions(config); |
417 |
|
|
|
418 |
|
|
// Load subprotocols available |
419 |
|
|
WSS_load_subprotocols(config); |
420 |
|
|
|
421 |
|
|
// Setting starting state |
422 |
|
|
WSS_log_trace("Starting server"); |
423 |
|
|
|
424 |
|
|
WSS_server_set_state(STARTING); |
425 |
|
|
|
426 |
|
|
// Listening for signals that could terminate program |
427 |
|
|
WSS_log_trace("Listening for signals"); |
428 |
|
|
|
429 |
|
|
// Set up the structure to specify the new action |
430 |
|
|
sigemptyset(&sa.sa_mask); |
431 |
|
|
sa.sa_handler = WSS_server_interrupt; |
432 |
|
|
sa.sa_flags = 0; |
433 |
|
|
|
434 |
|
|
if (sigaction (SIGINT, &sa, NULL) == -1) { |
435 |
|
|
WSS_log_fatal("Unable to listen for SIGINT signal: %s", strerror(errno)); |
436 |
|
|
|
437 |
|
|
WSS_destroy_subprotocols(); |
438 |
|
|
WSS_destroy_extensions(); |
439 |
|
|
pthread_mutex_destroy(&state.lock); |
440 |
|
|
|
441 |
|
|
return EXIT_FAILURE; |
442 |
|
|
} |
443 |
|
|
|
444 |
|
|
if (sigaction (SIGSEGV, &sa, NULL) == -1) { |
445 |
|
|
WSS_log_fatal("Unable to listen for SIGSEGV signal: %s", strerror(errno)); |
446 |
|
|
|
447 |
|
|
WSS_destroy_subprotocols(); |
448 |
|
|
WSS_destroy_extensions(); |
449 |
|
|
pthread_mutex_destroy(&state.lock); |
450 |
|
|
|
451 |
|
|
return EXIT_FAILURE; |
452 |
|
|
} |
453 |
|
|
|
454 |
|
|
if (sigaction (SIGILL, &sa, NULL) == -1) { |
455 |
|
|
WSS_log_fatal("Unable to listen for SIGILL signal: %s", strerror(errno)); |
456 |
|
|
|
457 |
|
|
WSS_destroy_subprotocols(); |
458 |
|
|
WSS_destroy_extensions(); |
459 |
|
|
pthread_mutex_destroy(&state.lock); |
460 |
|
|
|
461 |
|
|
return EXIT_FAILURE; |
462 |
|
|
} |
463 |
|
|
|
464 |
|
|
if (sigaction (SIGHUP, &sa, NULL) == -1) { |
465 |
|
|
WSS_log_fatal("Unable to listen for SIGHUB signal: %s", strerror(errno)); |
466 |
|
|
|
467 |
|
|
WSS_destroy_subprotocols(); |
468 |
|
|
WSS_destroy_extensions(); |
469 |
|
|
pthread_mutex_destroy(&state.lock); |
470 |
|
|
|
471 |
|
|
return EXIT_FAILURE; |
472 |
|
|
} |
473 |
|
|
|
474 |
|
|
if (sigaction (SIGFPE, &sa, NULL) == -1) { |
475 |
|
|
WSS_log_fatal("Unable to listen for SIGFPE signal: %s", strerror(errno)); |
476 |
|
|
|
477 |
|
|
WSS_destroy_subprotocols(); |
478 |
|
|
WSS_destroy_extensions(); |
479 |
|
|
pthread_mutex_destroy(&state.lock); |
480 |
|
|
|
481 |
|
|
return EXIT_FAILURE; |
482 |
|
|
} |
483 |
|
|
|
484 |
|
|
if (sigaction (SIGPIPE, &sa, NULL) == -1) { |
485 |
|
|
WSS_log_fatal("Unable to listen for SIGPIPE signal: %s", strerror(errno)); |
486 |
|
|
|
487 |
|
|
WSS_destroy_subprotocols(); |
488 |
|
|
WSS_destroy_extensions(); |
489 |
|
|
pthread_mutex_destroy(&state.lock); |
490 |
|
|
|
491 |
|
|
return EXIT_FAILURE; |
492 |
|
|
} |
493 |
|
|
|
494 |
|
|
WSS_log_trace("Initializing sessions"); |
495 |
|
|
if ( unlikely(WSS_SUCCESS != WSS_session_init_lock()) ) { |
496 |
|
|
WSS_log_fatal("Unable to initialize session mutex"); |
497 |
|
|
|
498 |
|
|
WSS_destroy_subprotocols(); |
499 |
|
|
WSS_destroy_extensions(); |
500 |
|
|
pthread_mutex_destroy(&state.lock); |
501 |
|
|
|
502 |
|
|
return EXIT_FAILURE; |
503 |
|
|
} |
504 |
|
|
|
505 |
|
|
WSS_log_trace("Allocating memory for HTTP instance"); |
506 |
|
|
|
507 |
|
|
if ( unlikely(NULL == (http = WSS_malloc(sizeof(wss_server_t)))) ) { |
508 |
|
|
WSS_log_fatal("Unable to allocate server structure"); |
509 |
|
|
|
510 |
|
|
WSS_session_destroy_lock(); |
511 |
|
|
WSS_destroy_subprotocols(); |
512 |
|
|
WSS_destroy_extensions(); |
513 |
|
|
pthread_mutex_destroy(&state.lock); |
514 |
|
|
|
515 |
|
|
return EXIT_FAILURE; |
516 |
|
|
} |
517 |
|
|
servers.http = http; |
518 |
|
|
servers.https = NULL; |
519 |
|
|
|
520 |
|
|
if ( unlikely(0 != (err = pthread_mutex_init(&http->lock, NULL))) ) { |
521 |
|
|
WSS_server_free(http); |
522 |
|
|
WSS_session_destroy_lock(); |
523 |
|
|
WSS_destroy_subprotocols(); |
524 |
|
|
WSS_destroy_extensions(); |
525 |
|
|
pthread_mutex_destroy(&state.lock); |
526 |
|
|
} |
527 |
|
|
|
528 |
|
|
WSS_log_trace("Setting to running state"); |
529 |
|
|
|
530 |
|
|
WSS_server_set_state(RUNNING); |
531 |
|
|
|
532 |
|
|
WSS_log_trace("Creating HTTP Instance"); |
533 |
|
|
|
534 |
|
|
http->config = config; |
535 |
|
|
http->port = config->port_http; |
536 |
|
|
if ( unlikely(WSS_SUCCESS != WSS_http_server(http)) ) { |
537 |
|
|
WSS_log_fatal("Unable to initialize http server"); |
538 |
|
|
|
539 |
|
|
WSS_server_free(http); |
540 |
|
|
WSS_session_destroy_lock(); |
541 |
|
|
WSS_destroy_subprotocols(); |
542 |
|
|
WSS_destroy_extensions(); |
543 |
|
|
pthread_mutex_destroy(&state.lock); |
544 |
|
|
|
545 |
|
|
return EXIT_FAILURE; |
546 |
|
|
} |
547 |
|
|
|
548 |
|
|
if (ssl) { |
549 |
|
|
WSS_log_trace("Allocating memory for HTTPS instance"); |
550 |
|
|
|
551 |
|
|
if ( unlikely(NULL == (https = (wss_server_t *) WSS_malloc(sizeof(wss_server_t)))) ) { |
552 |
|
|
WSS_server_free(http); |
553 |
|
|
WSS_session_destroy_lock(); |
554 |
|
|
WSS_destroy_subprotocols(); |
555 |
|
|
WSS_destroy_extensions(); |
556 |
|
|
pthread_mutex_destroy(&state.lock); |
557 |
|
|
|
558 |
|
|
WSS_log_fatal("Unable to allocate https server structure"); |
559 |
|
|
|
560 |
|
|
return EXIT_FAILURE; |
561 |
|
|
} |
562 |
|
|
|
563 |
|
|
servers.https = https; |
564 |
|
|
|
565 |
|
|
WSS_log_trace("Creating HTTPS Instance"); |
566 |
|
|
|
567 |
|
|
https->config = config; |
568 |
|
|
https->port = config->port_https; |
569 |
|
|
if ( unlikely(WSS_SUCCESS != WSS_http_ssl(https)) ) { |
570 |
|
|
WSS_server_free(https); |
571 |
|
|
WSS_server_free(http); |
572 |
|
|
WSS_session_destroy_lock(); |
573 |
|
|
WSS_destroy_subprotocols(); |
574 |
|
|
WSS_destroy_extensions(); |
575 |
|
|
pthread_mutex_destroy(&state.lock); |
576 |
|
|
|
577 |
|
|
WSS_log_fatal("Unable to establish ssl context"); |
578 |
|
|
|
579 |
|
|
return EXIT_FAILURE; |
580 |
|
|
} |
581 |
|
|
|
582 |
|
|
if ( unlikely(WSS_SUCCESS != WSS_http_server(https)) ) { |
583 |
|
|
WSS_server_free(https); |
584 |
|
|
WSS_server_free(http); |
585 |
|
|
WSS_session_destroy_lock(); |
586 |
|
|
WSS_destroy_subprotocols(); |
587 |
|
|
WSS_destroy_extensions(); |
588 |
|
|
pthread_mutex_destroy(&state.lock); |
589 |
|
|
|
590 |
|
|
WSS_log_fatal("Unable to initialize https server"); |
591 |
|
|
|
592 |
|
|
return EXIT_FAILURE; |
593 |
|
|
} |
594 |
|
|
} |
595 |
|
|
|
596 |
|
|
WSS_log_trace("Creating HTTP cleanup thread"); |
597 |
|
|
|
598 |
|
|
if ( unlikely(pthread_create(&cleanup_thread_id, NULL, WSS_cleanup, NULL) != 0) ) { |
599 |
|
|
if (ssl) { |
600 |
|
|
WSS_server_free(https); |
601 |
|
|
} |
602 |
|
|
WSS_server_free(http); |
603 |
|
|
WSS_session_destroy_lock(); |
604 |
|
|
WSS_destroy_subprotocols(); |
605 |
|
|
WSS_destroy_extensions(); |
606 |
|
|
pthread_mutex_destroy(&state.lock); |
607 |
|
|
|
608 |
|
|
WSS_log_fatal("Unable to create cleanup thread"); |
609 |
|
|
return EXIT_FAILURE; |
610 |
|
|
} |
611 |
|
|
|
612 |
|
|
WSS_log_trace("Joining server threads"); |
613 |
|
|
|
614 |
|
|
pthread_join(cleanup_thread_id, (void **) &err); |
615 |
|
|
if ( unlikely(WSS_SUCCESS != err) ) { |
616 |
|
|
WSS_log_error("Cleanup thread returned with error: %s", strerror(err)); |
617 |
|
|
WSS_server_set_state(HALT_ERROR); |
618 |
|
|
} |
619 |
|
|
|
620 |
|
|
WSS_log_trace("Cleanup thread has shutdown"); |
621 |
|
|
|
622 |
|
|
pthread_join(http->thread_id, (void **) &err); |
623 |
|
|
if ( unlikely(WSS_SUCCESS != err) ) { |
624 |
|
|
WSS_log_error("HTTP Server thread returned with error: %s", strerror(err)); |
625 |
|
|
WSS_server_set_state(HALT_ERROR); |
626 |
|
|
} |
627 |
|
|
|
628 |
|
|
WSS_log_trace("HTTP server thread has shutdown"); |
629 |
|
|
|
630 |
|
|
if (ssl) { |
631 |
|
|
pthread_join(https->thread_id, (void **) &err); |
632 |
|
|
if ( unlikely(WSS_SUCCESS != err) ) { |
633 |
|
|
WSS_log_error("HTTPS Server thread returned with error: %s", strerror(err)); |
634 |
|
|
WSS_server_set_state(HALT_ERROR); |
635 |
|
|
} |
636 |
|
|
|
637 |
|
|
WSS_log_trace("HTTPS server thread has shutdown"); |
638 |
|
|
} |
639 |
|
|
|
640 |
|
|
pthread_join(http->thread_id, (void **) &err); |
641 |
|
|
|
642 |
|
|
if ( unlikely(WSS_poll_close(http) != WSS_SUCCESS) ) { |
643 |
|
|
WSS_server_set_state(HALT_ERROR); |
644 |
|
|
} |
645 |
|
|
|
646 |
|
|
if ( unlikely(WSS_server_free(http) != 0) ) { |
647 |
|
|
WSS_server_set_state(HALT_ERROR); |
648 |
|
|
} |
649 |
|
|
|
650 |
|
|
WSS_log_trace("Freed memory associated with HTTP server instance"); |
651 |
|
|
|
652 |
|
|
if (ssl) { |
653 |
|
|
if ( unlikely(WSS_poll_close(https) != WSS_SUCCESS) ) { |
654 |
|
|
WSS_server_set_state(HALT_ERROR); |
655 |
|
|
} |
656 |
|
|
|
657 |
|
|
if ( unlikely(WSS_server_free(https) != 0) ) { |
658 |
|
|
WSS_server_set_state(HALT_ERROR); |
659 |
|
|
} |
660 |
|
|
|
661 |
|
|
WSS_log_trace("Freed memory associated with HTTPS server instance"); |
662 |
|
|
} |
663 |
|
|
|
664 |
|
|
if ( unlikely(WSS_SUCCESS != WSS_session_delete_all()) ) { |
665 |
|
|
WSS_server_set_state(HALT_ERROR); |
666 |
|
|
} |
667 |
|
|
|
668 |
|
|
WSS_log_trace("Freed all sessions"); |
669 |
|
|
|
670 |
|
|
if ( unlikely(WSS_SUCCESS != WSS_session_destroy_lock()) ) { |
671 |
|
|
WSS_server_set_state(HALT_ERROR); |
672 |
|
|
} |
673 |
|
|
|
674 |
|
|
WSS_log_trace("Destroyed session lock"); |
675 |
|
|
|
676 |
|
|
if ( unlikely(HALT_ERROR == state.state) ) { |
677 |
|
|
ret = EXIT_FAILURE; |
678 |
|
|
} |
679 |
|
|
|
680 |
|
|
WSS_destroy_subprotocols(); |
681 |
|
|
|
682 |
|
|
WSS_destroy_extensions(); |
683 |
|
|
|
684 |
|
|
pthread_mutex_destroy(&state.lock); |
685 |
|
|
|
686 |
|
|
return ret; |
687 |
|
|
} |