1 |
|
|
#include <stdio.h> /* fprintf */ |
2 |
|
|
#include <stdlib.h> /* NULL */ |
3 |
|
|
#include <getopt.h> /* getopt_long, struct option */ |
4 |
|
|
#include <string.h> /* strerror */ |
5 |
|
|
#include <errno.h> /* errno */ |
6 |
|
|
|
7 |
|
|
#include "server.h" /* server_start */ |
8 |
|
|
#include "config.h" /* config_t, WSS_config_load(), WSS_config_free() */ |
9 |
|
|
#include "error.h" /* wss_error_t */ |
10 |
|
|
#include "subprotocols.h" /* wss_subprotocol_t */ |
11 |
|
|
#include "alloc.h" /* WSS_malloc() */ |
12 |
|
|
#include "log.h" /* WSS_log_*() */ |
13 |
|
|
#include "predict.h" |
14 |
|
|
|
15 |
|
|
static void log_mutex(void *udata, int lock) { |
16 |
|
|
int err; |
17 |
|
|
pthread_mutex_t *l = (pthread_mutex_t *) udata; |
18 |
|
|
if (lock) { |
19 |
|
|
if ( unlikely((err = pthread_mutex_lock(l)) != 0) ) { |
20 |
|
|
WSS_log_error("Unable to lock log lock: %s", strerror(err)); |
21 |
|
|
} |
22 |
|
|
} else { |
23 |
|
|
if ( unlikely((err = pthread_mutex_unlock(l)) != 0) ) { |
24 |
|
|
WSS_log_error("Unable to unlock log lock: %s", strerror(err)); |
25 |
|
|
} |
26 |
|
|
} |
27 |
|
|
} |
28 |
|
|
|
29 |
|
|
static inline void wss_help(FILE *stream) { |
30 |
|
|
fprintf( |
31 |
|
|
stream, |
32 |
|
|
"Usage: ./WSServer [OPTIONS]\n\n" |
33 |
|
|
"OPTIONS:\n" |
34 |
|
|
"\t-h | --help show server arguments\n" |
35 |
|
|
"\t-c CONFIG_PATH | --config CONFIG_PATH provide JSON configuration file\n" |
36 |
|
|
); |
37 |
|
|
} |
38 |
|
|
|
39 |
|
|
int main(int argc, char *argv[]) { |
40 |
|
|
int err, res; |
41 |
|
|
wss_config_t config; |
42 |
|
|
FILE *file; |
43 |
|
|
pthread_mutex_t log_lock; |
44 |
|
|
char *echo = "subprotocols/echo/echo.so", *broadcast = "subprotocols/broadcast/broadcast.so"; |
45 |
|
|
|
46 |
|
|
#ifdef USE_RPMALLOC |
47 |
|
|
rpmalloc_initialize(); |
48 |
|
|
#endif |
49 |
|
|
|
50 |
|
|
static struct option long_options[] = { |
51 |
|
|
{"help" , no_argument, 0, 'h'}, |
52 |
|
|
{"config" , required_argument, 0, 'c'}, |
53 |
|
|
{0 , 0 , 0, 0 } |
54 |
|
|
}; |
55 |
|
|
|
56 |
|
|
// Default values |
57 |
|
|
config.subprotocols = NULL; |
58 |
|
|
config.subprotocols_length = 0; |
59 |
|
|
config.extensions = NULL; |
60 |
|
|
config.extensions_length = 0; |
61 |
|
|
config.favicon = NULL; |
62 |
|
|
config.origins = NULL; |
63 |
|
|
config.origins_length = 0; |
64 |
|
|
config.hosts = NULL; |
65 |
|
|
config.hosts_length = 0; |
66 |
|
|
config.paths = NULL; |
67 |
|
|
config.paths_length = 0; |
68 |
|
|
config.queries = NULL; |
69 |
|
|
config.queries_length = 0; |
70 |
|
|
config.string = NULL; |
71 |
|
|
config.data = NULL; |
72 |
|
|
config.length = 0; |
73 |
|
|
config.port_http = 80; |
74 |
|
|
config.port_https = 443; |
75 |
|
|
#ifdef NDEBUG |
76 |
|
|
config.log = WSS_LOG_INFO; |
77 |
|
|
#else |
78 |
|
|
config.log = WSS_LOG_TRACE; |
79 |
|
|
#endif |
80 |
|
|
config.size_header = 8192; |
81 |
|
|
config.size_payload = 16777215; |
82 |
|
|
config.size_uri = 8192; |
83 |
|
|
config.size_ringbuffer = 128; |
84 |
|
|
config.size_buffer = 32768; |
85 |
|
|
config.size_thread = 2097152; |
86 |
|
|
config.size_frame = 1048576; |
87 |
|
|
config.max_frames = 1048576; |
88 |
|
|
config.pool_workers = 4; |
89 |
|
|
config.pool_retries = 5; |
90 |
|
|
config.timeout_pings = 1; // Times that a client will be pinged before timeout occurs |
91 |
|
|
config.timeout_poll = -1; // Infinite |
92 |
|
|
config.timeout_read = 1000; // 1 Second |
93 |
|
|
config.timeout_write = 1000; // 1 Second |
94 |
|
|
config.timeout_client = 60000; // 1 Hour |
95 |
|
|
config.ssl_key = NULL; |
96 |
|
|
config.ssl_cert = NULL; |
97 |
|
|
config.ssl_dhparam = NULL; |
98 |
|
|
config.ssl_ca_file = NULL; |
99 |
|
|
config.ssl_ca_path = NULL; |
100 |
|
|
config.ssl_cipher_list = NULL; |
101 |
|
|
config.ssl_cipher_suites = NULL; |
102 |
|
|
config.ssl_compression = false; |
103 |
|
|
config.ssl_peer_cert = false; |
104 |
|
|
|
105 |
|
|
if ( NULL == (file = fopen("log/WSServer.log", "a+")) ) { |
106 |
|
|
WSS_config_free(&config); |
107 |
|
|
fprintf(stderr, "%s\n", strerror(errno)); |
108 |
|
|
#ifdef USE_RPMALLOC |
109 |
|
|
rpmalloc_finalize(); |
110 |
|
|
#endif |
111 |
|
|
return EXIT_FAILURE; |
112 |
|
|
} |
113 |
|
|
|
114 |
|
|
// Set file to write log to |
115 |
|
|
log_set_fp(file); |
116 |
|
|
|
117 |
|
|
// Set log level to default value until configuration is loaded |
118 |
|
|
log_set_level(config.log); |
119 |
|
|
|
120 |
|
|
if ( unlikely((err = pthread_mutex_init(&log_lock, NULL)) != 0) ) { |
121 |
|
|
WSS_config_free(&config); |
122 |
|
|
WSS_log_error("Unable to initialize log lock: %s", strerror(err)); |
123 |
|
|
fclose(file); |
124 |
|
|
#ifdef USE_RPMALLOC |
125 |
|
|
rpmalloc_finalize(); |
126 |
|
|
#endif |
127 |
|
|
return EXIT_FAILURE; |
128 |
|
|
} |
129 |
|
|
|
130 |
|
|
// Set lock to use in interal lock function |
131 |
|
|
log_set_udata(&log_lock); |
132 |
|
|
|
133 |
|
|
// Set lock function for logging functions |
134 |
|
|
log_set_lock(log_mutex); |
135 |
|
|
|
136 |
|
|
while ( likely((err = getopt_long(argc, argv, "c:h", long_options, NULL)) != -1)) { |
137 |
|
|
switch (err) { |
138 |
|
|
case 'c': |
139 |
|
|
if ( unlikely(WSS_SUCCESS != WSS_config_load(&config, optarg)) ) { |
140 |
|
|
WSS_config_free(&config); |
141 |
|
|
|
142 |
|
|
if ( unlikely((err = pthread_mutex_destroy(&log_lock)) != 0) ) { |
143 |
|
|
WSS_log_error("Unable to initialize log lock: %s", strerror(err)); |
144 |
|
|
} |
145 |
|
|
|
146 |
|
|
fclose(file); |
147 |
|
|
#ifdef USE_RPMALLOC |
148 |
|
|
rpmalloc_finalize(); |
149 |
|
|
#endif |
150 |
|
|
return EXIT_FAILURE; |
151 |
|
|
} |
152 |
|
|
break; |
153 |
|
|
case 'h': |
154 |
|
|
wss_help(stdout); |
155 |
|
|
WSS_config_free(&config); |
156 |
|
|
if ( unlikely((err = pthread_mutex_destroy(&log_lock)) != 0) ) { |
157 |
|
|
WSS_log_error("Unable to initialize log lock: %s", strerror(err)); |
158 |
|
|
fclose(file); |
159 |
|
|
#ifdef USE_RPMALLOC |
160 |
|
|
rpmalloc_finalize(); |
161 |
|
|
#endif |
162 |
|
|
return EXIT_FAILURE; |
163 |
|
|
} |
164 |
|
|
fclose(file); |
165 |
|
|
#ifdef USE_RPMALLOC |
166 |
|
|
rpmalloc_finalize(); |
167 |
|
|
#endif |
168 |
|
|
return EXIT_SUCCESS; |
169 |
|
|
default: |
170 |
|
|
wss_help(stderr); |
171 |
|
|
WSS_config_free(&config); |
172 |
|
|
if ( unlikely((err = pthread_mutex_destroy(&log_lock)) != 0) ) { |
173 |
|
|
WSS_log_error("Unable to initialize log lock: %s", strerror(err)); |
174 |
|
|
} |
175 |
|
|
fclose(file); |
176 |
|
|
#ifdef USE_RPMALLOC |
177 |
|
|
rpmalloc_finalize(); |
178 |
|
|
#endif |
179 |
|
|
return EXIT_FAILURE; |
180 |
|
|
} |
181 |
|
|
} |
182 |
|
|
|
183 |
|
|
// If in production mode do not print to stdout |
184 |
|
|
#ifdef NDEBUG |
185 |
|
|
WSS_log_info("Log is in quiet mode"); |
186 |
|
|
log_set_quiet(1); |
187 |
|
|
#endif |
188 |
|
|
|
189 |
|
|
// Set log level to what what specified in the configuration |
190 |
|
|
log_set_level(config.log); |
191 |
|
|
|
192 |
|
|
// Setting echo and broadcast protocols as default if none was loaded |
193 |
|
|
if ( config.subprotocols_length == 0 && config.subprotocols == NULL) { |
194 |
|
|
if ( NULL != (config.subprotocols = WSS_calloc(2, sizeof(char *)))) { |
195 |
|
|
if ( NULL != (config.subprotocols_config = WSS_calloc(2, sizeof(char *)))) { |
196 |
|
|
config.subprotocols[0] = echo; |
197 |
|
|
config.subprotocols[1] = broadcast; |
198 |
|
|
config.subprotocols_config[0] = NULL; |
199 |
|
|
config.subprotocols_config[1] = NULL; |
200 |
|
|
config.subprotocols_length = 2; |
201 |
|
|
} |
202 |
|
|
} |
203 |
|
|
} |
204 |
|
|
|
205 |
|
|
res = WSS_server_start(&config); |
206 |
|
|
|
207 |
|
|
if ( unlikely((err = pthread_mutex_destroy(&log_lock)) != 0) ) { |
208 |
|
|
WSS_log_error("Unable to initialize log lock: %s", strerror(err)); |
209 |
|
|
res = EXIT_FAILURE; |
210 |
|
|
} |
211 |
|
|
|
212 |
|
|
if ( unlikely(WSS_SUCCESS != WSS_config_free(&config)) ) { |
213 |
|
|
res = EXIT_FAILURE; |
214 |
|
|
} |
215 |
|
|
|
216 |
|
|
fclose(file); |
217 |
|
|
|
218 |
|
|
#ifdef USE_RPMALLOC |
219 |
|
|
rpmalloc_finalize(); |
220 |
|
|
#endif |
221 |
|
|
|
222 |
|
|
return res; |
223 |
|
|
} |