File: | lib/lwan.c |
Warning: | line 340, column 17 Potential leak of memory pointed to by 'key_copy' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * lwan - web server | |||
3 | * Copyright (c) 2012, 2013 L. A. F. Pereira <l@tia.mat.br> | |||
4 | * | |||
5 | * This program is free software; you can redistribute it and/or | |||
6 | * modify it under the terms of the GNU General Public License | |||
7 | * as published by the Free Software Foundation; either version 2 | |||
8 | * of the License, or any later version. | |||
9 | * | |||
10 | * This program is distributed in the hope that it will be useful, | |||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
13 | * GNU General Public License for more details. | |||
14 | * | |||
15 | * You should have received a copy of the GNU General Public License | |||
16 | * along with this program; if not, write to the Free Software | |||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, | |||
18 | * USA. | |||
19 | */ | |||
20 | ||||
21 | #define _GNU_SOURCE | |||
22 | #include <assert.h> | |||
23 | #include <ctype.h> | |||
24 | #include <dlfcn.h> | |||
25 | #include <errno(*__errno_location ()).h> | |||
26 | #include <fcntl.h> | |||
27 | #include <libproc.h> | |||
28 | #include <limits.h> | |||
29 | #include <signal.h> | |||
30 | #include <stdlib.h> | |||
31 | #include <string.h> | |||
32 | #include <sys/resource.h> | |||
33 | #include <sys/socket.h> | |||
34 | #include <sys/types.h> | |||
35 | #include <unistd.h> | |||
36 | ||||
37 | #include "lwan-private.h" | |||
38 | ||||
39 | #include "lwan-config.h" | |||
40 | #include "lwan-http-authorize.h" | |||
41 | ||||
42 | #if defined(LWAN_HAVE_LUA) | |||
43 | #include "lwan-lua.h" | |||
44 | #endif | |||
45 | ||||
46 | /* Ideally, this would check if all items in enum lwan_request_flags, | |||
47 | * when bitwise-or'd together, would not have have any bit set that | |||
48 | * is also set in REQUEST_METHOD_MASK. */ | |||
49 | static_assert_Static_assert(REQUEST_ACCEPT_DEFLATE > REQUEST_METHOD_MASK, | |||
50 | "enough bits to store request methods"); | |||
51 | ||||
52 | /* See detect_fastest_monotonic_clock() */ | |||
53 | clockid_t monotonic_clock_id = CLOCK_MONOTONIC1; | |||
54 | ||||
55 | static const struct lwan_config default_config = { | |||
56 | .listener = "localhost:8080", | |||
57 | .keep_alive_timeout = 15, | |||
58 | .quiet = false0, | |||
59 | .proxy_protocol = false0, | |||
60 | .allow_cors = false0, | |||
61 | .expires = 1 * ONE_WEEK(((60 * 60) * 24) * 7), | |||
62 | .n_threads = 0, | |||
63 | .request_buffer_size = DEFAULT_BUFFER_SIZE4096, | |||
64 | .max_post_data_size = 10 * DEFAULT_BUFFER_SIZE4096, | |||
65 | .allow_post_temp_file = false0, | |||
66 | .max_put_data_size = 10 * DEFAULT_BUFFER_SIZE4096, | |||
67 | .allow_put_temp_file = false0, | |||
68 | .use_dynamic_buffer = false0, | |||
69 | }; | |||
70 | ||||
71 | LWAN_HANDLER_ROUTE(brew_coffee, NULL /* do not autodetect this route */)static enum lwan_http_status lwan_handler_brew_coffee( struct lwan_request *, struct lwan_response *, void *); static const struct lwan_handler_info __attribute__((used, section("lwan_handler" ))) __attribute__((aligned(8))) lwan_handler_info_brew_coffee = { .name = "brew_coffee", .route = ((void*)0), .handler = lwan_handler_brew_coffee , }; __attribute__((used)) static enum lwan_http_status lwan_handler_brew_coffee ( struct lwan_request *request __attribute__((unused)), struct lwan_response *response __attribute__((unused)), void *data __attribute__ ((unused))) | |||
72 | { | |||
73 | /* Placeholder handler so that __start_lwan_handler and __stop_lwan_handler | |||
74 | * symbols will get defined. | |||
75 | */ | |||
76 | return HTTP_I_AM_A_TEAPOT; | |||
77 | } | |||
78 | ||||
79 | __attribute__((no_sanitize_address)) | |||
80 | static void *find_handler(const char *name) | |||
81 | { | |||
82 | const struct lwan_handler_info *handler; | |||
83 | ||||
84 | LWAN_SECTION_FOREACH(lwan_handler, handler)for (handler = ({ extern const typeof(*handler) __start_lwan_handler []; __start_lwan_handler; }); handler < ({ extern const typeof (*handler) __stop_lwan_handler[]; __stop_lwan_handler; }); (handler )++) { | |||
85 | if (streq(handler->name, name)) | |||
86 | return handler->handler; | |||
87 | } | |||
88 | ||||
89 | return NULL((void*)0); | |||
90 | } | |||
91 | ||||
92 | __attribute__((no_sanitize_address)) | |||
93 | static const struct lwan_module *find_module(const char *name) | |||
94 | { | |||
95 | const struct lwan_module_info *module; | |||
96 | ||||
97 | LWAN_SECTION_FOREACH(lwan_module, module)for (module = ({ extern const typeof(*module) __start_lwan_module []; __start_lwan_module; }); module < ({ extern const typeof (*module) __stop_lwan_module[]; __stop_lwan_module; }); (module )++) { | |||
98 | if (streq(module->name, name)) | |||
99 | return module->module; | |||
100 | } | |||
101 | ||||
102 | return NULL((void*)0); | |||
103 | } | |||
104 | ||||
105 | static void destroy_urlmap(void *data) | |||
106 | { | |||
107 | struct lwan_url_map *url_map = data; | |||
108 | ||||
109 | if (url_map->module) { | |||
110 | const struct lwan_module *module = url_map->module; | |||
111 | ||||
112 | if (module->destroy) | |||
113 | module->destroy(url_map->data); | |||
114 | } else if (url_map->data && url_map->flags & HANDLER_DATA_IS_HASH_TABLE) { | |||
115 | hash_free(url_map->data); | |||
116 | } | |||
117 | ||||
118 | free(url_map->authorization.realm); | |||
119 | free(url_map->authorization.password_file); | |||
120 | free((char *)url_map->prefix); | |||
121 | free(url_map); | |||
122 | } | |||
123 | ||||
124 | static struct lwan_url_map *add_url_map(struct lwan_trie *t, const char *prefix, | |||
125 | const struct lwan_url_map *map) | |||
126 | { | |||
127 | struct lwan_url_map *copy = malloc(sizeof(*copy)); | |||
128 | ||||
129 | if (!copy) | |||
130 | lwan_status_critical_perror("Could not copy URL map")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 130, __FUNCTION__, "Could not copy URL map"); | |||
131 | ||||
132 | memcpy(copy, map, sizeof(*copy)); | |||
133 | ||||
134 | copy->prefix = strdup(prefix ? prefix : copy->prefix); | |||
135 | if (!copy->prefix) | |||
136 | lwan_status_critical_perror("Could not copy URL prefix")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 136, __FUNCTION__, "Could not copy URL prefix"); | |||
137 | ||||
138 | copy->prefix_len = strlen(copy->prefix); | |||
139 | lwan_trie_add(t, copy->prefix, copy); | |||
140 | ||||
141 | return copy; | |||
142 | } | |||
143 | ||||
144 | static bool_Bool can_override_header(const char *name) | |||
145 | { | |||
146 | /* NOTE: Update lwan_prepare_response_header_full() in lwan-response.c | |||
147 | * if new headers are added here. */ | |||
148 | ||||
149 | if (strcaseequal_neutral(name, "Date")) | |||
150 | return false0; | |||
151 | if (strcaseequal_neutral(name, "Expires")) | |||
152 | return false0; | |||
153 | if (strcaseequal_neutral(name, "WWW-Authenticate")) | |||
154 | return false0; | |||
155 | if (strcaseequal_neutral(name, "Connection")) | |||
156 | return false0; | |||
157 | if (strcaseequal_neutral(name, "Content-Type")) | |||
158 | return false0; | |||
159 | if (strcaseequal_neutral(name, "Transfer-Encoding")) | |||
160 | return false0; | |||
161 | if (strcaseequal_neutral_len(name, "Access-Control-Allow-", | |||
162 | sizeof("Access-Control-Allow-") - 1)) | |||
163 | return false0; | |||
164 | ||||
165 | return true1; | |||
166 | } | |||
167 | ||||
168 | static void build_response_headers(struct lwan *l, | |||
169 | const struct lwan_key_value *kv) | |||
170 | { | |||
171 | struct lwan_strbuf strbuf; | |||
172 | bool_Bool set_server = false0; | |||
173 | ||||
174 | assert(l)((void) sizeof ((l) ? 1 : 0), __extension__ ({ if (l) ; else __assert_fail ("l", "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 174, __extension__ __PRETTY_FUNCTION__); })); | |||
175 | ||||
176 | lwan_strbuf_init(&strbuf); | |||
177 | ||||
178 | for (; kv && kv->key; kv++) { | |||
179 | if (!can_override_header(kv->key)) { | |||
180 | lwan_status_warning("Cannot override header '%s'", kv->key)lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 180, __FUNCTION__, "Cannot override header '%s'", kv->key ); | |||
181 | } else { | |||
182 | if (strcaseequal_neutral(kv->key, "Server")) | |||
183 | set_server = true1; | |||
184 | ||||
185 | lwan_strbuf_append_printf(&strbuf, "\r\n%s: %s", kv->key, | |||
186 | kv->value); | |||
187 | } | |||
188 | } | |||
189 | ||||
190 | if (!set_server) | |||
191 | lwan_strbuf_append_strz(&strbuf, "\r\nServer: lwan"); | |||
192 | ||||
193 | lwan_strbuf_append_strz(&strbuf, "\r\n\r\n"); | |||
194 | ||||
195 | l->headers = (struct lwan_value){.value = lwan_strbuf_get_buffer(&strbuf), | |||
196 | .len = lwan_strbuf_get_length(&strbuf)}; | |||
197 | } | |||
198 | ||||
199 | static void parse_global_headers(struct config *c, | |||
200 | struct lwan *lwan) | |||
201 | { | |||
202 | struct lwan_key_value_array hdrs; | |||
203 | const struct config_line *l; | |||
204 | struct lwan_key_value *kv; | |||
205 | ||||
206 | lwan_key_value_array_init(&hdrs); | |||
207 | ||||
208 | while ((l = config_read_line(c))) { | |||
209 | switch (l->type) { | |||
210 | case CONFIG_LINE_TYPE_SECTION: | |||
211 | config_error( | |||
212 | c, "No sections are supported under the 'headers' section"); | |||
213 | goto cleanup; | |||
214 | ||||
215 | case CONFIG_LINE_TYPE_LINE: | |||
216 | kv = lwan_key_value_array_append(&hdrs); | |||
217 | if (!kv) { | |||
218 | lwan_status_critical_perror(lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 219, __FUNCTION__, "Could not allocate memory for custom response header" ) | |||
219 | "Could not allocate memory for custom response header")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 219, __FUNCTION__, "Could not allocate memory for custom response header" ); | |||
220 | } | |||
221 | ||||
222 | kv->key = strdup(l->key); | |||
223 | if (!kv->key) { | |||
224 | lwan_status_critical_perror(lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 225, __FUNCTION__, "Could not allocate memory for custom response header" ) | |||
225 | "Could not allocate memory for custom response header")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 225, __FUNCTION__, "Could not allocate memory for custom response header" ); | |||
226 | } | |||
227 | ||||
228 | kv->value = strdup(l->value); | |||
229 | if (!kv->value) { | |||
230 | lwan_status_critical_perror(lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 231, __FUNCTION__, "Could not allocate memory for custom response header" ) | |||
231 | "Could not allocate memory for custom response header")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 231, __FUNCTION__, "Could not allocate memory for custom response header" ); | |||
232 | } | |||
233 | break; | |||
234 | ||||
235 | case CONFIG_LINE_TYPE_SECTION_END: | |||
236 | kv = lwan_key_value_array_append(&hdrs); | |||
237 | if (!kv) { | |||
238 | lwan_status_critical_perror(lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 239, __FUNCTION__, "Could not allocate memory for custom response header" ) | |||
239 | "Could not allocate memory for custom response header")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 239, __FUNCTION__, "Could not allocate memory for custom response header" ); | |||
240 | } | |||
241 | ||||
242 | kv->key = NULL((void*)0); | |||
243 | kv->value = NULL((void*)0); | |||
244 | ||||
245 | build_response_headers(lwan, lwan_key_value_array_get_array(&hdrs)); | |||
246 | goto cleanup; | |||
247 | } | |||
248 | } | |||
249 | ||||
250 | config_error(c, "EOF while looking for end of 'headers' section"); | |||
251 | ||||
252 | cleanup: | |||
253 | LWAN_ARRAY_FOREACH (&hdrs, kv)for (kv = (&hdrs)->base.base; kv < ((typeof(kv))(& hdrs)->base.base + (&hdrs)->base.elements); kv++) { | |||
254 | free(kv->key); | |||
255 | free(kv->value); | |||
256 | } | |||
257 | lwan_key_value_array_reset(&hdrs); | |||
258 | } | |||
259 | ||||
260 | static void parse_listener_prefix_authorization(struct config *c, | |||
261 | const struct config_line *l, | |||
262 | struct lwan_url_map *url_map) | |||
263 | { | |||
264 | if (!streq(l->value, "basic")) { | |||
265 | config_error(c, "Only basic authorization supported"); | |||
266 | return; | |||
267 | } | |||
268 | ||||
269 | memset(&url_map->authorization, 0, sizeof(url_map->authorization)); | |||
270 | ||||
271 | while ((l = config_read_line(c))) { | |||
272 | switch (l->type) { | |||
273 | case CONFIG_LINE_TYPE_LINE: | |||
274 | if (streq(l->key, "realm")) { | |||
275 | free(url_map->authorization.realm); | |||
276 | url_map->authorization.realm = strdup(l->value); | |||
277 | } else if (streq(l->key, "password_file")) { | |||
278 | free(url_map->authorization.password_file); | |||
279 | url_map->authorization.password_file = realpath(l->value, NULL((void*)0)); | |||
280 | if (!url_map->authorization.password_file) | |||
281 | config_error(c, "Could not determine full path for password file: %s", l->value); | |||
282 | } | |||
283 | break; | |||
284 | ||||
285 | case CONFIG_LINE_TYPE_SECTION: | |||
286 | config_error(c, "Unexpected section: %s", l->key); | |||
287 | goto error; | |||
288 | ||||
289 | case CONFIG_LINE_TYPE_SECTION_END: | |||
290 | if (!url_map->authorization.realm) | |||
291 | url_map->authorization.realm = strdup("Lwan"); | |||
292 | if (!url_map->authorization.password_file) | |||
293 | url_map->authorization.password_file = strdup("htpasswd"); | |||
294 | ||||
295 | url_map->flags |= HANDLER_MUST_AUTHORIZE; | |||
296 | return; | |||
297 | } | |||
298 | } | |||
299 | ||||
300 | config_error(c, "Could not find end of authorization section"); | |||
301 | ||||
302 | error: | |||
303 | free(url_map->authorization.realm); | |||
304 | free(url_map->authorization.password_file); | |||
305 | } | |||
306 | ||||
307 | __attribute__((no_sanitize_address)) | |||
308 | static const char *get_module_name(const struct lwan_module *module) | |||
309 | { | |||
310 | const struct lwan_module_info *iter; | |||
311 | ||||
312 | LWAN_SECTION_FOREACH(lwan_module, iter)for (iter = ({ extern const typeof(*iter) __start_lwan_module []; __start_lwan_module; }); iter < ({ extern const typeof (*iter) __stop_lwan_module[]; __stop_lwan_module; }); (iter)++ ) { | |||
313 | if (iter->module == module) | |||
314 | return iter->name; | |||
315 | } | |||
316 | ||||
317 | return "<unknown>"; | |||
318 | } | |||
319 | ||||
320 | static void parse_listener_prefix(struct config *c, | |||
321 | const struct config_line *l, | |||
322 | struct lwan *lwan, | |||
323 | const struct lwan_module *module, | |||
324 | void *handler) | |||
325 | { | |||
326 | struct lwan_url_map url_map = {}; | |||
327 | struct hash *hash = hash_str_new(free, free); | |||
328 | char *prefix = strdupa(l->value)(__extension__ ({ const char *__old = (l->value); size_t __len = strlen (__old) + 1; char *__new = (char *) __builtin_alloca (__len); (char *) memcpy (__new, __old, __len); })); | |||
329 | struct config *isolated; | |||
330 | ||||
331 | if (!hash) | |||
332 | lwan_status_critical("Could not allocate hash table")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 332, __FUNCTION__, "Could not allocate hash table"); | |||
333 | ||||
334 | isolated = config_isolate_section(c, l); | |||
335 | if (!isolated) { | |||
336 | config_error(c, "Could not isolate configuration file"); | |||
337 | goto out; | |||
338 | } | |||
339 | ||||
340 | while ((l = config_read_line(c))) { | |||
| ||||
341 | switch (l->type) { | |||
342 | case CONFIG_LINE_TYPE_LINE: { | |||
343 | char *key_copy = strdup(l->key); | |||
344 | char *value_copy = strdup(l->value); | |||
345 | ||||
346 | if (!key_copy) | |||
347 | lwan_status_critical("Could not copy key from config file")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 347, __FUNCTION__, "Could not copy key from config file"); | |||
348 | if (!value_copy) | |||
349 | lwan_status_critical("Could not copy value from config file")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 349, __FUNCTION__, "Could not copy value from config file"); | |||
350 | ||||
351 | hash_add(hash, key_copy, value_copy); | |||
352 | break; | |||
353 | } | |||
354 | ||||
355 | case CONFIG_LINE_TYPE_SECTION: | |||
356 | if (streq(l->key, "authorization")) { | |||
357 | parse_listener_prefix_authorization(c, l, &url_map); | |||
358 | } else if (!config_skip_section(c, l)) { | |||
359 | config_error(c, "Could not skip section"); | |||
360 | goto out; | |||
361 | } | |||
362 | break; | |||
363 | ||||
364 | case CONFIG_LINE_TYPE_SECTION_END: | |||
365 | goto add_map; | |||
366 | } | |||
367 | } | |||
368 | ||||
369 | config_error(c, "Expecting section end while parsing prefix"); | |||
370 | goto out; | |||
371 | ||||
372 | add_map: | |||
373 | assert((handler && !module) || (!handler && module))((void) sizeof (((handler && !module) || (!handler && module)) ? 1 : 0), __extension__ ({ if ((handler && ! module) || (!handler && module)) ; else __assert_fail ("(handler && !module) || (!handler && module)" , "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 373, __extension__ __PRETTY_FUNCTION__); })); | |||
374 | ||||
375 | if (handler) { | |||
376 | url_map.handler = handler; | |||
377 | url_map.flags |= HANDLER_PARSE_MASK | HANDLER_DATA_IS_HASH_TABLE; | |||
378 | url_map.data = hash; | |||
379 | url_map.module = NULL((void*)0); | |||
380 | ||||
381 | hash = NULL((void*)0); | |||
382 | } else if (module->create_from_hash && module->handle_request) { | |||
383 | lwan_status_debug("Initializing module %s from config",lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 384, __FUNCTION__, "Initializing module %s from config", get_module_name (module)) | |||
384 | get_module_name(module))lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 384, __FUNCTION__, "Initializing module %s from config", get_module_name (module)); | |||
385 | ||||
386 | url_map.data = module->create_from_hash(prefix, hash); | |||
387 | if (!url_map.data) { | |||
388 | config_error(c, "Could not create module instance"); | |||
389 | goto out; | |||
390 | } | |||
391 | ||||
392 | if (module->parse_conf && !module->parse_conf(url_map.data, isolated)) { | |||
393 | const char *msg = config_last_error(isolated); | |||
394 | ||||
395 | config_error(c, "Error from module: %s", msg ? msg : "Unknown"); | |||
396 | goto out; | |||
397 | } | |||
398 | ||||
399 | url_map.handler = module->handle_request; | |||
400 | url_map.flags |= module->flags; | |||
401 | url_map.module = module; | |||
402 | } else if (UNLIKELY(!module->create_from_hash)__builtin_expect(((!module->create_from_hash)), (0))) { | |||
403 | config_error(c, "Module isn't prepared to load settings from a file; " | |||
404 | "create_from_hash() method isn't present"); | |||
405 | goto out; | |||
406 | } else if (UNLIKELY(!module->handle_request)__builtin_expect(((!module->handle_request)), (0))) { | |||
407 | config_error(c, "Module does not have handle_request() method"); | |||
408 | goto out; | |||
409 | } | |||
410 | ||||
411 | add_url_map(&lwan->url_map_trie, prefix, &url_map); | |||
412 | ||||
413 | out: | |||
414 | hash_free(hash); | |||
415 | config_close(isolated); | |||
416 | } | |||
417 | ||||
418 | static void register_url_map(struct lwan *l, const struct lwan_url_map *map) | |||
419 | { | |||
420 | struct lwan_url_map *copy = add_url_map(&l->url_map_trie, NULL((void*)0), map); | |||
421 | ||||
422 | if (copy->module && copy->module->create) { | |||
423 | lwan_status_debug("Initializing module %s from struct",lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 424, __FUNCTION__, "Initializing module %s from struct", get_module_name (copy->module)) | |||
424 | get_module_name(copy->module))lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 424, __FUNCTION__, "Initializing module %s from struct", get_module_name (copy->module)); | |||
425 | ||||
426 | copy->data = copy->module->create(map->prefix, copy->args); | |||
427 | if (!copy->data) { | |||
428 | lwan_status_critical("Could not initialize module %s",lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 429, __FUNCTION__, "Could not initialize module %s", get_module_name (copy->module)) | |||
429 | get_module_name(copy->module))lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 429, __FUNCTION__, "Could not initialize module %s", get_module_name (copy->module)); | |||
430 | } | |||
431 | ||||
432 | copy->flags = copy->module->flags; | |||
433 | copy->handler = copy->module->handle_request; | |||
434 | } else { | |||
435 | copy->flags = HANDLER_PARSE_MASK; | |||
436 | } | |||
437 | } | |||
438 | ||||
439 | void lwan_set_url_map(struct lwan *l, const struct lwan_url_map *map) | |||
440 | { | |||
441 | lwan_trie_destroy(&l->url_map_trie); | |||
442 | if (UNLIKELY(!lwan_trie_init(&l->url_map_trie, destroy_urlmap))__builtin_expect(((!lwan_trie_init(&l->url_map_trie, destroy_urlmap ))), (0))) | |||
443 | lwan_status_critical_perror("Could not initialize trie")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 443, __FUNCTION__, "Could not initialize trie"); | |||
444 | ||||
445 | for (; map->prefix; map++) | |||
446 | register_url_map(l, map); | |||
447 | } | |||
448 | ||||
449 | __attribute__((no_sanitize_address)) | |||
450 | void lwan_detect_url_map(struct lwan *l) | |||
451 | { | |||
452 | const struct lwan_handler_info *iter; | |||
453 | ||||
454 | lwan_trie_destroy(&l->url_map_trie); | |||
455 | if (UNLIKELY(!lwan_trie_init(&l->url_map_trie, destroy_urlmap))__builtin_expect(((!lwan_trie_init(&l->url_map_trie, destroy_urlmap ))), (0))) | |||
456 | lwan_status_critical_perror("Could not initialize trie")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 456, __FUNCTION__, "Could not initialize trie"); | |||
457 | ||||
458 | LWAN_SECTION_FOREACH(lwan_handler, iter)for (iter = ({ extern const typeof(*iter) __start_lwan_handler []; __start_lwan_handler; }); iter < ({ extern const typeof (*iter) __stop_lwan_handler[]; __stop_lwan_handler; }); (iter )++) { | |||
459 | if (!iter->route) | |||
460 | continue; | |||
461 | ||||
462 | lwan_status_debug("Using handler `%s' for route `%s'",lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 463, __FUNCTION__, "Using handler `%s' for route `%s'", iter ->name, iter->route) | |||
463 | iter->name, iter->route)lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 463, __FUNCTION__, "Using handler `%s' for route `%s'", iter ->name, iter->route); | |||
464 | ||||
465 | const struct lwan_url_map map = {.prefix = iter->route, | |||
466 | .handler = iter->handler}; | |||
467 | register_url_map(l, &map); | |||
468 | } | |||
469 | } | |||
470 | ||||
471 | const char *lwan_get_config_path(char *path_buf, size_t path_buf_len) | |||
472 | { | |||
473 | char buffer[PATH_MAX4096]; | |||
474 | ||||
475 | if (proc_pidpath(getpid(), buffer, sizeof(buffer)) < 0) | |||
476 | goto out; | |||
477 | ||||
478 | char *path = strrchr(buffer, '/'); | |||
479 | if (!path) | |||
480 | goto out; | |||
481 | int ret = snprintf(path_buf, path_buf_len, "%s.conf", path + 1); | |||
482 | if (ret < 0 || ret >= (int)path_buf_len) | |||
483 | goto out; | |||
484 | ||||
485 | return path_buf; | |||
486 | ||||
487 | out: | |||
488 | return "lwan.conf"; | |||
489 | } | |||
490 | ||||
491 | static void parse_tls_listener(struct config *conf, const struct config_line *line, struct lwan *lwan) | |||
492 | { | |||
493 | #if !defined(LWAN_HAVE_MBEDTLS) | |||
494 | config_error(conf, "Lwan has been built without mbedTLS support"); | |||
495 | return; | |||
496 | #endif | |||
497 | ||||
498 | lwan->config.tls_listener = strdup(line->value); | |||
499 | if (!lwan->config.tls_listener) { | |||
500 | config_error(conf, "Could not allocate memory for tls_listener"); | |||
501 | return; | |||
502 | } | |||
503 | ||||
504 | lwan->config.ssl.cert = NULL((void*)0); | |||
505 | lwan->config.ssl.key = NULL((void*)0); | |||
506 | ||||
507 | while ((line = config_read_line(conf))) { | |||
508 | switch (line->type) { | |||
509 | case CONFIG_LINE_TYPE_SECTION_END: | |||
510 | if (!lwan->config.ssl.cert) | |||
511 | config_error(conf, "Missing path to certificate"); | |||
512 | if (!lwan->config.ssl.key) | |||
513 | config_error(conf, "Missing path to private key"); | |||
514 | return; | |||
515 | case CONFIG_LINE_TYPE_SECTION: | |||
516 | config_error(conf, "Unexpected section: %s", line->key); | |||
517 | return; | |||
518 | case CONFIG_LINE_TYPE_LINE: | |||
519 | if (streq(line->key, "cert")) { | |||
520 | free(lwan->config.ssl.cert); | |||
521 | lwan->config.ssl.cert = strdup(line->value); | |||
522 | if (!lwan->config.ssl.cert) | |||
523 | return lwan_status_critical("Could not copy string")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 523, __FUNCTION__, "Could not copy string"); | |||
524 | } else if (streq(line->key, "key")) { | |||
525 | free(lwan->config.ssl.key); | |||
526 | lwan->config.ssl.key = strdup(line->value); | |||
527 | if (!lwan->config.ssl.key) | |||
528 | return lwan_status_critical("Could not copy string")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 528, __FUNCTION__, "Could not copy string"); | |||
529 | } else if (streq(line->key, "hsts")) { | |||
530 | lwan->config.ssl.send_hsts_header = parse_bool(line->value, false0); | |||
531 | } else { | |||
532 | config_error(conf, "Unexpected key: %s", line->key); | |||
533 | } | |||
534 | } | |||
535 | } | |||
536 | ||||
537 | config_error(conf, "Expecting section end while parsing SSL configuration"); | |||
538 | } | |||
539 | ||||
540 | static void | |||
541 | parse_listener(struct config *c, const struct config_line *l, struct lwan *lwan) | |||
542 | { | |||
543 | lwan->config.listener = strdup(l->value); | |||
544 | if (!lwan->config.listener) | |||
545 | config_error(c, "Could not allocate memory for listener"); | |||
546 | ||||
547 | while ((l = config_read_line(c))) { | |||
548 | switch (l->type) { | |||
549 | case CONFIG_LINE_TYPE_LINE: | |||
550 | config_error(c, "Unexpected key %s", l->key); | |||
551 | return; | |||
552 | case CONFIG_LINE_TYPE_SECTION: | |||
553 | config_error(c, "Unexpected section %s", l->key); | |||
554 | return; | |||
555 | case CONFIG_LINE_TYPE_SECTION_END: | |||
556 | return; | |||
557 | } | |||
558 | } | |||
559 | ||||
560 | config_error(c, "Unexpected EOF while parsing listener"); | |||
561 | } | |||
562 | ||||
563 | static void | |||
564 | parse_site(struct config *c, const struct config_line *l, struct lwan *lwan) | |||
565 | { | |||
566 | while ((l = config_read_line(c))) { | |||
567 | switch (l->type) { | |||
568 | case CONFIG_LINE_TYPE_LINE: | |||
569 | config_error(c, "Expecting prefix section"); | |||
570 | return; | |||
571 | case CONFIG_LINE_TYPE_SECTION: | |||
572 | /* FIXME: per-site authorization? */ | |||
573 | ||||
574 | if (l->key[0] == '&') { | |||
575 | void *handler = find_handler(l->key + 1); | |||
576 | if (handler) { | |||
577 | parse_listener_prefix(c, l, lwan, NULL((void*)0), handler); | |||
578 | continue; | |||
579 | } | |||
580 | ||||
581 | config_error(c, "Could not find handler name: %s", l->key + 1); | |||
582 | return; | |||
583 | } | |||
584 | ||||
585 | const struct lwan_module *module = find_module(l->key); | |||
586 | if (module) { | |||
587 | parse_listener_prefix(c, l, lwan, module, NULL((void*)0)); | |||
588 | continue; | |||
589 | } | |||
590 | ||||
591 | config_error(c, "Invalid section or module not found: %s", l->key); | |||
592 | return; | |||
593 | case CONFIG_LINE_TYPE_SECTION_END: | |||
594 | return; | |||
595 | } | |||
596 | } | |||
597 | ||||
598 | config_error(c, "Expecting section end while parsing listener"); | |||
599 | } | |||
600 | ||||
601 | static bool_Bool setup_from_config(struct lwan *lwan, const char *path) | |||
602 | { | |||
603 | const struct config_line *line; | |||
604 | struct config *conf; | |||
605 | bool_Bool has_site = false0; | |||
606 | bool_Bool has_listener = false0; | |||
607 | bool_Bool has_tls_listener = false0; | |||
608 | char path_buf[PATH_MAX4096]; | |||
609 | ||||
610 | if (!path
| |||
611 | path = lwan_get_config_path(path_buf, sizeof(path_buf)); | |||
612 | lwan_status_info("Loading configuration file: %s", path)lwan_status_info_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 612, __FUNCTION__, "Loading configuration file: %s", path); | |||
613 | ||||
614 | conf = config_open(path); | |||
615 | if (!conf) | |||
616 | return false0; | |||
617 | ||||
618 | if (!lwan_trie_init(&lwan->url_map_trie, destroy_urlmap)) | |||
619 | return false0; | |||
620 | ||||
621 | while ((line = config_read_line(conf))) { | |||
622 | switch (line->type) { | |||
623 | case CONFIG_LINE_TYPE_LINE: | |||
624 | if (streq(line->key, "keep_alive_timeout")) { | |||
625 | lwan->config.keep_alive_timeout = (unsigned int)parse_long( | |||
626 | line->value, default_config.keep_alive_timeout); | |||
627 | } else if (streq(line->key, "quiet")) { | |||
628 | lwan->config.quiet = | |||
629 | parse_bool(line->value, default_config.quiet); | |||
630 | } else if (streq(line->key, "proxy_protocol")) { | |||
631 | lwan->config.proxy_protocol = | |||
632 | parse_bool(line->value, default_config.proxy_protocol); | |||
633 | } else if (streq(line->key, "allow_cors")) { | |||
634 | lwan->config.allow_cors = | |||
635 | parse_bool(line->value, default_config.allow_cors); | |||
636 | } else if (streq(line->key, "use_dynamic_buffer")) { | |||
637 | lwan->config.use_dynamic_buffer = | |||
638 | parse_bool(line->value, default_config.use_dynamic_buffer); | |||
639 | } else if (streq(line->key, "expires")) { | |||
640 | lwan->config.expires = | |||
641 | parse_time_period(line->value, default_config.expires); | |||
642 | } else if (streq(line->key, "error_template")) { | |||
643 | free(lwan->config.error_template); | |||
644 | lwan->config.error_template = strdup(line->value); | |||
645 | } else if (streq(line->key, "threads")) { | |||
646 | long n_threads = | |||
647 | parse_long(line->value, default_config.n_threads); | |||
648 | if (n_threads < 0) | |||
649 | config_error(conf, "Invalid number of threads: %ld", | |||
650 | n_threads); | |||
651 | lwan->config.n_threads = (unsigned int)n_threads; | |||
652 | } else if (streq(line->key, "request_buffer_size")) { | |||
653 | long request_buffer_size = parse_long( | |||
654 | line->value, (long)default_config.request_buffer_size); | |||
655 | ||||
656 | if (request_buffer_size < 0) { | |||
657 | config_error(conf, "Negative request buffer size requested"); | |||
658 | } else if (request_buffer_size > 16 * (1 << 20)) { | |||
659 | config_error(conf, | |||
660 | "Request buffer can't be over 16MiB"); | |||
661 | } else if (request_buffer_size < DEFAULT_BUFFER_SIZE4096) { | |||
662 | lwan_status_warning("Request buffer size of %ld is smaller than the "lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 666, __FUNCTION__, "Request buffer size of %ld is smaller than the " "recommended minimum of %d bytes. This might not " "be sufficient!" , request_buffer_size, 4096) | |||
663 | "recommended minimum of %d bytes. This might not "lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 666, __FUNCTION__, "Request buffer size of %ld is smaller than the " "recommended minimum of %d bytes. This might not " "be sufficient!" , request_buffer_size, 4096) | |||
664 | "be sufficient!",lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 666, __FUNCTION__, "Request buffer size of %ld is smaller than the " "recommended minimum of %d bytes. This might not " "be sufficient!" , request_buffer_size, 4096) | |||
665 | request_buffer_size,lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 666, __FUNCTION__, "Request buffer size of %ld is smaller than the " "recommended minimum of %d bytes. This might not " "be sufficient!" , request_buffer_size, 4096) | |||
666 | DEFAULT_BUFFER_SIZE)lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 666, __FUNCTION__, "Request buffer size of %ld is smaller than the " "recommended minimum of %d bytes. This might not " "be sufficient!" , request_buffer_size, 4096); | |||
667 | } | |||
668 | ||||
669 | lwan->config.request_buffer_size = (size_t)request_buffer_size; | |||
670 | } else if (streq(line->key, "max_post_data_size")) { | |||
671 | long max_post_data_size = parse_long( | |||
672 | line->value, (long)default_config.max_post_data_size); | |||
673 | ||||
674 | if (max_post_data_size < 0) { | |||
675 | config_error(conf, "Negative maximum post data size"); | |||
676 | } else if (max_post_data_size > 128 * (1 << 20)) { | |||
677 | config_error(conf, | |||
678 | "Maximum post data can't be over 128MiB"); | |||
679 | } | |||
680 | ||||
681 | lwan->config.max_post_data_size = (size_t)max_post_data_size; | |||
682 | } else if (streq(line->key, "max_put_data_size")) { | |||
683 | long max_put_data_size = parse_long( | |||
684 | line->value, (long)default_config.max_put_data_size); | |||
685 | ||||
686 | if (max_put_data_size < 0) { | |||
687 | config_error(conf, "Negative maximum put data size"); | |||
688 | } else if (max_put_data_size > 128 * (1 << 20)) { | |||
689 | config_error(conf, | |||
690 | "Maximum put data can't be over 128MiB"); | |||
691 | } | |||
692 | lwan->config.max_put_data_size = (size_t)max_put_data_size; | |||
693 | } else if (streq(line->key, "allow_temp_files")) { | |||
694 | bool_Bool has_post, has_put; | |||
695 | ||||
696 | if (strstr(line->value, "all")) { | |||
697 | has_post = has_put = true1; | |||
698 | } else { | |||
699 | has_post = !!strstr(line->value, "post"); | |||
700 | has_put = !!strstr(line->value, "put"); | |||
701 | } | |||
702 | ||||
703 | lwan->config.allow_post_temp_file = has_post; | |||
704 | lwan->config.allow_put_temp_file = has_put; | |||
705 | } else { | |||
706 | config_error(conf, "Unknown config key: %s", line->key); | |||
707 | } | |||
708 | break; | |||
709 | case CONFIG_LINE_TYPE_SECTION: | |||
710 | if (streq(line->key, "site")) { | |||
711 | if (!has_site
| |||
712 | parse_site(conf, line, lwan); | |||
713 | has_site = true1; | |||
714 | } else { | |||
715 | config_error(conf, "Only one site may be configured"); | |||
716 | } | |||
717 | } else if (streq(line->key, "straitjacket")) { | |||
718 | lwan_straitjacket_enforce_from_config(conf); | |||
719 | } else if (streq(line->key, "headers")) { | |||
720 | parse_global_headers(conf, lwan); | |||
721 | } else if (streq(line->key, "listener")) { | |||
722 | if (has_listener) { | |||
723 | config_error(conf, "Listener already set up"); | |||
724 | } else { | |||
725 | parse_listener(conf, line, lwan); | |||
726 | has_listener = true1; | |||
727 | } | |||
728 | } else if (streq(line->key, "tls_listener")) { | |||
729 | if (has_tls_listener) { | |||
730 | config_error(conf, "TLS Listener already set up"); | |||
731 | } else { | |||
732 | parse_tls_listener(conf, line, lwan); | |||
733 | has_tls_listener = true1; | |||
734 | } | |||
735 | } else { | |||
736 | config_error(conf, "Unknown section type: %s", line->key); | |||
737 | } | |||
738 | break; | |||
739 | case CONFIG_LINE_TYPE_SECTION_END: | |||
740 | config_error(conf, "Unexpected section end"); | |||
741 | } | |||
742 | } | |||
743 | ||||
744 | if (config_last_error(conf)) { | |||
745 | lwan_status_critical("Error on config file \"%s\", line %d: %s", path,lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 746, __FUNCTION__, "Error on config file \"%s\", line %d: %s" , path, config_cur_line(conf), config_last_error(conf)) | |||
746 | config_cur_line(conf), config_last_error(conf))lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 746, __FUNCTION__, "Error on config file \"%s\", line %d: %s" , path, config_cur_line(conf), config_last_error(conf)); | |||
747 | lwan_trie_destroy(&lwan->url_map_trie); | |||
748 | } | |||
749 | ||||
750 | config_close(conf); | |||
751 | ||||
752 | return true1; | |||
753 | } | |||
754 | ||||
755 | static void try_setup_from_config(struct lwan *l, | |||
756 | const struct lwan_config *config) | |||
757 | { | |||
758 | if (!setup_from_config(l, config->config_file_path)) { | |||
759 | if (config->config_file_path) { | |||
760 | lwan_status_critical("Could not read config file: %s",lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 761, __FUNCTION__, "Could not read config file: %s", config ->config_file_path) | |||
761 | config->config_file_path)lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 761, __FUNCTION__, "Could not read config file: %s", config ->config_file_path); | |||
762 | } | |||
763 | } | |||
764 | ||||
765 | lwan_status_init(l); /* `quiet` key might have changed value. */ | |||
766 | ||||
767 | l->config.request_flags = | |||
768 | (l->config.proxy_protocol ? REQUEST_ALLOW_PROXY_REQS : 0) | | |||
769 | (l->config.allow_cors ? REQUEST_ALLOW_CORS : 0) | | |||
770 | (l->config.ssl.send_hsts_header ? REQUEST_WANTS_HSTS_HEADER : 0); | |||
771 | } | |||
772 | ||||
773 | static rlim_t setup_open_file_count_limits(void) | |||
774 | { | |||
775 | struct rlimit r; | |||
776 | ||||
777 | if (getrlimit(RLIMIT_NOFILERLIMIT_NOFILE, &r) < 0) { | |||
778 | lwan_status_perror("Could not obtain maximum number of file "lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 780, __FUNCTION__, "Could not obtain maximum number of file " "descriptors. Assuming %d", 256) | |||
779 | "descriptors. Assuming %d",lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 780, __FUNCTION__, "Could not obtain maximum number of file " "descriptors. Assuming %d", 256) | |||
780 | OPEN_MAX)lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 780, __FUNCTION__, "Could not obtain maximum number of file " "descriptors. Assuming %d", 256); | |||
781 | return OPEN_MAX256; | |||
782 | } | |||
783 | ||||
784 | if (r.rlim_max != r.rlim_cur) { | |||
785 | const rlim_t current = r.rlim_cur; | |||
786 | ||||
787 | if (r.rlim_max == RLIM_INFINITY0xffffffffffffffffuLL && r.rlim_cur < OPEN_MAX256) { | |||
788 | r.rlim_cur = OPEN_MAX256; | |||
789 | } else if (r.rlim_cur < r.rlim_max) { | |||
790 | r.rlim_cur = r.rlim_max; | |||
791 | } else { | |||
792 | /* Shouldn't happen, so just return the current value. */ | |||
793 | goto out; | |||
794 | } | |||
795 | ||||
796 | if (setrlimit(RLIMIT_NOFILERLIMIT_NOFILE, &r) < 0) { | |||
797 | lwan_status_perror("Could not raise maximum number of file "lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 799, __FUNCTION__, "Could not raise maximum number of file " "descriptors to %" "l" "u" ". Leaving at " "%" "l" "u", r.rlim_max , current) | |||
798 | "descriptors to %" PRIu64 ". Leaving at "lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 799, __FUNCTION__, "Could not raise maximum number of file " "descriptors to %" "l" "u" ". Leaving at " "%" "l" "u", r.rlim_max , current) | |||
799 | "%" PRIu64, r.rlim_max, current)lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 799, __FUNCTION__, "Could not raise maximum number of file " "descriptors to %" "l" "u" ". Leaving at " "%" "l" "u", r.rlim_max , current); | |||
800 | r.rlim_cur = current; | |||
801 | } | |||
802 | } | |||
803 | ||||
804 | out: | |||
805 | return r.rlim_cur; | |||
806 | } | |||
807 | ||||
808 | static void allocate_connections(struct lwan *l, size_t max_open_files) | |||
809 | { | |||
810 | const size_t sz = max_open_files * sizeof(struct lwan_connection); | |||
811 | ||||
812 | l->conns = lwan_aligned_alloc(sz, 64); | |||
813 | if (UNLIKELY(!l->conns)__builtin_expect(((!l->conns)), (0))) | |||
814 | lwan_status_critical_perror("lwan_alloc_aligned")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 814, __FUNCTION__, "lwan_alloc_aligned"); | |||
815 | ||||
816 | memset(l->conns, 0, sz); | |||
817 | } | |||
818 | ||||
819 | static void get_number_of_cpus(struct lwan *l) | |||
820 | { | |||
821 | long n_online_cpus = sysconf(_SC_NPROCESSORS_ONLN_SC_NPROCESSORS_ONLN); | |||
822 | long n_available_cpus = sysconf(_SC_NPROCESSORS_CONF_SC_NPROCESSORS_CONF); | |||
823 | ||||
824 | if (n_online_cpus < 0) { | |||
825 | lwan_status_warning(lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 826, __FUNCTION__, "Could not get number of online CPUs, assuming 1 CPU" ) | |||
826 | "Could not get number of online CPUs, assuming 1 CPU")lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 826, __FUNCTION__, "Could not get number of online CPUs, assuming 1 CPU" ); | |||
827 | n_online_cpus = 1; | |||
828 | } | |||
829 | ||||
830 | if (n_available_cpus < 0) { | |||
831 | lwan_status_warning(lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 833, __FUNCTION__, "Could not get number of available CPUs, assuming %ld CPUs" , n_online_cpus) | |||
832 | "Could not get number of available CPUs, assuming %ld CPUs",lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 833, __FUNCTION__, "Could not get number of available CPUs, assuming %ld CPUs" , n_online_cpus) | |||
833 | n_online_cpus)lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 833, __FUNCTION__, "Could not get number of available CPUs, assuming %ld CPUs" , n_online_cpus); | |||
834 | n_available_cpus = n_online_cpus; | |||
835 | } | |||
836 | ||||
837 | l->online_cpus = (unsigned int)n_online_cpus; | |||
838 | l->available_cpus = (unsigned int)n_available_cpus; | |||
839 | } | |||
840 | ||||
841 | void lwan_init(struct lwan *l) { lwan_init_with_config(l, &default_config); } | |||
| ||||
842 | ||||
843 | const struct lwan_config *lwan_get_default_config(void) | |||
844 | { | |||
845 | return &default_config; | |||
846 | } | |||
847 | ||||
848 | static char *dup_or_null(const char *s) | |||
849 | { | |||
850 | return s ? strdup(s) : NULL((void*)0); | |||
851 | } | |||
852 | ||||
853 | void lwan_init_with_config(struct lwan *l, const struct lwan_config *config) | |||
854 | { | |||
855 | /* Load defaults */ | |||
856 | memset(l, 0, sizeof(*l)); | |||
857 | memcpy(&l->config, config, sizeof(*config)); | |||
858 | l->config.listener = dup_or_null(l->config.listener); | |||
859 | l->config.config_file_path = dup_or_null(l->config.config_file_path); | |||
860 | l->config.ssl.key = dup_or_null(l->config.ssl.key); | |||
861 | l->config.ssl.cert = dup_or_null(l->config.ssl.cert); | |||
862 | ||||
863 | /* Initialize status first, as it is used by other things during | |||
864 | * their initialization. */ | |||
865 | lwan_status_init(l); | |||
866 | ||||
867 | /* These will only print debugging messages. Debug messages are always | |||
868 | * printed if we're on a debug build, so the quiet setting will be | |||
869 | * respected. */ | |||
870 | lwan_job_thread_init(); | |||
871 | lwan_tables_init(); | |||
872 | ||||
873 | /* Get the number of CPUs here because straightjacket might be active | |||
874 | * and this will block access to /proc and /sys, which will cause | |||
875 | * get_number_of_cpus() to get incorrect fallback values. */ | |||
876 | get_number_of_cpus(l); | |||
877 | ||||
878 | try_setup_from_config(l, config); | |||
879 | ||||
880 | if (!l->headers.len) | |||
881 | build_response_headers(l, config->global_headers); | |||
882 | ||||
883 | lwan_response_init(l); | |||
884 | ||||
885 | /* Continue initialization as normal. */ | |||
886 | lwan_status_debug("Initializing lwan web server")lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 886, __FUNCTION__, "Initializing lwan web server"); | |||
887 | ||||
888 | if (!l->config.n_threads) { | |||
889 | l->thread.count = l->online_cpus; | |||
890 | if (l->thread.count == 1) | |||
891 | l->thread.count = 2; | |||
892 | } else if (l->config.n_threads > 3 * l->online_cpus) { | |||
893 | l->thread.count = l->online_cpus * 3; | |||
894 | ||||
895 | lwan_status_warning("%d threads requested, but only %d online CPUs "lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 898, __FUNCTION__, "%d threads requested, but only %d online CPUs " "(out of %d configured CPUs); capping to %d threads", l-> config.n_threads, l->online_cpus, l->available_cpus, 3 * l->online_cpus) | |||
896 | "(out of %d configured CPUs); capping to %d threads",lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 898, __FUNCTION__, "%d threads requested, but only %d online CPUs " "(out of %d configured CPUs); capping to %d threads", l-> config.n_threads, l->online_cpus, l->available_cpus, 3 * l->online_cpus) | |||
897 | l->config.n_threads, l->online_cpus, l->available_cpus,lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 898, __FUNCTION__, "%d threads requested, but only %d online CPUs " "(out of %d configured CPUs); capping to %d threads", l-> config.n_threads, l->online_cpus, l->available_cpus, 3 * l->online_cpus) | |||
898 | 3 * l->online_cpus)lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 898, __FUNCTION__, "%d threads requested, but only %d online CPUs " "(out of %d configured CPUs); capping to %d threads", l-> config.n_threads, l->online_cpus, l->available_cpus, 3 * l->online_cpus); | |||
899 | } else if (l->config.n_threads > 255) { | |||
900 | l->thread.count = 256; | |||
901 | ||||
902 | lwan_status_warning("%d threads requested, but max 256 supported",lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 903, __FUNCTION__, "%d threads requested, but max 256 supported" , l->config.n_threads) | |||
903 | l->config.n_threads)lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 903, __FUNCTION__, "%d threads requested, but max 256 supported" , l->config.n_threads); | |||
904 | } else { | |||
905 | l->thread.count = l->config.n_threads; | |||
906 | } | |||
907 | ||||
908 | rlim_t max_open_files = setup_open_file_count_limits(); | |||
909 | allocate_connections(l, (size_t)max_open_files); | |||
910 | ||||
911 | l->thread.max_fd = (unsigned)max_open_files / (unsigned)l->thread.count; | |||
912 | lwan_status_info("Using %d threads, maximum %d sockets per thread",lwan_status_info_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 913, __FUNCTION__, "Using %d threads, maximum %d sockets per thread" , l->thread.count, l->thread.max_fd) | |||
913 | l->thread.count, l->thread.max_fd)lwan_status_info_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 913, __FUNCTION__, "Using %d threads, maximum %d sockets per thread" , l->thread.count, l->thread.max_fd); | |||
914 | ||||
915 | signal(SIGPIPE13, SIG_IGN((__sighandler_t) 1)); | |||
916 | ||||
917 | lwan_readahead_init(); | |||
918 | lwan_thread_init(l); | |||
919 | lwan_http_authorize_init(); | |||
920 | } | |||
921 | ||||
922 | void lwan_shutdown(struct lwan *l) | |||
923 | { | |||
924 | lwan_status_info("Shutting down")lwan_status_info_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 924, __FUNCTION__, "Shutting down"); | |||
925 | ||||
926 | free(l->config.listener); | |||
927 | free(l->config.error_template); | |||
928 | free(l->config.config_file_path); | |||
929 | ||||
930 | lwan_always_bzero(l->config.ssl.cert, strlen(l->config.ssl.cert)); | |||
931 | free(l->config.ssl.cert); | |||
932 | lwan_always_bzero(l->config.ssl.key, strlen(l->config.ssl.key)); | |||
933 | free(l->config.ssl.key); | |||
934 | ||||
935 | lwan_job_thread_shutdown(); | |||
936 | lwan_thread_shutdown(l); | |||
937 | ||||
938 | lwan_status_debug("Shutting down URL handlers")lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 938, __FUNCTION__, "Shutting down URL handlers"); | |||
939 | lwan_trie_destroy(&l->url_map_trie); | |||
940 | ||||
941 | free(l->headers.value); | |||
942 | free(l->conns); | |||
943 | ||||
944 | lwan_response_shutdown(l); | |||
945 | lwan_tables_shutdown(); | |||
946 | lwan_status_shutdown(l); | |||
947 | lwan_http_authorize_shutdown(); | |||
948 | lwan_readahead_shutdown(); | |||
949 | } | |||
950 | ||||
951 | void lwan_main_loop(struct lwan *l) | |||
952 | { | |||
953 | lwan_status_info("Ready to serve")lwan_status_info_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan.c" , 953, __FUNCTION__, "Ready to serve"); | |||
954 | ||||
955 | lwan_job_thread_main_loop(); | |||
956 | } | |||
957 | ||||
958 | #ifdef CLOCK_MONOTONIC_COARSE6 | |||
959 | __attribute__((constructor)) static void detect_fastest_monotonic_clock(void) | |||
960 | { | |||
961 | struct timespec ts; | |||
962 | ||||
963 | if (!clock_gettime(CLOCK_MONOTONIC_COARSE6, &ts)) | |||
964 | monotonic_clock_id = CLOCK_MONOTONIC_COARSE6; | |||
965 | } | |||
966 | #endif | |||
967 | ||||
968 | void lwan_set_thread_name(const char *name) | |||
969 | { | |||
970 | char thread_name[16]; | |||
971 | char process_name[PATH_MAX4096]; | |||
972 | char *tmp; | |||
973 | int ret; | |||
974 | ||||
975 | if (proc_pidpath(getpid(), process_name, sizeof(process_name)) < 0) | |||
976 | return; | |||
977 | ||||
978 | tmp = strrchr(process_name, '/'); | |||
979 | if (!tmp) | |||
980 | return; | |||
981 | ||||
982 | ret = snprintf(thread_name, sizeof(thread_name), "%s %s", tmp + 1, name); | |||
983 | if (ret < 0) | |||
984 | return; | |||
985 | ||||
986 | pthread_set_name_np(pthread_self(), thread_name); | |||
987 | } |