Line data Source code
1 : #include "mongoose616.h"
2 : #include <string>
3 : #include <regex>
4 : #ifdef MG_MODULE_LINES
5 : #line 1 "mongoose/src/mg_internal.h"
6 : #endif
7 : /*
8 : * Copyright (c) 2014 Cesanta Software Limited
9 : * All rights reserved
10 : */
11 :
12 : #ifndef CS_MONGOOSE_SRC_INTERNAL_H_
13 : #define CS_MONGOOSE_SRC_INTERNAL_H_
14 :
15 : /* Amalgamated: #include "common/mg_mem.h" */
16 :
17 : #ifndef MBUF_REALLOC
18 : #define MBUF_REALLOC MG_REALLOC
19 : #endif
20 :
21 : #ifndef MBUF_FREE
22 : #define MBUF_FREE MG_FREE
23 : #endif
24 :
25 : #define MG_SET_PTRPTR(_ptr, _v) \
26 : do { \
27 : if (_ptr) *(_ptr) = _v; \
28 : } while (0)
29 :
30 : #ifndef MG_INTERNAL
31 : #define MG_INTERNAL static
32 : #endif
33 :
34 : #ifdef PICOTCP
35 : #define NO_LIBC
36 : #define MG_DISABLE_PFS
37 : #endif
38 :
39 : /* Amalgamated: #include "common/cs_dbg.h" */
40 : /* Amalgamated: #include "mg_http.h" */
41 : /* Amalgamated: #include "mg_net.h" */
42 :
43 : #ifndef MG_CTL_MSG_MESSAGE_SIZE
44 : #define MG_CTL_MSG_MESSAGE_SIZE 8192
45 : #endif
46 :
47 : /* internals that need to be accessible in unit tests */
48 : MG_INTERNAL struct mg_connection *mg_do_connect(struct mg_connection *nc,
49 : int proto,
50 : union socket_address *sa);
51 :
52 : MG_INTERNAL int mg_parse_address(const char *str, union socket_address *sa,
53 : int *proto, char *host, size_t host_len);
54 : MG_INTERNAL void mg_call(struct mg_connection *nc,
55 : mg_event_handler_t ev_handler, void *user_data, int ev,
56 : void *ev_data);
57 : void mg_forward(struct mg_connection *from, struct mg_connection *to);
58 : MG_INTERNAL void mg_add_conn(struct mg_mgr *mgr, struct mg_connection *c);
59 : MG_INTERNAL void mg_remove_conn(struct mg_connection *c);
60 : MG_INTERNAL struct mg_connection *mg_create_connection(
61 : struct mg_mgr *mgr, mg_event_handler_t callback,
62 : struct mg_add_sock_opts opts);
63 : #ifdef _WIN32
64 : /* Retur value is the same as for MultiByteToWideChar. */
65 : int to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len);
66 : #endif
67 :
68 : struct ctl_msg {
69 : mg_event_handler_t callback;
70 : char message[MG_CTL_MSG_MESSAGE_SIZE];
71 : };
72 :
73 : #if MG_ENABLE_MQTT
74 : struct mg_mqtt_message;
75 :
76 : #define MG_MQTT_ERROR_INCOMPLETE_MSG -1
77 : #define MG_MQTT_ERROR_MALFORMED_MSG -2
78 :
79 : MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm);
80 : #endif
81 :
82 : /* Forward declarations for testing. */
83 : extern void *(*test_malloc)(size_t size);
84 : extern void *(*test_calloc)(size_t count, size_t size);
85 :
86 : #ifndef MIN
87 : #define MIN(a, b) ((a) < (b) ? (a) : (b))
88 : #endif
89 :
90 : #if MG_ENABLE_HTTP
91 : struct mg_serve_http_opts;
92 :
93 : MG_INTERNAL struct mg_http_proto_data *mg_http_create_proto_data(
94 : struct mg_connection *c);
95 :
96 : /*
97 : * Reassemble the content of the buffer (buf, blen) which should be
98 : * in the HTTP chunked encoding, by collapsing data chunks to the
99 : * beginning of the buffer.
100 : *
101 : * If chunks get reassembled, modify hm->body to point to the reassembled
102 : * body and fire MG_EV_HTTP_CHUNK event. If handler sets MG_F_DELETE_CHUNK
103 : * in nc->flags, delete reassembled body from the mbuf.
104 : *
105 : * Return reassembled body size.
106 : */
107 : MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc,
108 : struct http_message *hm, char *buf,
109 : size_t blen);
110 :
111 : #if MG_ENABLE_FILESYSTEM
112 : MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm,
113 : const struct mg_serve_http_opts *opts,
114 : char **local_path,
115 : struct mg_str *remainder);
116 : MG_INTERNAL time_t mg_parse_date_string(const char *datetime);
117 : MG_INTERNAL int mg_is_not_modified(struct http_message *hm, cs_stat_t *st);
118 : #endif
119 : #if MG_ENABLE_HTTP_CGI
120 : MG_INTERNAL void mg_handle_cgi(struct mg_connection *nc, const char *prog,
121 : const struct mg_str *path_info,
122 : const struct http_message *hm,
123 : const struct mg_serve_http_opts *opts);
124 : struct mg_http_proto_data_cgi;
125 : MG_INTERNAL void mg_http_free_proto_data_cgi(struct mg_http_proto_data_cgi *d);
126 : #endif
127 : #if MG_ENABLE_HTTP_SSI
128 : MG_INTERNAL void mg_handle_ssi_request(struct mg_connection *nc,
129 : struct http_message *hm,
130 : const char *path,
131 : const struct mg_serve_http_opts *opts);
132 : #endif
133 : #if MG_ENABLE_HTTP_WEBDAV
134 : MG_INTERNAL int mg_is_dav_request(const struct mg_str *s);
135 : MG_INTERNAL void mg_handle_propfind(struct mg_connection *nc, const char *path,
136 : cs_stat_t *stp, struct http_message *hm,
137 : struct mg_serve_http_opts *opts);
138 : MG_INTERNAL void mg_handle_lock(struct mg_connection *nc, const char *path);
139 : MG_INTERNAL void mg_handle_mkcol(struct mg_connection *nc, const char *path,
140 : struct http_message *hm);
141 : MG_INTERNAL void mg_handle_move(struct mg_connection *c,
142 : const struct mg_serve_http_opts *opts,
143 : const char *path, struct http_message *hm);
144 : MG_INTERNAL void mg_handle_delete(struct mg_connection *nc,
145 : const struct mg_serve_http_opts *opts,
146 : const char *path);
147 : MG_INTERNAL void mg_handle_put(struct mg_connection *nc, const char *path,
148 : struct http_message *hm);
149 : #endif
150 : #if MG_ENABLE_HTTP_WEBSOCKET
151 : MG_INTERNAL void mg_ws_handler(struct mg_connection *nc, int ev,
152 : void *ev_data MG_UD_ARG(void *user_data));
153 : MG_INTERNAL void mg_ws_handshake(struct mg_connection *nc,
154 : const struct mg_str *key,
155 : struct http_message *);
156 : #endif
157 : #endif /* MG_ENABLE_HTTP */
158 :
159 : MG_INTERNAL int mg_get_errno(void);
160 :
161 : MG_INTERNAL void mg_close_conn(struct mg_connection *conn);
162 :
163 : #if MG_ENABLE_SNTP
164 : MG_INTERNAL int mg_sntp_parse_reply(const char *buf, int len,
165 : struct mg_sntp_message *msg);
166 : #endif
167 :
168 : #endif /* CS_MONGOOSE_SRC_INTERNAL_H_ */
169 : #ifdef MG_MODULE_LINES
170 : #line 1 "common/mg_mem.h"
171 : #endif
172 : /*
173 : * Copyright (c) 2014-2018 Cesanta Software Limited
174 : * All rights reserved
175 : *
176 : * Licensed under the Apache License, Version 2.0 (the ""License"");
177 : * you may not use this file except in compliance with the License.
178 : * You may obtain a copy of the License at
179 : *
180 : * http://www.apache.org/licenses/LICENSE-2.0
181 : *
182 : * Unless required by applicable law or agreed to in writing, software
183 : * distributed under the License is distributed on an ""AS IS"" BASIS,
184 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
185 : * See the License for the specific language governing permissions and
186 : * limitations under the License.
187 : */
188 :
189 : #ifndef CS_COMMON_MG_MEM_H_
190 : #define CS_COMMON_MG_MEM_H_
191 :
192 : #ifdef __cplusplus
193 : extern "C" {
194 : #endif
195 :
196 : #ifndef MG_MALLOC
197 : #define MG_MALLOC malloc
198 : #endif
199 :
200 : #ifndef MG_CALLOC
201 : #define MG_CALLOC calloc
202 : #endif
203 :
204 : #ifndef MG_REALLOC
205 : #define MG_REALLOC realloc
206 : #endif
207 :
208 : #ifndef MG_FREE
209 : #define MG_FREE free
210 : #endif
211 :
212 : #ifdef __cplusplus
213 : }
214 : #endif
215 :
216 : #endif /* CS_COMMON_MG_MEM_H_ */
217 : #ifdef MG_MODULE_LINES
218 : #line 1 "common/cs_base64.c"
219 : #endif
220 : /*
221 : * Copyright (c) 2014-2018 Cesanta Software Limited
222 : * All rights reserved
223 : *
224 : * Licensed under the Apache License, Version 2.0 (the ""License"");
225 : * you may not use this file except in compliance with the License.
226 : * You may obtain a copy of the License at
227 : *
228 : * http://www.apache.org/licenses/LICENSE-2.0
229 : *
230 : * Unless required by applicable law or agreed to in writing, software
231 : * distributed under the License is distributed on an ""AS IS"" BASIS,
232 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
233 : * See the License for the specific language governing permissions and
234 : * limitations under the License.
235 : */
236 :
237 : #ifndef EXCLUDE_COMMON
238 :
239 : /* Amalgamated: #include "common/cs_base64.h" */
240 :
241 : #include <string.h>
242 :
243 : /* Amalgamated: #include "common/cs_dbg.h" */
244 :
245 : /* ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ */
246 :
247 : #define NUM_UPPERCASES ('Z' - 'A' + 1)
248 : #define NUM_LETTERS (NUM_UPPERCASES * 2)
249 : #define NUM_DIGITS ('9' - '0' + 1)
250 :
251 : /*
252 : * Emit a base64 code char.
253 : *
254 : * Doesn't use memory, thus it's safe to use to safely dump memory in crashdumps
255 : */
256 0 : static void cs_base64_emit_code(struct cs_base64_ctx *ctx, int v) {
257 0 : if (v < NUM_UPPERCASES) {
258 0 : ctx->b64_putc(v + 'A', ctx->user_data);
259 0 : } else if (v < (NUM_LETTERS)) {
260 0 : ctx->b64_putc(v - NUM_UPPERCASES + 'a', ctx->user_data);
261 0 : } else if (v < (NUM_LETTERS + NUM_DIGITS)) {
262 0 : ctx->b64_putc(v - NUM_LETTERS + '0', ctx->user_data);
263 : } else {
264 0 : ctx->b64_putc(v - NUM_LETTERS - NUM_DIGITS == 0 ? '+' : '/',
265 : ctx->user_data);
266 : }
267 0 : }
268 :
269 0 : static void cs_base64_emit_chunk(struct cs_base64_ctx *ctx) {
270 : int a, b, c;
271 :
272 0 : a = ctx->chunk[0];
273 0 : b = ctx->chunk[1];
274 0 : c = ctx->chunk[2];
275 :
276 0 : cs_base64_emit_code(ctx, a >> 2);
277 0 : cs_base64_emit_code(ctx, ((a & 3) << 4) | (b >> 4));
278 0 : if (ctx->chunk_size > 1) {
279 0 : cs_base64_emit_code(ctx, (b & 15) << 2 | (c >> 6));
280 : }
281 0 : if (ctx->chunk_size > 2) {
282 0 : cs_base64_emit_code(ctx, c & 63);
283 : }
284 0 : }
285 :
286 0 : void cs_base64_init(struct cs_base64_ctx *ctx, cs_base64_putc_t b64_putc,
287 : void *user_data) {
288 0 : ctx->chunk_size = 0;
289 0 : ctx->b64_putc = b64_putc;
290 0 : ctx->user_data = user_data;
291 0 : }
292 :
293 0 : void cs_base64_update(struct cs_base64_ctx *ctx, const char *str, size_t len) {
294 0 : const unsigned char *src = (const unsigned char *) str;
295 : size_t i;
296 0 : for (i = 0; i < len; i++) {
297 0 : ctx->chunk[ctx->chunk_size++] = src[i];
298 0 : if (ctx->chunk_size == 3) {
299 0 : cs_base64_emit_chunk(ctx);
300 0 : ctx->chunk_size = 0;
301 : }
302 : }
303 0 : }
304 :
305 0 : void cs_base64_finish(struct cs_base64_ctx *ctx) {
306 0 : if (ctx->chunk_size > 0) {
307 : int i;
308 0 : memset(&ctx->chunk[ctx->chunk_size], 0, 3 - ctx->chunk_size);
309 0 : cs_base64_emit_chunk(ctx);
310 0 : for (i = 0; i < (3 - ctx->chunk_size); i++) {
311 0 : ctx->b64_putc('=', ctx->user_data);
312 : }
313 : }
314 0 : }
315 :
316 : #define BASE64_ENCODE_BODY \
317 : static const char *b64 = \
318 : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; \
319 : int i, j, a, b, c; \
320 : \
321 : for (i = j = 0; i < src_len; i += 3) { \
322 : a = src[i]; \
323 : b = i + 1 >= src_len ? 0 : src[i + 1]; \
324 : c = i + 2 >= src_len ? 0 : src[i + 2]; \
325 : \
326 : BASE64_OUT(b64[a >> 2]); \
327 : BASE64_OUT(b64[((a & 3) << 4) | (b >> 4)]); \
328 : if (i + 1 < src_len) { \
329 : BASE64_OUT(b64[(b & 15) << 2 | (c >> 6)]); \
330 : } \
331 : if (i + 2 < src_len) { \
332 : BASE64_OUT(b64[c & 63]); \
333 : } \
334 : } \
335 : \
336 : while (j % 4 != 0) { \
337 : BASE64_OUT('='); \
338 : } \
339 : BASE64_FLUSH()
340 :
341 : #define BASE64_OUT(ch) \
342 : do { \
343 : dst[j++] = (ch); \
344 : } while (0)
345 :
346 : #define BASE64_FLUSH() \
347 : do { \
348 : dst[j++] = '\0'; \
349 : } while (0)
350 :
351 0 : void cs_base64_encode(const unsigned char *src, int src_len, char *dst) {
352 0 : BASE64_ENCODE_BODY;
353 0 : }
354 :
355 : #undef BASE64_OUT
356 : #undef BASE64_FLUSH
357 :
358 : #if CS_ENABLE_STDIO
359 : #define BASE64_OUT(ch) \
360 : do { \
361 : fprintf(f, "%c", (ch)); \
362 : j++; \
363 : } while (0)
364 :
365 : #define BASE64_FLUSH()
366 :
367 0 : void cs_fprint_base64(FILE *f, const unsigned char *src, int src_len) {
368 0 : BASE64_ENCODE_BODY;
369 0 : }
370 :
371 : #undef BASE64_OUT
372 : #undef BASE64_FLUSH
373 : #endif /* CS_ENABLE_STDIO */
374 :
375 : /* Convert one byte of encoded base64 input stream to 6-bit chunk */
376 0 : static unsigned char from_b64(unsigned char ch) {
377 : /* Inverse lookup map */
378 : static const unsigned char tab[128] = {
379 : 255, 255, 255, 255,
380 : 255, 255, 255, 255, /* 0 */
381 : 255, 255, 255, 255,
382 : 255, 255, 255, 255, /* 8 */
383 : 255, 255, 255, 255,
384 : 255, 255, 255, 255, /* 16 */
385 : 255, 255, 255, 255,
386 : 255, 255, 255, 255, /* 24 */
387 : 255, 255, 255, 255,
388 : 255, 255, 255, 255, /* 32 */
389 : 255, 255, 255, 62,
390 : 255, 255, 255, 63, /* 40 */
391 : 52, 53, 54, 55,
392 : 56, 57, 58, 59, /* 48 */
393 : 60, 61, 255, 255,
394 : 255, 200, 255, 255, /* 56 '=' is 200, on index 61 */
395 : 255, 0, 1, 2,
396 : 3, 4, 5, 6, /* 64 */
397 : 7, 8, 9, 10,
398 : 11, 12, 13, 14, /* 72 */
399 : 15, 16, 17, 18,
400 : 19, 20, 21, 22, /* 80 */
401 : 23, 24, 25, 255,
402 : 255, 255, 255, 255, /* 88 */
403 : 255, 26, 27, 28,
404 : 29, 30, 31, 32, /* 96 */
405 : 33, 34, 35, 36,
406 : 37, 38, 39, 40, /* 104 */
407 : 41, 42, 43, 44,
408 : 45, 46, 47, 48, /* 112 */
409 : 49, 50, 51, 255,
410 : 255, 255, 255, 255, /* 120 */
411 : };
412 0 : return tab[ch & 127];
413 : }
414 :
415 0 : int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len) {
416 : unsigned char a, b, c, d;
417 0 : int orig_len = len;
418 0 : char *orig_dst = dst;
419 0 : while (len >= 4 && (a = from_b64(s[0])) != 255 &&
420 0 : (b = from_b64(s[1])) != 255 && (c = from_b64(s[2])) != 255 &&
421 0 : (d = from_b64(s[3])) != 255) {
422 0 : s += 4;
423 0 : len -= 4;
424 0 : if (a == 200 || b == 200) break; /* '=' can't be there */
425 0 : *dst++ = a << 2 | b >> 4;
426 0 : if (c == 200) break;
427 0 : *dst++ = b << 4 | c >> 2;
428 0 : if (d == 200) break;
429 0 : *dst++ = c << 6 | d;
430 : }
431 0 : *dst = 0;
432 0 : if (dec_len != NULL) *dec_len = (dst - orig_dst);
433 0 : return orig_len - len;
434 : }
435 :
436 : #endif /* EXCLUDE_COMMON */
437 : #ifdef MG_MODULE_LINES
438 : #line 1 "common/cs_dbg.h"
439 : #endif
440 : /*
441 : * Copyright (c) 2014-2018 Cesanta Software Limited
442 : * All rights reserved
443 : *
444 : * Licensed under the Apache License, Version 2.0 (the ""License"");
445 : * you may not use this file except in compliance with the License.
446 : * You may obtain a copy of the License at
447 : *
448 : * http://www.apache.org/licenses/LICENSE-2.0
449 : *
450 : * Unless required by applicable law or agreed to in writing, software
451 : * distributed under the License is distributed on an ""AS IS"" BASIS,
452 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
453 : * See the License for the specific language governing permissions and
454 : * limitations under the License.
455 : */
456 :
457 : #ifndef CS_COMMON_CS_DBG_H_
458 : #define CS_COMMON_CS_DBG_H_
459 :
460 : /* Amalgamated: #include "common/platform.h" */
461 :
462 : #if CS_ENABLE_STDIO
463 : #include <stdio.h>
464 : #endif
465 :
466 : #ifndef CS_ENABLE_DEBUG
467 : #define CS_ENABLE_DEBUG 0
468 : #endif
469 :
470 : #ifndef CS_LOG_PREFIX_LEN
471 : #define CS_LOG_PREFIX_LEN 24
472 : #endif
473 :
474 : #ifndef CS_LOG_ENABLE_TS_DIFF
475 : #define CS_LOG_ENABLE_TS_DIFF 0
476 : #endif
477 :
478 : #ifdef __cplusplus
479 : extern "C" {
480 : #endif /* __cplusplus */
481 :
482 : /*
483 : * Log level; `LL_INFO` is the default. Use `cs_log_set_level()` to change it.
484 : */
485 : enum cs_log_level {
486 : LL_NONE = -1,
487 : LL_ERROR = 0,
488 : LL_WARN = 1,
489 : LL_INFO = 2,
490 : LL_DEBUG = 3,
491 : LL_VERBOSE_DEBUG = 4,
492 :
493 : _LL_MIN = -2,
494 : _LL_MAX = 5,
495 : };
496 :
497 : /*
498 : * Set max log level to print; messages with the level above the given one will
499 : * not be printed.
500 : */
501 : void cs_log_set_level(enum cs_log_level level);
502 :
503 : /*
504 : * A comma-separated set of prefix=level.
505 : * prefix is matched against the log prefix exactly as printed, including line
506 : * number, but partial match is ok. Check stops on first matching entry.
507 : * If nothing matches, default level is used.
508 : *
509 : * Examples:
510 : * main.c:=4 - everything from main C at verbose debug level.
511 : * mongoose.c=1,mjs.c=1,=4 - everything at verbose debug except mg_* and mjs_*
512 : *
513 : */
514 : void cs_log_set_file_level(const char *file_level);
515 :
516 : /*
517 : * Helper function which prints message prefix with the given `level`.
518 : * If message should be printed (according to the current log level
519 : * and filter), prints the prefix and returns 1, otherwise returns 0.
520 : *
521 : * Clients should typically just use `LOG()` macro.
522 : */
523 : int cs_log_print_prefix(enum cs_log_level level, const char *fname, int line);
524 :
525 : extern enum cs_log_level cs_log_level;
526 :
527 : #if CS_ENABLE_STDIO
528 :
529 : /*
530 : * Set file to write logs into. If `NULL`, logs go to `stderr`.
531 : */
532 : void cs_log_set_file(FILE *file);
533 :
534 : /*
535 : * Prints log to the current log file, appends "\n" in the end and flushes the
536 : * stream.
537 : */
538 : void cs_log_printf(const char *fmt, ...) PRINTF_LIKE(1, 2);
539 :
540 : #if CS_ENABLE_STDIO
541 :
542 : /*
543 : * Format and print message `x` with the given level `l`. Example:
544 : *
545 : * ```c
546 : * LOG(LL_INFO, ("my info message: %d", 123));
547 : * LOG(LL_DEBUG, ("my debug message: %d", 123));
548 : * ```
549 : */
550 : #define LOG(l, x) \
551 : do { \
552 : if (cs_log_print_prefix(l, __FILE__, __LINE__)) { \
553 : cs_log_printf x; \
554 : } \
555 : } while (0)
556 :
557 : #else
558 :
559 : #define LOG(l, x) ((void) l)
560 :
561 : #endif
562 :
563 : #ifndef CS_NDEBUG
564 :
565 : /*
566 : * Shortcut for `LOG(LL_VERBOSE_DEBUG, (...))`
567 : */
568 : #define DBG(x) LOG(LL_VERBOSE_DEBUG, x)
569 :
570 : #else /* NDEBUG */
571 :
572 : #define DBG(x)
573 :
574 : #endif
575 :
576 : #else /* CS_ENABLE_STDIO */
577 :
578 : #define LOG(l, x)
579 : #define DBG(x)
580 :
581 : #endif
582 :
583 : #ifdef __cplusplus
584 : }
585 : #endif /* __cplusplus */
586 :
587 : #endif /* CS_COMMON_CS_DBG_H_ */
588 : #ifdef MG_MODULE_LINES
589 : #line 1 "common/cs_dbg.c"
590 : #endif
591 : /*
592 : * Copyright (c) 2014-2018 Cesanta Software Limited
593 : * All rights reserved
594 : *
595 : * Licensed under the Apache License, Version 2.0 (the ""License"");
596 : * you may not use this file except in compliance with the License.
597 : * You may obtain a copy of the License at
598 : *
599 : * http://www.apache.org/licenses/LICENSE-2.0
600 : *
601 : * Unless required by applicable law or agreed to in writing, software
602 : * distributed under the License is distributed on an ""AS IS"" BASIS,
603 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
604 : * See the License for the specific language governing permissions and
605 : * limitations under the License.
606 : */
607 :
608 : /* Amalgamated: #include "common/cs_dbg.h" */
609 :
610 : #include <stdarg.h>
611 : #include <stdio.h>
612 : #include <string.h>
613 :
614 : /* Amalgamated: #include "common/cs_time.h" */
615 : /* Amalgamated: #include "common/str_util.h" */
616 :
617 : enum cs_log_level cs_log_level WEAK =
618 : #if CS_ENABLE_DEBUG
619 : LL_VERBOSE_DEBUG;
620 : #else
621 : LL_ERROR;
622 : #endif
623 :
624 : #if CS_ENABLE_STDIO
625 : static char *s_file_level = NULL;
626 :
627 : void cs_log_set_file_level(const char *file_level) WEAK;
628 :
629 : FILE *cs_log_file WEAK = NULL;
630 :
631 : #if CS_LOG_ENABLE_TS_DIFF
632 : double cs_log_ts WEAK;
633 : #endif
634 :
635 : enum cs_log_level cs_log_cur_msg_level WEAK = LL_NONE;
636 :
637 0 : void cs_log_set_file_level(const char *file_level) {
638 0 : char *fl = s_file_level;
639 0 : if (file_level != NULL) {
640 0 : s_file_level = strdup(file_level);
641 : } else {
642 0 : s_file_level = NULL;
643 : }
644 0 : free(fl);
645 0 : }
646 :
647 : int cs_log_print_prefix(enum cs_log_level level, const char *file, int ln) WEAK;
648 0 : int cs_log_print_prefix(enum cs_log_level level, const char *file, int ln) {
649 : char prefix[CS_LOG_PREFIX_LEN], *q;
650 : const char *p;
651 0 : size_t fl = 0, ll = 0, pl = 0;
652 :
653 0 : if (level > cs_log_level && s_file_level == NULL) return 0;
654 :
655 0 : p = file + strlen(file);
656 :
657 0 : while (p != file) {
658 0 : const char c = *(p - 1);
659 0 : if (c == '/' || c == '\\') break;
660 0 : p--;
661 0 : fl++;
662 : }
663 :
664 0 : ll = (ln < 10000 ? (ln < 1000 ? (ln < 100 ? (ln < 10 ? 1 : 2) : 3) : 4) : 5);
665 0 : if (fl > (sizeof(prefix) - ll - 2)) fl = (sizeof(prefix) - ll - 2);
666 :
667 0 : pl = fl + 1 + ll;
668 0 : memcpy(prefix, p, fl);
669 0 : q = prefix + pl;
670 0 : memset(q, ' ', sizeof(prefix) - pl);
671 : do {
672 0 : *(--q) = '0' + (ln % 10);
673 0 : ln /= 10;
674 0 : } while (ln > 0);
675 0 : *(--q) = ':';
676 :
677 0 : if (s_file_level != NULL) {
678 0 : enum cs_log_level pll = cs_log_level;
679 0 : struct mg_str fl = mg_mk_str(s_file_level), ps = MG_MK_STR_N(prefix, pl);
680 : struct mg_str k, v;
681 0 : while ((fl = mg_next_comma_list_entry_n(fl, &k, &v)).p != NULL) {
682 0 : bool yes = !(!mg_str_starts_with(ps, k) || v.len == 0);
683 0 : if (!yes) continue;
684 0 : pll = (enum cs_log_level)(*v.p - '0');
685 0 : break;
686 : }
687 0 : if (level > pll) return 0;
688 : }
689 :
690 0 : if (cs_log_file == NULL) cs_log_file = stderr;
691 0 : cs_log_cur_msg_level = level;
692 0 : fwrite(prefix, 1, sizeof(prefix), cs_log_file);
693 : #if CS_LOG_ENABLE_TS_DIFF
694 : {
695 : double now = cs_time();
696 : fprintf(cs_log_file, "%7u ", (unsigned int) ((now - cs_log_ts) * 1000000));
697 : cs_log_ts = now;
698 : }
699 : #endif
700 0 : return 1;
701 : }
702 :
703 : void cs_log_printf(const char *fmt, ...) WEAK;
704 0 : void cs_log_printf(const char *fmt, ...) {
705 : va_list ap;
706 0 : va_start(ap, fmt);
707 0 : vfprintf(cs_log_file, fmt, ap);
708 0 : va_end(ap);
709 0 : fputc('\n', cs_log_file);
710 0 : fflush(cs_log_file);
711 0 : cs_log_cur_msg_level = LL_NONE;
712 0 : }
713 :
714 : void cs_log_set_file(FILE *file) WEAK;
715 0 : void cs_log_set_file(FILE *file) {
716 0 : cs_log_file = file;
717 0 : }
718 :
719 : #else
720 :
721 : void cs_log_set_file_level(const char *file_level) {
722 : (void) file_level;
723 : }
724 :
725 : #endif /* CS_ENABLE_STDIO */
726 :
727 : void cs_log_set_level(enum cs_log_level level) WEAK;
728 0 : void cs_log_set_level(enum cs_log_level level) {
729 0 : cs_log_level = level;
730 : #if CS_LOG_ENABLE_TS_DIFF && CS_ENABLE_STDIO
731 : cs_log_ts = cs_time();
732 : #endif
733 0 : }
734 : #ifdef MG_MODULE_LINES
735 : #line 1 "common/cs_dirent.h"
736 : #endif
737 : /*
738 : * Copyright (c) 2014-2018 Cesanta Software Limited
739 : * All rights reserved
740 : *
741 : * Licensed under the Apache License, Version 2.0 (the ""License"");
742 : * you may not use this file except in compliance with the License.
743 : * You may obtain a copy of the License at
744 : *
745 : * http://www.apache.org/licenses/LICENSE-2.0
746 : *
747 : * Unless required by applicable law or agreed to in writing, software
748 : * distributed under the License is distributed on an ""AS IS"" BASIS,
749 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
750 : * See the License for the specific language governing permissions and
751 : * limitations under the License.
752 : */
753 :
754 : #ifndef CS_COMMON_CS_DIRENT_H_
755 : #define CS_COMMON_CS_DIRENT_H_
756 :
757 : #include <limits.h>
758 :
759 : /* Amalgamated: #include "common/platform.h" */
760 :
761 : #ifdef __cplusplus
762 : extern "C" {
763 : #endif /* __cplusplus */
764 :
765 : #ifdef CS_DEFINE_DIRENT
766 : typedef struct { int dummy; } DIR;
767 :
768 : struct dirent {
769 : int d_ino;
770 : #ifdef _WIN32
771 : char d_name[MAX_PATH];
772 : #else
773 : /* TODO(rojer): Use PATH_MAX but make sure it's sane on every platform */
774 : char d_name[256];
775 : #endif
776 : };
777 :
778 : DIR *opendir(const char *dir_name);
779 : int closedir(DIR *dir);
780 : struct dirent *readdir(DIR *dir);
781 : #endif /* CS_DEFINE_DIRENT */
782 :
783 : #ifdef __cplusplus
784 : }
785 : #endif /* __cplusplus */
786 :
787 : #endif /* CS_COMMON_CS_DIRENT_H_ */
788 : #ifdef MG_MODULE_LINES
789 : #line 1 "common/cs_dirent.c"
790 : #endif
791 : /*
792 : * Copyright (c) 2014-2018 Cesanta Software Limited
793 : * All rights reserved
794 : *
795 : * Licensed under the Apache License, Version 2.0 (the ""License"");
796 : * you may not use this file except in compliance with the License.
797 : * You may obtain a copy of the License at
798 : *
799 : * http://www.apache.org/licenses/LICENSE-2.0
800 : *
801 : * Unless required by applicable law or agreed to in writing, software
802 : * distributed under the License is distributed on an ""AS IS"" BASIS,
803 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
804 : * See the License for the specific language governing permissions and
805 : * limitations under the License.
806 : */
807 :
808 : #ifndef EXCLUDE_COMMON
809 :
810 : /* Amalgamated: #include "common/mg_mem.h" */
811 : /* Amalgamated: #include "common/cs_dirent.h" */
812 :
813 : /*
814 : * This file contains POSIX opendir/closedir/readdir API implementation
815 : * for systems which do not natively support it (e.g. Windows).
816 : */
817 :
818 : #ifdef _WIN32
819 : struct win32_dir {
820 : DIR d;
821 : HANDLE handle;
822 : WIN32_FIND_DATAW info;
823 : struct dirent result;
824 : };
825 :
826 : DIR *opendir(const char *name) {
827 : struct win32_dir *dir = NULL;
828 : wchar_t wpath[MAX_PATH];
829 : DWORD attrs;
830 :
831 : if (name == NULL) {
832 : SetLastError(ERROR_BAD_ARGUMENTS);
833 : } else if ((dir = (struct win32_dir *) MG_MALLOC(sizeof(*dir))) == NULL) {
834 : SetLastError(ERROR_NOT_ENOUGH_MEMORY);
835 : } else {
836 : to_wchar(name, wpath, ARRAY_SIZE(wpath));
837 : attrs = GetFileAttributesW(wpath);
838 : if (attrs != 0xFFFFFFFF && (attrs & FILE_ATTRIBUTE_DIRECTORY)) {
839 : (void) wcscat(wpath, L"\\*");
840 : dir->handle = FindFirstFileW(wpath, &dir->info);
841 : dir->result.d_name[0] = '\0';
842 : } else {
843 : MG_FREE(dir);
844 : dir = NULL;
845 : }
846 : }
847 :
848 : return (DIR *) dir;
849 : }
850 :
851 : int closedir(DIR *d) {
852 : struct win32_dir *dir = (struct win32_dir *) d;
853 : int result = 0;
854 :
855 : if (dir != NULL) {
856 : if (dir->handle != INVALID_HANDLE_VALUE)
857 : result = FindClose(dir->handle) ? 0 : -1;
858 : MG_FREE(dir);
859 : } else {
860 : result = -1;
861 : SetLastError(ERROR_BAD_ARGUMENTS);
862 : }
863 :
864 : return result;
865 : }
866 :
867 : struct dirent *readdir(DIR *d) {
868 : struct win32_dir *dir = (struct win32_dir *) d;
869 : struct dirent *result = NULL;
870 :
871 : if (dir) {
872 : memset(&dir->result, 0, sizeof(dir->result));
873 : if (dir->handle != INVALID_HANDLE_VALUE) {
874 : result = &dir->result;
875 : (void) WideCharToMultiByte(CP_UTF8, 0, dir->info.cFileName, -1,
876 : result->d_name, sizeof(result->d_name), NULL,
877 : NULL);
878 :
879 : if (!FindNextFileW(dir->handle, &dir->info)) {
880 : (void) FindClose(dir->handle);
881 : dir->handle = INVALID_HANDLE_VALUE;
882 : }
883 :
884 : } else {
885 : SetLastError(ERROR_FILE_NOT_FOUND);
886 : }
887 : } else {
888 : SetLastError(ERROR_BAD_ARGUMENTS);
889 : }
890 :
891 : return result;
892 : }
893 : #endif
894 :
895 : #endif /* EXCLUDE_COMMON */
896 :
897 : /* ISO C requires a translation unit to contain at least one declaration */
898 : typedef int cs_dirent_dummy;
899 : #ifdef MG_MODULE_LINES
900 : #line 1 "common/cs_time.c"
901 : #endif
902 : /*
903 : * Copyright (c) 2014-2018 Cesanta Software Limited
904 : * All rights reserved
905 : *
906 : * Licensed under the Apache License, Version 2.0 (the ""License"");
907 : * you may not use this file except in compliance with the License.
908 : * You may obtain a copy of the License at
909 : *
910 : * http://www.apache.org/licenses/LICENSE-2.0
911 : *
912 : * Unless required by applicable law or agreed to in writing, software
913 : * distributed under the License is distributed on an ""AS IS"" BASIS,
914 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
915 : * See the License for the specific language governing permissions and
916 : * limitations under the License.
917 : */
918 :
919 : /* Amalgamated: #include "common/cs_time.h" */
920 :
921 : #ifndef _WIN32
922 : #include <stddef.h>
923 : /*
924 : * There is no sys/time.h on ARMCC.
925 : */
926 : #if !(defined(__ARMCC_VERSION) || defined(__ICCARM__)) && \
927 : !defined(__TI_COMPILER_VERSION__) && \
928 : (!defined(CS_PLATFORM) || CS_PLATFORM != CS_P_NXP_LPC)
929 : #include <sys/time.h>
930 : #endif
931 : #else
932 : #include <windows.h>
933 : #endif
934 :
935 : double cs_time(void) WEAK;
936 0 : double cs_time(void) {
937 : double now;
938 : #ifndef _WIN32
939 : struct timeval tv;
940 0 : if (gettimeofday(&tv, NULL /* tz */) != 0) return 0;
941 0 : now = (double) tv.tv_sec + (((double) tv.tv_usec) / 1000000.0);
942 : #else
943 : SYSTEMTIME sysnow;
944 : FILETIME ftime;
945 : GetLocalTime(&sysnow);
946 : SystemTimeToFileTime(&sysnow, &ftime);
947 : /*
948 : * 1. VC 6.0 doesn't support conversion uint64 -> double, so, using int64
949 : * This should not cause a problems in this (21th) century
950 : * 2. Windows FILETIME is a number of 100-nanosecond intervals since January
951 : * 1, 1601 while time_t is a number of _seconds_ since January 1, 1970 UTC,
952 : * thus, we need to convert to seconds and adjust amount (subtract 11644473600
953 : * seconds)
954 : */
955 : now = (double) (((int64_t) ftime.dwLowDateTime +
956 : ((int64_t) ftime.dwHighDateTime << 32)) /
957 : 10000000.0) -
958 : 11644473600;
959 : #endif /* _WIN32 */
960 0 : return now;
961 : }
962 :
963 0 : double cs_timegm(const struct tm *tm) {
964 : /* Month-to-day offset for non-leap-years. */
965 : static const int month_day[12] = {0, 31, 59, 90, 120, 151,
966 : 181, 212, 243, 273, 304, 334};
967 :
968 : /* Most of the calculation is easy; leap years are the main difficulty. */
969 0 : int month = tm->tm_mon % 12;
970 0 : int year = tm->tm_year + tm->tm_mon / 12;
971 : int year_for_leap;
972 : int64_t rt;
973 :
974 0 : if (month < 0) { /* Negative values % 12 are still negative. */
975 0 : month += 12;
976 0 : --year;
977 : }
978 :
979 : /* This is the number of Februaries since 1900. */
980 0 : year_for_leap = (month > 1) ? year + 1 : year;
981 :
982 0 : rt =
983 0 : tm->tm_sec /* Seconds */
984 0 : +
985 0 : 60 *
986 0 : (tm->tm_min /* Minute = 60 seconds */
987 0 : +
988 0 : 60 * (tm->tm_hour /* Hour = 60 minutes */
989 0 : +
990 0 : 24 * (month_day[month] + tm->tm_mday - 1 /* Day = 24 hours */
991 0 : + 365 * (year - 70) /* Year = 365 days */
992 0 : + (year_for_leap - 69) / 4 /* Every 4 years is leap... */
993 0 : - (year_for_leap - 1) / 100 /* Except centuries... */
994 0 : + (year_for_leap + 299) / 400))); /* Except 400s. */
995 0 : return rt < 0 ? -1 : (double) rt;
996 : }
997 : #ifdef MG_MODULE_LINES
998 : #line 1 "common/cs_endian.h"
999 : #endif
1000 : /*
1001 : * Copyright (c) 2014-2018 Cesanta Software Limited
1002 : * All rights reserved
1003 : *
1004 : * Licensed under the Apache License, Version 2.0 (the ""License"");
1005 : * you may not use this file except in compliance with the License.
1006 : * You may obtain a copy of the License at
1007 : *
1008 : * http://www.apache.org/licenses/LICENSE-2.0
1009 : *
1010 : * Unless required by applicable law or agreed to in writing, software
1011 : * distributed under the License is distributed on an ""AS IS"" BASIS,
1012 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1013 : * See the License for the specific language governing permissions and
1014 : * limitations under the License.
1015 : */
1016 :
1017 : #ifndef CS_COMMON_CS_ENDIAN_H_
1018 : #define CS_COMMON_CS_ENDIAN_H_
1019 :
1020 : #ifdef __cplusplus
1021 : extern "C" {
1022 : #endif
1023 :
1024 : /*
1025 : * clang with std=-c99 uses __LITTLE_ENDIAN, by default
1026 : * while for ex, RTOS gcc - LITTLE_ENDIAN, by default
1027 : * it depends on __USE_BSD, but let's have everything
1028 : */
1029 : #if !defined(BYTE_ORDER) && defined(__BYTE_ORDER)
1030 : #define BYTE_ORDER __BYTE_ORDER
1031 : #ifndef LITTLE_ENDIAN
1032 : #define LITTLE_ENDIAN __LITTLE_ENDIAN
1033 : #endif /* LITTLE_ENDIAN */
1034 : #ifndef BIG_ENDIAN
1035 : #define BIG_ENDIAN __LITTLE_ENDIAN
1036 : #endif /* BIG_ENDIAN */
1037 : #endif /* BYTE_ORDER */
1038 :
1039 : #ifdef __cplusplus
1040 : }
1041 : #endif
1042 :
1043 : #endif /* CS_COMMON_CS_ENDIAN_H_ */
1044 : #ifdef MG_MODULE_LINES
1045 : #line 1 "common/cs_md5.c"
1046 : #endif
1047 : /*
1048 : * This code implements the MD5 message-digest algorithm.
1049 : * The algorithm is due to Ron Rivest. This code was
1050 : * written by Colin Plumb in 1993, no copyright is claimed.
1051 : * This code is in the public domain; do with it what you wish.
1052 : *
1053 : * Equivalent code is available from RSA Data Security, Inc.
1054 : * This code has been tested against that, and is equivalent,
1055 : * except that you don't need to include two pages of legalese
1056 : * with every copy.
1057 : *
1058 : * To compute the message digest of a chunk of bytes, declare an
1059 : * MD5Context structure, pass it to MD5Init, call MD5Update as
1060 : * needed on buffers full of bytes, and then call MD5Final, which
1061 : * will fill a supplied 16-byte array with the digest.
1062 : */
1063 :
1064 : /* Amalgamated: #include "common/cs_md5.h" */
1065 : /* Amalgamated: #include "common/str_util.h" */
1066 :
1067 : #if !defined(EXCLUDE_COMMON)
1068 : #if !CS_DISABLE_MD5
1069 :
1070 : /* Amalgamated: #include "common/cs_endian.h" */
1071 :
1072 0 : static void byteReverse(unsigned char *buf, unsigned longs) {
1073 : /* Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN */
1074 : #if BYTE_ORDER == BIG_ENDIAN
1075 : do {
1076 : uint32_t t = (uint32_t)((unsigned) buf[3] << 8 | buf[2]) << 16 |
1077 : ((unsigned) buf[1] << 8 | buf[0]);
1078 : *(uint32_t *) buf = t;
1079 : buf += 4;
1080 : } while (--longs);
1081 : #else
1082 : (void) buf;
1083 : (void) longs;
1084 : #endif
1085 0 : }
1086 :
1087 : #define F1(x, y, z) (z ^ (x & (y ^ z)))
1088 : #define F2(x, y, z) F1(z, x, y)
1089 : #define F3(x, y, z) (x ^ y ^ z)
1090 : #define F4(x, y, z) (y ^ (x | ~z))
1091 :
1092 : #define MD5STEP(f, w, x, y, z, data, s) \
1093 : (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x)
1094 :
1095 : /*
1096 : * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
1097 : * initialization constants.
1098 : */
1099 0 : void cs_md5_init(cs_md5_ctx *ctx) {
1100 0 : ctx->buf[0] = 0x67452301;
1101 0 : ctx->buf[1] = 0xefcdab89;
1102 0 : ctx->buf[2] = 0x98badcfe;
1103 0 : ctx->buf[3] = 0x10325476;
1104 :
1105 0 : ctx->bits[0] = 0;
1106 0 : ctx->bits[1] = 0;
1107 0 : }
1108 :
1109 0 : static void cs_md5_transform(uint32_t buf[4], uint32_t const in[16]) {
1110 : uint32_t a, b, c, d;
1111 :
1112 0 : a = buf[0];
1113 0 : b = buf[1];
1114 0 : c = buf[2];
1115 0 : d = buf[3];
1116 :
1117 0 : MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
1118 0 : MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
1119 0 : MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
1120 0 : MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
1121 0 : MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
1122 0 : MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
1123 0 : MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
1124 0 : MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
1125 0 : MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
1126 0 : MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
1127 0 : MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
1128 0 : MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
1129 0 : MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
1130 0 : MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
1131 0 : MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
1132 0 : MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
1133 :
1134 0 : MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
1135 0 : MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
1136 0 : MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
1137 0 : MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
1138 0 : MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
1139 0 : MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
1140 0 : MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
1141 0 : MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
1142 0 : MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
1143 0 : MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
1144 0 : MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
1145 0 : MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
1146 0 : MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
1147 0 : MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
1148 0 : MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
1149 0 : MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
1150 :
1151 0 : MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
1152 0 : MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
1153 0 : MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
1154 0 : MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
1155 0 : MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
1156 0 : MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
1157 0 : MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
1158 0 : MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
1159 0 : MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
1160 0 : MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
1161 0 : MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
1162 0 : MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
1163 0 : MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
1164 0 : MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
1165 0 : MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
1166 0 : MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
1167 :
1168 0 : MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
1169 0 : MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
1170 0 : MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
1171 0 : MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
1172 0 : MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
1173 0 : MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
1174 0 : MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
1175 0 : MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
1176 0 : MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
1177 0 : MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
1178 0 : MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
1179 0 : MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
1180 0 : MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
1181 0 : MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
1182 0 : MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
1183 0 : MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
1184 :
1185 0 : buf[0] += a;
1186 0 : buf[1] += b;
1187 0 : buf[2] += c;
1188 0 : buf[3] += d;
1189 0 : }
1190 :
1191 0 : void cs_md5_update(cs_md5_ctx *ctx, const unsigned char *buf, size_t len) {
1192 : uint32_t t;
1193 :
1194 0 : t = ctx->bits[0];
1195 0 : if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) ctx->bits[1]++;
1196 0 : ctx->bits[1] += (uint32_t) len >> 29;
1197 :
1198 0 : t = (t >> 3) & 0x3f;
1199 :
1200 0 : if (t) {
1201 0 : unsigned char *p = (unsigned char *) ctx->in + t;
1202 :
1203 0 : t = 64 - t;
1204 0 : if (len < t) {
1205 0 : memcpy(p, buf, len);
1206 0 : return;
1207 : }
1208 0 : memcpy(p, buf, t);
1209 0 : byteReverse(ctx->in, 16);
1210 0 : cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
1211 0 : buf += t;
1212 0 : len -= t;
1213 : }
1214 :
1215 0 : while (len >= 64) {
1216 0 : memcpy(ctx->in, buf, 64);
1217 0 : byteReverse(ctx->in, 16);
1218 0 : cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
1219 0 : buf += 64;
1220 0 : len -= 64;
1221 : }
1222 :
1223 0 : memcpy(ctx->in, buf, len);
1224 : }
1225 :
1226 0 : void cs_md5_final(unsigned char digest[16], cs_md5_ctx *ctx) {
1227 : unsigned count;
1228 : unsigned char *p;
1229 : uint32_t *a;
1230 :
1231 0 : count = (ctx->bits[0] >> 3) & 0x3F;
1232 :
1233 0 : p = ctx->in + count;
1234 0 : *p++ = 0x80;
1235 0 : count = 64 - 1 - count;
1236 0 : if (count < 8) {
1237 0 : memset(p, 0, count);
1238 0 : byteReverse(ctx->in, 16);
1239 0 : cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
1240 0 : memset(ctx->in, 0, 56);
1241 : } else {
1242 0 : memset(p, 0, count - 8);
1243 : }
1244 0 : byteReverse(ctx->in, 14);
1245 :
1246 0 : a = (uint32_t *) ctx->in;
1247 0 : a[14] = ctx->bits[0];
1248 0 : a[15] = ctx->bits[1];
1249 :
1250 0 : cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
1251 0 : byteReverse((unsigned char *) ctx->buf, 4);
1252 0 : memcpy(digest, ctx->buf, 16);
1253 0 : memset((char *) ctx, 0, sizeof(*ctx));
1254 0 : }
1255 :
1256 : #endif /* CS_DISABLE_MD5 */
1257 : #endif /* EXCLUDE_COMMON */
1258 : #ifdef MG_MODULE_LINES
1259 : #line 1 "common/cs_sha1.c"
1260 : #endif
1261 : /* Copyright(c) By Steve Reid <steve@edmweb.com> */
1262 : /* 100% Public Domain */
1263 :
1264 : /* Amalgamated: #include "common/cs_sha1.h" */
1265 :
1266 : #if !CS_DISABLE_SHA1 && !defined(EXCLUDE_COMMON)
1267 :
1268 : /* Amalgamated: #include "common/cs_endian.h" */
1269 :
1270 : #define SHA1HANDSOFF
1271 : #if defined(__sun)
1272 : /* Amalgamated: #include "common/solarisfixes.h" */
1273 : #endif
1274 :
1275 : union char64long16 {
1276 : unsigned char c[64];
1277 : uint32_t l[16];
1278 : };
1279 :
1280 : #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
1281 :
1282 0 : static uint32_t blk0(union char64long16 *block, int i) {
1283 : /* Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN */
1284 : #if BYTE_ORDER == LITTLE_ENDIAN
1285 0 : block->l[i] =
1286 0 : (rol(block->l[i], 24) & 0xFF00FF00) | (rol(block->l[i], 8) & 0x00FF00FF);
1287 : #endif
1288 0 : return block->l[i];
1289 : }
1290 :
1291 : /* Avoid redefine warning (ARM /usr/include/sys/ucontext.h define R0~R4) */
1292 : #undef blk
1293 : #undef R0
1294 : #undef R1
1295 : #undef R2
1296 : #undef R3
1297 : #undef R4
1298 :
1299 : #define blk(i) \
1300 : (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ \
1301 : block->l[(i + 2) & 15] ^ block->l[i & 15], \
1302 : 1))
1303 : #define R0(v, w, x, y, z, i) \
1304 : z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \
1305 : w = rol(w, 30);
1306 : #define R1(v, w, x, y, z, i) \
1307 : z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
1308 : w = rol(w, 30);
1309 : #define R2(v, w, x, y, z, i) \
1310 : z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
1311 : w = rol(w, 30);
1312 : #define R3(v, w, x, y, z, i) \
1313 : z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
1314 : w = rol(w, 30);
1315 : #define R4(v, w, x, y, z, i) \
1316 : z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
1317 : w = rol(w, 30);
1318 :
1319 0 : void cs_sha1_transform(uint32_t state[5], const unsigned char buffer[64]) {
1320 : uint32_t a, b, c, d, e;
1321 : union char64long16 block[1];
1322 :
1323 0 : memcpy(block, buffer, 64);
1324 0 : a = state[0];
1325 0 : b = state[1];
1326 0 : c = state[2];
1327 0 : d = state[3];
1328 0 : e = state[4];
1329 0 : R0(a, b, c, d, e, 0);
1330 0 : R0(e, a, b, c, d, 1);
1331 0 : R0(d, e, a, b, c, 2);
1332 0 : R0(c, d, e, a, b, 3);
1333 0 : R0(b, c, d, e, a, 4);
1334 0 : R0(a, b, c, d, e, 5);
1335 0 : R0(e, a, b, c, d, 6);
1336 0 : R0(d, e, a, b, c, 7);
1337 0 : R0(c, d, e, a, b, 8);
1338 0 : R0(b, c, d, e, a, 9);
1339 0 : R0(a, b, c, d, e, 10);
1340 0 : R0(e, a, b, c, d, 11);
1341 0 : R0(d, e, a, b, c, 12);
1342 0 : R0(c, d, e, a, b, 13);
1343 0 : R0(b, c, d, e, a, 14);
1344 0 : R0(a, b, c, d, e, 15);
1345 0 : R1(e, a, b, c, d, 16);
1346 0 : R1(d, e, a, b, c, 17);
1347 0 : R1(c, d, e, a, b, 18);
1348 0 : R1(b, c, d, e, a, 19);
1349 0 : R2(a, b, c, d, e, 20);
1350 0 : R2(e, a, b, c, d, 21);
1351 0 : R2(d, e, a, b, c, 22);
1352 0 : R2(c, d, e, a, b, 23);
1353 0 : R2(b, c, d, e, a, 24);
1354 0 : R2(a, b, c, d, e, 25);
1355 0 : R2(e, a, b, c, d, 26);
1356 0 : R2(d, e, a, b, c, 27);
1357 0 : R2(c, d, e, a, b, 28);
1358 0 : R2(b, c, d, e, a, 29);
1359 0 : R2(a, b, c, d, e, 30);
1360 0 : R2(e, a, b, c, d, 31);
1361 0 : R2(d, e, a, b, c, 32);
1362 0 : R2(c, d, e, a, b, 33);
1363 0 : R2(b, c, d, e, a, 34);
1364 0 : R2(a, b, c, d, e, 35);
1365 0 : R2(e, a, b, c, d, 36);
1366 0 : R2(d, e, a, b, c, 37);
1367 0 : R2(c, d, e, a, b, 38);
1368 0 : R2(b, c, d, e, a, 39);
1369 0 : R3(a, b, c, d, e, 40);
1370 0 : R3(e, a, b, c, d, 41);
1371 0 : R3(d, e, a, b, c, 42);
1372 0 : R3(c, d, e, a, b, 43);
1373 0 : R3(b, c, d, e, a, 44);
1374 0 : R3(a, b, c, d, e, 45);
1375 0 : R3(e, a, b, c, d, 46);
1376 0 : R3(d, e, a, b, c, 47);
1377 0 : R3(c, d, e, a, b, 48);
1378 0 : R3(b, c, d, e, a, 49);
1379 0 : R3(a, b, c, d, e, 50);
1380 0 : R3(e, a, b, c, d, 51);
1381 0 : R3(d, e, a, b, c, 52);
1382 0 : R3(c, d, e, a, b, 53);
1383 0 : R3(b, c, d, e, a, 54);
1384 0 : R3(a, b, c, d, e, 55);
1385 0 : R3(e, a, b, c, d, 56);
1386 0 : R3(d, e, a, b, c, 57);
1387 0 : R3(c, d, e, a, b, 58);
1388 0 : R3(b, c, d, e, a, 59);
1389 0 : R4(a, b, c, d, e, 60);
1390 0 : R4(e, a, b, c, d, 61);
1391 0 : R4(d, e, a, b, c, 62);
1392 0 : R4(c, d, e, a, b, 63);
1393 0 : R4(b, c, d, e, a, 64);
1394 0 : R4(a, b, c, d, e, 65);
1395 0 : R4(e, a, b, c, d, 66);
1396 0 : R4(d, e, a, b, c, 67);
1397 0 : R4(c, d, e, a, b, 68);
1398 0 : R4(b, c, d, e, a, 69);
1399 0 : R4(a, b, c, d, e, 70);
1400 0 : R4(e, a, b, c, d, 71);
1401 0 : R4(d, e, a, b, c, 72);
1402 0 : R4(c, d, e, a, b, 73);
1403 0 : R4(b, c, d, e, a, 74);
1404 0 : R4(a, b, c, d, e, 75);
1405 0 : R4(e, a, b, c, d, 76);
1406 0 : R4(d, e, a, b, c, 77);
1407 0 : R4(c, d, e, a, b, 78);
1408 0 : R4(b, c, d, e, a, 79);
1409 0 : state[0] += a;
1410 0 : state[1] += b;
1411 0 : state[2] += c;
1412 0 : state[3] += d;
1413 0 : state[4] += e;
1414 : /* Erase working structures. The order of operations is important,
1415 : * used to ensure that compiler doesn't optimize those out. */
1416 0 : memset(block, 0, sizeof(block));
1417 0 : a = b = c = d = e = 0;
1418 : (void) a;
1419 : (void) b;
1420 : (void) c;
1421 : (void) d;
1422 : (void) e;
1423 0 : }
1424 :
1425 0 : void cs_sha1_init(cs_sha1_ctx *context) {
1426 0 : context->state[0] = 0x67452301;
1427 0 : context->state[1] = 0xEFCDAB89;
1428 0 : context->state[2] = 0x98BADCFE;
1429 0 : context->state[3] = 0x10325476;
1430 0 : context->state[4] = 0xC3D2E1F0;
1431 0 : context->count[0] = context->count[1] = 0;
1432 0 : }
1433 :
1434 0 : void cs_sha1_update(cs_sha1_ctx *context, const unsigned char *data,
1435 : uint32_t len) {
1436 : uint32_t i, j;
1437 :
1438 0 : j = context->count[0];
1439 0 : if ((context->count[0] += len << 3) < j) context->count[1]++;
1440 0 : context->count[1] += (len >> 29);
1441 0 : j = (j >> 3) & 63;
1442 0 : if ((j + len) > 63) {
1443 0 : memcpy(&context->buffer[j], data, (i = 64 - j));
1444 0 : cs_sha1_transform(context->state, context->buffer);
1445 0 : for (; i + 63 < len; i += 64) {
1446 0 : cs_sha1_transform(context->state, &data[i]);
1447 : }
1448 0 : j = 0;
1449 : } else
1450 0 : i = 0;
1451 0 : memcpy(&context->buffer[j], &data[i], len - i);
1452 0 : }
1453 :
1454 0 : void cs_sha1_final(unsigned char digest[20], cs_sha1_ctx *context) {
1455 : unsigned i;
1456 : unsigned char finalcount[8], c;
1457 :
1458 0 : for (i = 0; i < 8; i++) {
1459 0 : finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >>
1460 0 : ((3 - (i & 3)) * 8)) &
1461 : 255);
1462 : }
1463 0 : c = 0200;
1464 0 : cs_sha1_update(context, &c, 1);
1465 0 : while ((context->count[0] & 504) != 448) {
1466 0 : c = 0000;
1467 0 : cs_sha1_update(context, &c, 1);
1468 : }
1469 0 : cs_sha1_update(context, finalcount, 8);
1470 0 : for (i = 0; i < 20; i++) {
1471 0 : digest[i] =
1472 0 : (unsigned char) ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
1473 : }
1474 0 : memset(context, '\0', sizeof(*context));
1475 0 : memset(&finalcount, '\0', sizeof(finalcount));
1476 0 : }
1477 :
1478 0 : void cs_hmac_sha1(const unsigned char *key, size_t keylen,
1479 : const unsigned char *data, size_t datalen,
1480 : unsigned char out[20]) {
1481 : cs_sha1_ctx ctx;
1482 : unsigned char buf1[64], buf2[64], tmp_key[20], i;
1483 :
1484 0 : if (keylen > sizeof(buf1)) {
1485 0 : cs_sha1_init(&ctx);
1486 0 : cs_sha1_update(&ctx, key, keylen);
1487 0 : cs_sha1_final(tmp_key, &ctx);
1488 0 : key = tmp_key;
1489 0 : keylen = sizeof(tmp_key);
1490 : }
1491 :
1492 0 : memset(buf1, 0, sizeof(buf1));
1493 0 : memset(buf2, 0, sizeof(buf2));
1494 0 : memcpy(buf1, key, keylen);
1495 0 : memcpy(buf2, key, keylen);
1496 :
1497 0 : for (i = 0; i < sizeof(buf1); i++) {
1498 0 : buf1[i] ^= 0x36;
1499 0 : buf2[i] ^= 0x5c;
1500 : }
1501 :
1502 0 : cs_sha1_init(&ctx);
1503 0 : cs_sha1_update(&ctx, buf1, sizeof(buf1));
1504 0 : cs_sha1_update(&ctx, data, datalen);
1505 0 : cs_sha1_final(out, &ctx);
1506 :
1507 0 : cs_sha1_init(&ctx);
1508 0 : cs_sha1_update(&ctx, buf2, sizeof(buf2));
1509 0 : cs_sha1_update(&ctx, out, 20);
1510 0 : cs_sha1_final(out, &ctx);
1511 0 : }
1512 :
1513 : #endif /* EXCLUDE_COMMON */
1514 : #ifdef MG_MODULE_LINES
1515 : #line 1 "common/mbuf.c"
1516 : #endif
1517 : /*
1518 : * Copyright (c) 2014-2018 Cesanta Software Limited
1519 : * All rights reserved
1520 : *
1521 : * Licensed under the Apache License, Version 2.0 (the ""License"");
1522 : * you may not use this file except in compliance with the License.
1523 : * You may obtain a copy of the License at
1524 : *
1525 : * http://www.apache.org/licenses/LICENSE-2.0
1526 : *
1527 : * Unless required by applicable law or agreed to in writing, software
1528 : * distributed under the License is distributed on an ""AS IS"" BASIS,
1529 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1530 : * See the License for the specific language governing permissions and
1531 : * limitations under the License.
1532 : */
1533 :
1534 : #ifndef EXCLUDE_COMMON
1535 :
1536 : #include <assert.h>
1537 : #include <string.h>
1538 : /* Amalgamated: #include "common/mbuf.h" */
1539 :
1540 : #ifndef MBUF_REALLOC
1541 : #define MBUF_REALLOC realloc
1542 : #endif
1543 :
1544 : #ifndef MBUF_FREE
1545 : #define MBUF_FREE free
1546 : #endif
1547 :
1548 : void mbuf_init(struct mbuf *mbuf, size_t initial_size) WEAK;
1549 0 : void mbuf_init(struct mbuf *mbuf, size_t initial_size) {
1550 0 : mbuf->len = mbuf->size = 0;
1551 0 : mbuf->buf = NULL;
1552 0 : mbuf_resize(mbuf, initial_size);
1553 0 : }
1554 :
1555 : void mbuf_free(struct mbuf *mbuf) WEAK;
1556 0 : void mbuf_free(struct mbuf *mbuf) {
1557 0 : if (mbuf->buf != NULL) {
1558 0 : MBUF_FREE(mbuf->buf);
1559 0 : mbuf_init(mbuf, 0);
1560 : }
1561 0 : }
1562 :
1563 : void mbuf_resize(struct mbuf *a, size_t new_size) WEAK;
1564 0 : void mbuf_resize(struct mbuf *a, size_t new_size) {
1565 0 : if (new_size > a->size || (new_size < a->size && new_size >= a->len)) {
1566 0 : char *buf = (char *) MBUF_REALLOC(a->buf, new_size);
1567 : /*
1568 : * In case realloc fails, there's not much we can do, except keep things as
1569 : * they are. Note that NULL is a valid return value from realloc when
1570 : * size == 0, but that is covered too.
1571 : */
1572 0 : if (buf == NULL && new_size != 0) return;
1573 0 : a->buf = buf;
1574 0 : a->size = new_size;
1575 : }
1576 : }
1577 :
1578 : void mbuf_trim(struct mbuf *mbuf) WEAK;
1579 0 : void mbuf_trim(struct mbuf *mbuf) {
1580 0 : mbuf_resize(mbuf, mbuf->len);
1581 0 : }
1582 :
1583 : size_t mbuf_insert(struct mbuf *a, size_t off, const void *buf, size_t) WEAK;
1584 0 : size_t mbuf_insert(struct mbuf *a, size_t off, const void *buf, size_t len) {
1585 0 : char *p = NULL;
1586 :
1587 0 : assert(a != NULL);
1588 0 : assert(a->len <= a->size);
1589 0 : assert(off <= a->len);
1590 :
1591 : /* check overflow */
1592 0 : if (~(size_t) 0 - (size_t) a->buf < len) return 0;
1593 :
1594 0 : if (a->len + len <= a->size) {
1595 0 : memmove(a->buf + off + len, a->buf + off, a->len - off);
1596 0 : if (buf != NULL) {
1597 0 : memcpy(a->buf + off, buf, len);
1598 : }
1599 0 : a->len += len;
1600 : } else {
1601 0 : size_t min_size = (a->len + len);
1602 0 : size_t new_size = (size_t)(min_size * MBUF_SIZE_MULTIPLIER);
1603 0 : if (new_size - min_size > MBUF_SIZE_MAX_HEADROOM) {
1604 0 : new_size = min_size + MBUF_SIZE_MAX_HEADROOM;
1605 : }
1606 0 : p = (char *) MBUF_REALLOC(a->buf, new_size);
1607 0 : if (p == NULL && new_size != min_size) {
1608 0 : new_size = min_size;
1609 0 : p = (char *) MBUF_REALLOC(a->buf, new_size);
1610 : }
1611 0 : if (p != NULL) {
1612 0 : a->buf = p;
1613 0 : if (off != a->len) {
1614 0 : memmove(a->buf + off + len, a->buf + off, a->len - off);
1615 : }
1616 0 : if (buf != NULL) memcpy(a->buf + off, buf, len);
1617 0 : a->len += len;
1618 0 : a->size = new_size;
1619 : } else {
1620 0 : len = 0;
1621 : }
1622 : }
1623 :
1624 0 : return len;
1625 : }
1626 :
1627 : size_t mbuf_append(struct mbuf *a, const void *buf, size_t len) WEAK;
1628 0 : size_t mbuf_append(struct mbuf *a, const void *buf, size_t len) {
1629 0 : return mbuf_insert(a, a->len, buf, len);
1630 : }
1631 :
1632 : size_t mbuf_append_and_free(struct mbuf *a, void *buf, size_t len) WEAK;
1633 0 : size_t mbuf_append_and_free(struct mbuf *a, void *data, size_t len) {
1634 : size_t ret;
1635 : /* Optimization: if the buffer is currently empty,
1636 : * take over the user-provided buffer. */
1637 0 : if (a->len == 0) {
1638 0 : if (a->buf != NULL) free(a->buf);
1639 0 : a->buf = (char *) data;
1640 0 : a->len = a->size = len;
1641 0 : return len;
1642 : }
1643 0 : ret = mbuf_insert(a, a->len, data, len);
1644 0 : free(data);
1645 0 : return ret;
1646 : }
1647 :
1648 : void mbuf_remove(struct mbuf *mb, size_t n) WEAK;
1649 0 : void mbuf_remove(struct mbuf *mb, size_t n) {
1650 0 : if (n > 0 && n <= mb->len) {
1651 0 : memmove(mb->buf, mb->buf + n, mb->len - n);
1652 0 : mb->len -= n;
1653 : }
1654 0 : }
1655 :
1656 : void mbuf_clear(struct mbuf *mb) WEAK;
1657 0 : void mbuf_clear(struct mbuf *mb) {
1658 0 : mb->len = 0;
1659 0 : }
1660 :
1661 : void mbuf_move(struct mbuf *from, struct mbuf *to) WEAK;
1662 0 : void mbuf_move(struct mbuf *from, struct mbuf *to) {
1663 0 : memcpy(to, from, sizeof(*to));
1664 0 : memset(from, 0, sizeof(*from));
1665 0 : }
1666 :
1667 : #endif /* EXCLUDE_COMMON */
1668 : #ifdef MG_MODULE_LINES
1669 : #line 1 "common/mg_str.c"
1670 : #endif
1671 : /*
1672 : * Copyright (c) 2014-2018 Cesanta Software Limited
1673 : * All rights reserved
1674 : *
1675 : * Licensed under the Apache License, Version 2.0 (the ""License"");
1676 : * you may not use this file except in compliance with the License.
1677 : * You may obtain a copy of the License at
1678 : *
1679 : * http://www.apache.org/licenses/LICENSE-2.0
1680 : *
1681 : * Unless required by applicable law or agreed to in writing, software
1682 : * distributed under the License is distributed on an ""AS IS"" BASIS,
1683 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1684 : * See the License for the specific language governing permissions and
1685 : * limitations under the License.
1686 : */
1687 :
1688 : /* Amalgamated: #include "common/mg_mem.h" */
1689 : /* Amalgamated: #include "common/mg_str.h" */
1690 : /* Amalgamated: #include "common/platform.h" */
1691 :
1692 : #include <ctype.h>
1693 : #include <stdlib.h>
1694 : #include <string.h>
1695 :
1696 : int mg_ncasecmp(const char *s1, const char *s2, size_t len) WEAK;
1697 :
1698 : struct mg_str mg_mk_str(const char *s) WEAK;
1699 0 : struct mg_str mg_mk_str(const char *s) {
1700 0 : struct mg_str ret = {s, 0};
1701 0 : if (s != NULL) ret.len = strlen(s);
1702 0 : return ret;
1703 : }
1704 :
1705 : struct mg_str mg_mk_str_n(const char *s, size_t len) WEAK;
1706 0 : struct mg_str mg_mk_str_n(const char *s, size_t len) {
1707 0 : struct mg_str ret = {s, len};
1708 0 : return ret;
1709 : }
1710 :
1711 : int mg_vcmp(const struct mg_str *str1, const char *str2) WEAK;
1712 0 : int mg_vcmp(const struct mg_str *str1, const char *str2) {
1713 0 : size_t n2 = strlen(str2), n1 = str1->len;
1714 0 : int r = strncmp(str1->p, str2, (n1 < n2) ? n1 : n2);
1715 0 : if (r == 0) {
1716 0 : return n1 - n2;
1717 : }
1718 0 : return r;
1719 : }
1720 :
1721 : int mg_vcasecmp(const struct mg_str *str1, const char *str2) WEAK;
1722 0 : int mg_vcasecmp(const struct mg_str *str1, const char *str2) {
1723 0 : size_t n2 = strlen(str2), n1 = str1->len;
1724 0 : int r = mg_ncasecmp(str1->p, str2, (n1 < n2) ? n1 : n2);
1725 0 : if (r == 0) {
1726 0 : return n1 - n2;
1727 : }
1728 0 : return r;
1729 : }
1730 :
1731 0 : static struct mg_str mg_strdup_common(const struct mg_str s,
1732 : int nul_terminate) {
1733 0 : struct mg_str r = {NULL, 0};
1734 0 : if (s.len > 0 && s.p != NULL) {
1735 0 : char *sc = (char *) MG_MALLOC(s.len + (nul_terminate ? 1 : 0));
1736 0 : if (sc != NULL) {
1737 0 : memcpy(sc, s.p, s.len);
1738 0 : if (nul_terminate) sc[s.len] = '\0';
1739 0 : r.p = sc;
1740 0 : r.len = s.len;
1741 : }
1742 : }
1743 0 : return r;
1744 : }
1745 :
1746 : struct mg_str mg_strdup(const struct mg_str s) WEAK;
1747 0 : struct mg_str mg_strdup(const struct mg_str s) {
1748 0 : return mg_strdup_common(s, 0 /* NUL-terminate */);
1749 : }
1750 :
1751 : struct mg_str mg_strdup_nul(const struct mg_str s) WEAK;
1752 0 : struct mg_str mg_strdup_nul(const struct mg_str s) {
1753 0 : return mg_strdup_common(s, 1 /* NUL-terminate */);
1754 : }
1755 :
1756 : const char *mg_strchr(const struct mg_str s, int c) WEAK;
1757 0 : const char *mg_strchr(const struct mg_str s, int c) {
1758 : size_t i;
1759 0 : for (i = 0; i < s.len; i++) {
1760 0 : if (s.p[i] == c) return &s.p[i];
1761 : }
1762 0 : return NULL;
1763 : }
1764 :
1765 : int mg_strcmp(const struct mg_str str1, const struct mg_str str2) WEAK;
1766 0 : int mg_strcmp(const struct mg_str str1, const struct mg_str str2) {
1767 0 : size_t i = 0;
1768 0 : while (i < str1.len && i < str2.len) {
1769 0 : if (str1.p[i] < str2.p[i]) return -1;
1770 0 : if (str1.p[i] > str2.p[i]) return 1;
1771 0 : i++;
1772 : }
1773 0 : if (i < str1.len) return 1;
1774 0 : if (i < str2.len) return -1;
1775 0 : return 0;
1776 : }
1777 :
1778 : int mg_strncmp(const struct mg_str, const struct mg_str, size_t n) WEAK;
1779 0 : int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n) {
1780 0 : struct mg_str s1 = str1;
1781 0 : struct mg_str s2 = str2;
1782 :
1783 0 : if (s1.len > n) {
1784 0 : s1.len = n;
1785 : }
1786 0 : if (s2.len > n) {
1787 0 : s2.len = n;
1788 : }
1789 0 : return mg_strcmp(s1, s2);
1790 : }
1791 :
1792 : void mg_strfree(struct mg_str *s) WEAK;
1793 0 : void mg_strfree(struct mg_str *s) {
1794 0 : char *sp = (char *) s->p;
1795 0 : s->p = NULL;
1796 0 : s->len = 0;
1797 0 : if (sp != NULL) free(sp);
1798 0 : }
1799 :
1800 : const char *mg_strstr(const struct mg_str haystack,
1801 : const struct mg_str needle) WEAK;
1802 0 : const char *mg_strstr(const struct mg_str haystack,
1803 : const struct mg_str needle) {
1804 : size_t i;
1805 0 : if (needle.len > haystack.len) return NULL;
1806 0 : for (i = 0; i <= haystack.len - needle.len; i++) {
1807 0 : if (memcmp(haystack.p + i, needle.p, needle.len) == 0) {
1808 0 : return haystack.p + i;
1809 : }
1810 : }
1811 0 : return NULL;
1812 : }
1813 :
1814 : struct mg_str mg_strstrip(struct mg_str s) WEAK;
1815 0 : struct mg_str mg_strstrip(struct mg_str s) {
1816 0 : while (s.len > 0 && isspace((int) *s.p)) {
1817 0 : s.p++;
1818 0 : s.len--;
1819 : }
1820 0 : while (s.len > 0 && isspace((int) *(s.p + s.len - 1))) {
1821 0 : s.len--;
1822 : }
1823 0 : return s;
1824 : }
1825 :
1826 : int mg_str_starts_with(struct mg_str s, struct mg_str prefix) WEAK;
1827 0 : int mg_str_starts_with(struct mg_str s, struct mg_str prefix) {
1828 0 : const struct mg_str sp = MG_MK_STR_N(s.p, prefix.len);
1829 0 : if (s.len < prefix.len) return 0;
1830 0 : return (mg_strcmp(sp, prefix) == 0);
1831 : }
1832 : #ifdef MG_MODULE_LINES
1833 : #line 1 "common/str_util.c"
1834 : #endif
1835 : /*
1836 : * Copyright (c) 2014-2018 Cesanta Software Limited
1837 : * All rights reserved
1838 : *
1839 : * Licensed under the Apache License, Version 2.0 (the ""License"");
1840 : * you may not use this file except in compliance with the License.
1841 : * You may obtain a copy of the License at
1842 : *
1843 : * http://www.apache.org/licenses/LICENSE-2.0
1844 : *
1845 : * Unless required by applicable law or agreed to in writing, software
1846 : * distributed under the License is distributed on an ""AS IS"" BASIS,
1847 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1848 : * See the License for the specific language governing permissions and
1849 : * limitations under the License.
1850 : */
1851 :
1852 : #ifndef EXCLUDE_COMMON
1853 :
1854 : /* Amalgamated: #include "common/str_util.h" */
1855 : /* Amalgamated: #include "common/mg_mem.h" */
1856 : /* Amalgamated: #include "common/platform.h" */
1857 :
1858 : #ifndef C_DISABLE_BUILTIN_SNPRINTF
1859 : #define C_DISABLE_BUILTIN_SNPRINTF 0
1860 : #endif
1861 :
1862 : /* Amalgamated: #include "common/mg_mem.h" */
1863 :
1864 : size_t c_strnlen(const char *s, size_t maxlen) WEAK;
1865 0 : size_t c_strnlen(const char *s, size_t maxlen) {
1866 0 : size_t l = 0;
1867 0 : for (; l < maxlen && s[l] != '\0'; l++) {
1868 : }
1869 0 : return l;
1870 : }
1871 :
1872 : #define C_SNPRINTF_APPEND_CHAR(ch) \
1873 : do { \
1874 : if (i < (int) buf_size) buf[i] = ch; \
1875 : i++; \
1876 : } while (0)
1877 :
1878 : #define C_SNPRINTF_FLAG_ZERO 1
1879 :
1880 : #if C_DISABLE_BUILTIN_SNPRINTF
1881 : int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) WEAK;
1882 : int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) {
1883 : return vsnprintf(buf, buf_size, fmt, ap);
1884 : }
1885 : #else
1886 0 : static int c_itoa(char *buf, size_t buf_size, int64_t num, int base, int flags,
1887 : int field_width) {
1888 : char tmp[40];
1889 0 : int i = 0, k = 0, neg = 0;
1890 :
1891 0 : if (num < 0) {
1892 0 : neg++;
1893 0 : num = -num;
1894 : }
1895 :
1896 : /* Print into temporary buffer - in reverse order */
1897 : do {
1898 0 : int rem = num % base;
1899 0 : if (rem < 10) {
1900 0 : tmp[k++] = '0' + rem;
1901 : } else {
1902 0 : tmp[k++] = 'a' + (rem - 10);
1903 : }
1904 0 : num /= base;
1905 0 : } while (num > 0);
1906 :
1907 : /* Zero padding */
1908 0 : if (flags && C_SNPRINTF_FLAG_ZERO) {
1909 0 : while (k < field_width && k < (int) sizeof(tmp) - 1) {
1910 0 : tmp[k++] = '0';
1911 : }
1912 : }
1913 :
1914 : /* And sign */
1915 0 : if (neg) {
1916 0 : tmp[k++] = '-';
1917 : }
1918 :
1919 : /* Now output */
1920 0 : while (--k >= 0) {
1921 0 : C_SNPRINTF_APPEND_CHAR(tmp[k]);
1922 : }
1923 :
1924 0 : return i;
1925 : }
1926 :
1927 : int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) WEAK;
1928 0 : int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) {
1929 0 : int ch, i = 0, len_mod, flags, precision, field_width;
1930 :
1931 0 : while ((ch = *fmt++) != '\0') {
1932 0 : if (ch != '%') {
1933 0 : C_SNPRINTF_APPEND_CHAR(ch);
1934 : } else {
1935 : /*
1936 : * Conversion specification:
1937 : * zero or more flags (one of: # 0 - <space> + ')
1938 : * an optional minimum field width (digits)
1939 : * an optional precision (. followed by digits, or *)
1940 : * an optional length modifier (one of: hh h l ll L q j z t)
1941 : * conversion specifier (one of: d i o u x X e E f F g G a A c s p n)
1942 : */
1943 0 : flags = field_width = precision = len_mod = 0;
1944 :
1945 : /* Flags. only zero-pad flag is supported. */
1946 0 : if (*fmt == '0') {
1947 0 : flags |= C_SNPRINTF_FLAG_ZERO;
1948 : }
1949 :
1950 : /* Field width */
1951 0 : while (*fmt >= '0' && *fmt <= '9') {
1952 0 : field_width *= 10;
1953 0 : field_width += *fmt++ - '0';
1954 : }
1955 : /* Dynamic field width */
1956 0 : if (*fmt == '*') {
1957 0 : field_width = va_arg(ap, int);
1958 0 : fmt++;
1959 : }
1960 :
1961 : /* Precision */
1962 0 : if (*fmt == '.') {
1963 0 : fmt++;
1964 0 : if (*fmt == '*') {
1965 0 : precision = va_arg(ap, int);
1966 0 : fmt++;
1967 : } else {
1968 0 : while (*fmt >= '0' && *fmt <= '9') {
1969 0 : precision *= 10;
1970 0 : precision += *fmt++ - '0';
1971 : }
1972 : }
1973 : }
1974 :
1975 : /* Length modifier */
1976 0 : switch (*fmt) {
1977 0 : case 'h':
1978 : case 'l':
1979 : case 'L':
1980 : case 'I':
1981 : case 'q':
1982 : case 'j':
1983 : case 'z':
1984 : case 't':
1985 0 : len_mod = *fmt++;
1986 0 : if (*fmt == 'h') {
1987 0 : len_mod = 'H';
1988 0 : fmt++;
1989 : }
1990 0 : if (*fmt == 'l') {
1991 0 : len_mod = 'q';
1992 0 : fmt++;
1993 : }
1994 0 : break;
1995 : }
1996 :
1997 0 : ch = *fmt++;
1998 0 : if (ch == 's') {
1999 0 : const char *s = va_arg(ap, const char *); /* Always fetch parameter */
2000 : int j;
2001 0 : int pad = field_width - (precision >= 0 ? c_strnlen(s, precision) : 0);
2002 0 : for (j = 0; j < pad; j++) {
2003 0 : C_SNPRINTF_APPEND_CHAR(' ');
2004 : }
2005 :
2006 : /* `s` may be NULL in case of %.*s */
2007 0 : if (s != NULL) {
2008 : /* Ignore negative and 0 precisions */
2009 0 : for (j = 0; (precision <= 0 || j < precision) && s[j] != '\0'; j++) {
2010 0 : C_SNPRINTF_APPEND_CHAR(s[j]);
2011 : }
2012 : }
2013 0 : } else if (ch == 'c') {
2014 0 : ch = va_arg(ap, int); /* Always fetch parameter */
2015 0 : C_SNPRINTF_APPEND_CHAR(ch);
2016 0 : } else if (ch == 'd' && len_mod == 0) {
2017 0 : i += c_itoa(buf + i, buf_size - i, va_arg(ap, int), 10, flags,
2018 : field_width);
2019 0 : } else if (ch == 'd' && len_mod == 'l') {
2020 0 : i += c_itoa(buf + i, buf_size - i, va_arg(ap, long), 10, flags,
2021 : field_width);
2022 : #ifdef SSIZE_MAX
2023 0 : } else if (ch == 'd' && len_mod == 'z') {
2024 0 : i += c_itoa(buf + i, buf_size - i, va_arg(ap, ssize_t), 10, flags,
2025 : field_width);
2026 : #endif
2027 0 : } else if (ch == 'd' && len_mod == 'q') {
2028 0 : i += c_itoa(buf + i, buf_size - i, va_arg(ap, int64_t), 10, flags,
2029 : field_width);
2030 0 : } else if ((ch == 'x' || ch == 'u') && len_mod == 0) {
2031 0 : i += c_itoa(buf + i, buf_size - i, va_arg(ap, unsigned),
2032 : ch == 'x' ? 16 : 10, flags, field_width);
2033 0 : } else if ((ch == 'x' || ch == 'u') && len_mod == 'l') {
2034 0 : i += c_itoa(buf + i, buf_size - i, va_arg(ap, unsigned long),
2035 : ch == 'x' ? 16 : 10, flags, field_width);
2036 0 : } else if ((ch == 'x' || ch == 'u') && len_mod == 'z') {
2037 0 : i += c_itoa(buf + i, buf_size - i, va_arg(ap, size_t),
2038 : ch == 'x' ? 16 : 10, flags, field_width);
2039 0 : } else if (ch == 'p') {
2040 0 : unsigned long num = (unsigned long) (uintptr_t) va_arg(ap, void *);
2041 0 : C_SNPRINTF_APPEND_CHAR('0');
2042 0 : C_SNPRINTF_APPEND_CHAR('x');
2043 0 : i += c_itoa(buf + i, buf_size - i, num, 16, flags, 0);
2044 : } else {
2045 : #ifndef NO_LIBC
2046 : /*
2047 : * TODO(lsm): abort is not nice in a library, remove it
2048 : * Also, ESP8266 SDK doesn't have it
2049 : */
2050 0 : abort();
2051 : #endif
2052 : }
2053 : }
2054 : }
2055 :
2056 : /* Zero-terminate the result */
2057 0 : if (buf_size > 0) {
2058 0 : buf[i < (int) buf_size ? i : (int) buf_size - 1] = '\0';
2059 : }
2060 :
2061 0 : return i;
2062 : }
2063 : #endif
2064 :
2065 : int c_snprintf(char *buf, size_t buf_size, const char *fmt, ...) WEAK;
2066 0 : int c_snprintf(char *buf, size_t buf_size, const char *fmt, ...) {
2067 : int result;
2068 : va_list ap;
2069 0 : va_start(ap, fmt);
2070 0 : result = c_vsnprintf(buf, buf_size, fmt, ap);
2071 0 : va_end(ap);
2072 0 : return result;
2073 : }
2074 :
2075 : #ifdef _WIN32
2076 : int to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len) {
2077 : int ret;
2078 : char buf[MAX_PATH * 2], buf2[MAX_PATH * 2], *p;
2079 :
2080 : strncpy(buf, path, sizeof(buf));
2081 : buf[sizeof(buf) - 1] = '\0';
2082 :
2083 : /* Trim trailing slashes. Leave backslash for paths like "X:\" */
2084 : p = buf + strlen(buf) - 1;
2085 : while (p > buf && p[-1] != ':' && (p[0] == '\\' || p[0] == '/')) *p-- = '\0';
2086 :
2087 : memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
2088 : ret = MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
2089 :
2090 : /*
2091 : * Convert back to Unicode. If doubly-converted string does not match the
2092 : * original, something is fishy, reject.
2093 : */
2094 : WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
2095 : NULL, NULL);
2096 : if (strcmp(buf, buf2) != 0) {
2097 : wbuf[0] = L'\0';
2098 : ret = 0;
2099 : }
2100 :
2101 : return ret;
2102 : }
2103 : #endif /* _WIN32 */
2104 :
2105 : /* The simplest O(mn) algorithm. Better implementation are GPLed */
2106 : const char *c_strnstr(const char *s, const char *find, size_t slen) WEAK;
2107 0 : const char *c_strnstr(const char *s, const char *find, size_t slen) {
2108 0 : size_t find_length = strlen(find);
2109 : size_t i;
2110 :
2111 0 : for (i = 0; i < slen; i++) {
2112 0 : if (i + find_length > slen) {
2113 0 : return NULL;
2114 : }
2115 :
2116 0 : if (strncmp(&s[i], find, find_length) == 0) {
2117 0 : return &s[i];
2118 : }
2119 : }
2120 :
2121 0 : return NULL;
2122 : }
2123 :
2124 : #if CS_ENABLE_STRDUP
2125 : char *strdup(const char *src) WEAK;
2126 : char *strdup(const char *src) {
2127 : size_t len = strlen(src) + 1;
2128 : char *ret = MG_MALLOC(len);
2129 : if (ret != NULL) {
2130 : strcpy(ret, src);
2131 : }
2132 : return ret;
2133 : }
2134 : #endif
2135 :
2136 : void cs_to_hex(char *to, const unsigned char *p, size_t len) WEAK;
2137 0 : void cs_to_hex(char *to, const unsigned char *p, size_t len) {
2138 : static const char *hex = "0123456789abcdef";
2139 :
2140 0 : for (; len--; p++) {
2141 0 : *to++ = hex[p[0] >> 4];
2142 0 : *to++ = hex[p[0] & 0x0f];
2143 : }
2144 0 : *to = '\0';
2145 0 : }
2146 :
2147 0 : static int fourbit(int ch) {
2148 0 : if (ch >= '0' && ch <= '9') {
2149 0 : return ch - '0';
2150 0 : } else if (ch >= 'a' && ch <= 'f') {
2151 0 : return ch - 'a' + 10;
2152 0 : } else if (ch >= 'A' && ch <= 'F') {
2153 0 : return ch - 'A' + 10;
2154 : }
2155 0 : return 0;
2156 : }
2157 :
2158 : void cs_from_hex(char *to, const char *p, size_t len) WEAK;
2159 0 : void cs_from_hex(char *to, const char *p, size_t len) {
2160 : size_t i;
2161 :
2162 0 : for (i = 0; i < len; i += 2) {
2163 0 : *to++ = (fourbit(p[i]) << 4) + fourbit(p[i + 1]);
2164 : }
2165 0 : *to = '\0';
2166 0 : }
2167 :
2168 : #if CS_ENABLE_TO64
2169 : int64_t cs_to64(const char *s) WEAK;
2170 : int64_t cs_to64(const char *s) {
2171 : int64_t result = 0;
2172 : int64_t neg = 1;
2173 : while (*s && isspace((unsigned char) *s)) s++;
2174 : if (*s == '-') {
2175 : neg = -1;
2176 : s++;
2177 : }
2178 : while (isdigit((unsigned char) *s)) {
2179 : result *= 10;
2180 : result += (*s - '0');
2181 : s++;
2182 : }
2183 : return result * neg;
2184 : }
2185 : #endif
2186 :
2187 0 : static int str_util_lowercase(const char *s) {
2188 0 : return tolower(*(const unsigned char *) s);
2189 : }
2190 :
2191 : int mg_ncasecmp(const char *s1, const char *s2, size_t len) WEAK;
2192 0 : int mg_ncasecmp(const char *s1, const char *s2, size_t len) {
2193 0 : int diff = 0;
2194 :
2195 0 : if (len > 0) do {
2196 0 : diff = str_util_lowercase(s1++) - str_util_lowercase(s2++);
2197 0 : } while (diff == 0 && s1[-1] != '\0' && --len > 0);
2198 :
2199 0 : return diff;
2200 : }
2201 :
2202 : int mg_casecmp(const char *s1, const char *s2) WEAK;
2203 0 : int mg_casecmp(const char *s1, const char *s2) {
2204 0 : return mg_ncasecmp(s1, s2, (size_t) ~0);
2205 : }
2206 :
2207 : int mg_asprintf(char **buf, size_t size, const char *fmt, ...) WEAK;
2208 0 : int mg_asprintf(char **buf, size_t size, const char *fmt, ...) {
2209 : int ret;
2210 : va_list ap;
2211 0 : va_start(ap, fmt);
2212 0 : ret = mg_avprintf(buf, size, fmt, ap);
2213 0 : va_end(ap);
2214 0 : return ret;
2215 : }
2216 :
2217 : int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap) WEAK;
2218 0 : int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap) {
2219 : va_list ap_copy;
2220 : int len;
2221 :
2222 0 : va_copy(ap_copy, ap);
2223 0 : len = vsnprintf(*buf, size, fmt, ap_copy);
2224 0 : va_end(ap_copy);
2225 :
2226 0 : if (len < 0) {
2227 : /* eCos and Windows are not standard-compliant and return -1 when
2228 : * the buffer is too small. Keep allocating larger buffers until we
2229 : * succeed or out of memory. */
2230 : *buf = NULL; /* LCOV_EXCL_START */
2231 : while (len < 0) {
2232 : MG_FREE(*buf);
2233 : if (size == 0) {
2234 : size = 5;
2235 : }
2236 : size *= 2;
2237 : if ((*buf = (char *) MG_MALLOC(size)) == NULL) {
2238 : len = -1;
2239 : break;
2240 : }
2241 : va_copy(ap_copy, ap);
2242 : len = vsnprintf(*buf, size - 1, fmt, ap_copy);
2243 : va_end(ap_copy);
2244 : }
2245 :
2246 : /*
2247 : * Microsoft version of vsnprintf() is not always null-terminated, so put
2248 : * the terminator manually
2249 : */
2250 : (*buf)[len] = 0;
2251 : /* LCOV_EXCL_STOP */
2252 0 : } else if (len >= (int) size) {
2253 : /* Standard-compliant code path. Allocate a buffer that is large enough. */
2254 0 : if ((*buf = (char *) MG_MALLOC(len + 1)) == NULL) {
2255 : len = -1; /* LCOV_EXCL_LINE */
2256 : } else { /* LCOV_EXCL_LINE */
2257 0 : va_copy(ap_copy, ap);
2258 0 : len = vsnprintf(*buf, len + 1, fmt, ap_copy);
2259 0 : va_end(ap_copy);
2260 : }
2261 : }
2262 :
2263 0 : return len;
2264 : }
2265 :
2266 : const char *mg_next_comma_list_entry(const char *, struct mg_str *,
2267 : struct mg_str *) WEAK;
2268 0 : const char *mg_next_comma_list_entry(const char *list, struct mg_str *val,
2269 : struct mg_str *eq_val) {
2270 0 : struct mg_str ret = mg_next_comma_list_entry_n(mg_mk_str(list), val, eq_val);
2271 0 : return ret.p;
2272 : }
2273 :
2274 : struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val,
2275 : struct mg_str *eq_val) WEAK;
2276 0 : struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val,
2277 : struct mg_str *eq_val) {
2278 0 : if (list.len == 0) {
2279 : /* End of the list */
2280 0 : list = mg_mk_str(NULL);
2281 : } else {
2282 0 : const char *chr = NULL;
2283 0 : *val = list;
2284 :
2285 0 : if ((chr = mg_strchr(*val, ',')) != NULL) {
2286 : /* Comma found. Store length and shift the list ptr */
2287 0 : val->len = chr - val->p;
2288 0 : chr++;
2289 0 : list.len -= (chr - list.p);
2290 0 : list.p = chr;
2291 : } else {
2292 : /* This value is the last one */
2293 0 : list = mg_mk_str_n(list.p + list.len, 0);
2294 : }
2295 :
2296 0 : if (eq_val != NULL) {
2297 : /* Value has form "x=y", adjust pointers and lengths */
2298 : /* so that val points to "x", and eq_val points to "y". */
2299 0 : eq_val->len = 0;
2300 0 : eq_val->p = (const char *) memchr(val->p, '=', val->len);
2301 0 : if (eq_val->p != NULL) {
2302 0 : eq_val->p++; /* Skip over '=' character */
2303 0 : eq_val->len = val->p + val->len - eq_val->p;
2304 0 : val->len = (eq_val->p - val->p) - 1;
2305 : }
2306 : }
2307 : }
2308 :
2309 0 : return list;
2310 : }
2311 :
2312 : size_t mg_match_prefix_n(const struct mg_str, const struct mg_str) WEAK;
2313 0 : size_t mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str) {
2314 : const char *or_str;
2315 0 : size_t res = 0, len = 0, i = 0, j = 0;
2316 :
2317 0 : if ((or_str = (const char *) memchr(pattern.p, '|', pattern.len)) != NULL ||
2318 0 : (or_str = (const char *) memchr(pattern.p, ',', pattern.len)) != NULL) {
2319 0 : struct mg_str pstr = {pattern.p, (size_t)(or_str - pattern.p)};
2320 0 : res = mg_match_prefix_n(pstr, str);
2321 0 : if (res > 0) return res;
2322 0 : pstr.p = or_str + 1;
2323 0 : pstr.len = (pattern.p + pattern.len) - (or_str + 1);
2324 0 : return mg_match_prefix_n(pstr, str);
2325 : }
2326 :
2327 0 : for (; i < pattern.len && j < str.len; i++, j++) {
2328 0 : if (pattern.p[i] == '?') {
2329 0 : continue;
2330 0 : } else if (pattern.p[i] == '*') {
2331 0 : i++;
2332 0 : if (i < pattern.len && pattern.p[i] == '*') {
2333 0 : i++;
2334 0 : len = str.len - j;
2335 : } else {
2336 0 : len = 0;
2337 0 : while (j + len < str.len && str.p[j + len] != '/') len++;
2338 : }
2339 0 : if (i == pattern.len || (pattern.p[i] == '$' && i == pattern.len - 1))
2340 0 : return j + len;
2341 : do {
2342 0 : const struct mg_str pstr = {pattern.p + i, pattern.len - i};
2343 0 : const struct mg_str sstr = {str.p + j + len, str.len - j - len};
2344 0 : res = mg_match_prefix_n(pstr, sstr);
2345 0 : } while (res == 0 && len != 0 && len-- > 0);
2346 0 : return res == 0 ? 0 : j + res + len;
2347 0 : } else if (str_util_lowercase(&pattern.p[i]) !=
2348 0 : str_util_lowercase(&str.p[j])) {
2349 0 : break;
2350 : }
2351 : }
2352 0 : if (i < pattern.len && pattern.p[i] == '$') {
2353 0 : return j == str.len ? str.len : 0;
2354 : }
2355 0 : return i == pattern.len ? j : 0;
2356 : }
2357 :
2358 : size_t mg_match_prefix(const char *, int, const char *) WEAK;
2359 0 : size_t mg_match_prefix(const char *pattern, int pattern_len, const char *str) {
2360 0 : const struct mg_str pstr = {pattern, (size_t) pattern_len};
2361 0 : struct mg_str s = {str, 0};
2362 0 : if (str != NULL) s.len = strlen(str);
2363 0 : return mg_match_prefix_n(pstr, s);
2364 : }
2365 :
2366 : #endif /* EXCLUDE_COMMON */
2367 : #ifdef MG_MODULE_LINES
2368 : #line 1 "mongoose/src/mg_net.c"
2369 : #endif
2370 : /*
2371 : * Copyright (c) 2014 Cesanta Software Limited
2372 : * All rights reserved
2373 : *
2374 : * This software is dual-licensed: you can redistribute it and/or modify
2375 : * it under the terms of the GNU General Public License version 2 as
2376 : * published by the Free Software Foundation. For the terms of this
2377 : * license, see <http://www.gnu.org/licenses/>.
2378 : *
2379 : * You are free to use this software under the terms of the GNU General
2380 : * Public License, but WITHOUT ANY WARRANTY; without even the implied
2381 : * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
2382 : * See the GNU General Public License for more details.
2383 : *
2384 : * Alternatively, you can license this software under a commercial
2385 : * license, as set out in <https://www.cesanta.com/license>.
2386 : */
2387 :
2388 : /* Amalgamated: #include "common/cs_time.h" */
2389 : /* Amalgamated: #include "mg_dns.h" */
2390 : /* Amalgamated: #include "mg_internal.h" */
2391 : /* Amalgamated: #include "mg_resolv.h" */
2392 : /* Amalgamated: #include "mg_util.h" */
2393 :
2394 : #define MG_MAX_HOST_LEN 200
2395 :
2396 : #ifndef MG_TCP_IO_SIZE
2397 : //#define MG_TCP_IO_SIZE 1460
2398 : #define MG_TCP_IO_SIZE 1460000
2399 : #endif
2400 : #ifndef MG_UDP_IO_SIZE
2401 : #define MG_UDP_IO_SIZE 1460
2402 : #endif
2403 :
2404 : #define MG_COPY_COMMON_CONNECTION_OPTIONS(dst, src) \
2405 : memcpy(dst, src, sizeof(*dst));
2406 :
2407 : /* Which flags can be pre-set by the user at connection creation time. */
2408 : #define _MG_ALLOWED_CONNECT_FLAGS_MASK \
2409 : (MG_F_USER_1 | MG_F_USER_2 | MG_F_USER_3 | MG_F_USER_4 | MG_F_USER_5 | \
2410 : MG_F_USER_6 | MG_F_WEBSOCKET_NO_DEFRAG | MG_F_ENABLE_BROADCAST)
2411 : /* Which flags should be modifiable by user's callbacks. */
2412 : #define _MG_CALLBACK_MODIFIABLE_FLAGS_MASK \
2413 : (MG_F_USER_1 | MG_F_USER_2 | MG_F_USER_3 | MG_F_USER_4 | MG_F_USER_5 | \
2414 : MG_F_USER_6 | MG_F_WEBSOCKET_NO_DEFRAG | MG_F_SEND_AND_CLOSE | \
2415 : MG_F_CLOSE_IMMEDIATELY | MG_F_IS_WEBSOCKET | MG_F_DELETE_CHUNK)
2416 :
2417 : #ifndef intptr_t
2418 : #define intptr_t long
2419 : #endif
2420 :
2421 0 : MG_INTERNAL void mg_add_conn(struct mg_mgr *mgr, struct mg_connection *c) {
2422 0 : DBG(("%p %p", mgr, c));
2423 0 : c->mgr = mgr;
2424 0 : c->next = mgr->active_connections;
2425 0 : mgr->active_connections = c;
2426 0 : c->prev = NULL;
2427 0 : if (c->next != NULL) c->next->prev = c;
2428 0 : if (c->sock != INVALID_SOCKET) {
2429 0 : c->iface->vtable->add_conn(c);
2430 : }
2431 0 : }
2432 :
2433 0 : MG_INTERNAL void mg_remove_conn(struct mg_connection *conn) {
2434 0 : if (conn->prev == NULL) conn->mgr->active_connections = conn->next;
2435 0 : if (conn->prev) conn->prev->next = conn->next;
2436 0 : if (conn->next) conn->next->prev = conn->prev;
2437 0 : conn->prev = conn->next = NULL;
2438 0 : conn->iface->vtable->remove_conn(conn);
2439 0 : }
2440 :
2441 0 : MG_INTERNAL void mg_call(struct mg_connection *nc,
2442 : mg_event_handler_t ev_handler, void *user_data, int ev,
2443 : void *ev_data) {
2444 0 : if (ev_handler == NULL) {
2445 : /*
2446 : * If protocol handler is specified, call it. Otherwise, call user-specified
2447 : * event handler.
2448 : */
2449 0 : ev_handler = nc->proto_handler ? nc->proto_handler : nc->handler;
2450 : }
2451 0 : if (ev != MG_EV_POLL) {
2452 0 : DBG(("%p %s ev=%d ev_data=%p flags=0x%lx rmbl=%d smbl=%d", nc,
2453 : ev_handler == nc->handler ? "user" : "proto", ev, ev_data, nc->flags,
2454 : (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
2455 : }
2456 :
2457 : #if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
2458 0 : if (nc->mgr->hexdump_file != NULL && ev != MG_EV_POLL && ev != MG_EV_RECV &&
2459 : ev != MG_EV_SEND /* handled separately */) {
2460 0 : mg_hexdump_connection(nc, nc->mgr->hexdump_file, NULL, 0, ev);
2461 : }
2462 : #endif
2463 0 : if (ev_handler != NULL) {
2464 0 : unsigned long flags_before = nc->flags;
2465 0 : ev_handler(nc, ev, ev_data MG_UD_ARG(user_data));
2466 : /* Prevent user handler from fiddling with system flags. */
2467 0 : if (ev_handler == nc->handler && nc->flags != flags_before) {
2468 0 : nc->flags = (flags_before & ~_MG_CALLBACK_MODIFIABLE_FLAGS_MASK) |
2469 0 : (nc->flags & _MG_CALLBACK_MODIFIABLE_FLAGS_MASK);
2470 : }
2471 : }
2472 0 : if (ev != MG_EV_POLL) nc->mgr->num_calls++;
2473 0 : if (ev != MG_EV_POLL) {
2474 0 : DBG(("%p after %s flags=0x%lx rmbl=%d smbl=%d", nc,
2475 : ev_handler == nc->handler ? "user" : "proto", nc->flags,
2476 : (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
2477 : }
2478 : #if !MG_ENABLE_CALLBACK_USERDATA
2479 : (void) user_data;
2480 : #endif
2481 0 : }
2482 :
2483 0 : MG_INTERNAL void mg_timer(struct mg_connection *c, double now) {
2484 0 : if (c->ev_timer_time > 0 && now >= c->ev_timer_time) {
2485 0 : double old_value = c->ev_timer_time;
2486 0 : c->ev_timer_time = 0;
2487 0 : mg_call(c, NULL, c->user_data, MG_EV_TIMER, &old_value);
2488 : }
2489 0 : }
2490 :
2491 0 : MG_INTERNAL size_t recv_avail_size(struct mg_connection *conn, size_t max) {
2492 : size_t avail;
2493 0 : if (conn->recv_mbuf_limit < conn->recv_mbuf.len) return 0;
2494 0 : avail = conn->recv_mbuf_limit - conn->recv_mbuf.len;
2495 0 : return avail > max ? max : avail;
2496 : }
2497 :
2498 : static int mg_do_recv(struct mg_connection *nc);
2499 :
2500 0 : int mg_if_poll(struct mg_connection *nc, double now) {
2501 0 : if (nc->flags & MG_F_CLOSE_IMMEDIATELY) {
2502 0 : mg_close_conn(nc);
2503 0 : return 0;
2504 0 : } else if (nc->flags & MG_F_SEND_AND_CLOSE) {
2505 0 : if (nc->send_mbuf.len == 0) {
2506 0 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
2507 0 : mg_close_conn(nc);
2508 0 : return 0;
2509 : }
2510 0 : } else if (nc->flags & MG_F_RECV_AND_CLOSE) {
2511 0 : mg_close_conn(nc);
2512 0 : return 0;
2513 : }
2514 : #if MG_ENABLE_SSL
2515 : if ((nc->flags & (MG_F_SSL | MG_F_LISTENING | MG_F_CONNECTING)) == MG_F_SSL) {
2516 : /* SSL library may have data to be delivered to the app in its buffers,
2517 : * drain them. */
2518 : int recved = 0;
2519 : do {
2520 : if (nc->flags & (MG_F_WANT_READ | MG_F_WANT_WRITE)) break;
2521 : if (recv_avail_size(nc, MG_TCP_IO_SIZE) <= 0) break;
2522 : recved = mg_do_recv(nc);
2523 : } while (recved > 0);
2524 : }
2525 : #endif /* MG_ENABLE_SSL */
2526 0 : mg_timer(nc, now);
2527 : {
2528 0 : time_t now_t = (time_t) now;
2529 0 : mg_call(nc, NULL, nc->user_data, MG_EV_POLL, &now_t);
2530 : }
2531 0 : return 1;
2532 : }
2533 :
2534 0 : void mg_destroy_conn(struct mg_connection *conn, int destroy_if) {
2535 0 : if (conn->sock != INVALID_SOCKET) { /* Don't print timer-only conns */
2536 0 : LOG(LL_DEBUG, ("%p 0x%lx %d", conn, conn->flags, destroy_if));
2537 : }
2538 0 : if (destroy_if) conn->iface->vtable->destroy_conn(conn);
2539 0 : if (conn->proto_data != NULL && conn->proto_data_destructor != NULL) {
2540 0 : conn->proto_data_destructor(conn->proto_data);
2541 : }
2542 : #if MG_ENABLE_SSL
2543 : mg_ssl_if_conn_free(conn);
2544 : #endif
2545 0 : mbuf_free(&conn->recv_mbuf);
2546 0 : mbuf_free(&conn->send_mbuf);
2547 :
2548 0 : memset(conn, 0, sizeof(*conn));
2549 0 : MG_FREE(conn);
2550 0 : }
2551 :
2552 0 : void mg_close_conn(struct mg_connection *conn) {
2553 : /* See if there's any remaining data to deliver. Skip if user completely
2554 : * throttled the connection there will be no progress anyway. */
2555 0 : if (conn->sock != INVALID_SOCKET && mg_do_recv(conn) == -2) {
2556 : /* Receive is throttled, wait. */
2557 0 : conn->flags |= MG_F_RECV_AND_CLOSE;
2558 0 : return;
2559 : }
2560 : #if MG_ENABLE_SSL
2561 : if (conn->flags & MG_F_SSL_HANDSHAKE_DONE) {
2562 : mg_ssl_if_conn_close_notify(conn);
2563 : }
2564 : #endif
2565 : /*
2566 : * Clearly mark the connection as going away (if not already).
2567 : * Some net_if impls (LwIP) need this for cleanly handling half-dead conns.
2568 : */
2569 0 : conn->flags |= MG_F_CLOSE_IMMEDIATELY;
2570 0 : mg_remove_conn(conn);
2571 0 : conn->iface->vtable->destroy_conn(conn);
2572 0 : mg_call(conn, NULL, conn->user_data, MG_EV_CLOSE, NULL);
2573 0 : mg_destroy_conn(conn, 0 /* destroy_if */);
2574 : }
2575 :
2576 0 : void mg_mgr_init(struct mg_mgr *m, void *user_data) {
2577 : struct mg_mgr_init_opts opts;
2578 0 : memset(&opts, 0, sizeof(opts));
2579 0 : mg_mgr_init_opt(m, user_data, opts);
2580 0 : }
2581 :
2582 0 : void mg_mgr_init_opt(struct mg_mgr *m, void *user_data,
2583 : struct mg_mgr_init_opts opts) {
2584 0 : memset(m, 0, sizeof(*m));
2585 : #if MG_ENABLE_BROADCAST
2586 0 : m->ctl[0] = m->ctl[1] = INVALID_SOCKET;
2587 : #endif
2588 0 : m->user_data = user_data;
2589 :
2590 : #ifdef _WIN32
2591 : {
2592 : WSADATA data;
2593 : WSAStartup(MAKEWORD(2, 2), &data);
2594 : }
2595 : #elif defined(__unix__)
2596 : /* Ignore SIGPIPE signal, so if client cancels the request, it
2597 : * won't kill the whole process. */
2598 0 : signal(SIGPIPE, SIG_IGN);
2599 : #endif
2600 :
2601 : {
2602 : int i;
2603 0 : if (opts.num_ifaces == 0) {
2604 0 : opts.num_ifaces = mg_num_ifaces;
2605 0 : opts.ifaces = mg_ifaces;
2606 : }
2607 0 : if (opts.main_iface != NULL) {
2608 0 : opts.ifaces[MG_MAIN_IFACE] = opts.main_iface;
2609 : }
2610 0 : m->num_ifaces = opts.num_ifaces;
2611 0 : m->ifaces =
2612 0 : (struct mg_iface **) MG_MALLOC(sizeof(*m->ifaces) * opts.num_ifaces);
2613 0 : for (i = 0; i < opts.num_ifaces; i++) {
2614 0 : m->ifaces[i] = mg_if_create_iface(opts.ifaces[i], m);
2615 0 : m->ifaces[i]->vtable->init(m->ifaces[i]);
2616 : }
2617 : }
2618 0 : if (opts.nameserver != NULL) {
2619 0 : m->nameserver = strdup(opts.nameserver);
2620 : }
2621 0 : DBG(("=================================="));
2622 0 : DBG(("init mgr=%p", m));
2623 : #if MG_ENABLE_SSL
2624 : {
2625 : static int init_done;
2626 : if (!init_done) {
2627 : mg_ssl_if_init();
2628 : init_done++;
2629 : }
2630 : }
2631 : #endif
2632 0 : }
2633 :
2634 0 : void mg_mgr_free(struct mg_mgr *m) {
2635 : struct mg_connection *conn, *tmp_conn;
2636 :
2637 0 : DBG(("%p", m));
2638 0 : if (m == NULL) return;
2639 : /* Do one last poll, see https://github.com/cesanta/mongoose/issues/286 */
2640 0 : mg_mgr_poll(m, 0);
2641 :
2642 : #if MG_ENABLE_BROADCAST
2643 0 : if (m->ctl[0] != INVALID_SOCKET) closesocket(m->ctl[0]);
2644 0 : if (m->ctl[1] != INVALID_SOCKET) closesocket(m->ctl[1]);
2645 0 : m->ctl[0] = m->ctl[1] = INVALID_SOCKET;
2646 : #endif
2647 :
2648 0 : for (conn = m->active_connections; conn != NULL; conn = tmp_conn) {
2649 0 : tmp_conn = conn->next;
2650 0 : conn->flags |= MG_F_CLOSE_IMMEDIATELY;
2651 0 : mg_close_conn(conn);
2652 : }
2653 :
2654 : {
2655 : int i;
2656 0 : for (i = 0; i < m->num_ifaces; i++) {
2657 0 : m->ifaces[i]->vtable->free(m->ifaces[i]);
2658 0 : MG_FREE(m->ifaces[i]);
2659 : }
2660 0 : MG_FREE(m->ifaces);
2661 : }
2662 :
2663 0 : MG_FREE((char *) m->nameserver);
2664 : }
2665 :
2666 0 : int mg_mgr_poll(struct mg_mgr *m, int timeout_ms) {
2667 0 : int i, num_calls_before = m->num_calls;
2668 :
2669 0 : for (i = 0; i < m->num_ifaces; i++) {
2670 0 : m->ifaces[i]->vtable->poll(m->ifaces[i], timeout_ms);
2671 : }
2672 :
2673 0 : return (m->num_calls - num_calls_before);
2674 : }
2675 :
2676 0 : int mg_vprintf(struct mg_connection *nc, const char *fmt, va_list ap) {
2677 0 : char mem[MG_VPRINTF_BUFFER_SIZE], *buf = mem;
2678 : int len;
2679 :
2680 0 : if ((len = mg_avprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
2681 0 : mg_send(nc, buf, len);
2682 : }
2683 0 : if (buf != mem && buf != NULL) {
2684 : MG_FREE(buf); /* LCOV_EXCL_LINE */
2685 : } /* LCOV_EXCL_LINE */
2686 :
2687 0 : return len;
2688 : }
2689 :
2690 0 : int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
2691 : int len;
2692 : va_list ap;
2693 0 : va_start(ap, fmt);
2694 0 : len = mg_vprintf(conn, fmt, ap);
2695 0 : va_end(ap);
2696 0 : return len;
2697 : }
2698 :
2699 : #if MG_ENABLE_SYNC_RESOLVER
2700 : /* TODO(lsm): use non-blocking resolver */
2701 : static int mg_resolve2(const char *host, struct in_addr *ina) {
2702 : #if MG_ENABLE_GETADDRINFO
2703 : int rv = 0;
2704 : struct addrinfo hints, *servinfo, *p;
2705 : struct sockaddr_in *h = NULL;
2706 : memset(&hints, 0, sizeof hints);
2707 : hints.ai_family = AF_INET;
2708 : hints.ai_socktype = SOCK_STREAM;
2709 : if ((rv = getaddrinfo(host, NULL, NULL, &servinfo)) != 0) {
2710 : DBG(("getaddrinfo(%s) failed: %s", host, strerror(mg_get_errno())));
2711 : return 0;
2712 : }
2713 : for (p = servinfo; p != NULL; p = p->ai_next) {
2714 : memcpy(&h, &p->ai_addr, sizeof(h));
2715 : memcpy(ina, &h->sin_addr, sizeof(*ina));
2716 : }
2717 : freeaddrinfo(servinfo);
2718 : return 1;
2719 : #else
2720 : struct hostent *he;
2721 : if ((he = gethostbyname(host)) == NULL) {
2722 : DBG(("gethostbyname(%s) failed: %s", host, strerror(mg_get_errno())));
2723 : } else {
2724 : memcpy(ina, he->h_addr_list[0], sizeof(*ina));
2725 : return 1;
2726 : }
2727 : return 0;
2728 : #endif /* MG_ENABLE_GETADDRINFO */
2729 : }
2730 :
2731 : int mg_resolve(const char *host, char *buf, size_t n) {
2732 : struct in_addr ad;
2733 : return mg_resolve2(host, &ad) ? snprintf(buf, n, "%s", inet_ntoa(ad)) : 0;
2734 : }
2735 : #endif /* MG_ENABLE_SYNC_RESOLVER */
2736 :
2737 0 : MG_INTERNAL struct mg_connection *mg_create_connection_base(
2738 : struct mg_mgr *mgr, mg_event_handler_t callback,
2739 : struct mg_add_sock_opts opts) {
2740 : struct mg_connection *conn;
2741 :
2742 0 : if ((conn = (struct mg_connection *) MG_CALLOC(1, sizeof(*conn))) != NULL) {
2743 0 : conn->sock = INVALID_SOCKET;
2744 0 : conn->handler = callback;
2745 0 : conn->mgr = mgr;
2746 0 : conn->last_io_time = (time_t) mg_time();
2747 0 : conn->iface =
2748 0 : (opts.iface != NULL ? opts.iface : mgr->ifaces[MG_MAIN_IFACE]);
2749 0 : conn->flags = opts.flags & _MG_ALLOWED_CONNECT_FLAGS_MASK;
2750 0 : conn->user_data = opts.user_data;
2751 : /*
2752 : * SIZE_MAX is defined as a long long constant in
2753 : * system headers on some platforms and so it
2754 : * doesn't compile with pedantic ansi flags.
2755 : */
2756 0 : conn->recv_mbuf_limit = ~0;
2757 : } else {
2758 0 : MG_SET_PTRPTR(opts.error_string, "failed to create connection");
2759 : }
2760 :
2761 0 : return conn;
2762 : }
2763 :
2764 0 : MG_INTERNAL struct mg_connection *mg_create_connection(
2765 : struct mg_mgr *mgr, mg_event_handler_t callback,
2766 : struct mg_add_sock_opts opts) {
2767 0 : struct mg_connection *conn = mg_create_connection_base(mgr, callback, opts);
2768 :
2769 0 : if (conn != NULL && !conn->iface->vtable->create_conn(conn)) {
2770 0 : MG_FREE(conn);
2771 0 : conn = NULL;
2772 : }
2773 0 : if (conn == NULL) {
2774 0 : MG_SET_PTRPTR(opts.error_string, "failed to init connection");
2775 : }
2776 :
2777 0 : return conn;
2778 : }
2779 :
2780 : /*
2781 : * Address format: [PROTO://][HOST]:PORT
2782 : *
2783 : * HOST could be IPv4/IPv6 address or a host name.
2784 : * `host` is a destination buffer to hold parsed HOST part. Should be at least
2785 : * MG_MAX_HOST_LEN bytes long.
2786 : * `proto` is a returned socket type, either SOCK_STREAM or SOCK_DGRAM
2787 : *
2788 : * Return:
2789 : * -1 on parse error
2790 : * 0 if HOST needs DNS lookup
2791 : * >0 length of the address string
2792 : */
2793 0 : MG_INTERNAL int mg_parse_address(const char *str, union socket_address *sa,
2794 : int *proto, char *host, size_t host_len) {
2795 0 : unsigned int a, b, c, d, port = 0;
2796 0 : int ch, len = 0;
2797 : #if MG_ENABLE_IPV6
2798 : char buf[100];
2799 : #endif
2800 :
2801 : /*
2802 : * MacOS needs that. If we do not zero it, subsequent bind() will fail.
2803 : * Also, all-zeroes in the socket address means binding to all addresses
2804 : * for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT).
2805 : */
2806 0 : memset(sa, 0, sizeof(*sa));
2807 0 : sa->sin.sin_family = AF_INET;
2808 :
2809 0 : *proto = SOCK_STREAM;
2810 :
2811 0 : if (strncmp(str, "udp://", 6) == 0) {
2812 0 : str += 6;
2813 0 : *proto = SOCK_DGRAM;
2814 0 : } else if (strncmp(str, "tcp://", 6) == 0) {
2815 0 : str += 6;
2816 : }
2817 :
2818 0 : if (sscanf(str, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len) == 5) {
2819 : /* Bind to a specific IPv4 address, e.g. 192.168.1.5:8080 */
2820 0 : sa->sin.sin_addr.s_addr =
2821 0 : htonl(((uint32_t) a << 24) | ((uint32_t) b << 16) | c << 8 | d);
2822 0 : sa->sin.sin_port = htons((uint16_t) port);
2823 : #if MG_ENABLE_IPV6
2824 0 : } else if (sscanf(str, "[%99[^]]]:%u%n", buf, &port, &len) == 2 &&
2825 0 : inet_pton(AF_INET6, buf, &sa->sin6.sin6_addr)) {
2826 : /* IPv6 address, e.g. [3ffe:2a00:100:7031::1]:8080 */
2827 0 : sa->sin6.sin6_family = AF_INET6;
2828 0 : sa->sin.sin_port = htons((uint16_t) port);
2829 : #endif
2830 : #if MG_ENABLE_ASYNC_RESOLVER
2831 0 : } else if (strlen(str) < host_len &&
2832 0 : sscanf(str, "%[^ :]:%u%n", host, &port, &len) == 2) {
2833 0 : sa->sin.sin_port = htons((uint16_t) port);
2834 0 : if (mg_resolve_from_hosts_file(host, sa) != 0) {
2835 : /*
2836 : * if resolving from hosts file failed and the host
2837 : * we are trying to resolve is `localhost` - we should
2838 : * try to resolve it using `gethostbyname` and do not try
2839 : * to resolve it via DNS server if gethostbyname has failed too
2840 : */
2841 0 : if (mg_ncasecmp(host, "localhost", 9) != 0) {
2842 0 : return 0;
2843 : }
2844 :
2845 : #if MG_ENABLE_SYNC_RESOLVER
2846 : if (!mg_resolve2(host, &sa->sin.sin_addr)) {
2847 : return -1;
2848 : }
2849 : #else
2850 0 : return -1;
2851 : #endif
2852 : }
2853 : #endif
2854 0 : } else if (sscanf(str, ":%u%n", &port, &len) == 1 ||
2855 0 : sscanf(str, "%u%n", &port, &len) == 1) {
2856 : /* If only port is specified, bind to IPv4, INADDR_ANY */
2857 0 : sa->sin.sin_port = htons((uint16_t) port);
2858 : } else {
2859 0 : return -1;
2860 : }
2861 :
2862 : /* Required for MG_ENABLE_ASYNC_RESOLVER=0 */
2863 : (void) host;
2864 : (void) host_len;
2865 :
2866 0 : ch = str[len]; /* Character that follows the address */
2867 0 : return port < 0xffffUL && (ch == '\0' || ch == ',' || isspace(ch)) ? len : -1;
2868 : }
2869 :
2870 : #if MG_ENABLE_SSL
2871 : MG_INTERNAL void mg_ssl_handshake(struct mg_connection *nc) {
2872 : int err = 0;
2873 : int server_side = (nc->listener != NULL);
2874 : enum mg_ssl_if_result res;
2875 : if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) return;
2876 : res = mg_ssl_if_handshake(nc);
2877 :
2878 : if (res == MG_SSL_OK) {
2879 : nc->flags |= MG_F_SSL_HANDSHAKE_DONE;
2880 : nc->flags &= ~(MG_F_WANT_READ | MG_F_WANT_WRITE);
2881 : if (server_side) {
2882 : mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
2883 : } else {
2884 : mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err);
2885 : }
2886 : } else if (res == MG_SSL_WANT_READ) {
2887 : nc->flags |= MG_F_WANT_READ;
2888 : } else if (res == MG_SSL_WANT_WRITE) {
2889 : nc->flags |= MG_F_WANT_WRITE;
2890 : } else {
2891 : if (!server_side) {
2892 : err = res;
2893 : mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err);
2894 : }
2895 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
2896 : }
2897 : }
2898 : #endif /* MG_ENABLE_SSL */
2899 :
2900 0 : struct mg_connection *mg_if_accept_new_conn(struct mg_connection *lc) {
2901 : struct mg_add_sock_opts opts;
2902 : struct mg_connection *nc;
2903 0 : memset(&opts, 0, sizeof(opts));
2904 0 : nc = mg_create_connection(lc->mgr, lc->handler, opts);
2905 0 : if (nc == NULL) return NULL;
2906 0 : nc->listener = lc;
2907 0 : nc->proto_handler = lc->proto_handler;
2908 0 : nc->user_data = lc->user_data;
2909 0 : nc->recv_mbuf_limit = lc->recv_mbuf_limit;
2910 0 : nc->iface = lc->iface;
2911 0 : if (lc->flags & MG_F_SSL) nc->flags |= MG_F_SSL;
2912 0 : mg_add_conn(nc->mgr, nc);
2913 0 : LOG(LL_DEBUG, ("%p %p %d %d", lc, nc, nc->sock, (int) nc->flags));
2914 0 : return nc;
2915 : }
2916 :
2917 0 : void mg_if_accept_tcp_cb(struct mg_connection *nc, union socket_address *sa,
2918 : size_t sa_len) {
2919 0 : LOG(LL_DEBUG, ("%p %s://%s:%hu", nc, (nc->flags & MG_F_UDP ? "udp" : "tcp"),
2920 : inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port)));
2921 0 : nc->sa = *sa;
2922 : #if MG_ENABLE_SSL
2923 : if (nc->listener->flags & MG_F_SSL) {
2924 : nc->flags |= MG_F_SSL;
2925 : if (mg_ssl_if_conn_accept(nc, nc->listener) == MG_SSL_OK) {
2926 : mg_ssl_handshake(nc);
2927 : } else {
2928 : mg_close_conn(nc);
2929 : }
2930 : } else
2931 : #endif
2932 : {
2933 0 : mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
2934 : }
2935 : (void) sa_len;
2936 0 : }
2937 :
2938 0 : void mg_send(struct mg_connection *nc, const void *buf, int len) {
2939 0 : nc->last_io_time = (time_t) mg_time();
2940 0 : mbuf_append(&nc->send_mbuf, buf, len);
2941 0 : }
2942 :
2943 : static int mg_recv_tcp(struct mg_connection *nc, char *buf, size_t len);
2944 : static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len);
2945 :
2946 0 : static int mg_do_recv(struct mg_connection *nc) {
2947 0 : int res = 0;
2948 0 : char *buf = NULL;
2949 0 : size_t len = (nc->flags & MG_F_UDP ? MG_UDP_IO_SIZE : MG_TCP_IO_SIZE);
2950 0 : if ((nc->flags & (MG_F_CLOSE_IMMEDIATELY | MG_F_CONNECTING)) ||
2951 0 : ((nc->flags & MG_F_LISTENING) && !(nc->flags & MG_F_UDP))) {
2952 0 : return -1;
2953 : }
2954 : do {
2955 0 : len = recv_avail_size(nc, len);
2956 0 : if (len == 0) {
2957 0 : res = -2;
2958 0 : break;
2959 : }
2960 0 : if (nc->recv_mbuf.size < nc->recv_mbuf.len + len) {
2961 0 : mbuf_resize(&nc->recv_mbuf, nc->recv_mbuf.len + len);
2962 : }
2963 0 : buf = nc->recv_mbuf.buf + nc->recv_mbuf.len;
2964 0 : len = nc->recv_mbuf.size - nc->recv_mbuf.len;
2965 0 : if (nc->flags & MG_F_UDP) {
2966 0 : res = mg_recv_udp(nc, buf, len);
2967 : } else {
2968 0 : res = mg_recv_tcp(nc, buf, len);
2969 : }
2970 0 : } while (res > 0 && !(nc->flags & (MG_F_CLOSE_IMMEDIATELY | MG_F_UDP)));
2971 0 : return res;
2972 : }
2973 :
2974 0 : void mg_if_can_recv_cb(struct mg_connection *nc) {
2975 0 : mg_do_recv(nc);
2976 0 : }
2977 :
2978 0 : static int mg_recv_tcp(struct mg_connection *nc, char *buf, size_t len) {
2979 0 : int n = 0;
2980 : #if MG_ENABLE_SSL
2981 : if (nc->flags & MG_F_SSL) {
2982 : if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
2983 : n = mg_ssl_if_read(nc, buf, len);
2984 : DBG(("%p <- %d bytes (SSL)", nc, n));
2985 : if (n < 0) {
2986 : if (n == MG_SSL_WANT_READ) {
2987 : nc->flags |= MG_F_WANT_READ;
2988 : n = 0;
2989 : } else {
2990 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
2991 : }
2992 : } else if (n > 0) {
2993 : nc->flags &= ~MG_F_WANT_READ;
2994 : }
2995 : } else {
2996 : mg_ssl_handshake(nc);
2997 : }
2998 : } else
2999 : #endif
3000 : {
3001 0 : n = nc->iface->vtable->tcp_recv(nc, buf, len);
3002 0 : DBG(("%p <- %d bytes", nc, n));
3003 : }
3004 0 : if (n > 0) {
3005 0 : nc->recv_mbuf.len += n;
3006 0 : nc->last_io_time = (time_t) mg_time();
3007 : #if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
3008 0 : if (nc->mgr && nc->mgr->hexdump_file != NULL) {
3009 0 : mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV);
3010 : }
3011 : #endif
3012 0 : mbuf_trim(&nc->recv_mbuf);
3013 0 : mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n);
3014 0 : } else if (n < 0) {
3015 0 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
3016 : }
3017 0 : mbuf_trim(&nc->recv_mbuf);
3018 0 : return n;
3019 : }
3020 :
3021 0 : static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len) {
3022 0 : int n = 0;
3023 0 : struct mg_connection *lc = nc;
3024 : union socket_address sa;
3025 0 : size_t sa_len = sizeof(sa);
3026 0 : n = nc->iface->vtable->udp_recv(lc, buf, len, &sa, &sa_len);
3027 0 : if (n < 0) {
3028 0 : lc->flags |= MG_F_CLOSE_IMMEDIATELY;
3029 0 : goto out;
3030 : }
3031 0 : if (nc->flags & MG_F_LISTENING) {
3032 : /*
3033 : * Do we have an existing connection for this source?
3034 : * This is very inefficient for long connection lists.
3035 : */
3036 0 : lc = nc;
3037 0 : for (nc = mg_next(lc->mgr, NULL); nc != NULL; nc = mg_next(lc->mgr, nc)) {
3038 0 : if (memcmp(&nc->sa.sa, &sa.sa, sa_len) == 0 && nc->listener == lc) {
3039 0 : break;
3040 : }
3041 : }
3042 0 : if (nc == NULL) {
3043 : struct mg_add_sock_opts opts;
3044 0 : memset(&opts, 0, sizeof(opts));
3045 : /* Create fake connection w/out sock initialization */
3046 0 : nc = mg_create_connection_base(lc->mgr, lc->handler, opts);
3047 0 : if (nc != NULL) {
3048 0 : nc->sock = lc->sock;
3049 0 : nc->listener = lc;
3050 0 : nc->sa = sa;
3051 0 : nc->proto_handler = lc->proto_handler;
3052 0 : nc->user_data = lc->user_data;
3053 0 : nc->recv_mbuf_limit = lc->recv_mbuf_limit;
3054 0 : nc->flags = MG_F_UDP;
3055 : /*
3056 : * Long-lived UDP "connections" i.e. interactions that involve more
3057 : * than one request and response are rare, most are transactional:
3058 : * response is sent and the "connection" is closed. Or - should be.
3059 : * But users (including ourselves) tend to forget about that part,
3060 : * because UDP is connectionless and one does not think about
3061 : * processing a UDP request as handling a connection that needs to be
3062 : * closed. Thus, we begin with SEND_AND_CLOSE flag set, which should
3063 : * be a reasonable default for most use cases, but it is possible to
3064 : * turn it off the connection should be kept alive after processing.
3065 : */
3066 0 : nc->flags |= MG_F_SEND_AND_CLOSE;
3067 0 : mg_add_conn(lc->mgr, nc);
3068 0 : mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
3069 : }
3070 : }
3071 : }
3072 0 : if (nc != NULL) {
3073 0 : DBG(("%p <- %d bytes from %s:%d", nc, n, inet_ntoa(nc->sa.sin.sin_addr),
3074 : ntohs(nc->sa.sin.sin_port)));
3075 0 : if (nc == lc) {
3076 0 : nc->recv_mbuf.len += n;
3077 : } else {
3078 0 : mbuf_append(&nc->recv_mbuf, buf, n);
3079 : }
3080 0 : mbuf_trim(&lc->recv_mbuf);
3081 0 : lc->last_io_time = nc->last_io_time = (time_t) mg_time();
3082 : #if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
3083 0 : if (nc->mgr && nc->mgr->hexdump_file != NULL) {
3084 0 : mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV);
3085 : }
3086 : #endif
3087 0 : if (n != 0) {
3088 0 : mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n);
3089 : }
3090 : }
3091 :
3092 0 : out:
3093 0 : mbuf_free(&lc->recv_mbuf);
3094 0 : return n;
3095 : }
3096 :
3097 0 : void mg_if_can_send_cb(struct mg_connection *nc) {
3098 0 : int n = 0;
3099 0 : const char *buf = nc->send_mbuf.buf;
3100 0 : size_t len = nc->send_mbuf.len;
3101 :
3102 0 : if (nc->flags & (MG_F_CLOSE_IMMEDIATELY | MG_F_CONNECTING)) {
3103 0 : return;
3104 : }
3105 0 : if (!(nc->flags & MG_F_UDP)) {
3106 0 : if (nc->flags & MG_F_LISTENING) return;
3107 0 : if (len > MG_TCP_IO_SIZE) len = MG_TCP_IO_SIZE;
3108 : }
3109 : #if MG_ENABLE_SSL
3110 : if (nc->flags & MG_F_SSL) {
3111 : if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
3112 : if (len > 0) {
3113 : n = mg_ssl_if_write(nc, buf, len);
3114 : DBG(("%p -> %d bytes (SSL)", nc, n));
3115 : }
3116 : if (n < 0) {
3117 : if (n == MG_SSL_WANT_WRITE) {
3118 : nc->flags |= MG_F_WANT_WRITE;
3119 : n = 0;
3120 : } else {
3121 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
3122 : }
3123 : } else {
3124 : nc->flags &= ~MG_F_WANT_WRITE;
3125 : }
3126 : } else {
3127 : mg_ssl_handshake(nc);
3128 : }
3129 : } else
3130 : #endif
3131 0 : if (len > 0) {
3132 0 : if (nc->flags & MG_F_UDP) {
3133 0 : n = nc->iface->vtable->udp_send(nc, buf, len);
3134 : } else {
3135 0 : n = nc->iface->vtable->tcp_send(nc, buf, len);
3136 : }
3137 0 : DBG(("%p -> %d bytes", nc, n));
3138 : }
3139 :
3140 : #if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
3141 0 : if (n > 0 && nc->mgr && nc->mgr->hexdump_file != NULL) {
3142 0 : mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_SEND);
3143 : }
3144 : #endif
3145 0 : if (n < 0) {
3146 0 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
3147 0 : } else if (n > 0) {
3148 0 : nc->last_io_time = (time_t) mg_time();
3149 0 : mbuf_remove(&nc->send_mbuf, n);
3150 0 : mbuf_trim(&nc->send_mbuf);
3151 : }
3152 0 : if (n != 0) mg_call(nc, NULL, nc->user_data, MG_EV_SEND, &n);
3153 : }
3154 :
3155 : /*
3156 : * Schedules an async connect for a resolved address and proto.
3157 : * Called from two places: `mg_connect_opt()` and from async resolver.
3158 : * When called from the async resolver, it must trigger `MG_EV_CONNECT` event
3159 : * with a failure flag to indicate connection failure.
3160 : */
3161 0 : MG_INTERNAL struct mg_connection *mg_do_connect(struct mg_connection *nc,
3162 : int proto,
3163 : union socket_address *sa) {
3164 0 : LOG(LL_DEBUG, ("%p %s://%s:%hu", nc, proto == SOCK_DGRAM ? "udp" : "tcp",
3165 : inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port)));
3166 :
3167 0 : nc->flags |= MG_F_CONNECTING;
3168 0 : if (proto == SOCK_DGRAM) {
3169 0 : nc->iface->vtable->connect_udp(nc);
3170 : } else {
3171 0 : nc->iface->vtable->connect_tcp(nc, sa);
3172 : }
3173 0 : mg_add_conn(nc->mgr, nc);
3174 0 : return nc;
3175 : }
3176 :
3177 0 : void mg_if_connect_cb(struct mg_connection *nc, int err) {
3178 0 : LOG(LL_DEBUG,
3179 : ("%p %s://%s:%hu -> %d", nc, (nc->flags & MG_F_UDP ? "udp" : "tcp"),
3180 : inet_ntoa(nc->sa.sin.sin_addr), ntohs(nc->sa.sin.sin_port), err));
3181 0 : nc->flags &= ~MG_F_CONNECTING;
3182 0 : if (err != 0) {
3183 0 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
3184 : }
3185 : #if MG_ENABLE_SSL
3186 : if (err == 0 && (nc->flags & MG_F_SSL)) {
3187 : mg_ssl_handshake(nc);
3188 : } else
3189 : #endif
3190 : {
3191 0 : mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err);
3192 : }
3193 0 : }
3194 :
3195 : #if MG_ENABLE_ASYNC_RESOLVER
3196 : /*
3197 : * Callback for the async resolver on mg_connect_opt() call.
3198 : * Main task of this function is to trigger MG_EV_CONNECT event with
3199 : * either failure (and dealloc the connection)
3200 : * or success (and proceed with connect()
3201 : */
3202 0 : static void resolve_cb(struct mg_dns_message *msg, void *data,
3203 : enum mg_resolve_err e) {
3204 0 : struct mg_connection *nc = (struct mg_connection *) data;
3205 : int i;
3206 0 : int failure = -1;
3207 :
3208 0 : nc->flags &= ~MG_F_RESOLVING;
3209 0 : if (msg != NULL) {
3210 : /*
3211 : * Take the first DNS A answer and run...
3212 : */
3213 0 : for (i = 0; i < msg->num_answers; i++) {
3214 0 : if (msg->answers[i].rtype == MG_DNS_A_RECORD) {
3215 : /*
3216 : * Async resolver guarantees that there is at least one answer.
3217 : * TODO(lsm): handle IPv6 answers too
3218 : */
3219 0 : mg_dns_parse_record_data(msg, &msg->answers[i], &nc->sa.sin.sin_addr,
3220 : 4);
3221 0 : mg_do_connect(nc, nc->flags & MG_F_UDP ? SOCK_DGRAM : SOCK_STREAM,
3222 : &nc->sa);
3223 0 : return;
3224 : }
3225 : }
3226 : }
3227 :
3228 0 : if (e == MG_RESOLVE_TIMEOUT) {
3229 0 : double now = mg_time();
3230 0 : mg_call(nc, NULL, nc->user_data, MG_EV_TIMER, &now);
3231 : }
3232 :
3233 : /*
3234 : * If we get there was no MG_DNS_A_RECORD in the answer
3235 : */
3236 0 : mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &failure);
3237 0 : mg_call(nc, NULL, nc->user_data, MG_EV_CLOSE, NULL);
3238 0 : mg_destroy_conn(nc, 1 /* destroy_if */);
3239 : }
3240 : #endif
3241 :
3242 0 : struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *address,
3243 : MG_CB(mg_event_handler_t callback,
3244 : void *user_data)) {
3245 : struct mg_connect_opts opts;
3246 0 : memset(&opts, 0, sizeof(opts));
3247 0 : return mg_connect_opt(mgr, address, MG_CB(callback, user_data), opts);
3248 : }
3249 :
3250 0 : void mg_ev_handler_empty(struct mg_connection *c, int ev,
3251 : void *ev_data MG_UD_ARG(void *user_data)) {
3252 : (void) c;
3253 : (void) ev;
3254 : (void) ev_data;
3255 : #if MG_ENABLE_CALLBACK_USERDATA
3256 : (void) user_data;
3257 : #endif
3258 0 : }
3259 :
3260 0 : struct mg_connection *mg_connect_opt(struct mg_mgr *mgr, const char *address,
3261 : MG_CB(mg_event_handler_t callback,
3262 : void *user_data),
3263 : struct mg_connect_opts opts) {
3264 0 : struct mg_connection *nc = NULL;
3265 : int proto, rc;
3266 : struct mg_add_sock_opts add_sock_opts;
3267 : char host[MG_MAX_HOST_LEN];
3268 :
3269 0 : MG_COPY_COMMON_CONNECTION_OPTIONS(&add_sock_opts, &opts);
3270 :
3271 0 : if (callback == NULL) callback = mg_ev_handler_empty;
3272 :
3273 0 : if ((nc = mg_create_connection(mgr, callback, add_sock_opts)) == NULL) {
3274 0 : return NULL;
3275 : }
3276 :
3277 0 : if ((rc = mg_parse_address(address, &nc->sa, &proto, host, sizeof(host))) <
3278 : 0) {
3279 : /* Address is malformed */
3280 0 : MG_SET_PTRPTR(opts.error_string, "cannot parse address");
3281 0 : mg_destroy_conn(nc, 1 /* destroy_if */);
3282 0 : return NULL;
3283 : }
3284 :
3285 0 : nc->flags |= opts.flags & _MG_ALLOWED_CONNECT_FLAGS_MASK;
3286 0 : nc->flags |= (proto == SOCK_DGRAM) ? MG_F_UDP : 0;
3287 : #if MG_ENABLE_CALLBACK_USERDATA
3288 : nc->user_data = user_data;
3289 : #else
3290 0 : nc->user_data = opts.user_data;
3291 : #endif
3292 :
3293 : #if MG_ENABLE_SSL
3294 : LOG(LL_DEBUG,
3295 : ("%p %s %s,%s,%s", nc, address, (opts.ssl_cert ? opts.ssl_cert : "-"),
3296 : (opts.ssl_key ? opts.ssl_key : "-"),
3297 : (opts.ssl_ca_cert ? opts.ssl_ca_cert : "-")));
3298 :
3299 : if (opts.ssl_cert != NULL || opts.ssl_ca_cert != NULL ||
3300 : opts.ssl_psk_identity != NULL) {
3301 : const char *err_msg = NULL;
3302 : struct mg_ssl_if_conn_params params;
3303 : if (nc->flags & MG_F_UDP) {
3304 : MG_SET_PTRPTR(opts.error_string, "SSL for UDP is not supported");
3305 : mg_destroy_conn(nc, 1 /* destroy_if */);
3306 : return NULL;
3307 : }
3308 : memset(¶ms, 0, sizeof(params));
3309 : params.cert = opts.ssl_cert;
3310 : params.key = opts.ssl_key;
3311 : params.ca_cert = opts.ssl_ca_cert;
3312 : params.cipher_suites = opts.ssl_cipher_suites;
3313 : params.psk_identity = opts.ssl_psk_identity;
3314 : params.psk_key = opts.ssl_psk_key;
3315 : if (opts.ssl_ca_cert != NULL) {
3316 : if (opts.ssl_server_name != NULL) {
3317 : if (strcmp(opts.ssl_server_name, "*") != 0) {
3318 : params.server_name = opts.ssl_server_name;
3319 : }
3320 : } else if (rc == 0) { /* If it's a DNS name, use host. */
3321 : params.server_name = host;
3322 : }
3323 : }
3324 : if (mg_ssl_if_conn_init(nc, ¶ms, &err_msg) != MG_SSL_OK) {
3325 : MG_SET_PTRPTR(opts.error_string, err_msg);
3326 : mg_destroy_conn(nc, 1 /* destroy_if */);
3327 : return NULL;
3328 : }
3329 : nc->flags |= MG_F_SSL;
3330 : }
3331 : #endif /* MG_ENABLE_SSL */
3332 :
3333 0 : if (rc == 0) {
3334 : #if MG_ENABLE_ASYNC_RESOLVER
3335 : /*
3336 : * DNS resolution is required for host.
3337 : * mg_parse_address() fills port in nc->sa, which we pass to resolve_cb()
3338 : */
3339 0 : struct mg_connection *dns_conn = NULL;
3340 : struct mg_resolve_async_opts o;
3341 0 : memset(&o, 0, sizeof(o));
3342 0 : o.dns_conn = &dns_conn;
3343 0 : o.nameserver = opts.nameserver;
3344 0 : if (mg_resolve_async_opt(nc->mgr, host, MG_DNS_A_RECORD, resolve_cb, nc,
3345 0 : o) != 0) {
3346 0 : MG_SET_PTRPTR(opts.error_string, "cannot schedule DNS lookup");
3347 0 : mg_destroy_conn(nc, 1 /* destroy_if */);
3348 0 : return NULL;
3349 : }
3350 0 : nc->priv_2 = dns_conn;
3351 0 : nc->flags |= MG_F_RESOLVING;
3352 0 : return nc;
3353 : #else
3354 : MG_SET_PTRPTR(opts.error_string, "Resolver is disabled");
3355 : mg_destroy_conn(nc, 1 /* destroy_if */);
3356 : return NULL;
3357 : #endif
3358 : } else {
3359 : /* Address is parsed and resolved to IP. proceed with connect() */
3360 0 : return mg_do_connect(nc, proto, &nc->sa);
3361 : }
3362 : }
3363 :
3364 0 : struct mg_connection *mg_bind(struct mg_mgr *srv, const char *address,
3365 : MG_CB(mg_event_handler_t event_handler,
3366 : void *user_data)) {
3367 : struct mg_bind_opts opts;
3368 0 : memset(&opts, 0, sizeof(opts));
3369 0 : return mg_bind_opt(srv, address, MG_CB(event_handler, user_data), opts);
3370 : }
3371 :
3372 0 : struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address,
3373 : MG_CB(mg_event_handler_t callback,
3374 : void *user_data),
3375 : struct mg_bind_opts opts) {
3376 : union socket_address sa;
3377 0 : struct mg_connection *nc = NULL;
3378 : int proto, rc;
3379 : struct mg_add_sock_opts add_sock_opts;
3380 : char host[MG_MAX_HOST_LEN];
3381 :
3382 : #if MG_ENABLE_CALLBACK_USERDATA
3383 : opts.user_data = user_data;
3384 : #endif
3385 :
3386 0 : if (callback == NULL) callback = mg_ev_handler_empty;
3387 :
3388 0 : MG_COPY_COMMON_CONNECTION_OPTIONS(&add_sock_opts, &opts);
3389 :
3390 0 : if (mg_parse_address(address, &sa, &proto, host, sizeof(host)) <= 0) {
3391 0 : MG_SET_PTRPTR(opts.error_string, "cannot parse address");
3392 0 : return NULL;
3393 : }
3394 :
3395 0 : nc = mg_create_connection(mgr, callback, add_sock_opts);
3396 0 : if (nc == NULL) {
3397 0 : return NULL;
3398 : }
3399 :
3400 0 : nc->sa = sa;
3401 0 : nc->flags |= MG_F_LISTENING;
3402 0 : if (proto == SOCK_DGRAM) nc->flags |= MG_F_UDP;
3403 :
3404 : #if MG_ENABLE_SSL
3405 : DBG(("%p %s %s,%s,%s", nc, address, (opts.ssl_cert ? opts.ssl_cert : "-"),
3406 : (opts.ssl_key ? opts.ssl_key : "-"),
3407 : (opts.ssl_ca_cert ? opts.ssl_ca_cert : "-")));
3408 :
3409 : if (opts.ssl_cert != NULL || opts.ssl_ca_cert != NULL) {
3410 : const char *err_msg = NULL;
3411 : struct mg_ssl_if_conn_params params;
3412 : if (nc->flags & MG_F_UDP) {
3413 : MG_SET_PTRPTR(opts.error_string, "SSL for UDP is not supported");
3414 : mg_destroy_conn(nc, 1 /* destroy_if */);
3415 : return NULL;
3416 : }
3417 : memset(¶ms, 0, sizeof(params));
3418 : params.cert = opts.ssl_cert;
3419 : params.key = opts.ssl_key;
3420 : params.ca_cert = opts.ssl_ca_cert;
3421 : params.cipher_suites = opts.ssl_cipher_suites;
3422 : if (mg_ssl_if_conn_init(nc, ¶ms, &err_msg) != MG_SSL_OK) {
3423 : MG_SET_PTRPTR(opts.error_string, err_msg);
3424 : mg_destroy_conn(nc, 1 /* destroy_if */);
3425 : return NULL;
3426 : }
3427 : nc->flags |= MG_F_SSL;
3428 : }
3429 : #endif /* MG_ENABLE_SSL */
3430 :
3431 0 : if (nc->flags & MG_F_UDP) {
3432 0 : rc = nc->iface->vtable->listen_udp(nc, &nc->sa);
3433 : } else {
3434 0 : rc = nc->iface->vtable->listen_tcp(nc, &nc->sa);
3435 : }
3436 0 : if (rc != 0) {
3437 0 : DBG(("Failed to open listener: %d", rc));
3438 0 : MG_SET_PTRPTR(opts.error_string, "failed to open listener");
3439 0 : mg_destroy_conn(nc, 1 /* destroy_if */);
3440 0 : return NULL;
3441 : }
3442 0 : mg_add_conn(nc->mgr, nc);
3443 :
3444 0 : return nc;
3445 : }
3446 :
3447 0 : struct mg_connection *mg_next(struct mg_mgr *s, struct mg_connection *conn) {
3448 0 : return conn == NULL ? s->active_connections : conn->next;
3449 : }
3450 :
3451 : #if MG_ENABLE_BROADCAST
3452 0 : void mg_broadcast(struct mg_mgr *mgr, mg_event_handler_t cb, void *data,
3453 : size_t len) {
3454 : struct ctl_msg ctl_msg;
3455 :
3456 : /*
3457 : * Mongoose manager has a socketpair, `struct mg_mgr::ctl`,
3458 : * where `mg_broadcast()` pushes the message.
3459 : * `mg_mgr_poll()` wakes up, reads a message from the socket pair, and calls
3460 : * specified callback for each connection. Thus the callback function executes
3461 : * in event manager thread.
3462 : */
3463 0 : if (mgr->ctl[0] != INVALID_SOCKET && data != NULL &&
3464 0 : len < sizeof(ctl_msg.message)) {
3465 : size_t dummy;
3466 :
3467 0 : ctl_msg.callback = cb;
3468 0 : memcpy(ctl_msg.message, data, len);
3469 0 : dummy = MG_SEND_FUNC(mgr->ctl[0], (char *) &ctl_msg,
3470 : offsetof(struct ctl_msg, message) + len, 0);
3471 0 : dummy = MG_RECV_FUNC(mgr->ctl[0], (char *) &len, 1, 0);
3472 : (void) dummy; /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25509 */
3473 : }
3474 0 : }
3475 : #endif /* MG_ENABLE_BROADCAST */
3476 :
3477 0 : static int isbyte(int n) {
3478 0 : return n >= 0 && n <= 255;
3479 : }
3480 :
3481 0 : static int parse_net(const char *spec, uint32_t *net, uint32_t *mask) {
3482 0 : int n, a, b, c, d, slash = 32, len = 0;
3483 :
3484 0 : if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5 ||
3485 0 : sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) &&
3486 0 : isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) && slash >= 0 &&
3487 0 : slash < 33) {
3488 0 : len = n;
3489 0 : *net =
3490 0 : ((uint32_t) a << 24) | ((uint32_t) b << 16) | ((uint32_t) c << 8) | d;
3491 0 : *mask = slash ? 0xffffffffU << (32 - slash) : 0;
3492 : }
3493 :
3494 0 : return len;
3495 : }
3496 :
3497 0 : int mg_check_ip_acl(const char *acl, uint32_t remote_ip) {
3498 : int allowed, flag;
3499 : uint32_t net, mask;
3500 : struct mg_str vec;
3501 :
3502 : /* If any ACL is set, deny by default */
3503 0 : allowed = (acl == NULL || *acl == '\0') ? '+' : '-';
3504 :
3505 0 : while ((acl = mg_next_comma_list_entry(acl, &vec, NULL)) != NULL) {
3506 0 : flag = vec.p[0];
3507 0 : if ((flag != '+' && flag != '-') ||
3508 0 : parse_net(&vec.p[1], &net, &mask) == 0) {
3509 0 : return -1;
3510 : }
3511 :
3512 0 : if (net == (remote_ip & mask)) {
3513 0 : allowed = flag;
3514 : }
3515 : }
3516 :
3517 0 : DBG(("%08x %c", (unsigned int) remote_ip, allowed));
3518 0 : return allowed == '+';
3519 : }
3520 :
3521 : /* Move data from one connection to another */
3522 0 : void mg_forward(struct mg_connection *from, struct mg_connection *to) {
3523 0 : mg_send(to, from->recv_mbuf.buf, from->recv_mbuf.len);
3524 0 : mbuf_remove(&from->recv_mbuf, from->recv_mbuf.len);
3525 0 : }
3526 :
3527 0 : double mg_set_timer(struct mg_connection *c, double timestamp) {
3528 0 : double result = c->ev_timer_time;
3529 0 : c->ev_timer_time = timestamp;
3530 : /*
3531 : * If this connection is resolving, it's not in the list of active
3532 : * connections, so not processed yet. It has a DNS resolver connection
3533 : * linked to it. Set up a timer for the DNS connection.
3534 : */
3535 0 : DBG(("%p %p %d -> %lu", c, c->priv_2, (c->flags & MG_F_RESOLVING ? 1 : 0),
3536 : (unsigned long) timestamp));
3537 0 : if ((c->flags & MG_F_RESOLVING) && c->priv_2 != NULL) {
3538 0 : mg_set_timer((struct mg_connection *) c->priv_2, timestamp);
3539 : }
3540 0 : return result;
3541 : }
3542 :
3543 0 : void mg_sock_set(struct mg_connection *nc, sock_t sock) {
3544 0 : if (sock != INVALID_SOCKET) {
3545 0 : nc->iface->vtable->sock_set(nc, sock);
3546 : }
3547 0 : }
3548 :
3549 0 : void mg_if_get_conn_addr(struct mg_connection *nc, int remote,
3550 : union socket_address *sa) {
3551 0 : nc->iface->vtable->get_conn_addr(nc, remote, sa);
3552 0 : }
3553 :
3554 0 : struct mg_connection *mg_add_sock_opt(struct mg_mgr *s, sock_t sock,
3555 : MG_CB(mg_event_handler_t callback,
3556 : void *user_data),
3557 : struct mg_add_sock_opts opts) {
3558 : #if MG_ENABLE_CALLBACK_USERDATA
3559 : opts.user_data = user_data;
3560 : #endif
3561 :
3562 0 : struct mg_connection *nc = mg_create_connection_base(s, callback, opts);
3563 0 : if (nc != NULL) {
3564 0 : mg_sock_set(nc, sock);
3565 0 : mg_add_conn(nc->mgr, nc);
3566 : }
3567 0 : return nc;
3568 : }
3569 :
3570 0 : struct mg_connection *mg_add_sock(struct mg_mgr *s, sock_t sock,
3571 : MG_CB(mg_event_handler_t callback,
3572 : void *user_data)) {
3573 : struct mg_add_sock_opts opts;
3574 0 : memset(&opts, 0, sizeof(opts));
3575 0 : return mg_add_sock_opt(s, sock, MG_CB(callback, user_data), opts);
3576 : }
3577 :
3578 0 : double mg_time(void) {
3579 0 : return cs_time();
3580 : }
3581 : #ifdef MG_MODULE_LINES
3582 : #line 1 "mongoose/src/mg_net_if_socket.h"
3583 : #endif
3584 : /*
3585 : * Copyright (c) 2014-2016 Cesanta Software Limited
3586 : * All rights reserved
3587 : */
3588 :
3589 : #ifndef CS_MONGOOSE_SRC_NET_IF_SOCKET_H_
3590 : #define CS_MONGOOSE_SRC_NET_IF_SOCKET_H_
3591 :
3592 : /* Amalgamated: #include "mg_net_if.h" */
3593 :
3594 : #ifdef __cplusplus
3595 : extern "C" {
3596 : #endif /* __cplusplus */
3597 :
3598 : #ifndef MG_ENABLE_NET_IF_SOCKET
3599 : #define MG_ENABLE_NET_IF_SOCKET MG_NET_IF == MG_NET_IF_SOCKET
3600 : #endif
3601 :
3602 : extern const struct mg_iface_vtable mg_socket_iface_vtable;
3603 :
3604 : #ifdef __cplusplus
3605 : }
3606 : #endif /* __cplusplus */
3607 :
3608 : #endif /* CS_MONGOOSE_SRC_NET_IF_SOCKET_H_ */
3609 : #ifdef MG_MODULE_LINES
3610 : #line 1 "mongoose/src/mg_net_if_socks.h"
3611 : #endif
3612 : /*
3613 : * Copyright (c) 2014-2017 Cesanta Software Limited
3614 : * All rights reserved
3615 : */
3616 :
3617 : #ifndef CS_MONGOOSE_SRC_NET_IF_SOCKS_H_
3618 : #define CS_MONGOOSE_SRC_NET_IF_SOCKS_H_
3619 :
3620 : #if MG_ENABLE_SOCKS
3621 : /* Amalgamated: #include "mg_net_if.h" */
3622 :
3623 : #ifdef __cplusplus
3624 : extern "C" {
3625 : #endif /* __cplusplus */
3626 :
3627 : extern const struct mg_iface_vtable mg_socks_iface_vtable;
3628 :
3629 : #ifdef __cplusplus
3630 : }
3631 : #endif /* __cplusplus */
3632 : #endif /* MG_ENABLE_SOCKS */
3633 : #endif /* CS_MONGOOSE_SRC_NET_IF_SOCKS_H_ */
3634 : #ifdef MG_MODULE_LINES
3635 : #line 1 "mongoose/src/mg_net_if.c"
3636 : #endif
3637 : /* Amalgamated: #include "mg_net_if.h" */
3638 : /* Amalgamated: #include "mg_internal.h" */
3639 : /* Amalgamated: #include "mg_net_if_socket.h" */
3640 :
3641 : extern const struct mg_iface_vtable mg_default_iface_vtable;
3642 :
3643 : const struct mg_iface_vtable *mg_ifaces[] = {
3644 : &mg_default_iface_vtable,
3645 : };
3646 :
3647 : int mg_num_ifaces = (int) (sizeof(mg_ifaces) / sizeof(mg_ifaces[0]));
3648 :
3649 0 : struct mg_iface *mg_if_create_iface(const struct mg_iface_vtable *vtable,
3650 : struct mg_mgr *mgr) {
3651 0 : struct mg_iface *iface = (struct mg_iface *) MG_CALLOC(1, sizeof(*iface));
3652 0 : iface->mgr = mgr;
3653 0 : iface->data = NULL;
3654 0 : iface->vtable = vtable;
3655 0 : return iface;
3656 : }
3657 :
3658 0 : struct mg_iface *mg_find_iface(struct mg_mgr *mgr,
3659 : const struct mg_iface_vtable *vtable,
3660 : struct mg_iface *from) {
3661 0 : int i = 0;
3662 0 : if (from != NULL) {
3663 0 : for (i = 0; i < mgr->num_ifaces; i++) {
3664 0 : if (mgr->ifaces[i] == from) {
3665 0 : i++;
3666 0 : break;
3667 : }
3668 : }
3669 : }
3670 :
3671 0 : for (; i < mgr->num_ifaces; i++) {
3672 0 : if (mgr->ifaces[i]->vtable == vtable) {
3673 0 : return mgr->ifaces[i];
3674 : }
3675 : }
3676 0 : return NULL;
3677 : }
3678 :
3679 0 : double mg_mgr_min_timer(const struct mg_mgr *mgr) {
3680 0 : double min_timer = 0;
3681 : struct mg_connection *nc;
3682 0 : for (nc = mgr->active_connections; nc != NULL; nc = nc->next) {
3683 0 : if (nc->ev_timer_time <= 0) continue;
3684 0 : if (min_timer == 0 || nc->ev_timer_time < min_timer) {
3685 0 : min_timer = nc->ev_timer_time;
3686 : }
3687 : }
3688 0 : return min_timer;
3689 : }
3690 : #ifdef MG_MODULE_LINES
3691 : #line 1 "mongoose/src/mg_net_if_null.c"
3692 : #endif
3693 : /*
3694 : * Copyright (c) 2018 Cesanta Software Limited
3695 : * All rights reserved
3696 : *
3697 : * This software is dual-licensed: you can redistribute it and/or modify
3698 : * it under the terms of the GNU General Public License version 2 as
3699 : * published by the Free Software Foundation. For the terms of this
3700 : * license, see <http://www.gnu.org/licenses/>.
3701 : *
3702 : * You are free to use this software under the terms of the GNU General
3703 : * Public License, but WITHOUT ANY WARRANTY; without even the implied
3704 : * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
3705 : * See the GNU General Public License for more details.
3706 : *
3707 : * Alternatively, you can license this software under a commercial
3708 : * license, as set out in <https://www.cesanta.com/license>.
3709 : */
3710 :
3711 0 : static void mg_null_if_connect_tcp(struct mg_connection *c,
3712 : const union socket_address *sa) {
3713 0 : c->flags |= MG_F_CLOSE_IMMEDIATELY;
3714 : (void) sa;
3715 0 : }
3716 :
3717 0 : static void mg_null_if_connect_udp(struct mg_connection *c) {
3718 0 : c->flags |= MG_F_CLOSE_IMMEDIATELY;
3719 0 : }
3720 :
3721 0 : static int mg_null_if_listen_tcp(struct mg_connection *c,
3722 : union socket_address *sa) {
3723 : (void) c;
3724 : (void) sa;
3725 0 : return -1;
3726 : }
3727 :
3728 0 : static int mg_null_if_listen_udp(struct mg_connection *c,
3729 : union socket_address *sa) {
3730 : (void) c;
3731 : (void) sa;
3732 0 : return -1;
3733 : }
3734 :
3735 0 : static int mg_null_if_tcp_send(struct mg_connection *c, const void *buf,
3736 : size_t len) {
3737 : (void) c;
3738 : (void) buf;
3739 : (void) len;
3740 0 : return -1;
3741 : }
3742 :
3743 0 : static int mg_null_if_udp_send(struct mg_connection *c, const void *buf,
3744 : size_t len) {
3745 : (void) c;
3746 : (void) buf;
3747 : (void) len;
3748 0 : return -1;
3749 : }
3750 :
3751 0 : int mg_null_if_tcp_recv(struct mg_connection *c, void *buf, size_t len) {
3752 : (void) c;
3753 : (void) buf;
3754 : (void) len;
3755 0 : return -1;
3756 : }
3757 :
3758 0 : int mg_null_if_udp_recv(struct mg_connection *c, void *buf, size_t len,
3759 : union socket_address *sa, size_t *sa_len) {
3760 : (void) c;
3761 : (void) buf;
3762 : (void) len;
3763 : (void) sa;
3764 : (void) sa_len;
3765 0 : return -1;
3766 : }
3767 :
3768 0 : static int mg_null_if_create_conn(struct mg_connection *c) {
3769 : (void) c;
3770 0 : return 1;
3771 : }
3772 :
3773 0 : static void mg_null_if_destroy_conn(struct mg_connection *c) {
3774 : (void) c;
3775 0 : }
3776 :
3777 0 : static void mg_null_if_sock_set(struct mg_connection *c, sock_t sock) {
3778 : (void) c;
3779 : (void) sock;
3780 0 : }
3781 :
3782 0 : static void mg_null_if_init(struct mg_iface *iface) {
3783 : (void) iface;
3784 0 : }
3785 :
3786 0 : static void mg_null_if_free(struct mg_iface *iface) {
3787 : (void) iface;
3788 0 : }
3789 :
3790 0 : static void mg_null_if_add_conn(struct mg_connection *c) {
3791 0 : c->sock = INVALID_SOCKET;
3792 0 : c->flags |= MG_F_CLOSE_IMMEDIATELY;
3793 0 : }
3794 :
3795 0 : static void mg_null_if_remove_conn(struct mg_connection *c) {
3796 : (void) c;
3797 0 : }
3798 :
3799 0 : static time_t mg_null_if_poll(struct mg_iface *iface, int timeout_ms) {
3800 0 : struct mg_mgr *mgr = iface->mgr;
3801 : struct mg_connection *nc, *tmp;
3802 0 : double now = mg_time();
3803 : /* We basically just run timers and poll. */
3804 0 : for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
3805 0 : tmp = nc->next;
3806 0 : mg_if_poll(nc, now);
3807 : }
3808 : (void) timeout_ms;
3809 0 : return (time_t) now;
3810 : }
3811 :
3812 0 : static void mg_null_if_get_conn_addr(struct mg_connection *c, int remote,
3813 : union socket_address *sa) {
3814 : (void) c;
3815 : (void) remote;
3816 : (void) sa;
3817 0 : }
3818 :
3819 : #define MG_NULL_IFACE_VTABLE \
3820 : { \
3821 : mg_null_if_init, mg_null_if_free, mg_null_if_add_conn, \
3822 : mg_null_if_remove_conn, mg_null_if_poll, mg_null_if_listen_tcp, \
3823 : mg_null_if_listen_udp, mg_null_if_connect_tcp, mg_null_if_connect_udp, \
3824 : mg_null_if_tcp_send, mg_null_if_udp_send, mg_null_if_tcp_recv, \
3825 : mg_null_if_udp_recv, mg_null_if_create_conn, mg_null_if_destroy_conn, \
3826 : mg_null_if_sock_set, mg_null_if_get_conn_addr, \
3827 : }
3828 :
3829 : //const struct mg_iface_vtable mg_null_iface_vtable = MG_NULL_IFACE_VTABLE;
3830 :
3831 : #if MG_NET_IF == MG_NET_IF_NULL
3832 : const struct mg_iface_vtable mg_default_iface_vtable = MG_NULL_IFACE_VTABLE;
3833 : #endif /* MG_NET_IF == MG_NET_IF_NULL */
3834 : #ifdef MG_MODULE_LINES
3835 : #line 1 "mongoose/src/mg_net_if_socket.c"
3836 : #endif
3837 : /*
3838 : * Copyright (c) 2014-2016 Cesanta Software Limited
3839 : * All rights reserved
3840 : */
3841 :
3842 : #if MG_ENABLE_NET_IF_SOCKET
3843 :
3844 : /* Amalgamated: #include "mg_net_if_socket.h" */
3845 : /* Amalgamated: #include "mg_internal.h" */
3846 : /* Amalgamated: #include "mg_util.h" */
3847 :
3848 : static sock_t mg_open_listening_socket(union socket_address *sa, int type,
3849 : int proto);
3850 :
3851 0 : void mg_set_non_blocking_mode(sock_t sock) {
3852 : #ifdef _WIN32
3853 : unsigned long on = 1;
3854 : ioctlsocket(sock, FIONBIO, &on);
3855 : #else
3856 0 : int flags = fcntl(sock, F_GETFL, 0);
3857 0 : fcntl(sock, F_SETFL, flags | O_NONBLOCK);
3858 : #endif
3859 0 : }
3860 :
3861 0 : static int mg_is_error(void) {
3862 0 : int err = mg_get_errno();
3863 0 : return err != EINPROGRESS && err != EWOULDBLOCK
3864 : #ifndef WINCE
3865 0 : && err != EAGAIN && err != EINTR
3866 : #endif
3867 : #ifdef _WIN32
3868 : && WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK
3869 : #endif
3870 : ;
3871 : }
3872 :
3873 0 : void mg_socket_if_connect_tcp(struct mg_connection *nc,
3874 : const union socket_address *sa) {
3875 0 : int rc, proto = 0;
3876 0 : nc->sock = socket(AF_INET, SOCK_STREAM, proto);
3877 0 : if (nc->sock == INVALID_SOCKET) {
3878 0 : nc->err = mg_get_errno() ? mg_get_errno() : 1;
3879 0 : return;
3880 : }
3881 : #if !defined(MG_ESP8266)
3882 0 : mg_set_non_blocking_mode(nc->sock);
3883 : #endif
3884 0 : rc = connect(nc->sock, &sa->sa, sizeof(sa->sin));
3885 0 : nc->err = rc < 0 && mg_is_error() ? mg_get_errno() : 0;
3886 0 : DBG(("%p sock %d rc %d errno %d err %d", nc, nc->sock, rc, mg_get_errno(),
3887 : nc->err));
3888 : }
3889 :
3890 0 : void mg_socket_if_connect_udp(struct mg_connection *nc) {
3891 0 : nc->sock = socket(AF_INET, SOCK_DGRAM, 0);
3892 0 : if (nc->sock == INVALID_SOCKET) {
3893 0 : nc->err = mg_get_errno() ? mg_get_errno() : 1;
3894 0 : return;
3895 : }
3896 0 : if (nc->flags & MG_F_ENABLE_BROADCAST) {
3897 0 : int optval = 1;
3898 0 : if (setsockopt(nc->sock, SOL_SOCKET, SO_BROADCAST, (const char *) &optval,
3899 0 : sizeof(optval)) < 0) {
3900 0 : nc->err = mg_get_errno() ? mg_get_errno() : 1;
3901 0 : return;
3902 : }
3903 : }
3904 0 : nc->err = 0;
3905 : }
3906 :
3907 0 : int mg_socket_if_listen_tcp(struct mg_connection *nc,
3908 : union socket_address *sa) {
3909 0 : int proto = 0;
3910 0 : sock_t sock = mg_open_listening_socket(sa, SOCK_STREAM, proto);
3911 0 : if (sock == INVALID_SOCKET) {
3912 0 : return (mg_get_errno() ? mg_get_errno() : 1);
3913 : }
3914 0 : mg_sock_set(nc, sock);
3915 0 : return 0;
3916 : }
3917 :
3918 0 : static int mg_socket_if_listen_udp(struct mg_connection *nc,
3919 : union socket_address *sa) {
3920 0 : sock_t sock = mg_open_listening_socket(sa, SOCK_DGRAM, 0);
3921 0 : if (sock == INVALID_SOCKET) return (mg_get_errno() ? mg_get_errno() : 1);
3922 0 : mg_sock_set(nc, sock);
3923 0 : return 0;
3924 : }
3925 :
3926 0 : static int mg_socket_if_tcp_send(struct mg_connection *nc, const void *buf,
3927 : size_t len) {
3928 0 : int n = (int) MG_SEND_FUNC(nc->sock, buf, len, 0);
3929 0 : if (n < 0 && !mg_is_error()) n = 0;
3930 0 : return n;
3931 : }
3932 :
3933 0 : static int mg_socket_if_udp_send(struct mg_connection *nc, const void *buf,
3934 : size_t len) {
3935 0 : int n = sendto(nc->sock, buf, len, 0, &nc->sa.sa, sizeof(nc->sa.sin));
3936 0 : if (n < 0 && !mg_is_error()) n = 0;
3937 0 : return n;
3938 : }
3939 :
3940 0 : static int mg_socket_if_tcp_recv(struct mg_connection *nc, void *buf,
3941 : size_t len) {
3942 0 : int n = (int) MG_RECV_FUNC(nc->sock, buf, len, 0);
3943 0 : if (n == 0) {
3944 : /* Orderly shutdown of the socket, try flushing output. */
3945 0 : nc->flags |= MG_F_SEND_AND_CLOSE;
3946 0 : } else if (n < 0 && !mg_is_error()) {
3947 0 : n = 0;
3948 : }
3949 0 : return n;
3950 : }
3951 :
3952 0 : static int mg_socket_if_udp_recv(struct mg_connection *nc, void *buf,
3953 : size_t len, union socket_address *sa,
3954 : size_t *sa_len) {
3955 0 : socklen_t sa_len_st = *sa_len;
3956 0 : int n = recvfrom(nc->sock, buf, len, 0, &sa->sa, &sa_len_st);
3957 0 : *sa_len = sa_len_st;
3958 0 : if (n < 0 && !mg_is_error()) n = 0;
3959 0 : return n;
3960 : }
3961 :
3962 0 : int mg_socket_if_create_conn(struct mg_connection *nc) {
3963 : (void) nc;
3964 0 : return 1;
3965 : }
3966 :
3967 0 : void mg_socket_if_destroy_conn(struct mg_connection *nc) {
3968 0 : if (nc->sock == INVALID_SOCKET) return;
3969 0 : if (!(nc->flags & MG_F_UDP)) {
3970 0 : closesocket(nc->sock);
3971 : } else {
3972 : /* Only close outgoing UDP sockets or listeners. */
3973 0 : if (nc->listener == NULL) closesocket(nc->sock);
3974 : }
3975 0 : nc->sock = INVALID_SOCKET;
3976 : }
3977 :
3978 0 : static int mg_accept_conn(struct mg_connection *lc) {
3979 : struct mg_connection *nc;
3980 : union socket_address sa;
3981 0 : socklen_t sa_len = sizeof(sa);
3982 : /* NOTE(lsm): on Windows, sock is always > FD_SETSIZE */
3983 0 : sock_t sock = accept(lc->sock, &sa.sa, &sa_len);
3984 0 : if (sock == INVALID_SOCKET) {
3985 0 : if (mg_is_error()) {
3986 0 : DBG(("%p: failed to accept: %d", lc, mg_get_errno()));
3987 : }
3988 0 : return 0;
3989 : }
3990 0 : nc = mg_if_accept_new_conn(lc);
3991 0 : if (nc == NULL) {
3992 0 : closesocket(sock);
3993 0 : return 0;
3994 : }
3995 0 : DBG(("%p conn from %s:%d", nc, inet_ntoa(sa.sin.sin_addr),
3996 : ntohs(sa.sin.sin_port)));
3997 0 : mg_sock_set(nc, sock);
3998 0 : mg_if_accept_tcp_cb(nc, &sa, sa_len);
3999 0 : return 1;
4000 : }
4001 :
4002 : /* 'sa' must be an initialized address to bind to */
4003 0 : static sock_t mg_open_listening_socket(union socket_address *sa, int type,
4004 : int proto) {
4005 0 : socklen_t sa_len =
4006 0 : (sa->sa.sa_family == AF_INET) ? sizeof(sa->sin) : sizeof(sa->sin6);
4007 0 : sock_t sock = INVALID_SOCKET;
4008 : #if !MG_LWIP
4009 0 : int on = 1;
4010 : #endif
4011 :
4012 0 : if ((sock = socket(sa->sa.sa_family, type, proto)) != INVALID_SOCKET &&
4013 : #if !MG_LWIP /* LWIP doesn't support either */
4014 : #if defined(_WIN32) && defined(SO_EXCLUSIVEADDRUSE) && !defined(WINCE)
4015 : /* "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE" http://goo.gl/RmrFTm */
4016 : !setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &on,
4017 : sizeof(on)) &&
4018 : #endif
4019 :
4020 : #if !defined(_WIN32) || !defined(SO_EXCLUSIVEADDRUSE)
4021 : /*
4022 : * SO_RESUSEADDR is not enabled on Windows because the semantics of
4023 : * SO_REUSEADDR on UNIX and Windows is different. On Windows,
4024 : * SO_REUSEADDR allows to bind a socket to a port without error even if
4025 : * the port is already open by another program. This is not the behavior
4026 : * SO_REUSEADDR was designed for, and leads to hard-to-track failure
4027 : * scenarios. Therefore, SO_REUSEADDR was disabled on Windows unless
4028 : * SO_EXCLUSIVEADDRUSE is supported and set on a socket.
4029 : */
4030 0 : !setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) &&
4031 : #endif
4032 : #endif /* !MG_LWIP */
4033 :
4034 0 : !bind(sock, &sa->sa, sa_len) &&
4035 0 : (type == SOCK_DGRAM || listen(sock, SOMAXCONN) == 0)) {
4036 : #if !MG_LWIP
4037 0 : mg_set_non_blocking_mode(sock);
4038 : /* In case port was set to 0, get the real port number */
4039 0 : (void) getsockname(sock, &sa->sa, &sa_len);
4040 : #endif
4041 0 : } else if (sock != INVALID_SOCKET) {
4042 0 : closesocket(sock);
4043 0 : sock = INVALID_SOCKET;
4044 : }
4045 :
4046 0 : return sock;
4047 : }
4048 :
4049 : #define _MG_F_FD_CAN_READ 1
4050 : #define _MG_F_FD_CAN_WRITE 1 << 1
4051 : #define _MG_F_FD_ERROR 1 << 2
4052 :
4053 0 : void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
4054 0 : int worth_logging =
4055 0 : fd_flags != 0 || (nc->flags & (MG_F_WANT_READ | MG_F_WANT_WRITE));
4056 0 : if (worth_logging) {
4057 0 : DBG(("%p fd=%d fd_flags=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock,
4058 : fd_flags, nc->flags, (int) nc->recv_mbuf.len,
4059 : (int) nc->send_mbuf.len));
4060 : }
4061 :
4062 0 : if (!mg_if_poll(nc, now)) return;
4063 :
4064 0 : if (nc->flags & MG_F_CONNECTING) {
4065 0 : if (fd_flags != 0) {
4066 0 : int err = 0;
4067 : #if !defined(MG_ESP8266)
4068 0 : if (!(nc->flags & MG_F_UDP)) {
4069 0 : socklen_t len = sizeof(err);
4070 : int ret =
4071 0 : getsockopt(nc->sock, SOL_SOCKET, SO_ERROR, (char *) &err, &len);
4072 0 : if (ret != 0) {
4073 0 : err = 1;
4074 0 : } else if (err == EAGAIN || err == EWOULDBLOCK) {
4075 0 : err = 0;
4076 : }
4077 : }
4078 : #else
4079 : /*
4080 : * On ESP8266 we use blocking connect.
4081 : */
4082 : err = nc->err;
4083 : #endif
4084 0 : mg_if_connect_cb(nc, err);
4085 0 : } else if (nc->err != 0) {
4086 0 : mg_if_connect_cb(nc, nc->err);
4087 : }
4088 : }
4089 :
4090 0 : if (fd_flags & _MG_F_FD_CAN_READ) {
4091 0 : if (nc->flags & MG_F_UDP) {
4092 0 : mg_if_can_recv_cb(nc);
4093 : } else {
4094 0 : if (nc->flags & MG_F_LISTENING) {
4095 : /*
4096 : * We're not looping here, and accepting just one connection at
4097 : * a time. The reason is that eCos does not respect non-blocking
4098 : * flag on a listening socket and hangs in a loop.
4099 : */
4100 0 : mg_accept_conn(nc);
4101 : } else {
4102 0 : mg_if_can_recv_cb(nc);
4103 : }
4104 : }
4105 : }
4106 :
4107 0 : if (fd_flags & _MG_F_FD_CAN_WRITE) mg_if_can_send_cb(nc);
4108 :
4109 0 : if (worth_logging) {
4110 0 : DBG(("%p after fd=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock,
4111 : nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
4112 : }
4113 : }
4114 :
4115 : #if MG_ENABLE_BROADCAST
4116 0 : static void mg_mgr_handle_ctl_sock(struct mg_mgr *mgr) {
4117 : struct ctl_msg ctl_msg;
4118 : int len =
4119 0 : (int) MG_RECV_FUNC(mgr->ctl[1], (char *) &ctl_msg, sizeof(ctl_msg), 0);
4120 0 : DBG(("read %d from ctl socket", len));
4121 0 : if (len >= (int) sizeof(ctl_msg.callback) && ctl_msg.callback != NULL) {
4122 : struct mg_connection *nc;
4123 0 : for (nc = mg_next(mgr, NULL); nc != NULL; nc = mg_next(mgr, nc)) {
4124 0 : ctl_msg.callback(nc, MG_EV_POLL,
4125 : ctl_msg.message MG_UD_ARG(nc->user_data));
4126 : }
4127 : }
4128 : // change from original mongoose code: send the reply message
4129 : // after we finished processing the broadcast message. K.O.
4130 0 : size_t dummy = MG_SEND_FUNC(mgr->ctl[1], ctl_msg.message, 1, 0);
4131 : (void) dummy; /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25509 */
4132 0 : }
4133 : #endif
4134 :
4135 : /* Associate a socket to a connection. */
4136 0 : void mg_socket_if_sock_set(struct mg_connection *nc, sock_t sock) {
4137 0 : mg_set_non_blocking_mode(sock);
4138 0 : mg_set_close_on_exec(sock);
4139 0 : nc->sock = sock;
4140 0 : DBG(("%p %d", nc, sock));
4141 0 : }
4142 :
4143 0 : void mg_socket_if_init(struct mg_iface *iface) {
4144 : (void) iface;
4145 0 : DBG(("%p using select()", iface->mgr));
4146 : #if MG_ENABLE_BROADCAST
4147 0 : mg_socketpair(iface->mgr->ctl, SOCK_DGRAM);
4148 : #endif
4149 0 : }
4150 :
4151 0 : void mg_socket_if_free(struct mg_iface *iface) {
4152 : (void) iface;
4153 0 : }
4154 :
4155 0 : void mg_socket_if_add_conn(struct mg_connection *nc) {
4156 : (void) nc;
4157 0 : }
4158 :
4159 0 : void mg_socket_if_remove_conn(struct mg_connection *nc) {
4160 : (void) nc;
4161 0 : }
4162 :
4163 0 : void mg_add_to_set(sock_t sock, fd_set *set, sock_t *max_fd) {
4164 0 : if (sock != INVALID_SOCKET
4165 : #ifdef __unix__
4166 0 : && sock < (sock_t) FD_SETSIZE
4167 : #endif
4168 : ) {
4169 0 : FD_SET(sock, set);
4170 0 : if (*max_fd == INVALID_SOCKET || sock > *max_fd) {
4171 0 : *max_fd = sock;
4172 : }
4173 : }
4174 0 : }
4175 :
4176 0 : time_t mg_socket_if_poll(struct mg_iface *iface, int timeout_ms) {
4177 0 : struct mg_mgr *mgr = iface->mgr;
4178 0 : double now = mg_time();
4179 : double min_timer;
4180 : struct mg_connection *nc, *tmp;
4181 : struct timeval tv;
4182 : fd_set read_set, write_set, err_set;
4183 0 : sock_t max_fd = INVALID_SOCKET;
4184 0 : int num_fds, num_ev, num_timers = 0;
4185 : #ifdef __unix__
4186 0 : int try_dup = 1;
4187 : #endif
4188 :
4189 0 : FD_ZERO(&read_set);
4190 0 : FD_ZERO(&write_set);
4191 0 : FD_ZERO(&err_set);
4192 : #if MG_ENABLE_BROADCAST
4193 0 : mg_add_to_set(mgr->ctl[1], &read_set, &max_fd);
4194 : #endif
4195 :
4196 : /*
4197 : * Note: it is ok to have connections with sock == INVALID_SOCKET in the list,
4198 : * e.g. timer-only "connections".
4199 : */
4200 0 : min_timer = 0;
4201 0 : for (nc = mgr->active_connections, num_fds = 0; nc != NULL; nc = tmp) {
4202 0 : tmp = nc->next;
4203 :
4204 0 : if (nc->sock != INVALID_SOCKET) {
4205 0 : num_fds++;
4206 :
4207 : #ifdef __unix__
4208 : /* A hack to make sure all our file descriptos fit into FD_SETSIZE. */
4209 0 : if (nc->sock >= (sock_t) FD_SETSIZE && try_dup) {
4210 0 : int new_sock = dup(nc->sock);
4211 0 : if (new_sock >= 0) {
4212 0 : if (new_sock < (sock_t) FD_SETSIZE) {
4213 0 : closesocket(nc->sock);
4214 0 : DBG(("new sock %d -> %d", nc->sock, new_sock));
4215 0 : nc->sock = new_sock;
4216 : } else {
4217 0 : closesocket(new_sock);
4218 0 : DBG(("new sock is still larger than FD_SETSIZE, disregard"));
4219 0 : try_dup = 0;
4220 : }
4221 : } else {
4222 0 : try_dup = 0;
4223 : }
4224 : }
4225 : #endif
4226 :
4227 0 : if (nc->recv_mbuf.len < nc->recv_mbuf_limit &&
4228 0 : (!(nc->flags & MG_F_UDP) || nc->listener == NULL)) {
4229 0 : mg_add_to_set(nc->sock, &read_set, &max_fd);
4230 : }
4231 :
4232 0 : if (((nc->flags & MG_F_CONNECTING) && !(nc->flags & MG_F_WANT_READ)) ||
4233 0 : (nc->send_mbuf.len > 0 && !(nc->flags & MG_F_CONNECTING))) {
4234 0 : mg_add_to_set(nc->sock, &write_set, &max_fd);
4235 0 : mg_add_to_set(nc->sock, &err_set, &max_fd);
4236 : }
4237 : }
4238 :
4239 0 : if (nc->ev_timer_time > 0) {
4240 0 : if (num_timers == 0 || nc->ev_timer_time < min_timer) {
4241 0 : min_timer = nc->ev_timer_time;
4242 : }
4243 0 : num_timers++;
4244 : }
4245 : }
4246 :
4247 : /*
4248 : * If there is a timer to be fired earlier than the requested timeout,
4249 : * adjust the timeout.
4250 : */
4251 0 : if (num_timers > 0) {
4252 0 : double timer_timeout_ms = (min_timer - mg_time()) * 1000 + 1 /* rounding */;
4253 0 : if (timer_timeout_ms < timeout_ms) {
4254 0 : timeout_ms = (int) timer_timeout_ms;
4255 : }
4256 : }
4257 0 : if (timeout_ms < 0) timeout_ms = 0;
4258 :
4259 0 : tv.tv_sec = timeout_ms / 1000;
4260 0 : tv.tv_usec = (timeout_ms % 1000) * 1000;
4261 :
4262 0 : num_ev = select((int) max_fd + 1, &read_set, &write_set, &err_set, &tv);
4263 0 : now = mg_time();
4264 : #if 0
4265 : DBG(("select @ %ld num_ev=%d of %d, timeout=%d", (long) now, num_ev, num_fds,
4266 : timeout_ms));
4267 : #endif
4268 :
4269 : #if MG_ENABLE_BROADCAST
4270 0 : if (num_ev > 0 && mgr->ctl[1] != INVALID_SOCKET &&
4271 0 : FD_ISSET(mgr->ctl[1], &read_set)) {
4272 0 : mg_mgr_handle_ctl_sock(mgr);
4273 : }
4274 : #endif
4275 :
4276 0 : for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
4277 0 : int fd_flags = 0;
4278 0 : if (nc->sock != INVALID_SOCKET) {
4279 0 : if (num_ev > 0) {
4280 0 : fd_flags = (FD_ISSET(nc->sock, &read_set) &&
4281 0 : (!(nc->flags & MG_F_UDP) || nc->listener == NULL)
4282 0 : ? _MG_F_FD_CAN_READ
4283 0 : : 0) |
4284 0 : (FD_ISSET(nc->sock, &write_set) ? _MG_F_FD_CAN_WRITE : 0) |
4285 0 : (FD_ISSET(nc->sock, &err_set) ? _MG_F_FD_ERROR : 0);
4286 : }
4287 : #if MG_LWIP
4288 : /* With LWIP socket emulation layer, we don't get write events for UDP */
4289 : if ((nc->flags & MG_F_UDP) && nc->listener == NULL) {
4290 : fd_flags |= _MG_F_FD_CAN_WRITE;
4291 : }
4292 : #endif
4293 : }
4294 0 : tmp = nc->next;
4295 0 : mg_mgr_handle_conn(nc, fd_flags, now);
4296 : }
4297 :
4298 0 : return (time_t) now;
4299 : }
4300 :
4301 : #if MG_ENABLE_BROADCAST
4302 0 : MG_INTERNAL void mg_socketpair_close(sock_t *sock) {
4303 : while (1) {
4304 0 : if (closesocket(*sock) == -1 && errno == EINTR) continue;
4305 0 : break;
4306 : }
4307 0 : *sock = INVALID_SOCKET;
4308 0 : }
4309 :
4310 : MG_INTERNAL sock_t
4311 0 : mg_socketpair_accept(sock_t sock, union socket_address *sa, socklen_t sa_len) {
4312 : sock_t rc;
4313 : while (1) {
4314 0 : if ((rc = accept(sock, &sa->sa, &sa_len)) == INVALID_SOCKET &&
4315 0 : errno == EINTR)
4316 0 : continue;
4317 0 : break;
4318 : }
4319 0 : return rc;
4320 : }
4321 :
4322 0 : int mg_socketpair(sock_t sp[2], int sock_type) {
4323 : union socket_address sa, sa2;
4324 : sock_t sock;
4325 0 : socklen_t len = sizeof(sa.sin);
4326 0 : int ret = 0;
4327 :
4328 0 : sock = sp[0] = sp[1] = INVALID_SOCKET;
4329 :
4330 0 : (void) memset(&sa, 0, sizeof(sa));
4331 0 : sa.sin.sin_family = AF_INET;
4332 0 : sa.sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
4333 0 : sa2 = sa;
4334 :
4335 0 : if ((sock = socket(AF_INET, sock_type, 0)) == INVALID_SOCKET) {
4336 0 : } else if (bind(sock, &sa.sa, len) != 0) {
4337 0 : } else if (sock_type == SOCK_STREAM && listen(sock, 1) != 0) {
4338 0 : } else if (getsockname(sock, &sa.sa, &len) != 0) {
4339 0 : } else if ((sp[0] = socket(AF_INET, sock_type, 0)) == INVALID_SOCKET) {
4340 0 : } else if (sock_type == SOCK_STREAM && connect(sp[0], &sa.sa, len) != 0) {
4341 0 : } else if (sock_type == SOCK_DGRAM &&
4342 0 : (bind(sp[0], &sa2.sa, len) != 0 ||
4343 0 : getsockname(sp[0], &sa2.sa, &len) != 0 ||
4344 0 : connect(sp[0], &sa.sa, len) != 0 ||
4345 0 : connect(sock, &sa2.sa, len) != 0)) {
4346 0 : } else if ((sp[1] = (sock_type == SOCK_DGRAM ? sock : mg_socketpair_accept(
4347 0 : sock, &sa, len))) ==
4348 : INVALID_SOCKET) {
4349 : } else {
4350 0 : mg_set_close_on_exec(sp[0]);
4351 0 : mg_set_close_on_exec(sp[1]);
4352 0 : if (sock_type == SOCK_STREAM) mg_socketpair_close(&sock);
4353 0 : ret = 1;
4354 : }
4355 :
4356 0 : if (!ret) {
4357 0 : if (sp[0] != INVALID_SOCKET) mg_socketpair_close(&sp[0]);
4358 0 : if (sp[1] != INVALID_SOCKET) mg_socketpair_close(&sp[1]);
4359 0 : if (sock != INVALID_SOCKET) mg_socketpair_close(&sock);
4360 : }
4361 :
4362 0 : return ret;
4363 : }
4364 : #endif /* MG_ENABLE_BROADCAST */
4365 :
4366 0 : static void mg_sock_get_addr(sock_t sock, int remote,
4367 : union socket_address *sa) {
4368 0 : socklen_t slen = sizeof(*sa);
4369 0 : memset(sa, 0, slen);
4370 0 : if (remote) {
4371 0 : getpeername(sock, &sa->sa, &slen);
4372 : } else {
4373 0 : getsockname(sock, &sa->sa, &slen);
4374 : }
4375 0 : }
4376 :
4377 0 : void mg_sock_to_str(sock_t sock, char *buf, size_t len, int flags) {
4378 : union socket_address sa;
4379 0 : mg_sock_get_addr(sock, flags & MG_SOCK_STRINGIFY_REMOTE, &sa);
4380 0 : mg_sock_addr_to_str(&sa, buf, len, flags);
4381 0 : }
4382 :
4383 0 : void mg_socket_if_get_conn_addr(struct mg_connection *nc, int remote,
4384 : union socket_address *sa) {
4385 0 : if ((nc->flags & MG_F_UDP) && remote) {
4386 0 : memcpy(sa, &nc->sa, sizeof(*sa));
4387 0 : return;
4388 : }
4389 0 : mg_sock_get_addr(nc->sock, remote, sa);
4390 : }
4391 :
4392 : /* clang-format off */
4393 : #define MG_SOCKET_IFACE_VTABLE \
4394 : { \
4395 : mg_socket_if_init, \
4396 : mg_socket_if_free, \
4397 : mg_socket_if_add_conn, \
4398 : mg_socket_if_remove_conn, \
4399 : mg_socket_if_poll, \
4400 : mg_socket_if_listen_tcp, \
4401 : mg_socket_if_listen_udp, \
4402 : mg_socket_if_connect_tcp, \
4403 : mg_socket_if_connect_udp, \
4404 : mg_socket_if_tcp_send, \
4405 : mg_socket_if_udp_send, \
4406 : mg_socket_if_tcp_recv, \
4407 : mg_socket_if_udp_recv, \
4408 : mg_socket_if_create_conn, \
4409 : mg_socket_if_destroy_conn, \
4410 : mg_socket_if_sock_set, \
4411 : mg_socket_if_get_conn_addr, \
4412 : }
4413 : /* clang-format on */
4414 :
4415 : const struct mg_iface_vtable mg_socket_iface_vtable = MG_SOCKET_IFACE_VTABLE;
4416 : #if MG_NET_IF == MG_NET_IF_SOCKET
4417 : const struct mg_iface_vtable mg_default_iface_vtable = MG_SOCKET_IFACE_VTABLE;
4418 : #endif
4419 :
4420 : #endif /* MG_ENABLE_NET_IF_SOCKET */
4421 : #ifdef MG_MODULE_LINES
4422 : #line 1 "mongoose/src/mg_net_if_socks.c"
4423 : #endif
4424 : /*
4425 : * Copyright (c) 2014-2016 Cesanta Software Limited
4426 : * All rights reserved
4427 : */
4428 :
4429 : #if MG_ENABLE_SOCKS
4430 :
4431 : struct socksdata {
4432 : char *proxy_addr; /* HOST:PORT of the socks5 proxy server */
4433 : struct mg_connection *s; /* Respective connection to the server */
4434 : struct mg_connection *c; /* Connection to the client */
4435 : };
4436 :
4437 : static void socks_if_disband(struct socksdata *d) {
4438 : LOG(LL_DEBUG, ("disbanding proxy %p %p", d->c, d->s));
4439 : if (d->c) {
4440 : d->c->flags |= MG_F_SEND_AND_CLOSE;
4441 : d->c->user_data = NULL;
4442 : d->c = NULL;
4443 : }
4444 : if (d->s) {
4445 : d->s->flags |= MG_F_SEND_AND_CLOSE;
4446 : d->s->user_data = NULL;
4447 : d->s = NULL;
4448 : }
4449 : }
4450 :
4451 : static void socks_if_relay(struct mg_connection *s) {
4452 : struct socksdata *d = (struct socksdata *) s->user_data;
4453 : if (d == NULL || d->c == NULL || !(s->flags & MG_SOCKS_CONNECT_DONE) ||
4454 : d->s == NULL) {
4455 : return;
4456 : }
4457 : if (s->recv_mbuf.len > 0) mg_if_can_recv_cb(d->c);
4458 : if (d->c->send_mbuf.len > 0 && s->send_mbuf.len == 0) mg_if_can_send_cb(d->c);
4459 : }
4460 :
4461 : static void socks_if_handler(struct mg_connection *c, int ev, void *ev_data) {
4462 : struct socksdata *d = (struct socksdata *) c->user_data;
4463 : if (d == NULL) return;
4464 : if (ev == MG_EV_CONNECT) {
4465 : int res = *(int *) ev_data;
4466 : if (res == 0) {
4467 : /* Send handshake to the proxy server */
4468 : unsigned char buf[] = {MG_SOCKS_VERSION, 1, MG_SOCKS_HANDSHAKE_NOAUTH};
4469 : mg_send(d->s, buf, sizeof(buf));
4470 : LOG(LL_DEBUG, ("Sent handshake to %s", d->proxy_addr));
4471 : } else {
4472 : LOG(LL_ERROR, ("Cannot connect to %s: %d", d->proxy_addr, res));
4473 : d->c->flags |= MG_F_CLOSE_IMMEDIATELY;
4474 : }
4475 : } else if (ev == MG_EV_CLOSE) {
4476 : socks_if_disband(d);
4477 : } else if (ev == MG_EV_RECV) {
4478 : /* Handle handshake reply */
4479 : if (!(c->flags & MG_SOCKS_HANDSHAKE_DONE)) {
4480 : /* TODO(lsm): process IPv6 too */
4481 : unsigned char buf[10] = {MG_SOCKS_VERSION, MG_SOCKS_CMD_CONNECT, 0,
4482 : MG_SOCKS_ADDR_IPV4};
4483 : if (c->recv_mbuf.len < 2) return;
4484 : if ((unsigned char) c->recv_mbuf.buf[1] == MG_SOCKS_HANDSHAKE_FAILURE) {
4485 : LOG(LL_ERROR, ("Server kicked us out"));
4486 : socks_if_disband(d);
4487 : return;
4488 : }
4489 : mbuf_remove(&c->recv_mbuf, 2);
4490 : c->flags |= MG_SOCKS_HANDSHAKE_DONE;
4491 :
4492 : /* Send connect request */
4493 : memcpy(buf + 4, &d->c->sa.sin.sin_addr, 4);
4494 : memcpy(buf + 8, &d->c->sa.sin.sin_port, 2);
4495 : mg_send(c, buf, sizeof(buf));
4496 : LOG(LL_DEBUG, ("%p Sent connect request", c));
4497 : }
4498 : /* Process connect request */
4499 : if ((c->flags & MG_SOCKS_HANDSHAKE_DONE) &&
4500 : !(c->flags & MG_SOCKS_CONNECT_DONE)) {
4501 : if (c->recv_mbuf.len < 10) return;
4502 : if (c->recv_mbuf.buf[1] != MG_SOCKS_SUCCESS) {
4503 : LOG(LL_ERROR, ("Socks connection error: %d", c->recv_mbuf.buf[1]));
4504 : socks_if_disband(d);
4505 : return;
4506 : }
4507 : mbuf_remove(&c->recv_mbuf, 10);
4508 : c->flags |= MG_SOCKS_CONNECT_DONE;
4509 : LOG(LL_DEBUG, ("%p Connect done %p", c, d->c));
4510 : mg_if_connect_cb(d->c, 0);
4511 : }
4512 : socks_if_relay(c);
4513 : } else if (ev == MG_EV_SEND || ev == MG_EV_POLL) {
4514 : socks_if_relay(c);
4515 : }
4516 : }
4517 :
4518 : static void mg_socks_if_connect_tcp(struct mg_connection *c,
4519 : const union socket_address *sa) {
4520 : struct socksdata *d = (struct socksdata *) c->iface->data;
4521 : d->c = c;
4522 : d->s = mg_connect(c->mgr, d->proxy_addr, socks_if_handler);
4523 : d->s->user_data = d;
4524 : LOG(LL_DEBUG, ("%p %s %p %p", c, d->proxy_addr, d, d->s));
4525 : (void) sa;
4526 : }
4527 :
4528 : static void mg_socks_if_connect_udp(struct mg_connection *c) {
4529 : (void) c;
4530 : }
4531 :
4532 : static int mg_socks_if_listen_tcp(struct mg_connection *c,
4533 : union socket_address *sa) {
4534 : (void) c;
4535 : (void) sa;
4536 : return 0;
4537 : }
4538 :
4539 : static int mg_socks_if_listen_udp(struct mg_connection *c,
4540 : union socket_address *sa) {
4541 : (void) c;
4542 : (void) sa;
4543 : return -1;
4544 : }
4545 :
4546 : static int mg_socks_if_tcp_send(struct mg_connection *c, const void *buf,
4547 : size_t len) {
4548 : int res;
4549 : struct socksdata *d = (struct socksdata *) c->iface->data;
4550 : if (d->s == NULL) return -1;
4551 : res = (int) mbuf_append(&d->s->send_mbuf, buf, len);
4552 : DBG(("%p -> %d -> %p", c, res, d->s));
4553 : return res;
4554 : }
4555 :
4556 : static int mg_socks_if_udp_send(struct mg_connection *c, const void *buf,
4557 : size_t len) {
4558 : (void) c;
4559 : (void) buf;
4560 : (void) len;
4561 : return -1;
4562 : }
4563 :
4564 : int mg_socks_if_tcp_recv(struct mg_connection *c, void *buf, size_t len) {
4565 : struct socksdata *d = (struct socksdata *) c->iface->data;
4566 : if (d->s == NULL) return -1;
4567 : if (len > d->s->recv_mbuf.len) len = d->s->recv_mbuf.len;
4568 : if (len > 0) {
4569 : memcpy(buf, d->s->recv_mbuf.buf, len);
4570 : mbuf_remove(&d->s->recv_mbuf, len);
4571 : }
4572 : DBG(("%p <- %d <- %p", c, (int) len, d->s));
4573 : return len;
4574 : }
4575 :
4576 : int mg_socks_if_udp_recv(struct mg_connection *c, void *buf, size_t len,
4577 : union socket_address *sa, size_t *sa_len) {
4578 : (void) c;
4579 : (void) buf;
4580 : (void) len;
4581 : (void) sa;
4582 : (void) sa_len;
4583 : return -1;
4584 : }
4585 :
4586 : static int mg_socks_if_create_conn(struct mg_connection *c) {
4587 : (void) c;
4588 : return 1;
4589 : }
4590 :
4591 : static void mg_socks_if_destroy_conn(struct mg_connection *c) {
4592 : c->iface->vtable->free(c->iface);
4593 : MG_FREE(c->iface);
4594 : c->iface = NULL;
4595 : LOG(LL_DEBUG, ("%p", c));
4596 : }
4597 :
4598 : static void mg_socks_if_sock_set(struct mg_connection *c, sock_t sock) {
4599 : (void) c;
4600 : (void) sock;
4601 : }
4602 :
4603 : static void mg_socks_if_init(struct mg_iface *iface) {
4604 : (void) iface;
4605 : }
4606 :
4607 : static void mg_socks_if_free(struct mg_iface *iface) {
4608 : struct socksdata *d = (struct socksdata *) iface->data;
4609 : LOG(LL_DEBUG, ("%p", iface));
4610 : if (d != NULL) {
4611 : socks_if_disband(d);
4612 : MG_FREE(d->proxy_addr);
4613 : MG_FREE(d);
4614 : iface->data = NULL;
4615 : }
4616 : }
4617 :
4618 : static void mg_socks_if_add_conn(struct mg_connection *c) {
4619 : c->sock = INVALID_SOCKET;
4620 : }
4621 :
4622 : static void mg_socks_if_remove_conn(struct mg_connection *c) {
4623 : (void) c;
4624 : }
4625 :
4626 : static time_t mg_socks_if_poll(struct mg_iface *iface, int timeout_ms) {
4627 : LOG(LL_DEBUG, ("%p", iface));
4628 : (void) iface;
4629 : (void) timeout_ms;
4630 : return (time_t) cs_time();
4631 : }
4632 :
4633 : static void mg_socks_if_get_conn_addr(struct mg_connection *c, int remote,
4634 : union socket_address *sa) {
4635 : LOG(LL_DEBUG, ("%p", c));
4636 : (void) c;
4637 : (void) remote;
4638 : (void) sa;
4639 : }
4640 :
4641 : const struct mg_iface_vtable mg_socks_iface_vtable = {
4642 : mg_socks_if_init, mg_socks_if_free,
4643 : mg_socks_if_add_conn, mg_socks_if_remove_conn,
4644 : mg_socks_if_poll, mg_socks_if_listen_tcp,
4645 : mg_socks_if_listen_udp, mg_socks_if_connect_tcp,
4646 : mg_socks_if_connect_udp, mg_socks_if_tcp_send,
4647 : mg_socks_if_udp_send, mg_socks_if_tcp_recv,
4648 : mg_socks_if_udp_recv, mg_socks_if_create_conn,
4649 : mg_socks_if_destroy_conn, mg_socks_if_sock_set,
4650 : mg_socks_if_get_conn_addr,
4651 : };
4652 :
4653 : struct mg_iface *mg_socks_mk_iface(struct mg_mgr *mgr, const char *proxy_addr) {
4654 : struct mg_iface *iface = mg_if_create_iface(&mg_socks_iface_vtable, mgr);
4655 : iface->data = MG_CALLOC(1, sizeof(struct socksdata));
4656 : ((struct socksdata *) iface->data)->proxy_addr = strdup(proxy_addr);
4657 : return iface;
4658 : }
4659 :
4660 : #endif
4661 : #ifdef MG_MODULE_LINES
4662 : #line 1 "mongoose/src/mg_ssl_if_openssl.c"
4663 : #endif
4664 : /*
4665 : * Copyright (c) 2014-2016 Cesanta Software Limited
4666 : * All rights reserved
4667 : */
4668 :
4669 : #if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_OPENSSL
4670 :
4671 : #ifdef __APPLE__
4672 : #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
4673 : #endif
4674 :
4675 : #include <openssl/ssl.h>
4676 : #ifndef KR_VERSION
4677 : #include <openssl/tls1.h>
4678 : #endif
4679 :
4680 : struct mg_ssl_if_ctx {
4681 : SSL *ssl;
4682 : SSL_CTX *ssl_ctx;
4683 : struct mbuf psk;
4684 : size_t identity_len;
4685 : };
4686 :
4687 : void mg_ssl_if_init() {
4688 : SSL_library_init();
4689 : }
4690 :
4691 : enum mg_ssl_if_result mg_ssl_if_conn_accept(struct mg_connection *nc,
4692 : struct mg_connection *lc) {
4693 : struct mg_ssl_if_ctx *ctx =
4694 : (struct mg_ssl_if_ctx *) MG_CALLOC(1, sizeof(*ctx));
4695 : struct mg_ssl_if_ctx *lc_ctx = (struct mg_ssl_if_ctx *) lc->ssl_if_data;
4696 : nc->ssl_if_data = ctx;
4697 : if (ctx == NULL || lc_ctx == NULL) return MG_SSL_ERROR;
4698 : ctx->ssl_ctx = lc_ctx->ssl_ctx;
4699 : if ((ctx->ssl = SSL_new(ctx->ssl_ctx)) == NULL) {
4700 : return MG_SSL_ERROR;
4701 : }
4702 : return MG_SSL_OK;
4703 : }
4704 :
4705 : static enum mg_ssl_if_result mg_use_cert(SSL_CTX *ctx, const char *cert,
4706 : const char *key, const char **err_msg);
4707 : static enum mg_ssl_if_result mg_use_ca_cert(SSL_CTX *ctx, const char *cert);
4708 : static enum mg_ssl_if_result mg_set_cipher_list(SSL_CTX *ctx, const char *cl);
4709 : static enum mg_ssl_if_result mg_ssl_if_ossl_set_psk(struct mg_ssl_if_ctx *ctx,
4710 : const char *identity,
4711 : const char *key_str);
4712 :
4713 : enum mg_ssl_if_result mg_ssl_if_conn_init(
4714 : struct mg_connection *nc, const struct mg_ssl_if_conn_params *params,
4715 : const char **err_msg) {
4716 : struct mg_ssl_if_ctx *ctx =
4717 : (struct mg_ssl_if_ctx *) MG_CALLOC(1, sizeof(*ctx));
4718 : DBG(("%p %s,%s,%s", nc, (params->cert ? params->cert : ""),
4719 : (params->key ? params->key : ""),
4720 : (params->ca_cert ? params->ca_cert : "")));
4721 : if (ctx == NULL) {
4722 : MG_SET_PTRPTR(err_msg, "Out of memory");
4723 : return MG_SSL_ERROR;
4724 : }
4725 : nc->ssl_if_data = ctx;
4726 : if (nc->flags & MG_F_LISTENING) {
4727 : ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
4728 : } else {
4729 : ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
4730 : }
4731 : if (ctx->ssl_ctx == NULL) {
4732 : MG_SET_PTRPTR(err_msg, "Failed to create SSL context");
4733 : return MG_SSL_ERROR;
4734 : }
4735 :
4736 : #ifndef KR_VERSION
4737 : /* Disable deprecated protocols. */
4738 : SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2);
4739 : SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv3);
4740 : SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1);
4741 : #ifdef MG_SSL_OPENSSL_NO_COMPRESSION
4742 : SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_COMPRESSION);
4743 : #endif
4744 : #ifdef MG_SSL_OPENSSL_CIPHER_SERVER_PREFERENCE
4745 : SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
4746 : #endif
4747 : #else
4748 : /* Krypton only supports TLSv1.2 anyway. */
4749 : #endif
4750 :
4751 : if (params->cert != NULL &&
4752 : mg_use_cert(ctx->ssl_ctx, params->cert, params->key, err_msg) !=
4753 : MG_SSL_OK) {
4754 : return MG_SSL_ERROR;
4755 : }
4756 :
4757 : if (params->ca_cert != NULL &&
4758 : mg_use_ca_cert(ctx->ssl_ctx, params->ca_cert) != MG_SSL_OK) {
4759 : MG_SET_PTRPTR(err_msg, "Invalid SSL CA cert");
4760 : return MG_SSL_ERROR;
4761 : }
4762 :
4763 : if (mg_set_cipher_list(ctx->ssl_ctx, params->cipher_suites) != MG_SSL_OK) {
4764 : MG_SET_PTRPTR(err_msg, "Invalid cipher suite list");
4765 : return MG_SSL_ERROR;
4766 : }
4767 :
4768 : mbuf_init(&ctx->psk, 0);
4769 : if (mg_ssl_if_ossl_set_psk(ctx, params->psk_identity, params->psk_key) !=
4770 : MG_SSL_OK) {
4771 : MG_SET_PTRPTR(err_msg, "Invalid PSK settings");
4772 : return MG_SSL_ERROR;
4773 : }
4774 :
4775 : if (!(nc->flags & MG_F_LISTENING) &&
4776 : (ctx->ssl = SSL_new(ctx->ssl_ctx)) == NULL) {
4777 : MG_SET_PTRPTR(err_msg, "Failed to create SSL session");
4778 : return MG_SSL_ERROR;
4779 : }
4780 :
4781 : if (params->server_name != NULL) {
4782 : #ifdef KR_VERSION
4783 : SSL_CTX_kr_set_verify_name(ctx->ssl_ctx, params->server_name);
4784 : #else
4785 : SSL_set_tlsext_host_name(ctx->ssl, params->server_name);
4786 : #endif
4787 : }
4788 :
4789 : nc->flags |= MG_F_SSL;
4790 :
4791 : return MG_SSL_OK;
4792 : }
4793 :
4794 : static enum mg_ssl_if_result mg_ssl_if_ssl_err(struct mg_connection *nc,
4795 : int res) {
4796 : struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
4797 : int err = SSL_get_error(ctx->ssl, res);
4798 : if (err == SSL_ERROR_WANT_READ) return MG_SSL_WANT_READ;
4799 : if (err == SSL_ERROR_WANT_WRITE) return MG_SSL_WANT_WRITE;
4800 : DBG(("%p %p SSL error: %d %d", nc, ctx->ssl_ctx, res, err));
4801 : nc->err = err;
4802 : return MG_SSL_ERROR;
4803 : }
4804 :
4805 : enum mg_ssl_if_result mg_ssl_if_handshake(struct mg_connection *nc) {
4806 : struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
4807 : int server_side = (nc->listener != NULL);
4808 : int res;
4809 : /* If descriptor is not yet set, do it now. */
4810 : if (SSL_get_fd(ctx->ssl) < 0) {
4811 : if (SSL_set_fd(ctx->ssl, nc->sock) != 1) return MG_SSL_ERROR;
4812 : }
4813 : res = server_side ? SSL_accept(ctx->ssl) : SSL_connect(ctx->ssl);
4814 : if (res != 1) return mg_ssl_if_ssl_err(nc, res);
4815 : return MG_SSL_OK;
4816 : }
4817 :
4818 : int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t buf_size) {
4819 : struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
4820 : int n = SSL_read(ctx->ssl, buf, buf_size);
4821 : DBG(("%p %d -> %d", nc, (int) buf_size, n));
4822 : if (n < 0) return mg_ssl_if_ssl_err(nc, n);
4823 : if (n == 0) nc->flags |= MG_F_CLOSE_IMMEDIATELY;
4824 : return n;
4825 : }
4826 :
4827 : int mg_ssl_if_write(struct mg_connection *nc, const void *data, size_t len) {
4828 : struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
4829 : int n = SSL_write(ctx->ssl, data, len);
4830 : DBG(("%p %d -> %d", nc, (int) len, n));
4831 : if (n <= 0) return mg_ssl_if_ssl_err(nc, n);
4832 : return n;
4833 : }
4834 :
4835 : void mg_ssl_if_conn_close_notify(struct mg_connection *nc) {
4836 : struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
4837 : if (ctx == NULL) return;
4838 : SSL_shutdown(ctx->ssl);
4839 : }
4840 :
4841 : void mg_ssl_if_conn_free(struct mg_connection *nc) {
4842 : struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
4843 : if (ctx == NULL) return;
4844 : nc->ssl_if_data = NULL;
4845 : if (ctx->ssl != NULL) SSL_free(ctx->ssl);
4846 : if (ctx->ssl_ctx != NULL && nc->listener == NULL) SSL_CTX_free(ctx->ssl_ctx);
4847 : mbuf_free(&ctx->psk);
4848 : memset(ctx, 0, sizeof(*ctx));
4849 : MG_FREE(ctx);
4850 : }
4851 :
4852 : /*
4853 : * Cipher suite options used for TLS negotiation.
4854 : * https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations
4855 : */
4856 : static const char mg_s_cipher_list[] =
4857 : #if defined(MG_SSL_CRYPTO_MODERN)
4858 : "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:"
4859 : "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:"
4860 : "DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:"
4861 : "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:"
4862 : "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:"
4863 : "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:"
4864 : "DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:"
4865 : "DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:"
4866 : "!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK"
4867 : #elif defined(MG_SSL_CRYPTO_OLD)
4868 : "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:"
4869 : "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:"
4870 : "DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:"
4871 : "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:"
4872 : "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:"
4873 : "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:"
4874 : "DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:"
4875 : "DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:"
4876 : "ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:"
4877 : "AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:"
4878 : "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:"
4879 : "!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"
4880 : #else /* Default - intermediate. */
4881 : "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:"
4882 : "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:"
4883 : "DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:"
4884 : "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:"
4885 : "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:"
4886 : "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:"
4887 : "DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:"
4888 : "DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:"
4889 : "AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:"
4890 : "DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:"
4891 : "!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:"
4892 : "!CAMELLIA:"
4893 : "!RSA:"
4894 : "!DES:"
4895 : "!3DES"
4896 : //TLS_RSA_WITH_AES_128_CBC_SHA256
4897 : #endif
4898 : ;
4899 :
4900 : /*
4901 : * Default DH params for PFS cipher negotiation. This is a 2048-bit group.
4902 : * Will be used if none are provided by the user in the certificate file.
4903 : */
4904 : #if !MG_DISABLE_PFS && !defined(KR_VERSION)
4905 : static const char mg_s_default_dh_params[] =
4906 : "\
4907 : -----BEGIN DH PARAMETERS-----\n\
4908 : MIIBCAKCAQEAlvbgD/qh9znWIlGFcV0zdltD7rq8FeShIqIhkQ0C7hYFThrBvF2E\n\
4909 : Z9bmgaP+sfQwGpVlv9mtaWjvERbu6mEG7JTkgmVUJrUt/wiRzwTaCXBqZkdUO8Tq\n\
4910 : +E6VOEQAilstG90ikN1Tfo+K6+X68XkRUIlgawBTKuvKVwBhuvlqTGerOtnXWnrt\n\
4911 : ym//hd3cd5PBYGBix0i7oR4xdghvfR2WLVu0LgdThTBb6XP7gLd19cQ1JuBtAajZ\n\
4912 : wMuPn7qlUkEFDIkAZy59/Hue/H2Q2vU/JsvVhHWCQBL4F1ofEAt50il6ZxR1QfFK\n\
4913 : 9VGKDC4oOgm9DlxwwBoC2FjqmvQlqVV3kwIBAg==\n\
4914 : -----END DH PARAMETERS-----\n";
4915 : #endif
4916 :
4917 : static enum mg_ssl_if_result mg_use_ca_cert(SSL_CTX *ctx, const char *cert) {
4918 : if (cert == NULL || strcmp(cert, "*") == 0) {
4919 : return MG_SSL_OK;
4920 : }
4921 : SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);
4922 : return SSL_CTX_load_verify_locations(ctx, cert, NULL) == 1 ? MG_SSL_OK
4923 : : MG_SSL_ERROR;
4924 : }
4925 :
4926 : static enum mg_ssl_if_result mg_use_cert(SSL_CTX *ctx, const char *cert,
4927 : const char *key,
4928 : const char **err_msg) {
4929 : if (key == NULL) key = cert;
4930 : if (cert == NULL || cert[0] == '\0' || key == NULL || key[0] == '\0') {
4931 : return MG_SSL_OK;
4932 : } else if (SSL_CTX_use_certificate_file(ctx, cert, 1) == 0) {
4933 : MG_SET_PTRPTR(err_msg, "Invalid SSL cert");
4934 : return MG_SSL_ERROR;
4935 : } else if (SSL_CTX_use_PrivateKey_file(ctx, key, 1) == 0) {
4936 : MG_SET_PTRPTR(err_msg, "Invalid SSL key");
4937 : return MG_SSL_ERROR;
4938 : } else if (SSL_CTX_use_certificate_chain_file(ctx, cert) == 0) {
4939 : MG_SET_PTRPTR(err_msg, "Invalid CA bundle");
4940 : return MG_SSL_ERROR;
4941 : } else {
4942 : SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
4943 : #if !MG_DISABLE_PFS && !defined(KR_VERSION)
4944 : BIO *bio = NULL;
4945 : DH *dh = NULL;
4946 :
4947 : /* Try to read DH parameters from the cert/key file. */
4948 : bio = BIO_new_file(cert, "r");
4949 : if (bio != NULL) {
4950 : dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
4951 : BIO_free(bio);
4952 : }
4953 : /*
4954 : * If there are no DH params in the file, fall back to hard-coded ones.
4955 : * Not ideal, but better than nothing.
4956 : */
4957 : if (dh == NULL) {
4958 : bio = BIO_new_mem_buf((void *) mg_s_default_dh_params, -1);
4959 : dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
4960 : BIO_free(bio);
4961 : }
4962 : if (dh != NULL) {
4963 : SSL_CTX_set_tmp_dh(ctx, dh);
4964 : SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);
4965 : DH_free(dh);
4966 : }
4967 : #if OPENSSL_VERSION_NUMBER > 0x10002000L
4968 : SSL_CTX_set_ecdh_auto(ctx, 1);
4969 : #endif
4970 : #endif
4971 : }
4972 : return MG_SSL_OK;
4973 : }
4974 :
4975 : static enum mg_ssl_if_result mg_set_cipher_list(SSL_CTX *ctx, const char *cl) {
4976 : return (SSL_CTX_set_cipher_list(ctx, cl ? cl : mg_s_cipher_list) == 1
4977 : ? MG_SSL_OK
4978 : : MG_SSL_ERROR);
4979 : }
4980 :
4981 : #if !defined(KR_VERSION) && !defined(LIBRESSL_VERSION_NUMBER)
4982 : static unsigned int mg_ssl_if_ossl_psk_cb(SSL *ssl, const char *hint,
4983 : char *identity,
4984 : unsigned int max_identity_len,
4985 : unsigned char *psk,
4986 : unsigned int max_psk_len) {
4987 : struct mg_ssl_if_ctx *ctx =
4988 : (struct mg_ssl_if_ctx *) SSL_CTX_get_app_data(SSL_get_SSL_CTX(ssl));
4989 : size_t key_len = ctx->psk.len - ctx->identity_len - 1;
4990 : DBG(("hint: '%s'", (hint ? hint : "")));
4991 : if (ctx->identity_len + 1 > max_identity_len) {
4992 : DBG(("identity too long"));
4993 : return 0;
4994 : }
4995 : if (key_len > max_psk_len) {
4996 : DBG(("key too long"));
4997 : return 0;
4998 : }
4999 : memcpy(identity, ctx->psk.buf, ctx->identity_len + 1);
5000 : memcpy(psk, ctx->psk.buf + ctx->identity_len + 1, key_len);
5001 : (void) ssl;
5002 : return key_len;
5003 : }
5004 :
5005 : static enum mg_ssl_if_result mg_ssl_if_ossl_set_psk(struct mg_ssl_if_ctx *ctx,
5006 : const char *identity,
5007 : const char *key_str) {
5008 : unsigned char key[32];
5009 : size_t key_len;
5010 : size_t i = 0;
5011 : if (identity == NULL && key_str == NULL) return MG_SSL_OK;
5012 : if (identity == NULL || key_str == NULL) return MG_SSL_ERROR;
5013 : key_len = strlen(key_str);
5014 : if (key_len != 32 && key_len != 64) return MG_SSL_ERROR;
5015 : memset(key, 0, sizeof(key));
5016 : key_len = 0;
5017 : for (i = 0; key_str[i] != '\0'; i++) {
5018 : unsigned char c;
5019 : char hc = tolower((int) key_str[i]);
5020 : if (hc >= '0' && hc <= '9') {
5021 : c = hc - '0';
5022 : } else if (hc >= 'a' && hc <= 'f') {
5023 : c = hc - 'a' + 0xa;
5024 : } else {
5025 : return MG_SSL_ERROR;
5026 : }
5027 : key_len = i / 2;
5028 : key[key_len] <<= 4;
5029 : key[key_len] |= c;
5030 : }
5031 : key_len++;
5032 : DBG(("identity = '%s', key = (%u)", identity, (unsigned int) key_len));
5033 : ctx->identity_len = strlen(identity);
5034 : mbuf_append(&ctx->psk, identity, ctx->identity_len + 1);
5035 : mbuf_append(&ctx->psk, key, key_len);
5036 : SSL_CTX_set_psk_client_callback(ctx->ssl_ctx, mg_ssl_if_ossl_psk_cb);
5037 : SSL_CTX_set_app_data(ctx->ssl_ctx, ctx);
5038 : return MG_SSL_OK;
5039 : }
5040 : #else
5041 : static enum mg_ssl_if_result mg_ssl_if_ossl_set_psk(struct mg_ssl_if_ctx *ctx,
5042 : const char *identity,
5043 : const char *key_str) {
5044 : (void) ctx;
5045 : (void) identity;
5046 : (void) key_str;
5047 : /* Krypton / LibreSSL does not support PSK. */
5048 : return MG_SSL_ERROR;
5049 : }
5050 : #endif /* !defined(KR_VERSION) && !defined(LIBRESSL_VERSION_NUMBER) */
5051 :
5052 : const char *mg_set_ssl(struct mg_connection *nc, const char *cert,
5053 : const char *ca_cert) {
5054 : const char *err_msg = NULL;
5055 : struct mg_ssl_if_conn_params params;
5056 : memset(¶ms, 0, sizeof(params));
5057 : params.cert = cert;
5058 : params.ca_cert = ca_cert;
5059 : if (mg_ssl_if_conn_init(nc, ¶ms, &err_msg) != MG_SSL_OK) {
5060 : return err_msg;
5061 : }
5062 : return NULL;
5063 : }
5064 :
5065 : #endif /* MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_OPENSSL */
5066 : #ifdef MG_MODULE_LINES
5067 : #line 1 "mongoose/src/mg_ssl_if_mbedtls.c"
5068 : #endif
5069 : /*
5070 : * Copyright (c) 2014-2016 Cesanta Software Limited
5071 : * All rights reserved
5072 : */
5073 :
5074 : #if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_MBEDTLS
5075 :
5076 : #include <mbedtls/debug.h>
5077 : #include <mbedtls/ecp.h>
5078 : #include <mbedtls/net.h>
5079 : #include <mbedtls/platform.h>
5080 : #include <mbedtls/ssl.h>
5081 : #include <mbedtls/ssl_internal.h>
5082 : #include <mbedtls/x509_crt.h>
5083 : #include <mbedtls/version.h>
5084 :
5085 : static void mg_ssl_mbed_log(void *ctx, int level, const char *file, int line,
5086 : const char *str) {
5087 : enum cs_log_level cs_level;
5088 : switch (level) {
5089 : case 1:
5090 : cs_level = LL_ERROR;
5091 : break;
5092 : case 2:
5093 : cs_level = LL_INFO;
5094 : break;
5095 : case 3:
5096 : cs_level = LL_DEBUG;
5097 : break;
5098 : default:
5099 : cs_level = LL_VERBOSE_DEBUG;
5100 : }
5101 : /* mbedTLS passes strings with \n at the end, strip it. */
5102 : LOG(cs_level, ("%p %.*s", ctx, (int) (strlen(str) - 1), str));
5103 : (void) ctx;
5104 : (void) str;
5105 : (void) file;
5106 : (void) line;
5107 : (void) cs_level;
5108 : }
5109 :
5110 : struct mg_ssl_if_ctx {
5111 : mbedtls_ssl_config *conf;
5112 : mbedtls_ssl_context *ssl;
5113 : mbedtls_x509_crt *cert;
5114 : mbedtls_pk_context *key;
5115 : mbedtls_x509_crt *ca_cert;
5116 : struct mbuf cipher_suites;
5117 : size_t saved_len;
5118 : };
5119 :
5120 : /* Must be provided by the platform. ctx is struct mg_connection. */
5121 : extern int mg_ssl_if_mbed_random(void *ctx, unsigned char *buf, size_t len);
5122 :
5123 : void mg_ssl_if_init() {
5124 : LOG(LL_INFO, ("%s", MBEDTLS_VERSION_STRING_FULL));
5125 : }
5126 :
5127 : enum mg_ssl_if_result mg_ssl_if_conn_accept(struct mg_connection *nc,
5128 : struct mg_connection *lc) {
5129 : struct mg_ssl_if_ctx *ctx =
5130 : (struct mg_ssl_if_ctx *) MG_CALLOC(1, sizeof(*ctx));
5131 : struct mg_ssl_if_ctx *lc_ctx = (struct mg_ssl_if_ctx *) lc->ssl_if_data;
5132 : nc->ssl_if_data = ctx;
5133 : if (ctx == NULL || lc_ctx == NULL) return MG_SSL_ERROR;
5134 : ctx->ssl = (mbedtls_ssl_context *) MG_CALLOC(1, sizeof(*ctx->ssl));
5135 : if (mbedtls_ssl_setup(ctx->ssl, lc_ctx->conf) != 0) {
5136 : return MG_SSL_ERROR;
5137 : }
5138 : return MG_SSL_OK;
5139 : }
5140 :
5141 : static enum mg_ssl_if_result mg_use_cert(struct mg_ssl_if_ctx *ctx,
5142 : const char *cert, const char *key,
5143 : const char **err_msg);
5144 : static enum mg_ssl_if_result mg_use_ca_cert(struct mg_ssl_if_ctx *ctx,
5145 : const char *cert);
5146 : static enum mg_ssl_if_result mg_set_cipher_list(struct mg_ssl_if_ctx *ctx,
5147 : const char *ciphers);
5148 : #ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED
5149 : static enum mg_ssl_if_result mg_ssl_if_mbed_set_psk(struct mg_ssl_if_ctx *ctx,
5150 : const char *identity,
5151 : const char *key);
5152 : #endif
5153 :
5154 : enum mg_ssl_if_result mg_ssl_if_conn_init(
5155 : struct mg_connection *nc, const struct mg_ssl_if_conn_params *params,
5156 : const char **err_msg) {
5157 : struct mg_ssl_if_ctx *ctx =
5158 : (struct mg_ssl_if_ctx *) MG_CALLOC(1, sizeof(*ctx));
5159 : DBG(("%p %s,%s,%s", nc, (params->cert ? params->cert : ""),
5160 : (params->key ? params->key : ""),
5161 : (params->ca_cert ? params->ca_cert : "")));
5162 :
5163 : if (ctx == NULL) {
5164 : MG_SET_PTRPTR(err_msg, "Out of memory");
5165 : return MG_SSL_ERROR;
5166 : }
5167 : nc->ssl_if_data = ctx;
5168 : ctx->conf = (mbedtls_ssl_config *) MG_CALLOC(1, sizeof(*ctx->conf));
5169 : mbuf_init(&ctx->cipher_suites, 0);
5170 : mbedtls_ssl_config_init(ctx->conf);
5171 : mbedtls_ssl_conf_dbg(ctx->conf, mg_ssl_mbed_log, nc);
5172 : if (mbedtls_ssl_config_defaults(
5173 : ctx->conf, (nc->flags & MG_F_LISTENING ? MBEDTLS_SSL_IS_SERVER
5174 : : MBEDTLS_SSL_IS_CLIENT),
5175 : MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT) != 0) {
5176 : MG_SET_PTRPTR(err_msg, "Failed to init SSL config");
5177 : return MG_SSL_ERROR;
5178 : }
5179 :
5180 : /* TLS 1.2 and up */
5181 : mbedtls_ssl_conf_min_version(ctx->conf, MBEDTLS_SSL_MAJOR_VERSION_3,
5182 : MBEDTLS_SSL_MINOR_VERSION_3);
5183 : mbedtls_ssl_conf_rng(ctx->conf, mg_ssl_if_mbed_random, nc);
5184 :
5185 : if (params->cert != NULL &&
5186 : mg_use_cert(ctx, params->cert, params->key, err_msg) != MG_SSL_OK) {
5187 : return MG_SSL_ERROR;
5188 : }
5189 :
5190 : if (params->ca_cert != NULL &&
5191 : mg_use_ca_cert(ctx, params->ca_cert) != MG_SSL_OK) {
5192 : MG_SET_PTRPTR(err_msg, "Invalid SSL CA cert");
5193 : return MG_SSL_ERROR;
5194 : }
5195 :
5196 : if (mg_set_cipher_list(ctx, params->cipher_suites) != MG_SSL_OK) {
5197 : MG_SET_PTRPTR(err_msg, "Invalid cipher suite list");
5198 : return MG_SSL_ERROR;
5199 : }
5200 :
5201 : #ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED
5202 : if (mg_ssl_if_mbed_set_psk(ctx, params->psk_identity, params->psk_key) !=
5203 : MG_SSL_OK) {
5204 : MG_SET_PTRPTR(err_msg, "Invalid PSK settings");
5205 : return MG_SSL_ERROR;
5206 : }
5207 : #endif
5208 :
5209 : if (!(nc->flags & MG_F_LISTENING)) {
5210 : ctx->ssl = (mbedtls_ssl_context *) MG_CALLOC(1, sizeof(*ctx->ssl));
5211 : mbedtls_ssl_init(ctx->ssl);
5212 : if (mbedtls_ssl_setup(ctx->ssl, ctx->conf) != 0) {
5213 : MG_SET_PTRPTR(err_msg, "Failed to create SSL session");
5214 : return MG_SSL_ERROR;
5215 : }
5216 : if (params->server_name != NULL &&
5217 : mbedtls_ssl_set_hostname(ctx->ssl, params->server_name) != 0) {
5218 : return MG_SSL_ERROR;
5219 : }
5220 : }
5221 :
5222 : #ifdef MG_SSL_IF_MBEDTLS_MAX_FRAG_LEN
5223 : if (mbedtls_ssl_conf_max_frag_len(ctx->conf,
5224 : #if MG_SSL_IF_MBEDTLS_MAX_FRAG_LEN == 512
5225 : MBEDTLS_SSL_MAX_FRAG_LEN_512
5226 : #elif MG_SSL_IF_MBEDTLS_MAX_FRAG_LEN == 1024
5227 : MBEDTLS_SSL_MAX_FRAG_LEN_1024
5228 : #elif MG_SSL_IF_MBEDTLS_MAX_FRAG_LEN == 2048
5229 : MBEDTLS_SSL_MAX_FRAG_LEN_2048
5230 : #elif MG_SSL_IF_MBEDTLS_MAX_FRAG_LEN == 4096
5231 : MBEDTLS_SSL_MAX_FRAG_LEN_4096
5232 : #else
5233 : #error Invalid MG_SSL_IF_MBEDTLS_MAX_FRAG_LEN
5234 : #endif
5235 : ) != 0) {
5236 : return MG_SSL_ERROR;
5237 : }
5238 : #endif
5239 :
5240 : nc->flags |= MG_F_SSL;
5241 :
5242 : return MG_SSL_OK;
5243 : }
5244 :
5245 : static int mg_ssl_if_mbed_send(void *ctx, const unsigned char *buf,
5246 : size_t len) {
5247 : struct mg_connection *nc = (struct mg_connection *) ctx;
5248 : int n = nc->iface->vtable->tcp_send(nc, buf, len);
5249 : if (n > 0) return n;
5250 : if (n == 0) return MBEDTLS_ERR_SSL_WANT_WRITE;
5251 : return MBEDTLS_ERR_NET_SEND_FAILED;
5252 : }
5253 :
5254 : static int mg_ssl_if_mbed_recv(void *ctx, unsigned char *buf, size_t len) {
5255 : struct mg_connection *nc = (struct mg_connection *) ctx;
5256 : int n = nc->iface->vtable->tcp_recv(nc, buf, len);
5257 : if (n > 0) return n;
5258 : if (n == 0) return MBEDTLS_ERR_SSL_WANT_READ;
5259 : return MBEDTLS_ERR_NET_RECV_FAILED;
5260 : }
5261 :
5262 : static enum mg_ssl_if_result mg_ssl_if_mbed_err(struct mg_connection *nc,
5263 : int ret) {
5264 : enum mg_ssl_if_result res = MG_SSL_OK;
5265 : if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
5266 : res = MG_SSL_WANT_READ;
5267 : } else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
5268 : res = MG_SSL_WANT_WRITE;
5269 : } else if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
5270 : LOG(LL_DEBUG, ("%p TLS connection closed by peer", nc));
5271 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
5272 : res = MG_SSL_OK;
5273 : } else if (ret == MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE) {
5274 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
5275 : res = MG_SSL_ERROR;
5276 : } else if (ret == MBEDTLS_ERR_SSL_INVALID_MAC) {
5277 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
5278 : res = MG_SSL_ERROR;
5279 : } else if (ret == MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION) {
5280 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
5281 : res = MG_SSL_ERROR;
5282 : } else if (ret == MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE) {
5283 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
5284 : res = MG_SSL_ERROR;
5285 : } else if (ret == MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN) {
5286 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
5287 : res = MG_SSL_ERROR;
5288 : } else if (ret == MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE) {
5289 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
5290 : res = MG_SSL_ERROR;
5291 : } else if (ret == MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO) {
5292 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
5293 : res = MG_SSL_ERROR;
5294 : } else if (ret == MBEDTLS_ERR_NET_RECV_FAILED) {
5295 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
5296 : res = MG_SSL_ERROR;
5297 : } else {
5298 : LOG(LL_ERROR, ("%p mbedTLS error: -0x%04x", nc, -ret));
5299 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
5300 : res = MG_SSL_ERROR;
5301 : }
5302 : nc->err = ret;
5303 : return res;
5304 : }
5305 :
5306 : static void mg_ssl_if_mbed_free_certs_and_keys(struct mg_ssl_if_ctx *ctx) {
5307 : if (ctx->cert != NULL) {
5308 : mbedtls_x509_crt_free(ctx->cert);
5309 : MG_FREE(ctx->cert);
5310 : ctx->cert = NULL;
5311 : mbedtls_pk_free(ctx->key);
5312 : MG_FREE(ctx->key);
5313 : ctx->key = NULL;
5314 : }
5315 : if (ctx->ca_cert != NULL) {
5316 : mbedtls_ssl_conf_ca_chain(ctx->conf, NULL, NULL);
5317 : #ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK
5318 : if (ctx->conf->ca_chain_file != NULL) {
5319 : MG_FREE((void *) ctx->conf->ca_chain_file);
5320 : ctx->conf->ca_chain_file = NULL;
5321 : }
5322 : #endif
5323 : mbedtls_x509_crt_free(ctx->ca_cert);
5324 : MG_FREE(ctx->ca_cert);
5325 : ctx->ca_cert = NULL;
5326 : }
5327 : }
5328 :
5329 : enum mg_ssl_if_result mg_ssl_if_handshake(struct mg_connection *nc) {
5330 : struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
5331 : int err;
5332 : /* If bio is not yet set, do it now. */
5333 : if (ctx->ssl->p_bio == NULL) {
5334 : mbedtls_ssl_set_bio(ctx->ssl, nc, mg_ssl_if_mbed_send, mg_ssl_if_mbed_recv,
5335 : NULL);
5336 : }
5337 : err = mbedtls_ssl_handshake(ctx->ssl);
5338 : if (err != 0) return mg_ssl_if_mbed_err(nc, err);
5339 : #ifdef MG_SSL_IF_MBEDTLS_FREE_CERTS
5340 : /*
5341 : * Free the peer certificate, we don't need it after handshake.
5342 : * Note that this effectively disables renegotiation.
5343 : */
5344 : mbedtls_x509_crt_free(ctx->ssl->session->peer_cert);
5345 : mbedtls_free(ctx->ssl->session->peer_cert);
5346 : ctx->ssl->session->peer_cert = NULL;
5347 : /* On a client connection we can also free our own and CA certs. */
5348 : if (nc->listener == NULL) {
5349 : if (ctx->conf->key_cert != NULL) {
5350 : /* Note that this assumes one key_cert entry, which matches our init. */
5351 : MG_FREE(ctx->conf->key_cert);
5352 : ctx->conf->key_cert = NULL;
5353 : }
5354 : mbedtls_ssl_conf_ca_chain(ctx->conf, NULL, NULL);
5355 : mg_ssl_if_mbed_free_certs_and_keys(ctx);
5356 : }
5357 : #endif
5358 : return MG_SSL_OK;
5359 : }
5360 :
5361 : int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t len) {
5362 : struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
5363 : int n = mbedtls_ssl_read(ctx->ssl, (unsigned char *) buf, len);
5364 : DBG(("%p %d -> %d", nc, (int) len, n));
5365 : if (n < 0) return mg_ssl_if_mbed_err(nc, n);
5366 : if (n == 0) nc->flags |= MG_F_CLOSE_IMMEDIATELY;
5367 : return n;
5368 : }
5369 :
5370 : int mg_ssl_if_write(struct mg_connection *nc, const void *buf, size_t len) {
5371 : struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
5372 : /* Per mbedTLS docs, if write returns WANT_READ or WANT_WRITE, the operation
5373 : * should be retried with the same data and length.
5374 : * Here we assume that the data being pushed will remain the same but the
5375 : * amount may grow between calls so we save the length that was used and
5376 : * retry. The assumption being that the data itself won't change and won't
5377 : * be removed. */
5378 : size_t l = len;
5379 : if (ctx->saved_len > 0 && ctx->saved_len < l) l = ctx->saved_len;
5380 : int n = mbedtls_ssl_write(ctx->ssl, (const unsigned char *) buf, l);
5381 : DBG(("%p %d,%d,%d -> %d", nc, (int) len, (int) ctx->saved_len, (int) l, n));
5382 : if (n < 0) {
5383 : if (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE) {
5384 : ctx->saved_len = len;
5385 : }
5386 : return mg_ssl_if_mbed_err(nc, n);
5387 : } else if (n > 0) {
5388 : ctx->saved_len = 0;
5389 : }
5390 : return n;
5391 : }
5392 :
5393 : void mg_ssl_if_conn_close_notify(struct mg_connection *nc) {
5394 : struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
5395 : if (ctx == NULL) return;
5396 : mbedtls_ssl_close_notify(ctx->ssl);
5397 : }
5398 :
5399 : void mg_ssl_if_conn_free(struct mg_connection *nc) {
5400 : struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
5401 : if (ctx == NULL) return;
5402 : nc->ssl_if_data = NULL;
5403 : if (ctx->ssl != NULL) {
5404 : mbedtls_ssl_free(ctx->ssl);
5405 : MG_FREE(ctx->ssl);
5406 : }
5407 : mg_ssl_if_mbed_free_certs_and_keys(ctx);
5408 : if (ctx->conf != NULL) {
5409 : mbedtls_ssl_config_free(ctx->conf);
5410 : MG_FREE(ctx->conf);
5411 : }
5412 : mbuf_free(&ctx->cipher_suites);
5413 : memset(ctx, 0, sizeof(*ctx));
5414 : MG_FREE(ctx);
5415 : }
5416 :
5417 : static enum mg_ssl_if_result mg_use_ca_cert(struct mg_ssl_if_ctx *ctx,
5418 : const char *ca_cert) {
5419 : if (ca_cert == NULL || strcmp(ca_cert, "*") == 0) {
5420 : mbedtls_ssl_conf_authmode(ctx->conf, MBEDTLS_SSL_VERIFY_NONE);
5421 : return MG_SSL_OK;
5422 : }
5423 : ctx->ca_cert = (mbedtls_x509_crt *) MG_CALLOC(1, sizeof(*ctx->ca_cert));
5424 : mbedtls_x509_crt_init(ctx->ca_cert);
5425 : #ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK
5426 : ca_cert = strdup(ca_cert);
5427 : mbedtls_ssl_conf_ca_chain_file(ctx->conf, ca_cert, NULL);
5428 : #else
5429 : if (mbedtls_x509_crt_parse_file(ctx->ca_cert, ca_cert) != 0) {
5430 : return MG_SSL_ERROR;
5431 : }
5432 : mbedtls_ssl_conf_ca_chain(ctx->conf, ctx->ca_cert, NULL);
5433 : #endif
5434 : mbedtls_ssl_conf_authmode(ctx->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
5435 : return MG_SSL_OK;
5436 : }
5437 :
5438 : static enum mg_ssl_if_result mg_use_cert(struct mg_ssl_if_ctx *ctx,
5439 : const char *cert, const char *key,
5440 : const char **err_msg) {
5441 : if (key == NULL) key = cert;
5442 : if (cert == NULL || cert[0] == '\0' || key == NULL || key[0] == '\0') {
5443 : return MG_SSL_OK;
5444 : }
5445 : ctx->cert = (mbedtls_x509_crt *) MG_CALLOC(1, sizeof(*ctx->cert));
5446 : mbedtls_x509_crt_init(ctx->cert);
5447 : ctx->key = (mbedtls_pk_context *) MG_CALLOC(1, sizeof(*ctx->key));
5448 : mbedtls_pk_init(ctx->key);
5449 : if (mbedtls_x509_crt_parse_file(ctx->cert, cert) != 0) {
5450 : MG_SET_PTRPTR(err_msg, "Invalid SSL cert");
5451 : return MG_SSL_ERROR;
5452 : }
5453 : if (mbedtls_pk_parse_keyfile(ctx->key, key, NULL) != 0) {
5454 : MG_SET_PTRPTR(err_msg, "Invalid SSL key");
5455 : return MG_SSL_ERROR;
5456 : }
5457 : if (mbedtls_ssl_conf_own_cert(ctx->conf, ctx->cert, ctx->key) != 0) {
5458 : MG_SET_PTRPTR(err_msg, "Invalid SSL key or cert");
5459 : return MG_SSL_ERROR;
5460 : }
5461 : return MG_SSL_OK;
5462 : }
5463 :
5464 : static const int mg_s_cipher_list[] = {
5465 : #if CS_PLATFORM != CS_P_ESP8266
5466 : MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
5467 : MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
5468 : MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
5469 : MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
5470 : MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
5471 : MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
5472 : MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
5473 : MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
5474 : MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
5475 : MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
5476 : MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
5477 : MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
5478 : MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256,
5479 : MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256,
5480 : MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA,
5481 : #else
5482 : /*
5483 : * ECDHE is way too slow on ESP8266 w/o cryptochip, this sometimes results
5484 : * in WiFi STA deauths. Use weaker but faster cipher suites. Sad but true.
5485 : * Disable DHE completely because it's just hopelessly slow.
5486 : */
5487 : MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256,
5488 : MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256,
5489 : MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
5490 : MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
5491 : MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
5492 : MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
5493 : MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
5494 : MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
5495 : MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
5496 : MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
5497 : MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
5498 : MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
5499 : MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA,
5500 : #endif /* CS_PLATFORM != CS_P_ESP8266 */
5501 : 0,
5502 : };
5503 :
5504 : /*
5505 : * Ciphers can be specified as a colon-separated list of cipher suite names.
5506 : * These can be found in
5507 : * https://github.com/ARMmbed/mbedtls/blob/development/library/ssl_ciphersuites.c#L267
5508 : * E.g.: TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-CCM
5509 : */
5510 : static enum mg_ssl_if_result mg_set_cipher_list(struct mg_ssl_if_ctx *ctx,
5511 : const char *ciphers) {
5512 : if (ciphers != NULL) {
5513 : int l, id;
5514 : const char *s = ciphers, *e;
5515 : char tmp[50];
5516 : while (s != NULL) {
5517 : e = strchr(s, ':');
5518 : l = (e != NULL ? (e - s) : (int) strlen(s));
5519 : strncpy(tmp, s, l);
5520 : tmp[l] = '\0';
5521 : id = mbedtls_ssl_get_ciphersuite_id(tmp);
5522 : DBG(("%s -> %04x", tmp, id));
5523 : if (id != 0) {
5524 : mbuf_append(&ctx->cipher_suites, &id, sizeof(id));
5525 : }
5526 : s = (e != NULL ? e + 1 : NULL);
5527 : }
5528 : if (ctx->cipher_suites.len == 0) return MG_SSL_ERROR;
5529 : id = 0;
5530 : mbuf_append(&ctx->cipher_suites, &id, sizeof(id));
5531 : mbuf_trim(&ctx->cipher_suites);
5532 : mbedtls_ssl_conf_ciphersuites(ctx->conf,
5533 : (const int *) ctx->cipher_suites.buf);
5534 : } else {
5535 : mbedtls_ssl_conf_ciphersuites(ctx->conf, mg_s_cipher_list);
5536 : }
5537 : return MG_SSL_OK;
5538 : }
5539 :
5540 : #ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED
5541 : static enum mg_ssl_if_result mg_ssl_if_mbed_set_psk(struct mg_ssl_if_ctx *ctx,
5542 : const char *identity,
5543 : const char *key_str) {
5544 : unsigned char key[32];
5545 : size_t key_len;
5546 : if (identity == NULL && key_str == NULL) return MG_SSL_OK;
5547 : if (identity == NULL || key_str == NULL) return MG_SSL_ERROR;
5548 : key_len = strlen(key_str);
5549 : if (key_len != 32 && key_len != 64) return MG_SSL_ERROR;
5550 : size_t i = 0;
5551 : memset(key, 0, sizeof(key));
5552 : key_len = 0;
5553 : for (i = 0; key_str[i] != '\0'; i++) {
5554 : unsigned char c;
5555 : char hc = tolower((int) key_str[i]);
5556 : if (hc >= '0' && hc <= '9') {
5557 : c = hc - '0';
5558 : } else if (hc >= 'a' && hc <= 'f') {
5559 : c = hc - 'a' + 0xa;
5560 : } else {
5561 : return MG_SSL_ERROR;
5562 : }
5563 : key_len = i / 2;
5564 : key[key_len] <<= 4;
5565 : key[key_len] |= c;
5566 : }
5567 : key_len++;
5568 : DBG(("identity = '%s', key = (%u)", identity, (unsigned int) key_len));
5569 : /* mbedTLS makes copies of psk and identity. */
5570 : if (mbedtls_ssl_conf_psk(ctx->conf, (const unsigned char *) key, key_len,
5571 : (const unsigned char *) identity,
5572 : strlen(identity)) != 0) {
5573 : return MG_SSL_ERROR;
5574 : }
5575 : return MG_SSL_OK;
5576 : }
5577 : #endif
5578 :
5579 : const char *mg_set_ssl(struct mg_connection *nc, const char *cert,
5580 : const char *ca_cert) {
5581 : const char *err_msg = NULL;
5582 : struct mg_ssl_if_conn_params params;
5583 : memset(¶ms, 0, sizeof(params));
5584 : params.cert = cert;
5585 : params.ca_cert = ca_cert;
5586 : if (mg_ssl_if_conn_init(nc, ¶ms, &err_msg) != MG_SSL_OK) {
5587 : return err_msg;
5588 : }
5589 : return NULL;
5590 : }
5591 :
5592 : /* Lazy RNG. Warning: it would be a bad idea to do this in production! */
5593 : #ifdef MG_SSL_MBED_DUMMY_RANDOM
5594 : int mg_ssl_if_mbed_random(void *ctx, unsigned char *buf, size_t len) {
5595 : (void) ctx;
5596 : while (len--) *buf++ = rand();
5597 : return 0;
5598 : }
5599 : #endif
5600 :
5601 : #endif /* MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_MBEDTLS */
5602 : #ifdef MG_MODULE_LINES
5603 : #line 1 "mongoose/src/mg_uri.c"
5604 : #endif
5605 : /*
5606 : * Copyright (c) 2014 Cesanta Software Limited
5607 : * All rights reserved
5608 : */
5609 :
5610 : /* Amalgamated: #include "mg_internal.h" */
5611 : /* Amalgamated: #include "mg_uri.h" */
5612 :
5613 : /*
5614 : * scan string until encountering one of `seps`, keeping track of component
5615 : * boundaries in `res`.
5616 : *
5617 : * `p` will point to the char after the separator or it will be `end`.
5618 : */
5619 0 : static void parse_uri_component(const char **p, const char *end,
5620 : const char *seps, struct mg_str *res) {
5621 : const char *q;
5622 0 : res->p = *p;
5623 0 : for (; *p < end; (*p)++) {
5624 0 : for (q = seps; *q != '\0'; q++) {
5625 0 : if (**p == *q) break;
5626 : }
5627 0 : if (*q != '\0') break;
5628 : }
5629 0 : res->len = (*p) - res->p;
5630 0 : if (*p < end) (*p)++;
5631 0 : }
5632 :
5633 0 : int mg_parse_uri(const struct mg_str uri, struct mg_str *scheme,
5634 : struct mg_str *user_info, struct mg_str *host,
5635 : unsigned int *port, struct mg_str *path, struct mg_str *query,
5636 : struct mg_str *fragment) {
5637 0 : struct mg_str rscheme = {0, 0}, ruser_info = {0, 0}, rhost = {0, 0},
5638 0 : rpath = {0, 0}, rquery = {0, 0}, rfragment = {0, 0};
5639 0 : unsigned int rport = 0;
5640 : enum {
5641 : P_START,
5642 : P_SCHEME_OR_PORT,
5643 : P_USER_INFO,
5644 : P_HOST,
5645 : P_PORT,
5646 : P_REST
5647 0 : } state = P_START;
5648 :
5649 0 : const char *p = uri.p, *end = p + uri.len;
5650 0 : while (p < end) {
5651 0 : switch (state) {
5652 0 : case P_START:
5653 : /*
5654 : * expecting on of:
5655 : * - `scheme://xxxx`
5656 : * - `xxxx:port`
5657 : * - `[a:b:c]:port`
5658 : * - `xxxx/path`
5659 : */
5660 0 : if (*p == '[') {
5661 0 : state = P_HOST;
5662 0 : break;
5663 : }
5664 0 : for (; p < end; p++) {
5665 0 : if (*p == ':') {
5666 0 : state = P_SCHEME_OR_PORT;
5667 0 : break;
5668 0 : } else if (*p == '/') {
5669 0 : state = P_REST;
5670 0 : break;
5671 : }
5672 : }
5673 0 : if (state == P_START || state == P_REST) {
5674 0 : rhost.p = uri.p;
5675 0 : rhost.len = p - uri.p;
5676 : }
5677 0 : break;
5678 0 : case P_SCHEME_OR_PORT:
5679 0 : if (end - p >= 3 && strncmp(p, "://", 3) == 0) {
5680 0 : rscheme.p = uri.p;
5681 0 : rscheme.len = p - uri.p;
5682 0 : state = P_USER_INFO;
5683 0 : p += 3;
5684 : } else {
5685 0 : rhost.p = uri.p;
5686 0 : rhost.len = p - uri.p;
5687 0 : state = P_PORT;
5688 : }
5689 0 : break;
5690 0 : case P_USER_INFO:
5691 0 : ruser_info.p = p;
5692 0 : for (; p < end; p++) {
5693 0 : if (*p == '@' || *p == '[' || *p == '/') {
5694 : break;
5695 : }
5696 : }
5697 0 : if (p == end || *p == '/' || *p == '[') {
5698 : /* backtrack and parse as host */
5699 0 : p = ruser_info.p;
5700 : }
5701 0 : ruser_info.len = p - ruser_info.p;
5702 0 : state = P_HOST;
5703 0 : break;
5704 0 : case P_HOST:
5705 0 : if (*p == '@') p++;
5706 0 : rhost.p = p;
5707 0 : if (*p == '[') {
5708 0 : int found = 0;
5709 0 : for (; !found && p < end; p++) {
5710 0 : found = (*p == ']');
5711 : }
5712 0 : if (!found) return -1;
5713 : } else {
5714 0 : for (; p < end; p++) {
5715 0 : if (*p == ':' || *p == '/') break;
5716 : }
5717 : }
5718 0 : rhost.len = p - rhost.p;
5719 0 : if (p < end) {
5720 0 : if (*p == ':') {
5721 0 : state = P_PORT;
5722 0 : break;
5723 0 : } else if (*p == '/') {
5724 0 : state = P_REST;
5725 0 : break;
5726 : }
5727 : }
5728 0 : break;
5729 0 : case P_PORT:
5730 0 : p++;
5731 0 : for (; p < end; p++) {
5732 0 : if (*p == '/') {
5733 0 : state = P_REST;
5734 0 : break;
5735 : }
5736 0 : rport *= 10;
5737 0 : rport += *p - '0';
5738 : }
5739 0 : break;
5740 0 : case P_REST:
5741 : /* `p` points to separator. `path` includes the separator */
5742 0 : parse_uri_component(&p, end, "?#", &rpath);
5743 0 : if (p < end && *(p - 1) == '?') {
5744 0 : parse_uri_component(&p, end, "#", &rquery);
5745 : }
5746 0 : parse_uri_component(&p, end, "", &rfragment);
5747 0 : break;
5748 : }
5749 : }
5750 :
5751 0 : if (scheme != 0) *scheme = rscheme;
5752 0 : if (user_info != 0) *user_info = ruser_info;
5753 0 : if (host != 0) *host = rhost;
5754 0 : if (port != 0) *port = rport;
5755 0 : if (path != 0) *path = rpath;
5756 0 : if (query != 0) *query = rquery;
5757 0 : if (fragment != 0) *fragment = rfragment;
5758 :
5759 0 : return 0;
5760 : }
5761 :
5762 : /* Normalize the URI path. Remove/resolve "." and "..". */
5763 0 : int mg_normalize_uri_path(const struct mg_str *in, struct mg_str *out) {
5764 0 : const char *s = in->p, *se = s + in->len;
5765 0 : char *cp = (char *) out->p, *d;
5766 :
5767 0 : if (in->len == 0 || *s != '/') {
5768 0 : out->len = 0;
5769 0 : return 0;
5770 : }
5771 :
5772 0 : d = cp;
5773 :
5774 0 : while (s < se) {
5775 0 : const char *next = s;
5776 : struct mg_str component;
5777 0 : parse_uri_component(&next, se, "/", &component);
5778 0 : if (mg_vcmp(&component, ".") == 0) {
5779 : /* Yum. */
5780 0 : } else if (mg_vcmp(&component, "..") == 0) {
5781 : /* Backtrack to previous slash. */
5782 0 : if (d > cp + 1 && *(d - 1) == '/') d--;
5783 0 : while (d > cp && *(d - 1) != '/') d--;
5784 : } else {
5785 0 : memmove(d, s, next - s);
5786 0 : d += next - s;
5787 : }
5788 0 : s = next;
5789 : }
5790 0 : if (d == cp) *d++ = '/';
5791 :
5792 0 : out->p = cp;
5793 0 : out->len = d - cp;
5794 0 : return 1;
5795 : }
5796 :
5797 0 : int mg_assemble_uri(const struct mg_str *scheme, const struct mg_str *user_info,
5798 : const struct mg_str *host, unsigned int port,
5799 : const struct mg_str *path, const struct mg_str *query,
5800 : const struct mg_str *fragment, int normalize_path,
5801 : struct mg_str *uri) {
5802 0 : int result = -1;
5803 : struct mbuf out;
5804 0 : mbuf_init(&out, 0);
5805 :
5806 0 : if (scheme != NULL && scheme->len > 0) {
5807 0 : mbuf_append(&out, scheme->p, scheme->len);
5808 0 : mbuf_append(&out, "://", 3);
5809 : }
5810 :
5811 0 : if (user_info != NULL && user_info->len > 0) {
5812 0 : mbuf_append(&out, user_info->p, user_info->len);
5813 0 : mbuf_append(&out, "@", 1);
5814 : }
5815 :
5816 0 : if (host != NULL && host->len > 0) {
5817 0 : mbuf_append(&out, host->p, host->len);
5818 : }
5819 :
5820 0 : if (port != 0) {
5821 : char port_str[20];
5822 0 : int port_str_len = sprintf(port_str, ":%u", port);
5823 0 : mbuf_append(&out, port_str, port_str_len);
5824 : }
5825 :
5826 0 : if (path != NULL && path->len > 0) {
5827 0 : if (normalize_path) {
5828 0 : struct mg_str npath = mg_strdup(*path);
5829 0 : if (npath.len != path->len) goto out;
5830 0 : if (!mg_normalize_uri_path(path, &npath)) {
5831 0 : free((void *) npath.p);
5832 0 : goto out;
5833 : }
5834 0 : mbuf_append(&out, npath.p, npath.len);
5835 0 : free((void *) npath.p);
5836 : } else {
5837 0 : mbuf_append(&out, path->p, path->len);
5838 : }
5839 0 : } else if (normalize_path) {
5840 0 : mbuf_append(&out, "/", 1);
5841 : }
5842 :
5843 0 : if (query != NULL && query->len > 0) {
5844 0 : mbuf_append(&out, "?", 1);
5845 0 : mbuf_append(&out, query->p, query->len);
5846 : }
5847 :
5848 0 : if (fragment != NULL && fragment->len > 0) {
5849 0 : mbuf_append(&out, "#", 1);
5850 0 : mbuf_append(&out, fragment->p, fragment->len);
5851 : }
5852 :
5853 0 : result = 0;
5854 :
5855 0 : out:
5856 0 : if (result == 0) {
5857 0 : uri->p = out.buf;
5858 0 : uri->len = out.len;
5859 : } else {
5860 0 : mbuf_free(&out);
5861 0 : uri->p = NULL;
5862 0 : uri->len = 0;
5863 : }
5864 0 : return result;
5865 : }
5866 : #ifdef MG_MODULE_LINES
5867 : #line 1 "mongoose/src/mg_http.c"
5868 : #endif
5869 : /*
5870 : * Copyright (c) 2014 Cesanta Software Limited
5871 : * All rights reserved
5872 : */
5873 :
5874 : #if MG_ENABLE_HTTP
5875 :
5876 : /* Amalgamated: #include "common/cs_md5.h" */
5877 : /* Amalgamated: #include "mg_internal.h" */
5878 : /* Amalgamated: #include "mg_util.h" */
5879 :
5880 : /* altbuf {{{ */
5881 :
5882 : /*
5883 : * Alternate buffer: fills the client-provided buffer with data; and if it's
5884 : * not large enough, allocates another buffer (via mbuf), similar to asprintf.
5885 : */
5886 : struct altbuf {
5887 : struct mbuf m;
5888 : char *user_buf;
5889 : size_t len;
5890 : size_t user_buf_size;
5891 : };
5892 :
5893 : /*
5894 : * Initializes altbuf; `buf`, `buf_size` is the client-provided buffer.
5895 : */
5896 0 : MG_INTERNAL void altbuf_init(struct altbuf *ab, char *buf, size_t buf_size) {
5897 0 : mbuf_init(&ab->m, 0);
5898 0 : ab->user_buf = buf;
5899 0 : ab->user_buf_size = buf_size;
5900 0 : ab->len = 0;
5901 0 : }
5902 :
5903 : /*
5904 : * Appends a single char to the altbuf.
5905 : */
5906 0 : MG_INTERNAL void altbuf_append(struct altbuf *ab, char c) {
5907 0 : if (ab->len < ab->user_buf_size) {
5908 : /* The data fits into the original buffer */
5909 0 : ab->user_buf[ab->len++] = c;
5910 : } else {
5911 : /* The data can't fit into the original buffer, so write it to mbuf. */
5912 :
5913 : /*
5914 : * First of all, see if that's the first byte which overflows the original
5915 : * buffer: if so, copy the existing data from there to a newly allocated
5916 : * mbuf.
5917 : */
5918 0 : if (ab->len > 0 && ab->m.len == 0) {
5919 0 : mbuf_append(&ab->m, ab->user_buf, ab->len);
5920 : }
5921 :
5922 0 : mbuf_append(&ab->m, &c, 1);
5923 0 : ab->len = ab->m.len;
5924 : }
5925 0 : }
5926 :
5927 : /*
5928 : * Resets any data previously appended to altbuf.
5929 : */
5930 0 : MG_INTERNAL void altbuf_reset(struct altbuf *ab) {
5931 0 : mbuf_free(&ab->m);
5932 0 : ab->len = 0;
5933 0 : }
5934 :
5935 : /*
5936 : * Returns whether the additional buffer was allocated (and thus the data
5937 : * is in the mbuf, not the client-provided buffer)
5938 : */
5939 0 : MG_INTERNAL int altbuf_reallocated(struct altbuf *ab) {
5940 0 : return ab->len > ab->user_buf_size;
5941 : }
5942 :
5943 : /*
5944 : * Returns the actual buffer with data, either the client-provided or a newly
5945 : * allocated one. If `trim` is non-zero, mbuf-backed buffer is trimmed first.
5946 : */
5947 0 : MG_INTERNAL char *altbuf_get_buf(struct altbuf *ab, int trim) {
5948 0 : if (altbuf_reallocated(ab)) {
5949 0 : if (trim) {
5950 0 : mbuf_trim(&ab->m);
5951 : }
5952 0 : return ab->m.buf;
5953 : } else {
5954 0 : return ab->user_buf;
5955 : }
5956 : }
5957 :
5958 : /* }}} */
5959 :
5960 : static const char *mg_version_header = "Mongoose/" MG_VERSION;
5961 :
5962 : enum mg_http_proto_data_type { DATA_NONE, DATA_FILE, DATA_PUT };
5963 :
5964 : struct mg_http_proto_data_file {
5965 : FILE *fp; /* Opened file. */
5966 : int64_t cl; /* Content-Length. How many bytes to send. */
5967 : int64_t sent; /* How many bytes have been already sent. */
5968 : int keepalive; /* Keep connection open after sending. */
5969 : enum mg_http_proto_data_type type;
5970 : };
5971 :
5972 : #if MG_ENABLE_HTTP_CGI
5973 : struct mg_http_proto_data_cgi {
5974 : struct mg_connection *cgi_nc;
5975 : };
5976 : #endif
5977 :
5978 : struct mg_http_proto_data_chuncked {
5979 : int64_t body_len; /* How many bytes of chunked body was reassembled. */
5980 : };
5981 :
5982 : struct mg_http_endpoint {
5983 : struct mg_http_endpoint *next;
5984 : struct mg_str uri_pattern; /* owned */
5985 : char *auth_domain; /* owned */
5986 : char *auth_file; /* owned */
5987 :
5988 : mg_event_handler_t handler;
5989 : #if MG_ENABLE_CALLBACK_USERDATA
5990 : void *user_data;
5991 : #endif
5992 : };
5993 :
5994 : enum mg_http_multipart_stream_state {
5995 : MPS_BEGIN,
5996 : MPS_WAITING_FOR_BOUNDARY,
5997 : MPS_WAITING_FOR_CHUNK,
5998 : MPS_GOT_BOUNDARY,
5999 : MPS_FINALIZE,
6000 : MPS_FINISHED
6001 : };
6002 :
6003 : struct mg_http_multipart_stream {
6004 : const char *boundary;
6005 : int boundary_len;
6006 : const char *var_name;
6007 : const char *file_name;
6008 : void *user_data;
6009 : enum mg_http_multipart_stream_state state;
6010 : int processing_part;
6011 : int data_avail;
6012 : };
6013 :
6014 : struct mg_reverse_proxy_data {
6015 : struct mg_connection *linked_conn;
6016 : };
6017 :
6018 : struct mg_ws_proto_data {
6019 : /*
6020 : * Defragmented size of the frame so far.
6021 : *
6022 : * First byte of nc->recv_mbuf.buf is an op, the rest of the data is
6023 : * defragmented data.
6024 : */
6025 : size_t reass_len;
6026 : };
6027 :
6028 : struct mg_http_proto_data {
6029 : #if MG_ENABLE_FILESYSTEM
6030 : struct mg_http_proto_data_file file;
6031 : #endif
6032 : #if MG_ENABLE_HTTP_CGI
6033 : struct mg_http_proto_data_cgi cgi;
6034 : #endif
6035 : #if MG_ENABLE_HTTP_STREAMING_MULTIPART
6036 : struct mg_http_multipart_stream mp_stream;
6037 : #endif
6038 : #if MG_ENABLE_HTTP_WEBSOCKET
6039 : struct mg_ws_proto_data ws_data;
6040 : #endif
6041 : struct mg_http_proto_data_chuncked chunk;
6042 : struct mg_http_endpoint *endpoints;
6043 : mg_event_handler_t endpoint_handler;
6044 : struct mg_reverse_proxy_data reverse_proxy_data;
6045 : size_t rcvd; /* How many bytes we have received. */
6046 : };
6047 :
6048 : static void mg_http_proto_data_destructor(void *proto_data);
6049 :
6050 : struct mg_connection *mg_connect_http_base(
6051 : struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data),
6052 : struct mg_connect_opts opts, const char *scheme1, const char *scheme2,
6053 : const char *scheme_ssl1, const char *scheme_ssl2, const char *url,
6054 : struct mg_str *path, struct mg_str *user_info, struct mg_str *host);
6055 :
6056 0 : MG_INTERNAL struct mg_http_proto_data *mg_http_create_proto_data(
6057 : struct mg_connection *c) {
6058 : /* If we have proto data from previous connection, flush it. */
6059 0 : if (c->proto_data != NULL) {
6060 0 : void *pd = c->proto_data;
6061 0 : c->proto_data = NULL;
6062 0 : mg_http_proto_data_destructor(pd);
6063 : }
6064 0 : c->proto_data = MG_CALLOC(1, sizeof(struct mg_http_proto_data));
6065 0 : c->proto_data_destructor = mg_http_proto_data_destructor;
6066 0 : return (struct mg_http_proto_data *) c->proto_data;
6067 : }
6068 :
6069 0 : static struct mg_http_proto_data *mg_http_get_proto_data(
6070 : struct mg_connection *c) {
6071 0 : return (struct mg_http_proto_data *) c->proto_data;
6072 : }
6073 :
6074 : #if MG_ENABLE_HTTP_STREAMING_MULTIPART
6075 : static void mg_http_free_proto_data_mp_stream(
6076 : struct mg_http_multipart_stream *mp) {
6077 : MG_FREE((void *) mp->boundary);
6078 : MG_FREE((void *) mp->var_name);
6079 : MG_FREE((void *) mp->file_name);
6080 : memset(mp, 0, sizeof(*mp));
6081 : }
6082 : #endif
6083 :
6084 : #if MG_ENABLE_FILESYSTEM
6085 0 : static void mg_http_free_proto_data_file(struct mg_http_proto_data_file *d) {
6086 0 : if (d != NULL) {
6087 0 : if (d->fp != NULL) {
6088 0 : fclose(d->fp);
6089 : }
6090 0 : memset(d, 0, sizeof(struct mg_http_proto_data_file));
6091 : }
6092 0 : }
6093 : #endif
6094 :
6095 0 : static void mg_http_free_proto_data_endpoints(struct mg_http_endpoint **ep) {
6096 0 : struct mg_http_endpoint *current = *ep;
6097 :
6098 0 : while (current != NULL) {
6099 0 : struct mg_http_endpoint *tmp = current->next;
6100 0 : MG_FREE((void *) current->uri_pattern.p);
6101 0 : MG_FREE((void *) current->auth_domain);
6102 0 : MG_FREE((void *) current->auth_file);
6103 0 : MG_FREE(current);
6104 0 : current = tmp;
6105 : }
6106 :
6107 0 : ep = NULL;
6108 0 : }
6109 :
6110 0 : static void mg_http_free_reverse_proxy_data(struct mg_reverse_proxy_data *rpd) {
6111 0 : if (rpd->linked_conn != NULL) {
6112 : /*
6113 : * Connection has linked one, we have to unlink & close it
6114 : * since _this_ connection is going to die and
6115 : * it doesn't make sense to keep another one
6116 : */
6117 0 : struct mg_http_proto_data *pd = mg_http_get_proto_data(rpd->linked_conn);
6118 0 : if (pd->reverse_proxy_data.linked_conn != NULL) {
6119 0 : pd->reverse_proxy_data.linked_conn->flags |= MG_F_SEND_AND_CLOSE;
6120 0 : pd->reverse_proxy_data.linked_conn = NULL;
6121 : }
6122 0 : rpd->linked_conn = NULL;
6123 : }
6124 0 : }
6125 :
6126 0 : static void mg_http_proto_data_destructor(void *proto_data) {
6127 0 : struct mg_http_proto_data *pd = (struct mg_http_proto_data *) proto_data;
6128 : #if MG_ENABLE_FILESYSTEM
6129 0 : mg_http_free_proto_data_file(&pd->file);
6130 : #endif
6131 : #if MG_ENABLE_HTTP_CGI
6132 0 : mg_http_free_proto_data_cgi(&pd->cgi);
6133 : #endif
6134 : #if MG_ENABLE_HTTP_STREAMING_MULTIPART
6135 : mg_http_free_proto_data_mp_stream(&pd->mp_stream);
6136 : #endif
6137 0 : mg_http_free_proto_data_endpoints(&pd->endpoints);
6138 0 : mg_http_free_reverse_proxy_data(&pd->reverse_proxy_data);
6139 0 : MG_FREE(proto_data);
6140 0 : }
6141 :
6142 : #if MG_ENABLE_FILESYSTEM
6143 :
6144 : #define MIME_ENTRY(_ext, _type) \
6145 : { _ext, sizeof(_ext) - 1, _type }
6146 : static const struct {
6147 : const char *extension;
6148 : size_t ext_len;
6149 : const char *mime_type;
6150 : } mg_static_builtin_mime_types[] = {
6151 : MIME_ENTRY("html", "text/html"),
6152 : MIME_ENTRY("html", "text/html"),
6153 : MIME_ENTRY("htm", "text/html"),
6154 : MIME_ENTRY("shtm", "text/html"),
6155 : MIME_ENTRY("shtml", "text/html"),
6156 : MIME_ENTRY("css", "text/css"),
6157 : MIME_ENTRY("js", "application/x-javascript"),
6158 : MIME_ENTRY("ico", "image/x-icon"),
6159 : MIME_ENTRY("gif", "image/gif"),
6160 : MIME_ENTRY("jpg", "image/jpeg"),
6161 : MIME_ENTRY("jpeg", "image/jpeg"),
6162 : MIME_ENTRY("png", "image/png"),
6163 : MIME_ENTRY("svg", "image/svg+xml"),
6164 : MIME_ENTRY("txt", "text/plain"),
6165 : MIME_ENTRY("torrent", "application/x-bittorrent"),
6166 : MIME_ENTRY("wav", "audio/x-wav"),
6167 : MIME_ENTRY("mp3", "audio/x-mp3"),
6168 : MIME_ENTRY("mid", "audio/mid"),
6169 : MIME_ENTRY("m3u", "audio/x-mpegurl"),
6170 : MIME_ENTRY("ogg", "application/ogg"),
6171 : MIME_ENTRY("ram", "audio/x-pn-realaudio"),
6172 : MIME_ENTRY("xml", "text/xml"),
6173 : MIME_ENTRY("ttf", "application/x-font-ttf"),
6174 : MIME_ENTRY("json", "application/json"),
6175 : MIME_ENTRY("xslt", "application/xml"),
6176 : MIME_ENTRY("xsl", "application/xml"),
6177 : MIME_ENTRY("ra", "audio/x-pn-realaudio"),
6178 : MIME_ENTRY("doc", "application/msword"),
6179 : MIME_ENTRY("exe", "application/octet-stream"),
6180 : MIME_ENTRY("zip", "application/x-zip-compressed"),
6181 : MIME_ENTRY("xls", "application/excel"),
6182 : MIME_ENTRY("tgz", "application/x-tar-gz"),
6183 : MIME_ENTRY("tar", "application/x-tar"),
6184 : MIME_ENTRY("gz", "application/x-gunzip"),
6185 : MIME_ENTRY("arj", "application/x-arj-compressed"),
6186 : MIME_ENTRY("rar", "application/x-rar-compressed"),
6187 : MIME_ENTRY("rtf", "application/rtf"),
6188 : MIME_ENTRY("pdf", "application/pdf"),
6189 : MIME_ENTRY("swf", "application/x-shockwave-flash"),
6190 : MIME_ENTRY("mpg", "video/mpeg"),
6191 : MIME_ENTRY("webm", "video/webm"),
6192 : MIME_ENTRY("mpeg", "video/mpeg"),
6193 : MIME_ENTRY("mov", "video/quicktime"),
6194 : MIME_ENTRY("mp4", "video/mp4"),
6195 : MIME_ENTRY("m4v", "video/x-m4v"),
6196 : MIME_ENTRY("asf", "video/x-ms-asf"),
6197 : MIME_ENTRY("avi", "video/x-msvideo"),
6198 : MIME_ENTRY("bmp", "image/bmp"),
6199 : {NULL, 0, NULL}};
6200 :
6201 0 : static struct mg_str mg_get_mime_type(const char *path, const char *dflt,
6202 : const struct mg_serve_http_opts *opts) {
6203 : const char *ext, *overrides;
6204 : size_t i, path_len;
6205 : struct mg_str r, k, v;
6206 :
6207 0 : path_len = strlen(path);
6208 :
6209 0 : overrides = opts->custom_mime_types;
6210 0 : while ((overrides = mg_next_comma_list_entry(overrides, &k, &v)) != NULL) {
6211 0 : ext = path + (path_len - k.len);
6212 0 : if (path_len > k.len && mg_vcasecmp(&k, ext) == 0) {
6213 0 : return v;
6214 : }
6215 : }
6216 :
6217 0 : for (i = 0; mg_static_builtin_mime_types[i].extension != NULL; i++) {
6218 0 : ext = path + (path_len - mg_static_builtin_mime_types[i].ext_len);
6219 0 : if (path_len > mg_static_builtin_mime_types[i].ext_len && ext[-1] == '.' &&
6220 0 : mg_casecmp(ext, mg_static_builtin_mime_types[i].extension) == 0) {
6221 0 : r.p = mg_static_builtin_mime_types[i].mime_type;
6222 0 : r.len = strlen(r.p);
6223 0 : return r;
6224 : }
6225 : }
6226 :
6227 0 : r.p = dflt;
6228 0 : r.len = strlen(r.p);
6229 0 : return r;
6230 : }
6231 : #endif
6232 :
6233 : /*
6234 : * Check whether full request is buffered. Return:
6235 : * -1 if request is malformed
6236 : * 0 if request is not yet fully buffered
6237 : * >0 actual request length, including last \r\n\r\n
6238 : */
6239 0 : static int mg_http_get_request_len(const char *s, int buf_len) {
6240 0 : const unsigned char *buf = (unsigned char *) s;
6241 : int i;
6242 :
6243 0 : for (i = 0; i < buf_len; i++) {
6244 0 : if (!isprint(buf[i]) && buf[i] != '\r' && buf[i] != '\n' && buf[i] < 128) {
6245 0 : return -1;
6246 0 : } else if (buf[i] == '\n' && i + 1 < buf_len && buf[i + 1] == '\n') {
6247 0 : return i + 2;
6248 0 : } else if (buf[i] == '\n' && i + 2 < buf_len && buf[i + 1] == '\r' &&
6249 0 : buf[i + 2] == '\n') {
6250 0 : return i + 3;
6251 : }
6252 : }
6253 :
6254 0 : return 0;
6255 : }
6256 :
6257 0 : static const char *mg_http_parse_headers(const char *s, const char *end,
6258 : int len, struct http_message *req) {
6259 0 : int i = 0;
6260 0 : while (i < (int) ARRAY_SIZE(req->header_names) - 1) {
6261 0 : struct mg_str *k = &req->header_names[i], *v = &req->header_values[i];
6262 :
6263 0 : s = mg_skip(s, end, ": ", k);
6264 0 : s = mg_skip(s, end, "\r\n", v);
6265 :
6266 0 : while (v->len > 0 && v->p[v->len - 1] == ' ') {
6267 0 : v->len--; /* Trim trailing spaces in header value */
6268 : }
6269 :
6270 : /*
6271 : * If header value is empty - skip it and go to next (if any).
6272 : * NOTE: Do not add it to headers_values because such addition changes API
6273 : * behaviour
6274 : */
6275 0 : if (k->len != 0 && v->len == 0) {
6276 0 : continue;
6277 : }
6278 :
6279 0 : if (k->len == 0 || v->len == 0) {
6280 0 : k->p = v->p = NULL;
6281 0 : k->len = v->len = 0;
6282 0 : break;
6283 : }
6284 :
6285 0 : if (!mg_ncasecmp(k->p, "Content-Length", 14)) {
6286 0 : req->body.len = (size_t) to64(v->p);
6287 0 : req->message.len = len + req->body.len;
6288 : }
6289 :
6290 0 : i++;
6291 : }
6292 :
6293 0 : return s;
6294 : }
6295 :
6296 0 : int mg_parse_http(const char *s, int n, struct http_message *hm, int is_req) {
6297 : const char *end, *qs;
6298 0 : int len = mg_http_get_request_len(s, n);
6299 :
6300 0 : if (len <= 0) return len;
6301 :
6302 0 : memset(hm, 0, sizeof(*hm));
6303 0 : hm->message.p = s;
6304 0 : hm->body.p = s + len;
6305 0 : hm->message.len = hm->body.len = (size_t) ~0;
6306 0 : end = s + len;
6307 :
6308 : /* Request is fully buffered. Skip leading whitespaces. */
6309 0 : while (s < end && isspace(*(unsigned char *) s)) s++;
6310 :
6311 0 : if (is_req) {
6312 : /* Parse request line: method, URI, proto */
6313 0 : s = mg_skip(s, end, " ", &hm->method);
6314 0 : s = mg_skip(s, end, " ", &hm->uri);
6315 0 : s = mg_skip(s, end, "\r\n", &hm->proto);
6316 0 : if (hm->uri.p <= hm->method.p || hm->proto.p <= hm->uri.p) return -1;
6317 :
6318 : /* If URI contains '?' character, initialize query_string */
6319 0 : if ((qs = (char *) memchr(hm->uri.p, '?', hm->uri.len)) != NULL) {
6320 0 : hm->query_string.p = qs + 1;
6321 0 : hm->query_string.len = &hm->uri.p[hm->uri.len] - (qs + 1);
6322 0 : hm->uri.len = qs - hm->uri.p;
6323 : }
6324 : } else {
6325 0 : s = mg_skip(s, end, " ", &hm->proto);
6326 0 : if (end - s < 4 || s[0] < '0' || s[0] > '9' || s[3] != ' ') return -1;
6327 0 : hm->resp_code = atoi(s);
6328 0 : if (hm->resp_code < 100 || hm->resp_code >= 600) return -1;
6329 0 : s += 4;
6330 0 : s = mg_skip(s, end, "\r\n", &hm->resp_status_msg);
6331 : }
6332 :
6333 0 : s = mg_http_parse_headers(s, end, len, hm);
6334 :
6335 : /*
6336 : * mg_parse_http() is used to parse both HTTP requests and HTTP
6337 : * responses. If HTTP response does not have Content-Length set, then
6338 : * body is read until socket is closed, i.e. body.len is infinite (~0).
6339 : *
6340 : * For HTTP requests though, according to
6341 : * http://tools.ietf.org/html/rfc7231#section-8.1.3,
6342 : * only POST and PUT methods have defined body semantics.
6343 : * Therefore, if Content-Length is not specified and methods are
6344 : * not one of PUT or POST, set body length to 0.
6345 : *
6346 : * So,
6347 : * if it is HTTP request, and Content-Length is not set,
6348 : * and method is not (PUT or POST) then reset body length to zero.
6349 : */
6350 0 : if (hm->body.len == (size_t) ~0 && is_req &&
6351 0 : mg_vcasecmp(&hm->method, "PUT") != 0 &&
6352 0 : mg_vcasecmp(&hm->method, "POST") != 0) {
6353 0 : hm->body.len = 0;
6354 0 : hm->message.len = len;
6355 : }
6356 :
6357 0 : return len;
6358 : }
6359 :
6360 0 : struct mg_str *mg_get_http_header(struct http_message *hm, const char *name) {
6361 0 : size_t i, len = strlen(name);
6362 :
6363 0 : for (i = 0; hm->header_names[i].len > 0; i++) {
6364 0 : struct mg_str *h = &hm->header_names[i], *v = &hm->header_values[i];
6365 0 : if (h->p != NULL && h->len == len && !mg_ncasecmp(h->p, name, len))
6366 0 : return v;
6367 : }
6368 :
6369 0 : return NULL;
6370 : }
6371 :
6372 : #if MG_ENABLE_FILESYSTEM
6373 0 : static void mg_http_transfer_file_data(struct mg_connection *nc) {
6374 0 : struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
6375 : char buf[MG_MAX_HTTP_SEND_MBUF];
6376 0 : size_t n = 0, to_read = 0, left = (size_t)(pd->file.cl - pd->file.sent);
6377 :
6378 0 : if (pd->file.type == DATA_FILE) {
6379 0 : struct mbuf *io = &nc->send_mbuf;
6380 0 : if (io->len >= MG_MAX_HTTP_SEND_MBUF) {
6381 0 : to_read = 0;
6382 : } else {
6383 0 : to_read = MG_MAX_HTTP_SEND_MBUF - io->len;
6384 : }
6385 0 : if (to_read > left) {
6386 0 : to_read = left;
6387 : }
6388 0 : if (to_read > 0) {
6389 0 : n = mg_fread(buf, 1, to_read, pd->file.fp);
6390 0 : if (n > 0) {
6391 0 : mg_send(nc, buf, n);
6392 0 : pd->file.sent += n;
6393 0 : DBG(("%p sent %d (total %d)", nc, (int) n, (int) pd->file.sent));
6394 : }
6395 : } else {
6396 : /* Rate-limited */
6397 : }
6398 0 : if (pd->file.sent >= pd->file.cl) {
6399 0 : LOG(LL_DEBUG, ("%p done, %d bytes, ka %d", nc, (int) pd->file.sent,
6400 : pd->file.keepalive));
6401 0 : if (!pd->file.keepalive) nc->flags |= MG_F_SEND_AND_CLOSE;
6402 0 : mg_http_free_proto_data_file(&pd->file);
6403 : }
6404 0 : } else if (pd->file.type == DATA_PUT) {
6405 0 : struct mbuf *io = &nc->recv_mbuf;
6406 0 : size_t to_write = left <= 0 ? 0 : left < io->len ? (size_t) left : io->len;
6407 0 : size_t n = mg_fwrite(io->buf, 1, to_write, pd->file.fp);
6408 0 : if (n > 0) {
6409 0 : mbuf_remove(io, n);
6410 0 : pd->file.sent += n;
6411 : }
6412 0 : if (n == 0 || pd->file.sent >= pd->file.cl) {
6413 0 : if (!pd->file.keepalive) nc->flags |= MG_F_SEND_AND_CLOSE;
6414 0 : mg_http_free_proto_data_file(&pd->file);
6415 : }
6416 : }
6417 : #if MG_ENABLE_HTTP_CGI
6418 0 : else if (pd->cgi.cgi_nc != NULL) {
6419 : /* This is POST data that needs to be forwarded to the CGI process */
6420 0 : if (pd->cgi.cgi_nc != NULL) {
6421 0 : mg_forward(nc, pd->cgi.cgi_nc);
6422 : } else {
6423 0 : nc->flags |= MG_F_SEND_AND_CLOSE;
6424 : }
6425 : }
6426 : #endif
6427 0 : }
6428 : #endif /* MG_ENABLE_FILESYSTEM */
6429 :
6430 : /*
6431 : * Parse chunked-encoded buffer. Return 0 if the buffer is not encoded, or
6432 : * if it's incomplete. If the chunk is fully buffered, return total number of
6433 : * bytes in a chunk, and store data in `data`, `data_len`.
6434 : */
6435 0 : static size_t mg_http_parse_chunk(char *buf, size_t len, char **chunk_data,
6436 : size_t *chunk_len) {
6437 0 : unsigned char *s = (unsigned char *) buf;
6438 0 : size_t n = 0; /* scanned chunk length */
6439 0 : size_t i = 0; /* index in s */
6440 :
6441 : /* Scan chunk length. That should be a hexadecimal number. */
6442 0 : while (i < len && isxdigit(s[i])) {
6443 0 : n *= 16;
6444 0 : n += (s[i] >= '0' && s[i] <= '9') ? s[i] - '0' : tolower(s[i]) - 'a' + 10;
6445 0 : i++;
6446 0 : if (i > 6) {
6447 : /* Chunk size is unreasonable. */
6448 0 : return 0;
6449 : }
6450 : }
6451 :
6452 : /* Skip new line */
6453 0 : if (i == 0 || i + 2 > len || s[i] != '\r' || s[i + 1] != '\n') {
6454 0 : return 0;
6455 : }
6456 0 : i += 2;
6457 :
6458 : /* Record where the data is */
6459 0 : *chunk_data = (char *) s + i;
6460 0 : *chunk_len = n;
6461 :
6462 : /* Skip data */
6463 0 : i += n;
6464 :
6465 : /* Skip new line */
6466 0 : if (i == 0 || i + 2 > len || s[i] != '\r' || s[i + 1] != '\n') {
6467 0 : return 0;
6468 : }
6469 0 : return i + 2;
6470 : }
6471 :
6472 0 : MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc,
6473 : struct http_message *hm, char *buf,
6474 : size_t blen) {
6475 0 : struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
6476 : char *data;
6477 0 : size_t i, n, data_len, body_len, zero_chunk_received = 0;
6478 : /* Find out piece of received data that is not yet reassembled */
6479 0 : body_len = (size_t) pd->chunk.body_len;
6480 0 : assert(blen >= body_len);
6481 :
6482 : /* Traverse all fully buffered chunks */
6483 0 : for (i = body_len;
6484 0 : (n = mg_http_parse_chunk(buf + i, blen - i, &data, &data_len)) > 0;
6485 0 : i += n) {
6486 : /* Collapse chunk data to the rest of HTTP body */
6487 0 : memmove(buf + body_len, data, data_len);
6488 0 : body_len += data_len;
6489 0 : hm->body.len = body_len;
6490 :
6491 0 : if (data_len == 0) {
6492 0 : zero_chunk_received = 1;
6493 0 : i += n;
6494 0 : break;
6495 : }
6496 : }
6497 :
6498 0 : if (i > body_len) {
6499 : /* Shift unparsed content to the parsed body */
6500 0 : assert(i <= blen);
6501 0 : memmove(buf + body_len, buf + i, blen - i);
6502 0 : memset(buf + body_len + blen - i, 0, i - body_len);
6503 0 : nc->recv_mbuf.len -= i - body_len;
6504 0 : pd->chunk.body_len = body_len;
6505 :
6506 : /* Send MG_EV_HTTP_CHUNK event */
6507 0 : nc->flags &= ~MG_F_DELETE_CHUNK;
6508 0 : mg_call(nc, nc->handler, nc->user_data, MG_EV_HTTP_CHUNK, hm);
6509 :
6510 : /* Delete processed data if user set MG_F_DELETE_CHUNK flag */
6511 0 : if (nc->flags & MG_F_DELETE_CHUNK) {
6512 0 : memset(buf, 0, body_len);
6513 0 : memmove(buf, buf + body_len, blen - i);
6514 0 : nc->recv_mbuf.len -= body_len;
6515 0 : hm->body.len = 0;
6516 0 : pd->chunk.body_len = 0;
6517 : }
6518 :
6519 0 : if (zero_chunk_received) {
6520 : /* Total message size is len(body) + len(headers) */
6521 0 : hm->message.len =
6522 0 : (size_t) pd->chunk.body_len + blen - i + (hm->body.p - hm->message.p);
6523 : }
6524 : }
6525 :
6526 0 : return body_len;
6527 : }
6528 :
6529 0 : struct mg_http_endpoint *mg_http_get_endpoint_handler(struct mg_connection *nc,
6530 : struct mg_str *uri_path) {
6531 : struct mg_http_proto_data *pd;
6532 0 : struct mg_http_endpoint *ret = NULL;
6533 0 : int matched, matched_max = 0;
6534 : struct mg_http_endpoint *ep;
6535 :
6536 0 : if (nc == NULL) return NULL;
6537 :
6538 0 : pd = mg_http_get_proto_data(nc);
6539 :
6540 0 : if (pd == NULL) return NULL;
6541 :
6542 0 : ep = pd->endpoints;
6543 0 : while (ep != NULL) {
6544 0 : if ((matched = mg_match_prefix_n(ep->uri_pattern, *uri_path)) > 0) {
6545 0 : if (matched > matched_max) {
6546 : /* Looking for the longest suitable handler */
6547 0 : ret = ep;
6548 0 : matched_max = matched;
6549 : }
6550 : }
6551 :
6552 0 : ep = ep->next;
6553 : }
6554 :
6555 0 : return ret;
6556 : }
6557 :
6558 : #if MG_ENABLE_HTTP_STREAMING_MULTIPART
6559 : static void mg_http_multipart_continue(struct mg_connection *nc);
6560 :
6561 : static void mg_http_multipart_begin(struct mg_connection *nc,
6562 : struct http_message *hm, int req_len);
6563 :
6564 : #endif
6565 :
6566 : static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev,
6567 : struct http_message *hm);
6568 :
6569 0 : static void deliver_chunk(struct mg_connection *c, struct http_message *hm,
6570 : int req_len) {
6571 : /* Incomplete message received. Send MG_EV_HTTP_CHUNK event */
6572 0 : hm->body.len = c->recv_mbuf.len - req_len;
6573 0 : c->flags &= ~MG_F_DELETE_CHUNK;
6574 0 : mg_call(c, c->handler, c->user_data, MG_EV_HTTP_CHUNK, hm);
6575 : /* Delete processed data if user set MG_F_DELETE_CHUNK flag */
6576 0 : if (c->flags & MG_F_DELETE_CHUNK) c->recv_mbuf.len = req_len;
6577 0 : }
6578 :
6579 : /*
6580 : * lx106 compiler has a bug (TODO(mkm) report and insert tracking bug here)
6581 : * If a big structure is declared in a big function, lx106 gcc will make it
6582 : * even bigger (round up to 4k, from 700 bytes of actual size).
6583 : */
6584 : #ifdef __xtensa__
6585 : static void mg_http_handler2(struct mg_connection *nc, int ev,
6586 : void *ev_data MG_UD_ARG(void *user_data),
6587 : struct http_message *hm) __attribute__((noinline));
6588 :
6589 : void mg_http_handler(struct mg_connection *nc, int ev,
6590 : void *ev_data MG_UD_ARG(void *user_data)) {
6591 : struct http_message hm;
6592 : mg_http_handler2(nc, ev, ev_data MG_UD_ARG(user_data), &hm);
6593 : }
6594 :
6595 : static void mg_http_handler2(struct mg_connection *nc, int ev,
6596 : void *ev_data MG_UD_ARG(void *user_data),
6597 : struct http_message *hm) {
6598 : #else /* !__XTENSA__ */
6599 0 : void mg_http_handler(struct mg_connection *nc, int ev,
6600 : void *ev_data MG_UD_ARG(void *user_data)) {
6601 0 : struct http_message shm, *hm = &shm;
6602 : #endif /* __XTENSA__ */
6603 0 : struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
6604 0 : struct mbuf *io = &nc->recv_mbuf;
6605 : int req_len;
6606 0 : const int is_req = (nc->listener != NULL);
6607 : #if MG_ENABLE_HTTP_WEBSOCKET
6608 : struct mg_str *vec;
6609 : #endif
6610 0 : if (ev == MG_EV_CLOSE) {
6611 : #if MG_ENABLE_HTTP_CGI
6612 : /* Close associated CGI forwarder connection */
6613 0 : if (pd != NULL && pd->cgi.cgi_nc != NULL) {
6614 0 : pd->cgi.cgi_nc->user_data = NULL;
6615 0 : pd->cgi.cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY;
6616 : }
6617 : #endif
6618 : #if MG_ENABLE_HTTP_STREAMING_MULTIPART
6619 : if (pd != NULL && pd->mp_stream.boundary != NULL) {
6620 : /*
6621 : * Multipart message is in progress, but connection is closed.
6622 : * Finish part and request with an error flag.
6623 : */
6624 : struct mg_http_multipart_part mp;
6625 : memset(&mp, 0, sizeof(mp));
6626 : mp.status = -1;
6627 : mp.user_data = pd->mp_stream.user_data;
6628 : mp.var_name = pd->mp_stream.var_name;
6629 : mp.file_name = pd->mp_stream.file_name;
6630 : mg_call(nc, (pd->endpoint_handler ? pd->endpoint_handler : nc->handler),
6631 : nc->user_data, MG_EV_HTTP_PART_END, &mp);
6632 : mp.var_name = NULL;
6633 : mp.file_name = NULL;
6634 : mg_call(nc, (pd->endpoint_handler ? pd->endpoint_handler : nc->handler),
6635 : nc->user_data, MG_EV_HTTP_MULTIPART_REQUEST_END, &mp);
6636 : } else
6637 : #endif
6638 0 : if (io->len > 0 &&
6639 0 : (req_len = mg_parse_http(io->buf, io->len, hm, is_req)) > 0) {
6640 : /*
6641 : * For HTTP messages without Content-Length, always send HTTP message
6642 : * before MG_EV_CLOSE message.
6643 : */
6644 0 : int ev2 = is_req ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY;
6645 0 : hm->message.len = io->len;
6646 0 : hm->body.len = io->buf + io->len - hm->body.p;
6647 0 : deliver_chunk(nc, hm, req_len);
6648 0 : mg_http_call_endpoint_handler(nc, ev2, hm);
6649 : }
6650 0 : if (pd != NULL && pd->endpoint_handler != NULL &&
6651 0 : pd->endpoint_handler != nc->handler) {
6652 0 : mg_call(nc, pd->endpoint_handler, nc->user_data, ev, NULL);
6653 : }
6654 : }
6655 :
6656 : #if MG_ENABLE_FILESYSTEM
6657 0 : if (pd != NULL && pd->file.fp != NULL) {
6658 0 : mg_http_transfer_file_data(nc);
6659 : }
6660 : #endif
6661 :
6662 0 : mg_call(nc, nc->handler, nc->user_data, ev, ev_data);
6663 :
6664 : #if MG_ENABLE_HTTP_STREAMING_MULTIPART
6665 : if (pd != NULL && pd->mp_stream.boundary != NULL &&
6666 : (ev == MG_EV_RECV || ev == MG_EV_POLL)) {
6667 : if (ev == MG_EV_RECV) {
6668 : pd->rcvd += *(int *) ev_data;
6669 : mg_http_multipart_continue(nc);
6670 : } else if (pd->mp_stream.data_avail) {
6671 : /* Try re-delivering the data. */
6672 : mg_http_multipart_continue(nc);
6673 : }
6674 : return;
6675 : }
6676 : #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
6677 :
6678 0 : if (ev == MG_EV_RECV) {
6679 : struct mg_str *s;
6680 :
6681 0 : again:
6682 0 : req_len = mg_parse_http(io->buf, io->len, hm, is_req);
6683 :
6684 0 : if (req_len > 0) {
6685 : /* New request - new proto data */
6686 0 : if (!pd) {
6687 0 : pd = mg_http_create_proto_data(nc);
6688 : }
6689 0 : pd->rcvd = io->len;
6690 : }
6691 :
6692 0 : if (req_len > 0 &&
6693 0 : (s = mg_get_http_header(hm, "Transfer-Encoding")) != NULL &&
6694 0 : mg_vcasecmp(s, "chunked") == 0) {
6695 0 : mg_handle_chunked(nc, hm, io->buf + req_len, io->len - req_len);
6696 : }
6697 :
6698 : #if MG_ENABLE_HTTP_STREAMING_MULTIPART
6699 : if (req_len > 0 && (s = mg_get_http_header(hm, "Content-Type")) != NULL &&
6700 : s->len >= 9 && strncmp(s->p, "multipart", 9) == 0) {
6701 : mg_http_multipart_begin(nc, hm, req_len);
6702 : mg_http_multipart_continue(nc);
6703 : return;
6704 : }
6705 : #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
6706 :
6707 : /* TODO(alashkin): refactor this ifelseifelseifelseifelse */
6708 0 : if ((req_len < 0 ||
6709 0 : (req_len == 0 && io->len >= MG_MAX_HTTP_REQUEST_SIZE))) {
6710 0 : DBG(("invalid request"));
6711 0 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
6712 0 : } else if (req_len == 0) {
6713 : /* Do nothing, request is not yet fully buffered */
6714 : }
6715 : #if MG_ENABLE_HTTP_WEBSOCKET
6716 0 : else if (nc->listener == NULL && (nc->flags & MG_F_IS_WEBSOCKET)) {
6717 : /* We're websocket client, got handshake response from server. */
6718 0 : DBG(("%p WebSocket upgrade code %d", nc, hm->resp_code));
6719 0 : if (hm->resp_code == 101 &&
6720 0 : mg_get_http_header(hm, "Sec-WebSocket-Accept")) {
6721 : /* TODO(lsm): check the validity of accept Sec-WebSocket-Accept */
6722 0 : mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_HANDSHAKE_DONE,
6723 : hm);
6724 0 : mbuf_remove(io, req_len);
6725 0 : nc->proto_handler = mg_ws_handler;
6726 0 : mg_ws_handler(nc, MG_EV_RECV, ev_data MG_UD_ARG(user_data));
6727 : } else {
6728 0 : mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_HANDSHAKE_DONE,
6729 : hm);
6730 0 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
6731 0 : mbuf_remove(io, req_len);
6732 : }
6733 0 : } else if (nc->listener != NULL &&
6734 0 : (vec = mg_get_http_header(hm, "Sec-WebSocket-Key")) != NULL) {
6735 : struct mg_http_endpoint *ep;
6736 :
6737 : /* This is a websocket request. Switch protocol handlers. */
6738 0 : mbuf_remove(io, req_len);
6739 0 : nc->proto_handler = mg_ws_handler;
6740 0 : nc->flags |= MG_F_IS_WEBSOCKET;
6741 :
6742 : /*
6743 : * If we have a handler set up with mg_register_http_endpoint(),
6744 : * deliver subsequent websocket events to this handler after the
6745 : * protocol switch.
6746 : */
6747 0 : ep = mg_http_get_endpoint_handler(nc->listener, &hm->uri);
6748 0 : if (ep != NULL) {
6749 0 : nc->handler = ep->handler;
6750 : #if MG_ENABLE_CALLBACK_USERDATA
6751 : nc->user_data = ep->user_data;
6752 : #endif
6753 : }
6754 :
6755 : /* Send handshake */
6756 0 : mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_HANDSHAKE_REQUEST,
6757 : hm);
6758 0 : if (!(nc->flags & (MG_F_CLOSE_IMMEDIATELY | MG_F_SEND_AND_CLOSE))) {
6759 0 : if (nc->send_mbuf.len == 0) {
6760 0 : mg_ws_handshake(nc, vec, hm);
6761 : }
6762 0 : mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_HANDSHAKE_DONE,
6763 : hm);
6764 0 : mg_ws_handler(nc, MG_EV_RECV, ev_data MG_UD_ARG(user_data));
6765 : }
6766 : }
6767 : #endif /* MG_ENABLE_HTTP_WEBSOCKET */
6768 0 : else if (hm->message.len > pd->rcvd) {
6769 : /* Not yet received all HTTP body, deliver MG_EV_HTTP_CHUNK */
6770 0 : deliver_chunk(nc, hm, req_len);
6771 0 : if (nc->recv_mbuf_limit > 0 && nc->recv_mbuf.len >= nc->recv_mbuf_limit) {
6772 0 : LOG(LL_ERROR, ("%p recv buffer (%lu bytes) exceeds the limit "
6773 : "%lu bytes, and not drained, closing",
6774 : nc, (unsigned long) nc->recv_mbuf.len,
6775 : (unsigned long) nc->recv_mbuf_limit));
6776 0 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
6777 : }
6778 : } else {
6779 : /* We did receive all HTTP body. */
6780 0 : int request_done = 1;
6781 0 : int trigger_ev = nc->listener ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY;
6782 : char addr[32];
6783 0 : mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr),
6784 : MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT);
6785 0 : DBG(("%p %s %.*s %.*s", nc, addr, (int) hm->method.len, hm->method.p,
6786 : (int) hm->uri.len, hm->uri.p));
6787 0 : deliver_chunk(nc, hm, req_len);
6788 : /* Whole HTTP message is fully buffered, call event handler */
6789 0 : mg_http_call_endpoint_handler(nc, trigger_ev, hm);
6790 0 : mbuf_remove(io, hm->message.len);
6791 0 : pd->rcvd -= hm->message.len;
6792 : #if MG_ENABLE_FILESYSTEM
6793 : /* We don't have a generic mechanism of communicating that we are done
6794 : * responding to a request (should probably add one). But if we are
6795 : * serving
6796 : * a file, we are definitely not done. */
6797 0 : if (pd->file.fp != NULL) request_done = 0;
6798 : #endif
6799 : #if MG_ENABLE_HTTP_CGI
6800 : /* If this is a CGI request, we are not done either. */
6801 0 : if (pd->cgi.cgi_nc != NULL) request_done = 0;
6802 : #endif
6803 0 : if (request_done && io->len > 0) goto again;
6804 : }
6805 : }
6806 0 : }
6807 :
6808 0 : static size_t mg_get_line_len(const char *buf, size_t buf_len) {
6809 0 : size_t len = 0;
6810 0 : while (len < buf_len && buf[len] != '\n') len++;
6811 0 : return len == buf_len ? 0 : len + 1;
6812 : }
6813 :
6814 : #if MG_ENABLE_HTTP_STREAMING_MULTIPART
6815 : static void mg_http_multipart_begin(struct mg_connection *nc,
6816 : struct http_message *hm, int req_len) {
6817 : struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
6818 : struct mg_str *ct;
6819 : struct mbuf *io = &nc->recv_mbuf;
6820 :
6821 : char boundary_buf[100];
6822 : char *boundary = boundary_buf;
6823 : int boundary_len;
6824 :
6825 : ct = mg_get_http_header(hm, "Content-Type");
6826 : if (ct == NULL) {
6827 : /* We need more data - or it isn't multipart mesage */
6828 : goto exit_mp;
6829 : }
6830 :
6831 : /* Content-type should start with "multipart" */
6832 : if (ct->len < 9 || strncmp(ct->p, "multipart", 9) != 0) {
6833 : goto exit_mp;
6834 : }
6835 :
6836 : boundary_len =
6837 : mg_http_parse_header2(ct, "boundary", &boundary, sizeof(boundary_buf));
6838 : if (boundary_len == 0) {
6839 : /*
6840 : * Content type is multipart, but there is no boundary,
6841 : * probably malformed request
6842 : */
6843 : nc->flags = MG_F_CLOSE_IMMEDIATELY;
6844 : DBG(("invalid request"));
6845 : goto exit_mp;
6846 : }
6847 :
6848 : /* If we reach this place - that is multipart request */
6849 :
6850 : if (pd->mp_stream.boundary != NULL) {
6851 : /*
6852 : * Another streaming request was in progress,
6853 : * looks like protocol error
6854 : */
6855 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
6856 : } else {
6857 : struct mg_http_endpoint *ep = NULL;
6858 : pd->mp_stream.state = MPS_BEGIN;
6859 : pd->mp_stream.boundary = strdup(boundary);
6860 : pd->mp_stream.boundary_len = strlen(boundary);
6861 : pd->mp_stream.var_name = pd->mp_stream.file_name = NULL;
6862 : pd->endpoint_handler = nc->handler;
6863 :
6864 : ep = mg_http_get_endpoint_handler(nc->listener, &hm->uri);
6865 : if (ep != NULL) {
6866 : pd->endpoint_handler = ep->handler;
6867 : }
6868 :
6869 : mg_http_call_endpoint_handler(nc, MG_EV_HTTP_MULTIPART_REQUEST, hm);
6870 :
6871 : mbuf_remove(io, req_len);
6872 : }
6873 : exit_mp:
6874 : if (boundary != boundary_buf) MG_FREE(boundary);
6875 : }
6876 :
6877 : #define CONTENT_DISPOSITION "Content-Disposition: "
6878 :
6879 : static size_t mg_http_multipart_call_handler(struct mg_connection *c, int ev,
6880 : const char *data,
6881 : size_t data_len) {
6882 : struct mg_http_multipart_part mp;
6883 : struct mg_http_proto_data *pd = mg_http_get_proto_data(c);
6884 : memset(&mp, 0, sizeof(mp));
6885 :
6886 : mp.var_name = pd->mp_stream.var_name;
6887 : mp.file_name = pd->mp_stream.file_name;
6888 : mp.user_data = pd->mp_stream.user_data;
6889 : mp.data.p = data;
6890 : mp.data.len = data_len;
6891 : mp.num_data_consumed = data_len;
6892 : mg_call(c, pd->endpoint_handler, c->user_data, ev, &mp);
6893 : pd->mp_stream.user_data = mp.user_data;
6894 : pd->mp_stream.data_avail = (mp.num_data_consumed != data_len);
6895 : return mp.num_data_consumed;
6896 : }
6897 :
6898 : static int mg_http_multipart_finalize(struct mg_connection *c) {
6899 : struct mg_http_proto_data *pd = mg_http_get_proto_data(c);
6900 :
6901 : mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_END, NULL, 0);
6902 : MG_FREE((void *) pd->mp_stream.file_name);
6903 : pd->mp_stream.file_name = NULL;
6904 : MG_FREE((void *) pd->mp_stream.var_name);
6905 : pd->mp_stream.var_name = NULL;
6906 : mg_http_multipart_call_handler(c, MG_EV_HTTP_MULTIPART_REQUEST_END, NULL, 0);
6907 : mg_http_free_proto_data_mp_stream(&pd->mp_stream);
6908 : pd->mp_stream.state = MPS_FINISHED;
6909 :
6910 : return 1;
6911 : }
6912 :
6913 : static int mg_http_multipart_wait_for_boundary(struct mg_connection *c) {
6914 : const char *boundary;
6915 : struct mbuf *io = &c->recv_mbuf;
6916 : struct mg_http_proto_data *pd = mg_http_get_proto_data(c);
6917 :
6918 : if (pd->mp_stream.boundary == NULL) {
6919 : pd->mp_stream.state = MPS_FINALIZE;
6920 : DBG(("Invalid request: boundary not initialized"));
6921 : return 0;
6922 : }
6923 :
6924 : if ((int) io->len < pd->mp_stream.boundary_len + 2) {
6925 : return 0;
6926 : }
6927 :
6928 : boundary = c_strnstr(io->buf, pd->mp_stream.boundary, io->len);
6929 : if (boundary != NULL) {
6930 : const char *boundary_end = (boundary + pd->mp_stream.boundary_len);
6931 : if (io->len - (boundary_end - io->buf) < 4) {
6932 : return 0;
6933 : }
6934 : if (strncmp(boundary_end, "--\r\n", 4) == 0) {
6935 : pd->mp_stream.state = MPS_FINALIZE;
6936 : mbuf_remove(io, (boundary_end - io->buf) + 4);
6937 : } else {
6938 : pd->mp_stream.state = MPS_GOT_BOUNDARY;
6939 : }
6940 : } else {
6941 : return 0;
6942 : }
6943 :
6944 : return 1;
6945 : }
6946 :
6947 : static void mg_http_parse_header_internal(struct mg_str *hdr,
6948 : const char *var_name,
6949 : struct altbuf *ab);
6950 :
6951 : static int mg_http_multipart_process_boundary(struct mg_connection *c) {
6952 : int data_size;
6953 : const char *boundary, *block_begin;
6954 : struct mbuf *io = &c->recv_mbuf;
6955 : struct mg_http_proto_data *pd = mg_http_get_proto_data(c);
6956 : struct altbuf ab_file_name, ab_var_name;
6957 : int line_len;
6958 : boundary = c_strnstr(io->buf, pd->mp_stream.boundary, io->len);
6959 : block_begin = boundary + pd->mp_stream.boundary_len + 2;
6960 : data_size = io->len - (block_begin - io->buf);
6961 :
6962 : altbuf_init(&ab_file_name, NULL, 0);
6963 : altbuf_init(&ab_var_name, NULL, 0);
6964 :
6965 : while (data_size > 0 &&
6966 : (line_len = mg_get_line_len(block_begin, data_size)) != 0) {
6967 : if (line_len > (int) sizeof(CONTENT_DISPOSITION) &&
6968 : mg_ncasecmp(block_begin, CONTENT_DISPOSITION,
6969 : sizeof(CONTENT_DISPOSITION) - 1) == 0) {
6970 : struct mg_str header;
6971 :
6972 : header.p = block_begin + sizeof(CONTENT_DISPOSITION) - 1;
6973 : header.len = line_len - sizeof(CONTENT_DISPOSITION) - 1;
6974 :
6975 : altbuf_reset(&ab_var_name);
6976 : mg_http_parse_header_internal(&header, "name", &ab_var_name);
6977 :
6978 : altbuf_reset(&ab_file_name);
6979 : mg_http_parse_header_internal(&header, "filename", &ab_file_name);
6980 :
6981 : block_begin += line_len;
6982 : data_size -= line_len;
6983 :
6984 : continue;
6985 : }
6986 :
6987 : if (line_len == 2 && mg_ncasecmp(block_begin, "\r\n", 2) == 0) {
6988 : mbuf_remove(io, block_begin - io->buf + 2);
6989 :
6990 : if (pd->mp_stream.processing_part != 0) {
6991 : mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_END, NULL, 0);
6992 : }
6993 :
6994 : /* Reserve 2 bytes for "\r\n" in file_name and var_name */
6995 : altbuf_append(&ab_file_name, '\0');
6996 : altbuf_append(&ab_file_name, '\0');
6997 : altbuf_append(&ab_var_name, '\0');
6998 : altbuf_append(&ab_var_name, '\0');
6999 :
7000 : MG_FREE((void *) pd->mp_stream.file_name);
7001 : pd->mp_stream.file_name = altbuf_get_buf(&ab_file_name, 1 /* trim */);
7002 : MG_FREE((void *) pd->mp_stream.var_name);
7003 : pd->mp_stream.var_name = altbuf_get_buf(&ab_var_name, 1 /* trim */);
7004 :
7005 : mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_BEGIN, NULL, 0);
7006 : pd->mp_stream.state = MPS_WAITING_FOR_CHUNK;
7007 : pd->mp_stream.processing_part++;
7008 : return 1;
7009 : }
7010 :
7011 : block_begin += line_len;
7012 : }
7013 :
7014 : pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY;
7015 :
7016 : altbuf_reset(&ab_var_name);
7017 : altbuf_reset(&ab_file_name);
7018 :
7019 : return 0;
7020 : }
7021 :
7022 : static int mg_http_multipart_continue_wait_for_chunk(struct mg_connection *c) {
7023 : struct mg_http_proto_data *pd = mg_http_get_proto_data(c);
7024 : struct mbuf *io = &c->recv_mbuf;
7025 :
7026 : const char *boundary;
7027 : if ((int) io->len < pd->mp_stream.boundary_len + 6 /* \r\n, --, -- */) {
7028 : return 0;
7029 : }
7030 :
7031 : boundary = c_strnstr(io->buf, pd->mp_stream.boundary, io->len);
7032 : if (boundary == NULL) {
7033 : int data_len = (io->len - (pd->mp_stream.boundary_len + 6));
7034 : if (data_len > 0) {
7035 : size_t consumed = mg_http_multipart_call_handler(
7036 : c, MG_EV_HTTP_PART_DATA, io->buf, (size_t) data_len);
7037 : mbuf_remove(io, consumed);
7038 : }
7039 : return 0;
7040 : } else if (boundary != NULL) {
7041 : size_t data_len = ((size_t)(boundary - io->buf) - 4);
7042 : size_t consumed = mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_DATA,
7043 : io->buf, data_len);
7044 : mbuf_remove(io, consumed);
7045 : if (consumed == data_len) {
7046 : mbuf_remove(io, 4);
7047 : pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY;
7048 : return 1;
7049 : } else {
7050 : return 0;
7051 : }
7052 : } else {
7053 : return 0;
7054 : }
7055 : }
7056 :
7057 : static void mg_http_multipart_continue(struct mg_connection *c) {
7058 : struct mg_http_proto_data *pd = mg_http_get_proto_data(c);
7059 : while (1) {
7060 : switch (pd->mp_stream.state) {
7061 : case MPS_BEGIN: {
7062 : pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY;
7063 : break;
7064 : }
7065 : case MPS_WAITING_FOR_BOUNDARY: {
7066 : if (mg_http_multipart_wait_for_boundary(c) == 0) {
7067 : return;
7068 : }
7069 : break;
7070 : }
7071 : case MPS_GOT_BOUNDARY: {
7072 : if (mg_http_multipart_process_boundary(c) == 0) {
7073 : return;
7074 : }
7075 : break;
7076 : }
7077 : case MPS_WAITING_FOR_CHUNK: {
7078 : if (mg_http_multipart_continue_wait_for_chunk(c) == 0) {
7079 : return;
7080 : }
7081 : break;
7082 : }
7083 : case MPS_FINALIZE: {
7084 : if (mg_http_multipart_finalize(c) == 0) {
7085 : return;
7086 : }
7087 : break;
7088 : }
7089 : case MPS_FINISHED: {
7090 : return;
7091 : }
7092 : }
7093 : }
7094 : }
7095 :
7096 : struct file_upload_state {
7097 : char *lfn;
7098 : size_t num_recd;
7099 : FILE *fp;
7100 : };
7101 :
7102 : #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
7103 :
7104 0 : void mg_set_protocol_http_websocket(struct mg_connection *nc) {
7105 0 : nc->proto_handler = mg_http_handler;
7106 0 : }
7107 :
7108 0 : const char *mg_status_message(int status_code) {
7109 0 : switch (status_code) {
7110 0 : case 206:
7111 0 : return "Partial Content";
7112 0 : case 301:
7113 0 : return "Moved";
7114 0 : case 302:
7115 0 : return "Found";
7116 0 : case 400:
7117 0 : return "Bad Request";
7118 0 : case 401:
7119 0 : return "Unauthorized";
7120 0 : case 403:
7121 0 : return "Forbidden";
7122 0 : case 404:
7123 0 : return "Not Found";
7124 0 : case 416:
7125 0 : return "Requested Range Not Satisfiable";
7126 0 : case 418:
7127 0 : return "I'm a teapot";
7128 0 : case 500:
7129 0 : return "Internal Server Error";
7130 0 : case 502:
7131 0 : return "Bad Gateway";
7132 0 : case 503:
7133 0 : return "Service Unavailable";
7134 :
7135 : #if MG_ENABLE_EXTRA_ERRORS_DESC
7136 0 : case 100:
7137 0 : return "Continue";
7138 0 : case 101:
7139 0 : return "Switching Protocols";
7140 0 : case 102:
7141 0 : return "Processing";
7142 0 : case 200:
7143 0 : return "OK";
7144 0 : case 201:
7145 0 : return "Created";
7146 0 : case 202:
7147 0 : return "Accepted";
7148 0 : case 203:
7149 0 : return "Non-Authoritative Information";
7150 0 : case 204:
7151 0 : return "No Content";
7152 0 : case 205:
7153 0 : return "Reset Content";
7154 0 : case 207:
7155 0 : return "Multi-Status";
7156 0 : case 208:
7157 0 : return "Already Reported";
7158 0 : case 226:
7159 0 : return "IM Used";
7160 0 : case 300:
7161 0 : return "Multiple Choices";
7162 0 : case 303:
7163 0 : return "See Other";
7164 0 : case 304:
7165 0 : return "Not Modified";
7166 0 : case 305:
7167 0 : return "Use Proxy";
7168 0 : case 306:
7169 0 : return "Switch Proxy";
7170 0 : case 307:
7171 0 : return "Temporary Redirect";
7172 0 : case 308:
7173 0 : return "Permanent Redirect";
7174 0 : case 402:
7175 0 : return "Payment Required";
7176 0 : case 405:
7177 0 : return "Method Not Allowed";
7178 0 : case 406:
7179 0 : return "Not Acceptable";
7180 0 : case 407:
7181 0 : return "Proxy Authentication Required";
7182 0 : case 408:
7183 0 : return "Request Timeout";
7184 0 : case 409:
7185 0 : return "Conflict";
7186 0 : case 410:
7187 0 : return "Gone";
7188 0 : case 411:
7189 0 : return "Length Required";
7190 0 : case 412:
7191 0 : return "Precondition Failed";
7192 0 : case 413:
7193 0 : return "Payload Too Large";
7194 0 : case 414:
7195 0 : return "URI Too Long";
7196 0 : case 415:
7197 0 : return "Unsupported Media Type";
7198 0 : case 417:
7199 0 : return "Expectation Failed";
7200 0 : case 422:
7201 0 : return "Unprocessable Entity";
7202 0 : case 423:
7203 0 : return "Locked";
7204 0 : case 424:
7205 0 : return "Failed Dependency";
7206 0 : case 426:
7207 0 : return "Upgrade Required";
7208 0 : case 428:
7209 0 : return "Precondition Required";
7210 0 : case 429:
7211 0 : return "Too Many Requests";
7212 0 : case 431:
7213 0 : return "Request Header Fields Too Large";
7214 0 : case 451:
7215 0 : return "Unavailable For Legal Reasons";
7216 0 : case 501:
7217 0 : return "Not Implemented";
7218 0 : case 504:
7219 0 : return "Gateway Timeout";
7220 0 : case 505:
7221 0 : return "HTTP Version Not Supported";
7222 0 : case 506:
7223 0 : return "Variant Also Negotiates";
7224 0 : case 507:
7225 0 : return "Insufficient Storage";
7226 0 : case 508:
7227 0 : return "Loop Detected";
7228 0 : case 510:
7229 0 : return "Not Extended";
7230 0 : case 511:
7231 0 : return "Network Authentication Required";
7232 : #endif /* MG_ENABLE_EXTRA_ERRORS_DESC */
7233 :
7234 0 : default:
7235 0 : return "OK";
7236 : }
7237 : }
7238 :
7239 0 : void mg_send_response_line_s(struct mg_connection *nc, int status_code,
7240 : const struct mg_str extra_headers) {
7241 0 : mg_printf(nc, "HTTP/1.1 %d %s\r\n", status_code,
7242 : mg_status_message(status_code));
7243 : #ifndef MG_HIDE_SERVER_INFO
7244 0 : mg_printf(nc, "Server: %s\r\n", mg_version_header);
7245 : #endif
7246 0 : if (extra_headers.len > 0) {
7247 0 : mg_printf(nc, "%.*s\r\n", (int) extra_headers.len, extra_headers.p);
7248 : }
7249 0 : }
7250 :
7251 0 : void mg_send_response_line(struct mg_connection *nc, int status_code,
7252 : const char *extra_headers) {
7253 0 : mg_send_response_line_s(nc, status_code, mg_mk_str(extra_headers));
7254 0 : }
7255 :
7256 0 : void mg_http_send_redirect(struct mg_connection *nc, int status_code,
7257 : const struct mg_str location,
7258 : const struct mg_str extra_headers) {
7259 0 : char bbody[100], *pbody = bbody;
7260 0 : int bl = mg_asprintf(&pbody, sizeof(bbody),
7261 : "<p>Moved <a href='%.*s'>here</a>.\r\n",
7262 0 : (int) location.len, location.p);
7263 0 : char bhead[150], *phead = bhead;
7264 0 : mg_asprintf(&phead, sizeof(bhead),
7265 : "Location: %.*s\r\n"
7266 : "Content-Type: text/html\r\n"
7267 : "Content-Length: %d\r\n"
7268 : "Cache-Control: no-cache\r\n"
7269 : "%.*s%s",
7270 0 : (int) location.len, location.p, bl, (int) extra_headers.len,
7271 0 : extra_headers.p, (extra_headers.len > 0 ? "\r\n" : ""));
7272 0 : mg_send_response_line(nc, status_code, phead);
7273 0 : if (phead != bhead) MG_FREE(phead);
7274 0 : mg_send(nc, pbody, bl);
7275 0 : if (pbody != bbody) MG_FREE(pbody);
7276 0 : }
7277 :
7278 0 : void mg_send_head(struct mg_connection *c, int status_code,
7279 : int64_t content_length, const char *extra_headers) {
7280 0 : mg_send_response_line(c, status_code, extra_headers);
7281 0 : if (content_length < 0) {
7282 0 : mg_printf(c, "%s", "Transfer-Encoding: chunked\r\n");
7283 : } else {
7284 0 : mg_printf(c, "Content-Length: %" INT64_FMT "\r\n", content_length);
7285 : }
7286 0 : mg_send(c, "\r\n", 2);
7287 0 : }
7288 :
7289 0 : void mg_http_send_error(struct mg_connection *nc, int code,
7290 : const char *reason) {
7291 0 : if (!reason) reason = mg_status_message(code);
7292 0 : LOG(LL_DEBUG, ("%p %d %s", nc, code, reason));
7293 0 : mg_send_head(nc, code, strlen(reason),
7294 : "Content-Type: text/plain\r\nConnection: close");
7295 0 : mg_send(nc, reason, strlen(reason));
7296 0 : nc->flags |= MG_F_SEND_AND_CLOSE;
7297 0 : }
7298 :
7299 : #if MG_ENABLE_FILESYSTEM
7300 0 : static void mg_http_construct_etag(char *buf, size_t buf_len,
7301 : const cs_stat_t *st) {
7302 0 : snprintf(buf, buf_len, "\"%lx.%" INT64_FMT "\"", (unsigned long) st->st_mtime,
7303 0 : (int64_t) st->st_size);
7304 0 : }
7305 :
7306 : #ifndef WINCE
7307 0 : static void mg_gmt_time_string(char *buf, size_t buf_len, time_t *t) {
7308 0 : strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(t));
7309 0 : }
7310 : #else
7311 : /* Look wince_lib.c for WindowsCE implementation */
7312 : static void mg_gmt_time_string(char *buf, size_t buf_len, time_t *t);
7313 : #endif
7314 :
7315 0 : static int mg_http_parse_range_header(const struct mg_str *header, int64_t *a,
7316 : int64_t *b) {
7317 : /*
7318 : * There is no snscanf. Headers are not guaranteed to be NUL-terminated,
7319 : * so we have this. Ugh.
7320 : */
7321 : int result;
7322 0 : char *p = (char *) MG_MALLOC(header->len + 1);
7323 0 : if (p == NULL) return 0;
7324 0 : memcpy(p, header->p, header->len);
7325 0 : p[header->len] = '\0';
7326 0 : result = sscanf(p, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
7327 0 : MG_FREE(p);
7328 0 : return result;
7329 : }
7330 :
7331 0 : void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm,
7332 : const char *path, const struct mg_str mime_type,
7333 : const struct mg_str extra_headers) {
7334 0 : struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
7335 : cs_stat_t st;
7336 0 : LOG(LL_DEBUG, ("%p [%s] %.*s", nc, path, (int) mime_type.len, mime_type.p));
7337 0 : if (mg_stat(path, &st) != 0 || (pd->file.fp = mg_fopen(path, "rb")) == NULL) {
7338 0 : int code, err = mg_get_errno();
7339 0 : switch (err) {
7340 0 : case EACCES:
7341 0 : code = 403;
7342 0 : break;
7343 0 : case ENOENT:
7344 0 : code = 404;
7345 0 : break;
7346 0 : default:
7347 0 : code = 500;
7348 : };
7349 0 : mg_http_send_error(nc, code, "Open failed");
7350 : } else {
7351 : char etag[50], current_time[50], last_modified[50], range[70];
7352 0 : time_t t = (time_t) mg_time();
7353 0 : int64_t r1 = 0, r2 = 0, cl = st.st_size;
7354 0 : struct mg_str *range_hdr = mg_get_http_header(hm, "Range");
7355 0 : int n, status_code = 200;
7356 :
7357 : /* Handle Range header */
7358 0 : range[0] = '\0';
7359 0 : if (range_hdr != NULL &&
7360 0 : (n = mg_http_parse_range_header(range_hdr, &r1, &r2)) > 0 && r1 >= 0 &&
7361 0 : r2 >= 0) {
7362 : /* If range is specified like "400-", set second limit to content len */
7363 0 : if (n == 1) {
7364 0 : r2 = cl - 1;
7365 : }
7366 0 : if (r1 > r2 || r2 >= cl) {
7367 0 : status_code = 416;
7368 0 : cl = 0;
7369 0 : snprintf(range, sizeof(range),
7370 : "Content-Range: bytes */%" INT64_FMT "\r\n",
7371 0 : (int64_t) st.st_size);
7372 : } else {
7373 0 : status_code = 206;
7374 0 : cl = r2 - r1 + 1;
7375 0 : snprintf(range, sizeof(range), "Content-Range: bytes %" INT64_FMT
7376 : "-%" INT64_FMT "/%" INT64_FMT "\r\n",
7377 0 : r1, r1 + cl - 1, (int64_t) st.st_size);
7378 : #if _FILE_OFFSET_BITS == 64 || _POSIX_C_SOURCE >= 200112L || \
7379 : _XOPEN_SOURCE >= 600
7380 0 : fseeko(pd->file.fp, r1, SEEK_SET);
7381 : #else
7382 : fseek(pd->file.fp, (long) r1, SEEK_SET);
7383 : #endif
7384 : }
7385 : }
7386 :
7387 : #if !MG_DISABLE_HTTP_KEEP_ALIVE
7388 : {
7389 0 : struct mg_str *conn_hdr = mg_get_http_header(hm, "Connection");
7390 0 : if (conn_hdr != NULL) {
7391 0 : pd->file.keepalive = (mg_vcasecmp(conn_hdr, "keep-alive") == 0);
7392 : } else {
7393 0 : pd->file.keepalive = (mg_vcmp(&hm->proto, "HTTP/1.1") == 0);
7394 : }
7395 : }
7396 : #endif
7397 :
7398 0 : mg_http_construct_etag(etag, sizeof(etag), &st);
7399 0 : mg_gmt_time_string(current_time, sizeof(current_time), &t);
7400 0 : mg_gmt_time_string(last_modified, sizeof(last_modified), &st.st_mtime);
7401 : /*
7402 : * Content length casted to size_t because:
7403 : * 1) that's the maximum buffer size anyway
7404 : * 2) ESP8266 RTOS SDK newlib vprintf cannot contain a 64bit arg at non-last
7405 : * position
7406 : * TODO(mkm): fix ESP8266 RTOS SDK
7407 : */
7408 0 : mg_send_response_line_s(nc, status_code, extra_headers);
7409 0 : mg_printf(nc,
7410 : "Date: %s\r\n"
7411 : "Last-Modified: %s\r\n"
7412 : "Accept-Ranges: bytes\r\n"
7413 : "Content-Type: %.*s\r\n"
7414 : "Connection: %s\r\n"
7415 : "Content-Length: %" SIZE_T_FMT
7416 : "\r\n"
7417 : "%sEtag: %s\r\n\r\n",
7418 0 : current_time, last_modified, (int) mime_type.len, mime_type.p,
7419 0 : (pd->file.keepalive ? "keep-alive" : "close"), (size_t) cl, range,
7420 : etag);
7421 :
7422 0 : pd->file.cl = cl;
7423 0 : pd->file.type = DATA_FILE;
7424 0 : mg_http_transfer_file_data(nc);
7425 : }
7426 0 : }
7427 :
7428 0 : static void mg_http_serve_file2(struct mg_connection *nc, const char *path,
7429 : struct http_message *hm,
7430 : struct mg_serve_http_opts *opts) {
7431 : #if MG_ENABLE_HTTP_SSI
7432 : if (mg_match_prefix(opts->ssi_pattern, strlen(opts->ssi_pattern), path) > 0) {
7433 : mg_handle_ssi_request(nc, hm, path, opts);
7434 : return;
7435 : }
7436 : #endif
7437 0 : mg_http_serve_file(nc, hm, path, mg_get_mime_type(path, "text/plain", opts),
7438 : mg_mk_str(opts->extra_headers));
7439 0 : }
7440 :
7441 : #endif
7442 :
7443 0 : int mg_url_decode(const char *src, int src_len, char *dst, int dst_len,
7444 : int is_form_url_encoded) {
7445 : int i, j, a, b;
7446 : #define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
7447 :
7448 0 : for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
7449 0 : if (src[i] == '%') {
7450 0 : if (i < src_len - 2 && isxdigit(*(const unsigned char *) (src + i + 1)) &&
7451 0 : isxdigit(*(const unsigned char *) (src + i + 2))) {
7452 0 : a = tolower(*(const unsigned char *) (src + i + 1));
7453 0 : b = tolower(*(const unsigned char *) (src + i + 2));
7454 0 : dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b));
7455 0 : i += 2;
7456 : } else {
7457 0 : return -1;
7458 : }
7459 0 : } else if (is_form_url_encoded && src[i] == '+') {
7460 0 : dst[j] = ' ';
7461 : } else {
7462 0 : dst[j] = src[i];
7463 : }
7464 : }
7465 :
7466 0 : dst[j] = '\0'; /* Null-terminate the destination */
7467 :
7468 0 : return i >= src_len ? j : -1;
7469 : }
7470 :
7471 0 : int mg_get_http_var(const struct mg_str *buf, const char *name, char *dst,
7472 : size_t dst_len) {
7473 : const char *p, *e, *s;
7474 : size_t name_len;
7475 : int len;
7476 :
7477 : /*
7478 : * According to the documentation function returns negative
7479 : * value in case of error. For debug purposes it returns:
7480 : * -1 - src is wrong (NUUL)
7481 : * -2 - dst is wrong (NULL)
7482 : * -3 - failed to decode url or dst is to small
7483 : * -4 - name does not exist
7484 : */
7485 0 : if (dst == NULL || dst_len == 0) {
7486 0 : len = -2;
7487 0 : } else if (buf->p == NULL || name == NULL || buf->len == 0) {
7488 0 : len = -1;
7489 0 : dst[0] = '\0';
7490 : } else {
7491 0 : name_len = strlen(name);
7492 0 : e = buf->p + buf->len;
7493 0 : len = -4;
7494 0 : dst[0] = '\0';
7495 :
7496 0 : for (p = buf->p; p + name_len < e; p++) {
7497 0 : if ((p == buf->p || p[-1] == '&') && p[name_len] == '=' &&
7498 0 : !mg_ncasecmp(name, p, name_len)) {
7499 0 : p += name_len + 1;
7500 0 : s = (const char *) memchr(p, '&', (size_t)(e - p));
7501 0 : if (s == NULL) {
7502 0 : s = e;
7503 : }
7504 0 : len = mg_url_decode(p, (size_t)(s - p), dst, dst_len, 1);
7505 : /* -1 means: failed to decode or dst is too small */
7506 0 : if (len == -1) {
7507 0 : len = -3;
7508 : }
7509 0 : break;
7510 : }
7511 : }
7512 : }
7513 :
7514 0 : return len;
7515 : }
7516 :
7517 0 : void mg_send_http_chunk(struct mg_connection *nc, const char *buf, size_t len) {
7518 : char chunk_size[50];
7519 : int n;
7520 :
7521 0 : n = snprintf(chunk_size, sizeof(chunk_size), "%lX\r\n", (unsigned long) len);
7522 0 : mg_send(nc, chunk_size, n);
7523 0 : mg_send(nc, buf, len);
7524 0 : mg_send(nc, "\r\n", 2);
7525 0 : }
7526 :
7527 0 : void mg_printf_http_chunk(struct mg_connection *nc, const char *fmt, ...) {
7528 0 : char mem[MG_VPRINTF_BUFFER_SIZE], *buf = mem;
7529 : int len;
7530 : va_list ap;
7531 :
7532 0 : va_start(ap, fmt);
7533 0 : len = mg_avprintf(&buf, sizeof(mem), fmt, ap);
7534 0 : va_end(ap);
7535 :
7536 0 : if (len >= 0) {
7537 0 : mg_send_http_chunk(nc, buf, len);
7538 : }
7539 :
7540 : /* LCOV_EXCL_START */
7541 : if (buf != mem && buf != NULL) {
7542 : MG_FREE(buf);
7543 : }
7544 : /* LCOV_EXCL_STOP */
7545 0 : }
7546 :
7547 0 : void mg_printf_html_escape(struct mg_connection *nc, const char *fmt, ...) {
7548 0 : char mem[MG_VPRINTF_BUFFER_SIZE], *buf = mem;
7549 : int i, j, len;
7550 : va_list ap;
7551 :
7552 0 : va_start(ap, fmt);
7553 0 : len = mg_avprintf(&buf, sizeof(mem), fmt, ap);
7554 0 : va_end(ap);
7555 :
7556 0 : if (len >= 0) {
7557 0 : for (i = j = 0; i < len; i++) {
7558 0 : if (buf[i] == '<' || buf[i] == '>') {
7559 0 : mg_send(nc, buf + j, i - j);
7560 0 : mg_send(nc, buf[i] == '<' ? "<" : ">", 4);
7561 0 : j = i + 1;
7562 : }
7563 : }
7564 0 : mg_send(nc, buf + j, i - j);
7565 : }
7566 :
7567 : /* LCOV_EXCL_START */
7568 : if (buf != mem && buf != NULL) {
7569 : MG_FREE(buf);
7570 : }
7571 : /* LCOV_EXCL_STOP */
7572 0 : }
7573 :
7574 0 : static void mg_http_parse_header_internal(struct mg_str *hdr,
7575 : const char *var_name,
7576 : struct altbuf *ab) {
7577 0 : int ch = ' ', ch1 = ',', ch2 = ';', n = strlen(var_name);
7578 0 : const char *p, *end = hdr ? hdr->p + hdr->len : NULL, *s = NULL;
7579 :
7580 : /* Find where variable starts */
7581 0 : for (s = hdr->p; s != NULL && s + n < end; s++) {
7582 0 : if ((s == hdr->p || s[-1] == ch || s[-1] == ch1 || s[-1] == ';') &&
7583 0 : s[n] == '=' && !strncmp(s, var_name, n))
7584 0 : break;
7585 : }
7586 :
7587 0 : if (s != NULL && &s[n + 1] < end) {
7588 0 : s += n + 1;
7589 0 : if (*s == '"' || *s == '\'') {
7590 0 : ch = ch1 = ch2 = *s++;
7591 : }
7592 0 : p = s;
7593 0 : while (p < end && p[0] != ch && p[0] != ch1 && p[0] != ch2) {
7594 0 : if (ch != ' ' && p[0] == '\\' && p[1] == ch) p++;
7595 0 : altbuf_append(ab, *p++);
7596 : }
7597 :
7598 0 : if (ch != ' ' && *p != ch) {
7599 0 : altbuf_reset(ab);
7600 : }
7601 : }
7602 :
7603 : /* If there is some data, append a NUL. */
7604 0 : if (ab->len > 0) {
7605 0 : altbuf_append(ab, '\0');
7606 : }
7607 0 : }
7608 :
7609 0 : int mg_http_parse_header2(struct mg_str *hdr, const char *var_name, char **buf,
7610 : size_t buf_size) {
7611 : struct altbuf ab;
7612 0 : altbuf_init(&ab, *buf, buf_size);
7613 0 : if (hdr == NULL) return 0;
7614 0 : if (*buf != NULL && buf_size > 0) *buf[0] = '\0';
7615 :
7616 0 : mg_http_parse_header_internal(hdr, var_name, &ab);
7617 :
7618 : /*
7619 : * Get a (trimmed) buffer, and return a len without a NUL byte which might
7620 : * have been added.
7621 : */
7622 0 : *buf = altbuf_get_buf(&ab, 1 /* trim */);
7623 0 : return ab.len > 0 ? ab.len - 1 : 0;
7624 : }
7625 :
7626 0 : int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf,
7627 : size_t buf_size) {
7628 0 : char *buf2 = buf;
7629 :
7630 0 : int len = mg_http_parse_header2(hdr, var_name, &buf2, buf_size);
7631 :
7632 0 : if (buf2 != buf) {
7633 : /* Buffer was not enough and was reallocated: free it and just return 0 */
7634 0 : MG_FREE(buf2);
7635 0 : return 0;
7636 : }
7637 :
7638 0 : return len;
7639 : }
7640 :
7641 0 : int mg_get_http_basic_auth(struct http_message *hm, char *user, size_t user_len,
7642 : char *pass, size_t pass_len) {
7643 0 : struct mg_str *hdr = mg_get_http_header(hm, "Authorization");
7644 0 : if (hdr == NULL) return -1;
7645 0 : return mg_parse_http_basic_auth(hdr, user, user_len, pass, pass_len);
7646 : }
7647 :
7648 0 : int mg_parse_http_basic_auth(struct mg_str *hdr, char *user, size_t user_len,
7649 : char *pass, size_t pass_len) {
7650 0 : char *buf = NULL;
7651 : char fmt[64];
7652 0 : int res = 0;
7653 :
7654 0 : if (mg_strncmp(*hdr, mg_mk_str("Basic "), 6) != 0) return -1;
7655 :
7656 0 : buf = (char *) MG_MALLOC(hdr->len);
7657 0 : cs_base64_decode((unsigned char *) hdr->p + 6, hdr->len, buf, NULL);
7658 :
7659 : /* e.g. "%123[^:]:%321[^\n]" */
7660 0 : snprintf(fmt, sizeof(fmt), "%%%" SIZE_T_FMT "[^:]:%%%" SIZE_T_FMT "[^\n]",
7661 : user_len - 1, pass_len - 1);
7662 0 : if (sscanf(buf, fmt, user, pass) == 0) {
7663 0 : res = -1;
7664 : }
7665 :
7666 0 : MG_FREE(buf);
7667 0 : return res;
7668 : }
7669 :
7670 : #if MG_ENABLE_FILESYSTEM
7671 0 : static int mg_is_file_hidden(const char *path,
7672 : const struct mg_serve_http_opts *opts,
7673 : int exclude_specials) {
7674 0 : const char *p1 = opts->per_directory_auth_file;
7675 0 : const char *p2 = opts->hidden_file_pattern;
7676 :
7677 : /* Strip directory path from the file name */
7678 0 : const char *pdir = strrchr(path, DIRSEP);
7679 0 : if (pdir != NULL) {
7680 0 : path = pdir + 1;
7681 : }
7682 :
7683 0 : return (exclude_specials && (!strcmp(path, ".") || !strcmp(path, ".."))) ||
7684 0 : (p1 != NULL && mg_match_prefix(p1, strlen(p1), path) == strlen(p1)) ||
7685 0 : (p2 != NULL && mg_match_prefix(p2, strlen(p2), path) > 0);
7686 : }
7687 :
7688 : #if !MG_DISABLE_HTTP_DIGEST_AUTH
7689 :
7690 : #ifndef MG_EXT_MD5
7691 0 : void mg_hash_md5_v(size_t num_msgs, const uint8_t *msgs[],
7692 : const size_t *msg_lens, uint8_t *digest) {
7693 : size_t i;
7694 : cs_md5_ctx md5_ctx;
7695 0 : cs_md5_init(&md5_ctx);
7696 0 : for (i = 0; i < num_msgs; i++) {
7697 0 : cs_md5_update(&md5_ctx, msgs[i], msg_lens[i]);
7698 : }
7699 0 : cs_md5_final(digest, &md5_ctx);
7700 0 : }
7701 : #else
7702 : extern void mg_hash_md5_v(size_t num_msgs, const uint8_t *msgs[],
7703 : const size_t *msg_lens, uint8_t *digest);
7704 : #endif
7705 :
7706 0 : void cs_md5(char buf[33], ...) {
7707 : unsigned char hash[16];
7708 : const uint8_t *msgs[20], *p;
7709 : size_t msg_lens[20];
7710 0 : size_t num_msgs = 0;
7711 : va_list ap;
7712 :
7713 0 : va_start(ap, buf);
7714 0 : while ((p = va_arg(ap, const unsigned char *) ) != NULL) {
7715 0 : msgs[num_msgs] = p;
7716 0 : msg_lens[num_msgs] = va_arg(ap, size_t);
7717 0 : num_msgs++;
7718 : }
7719 0 : va_end(ap);
7720 :
7721 0 : mg_hash_md5_v(num_msgs, msgs, msg_lens, hash);
7722 0 : cs_to_hex(buf, hash, sizeof(hash));
7723 0 : }
7724 :
7725 0 : static void mg_mkmd5resp(const char *method, size_t method_len, const char *uri,
7726 : size_t uri_len, const char *ha1, size_t ha1_len,
7727 : const char *nonce, size_t nonce_len, const char *nc,
7728 : size_t nc_len, const char *cnonce, size_t cnonce_len,
7729 : const char *qop, size_t qop_len, char *resp) {
7730 : static const char colon[] = ":";
7731 : static const size_t one = 1;
7732 : char ha2[33];
7733 0 : cs_md5(ha2, method, method_len, colon, one, uri, uri_len, NULL);
7734 0 : cs_md5(resp, ha1, ha1_len, colon, one, nonce, nonce_len, colon, one, nc,
7735 : nc_len, colon, one, cnonce, cnonce_len, colon, one, qop, qop_len,
7736 : colon, one, ha2, sizeof(ha2) - 1, NULL);
7737 0 : }
7738 :
7739 0 : int mg_http_create_digest_auth_header(char *buf, size_t buf_len,
7740 : const char *method, const char *uri,
7741 : const char *auth_domain, const char *user,
7742 : const char *passwd, const char *nonce) {
7743 : static const char colon[] = ":", qop[] = "auth";
7744 : static const size_t one = 1;
7745 : char ha1[33], resp[33], cnonce[40];
7746 :
7747 0 : snprintf(cnonce, sizeof(cnonce), "%lx", (unsigned long) mg_time());
7748 0 : cs_md5(ha1, user, (size_t) strlen(user), colon, one, auth_domain,
7749 : (size_t) strlen(auth_domain), colon, one, passwd,
7750 : (size_t) strlen(passwd), NULL);
7751 0 : mg_mkmd5resp(method, strlen(method), uri, strlen(uri), ha1, sizeof(ha1) - 1,
7752 : nonce, strlen(nonce), "1", one, cnonce, strlen(cnonce), qop,
7753 : sizeof(qop) - 1, resp);
7754 0 : return snprintf(buf, buf_len,
7755 : "Authorization: Digest username=\"%s\","
7756 : "realm=\"%s\",uri=\"%s\",qop=%s,nc=1,cnonce=%s,"
7757 : "nonce=%s,response=%s\r\n",
7758 0 : user, auth_domain, uri, qop, cnonce, nonce, resp);
7759 : }
7760 :
7761 : /*
7762 : * Check for authentication timeout.
7763 : * Clients send time stamp encoded in nonce. Make sure it is not too old,
7764 : * to prevent replay attacks.
7765 : * Assumption: nonce is a hexadecimal number of seconds since 1970.
7766 : */
7767 0 : static int mg_check_nonce(const char *nonce) {
7768 0 : unsigned long now = (unsigned long) mg_time();
7769 0 : unsigned long val = (unsigned long) strtoul(nonce, NULL, 16);
7770 0 : return (now >= val) && (now - val < 60 * 60);
7771 : }
7772 :
7773 0 : int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain,
7774 : FILE *fp) {
7775 0 : int ret = 0;
7776 : struct mg_str *hdr;
7777 : char username_buf[50], cnonce_buf[64], response_buf[40], uri_buf[200],
7778 : qop_buf[20], nc_buf[20], nonce_buf[16];
7779 :
7780 0 : char *username = username_buf, *cnonce = cnonce_buf, *response = response_buf,
7781 0 : *uri = uri_buf, *qop = qop_buf, *nc = nc_buf, *nonce = nonce_buf;
7782 :
7783 : /* Parse "Authorization:" header, fail fast on parse error */
7784 0 : if (hm == NULL || fp == NULL ||
7785 0 : (hdr = mg_get_http_header(hm, "Authorization")) == NULL ||
7786 0 : mg_http_parse_header2(hdr, "username", &username, sizeof(username_buf)) ==
7787 0 : 0 ||
7788 0 : mg_http_parse_header2(hdr, "cnonce", &cnonce, sizeof(cnonce_buf)) == 0 ||
7789 0 : mg_http_parse_header2(hdr, "response", &response, sizeof(response_buf)) ==
7790 0 : 0 ||
7791 0 : mg_http_parse_header2(hdr, "uri", &uri, sizeof(uri_buf)) == 0 ||
7792 0 : mg_http_parse_header2(hdr, "qop", &qop, sizeof(qop_buf)) == 0 ||
7793 0 : mg_http_parse_header2(hdr, "nc", &nc, sizeof(nc_buf)) == 0 ||
7794 0 : mg_http_parse_header2(hdr, "nonce", &nonce, sizeof(nonce_buf)) == 0 ||
7795 0 : mg_check_nonce(nonce) == 0) {
7796 0 : ret = 0;
7797 0 : goto clean;
7798 : }
7799 :
7800 : /* NOTE(lsm): due to a bug in MSIE, we do not compare URIs */
7801 :
7802 0 : ret = mg_check_digest_auth(
7803 : hm->method,
7804 : mg_mk_str_n(
7805 : hm->uri.p,
7806 0 : hm->uri.len + (hm->query_string.len ? hm->query_string.len + 1 : 0)),
7807 : mg_mk_str(username), mg_mk_str(cnonce), mg_mk_str(response),
7808 : mg_mk_str(qop), mg_mk_str(nc), mg_mk_str(nonce), mg_mk_str(auth_domain),
7809 : fp);
7810 :
7811 0 : clean:
7812 0 : if (username != username_buf) MG_FREE(username);
7813 0 : if (cnonce != cnonce_buf) MG_FREE(cnonce);
7814 0 : if (response != response_buf) MG_FREE(response);
7815 0 : if (uri != uri_buf) MG_FREE(uri);
7816 0 : if (qop != qop_buf) MG_FREE(qop);
7817 0 : if (nc != nc_buf) MG_FREE(nc);
7818 0 : if (nonce != nonce_buf) MG_FREE(nonce);
7819 :
7820 0 : return ret;
7821 : }
7822 :
7823 0 : int mg_check_digest_auth(struct mg_str method, struct mg_str uri,
7824 : struct mg_str username, struct mg_str cnonce,
7825 : struct mg_str response, struct mg_str qop,
7826 : struct mg_str nc, struct mg_str nonce,
7827 : struct mg_str auth_domain, FILE *fp) {
7828 : char buf[128], f_user[sizeof(buf)], f_ha1[sizeof(buf)], f_domain[sizeof(buf)];
7829 : char exp_resp[33];
7830 :
7831 : /*
7832 : * Read passwords file line by line. If should have htdigest format,
7833 : * i.e. each line should be a colon-separated sequence:
7834 : * USER_NAME:DOMAIN_NAME:HA1_HASH_OF_USER_DOMAIN_AND_PASSWORD
7835 : */
7836 0 : while (fgets(buf, sizeof(buf), fp) != NULL) {
7837 0 : if (sscanf(buf, "%[^:]:%[^:]:%s", f_user, f_domain, f_ha1) == 3 &&
7838 0 : mg_vcmp(&username, f_user) == 0 &&
7839 0 : mg_vcmp(&auth_domain, f_domain) == 0) {
7840 : /* Username and domain matched, check the password */
7841 0 : mg_mkmd5resp(method.p, method.len, uri.p, uri.len, f_ha1, strlen(f_ha1),
7842 : nonce.p, nonce.len, nc.p, nc.len, cnonce.p, cnonce.len,
7843 : qop.p, qop.len, exp_resp);
7844 0 : LOG(LL_DEBUG, ("%.*s %s %.*s %s", (int) username.len, username.p,
7845 : f_domain, (int) response.len, response.p, exp_resp));
7846 0 : return mg_ncasecmp(response.p, exp_resp, strlen(exp_resp)) == 0;
7847 : }
7848 : }
7849 :
7850 : /* None of the entries in the passwords file matched - return failure */
7851 0 : return 0;
7852 : }
7853 :
7854 0 : int mg_http_is_authorized(struct http_message *hm, struct mg_str path,
7855 : const char *domain, const char *passwords_file,
7856 : int flags) {
7857 : char buf[MG_MAX_PATH];
7858 : const char *p;
7859 : FILE *fp;
7860 0 : int authorized = 1;
7861 :
7862 0 : if (domain != NULL && passwords_file != NULL) {
7863 0 : if (flags & MG_AUTH_FLAG_IS_GLOBAL_PASS_FILE) {
7864 0 : fp = mg_fopen(passwords_file, "r");
7865 0 : } else if (flags & MG_AUTH_FLAG_IS_DIRECTORY) {
7866 0 : snprintf(buf, sizeof(buf), "%.*s%c%s", (int) path.len, path.p, DIRSEP,
7867 : passwords_file);
7868 0 : fp = mg_fopen(buf, "r");
7869 : } else {
7870 0 : p = strrchr(path.p, DIRSEP);
7871 0 : if (p == NULL) p = path.p;
7872 0 : snprintf(buf, sizeof(buf), "%.*s%c%s", (int) (p - path.p), path.p, DIRSEP,
7873 : passwords_file);
7874 0 : fp = mg_fopen(buf, "r");
7875 : }
7876 :
7877 0 : if (fp != NULL) {
7878 0 : authorized = mg_http_check_digest_auth(hm, domain, fp);
7879 0 : fclose(fp);
7880 0 : } else if (!(flags & MG_AUTH_FLAG_ALLOW_MISSING_FILE)) {
7881 0 : authorized = 0;
7882 : }
7883 : }
7884 :
7885 0 : LOG(LL_DEBUG, ("%.*s %s %x %d", (int) path.len, path.p,
7886 : passwords_file ? passwords_file : "", flags, authorized));
7887 0 : return authorized;
7888 : }
7889 : #else
7890 : int mg_http_is_authorized(struct http_message *hm, const struct mg_str path,
7891 : const char *domain, const char *passwords_file,
7892 : int flags) {
7893 : (void) hm;
7894 : (void) path;
7895 : (void) domain;
7896 : (void) passwords_file;
7897 : (void) flags;
7898 : return 1;
7899 : }
7900 : #endif
7901 :
7902 : #if MG_ENABLE_DIRECTORY_LISTING
7903 0 : static void mg_escape(const char *src, char *dst, size_t dst_len) {
7904 0 : size_t n = 0;
7905 0 : while (*src != '\0' && n + 5 < dst_len) {
7906 0 : unsigned char ch = *(unsigned char *) src++;
7907 0 : if (ch == '<') {
7908 0 : n += snprintf(dst + n, dst_len - n, "%s", "<");
7909 : } else {
7910 0 : dst[n++] = ch;
7911 : }
7912 : }
7913 0 : dst[n] = '\0';
7914 0 : }
7915 :
7916 0 : static void mg_print_dir_entry(struct mg_connection *nc, const char *file_name,
7917 : cs_stat_t *stp) {
7918 : char size[64], mod[64], path[MG_MAX_PATH];
7919 0 : int64_t fsize = stp->st_size;
7920 0 : int is_dir = S_ISDIR(stp->st_mode);
7921 0 : const char *slash = is_dir ? "/" : "";
7922 : struct mg_str href;
7923 :
7924 0 : if (is_dir) {
7925 0 : snprintf(size, sizeof(size), "%s", "[DIRECTORY]");
7926 : } else {
7927 : /*
7928 : * We use (double) cast below because MSVC 6 compiler cannot
7929 : * convert unsigned __int64 to double.
7930 : */
7931 0 : if (fsize < 1024) {
7932 0 : snprintf(size, sizeof(size), "%d", (int) fsize);
7933 0 : } else if (fsize < 0x100000) {
7934 0 : snprintf(size, sizeof(size), "%.1fk", (double) fsize / 1024.0);
7935 0 : } else if (fsize < 0x40000000) {
7936 0 : snprintf(size, sizeof(size), "%.1fM", (double) fsize / 1048576);
7937 : } else {
7938 0 : snprintf(size, sizeof(size), "%.1fG", (double) fsize / 1073741824);
7939 : }
7940 : }
7941 0 : strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&stp->st_mtime));
7942 0 : mg_escape(file_name, path, sizeof(path));
7943 0 : href = mg_url_encode(mg_mk_str(file_name));
7944 0 : mg_printf_http_chunk(nc,
7945 : "<tr><td><a href=\"%s%s\">%s%s</a></td>"
7946 : "<td>%s</td><td name=%" INT64_FMT ">%s</td></tr>\n",
7947 : href.p, slash, path, slash, mod, is_dir ? -1 : fsize,
7948 : size);
7949 0 : free((void *) href.p);
7950 0 : }
7951 :
7952 0 : static void mg_scan_directory(struct mg_connection *nc, const char *dir,
7953 : const struct mg_serve_http_opts *opts,
7954 : void (*func)(struct mg_connection *, const char *,
7955 : cs_stat_t *)) {
7956 : char path[MG_MAX_PATH + 1];
7957 : cs_stat_t st;
7958 : struct dirent *dp;
7959 : DIR *dirp;
7960 :
7961 0 : LOG(LL_DEBUG, ("%p [%s]", nc, dir));
7962 0 : if ((dirp = (opendir(dir))) != NULL) {
7963 0 : while ((dp = readdir(dirp)) != NULL) {
7964 : /* Do not show current dir and hidden files */
7965 0 : if (mg_is_file_hidden((const char *) dp->d_name, opts, 1)) {
7966 0 : continue;
7967 : }
7968 0 : snprintf(path, sizeof(path), "%s/%s", dir, dp->d_name);
7969 0 : if (mg_stat(path, &st) == 0) {
7970 0 : func(nc, (const char *) dp->d_name, &st);
7971 : }
7972 : }
7973 0 : closedir(dirp);
7974 : } else {
7975 0 : LOG(LL_DEBUG, ("%p opendir(%s) -> %d", nc, dir, mg_get_errno()));
7976 : }
7977 0 : }
7978 :
7979 0 : static void mg_send_directory_listing(struct mg_connection *nc, const char *dir,
7980 : struct http_message *hm,
7981 : struct mg_serve_http_opts *opts) {
7982 : static const char *sort_js_code =
7983 : "<script>function srt(tb, sc, so, d) {"
7984 : "var tr = Array.prototype.slice.call(tb.rows, 0),"
7985 : "tr = tr.sort(function (a, b) { var c1 = a.cells[sc], c2 = b.cells[sc],"
7986 : "n1 = c1.getAttribute('name'), n2 = c2.getAttribute('name'), "
7987 : "t1 = a.cells[2].getAttribute('name'), "
7988 : "t2 = b.cells[2].getAttribute('name'); "
7989 : "return so * (t1 < 0 && t2 >= 0 ? -1 : t2 < 0 && t1 >= 0 ? 1 : "
7990 : "n1 ? parseInt(n2) - parseInt(n1) : "
7991 : "c1.textContent.trim().localeCompare(c2.textContent.trim())); });";
7992 : static const char *sort_js_code2 =
7993 : "for (var i = 0; i < tr.length; i++) tb.appendChild(tr[i]); "
7994 : "if (!d) window.location.hash = ('sc=' + sc + '&so=' + so); "
7995 : "};"
7996 : "window.onload = function() {"
7997 : "var tb = document.getElementById('tb');"
7998 : "var m = /sc=([012]).so=(1|-1)/.exec(window.location.hash) || [0, 2, 1];"
7999 : "var sc = m[1], so = m[2]; document.onclick = function(ev) { "
8000 : "var c = ev.target.rel; if (c) {if (c == sc) so *= -1; srt(tb, c, so); "
8001 : "sc = c; ev.preventDefault();}};"
8002 : "srt(tb, sc, so, true);"
8003 : "}"
8004 : "</script>";
8005 :
8006 0 : mg_send_response_line(nc, 200, opts->extra_headers);
8007 0 : mg_printf(nc, "%s: %s\r\n%s: %s\r\n\r\n", "Transfer-Encoding", "chunked",
8008 : "Content-Type", "text/html; charset=utf-8");
8009 :
8010 0 : mg_printf_http_chunk(
8011 : nc,
8012 : "<html><head><title>Index of %.*s</title>%s%s"
8013 : "<style>th,td {text-align: left; padding-right: 1em; "
8014 : "font-family: monospace; }</style></head>\n"
8015 : "<body><h1>Index of %.*s</h1>\n<table cellpadding=0><thead>"
8016 : "<tr><th><a href=# rel=0>Name</a></th><th>"
8017 : "<a href=# rel=1>Modified</a</th>"
8018 : "<th><a href=# rel=2>Size</a></th></tr>"
8019 : "<tr><td colspan=3><hr></td></tr>\n"
8020 : "</thead>\n"
8021 : "<tbody id=tb>",
8022 0 : (int) hm->uri.len, hm->uri.p, sort_js_code, sort_js_code2,
8023 0 : (int) hm->uri.len, hm->uri.p);
8024 0 : mg_scan_directory(nc, dir, opts, mg_print_dir_entry);
8025 0 : mg_printf_http_chunk(nc,
8026 : "</tbody><tr><td colspan=3><hr></td></tr>\n"
8027 : "</table>\n"
8028 : "<address>%s</address>\n"
8029 : "</body></html>",
8030 : mg_version_header);
8031 0 : mg_send_http_chunk(nc, "", 0);
8032 : /* TODO(rojer): Remove when cesanta/dev/issues/197 is fixed. */
8033 0 : nc->flags |= MG_F_SEND_AND_CLOSE;
8034 0 : }
8035 : #endif /* MG_ENABLE_DIRECTORY_LISTING */
8036 :
8037 : /*
8038 : * Given a directory path, find one of the files specified in the
8039 : * comma-separated list of index files `list`.
8040 : * First found index file wins. If an index file is found, then gets
8041 : * appended to the `path`, stat-ed, and result of `stat()` passed to `stp`.
8042 : * If index file is not found, then `path` and `stp` remain unchanged.
8043 : */
8044 0 : MG_INTERNAL void mg_find_index_file(const char *path, const char *list,
8045 : char **index_file, cs_stat_t *stp) {
8046 : struct mg_str vec;
8047 0 : size_t path_len = strlen(path);
8048 0 : int found = 0;
8049 0 : *index_file = NULL;
8050 :
8051 : /* Traverse index files list. For each entry, append it to the given */
8052 : /* path and see if the file exists. If it exists, break the loop */
8053 0 : while ((list = mg_next_comma_list_entry(list, &vec, NULL)) != NULL) {
8054 : cs_stat_t st;
8055 0 : size_t len = path_len + 1 + vec.len + 1;
8056 0 : *index_file = (char *) MG_REALLOC(*index_file, len);
8057 0 : if (*index_file == NULL) break;
8058 0 : snprintf(*index_file, len, "%s%c%.*s", path, DIRSEP, (int) vec.len, vec.p);
8059 :
8060 : /* Does it exist? Is it a file? */
8061 0 : if (mg_stat(*index_file, &st) == 0 && S_ISREG(st.st_mode)) {
8062 : /* Yes it does, break the loop */
8063 0 : *stp = st;
8064 0 : found = 1;
8065 0 : break;
8066 : }
8067 : }
8068 0 : if (!found) {
8069 0 : MG_FREE(*index_file);
8070 0 : *index_file = NULL;
8071 : }
8072 0 : LOG(LL_DEBUG, ("[%s] [%s]", path, (*index_file ? *index_file : "")));
8073 0 : }
8074 :
8075 : #if MG_ENABLE_HTTP_URL_REWRITES
8076 0 : static int mg_http_send_port_based_redirect(
8077 : struct mg_connection *c, struct http_message *hm,
8078 : const struct mg_serve_http_opts *opts) {
8079 0 : const char *rewrites = opts->url_rewrites;
8080 : struct mg_str a, b;
8081 0 : char local_port[20] = {'%'};
8082 :
8083 0 : mg_conn_addr_to_str(c, local_port + 1, sizeof(local_port) - 1,
8084 : MG_SOCK_STRINGIFY_PORT);
8085 :
8086 0 : while ((rewrites = mg_next_comma_list_entry(rewrites, &a, &b)) != NULL) {
8087 0 : if (mg_vcmp(&a, local_port) == 0) {
8088 0 : mg_send_response_line(c, 301, NULL);
8089 0 : mg_printf(c, "Content-Length: 0\r\nLocation: %.*s%.*s\r\n\r\n",
8090 0 : (int) b.len, b.p, (int) (hm->proto.p - hm->uri.p - 1),
8091 : hm->uri.p);
8092 0 : return 1;
8093 : }
8094 : }
8095 :
8096 0 : return 0;
8097 : }
8098 :
8099 0 : static uint64_t ContentLength(const std::string& msg)
8100 : {
8101 0 : const char* CRLFCRLF = "\r\n\r\n";
8102 0 : size_t pos = msg.find(CRLFCRLF);
8103 0 : if (pos == std::string::npos) {
8104 0 : return 0;
8105 : }
8106 : //printf("msg.length %d, pos %d\n", (int)msg.length(), (int)pos);
8107 0 : return msg.length() - pos - 4;
8108 : }
8109 :
8110 0 : static void SetContentLength(std::string& msg, uint64_t len)
8111 : {
8112 0 : const char* CRLF = "\r\n";
8113 0 : const char* CL = "Content-Length: ";
8114 0 : size_t pos = msg.find(CL);
8115 0 : if (pos == std::string::npos) {
8116 0 : return;
8117 : }
8118 0 : pos += strlen(CL);
8119 0 : size_t pos2 = msg.find(CRLF, pos);
8120 0 : if (pos2 == std::string::npos) {
8121 0 : return;
8122 : }
8123 : char buf[256];
8124 0 : sprintf(buf, "%llu", (long long unsigned)len);
8125 0 : msg.replace(pos, pos2-pos, buf);
8126 : //printf("content-length %d, pos %d, pos2 %d\n", (int)len, (int)pos, (int)pos2);
8127 : }
8128 :
8129 0 : bool Rewrite(std::string& message, const char* re, const char* rs)
8130 : {
8131 0 : bool changed = false;
8132 0 : size_t pos = 0;
8133 0 : size_t len = strlen(re);
8134 : while (1) {
8135 0 : pos = message.find(re, pos);
8136 0 : if (pos == std::string::npos) {
8137 0 : break;
8138 : }
8139 0 : message.replace(pos, len, rs);
8140 0 : changed = true;
8141 : }
8142 0 : return changed;
8143 : }
8144 :
8145 0 : static void mg_reverse_proxy_handler(struct mg_connection *nc, int ev,
8146 : void *ev_data MG_UD_ARG(void *user_data)) {
8147 0 : struct http_message *hm = (struct http_message *) ev_data;
8148 0 : struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
8149 :
8150 0 : if (pd == NULL || pd->reverse_proxy_data.linked_conn == NULL) {
8151 0 : DBG(("%p: upstream closed", nc));
8152 0 : return;
8153 : }
8154 :
8155 : //if (ev != 0) {
8156 : // printf("proxy event %d\n", ev);
8157 : //}
8158 :
8159 0 : switch (ev) {
8160 0 : case MG_EV_CONNECT:
8161 0 : if (*(int *) ev_data != 0) {
8162 0 : mg_http_send_error(pd->reverse_proxy_data.linked_conn, 502, NULL);
8163 : }
8164 0 : break;
8165 : /* TODO(mkm): handle streaming */
8166 0 : case MG_EV_RECV: {
8167 : //struct mbuf *io = &nc->recv_mbuf;
8168 : //printf("proxy read: %d bytes [%s]\n", (int)io->len, io->buf);
8169 0 : break;
8170 : }
8171 0 : case MG_EV_HTTP_REPLY: {
8172 : // HTTP header "Transfer-Encoding: chunked" has to be removed:
8173 : // proxy data is chunked, after mongoose reads it, chunking is removed,
8174 : // it is sent to requestor all in one go (not chunked), but
8175 : // Transfer-Encoding header is still there and confuses the web browser.
8176 : // We hack the message to hide this header and everything works. K.O.
8177 : mg_str xstr;
8178 0 : xstr.p = "Transfer-Encoding: chunked";
8179 0 : xstr.len = strlen(xstr.p);
8180 0 : const char* s = mg_strstr(hm->message, xstr);
8181 0 : if (s) {
8182 0 : *(char*)s = 'X';
8183 : }
8184 : //printf("proxy reply: [%s]\n", hm->message.p);
8185 : if (0) {
8186 : std::string message_in(hm->message.p, hm->message.len);
8187 : // <link rel="icon" type="image/png" href="/static/favicons/favicon-16px-a64986.png" sizes="16x16">
8188 : // <script type="text/javascript" src="/static/scripts/bundle-9e842c.js"></script></body>
8189 : //std::regex re("href=\"/");
8190 : //std::string rs("href=\"");
8191 : //std::regex re("h");
8192 : //std::string rs("XXX");
8193 : //std::regex re ("\\b(sub)([^ ]*)");
8194 : //std::string message = std::regex_replace(message_in.c_str(), re, "sub-$2");
8195 : bool changed = false;
8196 : std::string message = message_in;
8197 : changed |= Rewrite(message, "href=\"/", "href=\"");
8198 : changed |= Rewrite(message, "src=\"/", "src=\"");
8199 : // ...post("/api/...
8200 : changed |= Rewrite(message, "post(\"/api/", "post(\"api/");
8201 : if (changed) {
8202 : // need to doctor ContentLength!
8203 : SetContentLength(message, ContentLength(message));
8204 : //printf("proxy rewrite:\n[%s] content-length %d\n[%s] content-length %d\n", message_in.c_str(), (int)ContentLength(message_in), message.c_str(), (int)ContentLength(message));
8205 : mg_send(pd->reverse_proxy_data.linked_conn, message.c_str(), message.length());
8206 : } else {
8207 : mg_send(pd->reverse_proxy_data.linked_conn, hm->message.p, hm->message.len);
8208 : }
8209 : } else {
8210 0 : mg_send(pd->reverse_proxy_data.linked_conn, hm->message.p, hm->message.len);
8211 : }
8212 0 : pd->reverse_proxy_data.linked_conn->flags |= MG_F_SEND_AND_CLOSE;
8213 0 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
8214 0 : break;
8215 : }
8216 0 : case MG_EV_CLOSE: {
8217 0 : struct mbuf *io = &nc->recv_mbuf;
8218 : //printf("proxy close: mbuf %p, bytes %d\n", io, (int)io->len); //, io->buf);
8219 0 : if (io->len > 0) {
8220 0 : mg_send(pd->reverse_proxy_data.linked_conn, io->buf, io->len);
8221 : }
8222 0 : pd->reverse_proxy_data.linked_conn->flags |= MG_F_SEND_AND_CLOSE;
8223 0 : break;
8224 : }
8225 : }
8226 :
8227 : #if MG_ENABLE_CALLBACK_USERDATA
8228 : (void) user_data;
8229 : #endif
8230 : }
8231 :
8232 0 : void mg_http_reverse_proxy(struct mg_connection *nc,
8233 : const struct http_message *hm, struct mg_str mount,
8234 : struct mg_str upstream) {
8235 : struct mg_connection *be;
8236 0 : char burl[256], *purl = burl;
8237 : int i;
8238 : const char *error;
8239 : struct mg_connect_opts opts;
8240 0 : struct mg_str path = MG_NULL_STR, user_info = MG_NULL_STR, host = MG_NULL_STR;
8241 0 : memset(&opts, 0, sizeof(opts));
8242 0 : opts.error_string = &error;
8243 :
8244 0 : mg_asprintf(&purl, sizeof(burl), "%.*s%.*s%s%.*s", (int) upstream.len, upstream.p,
8245 0 : (int) (hm->uri.len - mount.len), hm->uri.p + mount.len, (hm->query_string.len > 0 ? "?" : ""), (int) hm->query_string.len, hm->query_string.p);
8246 :
8247 : //printf("proxy url: [%s]\n", purl);
8248 :
8249 0 : be = mg_connect_http_base(nc->mgr, MG_CB(mg_reverse_proxy_handler, NULL),
8250 : opts, "http", NULL, "https", NULL, purl, &path,
8251 : &user_info, &host);
8252 0 : LOG(LL_DEBUG, ("Proxying %.*s to %s (rule: %.*s)", (int) hm->uri.len,
8253 : hm->uri.p, purl, (int) mount.len, mount.p));
8254 :
8255 0 : if (be == NULL) {
8256 0 : LOG(LL_ERROR, ("Error connecting to %s: %s", purl, error));
8257 0 : mg_http_send_error(nc, 502, NULL);
8258 0 : goto cleanup;
8259 : }
8260 :
8261 0 : mg_http_create_proto_data(be);
8262 :
8263 : /* link connections to each other, they must live and die together */
8264 0 : mg_http_get_proto_data(be)->reverse_proxy_data.linked_conn = nc;
8265 0 : mg_http_get_proto_data(nc)->reverse_proxy_data.linked_conn = be;
8266 :
8267 : /* send request upstream */
8268 0 : mg_printf(be, "%.*s %.*s HTTP/1.1\r\n", (int) hm->method.len, hm->method.p,
8269 0 : (int) path.len, path.p);
8270 :
8271 0 : mg_printf(be, "Host: %.*s\r\n", (int) host.len, host.p);
8272 0 : for (i = 0; i < MG_MAX_HTTP_HEADERS && hm->header_names[i].len > 0; i++) {
8273 0 : struct mg_str hn = hm->header_names[i];
8274 0 : struct mg_str hv = hm->header_values[i];
8275 :
8276 : /* we rewrite the host header */
8277 0 : if (mg_vcasecmp(&hn, "Host") == 0) continue;
8278 : /*
8279 : * Don't pass chunked transfer encoding to the client because hm->body is
8280 : * already dechunked when we arrive here.
8281 : */
8282 0 : if (mg_vcasecmp(&hn, "Transfer-encoding") == 0 &&
8283 0 : mg_vcasecmp(&hv, "chunked") == 0) {
8284 0 : mg_printf(be, "Content-Length: %" SIZE_T_FMT "\r\n", hm->body.len);
8285 0 : continue;
8286 : }
8287 : /* We don't support proxying Expect: 100-continue. */
8288 0 : if (mg_vcasecmp(&hn, "Expect") == 0 &&
8289 0 : mg_vcasecmp(&hv, "100-continue") == 0) {
8290 0 : continue;
8291 : }
8292 :
8293 0 : mg_printf(be, "%.*s: %.*s\r\n", (int) hn.len, hn.p, (int) hv.len, hv.p);
8294 : }
8295 :
8296 0 : mg_send(be, "\r\n", 2);
8297 0 : mg_send(be, hm->body.p, hm->body.len);
8298 :
8299 0 : cleanup:
8300 0 : if (purl != burl) MG_FREE(purl);
8301 0 : }
8302 :
8303 0 : static int mg_http_handle_forwarding(struct mg_connection *nc,
8304 : struct http_message *hm,
8305 : const struct mg_serve_http_opts *opts) {
8306 0 : const char *rewrites = opts->url_rewrites;
8307 : struct mg_str a, b;
8308 0 : struct mg_str p1 = MG_MK_STR("http://"), p2 = MG_MK_STR("https://");
8309 :
8310 0 : while ((rewrites = mg_next_comma_list_entry(rewrites, &a, &b)) != NULL) {
8311 0 : if (mg_strncmp(a, hm->uri, a.len) == 0) {
8312 0 : if (mg_strncmp(b, p1, p1.len) == 0 || mg_strncmp(b, p2, p2.len) == 0) {
8313 0 : mg_http_reverse_proxy(nc, hm, a, b);
8314 0 : return 1;
8315 : }
8316 : }
8317 : }
8318 :
8319 0 : return 0;
8320 : }
8321 : #endif /* MG_ENABLE_FILESYSTEM */
8322 :
8323 : #if 0
8324 : MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm,
8325 : const struct mg_serve_http_opts *opts,
8326 : char **local_path,
8327 : struct mg_str *remainder) {
8328 : int ok = 1;
8329 : const char *cp = hm->uri.p, *cp_end = hm->uri.p + hm->uri.len;
8330 : struct mg_str root = {NULL, 0};
8331 : const char *file_uri_start = cp;
8332 : *local_path = NULL;
8333 : remainder->p = NULL;
8334 : remainder->len = 0;
8335 :
8336 : { /* 1. Determine which root to use. */
8337 :
8338 : #if MG_ENABLE_HTTP_URL_REWRITES
8339 : const char *rewrites = opts->url_rewrites;
8340 : #else
8341 : const char *rewrites = "";
8342 : #endif
8343 : struct mg_str *hh = mg_get_http_header(hm, "Host");
8344 : struct mg_str a, b;
8345 : /* Check rewrites first. */
8346 : while ((rewrites = mg_next_comma_list_entry(rewrites, &a, &b)) != NULL) {
8347 : if (a.len > 1 && a.p[0] == '@') {
8348 : /* Host rewrite. */
8349 : if (hh != NULL && hh->len == a.len - 1 &&
8350 : mg_ncasecmp(a.p + 1, hh->p, a.len - 1) == 0) {
8351 : root = b;
8352 : break;
8353 : }
8354 : } else {
8355 : /* Regular rewrite, URI=directory */
8356 : size_t match_len = mg_match_prefix_n(a, hm->uri);
8357 : if (match_len > 0) {
8358 : file_uri_start = hm->uri.p + match_len;
8359 : if (*file_uri_start == '/' || file_uri_start == cp_end) {
8360 : /* Match ended at component boundary, ok. */
8361 : } else if (*(file_uri_start - 1) == '/') {
8362 : /* Pattern ends with '/', backtrack. */
8363 : file_uri_start--;
8364 : } else {
8365 : /* No match: must fall on the component boundary. */
8366 : continue;
8367 : }
8368 : root = b;
8369 : break;
8370 : }
8371 : }
8372 : }
8373 : /* If no rewrite rules matched, use DAV or regular document root. */
8374 : if (root.p == NULL) {
8375 : #if MG_ENABLE_HTTP_WEBDAV
8376 : if (opts->dav_document_root != NULL && mg_is_dav_request(&hm->method)) {
8377 : root.p = opts->dav_document_root;
8378 : root.len = strlen(opts->dav_document_root);
8379 : } else
8380 : #endif
8381 : {
8382 : root.p = opts->document_root;
8383 : root.len = strlen(opts->document_root);
8384 : }
8385 : }
8386 : assert(root.p != NULL && root.len > 0);
8387 : }
8388 :
8389 : { /* 2. Find where in the canonical URI path the local path ends. */
8390 : const char *u = file_uri_start + 1;
8391 : char *lp = (char *) MG_MALLOC(root.len + hm->uri.len + 1);
8392 : char *lp_end = lp + root.len + hm->uri.len + 1;
8393 : char *p = lp, *ps;
8394 : int exists = 1;
8395 : if (lp == NULL) {
8396 : ok = 0;
8397 : goto out;
8398 : }
8399 : memcpy(p, root.p, root.len);
8400 : p += root.len;
8401 : if (*(p - 1) == DIRSEP) p--;
8402 : *p = '\0';
8403 : ps = p;
8404 :
8405 : /* Chop off URI path components one by one and build local path. */
8406 : while (u <= cp_end) {
8407 : const char *next = u;
8408 : struct mg_str component;
8409 : if (exists) {
8410 : cs_stat_t st;
8411 : exists = (mg_stat(lp, &st) == 0);
8412 : if (exists && S_ISREG(st.st_mode)) {
8413 : /* We found the terminal, the rest of the URI (if any) is path_info.
8414 : */
8415 : if (*(u - 1) == '/') u--;
8416 : break;
8417 : }
8418 : }
8419 : if (u >= cp_end) break;
8420 : parse_uri_component((const char **) &next, cp_end, "/", &component);
8421 : if (component.len > 0) {
8422 : int len;
8423 : memmove(p + 1, component.p, component.len);
8424 : len = mg_url_decode(p + 1, component.len, p + 1, lp_end - p - 1, 0);
8425 : if (len <= 0) {
8426 : ok = 0;
8427 : break;
8428 : }
8429 : component.p = p + 1;
8430 : component.len = len;
8431 : if (mg_vcmp(&component, ".") == 0) {
8432 : /* Yum. */
8433 : } else if (mg_vcmp(&component, "..") == 0) {
8434 : while (p > ps && *p != DIRSEP) p--;
8435 : *p = '\0';
8436 : } else {
8437 : size_t i;
8438 : #ifdef _WIN32
8439 : /* On Windows, make sure it's valid Unicode (no funny stuff). */
8440 : wchar_t buf[MG_MAX_PATH * 2];
8441 : if (to_wchar(component.p, buf, MG_MAX_PATH) == 0) {
8442 : DBG(("[%.*s] smells funny", (int) component.len, component.p));
8443 : ok = 0;
8444 : break;
8445 : }
8446 : #endif
8447 : *p++ = DIRSEP;
8448 : /* No NULs and DIRSEPs in the component (percent-encoded). */
8449 : for (i = 0; i < component.len; i++, p++) {
8450 : if (*p == '\0' || *p == DIRSEP
8451 : #ifdef _WIN32
8452 : /* On Windows, "/" is also accepted, so check for that too. */
8453 : ||
8454 : *p == '/'
8455 : #endif
8456 : ) {
8457 : ok = 0;
8458 : break;
8459 : }
8460 : }
8461 : }
8462 : }
8463 : u = next;
8464 : }
8465 : if (ok) {
8466 : *local_path = lp;
8467 : if (u > cp_end) u = cp_end;
8468 : remainder->p = u;
8469 : remainder->len = cp_end - u;
8470 : } else {
8471 : MG_FREE(lp);
8472 : }
8473 : }
8474 :
8475 : out:
8476 : LOG(LL_DEBUG,
8477 : ("'%.*s' -> '%s' + '%.*s'", (int) hm->uri.len, hm->uri.p,
8478 : *local_path ? *local_path : "", (int) remainder->len, remainder->p));
8479 : return ok;
8480 : }
8481 : #endif
8482 :
8483 0 : static int mg_get_month_index(const char *s) {
8484 : static const char *month_names[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
8485 : "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
8486 : size_t i;
8487 :
8488 0 : for (i = 0; i < ARRAY_SIZE(month_names); i++)
8489 0 : if (!strcmp(s, month_names[i])) return (int) i;
8490 :
8491 0 : return -1;
8492 : }
8493 :
8494 0 : static int mg_num_leap_years(int year) {
8495 0 : return year / 4 - year / 100 + year / 400;
8496 : }
8497 :
8498 : /* Parse UTC date-time string, and return the corresponding time_t value. */
8499 0 : MG_INTERNAL time_t mg_parse_date_string(const char *datetime) {
8500 : static const unsigned short days_before_month[] = {
8501 : 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
8502 : char month_str[32];
8503 : int second, minute, hour, day, month, year, leap_days, days;
8504 0 : time_t result = (time_t) 0;
8505 :
8506 0 : if (((sscanf(datetime, "%d/%3s/%d %d:%d:%d", &day, month_str, &year, &hour,
8507 0 : &minute, &second) == 6) ||
8508 0 : (sscanf(datetime, "%d %3s %d %d:%d:%d", &day, month_str, &year, &hour,
8509 0 : &minute, &second) == 6) ||
8510 0 : (sscanf(datetime, "%*3s, %d %3s %d %d:%d:%d", &day, month_str, &year,
8511 0 : &hour, &minute, &second) == 6) ||
8512 0 : (sscanf(datetime, "%d-%3s-%d %d:%d:%d", &day, month_str, &year, &hour,
8513 0 : &minute, &second) == 6)) &&
8514 0 : year > 1970 && (month = mg_get_month_index(month_str)) != -1) {
8515 0 : leap_days = mg_num_leap_years(year) - mg_num_leap_years(1970);
8516 0 : year -= 1970;
8517 0 : days = year * 365 + days_before_month[month] + (day - 1) + leap_days;
8518 0 : result = days * 24 * 3600 + hour * 3600 + minute * 60 + second;
8519 : }
8520 :
8521 0 : return result;
8522 : }
8523 :
8524 0 : MG_INTERNAL int mg_is_not_modified(struct http_message *hm, cs_stat_t *st) {
8525 : struct mg_str *hdr;
8526 0 : if ((hdr = mg_get_http_header(hm, "If-None-Match")) != NULL) {
8527 : char etag[64];
8528 0 : mg_http_construct_etag(etag, sizeof(etag), st);
8529 0 : return mg_vcasecmp(hdr, etag) == 0;
8530 0 : } else if ((hdr = mg_get_http_header(hm, "If-Modified-Since")) != NULL) {
8531 0 : return st->st_mtime <= mg_parse_date_string(hdr->p);
8532 : } else {
8533 0 : return 0;
8534 : }
8535 : }
8536 :
8537 0 : void mg_http_send_digest_auth_request(struct mg_connection *c,
8538 : const char *domain) {
8539 0 : mg_printf(c,
8540 : "HTTP/1.1 401 Unauthorized\r\n"
8541 : "WWW-Authenticate: Digest qop=\"auth\", "
8542 : "realm=\"%s\", nonce=\"%lx\"\r\n"
8543 : "Content-Length: 0\r\n\r\n",
8544 0 : domain, (unsigned long) mg_time());
8545 0 : }
8546 :
8547 0 : static void mg_http_send_options(struct mg_connection *nc,
8548 : struct mg_serve_http_opts *opts) {
8549 0 : mg_send_response_line(nc, 200, opts->extra_headers);
8550 0 : mg_printf(nc, "%s",
8551 : "Allow: GET, POST, HEAD, CONNECT, OPTIONS"
8552 : #if MG_ENABLE_HTTP_WEBDAV
8553 : ", MKCOL, PUT, DELETE, PROPFIND, MOVE\r\nDAV: 1,2"
8554 : #endif
8555 : "\r\n\r\n");
8556 0 : nc->flags |= MG_F_SEND_AND_CLOSE;
8557 0 : }
8558 :
8559 0 : static int mg_is_creation_request(const struct http_message *hm) {
8560 0 : return mg_vcmp(&hm->method, "MKCOL") == 0 || mg_vcmp(&hm->method, "PUT") == 0;
8561 : }
8562 :
8563 0 : MG_INTERNAL void mg_send_http_file(struct mg_connection *nc, char *path,
8564 : const struct mg_str *path_info,
8565 : struct http_message *hm,
8566 : struct mg_serve_http_opts *opts) {
8567 : int exists, is_directory, is_cgi;
8568 : #if MG_ENABLE_HTTP_WEBDAV
8569 : int is_dav = mg_is_dav_request(&hm->method);
8570 : #else
8571 0 : int is_dav = 0;
8572 : #endif
8573 0 : char *index_file = NULL;
8574 : cs_stat_t st;
8575 :
8576 0 : exists = (mg_stat(path, &st) == 0);
8577 0 : is_directory = exists && S_ISDIR(st.st_mode);
8578 :
8579 0 : if (is_directory)
8580 0 : mg_find_index_file(path, opts->index_files, &index_file, &st);
8581 :
8582 0 : is_cgi =
8583 0 : (mg_match_prefix(opts->cgi_file_pattern, strlen(opts->cgi_file_pattern),
8584 0 : index_file ? index_file : path) > 0);
8585 :
8586 0 : LOG(LL_DEBUG,
8587 : ("%p %.*s [%s] exists=%d is_dir=%d is_dav=%d is_cgi=%d index=%s", nc,
8588 : (int) hm->method.len, hm->method.p, path, exists, is_directory, is_dav,
8589 : is_cgi, index_file ? index_file : ""));
8590 :
8591 0 : if (is_directory && hm->uri.p[hm->uri.len - 1] != '/' && !is_dav) {
8592 0 : mg_printf(nc,
8593 : "HTTP/1.1 301 Moved\r\nLocation: %.*s/\r\n"
8594 : "Content-Length: 0\r\n\r\n",
8595 0 : (int) hm->uri.len, hm->uri.p);
8596 0 : MG_FREE(index_file);
8597 0 : return;
8598 : }
8599 :
8600 : /* If we have path_info, the only way to handle it is CGI. */
8601 0 : if (path_info->len > 0 && !is_cgi) {
8602 0 : mg_http_send_error(nc, 501, NULL);
8603 0 : MG_FREE(index_file);
8604 0 : return;
8605 : }
8606 :
8607 0 : if (is_dav && opts->dav_document_root == NULL) {
8608 0 : mg_http_send_error(nc, 501, NULL);
8609 0 : } else if (!mg_http_is_authorized(
8610 : hm, mg_mk_str(path), opts->auth_domain, opts->global_auth_file,
8611 : ((is_directory ? MG_AUTH_FLAG_IS_DIRECTORY : 0) |
8612 : MG_AUTH_FLAG_IS_GLOBAL_PASS_FILE |
8613 0 : MG_AUTH_FLAG_ALLOW_MISSING_FILE)) ||
8614 0 : !mg_http_is_authorized(
8615 : hm, mg_mk_str(path), opts->auth_domain,
8616 : opts->per_directory_auth_file,
8617 : ((is_directory ? MG_AUTH_FLAG_IS_DIRECTORY : 0) |
8618 : MG_AUTH_FLAG_ALLOW_MISSING_FILE))) {
8619 0 : mg_http_send_digest_auth_request(nc, opts->auth_domain);
8620 0 : } else if (is_cgi) {
8621 : #if MG_ENABLE_HTTP_CGI
8622 0 : mg_handle_cgi(nc, index_file ? index_file : path, path_info, hm, opts);
8623 : #else
8624 : mg_http_send_error(nc, 501, NULL);
8625 : #endif /* MG_ENABLE_HTTP_CGI */
8626 0 : } else if ((!exists ||
8627 0 : mg_is_file_hidden(path, opts, 0 /* specials are ok */)) &&
8628 0 : !mg_is_creation_request(hm)) {
8629 0 : mg_http_send_error(nc, 404, NULL);
8630 : #if MG_ENABLE_HTTP_WEBDAV
8631 : } else if (!mg_vcmp(&hm->method, "PROPFIND")) {
8632 : mg_handle_propfind(nc, path, &st, hm, opts);
8633 : #if !MG_DISABLE_DAV_AUTH
8634 : } else if (is_dav &&
8635 : (opts->dav_auth_file == NULL ||
8636 : (strcmp(opts->dav_auth_file, "-") != 0 &&
8637 : !mg_http_is_authorized(
8638 : hm, mg_mk_str(path), opts->auth_domain, opts->dav_auth_file,
8639 : ((is_directory ? MG_AUTH_FLAG_IS_DIRECTORY : 0) |
8640 : MG_AUTH_FLAG_IS_GLOBAL_PASS_FILE |
8641 : MG_AUTH_FLAG_ALLOW_MISSING_FILE))))) {
8642 : mg_http_send_digest_auth_request(nc, opts->auth_domain);
8643 : #endif
8644 : } else if (!mg_vcmp(&hm->method, "MKCOL")) {
8645 : mg_handle_mkcol(nc, path, hm);
8646 : } else if (!mg_vcmp(&hm->method, "DELETE")) {
8647 : mg_handle_delete(nc, opts, path);
8648 : } else if (!mg_vcmp(&hm->method, "PUT")) {
8649 : mg_handle_put(nc, path, hm);
8650 : } else if (!mg_vcmp(&hm->method, "MOVE")) {
8651 : mg_handle_move(nc, opts, path, hm);
8652 : #if MG_ENABLE_FAKE_DAVLOCK
8653 : } else if (!mg_vcmp(&hm->method, "LOCK")) {
8654 : mg_handle_lock(nc, path);
8655 : #endif
8656 : #endif /* MG_ENABLE_HTTP_WEBDAV */
8657 0 : } else if (!mg_vcmp(&hm->method, "OPTIONS")) {
8658 0 : mg_http_send_options(nc, opts);
8659 0 : } else if (is_directory && index_file == NULL) {
8660 : #if MG_ENABLE_DIRECTORY_LISTING
8661 0 : if (strcmp(opts->enable_directory_listing, "yes") == 0) {
8662 0 : mg_send_directory_listing(nc, path, hm, opts);
8663 : } else {
8664 0 : mg_http_send_error(nc, 403, NULL);
8665 : }
8666 : #else
8667 : mg_http_send_error(nc, 501, NULL);
8668 : #endif
8669 0 : } else if (mg_is_not_modified(hm, &st)) {
8670 0 : mg_http_send_error(nc, 304, "Not Modified");
8671 : } else {
8672 0 : mg_http_serve_file2(nc, index_file ? index_file : path, hm, opts);
8673 : }
8674 0 : MG_FREE(index_file);
8675 : }
8676 :
8677 : #if 0
8678 : void mg_serve_http(struct mg_connection *nc, struct http_message *hm,
8679 : struct mg_serve_http_opts opts) {
8680 : char *path = NULL;
8681 : struct mg_str *hdr, path_info;
8682 : uint32_t remote_ip = ntohl(*(uint32_t *) &nc->sa.sin.sin_addr);
8683 :
8684 : if (mg_check_ip_acl(opts.ip_acl, remote_ip) != 1) {
8685 : /* Not allowed to connect */
8686 : mg_http_send_error(nc, 403, NULL);
8687 : nc->flags |= MG_F_SEND_AND_CLOSE;
8688 : return;
8689 : }
8690 :
8691 : #if MG_ENABLE_HTTP_URL_REWRITES
8692 : if (mg_http_handle_forwarding(nc, hm, &opts)) {
8693 : return;
8694 : }
8695 :
8696 : if (mg_http_send_port_based_redirect(nc, hm, &opts)) {
8697 : return;
8698 : }
8699 : #endif
8700 :
8701 : if (opts.document_root == NULL) {
8702 : opts.document_root = ".";
8703 : }
8704 : if (opts.per_directory_auth_file == NULL) {
8705 : opts.per_directory_auth_file = ".htpasswd";
8706 : }
8707 : if (opts.enable_directory_listing == NULL) {
8708 : opts.enable_directory_listing = "yes";
8709 : }
8710 : if (opts.cgi_file_pattern == NULL) {
8711 : opts.cgi_file_pattern = "**.cgi$|**.php$";
8712 : }
8713 : if (opts.ssi_pattern == NULL) {
8714 : opts.ssi_pattern = "**.shtml$|**.shtm$";
8715 : }
8716 : if (opts.index_files == NULL) {
8717 : opts.index_files = "index.html,index.htm,index.shtml,index.cgi,index.php";
8718 : }
8719 : /* Normalize path - resolve "." and ".." (in-place). */
8720 : if (!mg_normalize_uri_path(&hm->uri, &hm->uri)) {
8721 : mg_http_send_error(nc, 400, NULL);
8722 : return;
8723 : }
8724 : if (mg_uri_to_local_path(hm, &opts, &path, &path_info) == 0) {
8725 : mg_http_send_error(nc, 404, NULL);
8726 : return;
8727 : }
8728 : mg_send_http_file(nc, path, &path_info, hm, &opts);
8729 :
8730 : MG_FREE(path);
8731 : path = NULL;
8732 :
8733 : /* Close connection for non-keep-alive requests */
8734 : if (mg_vcmp(&hm->proto, "HTTP/1.1") != 0 ||
8735 : ((hdr = mg_get_http_header(hm, "Connection")) != NULL &&
8736 : mg_vcmp(hdr, "keep-alive") != 0)) {
8737 : #if 0
8738 : nc->flags |= MG_F_SEND_AND_CLOSE;
8739 : #endif
8740 : }
8741 : }
8742 : #endif
8743 :
8744 : #if MG_ENABLE_HTTP_STREAMING_MULTIPART
8745 : void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data,
8746 : mg_fu_fname_fn local_name_fn
8747 : MG_UD_ARG(void *user_data)) {
8748 : switch (ev) {
8749 : case MG_EV_HTTP_PART_BEGIN: {
8750 : struct mg_http_multipart_part *mp =
8751 : (struct mg_http_multipart_part *) ev_data;
8752 : struct file_upload_state *fus;
8753 : struct mg_str lfn = local_name_fn(nc, mg_mk_str(mp->file_name));
8754 : mp->user_data = NULL;
8755 : if (lfn.p == NULL || lfn.len == 0) {
8756 : LOG(LL_ERROR, ("%p Not allowed to upload %s", nc, mp->file_name));
8757 : mg_printf(nc,
8758 : "HTTP/1.1 403 Not Allowed\r\n"
8759 : "Content-Type: text/plain\r\n"
8760 : "Connection: close\r\n\r\n"
8761 : "Not allowed to upload %s\r\n",
8762 : mp->file_name);
8763 : nc->flags |= MG_F_SEND_AND_CLOSE;
8764 : return;
8765 : }
8766 : fus = (struct file_upload_state *) MG_CALLOC(1, sizeof(*fus));
8767 : if (fus == NULL) {
8768 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
8769 : return;
8770 : }
8771 : fus->lfn = (char *) MG_MALLOC(lfn.len + 1);
8772 : memcpy(fus->lfn, lfn.p, lfn.len);
8773 : fus->lfn[lfn.len] = '\0';
8774 : if (lfn.p != mp->file_name) MG_FREE((char *) lfn.p);
8775 : LOG(LL_DEBUG,
8776 : ("%p Receiving file %s -> %s", nc, mp->file_name, fus->lfn));
8777 : fus->fp = mg_fopen(fus->lfn, "wb");
8778 : if (fus->fp == NULL) {
8779 : mg_printf(nc,
8780 : "HTTP/1.1 500 Internal Server Error\r\n"
8781 : "Content-Type: text/plain\r\n"
8782 : "Connection: close\r\n\r\n");
8783 : LOG(LL_ERROR, ("Failed to open %s: %d\n", fus->lfn, mg_get_errno()));
8784 : mg_printf(nc, "Failed to open %s: %d\n", fus->lfn, mg_get_errno());
8785 : /* Do not close the connection just yet, discard remainder of the data.
8786 : * This is because at the time of writing some browsers (Chrome) fail to
8787 : * render response before all the data is sent. */
8788 : }
8789 : mp->user_data = (void *) fus;
8790 : break;
8791 : }
8792 : case MG_EV_HTTP_PART_DATA: {
8793 : struct mg_http_multipart_part *mp =
8794 : (struct mg_http_multipart_part *) ev_data;
8795 : struct file_upload_state *fus =
8796 : (struct file_upload_state *) mp->user_data;
8797 : if (fus == NULL || fus->fp == NULL) break;
8798 : if (mg_fwrite(mp->data.p, 1, mp->data.len, fus->fp) != mp->data.len) {
8799 : LOG(LL_ERROR, ("Failed to write to %s: %d, wrote %d", fus->lfn,
8800 : mg_get_errno(), (int) fus->num_recd));
8801 : if (mg_get_errno() == ENOSPC
8802 : #ifdef SPIFFS_ERR_FULL
8803 : || mg_get_errno() == SPIFFS_ERR_FULL
8804 : #endif
8805 : ) {
8806 : mg_printf(nc,
8807 : "HTTP/1.1 413 Payload Too Large\r\n"
8808 : "Content-Type: text/plain\r\n"
8809 : "Connection: close\r\n\r\n");
8810 : mg_printf(nc, "Failed to write to %s: no space left; wrote %d\r\n",
8811 : fus->lfn, (int) fus->num_recd);
8812 : } else {
8813 : mg_printf(nc,
8814 : "HTTP/1.1 500 Internal Server Error\r\n"
8815 : "Content-Type: text/plain\r\n"
8816 : "Connection: close\r\n\r\n");
8817 : mg_printf(nc, "Failed to write to %s: %d, wrote %d", mp->file_name,
8818 : mg_get_errno(), (int) fus->num_recd);
8819 : }
8820 : fclose(fus->fp);
8821 : remove(fus->lfn);
8822 : fus->fp = NULL;
8823 : /* Do not close the connection just yet, discard remainder of the data.
8824 : * This is because at the time of writing some browsers (Chrome) fail to
8825 : * render response before all the data is sent. */
8826 : return;
8827 : }
8828 : fus->num_recd += mp->data.len;
8829 : LOG(LL_DEBUG, ("%p rec'd %d bytes, %d total", nc, (int) mp->data.len,
8830 : (int) fus->num_recd));
8831 : break;
8832 : }
8833 : case MG_EV_HTTP_PART_END: {
8834 : struct mg_http_multipart_part *mp =
8835 : (struct mg_http_multipart_part *) ev_data;
8836 : struct file_upload_state *fus =
8837 : (struct file_upload_state *) mp->user_data;
8838 : if (fus == NULL) break;
8839 : if (mp->status >= 0 && fus->fp != NULL) {
8840 : LOG(LL_DEBUG, ("%p Uploaded %s (%s), %d bytes", nc, mp->file_name,
8841 : fus->lfn, (int) fus->num_recd));
8842 : } else {
8843 : LOG(LL_ERROR, ("Failed to store %s (%s)", mp->file_name, fus->lfn));
8844 : /*
8845 : * mp->status < 0 means connection was terminated, so no reason to send
8846 : * HTTP reply
8847 : */
8848 : }
8849 : if (fus->fp != NULL) fclose(fus->fp);
8850 : MG_FREE(fus->lfn);
8851 : MG_FREE(fus);
8852 : mp->user_data = NULL;
8853 : /* Don't close the connection yet, there may be more files to come. */
8854 : break;
8855 : }
8856 : case MG_EV_HTTP_MULTIPART_REQUEST_END: {
8857 : mg_printf(nc,
8858 : "HTTP/1.1 200 OK\r\n"
8859 : "Content-Type: text/plain\r\n"
8860 : "Connection: close\r\n\r\n"
8861 : "Ok.\r\n");
8862 : nc->flags |= MG_F_SEND_AND_CLOSE;
8863 : break;
8864 : }
8865 : }
8866 :
8867 : #if MG_ENABLE_CALLBACK_USERDATA
8868 : (void) user_data;
8869 : #endif
8870 : }
8871 :
8872 : #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
8873 : #endif /* MG_ENABLE_FILESYSTEM */
8874 :
8875 0 : struct mg_connection *mg_connect_http_base(
8876 : struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data),
8877 : struct mg_connect_opts opts, const char *scheme1, const char *scheme2,
8878 : const char *scheme_ssl1, const char *scheme_ssl2, const char *url,
8879 : struct mg_str *path, struct mg_str *user_info, struct mg_str *host) {
8880 0 : struct mg_connection *nc = NULL;
8881 0 : unsigned int port_i = 0;
8882 0 : int use_ssl = 0;
8883 : struct mg_str scheme, query, fragment;
8884 : char conn_addr_buf[2];
8885 0 : char *conn_addr = conn_addr_buf;
8886 :
8887 0 : if (mg_parse_uri(mg_mk_str(url), &scheme, user_info, host, &port_i, path,
8888 0 : &query, &fragment) != 0) {
8889 0 : MG_SET_PTRPTR(opts.error_string, "cannot parse url");
8890 0 : goto out;
8891 : }
8892 :
8893 : /* If query is present, do not strip it. Pass to the caller. */
8894 0 : if (query.len > 0) path->len += query.len + 1;
8895 :
8896 0 : if (scheme.len == 0 || mg_vcmp(&scheme, scheme1) == 0 ||
8897 0 : (scheme2 != NULL && mg_vcmp(&scheme, scheme2) == 0)) {
8898 0 : use_ssl = 0;
8899 0 : if (port_i == 0) port_i = 80;
8900 0 : } else if (mg_vcmp(&scheme, scheme_ssl1) == 0 ||
8901 0 : (scheme2 != NULL && mg_vcmp(&scheme, scheme_ssl2) == 0)) {
8902 0 : use_ssl = 1;
8903 0 : if (port_i == 0) port_i = 443;
8904 : } else {
8905 0 : goto out;
8906 : }
8907 :
8908 0 : mg_asprintf(&conn_addr, sizeof(conn_addr_buf), "tcp://%.*s:%u",
8909 0 : (int) host->len, host->p, port_i);
8910 0 : if (conn_addr == NULL) goto out;
8911 :
8912 0 : LOG(LL_DEBUG, ("%s use_ssl? %d %s", url, use_ssl, conn_addr));
8913 0 : if (use_ssl) {
8914 : #if MG_ENABLE_SSL
8915 : /*
8916 : * Schema requires SSL, but no SSL parameters were provided in opts.
8917 : * In order to maintain backward compatibility, use a faux-SSL with no
8918 : * verification.
8919 : */
8920 : if (opts.ssl_ca_cert == NULL) {
8921 : opts.ssl_ca_cert = "*";
8922 : }
8923 : #else
8924 0 : MG_SET_PTRPTR(opts.error_string, "ssl is disabled");
8925 0 : goto out;
8926 : #endif
8927 : }
8928 :
8929 0 : if ((nc = mg_connect_opt(mgr, conn_addr, MG_CB(ev_handler, user_data),
8930 0 : opts)) != NULL) {
8931 0 : mg_set_protocol_http_websocket(nc);
8932 : }
8933 :
8934 0 : out:
8935 0 : if (conn_addr != NULL && conn_addr != conn_addr_buf) MG_FREE(conn_addr);
8936 0 : return nc;
8937 : }
8938 :
8939 0 : struct mg_connection *mg_connect_http_opt(
8940 : struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data),
8941 : struct mg_connect_opts opts, const char *url, const char *extra_headers,
8942 : const char *post_data) {
8943 0 : struct mg_str user = MG_NULL_STR, null_str = MG_NULL_STR;
8944 0 : struct mg_str host = MG_NULL_STR, path = MG_NULL_STR;
8945 : struct mbuf auth;
8946 : struct mg_connection *nc =
8947 0 : mg_connect_http_base(mgr, MG_CB(ev_handler, user_data), opts, "http",
8948 : NULL, "https", NULL, url, &path, &user, &host);
8949 :
8950 0 : if (nc == NULL) {
8951 0 : return NULL;
8952 : }
8953 :
8954 0 : mbuf_init(&auth, 0);
8955 0 : if (user.len > 0) {
8956 0 : mg_basic_auth_header(user, null_str, &auth);
8957 : }
8958 :
8959 0 : if (post_data == NULL) post_data = "";
8960 0 : if (extra_headers == NULL) extra_headers = "";
8961 0 : if (path.len == 0) path = mg_mk_str("/");
8962 0 : if (host.len == 0) host = mg_mk_str("");
8963 :
8964 0 : mg_printf(nc, "%s %.*s HTTP/1.1\r\nHost: %.*s\r\nContent-Length: %" SIZE_T_FMT
8965 : "\r\n%.*s%s\r\n%s",
8966 0 : (post_data[0] == '\0' ? "GET" : "POST"), (int) path.len, path.p,
8967 0 : (int) (path.p - host.p), host.p, strlen(post_data), (int) auth.len,
8968 0 : (auth.buf == NULL ? "" : auth.buf), extra_headers, post_data);
8969 :
8970 0 : mbuf_free(&auth);
8971 0 : return nc;
8972 : }
8973 :
8974 0 : struct mg_connection *mg_connect_http(
8975 : struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data),
8976 : const char *url, const char *extra_headers, const char *post_data) {
8977 : struct mg_connect_opts opts;
8978 0 : memset(&opts, 0, sizeof(opts));
8979 0 : return mg_connect_http_opt(mgr, MG_CB(ev_handler, user_data), opts, url,
8980 0 : extra_headers, post_data);
8981 : }
8982 :
8983 0 : size_t mg_parse_multipart(const char *buf, size_t buf_len, char *var_name,
8984 : size_t var_name_len, char *file_name,
8985 : size_t file_name_len, const char **data,
8986 : size_t *data_len) {
8987 : static const char cd[] = "Content-Disposition: ";
8988 0 : size_t hl, bl, n, ll, pos, cdl = sizeof(cd) - 1;
8989 : int shl;
8990 :
8991 0 : if (buf == NULL || buf_len <= 0) return 0;
8992 0 : if ((shl = mg_http_get_request_len(buf, buf_len)) <= 0) return 0;
8993 0 : hl = shl;
8994 0 : if (buf[0] != '-' || buf[1] != '-' || buf[2] == '\n') return 0;
8995 :
8996 : /* Get boundary length */
8997 0 : bl = mg_get_line_len(buf, buf_len);
8998 :
8999 : /* Loop through headers, fetch variable name and file name */
9000 0 : var_name[0] = file_name[0] = '\0';
9001 0 : for (n = bl; (ll = mg_get_line_len(buf + n, hl - n)) > 0; n += ll) {
9002 0 : if (mg_ncasecmp(cd, buf + n, cdl) == 0) {
9003 : struct mg_str header;
9004 0 : header.p = buf + n + cdl;
9005 0 : header.len = ll - (cdl + 2);
9006 : {
9007 0 : char *var_name2 = var_name;
9008 0 : mg_http_parse_header2(&header, "name", &var_name2, var_name_len);
9009 : /* TODO: handle reallocated buffer correctly */
9010 0 : if (var_name2 != var_name) {
9011 0 : MG_FREE(var_name2);
9012 0 : var_name[0] = '\0';
9013 : }
9014 : }
9015 : {
9016 0 : char *file_name2 = file_name;
9017 0 : mg_http_parse_header2(&header, "filename", &file_name2, file_name_len);
9018 : /* TODO: handle reallocated buffer correctly */
9019 0 : if (file_name2 != file_name) {
9020 0 : MG_FREE(file_name2);
9021 0 : file_name[0] = '\0';
9022 : }
9023 : }
9024 : }
9025 : }
9026 :
9027 : /* Scan through the body, search for terminating boundary */
9028 0 : for (pos = hl; pos + (bl - 2) < buf_len; pos++) {
9029 0 : if (buf[pos] == '-' && !strncmp(buf, &buf[pos], bl - 2)) {
9030 0 : if (data_len != NULL) *data_len = (pos - 2) - hl;
9031 0 : if (data != NULL) *data = buf + hl;
9032 0 : return pos;
9033 : }
9034 : }
9035 :
9036 0 : return 0;
9037 : }
9038 :
9039 0 : void mg_register_http_endpoint_opt(struct mg_connection *nc,
9040 : const char *uri_path,
9041 : mg_event_handler_t handler,
9042 : struct mg_http_endpoint_opts opts) {
9043 0 : struct mg_http_proto_data *pd = NULL;
9044 0 : struct mg_http_endpoint *new_ep = NULL;
9045 :
9046 0 : if (nc == NULL) return;
9047 0 : new_ep = (struct mg_http_endpoint *) MG_CALLOC(1, sizeof(*new_ep));
9048 0 : if (new_ep == NULL) return;
9049 :
9050 0 : pd = mg_http_get_proto_data(nc);
9051 0 : if (pd == NULL) pd = mg_http_create_proto_data(nc);
9052 0 : new_ep->uri_pattern = mg_strdup(mg_mk_str(uri_path));
9053 0 : if (opts.auth_domain != NULL && opts.auth_file != NULL) {
9054 0 : new_ep->auth_domain = strdup(opts.auth_domain);
9055 0 : new_ep->auth_file = strdup(opts.auth_file);
9056 : }
9057 0 : new_ep->handler = handler;
9058 : #if MG_ENABLE_CALLBACK_USERDATA
9059 : new_ep->user_data = opts.user_data;
9060 : #endif
9061 0 : new_ep->next = pd->endpoints;
9062 0 : pd->endpoints = new_ep;
9063 : }
9064 :
9065 0 : static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev,
9066 : struct http_message *hm) {
9067 0 : struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
9068 0 : void *user_data = nc->user_data;
9069 :
9070 0 : if (ev == MG_EV_HTTP_REQUEST
9071 : #if MG_ENABLE_HTTP_STREAMING_MULTIPART
9072 : || ev == MG_EV_HTTP_MULTIPART_REQUEST
9073 : #endif
9074 : ) {
9075 : struct mg_http_endpoint *ep =
9076 0 : mg_http_get_endpoint_handler(nc->listener, &hm->uri);
9077 0 : if (ep != NULL) {
9078 : #if MG_ENABLE_FILESYSTEM && !MG_DISABLE_HTTP_DIGEST_AUTH
9079 0 : if (!mg_http_is_authorized(hm, hm->uri, ep->auth_domain, ep->auth_file,
9080 : MG_AUTH_FLAG_IS_GLOBAL_PASS_FILE)) {
9081 0 : mg_http_send_digest_auth_request(nc, ep->auth_domain);
9082 0 : return;
9083 : }
9084 : #endif
9085 0 : pd->endpoint_handler = ep->handler;
9086 : #if MG_ENABLE_CALLBACK_USERDATA
9087 : user_data = ep->user_data;
9088 : #endif
9089 : }
9090 : }
9091 0 : mg_call(nc, pd->endpoint_handler ? pd->endpoint_handler : nc->handler,
9092 : user_data, ev, hm);
9093 : }
9094 :
9095 0 : void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path,
9096 : MG_CB(mg_event_handler_t handler,
9097 : void *user_data)) {
9098 : struct mg_http_endpoint_opts opts;
9099 0 : memset(&opts, 0, sizeof(opts));
9100 : #if MG_ENABLE_CALLBACK_USERDATA
9101 : opts.user_data = user_data;
9102 : #endif
9103 0 : mg_register_http_endpoint_opt(nc, uri_path, handler, opts);
9104 0 : }
9105 :
9106 : #endif /* MG_ENABLE_HTTP */
9107 : #ifdef MG_MODULE_LINES
9108 : #line 1 "mongoose/src/mg_http_cgi.c"
9109 : #endif
9110 : /*
9111 : * Copyright (c) 2014-2016 Cesanta Software Limited
9112 : * All rights reserved
9113 : */
9114 :
9115 : #ifndef _WIN32
9116 : #include <signal.h>
9117 : #endif
9118 :
9119 : #if MG_ENABLE_HTTP && MG_ENABLE_HTTP_CGI
9120 :
9121 : #ifndef MG_MAX_CGI_ENVIR_VARS
9122 : #define MG_MAX_CGI_ENVIR_VARS 64
9123 : #endif
9124 :
9125 : #ifndef MG_ENV_EXPORT_TO_CGI
9126 : #define MG_ENV_EXPORT_TO_CGI "MONGOOSE_CGI"
9127 : #endif
9128 :
9129 : #define MG_F_HTTP_CGI_PARSE_HEADERS MG_F_USER_1
9130 :
9131 : /*
9132 : * This structure helps to create an environment for the spawned CGI program.
9133 : * Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
9134 : * last element must be NULL.
9135 : * However, on Windows there is a requirement that all these VARIABLE=VALUE\0
9136 : * strings must reside in a contiguous buffer. The end of the buffer is
9137 : * marked by two '\0' characters.
9138 : * We satisfy both worlds: we create an envp array (which is vars), all
9139 : * entries are actually pointers inside buf.
9140 : */
9141 : struct mg_cgi_env_block {
9142 : struct mg_connection *nc;
9143 : char buf[MG_CGI_ENVIRONMENT_SIZE]; /* Environment buffer */
9144 : const char *vars[MG_MAX_CGI_ENVIR_VARS]; /* char *envp[] */
9145 : int len; /* Space taken */
9146 : int nvars; /* Number of variables in envp[] */
9147 : };
9148 :
9149 : #ifdef _WIN32
9150 : struct mg_threadparam {
9151 : sock_t s;
9152 : HANDLE hPipe;
9153 : };
9154 :
9155 : static int mg_wait_until_ready(sock_t sock, int for_read) {
9156 : fd_set set;
9157 : FD_ZERO(&set);
9158 : FD_SET(sock, &set);
9159 : return select(sock + 1, for_read ? &set : 0, for_read ? 0 : &set, 0, 0) == 1;
9160 : }
9161 :
9162 : static void *mg_push_to_stdin(void *arg) {
9163 : struct mg_threadparam *tp = (struct mg_threadparam *) arg;
9164 : int n, sent, stop = 0;
9165 : DWORD k;
9166 : char buf[BUFSIZ];
9167 :
9168 : while (!stop && mg_wait_until_ready(tp->s, 1) &&
9169 : (n = recv(tp->s, buf, sizeof(buf), 0)) > 0) {
9170 : if (n == -1 && GetLastError() == WSAEWOULDBLOCK) continue;
9171 : for (sent = 0; !stop && sent < n; sent += k) {
9172 : if (!WriteFile(tp->hPipe, buf + sent, n - sent, &k, 0)) stop = 1;
9173 : }
9174 : }
9175 : DBG(("%s", "FORWARED EVERYTHING TO CGI"));
9176 : CloseHandle(tp->hPipe);
9177 : MG_FREE(tp);
9178 : return NULL;
9179 : }
9180 :
9181 : static void *mg_pull_from_stdout(void *arg) {
9182 : struct mg_threadparam *tp = (struct mg_threadparam *) arg;
9183 : int k = 0, stop = 0;
9184 : DWORD n, sent;
9185 : char buf[BUFSIZ];
9186 :
9187 : while (!stop && ReadFile(tp->hPipe, buf, sizeof(buf), &n, NULL)) {
9188 : for (sent = 0; !stop && sent < n; sent += k) {
9189 : if (mg_wait_until_ready(tp->s, 0) &&
9190 : (k = send(tp->s, buf + sent, n - sent, 0)) <= 0)
9191 : stop = 1;
9192 : }
9193 : }
9194 : DBG(("%s", "EOF FROM CGI"));
9195 : CloseHandle(tp->hPipe);
9196 : shutdown(tp->s, 2); // Without this, IO thread may get truncated data
9197 : closesocket(tp->s);
9198 : MG_FREE(tp);
9199 : return NULL;
9200 : }
9201 :
9202 : static void mg_spawn_stdio_thread(sock_t sock, HANDLE hPipe,
9203 : void *(*func)(void *)) {
9204 : struct mg_threadparam *tp = (struct mg_threadparam *) MG_MALLOC(sizeof(*tp));
9205 : if (tp != NULL) {
9206 : tp->s = sock;
9207 : tp->hPipe = hPipe;
9208 : mg_start_thread(func, tp);
9209 : }
9210 : }
9211 :
9212 : static void mg_abs_path(const char *utf8_path, char *abs_path, size_t len) {
9213 : wchar_t buf[MG_MAX_PATH], buf2[MG_MAX_PATH];
9214 : to_wchar(utf8_path, buf, ARRAY_SIZE(buf));
9215 : GetFullPathNameW(buf, ARRAY_SIZE(buf2), buf2, NULL);
9216 : WideCharToMultiByte(CP_UTF8, 0, buf2, wcslen(buf2) + 1, abs_path, len, 0, 0);
9217 : }
9218 :
9219 : static int mg_start_process(const char *interp, const char *cmd,
9220 : const char *env, const char *envp[],
9221 : const char *dir, sock_t sock) {
9222 : STARTUPINFOW si;
9223 : PROCESS_INFORMATION pi;
9224 : HANDLE a[2], b[2], me = GetCurrentProcess();
9225 : wchar_t wcmd[MG_MAX_PATH], full_dir[MG_MAX_PATH];
9226 : char buf[MG_MAX_PATH], buf2[MG_MAX_PATH], buf5[MG_MAX_PATH],
9227 : buf4[MG_MAX_PATH], cmdline[MG_MAX_PATH];
9228 : DWORD flags = DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS;
9229 : FILE *fp;
9230 :
9231 : memset(&si, 0, sizeof(si));
9232 : memset(&pi, 0, sizeof(pi));
9233 :
9234 : si.cb = sizeof(si);
9235 : si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
9236 : si.wShowWindow = SW_HIDE;
9237 : si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
9238 :
9239 : CreatePipe(&a[0], &a[1], NULL, 0);
9240 : CreatePipe(&b[0], &b[1], NULL, 0);
9241 : DuplicateHandle(me, a[0], me, &si.hStdInput, 0, TRUE, flags);
9242 : DuplicateHandle(me, b[1], me, &si.hStdOutput, 0, TRUE, flags);
9243 :
9244 : if (interp == NULL && (fp = mg_fopen(cmd, "r")) != NULL) {
9245 : buf[0] = buf[1] = '\0';
9246 : fgets(buf, sizeof(buf), fp);
9247 : buf[sizeof(buf) - 1] = '\0';
9248 : if (buf[0] == '#' && buf[1] == '!') {
9249 : interp = buf + 2;
9250 : /* Trim leading spaces: https://github.com/cesanta/mongoose/issues/489 */
9251 : while (*interp != '\0' && isspace(*(unsigned char *) interp)) {
9252 : interp++;
9253 : }
9254 : }
9255 : fclose(fp);
9256 : }
9257 :
9258 : snprintf(buf, sizeof(buf), "%s/%s", dir, cmd);
9259 : mg_abs_path(buf, buf2, ARRAY_SIZE(buf2));
9260 :
9261 : mg_abs_path(dir, buf5, ARRAY_SIZE(buf5));
9262 : to_wchar(dir, full_dir, ARRAY_SIZE(full_dir));
9263 :
9264 : if (interp != NULL) {
9265 : mg_abs_path(interp, buf4, ARRAY_SIZE(buf4));
9266 : snprintf(cmdline, sizeof(cmdline), "%s \"%s\"", buf4, buf2);
9267 : } else {
9268 : snprintf(cmdline, sizeof(cmdline), "\"%s\"", buf2);
9269 : }
9270 : to_wchar(cmdline, wcmd, ARRAY_SIZE(wcmd));
9271 :
9272 : if (CreateProcessW(NULL, wcmd, NULL, NULL, TRUE, CREATE_NEW_PROCESS_GROUP,
9273 : (void *) env, full_dir, &si, &pi) != 0) {
9274 : mg_spawn_stdio_thread(sock, a[1], mg_push_to_stdin);
9275 : mg_spawn_stdio_thread(sock, b[0], mg_pull_from_stdout);
9276 :
9277 : CloseHandle(si.hStdOutput);
9278 : CloseHandle(si.hStdInput);
9279 :
9280 : CloseHandle(pi.hThread);
9281 : CloseHandle(pi.hProcess);
9282 : } else {
9283 : CloseHandle(a[1]);
9284 : CloseHandle(b[0]);
9285 : closesocket(sock);
9286 : }
9287 : DBG(("CGI command: [%ls] -> %p", wcmd, pi.hProcess));
9288 :
9289 : /* Not closing a[0] and b[1] because we've used DUPLICATE_CLOSE_SOURCE */
9290 : (void) envp;
9291 : return (pi.hProcess != NULL);
9292 : }
9293 : #else
9294 0 : static int mg_start_process(const char *interp, const char *cmd,
9295 : const char *env, const char *envp[],
9296 : const char *dir, sock_t sock) {
9297 : char buf[500];
9298 0 : pid_t pid = fork();
9299 : (void) env;
9300 :
9301 0 : if (pid == 0) {
9302 : /*
9303 : * In Linux `chdir` declared with `warn_unused_result` attribute
9304 : * To shutup compiler we have yo use result in some way
9305 : */
9306 0 : int tmp = chdir(dir);
9307 : (void) tmp;
9308 0 : (void) dup2(sock, 0);
9309 0 : (void) dup2(sock, 1);
9310 0 : closesocket(sock);
9311 :
9312 : /*
9313 : * After exec, all signal handlers are restored to their default values,
9314 : * with one exception of SIGCHLD. According to POSIX.1-2001 and Linux's
9315 : * implementation, SIGCHLD's handler will leave unchanged after exec
9316 : * if it was set to be ignored. Restore it to default action.
9317 : */
9318 0 : signal(SIGCHLD, SIG_DFL);
9319 :
9320 0 : if (interp == NULL) {
9321 0 : execle(cmd, cmd, (char *) 0, envp); /* (char *) 0 to squash warning */
9322 : } else {
9323 0 : execle(interp, interp, cmd, (char *) 0, envp);
9324 : }
9325 0 : snprintf(buf, sizeof(buf),
9326 : "Status: 500\r\n\r\n"
9327 : "500 Server Error: %s%s%s: %s",
9328 : interp == NULL ? "" : interp, interp == NULL ? "" : " ", cmd,
9329 0 : strerror(errno));
9330 0 : send(1, buf, strlen(buf), 0);
9331 0 : _exit(EXIT_FAILURE); /* exec call failed */
9332 : }
9333 :
9334 0 : return (pid != 0);
9335 : }
9336 : #endif /* _WIN32 */
9337 :
9338 : /*
9339 : * Append VARIABLE=VALUE\0 string to the buffer, and add a respective
9340 : * pointer into the vars array.
9341 : */
9342 0 : static char *mg_addenv(struct mg_cgi_env_block *block, const char *fmt, ...) {
9343 : int n, space;
9344 0 : char *added = block->buf + block->len;
9345 : va_list ap;
9346 :
9347 : /* Calculate how much space is left in the buffer */
9348 0 : space = sizeof(block->buf) - (block->len + 2);
9349 0 : if (space > 0) {
9350 : /* Copy VARIABLE=VALUE\0 string into the free space */
9351 0 : va_start(ap, fmt);
9352 0 : n = vsnprintf(added, (size_t) space, fmt, ap);
9353 0 : va_end(ap);
9354 :
9355 : /* Make sure we do not overflow buffer and the envp array */
9356 0 : if (n > 0 && n + 1 < space &&
9357 0 : block->nvars < (int) ARRAY_SIZE(block->vars) - 2) {
9358 : /* Append a pointer to the added string into the envp array */
9359 0 : block->vars[block->nvars++] = added;
9360 : /* Bump up used length counter. Include \0 terminator */
9361 0 : block->len += n + 1;
9362 : }
9363 : }
9364 :
9365 0 : return added;
9366 : }
9367 :
9368 0 : static void mg_addenv2(struct mg_cgi_env_block *blk, const char *name) {
9369 : const char *s;
9370 0 : if ((s = getenv(name)) != NULL) mg_addenv(blk, "%s=%s", name, s);
9371 0 : }
9372 :
9373 0 : static void mg_prepare_cgi_environment(struct mg_connection *nc,
9374 : const char *prog,
9375 : const struct mg_str *path_info,
9376 : const struct http_message *hm,
9377 : const struct mg_serve_http_opts *opts,
9378 : struct mg_cgi_env_block *blk) {
9379 : const char *s;
9380 : struct mg_str *h;
9381 : char *p;
9382 : size_t i;
9383 : char buf[100];
9384 0 : size_t path_info_len = path_info != NULL ? path_info->len : 0;
9385 :
9386 0 : blk->len = blk->nvars = 0;
9387 0 : blk->nc = nc;
9388 :
9389 0 : if ((s = getenv("SERVER_NAME")) != NULL) {
9390 0 : mg_addenv(blk, "SERVER_NAME=%s", s);
9391 : } else {
9392 0 : mg_sock_to_str(nc->sock, buf, sizeof(buf), 3);
9393 0 : mg_addenv(blk, "SERVER_NAME=%s", buf);
9394 : }
9395 0 : mg_addenv(blk, "SERVER_ROOT=%s", opts->document_root);
9396 0 : mg_addenv(blk, "DOCUMENT_ROOT=%s", opts->document_root);
9397 0 : mg_addenv(blk, "SERVER_SOFTWARE=%s/%s", "Mongoose", MG_VERSION);
9398 :
9399 : /* Prepare the environment block */
9400 0 : mg_addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
9401 0 : mg_addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
9402 0 : mg_addenv(blk, "%s", "REDIRECT_STATUS=200"); /* For PHP */
9403 :
9404 0 : mg_addenv(blk, "REQUEST_METHOD=%.*s", (int) hm->method.len, hm->method.p);
9405 :
9406 0 : mg_addenv(blk, "REQUEST_URI=%.*s%s%.*s", (int) hm->uri.len, hm->uri.p,
9407 0 : hm->query_string.len == 0 ? "" : "?", (int) hm->query_string.len,
9408 0 : hm->query_string.p);
9409 :
9410 0 : mg_conn_addr_to_str(nc, buf, sizeof(buf),
9411 : MG_SOCK_STRINGIFY_REMOTE | MG_SOCK_STRINGIFY_IP);
9412 0 : mg_addenv(blk, "REMOTE_ADDR=%s", buf);
9413 0 : mg_conn_addr_to_str(nc, buf, sizeof(buf), MG_SOCK_STRINGIFY_PORT);
9414 0 : mg_addenv(blk, "SERVER_PORT=%s", buf);
9415 :
9416 0 : s = hm->uri.p + hm->uri.len - path_info_len - 1;
9417 0 : if (*s == '/') {
9418 0 : const char *base_name = strrchr(prog, DIRSEP);
9419 0 : mg_addenv(blk, "SCRIPT_NAME=%.*s/%s", (int) (s - hm->uri.p), hm->uri.p,
9420 : (base_name != NULL ? base_name + 1 : prog));
9421 : } else {
9422 0 : mg_addenv(blk, "SCRIPT_NAME=%.*s", (int) (s - hm->uri.p + 1), hm->uri.p);
9423 : }
9424 0 : mg_addenv(blk, "SCRIPT_FILENAME=%s", prog);
9425 :
9426 0 : if (path_info != NULL && path_info->len > 0) {
9427 0 : mg_addenv(blk, "PATH_INFO=%.*s", (int) path_info->len, path_info->p);
9428 : /* Not really translated... */
9429 0 : mg_addenv(blk, "PATH_TRANSLATED=%.*s", (int) path_info->len, path_info->p);
9430 : }
9431 :
9432 : #if MG_ENABLE_SSL
9433 : mg_addenv(blk, "HTTPS=%s", (nc->flags & MG_F_SSL ? "on" : "off"));
9434 : #else
9435 0 : mg_addenv(blk, "HTTPS=off");
9436 : #endif
9437 :
9438 0 : if ((h = mg_get_http_header((struct http_message *) hm, "Content-Type")) !=
9439 : NULL) {
9440 0 : mg_addenv(blk, "CONTENT_TYPE=%.*s", (int) h->len, h->p);
9441 : }
9442 :
9443 0 : if (hm->query_string.len > 0) {
9444 0 : mg_addenv(blk, "QUERY_STRING=%.*s", (int) hm->query_string.len,
9445 0 : hm->query_string.p);
9446 : }
9447 :
9448 0 : if ((h = mg_get_http_header((struct http_message *) hm, "Content-Length")) !=
9449 : NULL) {
9450 0 : mg_addenv(blk, "CONTENT_LENGTH=%.*s", (int) h->len, h->p);
9451 : }
9452 :
9453 0 : mg_addenv2(blk, "PATH");
9454 0 : mg_addenv2(blk, "TMP");
9455 0 : mg_addenv2(blk, "TEMP");
9456 0 : mg_addenv2(blk, "TMPDIR");
9457 0 : mg_addenv2(blk, "PERLLIB");
9458 0 : mg_addenv2(blk, MG_ENV_EXPORT_TO_CGI);
9459 :
9460 : #ifdef _WIN32
9461 : mg_addenv2(blk, "COMSPEC");
9462 : mg_addenv2(blk, "SYSTEMROOT");
9463 : mg_addenv2(blk, "SystemDrive");
9464 : mg_addenv2(blk, "ProgramFiles");
9465 : mg_addenv2(blk, "ProgramFiles(x86)");
9466 : mg_addenv2(blk, "CommonProgramFiles(x86)");
9467 : #else
9468 0 : mg_addenv2(blk, "LD_LIBRARY_PATH");
9469 : #endif /* _WIN32 */
9470 :
9471 : /* Add all headers as HTTP_* variables */
9472 0 : for (i = 0; hm->header_names[i].len > 0; i++) {
9473 0 : p = mg_addenv(blk, "HTTP_%.*s=%.*s", (int) hm->header_names[i].len,
9474 0 : hm->header_names[i].p, (int) hm->header_values[i].len,
9475 0 : hm->header_values[i].p);
9476 :
9477 : /* Convert variable name into uppercase, and change - to _ */
9478 0 : for (; *p != '=' && *p != '\0'; p++) {
9479 0 : if (*p == '-') *p = '_';
9480 0 : *p = (char) toupper(*(unsigned char *) p);
9481 : }
9482 : }
9483 :
9484 0 : blk->vars[blk->nvars++] = NULL;
9485 0 : blk->buf[blk->len++] = '\0';
9486 0 : }
9487 :
9488 0 : static void mg_cgi_ev_handler(struct mg_connection *cgi_nc, int ev,
9489 : void *ev_data MG_UD_ARG(void *user_data)) {
9490 : #if !MG_ENABLE_CALLBACK_USERDATA
9491 0 : void *user_data = cgi_nc->user_data;
9492 : #endif
9493 0 : struct mg_connection *nc = (struct mg_connection *) user_data;
9494 : (void) ev_data;
9495 :
9496 0 : if (nc == NULL) {
9497 : /* The corresponding network connection was closed. */
9498 0 : cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY;
9499 0 : return;
9500 : }
9501 :
9502 0 : switch (ev) {
9503 0 : case MG_EV_RECV:
9504 : /*
9505 : * CGI script does not output reply line, like "HTTP/1.1 CODE XXXXX\n"
9506 : * It outputs headers, then body. Headers might include "Status"
9507 : * header, which changes CODE, and it might include "Location" header
9508 : * which changes CODE to 302.
9509 : *
9510 : * Therefore we do not send the output from the CGI script to the user
9511 : * until all CGI headers are received.
9512 : *
9513 : * Here we parse the output from the CGI script, and if all headers has
9514 : * been received, send appropriate reply line, and forward all
9515 : * received headers to the client.
9516 : */
9517 0 : if (nc->flags & MG_F_HTTP_CGI_PARSE_HEADERS) {
9518 0 : struct mbuf *io = &cgi_nc->recv_mbuf;
9519 0 : int len = mg_http_get_request_len(io->buf, io->len);
9520 :
9521 0 : if (len == 0) break;
9522 0 : if (len < 0 || io->len > MG_MAX_HTTP_REQUEST_SIZE) {
9523 0 : cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY;
9524 0 : mg_http_send_error(nc, 500, "Bad headers");
9525 : } else {
9526 : struct http_message hm;
9527 : struct mg_str *h;
9528 0 : mg_http_parse_headers(io->buf, io->buf + io->len, io->len, &hm);
9529 0 : if (mg_get_http_header(&hm, "Location") != NULL) {
9530 0 : mg_printf(nc, "%s", "HTTP/1.1 302 Moved\r\n");
9531 0 : } else if ((h = mg_get_http_header(&hm, "Status")) != NULL) {
9532 0 : mg_printf(nc, "HTTP/1.1 %.*s\r\n", (int) h->len, h->p);
9533 : } else {
9534 0 : mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\n");
9535 : }
9536 : }
9537 0 : nc->flags &= ~MG_F_HTTP_CGI_PARSE_HEADERS;
9538 : }
9539 0 : if (!(nc->flags & MG_F_HTTP_CGI_PARSE_HEADERS)) {
9540 0 : mg_forward(cgi_nc, nc);
9541 : }
9542 0 : break;
9543 0 : case MG_EV_CLOSE:
9544 0 : DBG(("%p CLOSE", cgi_nc));
9545 0 : mg_http_free_proto_data_cgi(&mg_http_get_proto_data(nc)->cgi);
9546 0 : nc->flags |= MG_F_SEND_AND_CLOSE;
9547 0 : break;
9548 : }
9549 : }
9550 :
9551 0 : MG_INTERNAL void mg_handle_cgi(struct mg_connection *nc, const char *prog,
9552 : const struct mg_str *path_info,
9553 : const struct http_message *hm,
9554 : const struct mg_serve_http_opts *opts) {
9555 : struct mg_cgi_env_block blk;
9556 : char dir[MG_MAX_PATH];
9557 : const char *p;
9558 : sock_t fds[2];
9559 :
9560 0 : DBG(("%p [%s]", nc, prog));
9561 0 : mg_prepare_cgi_environment(nc, prog, path_info, hm, opts, &blk);
9562 : /*
9563 : * CGI must be executed in its own directory. 'dir' must point to the
9564 : * directory containing executable program, 'p' must point to the
9565 : * executable program name relative to 'dir'.
9566 : */
9567 0 : if ((p = strrchr(prog, DIRSEP)) == NULL) {
9568 0 : snprintf(dir, sizeof(dir), "%s", ".");
9569 : } else {
9570 0 : snprintf(dir, sizeof(dir), "%.*s", (int) (p - prog), prog);
9571 0 : prog = p + 1;
9572 : }
9573 :
9574 0 : if (!mg_socketpair(fds, SOCK_STREAM)) {
9575 0 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
9576 0 : return;
9577 : }
9578 :
9579 : #ifndef _WIN32
9580 : struct sigaction sa;
9581 :
9582 0 : sigemptyset(&sa.sa_mask);
9583 0 : sa.sa_handler = SIG_IGN;
9584 0 : sa.sa_flags = 0;
9585 0 : sigaction(SIGCHLD, &sa, NULL);
9586 : #endif
9587 :
9588 0 : if (mg_start_process(opts->cgi_interpreter, prog, blk.buf, blk.vars, dir,
9589 0 : fds[1]) != 0) {
9590 : struct mg_connection *cgi_nc =
9591 0 : mg_add_sock(nc->mgr, fds[0], mg_cgi_ev_handler MG_UD_ARG(nc));
9592 0 : struct mg_http_proto_data *cgi_pd = mg_http_get_proto_data(nc);
9593 0 : cgi_pd->cgi.cgi_nc = cgi_nc;
9594 : #if !MG_ENABLE_CALLBACK_USERDATA
9595 0 : cgi_pd->cgi.cgi_nc->user_data = nc;
9596 : #endif
9597 0 : nc->flags |= MG_F_HTTP_CGI_PARSE_HEADERS;
9598 : /* Push POST data to the CGI */
9599 0 : if (hm->body.len > 0) {
9600 0 : mg_send(cgi_pd->cgi.cgi_nc, hm->body.p, hm->body.len);
9601 : }
9602 0 : mbuf_remove(&nc->recv_mbuf, nc->recv_mbuf.len);
9603 : } else {
9604 0 : closesocket(fds[0]);
9605 0 : mg_http_send_error(nc, 500, "CGI failure");
9606 : }
9607 :
9608 : #ifndef _WIN32
9609 0 : closesocket(fds[1]); /* On Windows, CGI stdio thread closes that socket */
9610 : #endif
9611 : }
9612 :
9613 0 : MG_INTERNAL void mg_http_free_proto_data_cgi(struct mg_http_proto_data_cgi *d) {
9614 0 : if (d == NULL) return;
9615 0 : if (d->cgi_nc != NULL) {
9616 0 : d->cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY;
9617 0 : d->cgi_nc->user_data = NULL;
9618 : }
9619 0 : memset(d, 0, sizeof(*d));
9620 : }
9621 :
9622 : #endif /* MG_ENABLE_HTTP && MG_ENABLE_HTTP_CGI */
9623 : #ifdef MG_MODULE_LINES
9624 : #line 1 "mongoose/src/mg_http_ssi.c"
9625 : #endif
9626 : /*
9627 : * Copyright (c) 2014-2016 Cesanta Software Limited
9628 : * All rights reserved
9629 : */
9630 :
9631 : #if MG_ENABLE_HTTP && MG_ENABLE_HTTP_SSI && MG_ENABLE_FILESYSTEM
9632 :
9633 : static void mg_send_ssi_file(struct mg_connection *nc, struct http_message *hm,
9634 : const char *path, FILE *fp, int include_level,
9635 : const struct mg_serve_http_opts *opts);
9636 :
9637 : static void mg_send_file_data(struct mg_connection *nc, FILE *fp) {
9638 : char buf[BUFSIZ];
9639 : size_t n;
9640 : while ((n = mg_fread(buf, 1, sizeof(buf), fp)) > 0) {
9641 : mg_send(nc, buf, n);
9642 : }
9643 : }
9644 :
9645 : #if 0
9646 : static void mg_do_ssi_include(struct mg_connection *nc, struct http_message *hm,
9647 : const char *ssi, char *tag, int include_level,
9648 : const struct mg_serve_http_opts *opts) {
9649 : char file_name[MG_MAX_PATH], path[MG_MAX_PATH], *p;
9650 : FILE *fp;
9651 :
9652 : /*
9653 : * sscanf() is safe here, since send_ssi_file() also uses buffer
9654 : * of size MG_BUF_LEN to get the tag. So strlen(tag) is always < MG_BUF_LEN.
9655 : */
9656 : if (sscanf(tag, " virtual=\"%[^\"]\"", file_name) == 1) {
9657 : /* File name is relative to the webserver root */
9658 : snprintf(path, sizeof(path), "%s/%s", opts->document_root, file_name);
9659 : } else if (sscanf(tag, " abspath=\"%[^\"]\"", file_name) == 1) {
9660 : /*
9661 : * File name is relative to the webserver working directory
9662 : * or it is absolute system path
9663 : */
9664 : snprintf(path, sizeof(path), "%s", file_name);
9665 : } else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1 ||
9666 : sscanf(tag, " \"%[^\"]\"", file_name) == 1) {
9667 : /* File name is relative to the currect document */
9668 : snprintf(path, sizeof(path), "%s", ssi);
9669 : if ((p = strrchr(path, DIRSEP)) != NULL) {
9670 : p[1] = '\0';
9671 : }
9672 : snprintf(path + strlen(path), sizeof(path) - strlen(path), "%s", file_name);
9673 : } else {
9674 : mg_printf(nc, "Bad SSI #include: [%s]", tag);
9675 : return;
9676 : }
9677 :
9678 : if ((fp = mg_fopen(path, "rb")) == NULL) {
9679 : mg_printf(nc, "SSI include error: mg_fopen(%s): %s", path,
9680 : strerror(mg_get_errno()));
9681 : } else {
9682 : mg_set_close_on_exec((sock_t) fileno(fp));
9683 : if (mg_match_prefix(opts->ssi_pattern, strlen(opts->ssi_pattern), path) >
9684 : 0) {
9685 : mg_send_ssi_file(nc, hm, path, fp, include_level + 1, opts);
9686 : } else {
9687 : mg_send_file_data(nc, fp);
9688 : }
9689 : fclose(fp);
9690 : }
9691 : }
9692 : #endif
9693 :
9694 : #if MG_ENABLE_HTTP_SSI_EXEC
9695 : static void do_ssi_exec(struct mg_connection *nc, char *tag) {
9696 : char cmd[BUFSIZ];
9697 : FILE *fp;
9698 :
9699 : if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) {
9700 : mg_printf(nc, "Bad SSI #exec: [%s]", tag);
9701 : } else if ((fp = popen(cmd, "r")) == NULL) {
9702 : mg_printf(nc, "Cannot SSI #exec: [%s]: %s", cmd, strerror(mg_get_errno()));
9703 : } else {
9704 : mg_send_file_data(nc, fp);
9705 : pclose(fp);
9706 : }
9707 : }
9708 : #endif /* MG_ENABLE_HTTP_SSI_EXEC */
9709 :
9710 : /*
9711 : * SSI directive has the following format:
9712 : * <!--#directive parameter=value parameter=value -->
9713 : */
9714 : #if 0
9715 : static void mg_send_ssi_file(struct mg_connection *nc, struct http_message *hm,
9716 : const char *path, FILE *fp, int include_level,
9717 : const struct mg_serve_http_opts *opts) {
9718 : static const struct mg_str btag = MG_MK_STR("<!--#");
9719 : static const struct mg_str d_include = MG_MK_STR("include");
9720 : static const struct mg_str d_call = MG_MK_STR("call");
9721 : #if MG_ENABLE_HTTP_SSI_EXEC
9722 : static const struct mg_str d_exec = MG_MK_STR("exec");
9723 : #endif
9724 : char buf[BUFSIZ], *p = buf + btag.len; /* p points to SSI directive */
9725 : int ch, len, in_ssi_tag;
9726 :
9727 : if (include_level > 10) {
9728 : mg_printf(nc, "SSI #include level is too deep (%s)", path);
9729 : return;
9730 : }
9731 :
9732 : in_ssi_tag = len = 0;
9733 : while ((ch = fgetc(fp)) != EOF) {
9734 : if (in_ssi_tag && ch == '>' && buf[len - 1] == '-' && buf[len - 2] == '-') {
9735 : size_t i = len - 2;
9736 : in_ssi_tag = 0;
9737 :
9738 : /* Trim closing --> */
9739 : buf[i--] = '\0';
9740 : while (i > 0 && buf[i] == ' ') {
9741 : buf[i--] = '\0';
9742 : }
9743 :
9744 : /* Handle known SSI directives */
9745 : if (strncmp(p, d_include.p, d_include.len) == 0) {
9746 : mg_do_ssi_include(nc, hm, path, p + d_include.len + 1, include_level,
9747 : opts);
9748 : } else if (strncmp(p, d_call.p, d_call.len) == 0) {
9749 : struct mg_ssi_call_ctx cctx;
9750 : memset(&cctx, 0, sizeof(cctx));
9751 : cctx.req = hm;
9752 : cctx.file = mg_mk_str(path);
9753 : cctx.arg = mg_mk_str(p + d_call.len + 1);
9754 : mg_call(nc, NULL, nc->user_data, MG_EV_SSI_CALL,
9755 : (void *) cctx.arg.p); /* NUL added above */
9756 : mg_call(nc, NULL, nc->user_data, MG_EV_SSI_CALL_CTX, &cctx);
9757 : #if MG_ENABLE_HTTP_SSI_EXEC
9758 : } else if (strncmp(p, d_exec.p, d_exec.len) == 0) {
9759 : do_ssi_exec(nc, p + d_exec.len + 1);
9760 : #endif
9761 : } else {
9762 : /* Silently ignore unknown SSI directive. */
9763 : }
9764 : len = 0;
9765 : } else if (ch == '<') {
9766 : in_ssi_tag = 1;
9767 : if (len > 0) {
9768 : mg_send(nc, buf, (size_t) len);
9769 : }
9770 : len = 0;
9771 : buf[len++] = ch & 0xff;
9772 : } else if (in_ssi_tag) {
9773 : if (len == (int) btag.len && strncmp(buf, btag.p, btag.len) != 0) {
9774 : /* Not an SSI tag */
9775 : in_ssi_tag = 0;
9776 : } else if (len == (int) sizeof(buf) - 2) {
9777 : mg_printf(nc, "%s: SSI tag is too large", path);
9778 : len = 0;
9779 : }
9780 : buf[len++] = ch & 0xff;
9781 : } else {
9782 : buf[len++] = ch & 0xff;
9783 : if (len == (int) sizeof(buf)) {
9784 : mg_send(nc, buf, (size_t) len);
9785 : len = 0;
9786 : }
9787 : }
9788 : }
9789 :
9790 : /* Send the rest of buffered data */
9791 : if (len > 0) {
9792 : mg_send(nc, buf, (size_t) len);
9793 : }
9794 : }
9795 :
9796 : MG_INTERNAL void mg_handle_ssi_request(struct mg_connection *nc,
9797 : struct http_message *hm,
9798 : const char *path,
9799 : const struct mg_serve_http_opts *opts) {
9800 : FILE *fp;
9801 : struct mg_str mime_type;
9802 : DBG(("%p %s", nc, path));
9803 :
9804 : if ((fp = mg_fopen(path, "rb")) == NULL) {
9805 : mg_http_send_error(nc, 404, NULL);
9806 : } else {
9807 : mg_set_close_on_exec((sock_t) fileno(fp));
9808 :
9809 : mime_type = mg_get_mime_type(path, "text/plain", opts);
9810 : mg_send_response_line(nc, 200, opts->extra_headers);
9811 : mg_printf(nc,
9812 : "Content-Type: %.*s\r\n"
9813 : "Connection: close\r\n\r\n",
9814 : (int) mime_type.len, mime_type.p);
9815 : mg_send_ssi_file(nc, hm, path, fp, 0, opts);
9816 : fclose(fp);
9817 : nc->flags |= MG_F_SEND_AND_CLOSE;
9818 : }
9819 : }
9820 : #endif
9821 :
9822 : #endif /* MG_ENABLE_HTTP_SSI && MG_ENABLE_HTTP && MG_ENABLE_FILESYSTEM */
9823 : #ifdef MG_MODULE_LINES
9824 : #line 1 "mongoose/src/mg_http_webdav.c"
9825 : #endif
9826 : /*
9827 : * Copyright (c) 2014-2016 Cesanta Software Limited
9828 : * All rights reserved
9829 : */
9830 :
9831 : #if MG_ENABLE_HTTP && MG_ENABLE_HTTP_WEBDAV
9832 :
9833 : MG_INTERNAL int mg_is_dav_request(const struct mg_str *s) {
9834 : static const char *methods[] = {
9835 : "PUT",
9836 : "DELETE",
9837 : "MKCOL",
9838 : "PROPFIND",
9839 : "MOVE"
9840 : #if MG_ENABLE_FAKE_DAVLOCK
9841 : ,
9842 : "LOCK",
9843 : "UNLOCK"
9844 : #endif
9845 : };
9846 : size_t i;
9847 :
9848 : for (i = 0; i < ARRAY_SIZE(methods); i++) {
9849 : if (mg_vcmp(s, methods[i]) == 0) {
9850 : return 1;
9851 : }
9852 : }
9853 :
9854 : return 0;
9855 : }
9856 :
9857 : static int mg_mkdir(const char *path, uint32_t mode) {
9858 : #ifndef _WIN32
9859 : return mkdir(path, mode);
9860 : #else
9861 : (void) mode;
9862 : return _mkdir(path);
9863 : #endif
9864 : }
9865 :
9866 : static void mg_print_props(struct mg_connection *nc, const char *name,
9867 : cs_stat_t *stp) {
9868 : char mtime[64];
9869 : time_t t = stp->st_mtime; /* store in local variable for NDK compile */
9870 : struct mg_str name_esc = mg_url_encode(mg_mk_str(name));
9871 : mg_gmt_time_string(mtime, sizeof(mtime), &t);
9872 : mg_printf(nc,
9873 : "<d:response>"
9874 : "<d:href>%s</d:href>"
9875 : "<d:propstat>"
9876 : "<d:prop>"
9877 : "<d:resourcetype>%s</d:resourcetype>"
9878 : "<d:getcontentlength>%" INT64_FMT
9879 : "</d:getcontentlength>"
9880 : "<d:getlastmodified>%s</d:getlastmodified>"
9881 : "</d:prop>"
9882 : "<d:status>HTTP/1.1 200 OK</d:status>"
9883 : "</d:propstat>"
9884 : "</d:response>\n",
9885 : name_esc.p, S_ISDIR(stp->st_mode) ? "<d:collection/>" : "",
9886 : (int64_t) stp->st_size, mtime);
9887 : free((void *) name_esc.p);
9888 : }
9889 :
9890 : MG_INTERNAL void mg_handle_propfind(struct mg_connection *nc, const char *path,
9891 : cs_stat_t *stp, struct http_message *hm,
9892 : struct mg_serve_http_opts *opts) {
9893 : static const char header[] =
9894 : "HTTP/1.1 207 Multi-Status\r\n"
9895 : "Connection: close\r\n"
9896 : "Content-Type: text/xml; charset=utf-8\r\n\r\n"
9897 : "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
9898 : "<d:multistatus xmlns:d='DAV:'>\n";
9899 : static const char footer[] = "</d:multistatus>\n";
9900 : const struct mg_str *depth = mg_get_http_header(hm, "Depth");
9901 :
9902 : /* Print properties for the requested resource itself */
9903 : if (S_ISDIR(stp->st_mode) &&
9904 : strcmp(opts->enable_directory_listing, "yes") != 0) {
9905 : mg_printf(nc, "%s", "HTTP/1.1 403 Directory Listing Denied\r\n\r\n");
9906 : } else {
9907 : char uri[MG_MAX_PATH];
9908 : mg_send(nc, header, sizeof(header) - 1);
9909 : snprintf(uri, sizeof(uri), "%.*s", (int) hm->uri.len, hm->uri.p);
9910 : mg_print_props(nc, uri, stp);
9911 : if (S_ISDIR(stp->st_mode) && (depth == NULL || mg_vcmp(depth, "0") != 0)) {
9912 : mg_scan_directory(nc, path, opts, mg_print_props);
9913 : }
9914 : mg_send(nc, footer, sizeof(footer) - 1);
9915 : nc->flags |= MG_F_SEND_AND_CLOSE;
9916 : }
9917 : }
9918 :
9919 : #if MG_ENABLE_FAKE_DAVLOCK
9920 : /*
9921 : * Windows explorer (probably there are another WebDav clients like it)
9922 : * requires LOCK support in webdav. W/out this, it still works, but fails
9923 : * to save file: shows error message and offers "Save As".
9924 : * "Save as" works, but this message is very annoying.
9925 : * This is fake lock, which doesn't lock something, just returns LOCK token,
9926 : * UNLOCK always answers "OK".
9927 : * With this fake LOCK Windows Explorer looks happy and saves file.
9928 : * NOTE: that is not DAV LOCK imlementation, it is just a way to shut up
9929 : * Windows native DAV client. This is why FAKE LOCK is not enabed by default
9930 : */
9931 : MG_INTERNAL void mg_handle_lock(struct mg_connection *nc, const char *path) {
9932 : static const char *reply =
9933 : "HTTP/1.1 207 Multi-Status\r\n"
9934 : "Connection: close\r\n"
9935 : "Content-Type: text/xml; charset=utf-8\r\n\r\n"
9936 : "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
9937 : "<d:multistatus xmlns:d='DAV:'>\n"
9938 : "<D:lockdiscovery>\n"
9939 : "<D:activelock>\n"
9940 : "<D:locktoken>\n"
9941 : "<D:href>\n"
9942 : "opaquelocktoken:%s%u"
9943 : "</D:href>"
9944 : "</D:locktoken>"
9945 : "</D:activelock>\n"
9946 : "</D:lockdiscovery>"
9947 : "</d:multistatus>\n";
9948 : mg_printf(nc, reply, path, (unsigned int) mg_time());
9949 : nc->flags |= MG_F_SEND_AND_CLOSE;
9950 : }
9951 : #endif
9952 :
9953 : MG_INTERNAL void mg_handle_mkcol(struct mg_connection *nc, const char *path,
9954 : struct http_message *hm) {
9955 : int status_code = 500;
9956 : if (hm->body.len != (size_t) ~0 && hm->body.len > 0) {
9957 : status_code = 415;
9958 : } else if (!mg_mkdir(path, 0755)) {
9959 : status_code = 201;
9960 : } else if (errno == EEXIST) {
9961 : status_code = 405;
9962 : } else if (errno == EACCES) {
9963 : status_code = 403;
9964 : } else if (errno == ENOENT) {
9965 : status_code = 409;
9966 : } else {
9967 : status_code = 500;
9968 : }
9969 : mg_http_send_error(nc, status_code, NULL);
9970 : }
9971 :
9972 : static int mg_remove_directory(const struct mg_serve_http_opts *opts,
9973 : const char *dir) {
9974 : char path[MG_MAX_PATH];
9975 : struct dirent *dp;
9976 : cs_stat_t st;
9977 : DIR *dirp;
9978 :
9979 : if ((dirp = opendir(dir)) == NULL) return 0;
9980 :
9981 : while ((dp = readdir(dirp)) != NULL) {
9982 : if (mg_is_file_hidden((const char *) dp->d_name, opts, 1)) {
9983 : continue;
9984 : }
9985 : snprintf(path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
9986 : mg_stat(path, &st);
9987 : if (S_ISDIR(st.st_mode)) {
9988 : mg_remove_directory(opts, path);
9989 : } else {
9990 : remove(path);
9991 : }
9992 : }
9993 : closedir(dirp);
9994 : rmdir(dir);
9995 :
9996 : return 1;
9997 : }
9998 :
9999 : MG_INTERNAL void mg_handle_move(struct mg_connection *c,
10000 : const struct mg_serve_http_opts *opts,
10001 : const char *path, struct http_message *hm) {
10002 : const struct mg_str *dest = mg_get_http_header(hm, "Destination");
10003 : if (dest == NULL) {
10004 : mg_http_send_error(c, 411, NULL);
10005 : } else {
10006 : const char *p = (char *) memchr(dest->p, '/', dest->len);
10007 : if (p != NULL && p[1] == '/' &&
10008 : (p = (char *) memchr(p + 2, '/', dest->p + dest->len - p)) != NULL) {
10009 : char buf[MG_MAX_PATH];
10010 : snprintf(buf, sizeof(buf), "%s%.*s", opts->dav_document_root,
10011 : (int) (dest->p + dest->len - p), p);
10012 : if (rename(path, buf) == 0) {
10013 : mg_http_send_error(c, 200, NULL);
10014 : } else {
10015 : mg_http_send_error(c, 418, NULL);
10016 : }
10017 : } else {
10018 : mg_http_send_error(c, 500, NULL);
10019 : }
10020 : }
10021 : }
10022 :
10023 : MG_INTERNAL void mg_handle_delete(struct mg_connection *nc,
10024 : const struct mg_serve_http_opts *opts,
10025 : const char *path) {
10026 : cs_stat_t st;
10027 : if (mg_stat(path, &st) != 0) {
10028 : mg_http_send_error(nc, 404, NULL);
10029 : } else if (S_ISDIR(st.st_mode)) {
10030 : mg_remove_directory(opts, path);
10031 : mg_http_send_error(nc, 204, NULL);
10032 : } else if (remove(path) == 0) {
10033 : mg_http_send_error(nc, 204, NULL);
10034 : } else {
10035 : mg_http_send_error(nc, 423, NULL);
10036 : }
10037 : }
10038 :
10039 : /* Return -1 on error, 1 on success. */
10040 : static int mg_create_itermediate_directories(const char *path) {
10041 : const char *s;
10042 :
10043 : /* Create intermediate directories if they do not exist */
10044 : for (s = path + 1; *s != '\0'; s++) {
10045 : if (*s == '/') {
10046 : char buf[MG_MAX_PATH];
10047 : cs_stat_t st;
10048 : snprintf(buf, sizeof(buf), "%.*s", (int) (s - path), path);
10049 : buf[sizeof(buf) - 1] = '\0';
10050 : if (mg_stat(buf, &st) != 0 && mg_mkdir(buf, 0755) != 0) {
10051 : return -1;
10052 : }
10053 : }
10054 : }
10055 :
10056 : return 1;
10057 : }
10058 :
10059 : MG_INTERNAL void mg_handle_put(struct mg_connection *nc, const char *path,
10060 : struct http_message *hm) {
10061 : struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
10062 : cs_stat_t st;
10063 : const struct mg_str *cl_hdr = mg_get_http_header(hm, "Content-Length");
10064 : int rc, status_code = mg_stat(path, &st) == 0 ? 200 : 201;
10065 :
10066 : mg_http_free_proto_data_file(&pd->file);
10067 : if ((rc = mg_create_itermediate_directories(path)) == 0) {
10068 : mg_printf(nc, "HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n", status_code);
10069 : } else if (rc == -1) {
10070 : mg_http_send_error(nc, 500, NULL);
10071 : } else if (cl_hdr == NULL) {
10072 : mg_http_send_error(nc, 411, NULL);
10073 : } else if ((pd->file.fp = mg_fopen(path, "w+b")) == NULL) {
10074 : mg_http_send_error(nc, 500, NULL);
10075 : } else {
10076 : const struct mg_str *range_hdr = mg_get_http_header(hm, "Content-Range");
10077 : int64_t r1 = 0, r2 = 0;
10078 : pd->file.type = DATA_PUT;
10079 : mg_set_close_on_exec((sock_t) fileno(pd->file.fp));
10080 : pd->file.cl = to64(cl_hdr->p);
10081 : if (range_hdr != NULL &&
10082 : mg_http_parse_range_header(range_hdr, &r1, &r2) > 0) {
10083 : status_code = 206;
10084 : fseeko(pd->file.fp, r1, SEEK_SET);
10085 : pd->file.cl = r2 > r1 ? r2 - r1 + 1 : pd->file.cl - r1;
10086 : }
10087 : mg_printf(nc, "HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n", status_code);
10088 : /* Remove HTTP request from the mbuf, leave only payload */
10089 : mbuf_remove(&nc->recv_mbuf, hm->message.len - hm->body.len);
10090 : mg_http_transfer_file_data(nc);
10091 : }
10092 : }
10093 :
10094 : #endif /* MG_ENABLE_HTTP && MG_ENABLE_HTTP_WEBDAV */
10095 : #ifdef MG_MODULE_LINES
10096 : #line 1 "mongoose/src/mg_http_websocket.c"
10097 : #endif
10098 : /*
10099 : * Copyright (c) 2014 Cesanta Software Limited
10100 : * All rights reserved
10101 : */
10102 :
10103 : #if MG_ENABLE_HTTP && MG_ENABLE_HTTP_WEBSOCKET
10104 :
10105 : /* Amalgamated: #include "common/cs_sha1.h" */
10106 :
10107 : #ifndef MG_WEBSOCKET_PING_INTERVAL_SECONDS
10108 : #define MG_WEBSOCKET_PING_INTERVAL_SECONDS 5
10109 : #endif
10110 :
10111 : #define FLAGS_MASK_FIN (1 << 7)
10112 : #define FLAGS_MASK_OP 0x0f
10113 :
10114 0 : static int mg_is_ws_fragment(unsigned char flags) {
10115 0 : return (flags & FLAGS_MASK_FIN) == 0 ||
10116 0 : (flags & FLAGS_MASK_OP) == WEBSOCKET_OP_CONTINUE;
10117 : }
10118 :
10119 0 : static int mg_is_ws_first_fragment(unsigned char flags) {
10120 0 : return (flags & FLAGS_MASK_FIN) == 0 &&
10121 0 : (flags & FLAGS_MASK_OP) != WEBSOCKET_OP_CONTINUE;
10122 : }
10123 :
10124 0 : static int mg_is_ws_control_frame(unsigned char flags) {
10125 0 : unsigned char op = (flags & FLAGS_MASK_OP);
10126 0 : return op == WEBSOCKET_OP_CLOSE || op == WEBSOCKET_OP_PING ||
10127 0 : op == WEBSOCKET_OP_PONG;
10128 : }
10129 :
10130 0 : static void mg_handle_incoming_websocket_frame(struct mg_connection *nc,
10131 : struct websocket_message *wsm) {
10132 0 : if (wsm->flags & 0x8) {
10133 0 : mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_CONTROL_FRAME, wsm);
10134 : } else {
10135 0 : mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_FRAME, wsm);
10136 : }
10137 0 : }
10138 :
10139 0 : static struct mg_ws_proto_data *mg_ws_get_proto_data(struct mg_connection *nc) {
10140 0 : struct mg_http_proto_data *htd = mg_http_get_proto_data(nc);
10141 0 : return (htd != NULL ? &htd->ws_data : NULL);
10142 : }
10143 :
10144 : /*
10145 : * Sends a Close websocket frame with the given data, and closes the underlying
10146 : * connection. If `len` is ~0, strlen(data) is used.
10147 : */
10148 0 : static void mg_ws_close(struct mg_connection *nc, const void *data,
10149 : size_t len) {
10150 0 : if ((int) len == ~0) {
10151 0 : len = strlen((const char *) data);
10152 : }
10153 0 : mg_send_websocket_frame(nc, WEBSOCKET_OP_CLOSE, data, len);
10154 0 : nc->flags |= MG_F_SEND_AND_CLOSE;
10155 0 : }
10156 :
10157 0 : static int mg_deliver_websocket_data(struct mg_connection *nc) {
10158 : /* Using unsigned char *, cause of integer arithmetic below */
10159 0 : uint64_t i, data_len = 0, frame_len = 0, new_data_len = nc->recv_mbuf.len,
10160 0 : len, mask_len = 0, header_len = 0;
10161 0 : struct mg_ws_proto_data *wsd = mg_ws_get_proto_data(nc);
10162 0 : unsigned char *new_data = (unsigned char *) nc->recv_mbuf.buf,
10163 0 : *e = (unsigned char *) nc->recv_mbuf.buf + nc->recv_mbuf.len;
10164 : uint8_t flags;
10165 : int ok, reass;
10166 :
10167 0 : if (wsd->reass_len > 0) {
10168 : /*
10169 : * We already have some previously received data which we need to
10170 : * reassemble and deliver to the client code when we get the final
10171 : * fragment.
10172 : *
10173 : * NOTE: it doesn't mean that the current message must be a continuation:
10174 : * it might be a control frame (Close, Ping or Pong), which should be
10175 : * handled without breaking the fragmented message.
10176 : */
10177 :
10178 0 : size_t existing_len = wsd->reass_len;
10179 0 : assert(new_data_len >= existing_len);
10180 :
10181 0 : new_data += existing_len;
10182 0 : new_data_len -= existing_len;
10183 : }
10184 :
10185 0 : flags = new_data[0];
10186 :
10187 0 : reass = new_data_len > 0 && mg_is_ws_fragment(flags) &&
10188 0 : !(nc->flags & MG_F_WEBSOCKET_NO_DEFRAG);
10189 :
10190 0 : if (reass && mg_is_ws_control_frame(flags)) {
10191 : /*
10192 : * Control frames can't be fragmented, so if we encounter fragmented
10193 : * control frame, close connection immediately.
10194 : */
10195 0 : mg_ws_close(nc, "fragmented control frames are illegal", ~0);
10196 0 : return 0;
10197 0 : } else if (new_data_len > 0 && !reass && !mg_is_ws_control_frame(flags) &&
10198 0 : wsd->reass_len > 0) {
10199 : /*
10200 : * When in the middle of a fragmented message, only the continuations
10201 : * and control frames are allowed.
10202 : */
10203 0 : mg_ws_close(nc, "non-continuation in the middle of a fragmented message",
10204 : ~0);
10205 0 : return 0;
10206 : }
10207 :
10208 0 : if (new_data_len >= 2) {
10209 0 : len = new_data[1] & 0x7f;
10210 0 : mask_len = new_data[1] & FLAGS_MASK_FIN ? 4 : 0;
10211 0 : if (len < 126 && new_data_len >= mask_len) {
10212 0 : data_len = len;
10213 0 : header_len = 2 + mask_len;
10214 0 : } else if (len == 126 && new_data_len >= 4 + mask_len) {
10215 0 : header_len = 4 + mask_len;
10216 0 : data_len = ntohs(*(uint16_t *) &new_data[2]);
10217 0 : } else if (new_data_len >= 10 + mask_len) {
10218 0 : header_len = 10 + mask_len;
10219 0 : data_len = (((uint64_t) ntohl(*(uint32_t *) &new_data[2])) << 32) +
10220 0 : ntohl(*(uint32_t *) &new_data[6]);
10221 : }
10222 : }
10223 :
10224 0 : frame_len = header_len + data_len;
10225 0 : ok = (frame_len > 0 && frame_len <= new_data_len);
10226 :
10227 : /* Check for overflow */
10228 0 : if (frame_len < header_len || frame_len < data_len) {
10229 0 : ok = 0;
10230 0 : mg_ws_close(nc, "overflowed message", ~0);
10231 : }
10232 :
10233 0 : if (ok) {
10234 0 : size_t cleanup_len = 0;
10235 : struct websocket_message wsm;
10236 :
10237 0 : wsm.size = (size_t) data_len;
10238 0 : wsm.data = new_data + header_len;
10239 0 : wsm.flags = flags;
10240 :
10241 : /* Apply mask if necessary */
10242 0 : if (mask_len > 0) {
10243 0 : for (i = 0; i < data_len; i++) {
10244 0 : new_data[i + header_len] ^= (new_data + header_len - mask_len)[i % 4];
10245 : }
10246 : }
10247 :
10248 0 : if (reass) {
10249 : /* This is a message fragment */
10250 :
10251 0 : if (mg_is_ws_first_fragment(flags)) {
10252 : /*
10253 : * On the first fragmented frame, skip the first byte (op) and also
10254 : * reset size to 1 (op), it'll be incremented with the data len below.
10255 : */
10256 0 : new_data += 1;
10257 0 : wsd->reass_len = 1 /* op */;
10258 : }
10259 :
10260 : /* Append this frame to the reassembled buffer */
10261 0 : memmove(new_data, wsm.data, e - wsm.data);
10262 0 : wsd->reass_len += wsm.size;
10263 0 : nc->recv_mbuf.len -= wsm.data - new_data;
10264 :
10265 0 : if (flags & FLAGS_MASK_FIN) {
10266 : /* On last fragmented frame - call user handler and remove data */
10267 0 : wsm.flags = FLAGS_MASK_FIN | nc->recv_mbuf.buf[0];
10268 0 : wsm.data = (unsigned char *) nc->recv_mbuf.buf + 1 /* op */;
10269 0 : wsm.size = wsd->reass_len - 1 /* op */;
10270 0 : cleanup_len = wsd->reass_len;
10271 0 : wsd->reass_len = 0;
10272 :
10273 : /* Pass reassembled message to the client code. */
10274 0 : mg_handle_incoming_websocket_frame(nc, &wsm);
10275 0 : mbuf_remove(&nc->recv_mbuf, cleanup_len); /* Cleanup frame */
10276 : }
10277 : } else {
10278 : /*
10279 : * This is a complete message, not a fragment. It might happen in between
10280 : * of a fragmented message (in this case, WebSocket protocol requires
10281 : * current message to be a control frame).
10282 : */
10283 0 : cleanup_len = (size_t) frame_len;
10284 :
10285 : /* First of all, check if we need to react on a control frame. */
10286 0 : switch (flags & FLAGS_MASK_OP) {
10287 0 : case WEBSOCKET_OP_PING:
10288 0 : mg_send_websocket_frame(nc, WEBSOCKET_OP_PONG, wsm.data, wsm.size);
10289 0 : break;
10290 :
10291 0 : case WEBSOCKET_OP_CLOSE:
10292 0 : mg_ws_close(nc, wsm.data, wsm.size);
10293 0 : break;
10294 : }
10295 :
10296 : /* Pass received message to the client code. */
10297 0 : mg_handle_incoming_websocket_frame(nc, &wsm);
10298 :
10299 : /* Cleanup frame */
10300 0 : memmove(nc->recv_mbuf.buf + wsd->reass_len,
10301 0 : nc->recv_mbuf.buf + wsd->reass_len + cleanup_len,
10302 0 : nc->recv_mbuf.len - wsd->reass_len - cleanup_len);
10303 0 : nc->recv_mbuf.len -= cleanup_len;
10304 : }
10305 : }
10306 :
10307 0 : return ok;
10308 : }
10309 :
10310 : struct ws_mask_ctx {
10311 : size_t pos; /* zero means unmasked */
10312 : uint32_t mask;
10313 : };
10314 :
10315 0 : static uint32_t mg_ws_random_mask(void) {
10316 : uint32_t mask;
10317 : /*
10318 : * The spec requires WS client to generate hard to
10319 : * guess mask keys. From RFC6455, Section 5.3:
10320 : *
10321 : * The unpredictability of the masking key is essential to prevent
10322 : * authors of malicious applications from selecting the bytes that appear on
10323 : * the wire.
10324 : *
10325 : * Hence this feature is essential when the actual end user of this API
10326 : * is untrusted code that wouldn't have access to a lower level net API
10327 : * anyway (e.g. web browsers). Hence this feature is low prio for most
10328 : * mongoose use cases and thus can be disabled, e.g. when porting to a platform
10329 : * that lacks rand().
10330 : */
10331 : #if MG_DISABLE_WS_RANDOM_MASK
10332 : mask = 0xefbeadde; /* generated with a random number generator, I swear */
10333 : #else
10334 : if (sizeof(long) >= 4) {
10335 0 : mask = (uint32_t) rand();
10336 : } else if (sizeof(long) == 2) {
10337 : mask = (uint32_t) rand() << 16 | (uint32_t) rand();
10338 : }
10339 : #endif
10340 0 : return mask;
10341 : }
10342 :
10343 0 : static void mg_send_ws_header(struct mg_connection *nc, int op, size_t len,
10344 : struct ws_mask_ctx *ctx) {
10345 : int header_len;
10346 : unsigned char header[10];
10347 :
10348 0 : header[0] =
10349 0 : (op & WEBSOCKET_DONT_FIN ? 0x0 : FLAGS_MASK_FIN) | (op & FLAGS_MASK_OP);
10350 0 : if (len < 126) {
10351 0 : header[1] = (unsigned char) len;
10352 0 : header_len = 2;
10353 0 : } else if (len < 65535) {
10354 0 : uint16_t tmp = htons((uint16_t) len);
10355 0 : header[1] = 126;
10356 0 : memcpy(&header[2], &tmp, sizeof(tmp));
10357 0 : header_len = 4;
10358 : } else {
10359 : uint32_t tmp;
10360 0 : header[1] = 127;
10361 0 : tmp = htonl((uint32_t)((uint64_t) len >> 32));
10362 0 : memcpy(&header[2], &tmp, sizeof(tmp));
10363 0 : tmp = htonl((uint32_t)(len & 0xffffffff));
10364 0 : memcpy(&header[6], &tmp, sizeof(tmp));
10365 0 : header_len = 10;
10366 : }
10367 :
10368 : /* client connections enable masking */
10369 0 : if (nc->listener == NULL) {
10370 0 : header[1] |= 1 << 7; /* set masking flag */
10371 0 : mg_send(nc, header, header_len);
10372 0 : ctx->mask = mg_ws_random_mask();
10373 0 : mg_send(nc, &ctx->mask, sizeof(ctx->mask));
10374 0 : ctx->pos = nc->send_mbuf.len;
10375 : } else {
10376 0 : mg_send(nc, header, header_len);
10377 0 : ctx->pos = 0;
10378 : }
10379 0 : }
10380 :
10381 0 : static void mg_ws_mask_frame(struct mbuf *mbuf, struct ws_mask_ctx *ctx) {
10382 : size_t i;
10383 0 : if (ctx->pos == 0) return;
10384 0 : for (i = 0; i < (mbuf->len - ctx->pos); i++) {
10385 0 : mbuf->buf[ctx->pos + i] ^= ((char *) &ctx->mask)[i % 4];
10386 : }
10387 : }
10388 :
10389 0 : void mg_send_websocket_frame(struct mg_connection *nc, int op, const void *data,
10390 : size_t len) {
10391 : struct ws_mask_ctx ctx;
10392 0 : DBG(("%p %d %d", nc, op, (int) len));
10393 0 : mg_send_ws_header(nc, op, len, &ctx);
10394 0 : mg_send(nc, data, len);
10395 :
10396 0 : mg_ws_mask_frame(&nc->send_mbuf, &ctx);
10397 :
10398 0 : if (op == WEBSOCKET_OP_CLOSE) {
10399 0 : nc->flags |= MG_F_SEND_AND_CLOSE;
10400 : }
10401 0 : }
10402 :
10403 0 : void mg_send_websocket_framev(struct mg_connection *nc, int op,
10404 : const struct mg_str *strv, int strvcnt) {
10405 : struct ws_mask_ctx ctx;
10406 : int i;
10407 0 : int len = 0;
10408 0 : for (i = 0; i < strvcnt; i++) {
10409 0 : len += strv[i].len;
10410 : }
10411 :
10412 0 : mg_send_ws_header(nc, op, len, &ctx);
10413 :
10414 0 : for (i = 0; i < strvcnt; i++) {
10415 0 : mg_send(nc, strv[i].p, strv[i].len);
10416 : }
10417 :
10418 0 : mg_ws_mask_frame(&nc->send_mbuf, &ctx);
10419 :
10420 0 : if (op == WEBSOCKET_OP_CLOSE) {
10421 0 : nc->flags |= MG_F_SEND_AND_CLOSE;
10422 : }
10423 0 : }
10424 :
10425 0 : void mg_printf_websocket_frame(struct mg_connection *nc, int op,
10426 : const char *fmt, ...) {
10427 0 : char mem[MG_VPRINTF_BUFFER_SIZE], *buf = mem;
10428 : va_list ap;
10429 : int len;
10430 :
10431 0 : va_start(ap, fmt);
10432 0 : if ((len = mg_avprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
10433 0 : mg_send_websocket_frame(nc, op, buf, len);
10434 : }
10435 0 : va_end(ap);
10436 :
10437 0 : if (buf != mem && buf != NULL) {
10438 0 : MG_FREE(buf);
10439 : }
10440 0 : }
10441 :
10442 0 : MG_INTERNAL void mg_ws_handler(struct mg_connection *nc, int ev,
10443 : void *ev_data MG_UD_ARG(void *user_data)) {
10444 0 : mg_call(nc, nc->handler, nc->user_data, ev, ev_data);
10445 :
10446 0 : switch (ev) {
10447 0 : case MG_EV_RECV:
10448 : do {
10449 0 : } while (mg_deliver_websocket_data(nc));
10450 0 : break;
10451 0 : case MG_EV_POLL:
10452 : /* Ping idle websocket connections */
10453 : {
10454 0 : time_t now = *(time_t *) ev_data;
10455 0 : if (nc->flags & MG_F_IS_WEBSOCKET &&
10456 0 : now > nc->last_io_time + MG_WEBSOCKET_PING_INTERVAL_SECONDS) {
10457 0 : mg_send_websocket_frame(nc, WEBSOCKET_OP_PING, "", 0);
10458 : }
10459 : }
10460 0 : break;
10461 0 : default:
10462 0 : break;
10463 : }
10464 : #if MG_ENABLE_CALLBACK_USERDATA
10465 : (void) user_data;
10466 : #endif
10467 0 : }
10468 :
10469 : #ifndef MG_EXT_SHA1
10470 0 : void mg_hash_sha1_v(size_t num_msgs, const uint8_t *msgs[],
10471 : const size_t *msg_lens, uint8_t *digest) {
10472 : size_t i;
10473 : cs_sha1_ctx sha_ctx;
10474 0 : cs_sha1_init(&sha_ctx);
10475 0 : for (i = 0; i < num_msgs; i++) {
10476 0 : cs_sha1_update(&sha_ctx, msgs[i], msg_lens[i]);
10477 : }
10478 0 : cs_sha1_final(digest, &sha_ctx);
10479 0 : }
10480 : #else
10481 : extern void mg_hash_sha1_v(size_t num_msgs, const uint8_t *msgs[],
10482 : const size_t *msg_lens, uint8_t *digest);
10483 : #endif
10484 :
10485 0 : MG_INTERNAL void mg_ws_handshake(struct mg_connection *nc,
10486 : const struct mg_str *key,
10487 : struct http_message *hm) {
10488 : static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
10489 0 : const uint8_t *msgs[2] = {(const uint8_t *) key->p, (const uint8_t *) magic};
10490 0 : const size_t msg_lens[2] = {key->len, 36};
10491 : unsigned char sha[20];
10492 : char b64_sha[30];
10493 : struct mg_str *s;
10494 :
10495 0 : mg_hash_sha1_v(2, msgs, msg_lens, sha);
10496 0 : mg_base64_encode(sha, sizeof(sha), b64_sha);
10497 0 : mg_printf(nc, "%s",
10498 : "HTTP/1.1 101 Switching Protocols\r\n"
10499 : "Upgrade: websocket\r\n"
10500 : "Connection: Upgrade\r\n");
10501 :
10502 0 : s = mg_get_http_header(hm, "Sec-WebSocket-Protocol");
10503 0 : if (s != NULL) {
10504 0 : mg_printf(nc, "Sec-WebSocket-Protocol: %.*s\r\n", (int) s->len, s->p);
10505 : }
10506 0 : mg_printf(nc, "Sec-WebSocket-Accept: %s%s", b64_sha, "\r\n\r\n");
10507 :
10508 0 : DBG(("%p %.*s %s", nc, (int) key->len, key->p, b64_sha));
10509 0 : }
10510 :
10511 0 : void mg_send_websocket_handshake2(struct mg_connection *nc, const char *path,
10512 : const char *host, const char *protocol,
10513 : const char *extra_headers) {
10514 0 : mg_send_websocket_handshake3(nc, path, host, protocol, extra_headers, NULL,
10515 : NULL);
10516 0 : }
10517 :
10518 0 : void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path,
10519 : const char *host, const char *protocol,
10520 : const char *extra_headers, const char *user,
10521 : const char *pass) {
10522 0 : mg_send_websocket_handshake3v(nc, mg_mk_str(path), mg_mk_str(host),
10523 : mg_mk_str(protocol), mg_mk_str(extra_headers),
10524 : mg_mk_str(user), mg_mk_str(pass));
10525 0 : }
10526 :
10527 0 : void mg_send_websocket_handshake3v(struct mg_connection *nc,
10528 : const struct mg_str path,
10529 : const struct mg_str host,
10530 : const struct mg_str protocol,
10531 : const struct mg_str extra_headers,
10532 : const struct mg_str user,
10533 : const struct mg_str pass) {
10534 : struct mbuf auth;
10535 : char key[25];
10536 : uint32_t nonce[4];
10537 0 : nonce[0] = mg_ws_random_mask();
10538 0 : nonce[1] = mg_ws_random_mask();
10539 0 : nonce[2] = mg_ws_random_mask();
10540 0 : nonce[3] = mg_ws_random_mask();
10541 0 : mg_base64_encode((unsigned char *) &nonce, sizeof(nonce), key);
10542 :
10543 0 : mbuf_init(&auth, 0);
10544 0 : if (user.len > 0) {
10545 0 : mg_basic_auth_header(user, pass, &auth);
10546 : }
10547 :
10548 : /*
10549 : * NOTE: the (auth.buf == NULL ? "" : auth.buf) is because cc3200 libc is
10550 : * broken: it doesn't like zero length to be passed to %.*s
10551 : * i.e. sprintf("f%.*so", (int)0, NULL), yields `f\0o`.
10552 : * because it handles NULL specially (and incorrectly).
10553 : */
10554 0 : mg_printf(nc,
10555 : "GET %.*s HTTP/1.1\r\n"
10556 : "Upgrade: websocket\r\n"
10557 : "Connection: Upgrade\r\n"
10558 : "%.*s"
10559 : "Sec-WebSocket-Version: 13\r\n"
10560 : "Sec-WebSocket-Key: %s\r\n",
10561 0 : (int) path.len, path.p, (int) auth.len,
10562 0 : (auth.buf == NULL ? "" : auth.buf), key);
10563 :
10564 : /* TODO(mkm): take default hostname from http proto data if host == NULL */
10565 0 : if (host.len > 0) {
10566 0 : int host_len = (int) (path.p - host.p); /* Account for possible :PORT */
10567 0 : mg_printf(nc, "Host: %.*s\r\n", host_len, host.p);
10568 : }
10569 0 : if (protocol.len > 0) {
10570 0 : mg_printf(nc, "Sec-WebSocket-Protocol: %.*s\r\n", (int) protocol.len,
10571 0 : protocol.p);
10572 : }
10573 0 : if (extra_headers.len > 0) {
10574 0 : mg_printf(nc, "%.*s", (int) extra_headers.len, extra_headers.p);
10575 : }
10576 0 : mg_printf(nc, "\r\n");
10577 :
10578 0 : nc->flags |= MG_F_IS_WEBSOCKET;
10579 :
10580 0 : mbuf_free(&auth);
10581 0 : }
10582 :
10583 0 : void mg_send_websocket_handshake(struct mg_connection *nc, const char *path,
10584 : const char *extra_headers) {
10585 0 : struct mg_str null_str = MG_NULL_STR;
10586 0 : mg_send_websocket_handshake3v(
10587 : nc, mg_mk_str(path), null_str /* host */, null_str /* protocol */,
10588 : mg_mk_str(extra_headers), null_str /* user */, null_str /* pass */);
10589 0 : }
10590 :
10591 0 : struct mg_connection *mg_connect_ws_opt(
10592 : struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data),
10593 : struct mg_connect_opts opts, const char *url, const char *protocol,
10594 : const char *extra_headers) {
10595 0 : struct mg_str null_str = MG_NULL_STR;
10596 0 : struct mg_str host = MG_NULL_STR, path = MG_NULL_STR, user_info = MG_NULL_STR;
10597 : struct mg_connection *nc =
10598 0 : mg_connect_http_base(mgr, MG_CB(ev_handler, user_data), opts, "http",
10599 : "ws", "https", "wss", url, &path, &user_info, &host);
10600 0 : if (nc != NULL) {
10601 0 : mg_send_websocket_handshake3v(nc, path, host, mg_mk_str(protocol),
10602 : mg_mk_str(extra_headers), user_info,
10603 : null_str);
10604 : }
10605 0 : return nc;
10606 : }
10607 :
10608 0 : struct mg_connection *mg_connect_ws(
10609 : struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data),
10610 : const char *url, const char *protocol, const char *extra_headers) {
10611 : struct mg_connect_opts opts;
10612 0 : memset(&opts, 0, sizeof(opts));
10613 0 : return mg_connect_ws_opt(mgr, MG_CB(ev_handler, user_data), opts, url,
10614 0 : protocol, extra_headers);
10615 : }
10616 : #endif /* MG_ENABLE_HTTP && MG_ENABLE_HTTP_WEBSOCKET */
10617 : #ifdef MG_MODULE_LINES
10618 : #line 1 "mongoose/src/mg_util.c"
10619 : #endif
10620 : /*
10621 : * Copyright (c) 2014 Cesanta Software Limited
10622 : * All rights reserved
10623 : */
10624 :
10625 : /* Amalgamated: #include "common/cs_base64.h" */
10626 : /* Amalgamated: #include "mg_internal.h" */
10627 : /* Amalgamated: #include "mg_util.h" */
10628 :
10629 : /* For platforms with limited libc */
10630 : #ifndef MAX
10631 : #define MAX(a, b) ((a) > (b) ? (a) : (b))
10632 : #endif
10633 :
10634 0 : const char *mg_skip(const char *s, const char *end, const char *delims,
10635 : struct mg_str *v) {
10636 0 : v->p = s;
10637 0 : while (s < end && strchr(delims, *(unsigned char *) s) == NULL) s++;
10638 0 : v->len = s - v->p;
10639 0 : while (s < end && strchr(delims, *(unsigned char *) s) != NULL) s++;
10640 0 : return s;
10641 : }
10642 :
10643 : #if MG_ENABLE_FILESYSTEM && !defined(MG_USER_FILE_FUNCTIONS)
10644 0 : int mg_stat(const char *path, cs_stat_t *st) {
10645 : #ifdef _WIN32
10646 : wchar_t wpath[MG_MAX_PATH];
10647 : to_wchar(path, wpath, ARRAY_SIZE(wpath));
10648 : DBG(("[%ls] -> %d", wpath, _wstati64(wpath, st)));
10649 : return _wstati64(wpath, st);
10650 : #else
10651 0 : return stat(path, st);
10652 : #endif
10653 : }
10654 :
10655 0 : FILE *mg_fopen(const char *path, const char *mode) {
10656 : #ifdef _WIN32
10657 : wchar_t wpath[MG_MAX_PATH], wmode[10];
10658 : to_wchar(path, wpath, ARRAY_SIZE(wpath));
10659 : to_wchar(mode, wmode, ARRAY_SIZE(wmode));
10660 : return _wfopen(wpath, wmode);
10661 : #else
10662 0 : return fopen(path, mode);
10663 : #endif
10664 : }
10665 :
10666 : int mg_open(const char *path, int flag, int mode) { /* LCOV_EXCL_LINE */
10667 : #if defined(_WIN32) && !defined(WINCE)
10668 : wchar_t wpath[MG_MAX_PATH];
10669 : to_wchar(path, wpath, ARRAY_SIZE(wpath));
10670 : return _wopen(wpath, flag, mode);
10671 : #else
10672 : return open(path, flag, mode); /* LCOV_EXCL_LINE */
10673 : #endif
10674 : }
10675 :
10676 0 : size_t mg_fread(void *ptr, size_t size, size_t count, FILE *f) {
10677 0 : return fread(ptr, size, count, f);
10678 : }
10679 :
10680 0 : size_t mg_fwrite(const void *ptr, size_t size, size_t count, FILE *f) {
10681 0 : return fwrite(ptr, size, count, f);
10682 : }
10683 : #endif
10684 :
10685 0 : void mg_base64_encode(const unsigned char *src, int src_len, char *dst) {
10686 0 : cs_base64_encode(src, src_len, dst);
10687 0 : }
10688 :
10689 0 : int mg_base64_decode(const unsigned char *s, int len, char *dst) {
10690 0 : return cs_base64_decode(s, len, dst, NULL);
10691 : }
10692 :
10693 : #if MG_ENABLE_THREADS
10694 0 : void *mg_start_thread(void *(*f)(void *), void *p) {
10695 : #ifdef WINCE
10696 : return (void *) CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) f, p, 0, NULL);
10697 : #elif defined(_WIN32)
10698 : return (void *) _beginthread((void(__cdecl *) (void *) ) f, 0, p);
10699 : #else
10700 0 : pthread_t thread_id = (pthread_t) 0;
10701 : pthread_attr_t attr;
10702 :
10703 0 : (void) pthread_attr_init(&attr);
10704 0 : (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
10705 :
10706 : #if defined(MG_STACK_SIZE) && MG_STACK_SIZE > 1
10707 : (void) pthread_attr_setstacksize(&attr, MG_STACK_SIZE);
10708 : #endif
10709 :
10710 0 : pthread_create(&thread_id, &attr, f, p);
10711 0 : pthread_attr_destroy(&attr);
10712 :
10713 0 : return (void *) thread_id;
10714 : #endif
10715 : }
10716 : #endif /* MG_ENABLE_THREADS */
10717 :
10718 : /* Set close-on-exec bit for a given socket. */
10719 0 : void mg_set_close_on_exec(sock_t sock) {
10720 : #if defined(_WIN32) && !defined(WINCE)
10721 : (void) SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
10722 : #elif defined(__unix__)
10723 0 : fcntl(sock, F_SETFD, FD_CLOEXEC);
10724 : #else
10725 : (void) sock;
10726 : #endif
10727 0 : }
10728 :
10729 0 : int mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len,
10730 : int flags) {
10731 : int is_v6;
10732 0 : if (buf == NULL || len <= 0) return 0;
10733 0 : memset(buf, 0, len);
10734 : #if MG_ENABLE_IPV6
10735 0 : is_v6 = sa->sa.sa_family == AF_INET6;
10736 : #else
10737 : is_v6 = 0;
10738 : #endif
10739 0 : if (flags & MG_SOCK_STRINGIFY_IP) {
10740 : #if MG_ENABLE_IPV6
10741 0 : const void *addr = NULL;
10742 0 : char *start = buf;
10743 0 : socklen_t capacity = len;
10744 0 : if (!is_v6) {
10745 0 : addr = &sa->sin.sin_addr;
10746 : } else {
10747 0 : addr = (void *) &sa->sin6.sin6_addr;
10748 0 : if (flags & MG_SOCK_STRINGIFY_PORT) {
10749 0 : *buf = '[';
10750 0 : start++;
10751 0 : capacity--;
10752 : }
10753 : }
10754 0 : if (inet_ntop(sa->sa.sa_family, addr, start, capacity) == NULL) {
10755 0 : goto cleanup;
10756 : }
10757 : #elif defined(_WIN32) || MG_LWIP || (MG_NET_IF == MG_NET_IF_PIC32)
10758 : /* Only Windoze Vista (and newer) have inet_ntop() */
10759 : char *addr_str = inet_ntoa(sa->sin.sin_addr);
10760 : if (addr_str != NULL) {
10761 : strncpy(buf, inet_ntoa(sa->sin.sin_addr), len - 1);
10762 : } else {
10763 : goto cleanup;
10764 : }
10765 : #else
10766 : if (inet_ntop(AF_INET, (void *) &sa->sin.sin_addr, buf, len) == NULL) {
10767 : goto cleanup;
10768 : }
10769 : #endif
10770 : }
10771 0 : if (flags & MG_SOCK_STRINGIFY_PORT) {
10772 0 : int port = ntohs(sa->sin.sin_port);
10773 0 : if (flags & MG_SOCK_STRINGIFY_IP) {
10774 0 : int buf_len = strlen(buf);
10775 0 : snprintf(buf + buf_len, len - (buf_len + 1), "%s:%d", (is_v6 ? "]" : ""),
10776 : port);
10777 : } else {
10778 0 : snprintf(buf, len, "%d", port);
10779 : }
10780 : }
10781 :
10782 0 : return strlen(buf);
10783 :
10784 0 : cleanup:
10785 0 : *buf = '\0';
10786 0 : return 0;
10787 : }
10788 :
10789 0 : int mg_conn_addr_to_str(struct mg_connection *nc, char *buf, size_t len,
10790 : int flags) {
10791 : union socket_address sa;
10792 0 : memset(&sa, 0, sizeof(sa));
10793 0 : mg_if_get_conn_addr(nc, flags & MG_SOCK_STRINGIFY_REMOTE, &sa);
10794 0 : return mg_sock_addr_to_str(&sa, buf, len, flags);
10795 : }
10796 :
10797 : #if MG_ENABLE_HEXDUMP
10798 0 : static int mg_hexdump_n(const void *buf, int len, char *dst, int dst_len,
10799 : int offset) {
10800 0 : const unsigned char *p = (const unsigned char *) buf;
10801 0 : char ascii[17] = "";
10802 0 : int i, idx, n = 0;
10803 :
10804 0 : for (i = 0; i < len; i++) {
10805 0 : idx = i % 16;
10806 0 : if (idx == 0) {
10807 0 : if (i > 0) n += snprintf(dst + n, MAX(dst_len - n, 0), " %s\n", ascii);
10808 0 : n += snprintf(dst + n, MAX(dst_len - n, 0), "%04x ", i + offset);
10809 : }
10810 0 : if (dst_len - n < 0) {
10811 0 : return n;
10812 : }
10813 0 : n += snprintf(dst + n, MAX(dst_len - n, 0), " %02x", p[i]);
10814 0 : ascii[idx] = p[i] < 0x20 || p[i] > 0x7e ? '.' : p[i];
10815 0 : ascii[idx + 1] = '\0';
10816 : }
10817 :
10818 0 : while (i++ % 16) n += snprintf(dst + n, MAX(dst_len - n, 0), "%s", " ");
10819 0 : n += snprintf(dst + n, MAX(dst_len - n, 0), " %s\n", ascii);
10820 :
10821 0 : return n;
10822 : }
10823 :
10824 0 : int mg_hexdump(const void *buf, int len, char *dst, int dst_len) {
10825 0 : return mg_hexdump_n(buf, len, dst, dst_len, 0);
10826 : }
10827 :
10828 0 : void mg_hexdumpf(FILE *fp, const void *buf, int len) {
10829 : char tmp[80];
10830 0 : int offset = 0, n;
10831 0 : while (len > 0) {
10832 0 : n = (len < 16 ? len : 16);
10833 0 : mg_hexdump_n(((const char *) buf) + offset, n, tmp, sizeof(tmp), offset);
10834 0 : fputs(tmp, fp);
10835 0 : offset += n;
10836 0 : len -= n;
10837 : }
10838 0 : }
10839 :
10840 0 : void mg_hexdump_connection(struct mg_connection *nc, const char *path,
10841 : const void *buf, int num_bytes, int ev) {
10842 0 : FILE *fp = NULL;
10843 : char src[60], dst[60];
10844 0 : const char *tag = NULL;
10845 0 : switch (ev) {
10846 0 : case MG_EV_RECV:
10847 0 : tag = "<-";
10848 0 : break;
10849 0 : case MG_EV_SEND:
10850 0 : tag = "->";
10851 0 : break;
10852 0 : case MG_EV_ACCEPT:
10853 0 : tag = "<A";
10854 0 : break;
10855 0 : case MG_EV_CONNECT:
10856 0 : tag = "C>";
10857 0 : break;
10858 0 : case MG_EV_CLOSE:
10859 0 : tag = "XX";
10860 0 : break;
10861 : }
10862 0 : if (tag == NULL) return; /* Don't log MG_EV_TIMER, etc */
10863 :
10864 0 : if (strcmp(path, "-") == 0) {
10865 0 : fp = stdout;
10866 0 : } else if (strcmp(path, "--") == 0) {
10867 0 : fp = stderr;
10868 : #if MG_ENABLE_FILESYSTEM
10869 : } else {
10870 0 : fp = mg_fopen(path, "a");
10871 : #endif
10872 : }
10873 0 : if (fp == NULL) return;
10874 :
10875 0 : mg_conn_addr_to_str(nc, src, sizeof(src),
10876 : MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT);
10877 0 : mg_conn_addr_to_str(nc, dst, sizeof(dst), MG_SOCK_STRINGIFY_IP |
10878 : MG_SOCK_STRINGIFY_PORT |
10879 : MG_SOCK_STRINGIFY_REMOTE);
10880 0 : fprintf(fp, "%lu %p %s %s %s %d\n", (unsigned long) mg_time(), (void *) nc,
10881 : src, tag, dst, (int) num_bytes);
10882 0 : if (num_bytes > 0) {
10883 0 : mg_hexdumpf(fp, buf, num_bytes);
10884 : }
10885 0 : if (fp != stdout && fp != stderr) fclose(fp);
10886 : }
10887 : #endif
10888 :
10889 0 : int mg_is_big_endian(void) {
10890 : static const int n = 1;
10891 : /* TODO(mkm) use compiletime check with 4-byte char literal */
10892 0 : return ((char *) &n)[0] == 0;
10893 : }
10894 :
10895 0 : DO_NOT_WARN_UNUSED MG_INTERNAL int mg_get_errno(void) {
10896 : #ifndef WINCE
10897 0 : return errno;
10898 : #else
10899 : /* TODO(alashkin): translate error codes? */
10900 : return GetLastError();
10901 : #endif
10902 : }
10903 :
10904 0 : void mg_mbuf_append_base64_putc(char ch, void *user_data) {
10905 0 : struct mbuf *mbuf = (struct mbuf *) user_data;
10906 0 : mbuf_append(mbuf, &ch, sizeof(ch));
10907 0 : }
10908 :
10909 0 : void mg_mbuf_append_base64(struct mbuf *mbuf, const void *data, size_t len) {
10910 : struct cs_base64_ctx ctx;
10911 0 : cs_base64_init(&ctx, mg_mbuf_append_base64_putc, mbuf);
10912 0 : cs_base64_update(&ctx, (const char *) data, len);
10913 0 : cs_base64_finish(&ctx);
10914 0 : }
10915 :
10916 0 : void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass,
10917 : struct mbuf *buf) {
10918 0 : const char *header_prefix = "Authorization: Basic ";
10919 0 : const char *header_suffix = "\r\n";
10920 :
10921 : struct cs_base64_ctx ctx;
10922 0 : cs_base64_init(&ctx, mg_mbuf_append_base64_putc, buf);
10923 :
10924 0 : mbuf_append(buf, header_prefix, strlen(header_prefix));
10925 :
10926 0 : cs_base64_update(&ctx, user.p, user.len);
10927 0 : if (pass.len > 0) {
10928 0 : cs_base64_update(&ctx, ":", 1);
10929 0 : cs_base64_update(&ctx, pass.p, pass.len);
10930 : }
10931 0 : cs_base64_finish(&ctx);
10932 0 : mbuf_append(buf, header_suffix, strlen(header_suffix));
10933 0 : }
10934 :
10935 0 : struct mg_str mg_url_encode_opt(const struct mg_str src,
10936 : const struct mg_str safe, unsigned int flags) {
10937 0 : const char *hex =
10938 0 : (flags & MG_URL_ENCODE_F_UPPERCASE_HEX ? "0123456789ABCDEF"
10939 : : "0123456789abcdef");
10940 0 : size_t i = 0;
10941 : struct mbuf mb;
10942 0 : mbuf_init(&mb, src.len);
10943 :
10944 0 : for (i = 0; i < src.len; i++) {
10945 0 : const unsigned char c = *((const unsigned char *) src.p + i);
10946 0 : if (isalnum(c) || mg_strchr(safe, c) != NULL) {
10947 0 : mbuf_append(&mb, &c, 1);
10948 0 : } else if (c == ' ' && (flags & MG_URL_ENCODE_F_SPACE_AS_PLUS)) {
10949 0 : mbuf_append(&mb, "+", 1);
10950 : } else {
10951 0 : mbuf_append(&mb, "%", 1);
10952 0 : mbuf_append(&mb, &hex[c >> 4], 1);
10953 0 : mbuf_append(&mb, &hex[c & 15], 1);
10954 : }
10955 : }
10956 0 : mbuf_append(&mb, "", 1);
10957 0 : mbuf_trim(&mb);
10958 0 : return mg_mk_str_n(mb.buf, mb.len - 1);
10959 : }
10960 :
10961 0 : struct mg_str mg_url_encode(const struct mg_str src) {
10962 0 : return mg_url_encode_opt(src, mg_mk_str("._-$,;~()/"), 0);
10963 : }
10964 : #ifdef MG_MODULE_LINES
10965 : #line 1 "mongoose/src/mg_mqtt.c"
10966 : #endif
10967 : /*
10968 : * Copyright (c) 2014 Cesanta Software Limited
10969 : * All rights reserved
10970 : */
10971 :
10972 : #if MG_ENABLE_MQTT
10973 :
10974 : #include <string.h>
10975 :
10976 : /* Amalgamated: #include "mg_internal.h" */
10977 : /* Amalgamated: #include "mg_mqtt.h" */
10978 :
10979 0 : static uint16_t getu16(const char *p) {
10980 0 : const uint8_t *up = (const uint8_t *) p;
10981 0 : return (up[0] << 8) + up[1];
10982 : }
10983 :
10984 0 : static const char *scanto(const char *p, struct mg_str *s) {
10985 0 : s->len = getu16(p);
10986 0 : s->p = p + 2;
10987 0 : return s->p + s->len;
10988 : }
10989 :
10990 0 : MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm) {
10991 : uint8_t header;
10992 0 : size_t len = 0, len_len = 0;
10993 0 : const char *p, *end, *eop = &io->buf[io->len];
10994 0 : unsigned char lc = 0;
10995 : int cmd;
10996 :
10997 0 : if (io->len < 2) return MG_MQTT_ERROR_INCOMPLETE_MSG;
10998 0 : header = io->buf[0];
10999 0 : cmd = header >> 4;
11000 :
11001 : /* decode mqtt variable length */
11002 0 : len = len_len = 0;
11003 0 : p = io->buf + 1;
11004 0 : while (p < eop) {
11005 0 : lc = *((const unsigned char *) p++);
11006 0 : len += (lc & 0x7f) << 7 * len_len;
11007 0 : len_len++;
11008 0 : if (!(lc & 0x80)) break;
11009 0 : if (len_len > 4) return MG_MQTT_ERROR_MALFORMED_MSG;
11010 : }
11011 :
11012 0 : end = p + len;
11013 0 : if (lc & 0x80 || end > eop) return MG_MQTT_ERROR_INCOMPLETE_MSG;
11014 :
11015 0 : mm->cmd = cmd;
11016 0 : mm->qos = MG_MQTT_GET_QOS(header);
11017 :
11018 0 : switch (cmd) {
11019 0 : case MG_MQTT_CMD_CONNECT: {
11020 0 : p = scanto(p, &mm->protocol_name);
11021 0 : if (p > end - 4) return MG_MQTT_ERROR_MALFORMED_MSG;
11022 0 : mm->protocol_version = *(uint8_t *) p++;
11023 0 : mm->connect_flags = *(uint8_t *) p++;
11024 0 : mm->keep_alive_timer = getu16(p);
11025 0 : p += 2;
11026 0 : if (p >= end) return MG_MQTT_ERROR_MALFORMED_MSG;
11027 0 : p = scanto(p, &mm->client_id);
11028 0 : if (p > end) return MG_MQTT_ERROR_MALFORMED_MSG;
11029 0 : if (mm->connect_flags & MG_MQTT_HAS_WILL) {
11030 0 : if (p >= end) return MG_MQTT_ERROR_MALFORMED_MSG;
11031 0 : p = scanto(p, &mm->will_topic);
11032 : }
11033 0 : if (mm->connect_flags & MG_MQTT_HAS_WILL) {
11034 0 : if (p >= end) return MG_MQTT_ERROR_MALFORMED_MSG;
11035 0 : p = scanto(p, &mm->will_message);
11036 : }
11037 0 : if (mm->connect_flags & MG_MQTT_HAS_USER_NAME) {
11038 0 : if (p >= end) return MG_MQTT_ERROR_MALFORMED_MSG;
11039 0 : p = scanto(p, &mm->user_name);
11040 : }
11041 0 : if (mm->connect_flags & MG_MQTT_HAS_PASSWORD) {
11042 0 : if (p >= end) return MG_MQTT_ERROR_MALFORMED_MSG;
11043 0 : p = scanto(p, &mm->password);
11044 : }
11045 0 : if (p != end) return MG_MQTT_ERROR_MALFORMED_MSG;
11046 :
11047 0 : LOG(LL_DEBUG,
11048 : ("%d %2x %d proto [%.*s] client_id [%.*s] will_topic [%.*s] "
11049 : "will_msg [%.*s] user_name [%.*s] password [%.*s]",
11050 : (int) len, (int) mm->connect_flags, (int) mm->keep_alive_timer,
11051 : (int) mm->protocol_name.len, mm->protocol_name.p,
11052 : (int) mm->client_id.len, mm->client_id.p, (int) mm->will_topic.len,
11053 : mm->will_topic.p, (int) mm->will_message.len, mm->will_message.p,
11054 : (int) mm->user_name.len, mm->user_name.p, (int) mm->password.len,
11055 : mm->password.p));
11056 0 : break;
11057 : }
11058 0 : case MG_MQTT_CMD_CONNACK:
11059 0 : if (end - p < 2) return MG_MQTT_ERROR_MALFORMED_MSG;
11060 0 : mm->connack_ret_code = p[1];
11061 0 : break;
11062 0 : case MG_MQTT_CMD_PUBACK:
11063 : case MG_MQTT_CMD_PUBREC:
11064 : case MG_MQTT_CMD_PUBREL:
11065 : case MG_MQTT_CMD_PUBCOMP:
11066 : case MG_MQTT_CMD_SUBACK:
11067 0 : if (end - p < 2) return MG_MQTT_ERROR_MALFORMED_MSG;
11068 0 : mm->message_id = getu16(p);
11069 0 : p += 2;
11070 0 : break;
11071 0 : case MG_MQTT_CMD_PUBLISH: {
11072 0 : p = scanto(p, &mm->topic);
11073 0 : if (p > end) return MG_MQTT_ERROR_MALFORMED_MSG;
11074 0 : if (mm->qos > 0) {
11075 0 : if (end - p < 2) return MG_MQTT_ERROR_MALFORMED_MSG;
11076 0 : mm->message_id = getu16(p);
11077 0 : p += 2;
11078 : }
11079 0 : mm->payload.p = p;
11080 0 : mm->payload.len = end - p;
11081 0 : break;
11082 : }
11083 0 : case MG_MQTT_CMD_SUBSCRIBE:
11084 0 : if (end - p < 2) return MG_MQTT_ERROR_MALFORMED_MSG;
11085 0 : mm->message_id = getu16(p);
11086 0 : p += 2;
11087 : /*
11088 : * topic expressions are left in the payload and can be parsed with
11089 : * `mg_mqtt_next_subscribe_topic`
11090 : */
11091 0 : mm->payload.p = p;
11092 0 : mm->payload.len = end - p;
11093 0 : break;
11094 0 : default:
11095 : /* Unhandled command */
11096 0 : break;
11097 : }
11098 :
11099 0 : mm->len = end - io->buf;
11100 0 : return mm->len;
11101 : }
11102 :
11103 0 : static void mqtt_handler(struct mg_connection *nc, int ev,
11104 : void *ev_data MG_UD_ARG(void *user_data)) {
11105 0 : struct mbuf *io = &nc->recv_mbuf;
11106 : struct mg_mqtt_message mm;
11107 0 : memset(&mm, 0, sizeof(mm));
11108 :
11109 0 : nc->handler(nc, ev, ev_data MG_UD_ARG(user_data));
11110 :
11111 0 : switch (ev) {
11112 0 : case MG_EV_ACCEPT:
11113 0 : if (nc->proto_data == NULL) mg_set_protocol_mqtt(nc);
11114 0 : break;
11115 0 : case MG_EV_RECV: {
11116 : /* There can be multiple messages in the buffer, process them all. */
11117 : while (1) {
11118 0 : int len = parse_mqtt(io, &mm);
11119 0 : if (len < 0) {
11120 0 : if (len == MG_MQTT_ERROR_MALFORMED_MSG) {
11121 : /* Protocol error. */
11122 0 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
11123 0 : } else if (len == MG_MQTT_ERROR_INCOMPLETE_MSG) {
11124 : /* Not fully buffered, let's check if we have a chance to get more
11125 : * data later */
11126 0 : if (nc->recv_mbuf_limit > 0 &&
11127 0 : nc->recv_mbuf.len >= nc->recv_mbuf_limit) {
11128 0 : LOG(LL_ERROR, ("%p recv buffer (%lu bytes) exceeds the limit "
11129 : "%lu bytes, and not drained, closing",
11130 : nc, (unsigned long) nc->recv_mbuf.len,
11131 : (unsigned long) nc->recv_mbuf_limit));
11132 0 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
11133 : }
11134 : } else {
11135 : /* Should never be here */
11136 0 : LOG(LL_ERROR, ("%p invalid len: %d, closing", nc, len));
11137 0 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
11138 : }
11139 0 : break;
11140 : }
11141 :
11142 0 : nc->handler(nc, MG_MQTT_EVENT_BASE + mm.cmd, &mm MG_UD_ARG(user_data));
11143 0 : mbuf_remove(io, len);
11144 0 : }
11145 0 : break;
11146 : }
11147 0 : case MG_EV_POLL: {
11148 0 : struct mg_mqtt_proto_data *pd =
11149 : (struct mg_mqtt_proto_data *) nc->proto_data;
11150 0 : double now = mg_time();
11151 0 : if (pd->keep_alive > 0 && pd->last_control_time > 0 &&
11152 0 : (now - pd->last_control_time) > pd->keep_alive) {
11153 0 : LOG(LL_DEBUG, ("Send PINGREQ"));
11154 0 : mg_mqtt_ping(nc);
11155 : }
11156 0 : break;
11157 : }
11158 : }
11159 0 : }
11160 :
11161 0 : static void mg_mqtt_proto_data_destructor(void *proto_data) {
11162 0 : MG_FREE(proto_data);
11163 0 : }
11164 :
11165 0 : static struct mg_str mg_mqtt_next_topic_component(struct mg_str *topic) {
11166 0 : struct mg_str res = *topic;
11167 0 : const char *c = mg_strchr(*topic, '/');
11168 0 : if (c != NULL) {
11169 0 : res.len = (c - topic->p);
11170 0 : topic->len -= (res.len + 1);
11171 0 : topic->p += (res.len + 1);
11172 : } else {
11173 0 : topic->len = 0;
11174 : }
11175 0 : return res;
11176 : }
11177 :
11178 : /* Refernce: https://mosquitto.org/man/mqtt-7.html */
11179 0 : int mg_mqtt_match_topic_expression(struct mg_str exp, struct mg_str topic) {
11180 : struct mg_str ec, tc;
11181 0 : if (exp.len == 0) return 0;
11182 : while (1) {
11183 0 : ec = mg_mqtt_next_topic_component(&exp);
11184 0 : tc = mg_mqtt_next_topic_component(&topic);
11185 0 : if (ec.len == 0) {
11186 0 : if (tc.len != 0) return 0;
11187 0 : if (exp.len == 0) break;
11188 0 : continue;
11189 : }
11190 0 : if (mg_vcmp(&ec, "+") == 0) {
11191 0 : if (tc.len == 0 && topic.len == 0) return 0;
11192 0 : continue;
11193 : }
11194 0 : if (mg_vcmp(&ec, "#") == 0) {
11195 : /* Must be the last component in the expression or it's invalid. */
11196 0 : return (exp.len == 0);
11197 : }
11198 0 : if (mg_strcmp(ec, tc) != 0) {
11199 0 : return 0;
11200 : }
11201 : }
11202 0 : return (tc.len == 0 && topic.len == 0);
11203 : }
11204 :
11205 0 : int mg_mqtt_vmatch_topic_expression(const char *exp, struct mg_str topic) {
11206 0 : return mg_mqtt_match_topic_expression(mg_mk_str(exp), topic);
11207 : }
11208 :
11209 0 : void mg_set_protocol_mqtt(struct mg_connection *nc) {
11210 0 : nc->proto_handler = mqtt_handler;
11211 0 : nc->proto_data = MG_CALLOC(1, sizeof(struct mg_mqtt_proto_data));
11212 0 : nc->proto_data_destructor = mg_mqtt_proto_data_destructor;
11213 0 : }
11214 :
11215 0 : static void mg_send_mqtt_header(struct mg_connection *nc, uint8_t cmd,
11216 : uint8_t flags, size_t len) {
11217 0 : struct mg_mqtt_proto_data *pd = (struct mg_mqtt_proto_data *) nc->proto_data;
11218 : uint8_t buf[1 + sizeof(size_t)];
11219 0 : uint8_t *vlen = &buf[1];
11220 :
11221 0 : buf[0] = (cmd << 4) | flags;
11222 :
11223 : /* mqtt variable length encoding */
11224 : do {
11225 0 : *vlen = len % 0x80;
11226 0 : len /= 0x80;
11227 0 : if (len > 0) *vlen |= 0x80;
11228 0 : vlen++;
11229 0 : } while (len > 0);
11230 :
11231 0 : mg_send(nc, buf, vlen - buf);
11232 0 : pd->last_control_time = mg_time();
11233 0 : }
11234 :
11235 0 : void mg_send_mqtt_handshake(struct mg_connection *nc, const char *client_id) {
11236 : static struct mg_send_mqtt_handshake_opts opts;
11237 0 : mg_send_mqtt_handshake_opt(nc, client_id, opts);
11238 0 : }
11239 :
11240 0 : void mg_send_mqtt_handshake_opt(struct mg_connection *nc, const char *client_id,
11241 : struct mg_send_mqtt_handshake_opts opts) {
11242 0 : struct mg_mqtt_proto_data *pd = (struct mg_mqtt_proto_data *) nc->proto_data;
11243 0 : uint16_t id_len = 0, wt_len = 0, wm_len = 0, user_len = 0, pw_len = 0;
11244 : uint16_t netbytes;
11245 : size_t total_len;
11246 :
11247 0 : if (client_id != NULL) {
11248 0 : id_len = strlen(client_id);
11249 : }
11250 :
11251 0 : total_len = 7 + 1 + 2 + 2 + id_len;
11252 :
11253 0 : if (opts.user_name != NULL) {
11254 0 : opts.flags |= MG_MQTT_HAS_USER_NAME;
11255 : }
11256 0 : if (opts.password != NULL) {
11257 0 : opts.flags |= MG_MQTT_HAS_PASSWORD;
11258 : }
11259 0 : if (opts.will_topic != NULL && opts.will_message != NULL) {
11260 0 : wt_len = strlen(opts.will_topic);
11261 0 : wm_len = strlen(opts.will_message);
11262 0 : opts.flags |= MG_MQTT_HAS_WILL;
11263 : }
11264 0 : if (opts.keep_alive == 0) {
11265 0 : opts.keep_alive = 60;
11266 : }
11267 :
11268 0 : if (opts.flags & MG_MQTT_HAS_WILL) {
11269 0 : total_len += 2 + wt_len + 2 + wm_len;
11270 : }
11271 0 : if (opts.flags & MG_MQTT_HAS_USER_NAME) {
11272 0 : user_len = strlen(opts.user_name);
11273 0 : total_len += 2 + user_len;
11274 : }
11275 0 : if (opts.flags & MG_MQTT_HAS_PASSWORD) {
11276 0 : pw_len = strlen(opts.password);
11277 0 : total_len += 2 + pw_len;
11278 : }
11279 :
11280 0 : mg_send_mqtt_header(nc, MG_MQTT_CMD_CONNECT, 0, total_len);
11281 0 : mg_send(nc, "\00\04MQTT\04", 7);
11282 0 : mg_send(nc, &opts.flags, 1);
11283 :
11284 0 : netbytes = htons(opts.keep_alive);
11285 0 : mg_send(nc, &netbytes, 2);
11286 :
11287 0 : netbytes = htons(id_len);
11288 0 : mg_send(nc, &netbytes, 2);
11289 0 : mg_send(nc, client_id, id_len);
11290 :
11291 0 : if (opts.flags & MG_MQTT_HAS_WILL) {
11292 0 : netbytes = htons(wt_len);
11293 0 : mg_send(nc, &netbytes, 2);
11294 0 : mg_send(nc, opts.will_topic, wt_len);
11295 :
11296 0 : netbytes = htons(wm_len);
11297 0 : mg_send(nc, &netbytes, 2);
11298 0 : mg_send(nc, opts.will_message, wm_len);
11299 : }
11300 :
11301 0 : if (opts.flags & MG_MQTT_HAS_USER_NAME) {
11302 0 : netbytes = htons(user_len);
11303 0 : mg_send(nc, &netbytes, 2);
11304 0 : mg_send(nc, opts.user_name, user_len);
11305 : }
11306 0 : if (opts.flags & MG_MQTT_HAS_PASSWORD) {
11307 0 : netbytes = htons(pw_len);
11308 0 : mg_send(nc, &netbytes, 2);
11309 0 : mg_send(nc, opts.password, pw_len);
11310 : }
11311 :
11312 0 : if (pd != NULL) {
11313 0 : pd->keep_alive = opts.keep_alive;
11314 : }
11315 0 : }
11316 :
11317 0 : void mg_mqtt_publish(struct mg_connection *nc, const char *topic,
11318 : uint16_t message_id, int flags, const void *data,
11319 : size_t len) {
11320 : uint16_t netbytes;
11321 0 : uint16_t topic_len = strlen(topic);
11322 :
11323 0 : size_t total_len = 2 + topic_len + len;
11324 0 : if (MG_MQTT_GET_QOS(flags) > 0) {
11325 0 : total_len += 2;
11326 : }
11327 :
11328 0 : mg_send_mqtt_header(nc, MG_MQTT_CMD_PUBLISH, flags, total_len);
11329 :
11330 0 : netbytes = htons(topic_len);
11331 0 : mg_send(nc, &netbytes, 2);
11332 0 : mg_send(nc, topic, topic_len);
11333 :
11334 0 : if (MG_MQTT_GET_QOS(flags) > 0) {
11335 0 : netbytes = htons(message_id);
11336 0 : mg_send(nc, &netbytes, 2);
11337 : }
11338 :
11339 0 : mg_send(nc, data, len);
11340 0 : }
11341 :
11342 0 : void mg_mqtt_subscribe(struct mg_connection *nc,
11343 : const struct mg_mqtt_topic_expression *topics,
11344 : size_t topics_len, uint16_t message_id) {
11345 : uint16_t netbytes;
11346 : size_t i;
11347 : uint16_t topic_len;
11348 0 : size_t total_len = 2;
11349 :
11350 0 : for (i = 0; i < topics_len; i++) {
11351 0 : total_len += 2 + strlen(topics[i].topic) + 1;
11352 : }
11353 :
11354 0 : mg_send_mqtt_header(nc, MG_MQTT_CMD_SUBSCRIBE, MG_MQTT_QOS(1), total_len);
11355 :
11356 0 : netbytes = htons(message_id);
11357 0 : mg_send(nc, (char *) &netbytes, 2);
11358 :
11359 0 : for (i = 0; i < topics_len; i++) {
11360 0 : topic_len = strlen(topics[i].topic);
11361 0 : netbytes = htons(topic_len);
11362 0 : mg_send(nc, &netbytes, 2);
11363 0 : mg_send(nc, topics[i].topic, topic_len);
11364 0 : mg_send(nc, &topics[i].qos, 1);
11365 : }
11366 0 : }
11367 :
11368 0 : int mg_mqtt_next_subscribe_topic(struct mg_mqtt_message *msg,
11369 : struct mg_str *topic, uint8_t *qos, int pos) {
11370 0 : unsigned char *buf = (unsigned char *) msg->payload.p + pos;
11371 : int new_pos;
11372 :
11373 0 : if ((size_t) pos >= msg->payload.len) return -1;
11374 :
11375 0 : topic->len = buf[0] << 8 | buf[1];
11376 0 : topic->p = (char *) buf + 2;
11377 0 : new_pos = pos + 2 + topic->len + 1;
11378 0 : if ((size_t) new_pos > msg->payload.len) return -1;
11379 0 : *qos = buf[2 + topic->len];
11380 0 : return new_pos;
11381 : }
11382 :
11383 0 : void mg_mqtt_unsubscribe(struct mg_connection *nc, char **topics,
11384 : size_t topics_len, uint16_t message_id) {
11385 : uint16_t netbytes;
11386 : size_t i;
11387 : uint16_t topic_len;
11388 0 : size_t total_len = 2;
11389 :
11390 0 : for (i = 0; i < topics_len; i++) {
11391 0 : total_len += 2 + strlen(topics[i]);
11392 : }
11393 :
11394 0 : mg_send_mqtt_header(nc, MG_MQTT_CMD_UNSUBSCRIBE, MG_MQTT_QOS(1), total_len);
11395 :
11396 0 : netbytes = htons(message_id);
11397 0 : mg_send(nc, (char *) &netbytes, 2);
11398 :
11399 0 : for (i = 0; i < topics_len; i++) {
11400 0 : topic_len = strlen(topics[i]);
11401 0 : netbytes = htons(topic_len);
11402 0 : mg_send(nc, &netbytes, 2);
11403 0 : mg_send(nc, topics[i], topic_len);
11404 : }
11405 0 : }
11406 :
11407 0 : void mg_mqtt_connack(struct mg_connection *nc, uint8_t return_code) {
11408 0 : uint8_t unused = 0;
11409 0 : mg_send_mqtt_header(nc, MG_MQTT_CMD_CONNACK, 0, 2);
11410 0 : mg_send(nc, &unused, 1);
11411 0 : mg_send(nc, &return_code, 1);
11412 0 : }
11413 :
11414 : /*
11415 : * Sends a command which contains only a `message_id` and a QoS level of 1.
11416 : *
11417 : * Helper function.
11418 : */
11419 0 : static void mg_send_mqtt_short_command(struct mg_connection *nc, uint8_t cmd,
11420 : uint16_t message_id) {
11421 : uint16_t netbytes;
11422 0 : uint8_t flags = (cmd == MG_MQTT_CMD_PUBREL ? 2 : 0);
11423 :
11424 0 : mg_send_mqtt_header(nc, cmd, flags, 2 /* len */);
11425 :
11426 0 : netbytes = htons(message_id);
11427 0 : mg_send(nc, &netbytes, 2);
11428 0 : }
11429 :
11430 0 : void mg_mqtt_puback(struct mg_connection *nc, uint16_t message_id) {
11431 0 : mg_send_mqtt_short_command(nc, MG_MQTT_CMD_PUBACK, message_id);
11432 0 : }
11433 :
11434 0 : void mg_mqtt_pubrec(struct mg_connection *nc, uint16_t message_id) {
11435 0 : mg_send_mqtt_short_command(nc, MG_MQTT_CMD_PUBREC, message_id);
11436 0 : }
11437 :
11438 0 : void mg_mqtt_pubrel(struct mg_connection *nc, uint16_t message_id) {
11439 0 : mg_send_mqtt_short_command(nc, MG_MQTT_CMD_PUBREL, message_id);
11440 0 : }
11441 :
11442 0 : void mg_mqtt_pubcomp(struct mg_connection *nc, uint16_t message_id) {
11443 0 : mg_send_mqtt_short_command(nc, MG_MQTT_CMD_PUBCOMP, message_id);
11444 0 : }
11445 :
11446 0 : void mg_mqtt_suback(struct mg_connection *nc, uint8_t *qoss, size_t qoss_len,
11447 : uint16_t message_id) {
11448 : size_t i;
11449 : uint16_t netbytes;
11450 :
11451 0 : mg_send_mqtt_header(nc, MG_MQTT_CMD_SUBACK, MG_MQTT_QOS(1), 2 + qoss_len);
11452 :
11453 0 : netbytes = htons(message_id);
11454 0 : mg_send(nc, &netbytes, 2);
11455 :
11456 0 : for (i = 0; i < qoss_len; i++) {
11457 0 : mg_send(nc, &qoss[i], 1);
11458 : }
11459 0 : }
11460 :
11461 0 : void mg_mqtt_unsuback(struct mg_connection *nc, uint16_t message_id) {
11462 0 : mg_send_mqtt_short_command(nc, MG_MQTT_CMD_UNSUBACK, message_id);
11463 0 : }
11464 :
11465 0 : void mg_mqtt_ping(struct mg_connection *nc) {
11466 0 : mg_send_mqtt_header(nc, MG_MQTT_CMD_PINGREQ, 0, 0);
11467 0 : }
11468 :
11469 0 : void mg_mqtt_pong(struct mg_connection *nc) {
11470 0 : mg_send_mqtt_header(nc, MG_MQTT_CMD_PINGRESP, 0, 0);
11471 0 : }
11472 :
11473 0 : void mg_mqtt_disconnect(struct mg_connection *nc) {
11474 0 : mg_send_mqtt_header(nc, MG_MQTT_CMD_DISCONNECT, 0, 0);
11475 0 : }
11476 :
11477 : #endif /* MG_ENABLE_MQTT */
11478 : #ifdef MG_MODULE_LINES
11479 : #line 1 "mongoose/src/mg_mqtt_server.c"
11480 : #endif
11481 : /*
11482 : * Copyright (c) 2014 Cesanta Software Limited
11483 : * All rights reserved
11484 : */
11485 :
11486 : /* Amalgamated: #include "mg_internal.h" */
11487 : /* Amalgamated: #include "mg_mqtt_server.h" */
11488 :
11489 : #if MG_ENABLE_MQTT_BROKER
11490 :
11491 : static void mg_mqtt_session_init(struct mg_mqtt_broker *brk,
11492 : struct mg_mqtt_session *s,
11493 : struct mg_connection *nc) {
11494 : s->brk = brk;
11495 : s->subscriptions = NULL;
11496 : s->num_subscriptions = 0;
11497 : s->nc = nc;
11498 : }
11499 :
11500 : static void mg_mqtt_add_session(struct mg_mqtt_session *s) {
11501 : LIST_INSERT_HEAD(&s->brk->sessions, s, link);
11502 : }
11503 :
11504 : static void mg_mqtt_remove_session(struct mg_mqtt_session *s) {
11505 : LIST_REMOVE(s, link);
11506 : }
11507 :
11508 : static void mg_mqtt_destroy_session(struct mg_mqtt_session *s) {
11509 : size_t i;
11510 : for (i = 0; i < s->num_subscriptions; i++) {
11511 : MG_FREE((void *) s->subscriptions[i].topic);
11512 : }
11513 : MG_FREE(s->subscriptions);
11514 : MG_FREE(s);
11515 : }
11516 :
11517 : static void mg_mqtt_close_session(struct mg_mqtt_session *s) {
11518 : mg_mqtt_remove_session(s);
11519 : mg_mqtt_destroy_session(s);
11520 : }
11521 :
11522 : void mg_mqtt_broker_init(struct mg_mqtt_broker *brk, void *user_data) {
11523 : LIST_INIT(&brk->sessions);
11524 : brk->user_data = user_data;
11525 : }
11526 :
11527 : static void mg_mqtt_broker_handle_connect(struct mg_mqtt_broker *brk,
11528 : struct mg_connection *nc) {
11529 : struct mg_mqtt_session *s =
11530 : (struct mg_mqtt_session *) MG_CALLOC(1, sizeof *s);
11531 : if (s == NULL) {
11532 : /* LCOV_EXCL_START */
11533 : mg_mqtt_connack(nc, MG_EV_MQTT_CONNACK_SERVER_UNAVAILABLE);
11534 : return;
11535 : /* LCOV_EXCL_STOP */
11536 : }
11537 :
11538 : /* TODO(mkm): check header (magic and version) */
11539 :
11540 : mg_mqtt_session_init(brk, s, nc);
11541 : nc->priv_2 = s;
11542 : mg_mqtt_add_session(s);
11543 :
11544 : mg_mqtt_connack(nc, MG_EV_MQTT_CONNACK_ACCEPTED);
11545 : }
11546 :
11547 : static void mg_mqtt_broker_handle_subscribe(struct mg_connection *nc,
11548 : struct mg_mqtt_message *msg) {
11549 : struct mg_mqtt_session *ss = (struct mg_mqtt_session *) nc->priv_2;
11550 : uint8_t qoss[MG_MQTT_MAX_SESSION_SUBSCRIPTIONS];
11551 : size_t num_subs = 0;
11552 : struct mg_str topic;
11553 : uint8_t qos;
11554 : int pos;
11555 : struct mg_mqtt_topic_expression *te;
11556 :
11557 : for (pos = 0;
11558 : (pos = mg_mqtt_next_subscribe_topic(msg, &topic, &qos, pos)) != -1;) {
11559 : if (num_subs >= sizeof(MG_MQTT_MAX_SESSION_SUBSCRIPTIONS) ||
11560 : (ss->num_subscriptions + num_subs >=
11561 : MG_MQTT_MAX_SESSION_SUBSCRIPTIONS)) {
11562 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
11563 : return;
11564 : }
11565 : qoss[num_subs++] = qos;
11566 : }
11567 :
11568 : if (num_subs > 0) {
11569 : te = (struct mg_mqtt_topic_expression *) MG_REALLOC(
11570 : ss->subscriptions,
11571 : sizeof(*ss->subscriptions) * (ss->num_subscriptions + num_subs));
11572 : if (te == NULL) {
11573 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
11574 : return;
11575 : }
11576 : ss->subscriptions = te;
11577 : for (pos = 0;
11578 : pos < (int) msg->payload.len &&
11579 : (pos = mg_mqtt_next_subscribe_topic(msg, &topic, &qos, pos)) != -1;
11580 : ss->num_subscriptions++) {
11581 : te = &ss->subscriptions[ss->num_subscriptions];
11582 : te->topic = (char *) MG_MALLOC(topic.len + 1);
11583 : te->qos = qos;
11584 : memcpy((char *) te->topic, topic.p, topic.len);
11585 : ((char *) te->topic)[topic.len] = '\0';
11586 : }
11587 : }
11588 :
11589 : if (pos == (int) msg->payload.len) {
11590 : mg_mqtt_suback(nc, qoss, num_subs, msg->message_id);
11591 : } else {
11592 : /* We did not fully parse the payload, something must be wrong. */
11593 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
11594 : }
11595 : }
11596 :
11597 : static void mg_mqtt_broker_handle_publish(struct mg_mqtt_broker *brk,
11598 : struct mg_mqtt_message *msg) {
11599 : struct mg_mqtt_session *s;
11600 : size_t i;
11601 :
11602 : for (s = mg_mqtt_next(brk, NULL); s != NULL; s = mg_mqtt_next(brk, s)) {
11603 : for (i = 0; i < s->num_subscriptions; i++) {
11604 : if (mg_mqtt_vmatch_topic_expression(s->subscriptions[i].topic,
11605 : msg->topic)) {
11606 : char buf[100], *p = buf;
11607 : mg_asprintf(&p, sizeof(buf), "%.*s", (int) msg->topic.len,
11608 : msg->topic.p);
11609 : if (p == NULL) {
11610 : return;
11611 : }
11612 : mg_mqtt_publish(s->nc, p, 0, 0, msg->payload.p, msg->payload.len);
11613 : if (p != buf) {
11614 : MG_FREE(p);
11615 : }
11616 : break;
11617 : }
11618 : }
11619 : }
11620 : }
11621 :
11622 : void mg_mqtt_broker(struct mg_connection *nc, int ev, void *data) {
11623 : struct mg_mqtt_message *msg = (struct mg_mqtt_message *) data;
11624 : struct mg_mqtt_broker *brk;
11625 :
11626 : if (nc->listener) {
11627 : brk = (struct mg_mqtt_broker *) nc->listener->priv_2;
11628 : } else {
11629 : brk = (struct mg_mqtt_broker *) nc->priv_2;
11630 : }
11631 :
11632 : switch (ev) {
11633 : case MG_EV_ACCEPT:
11634 : if (nc->proto_data == NULL) mg_set_protocol_mqtt(nc);
11635 : nc->priv_2 = NULL; /* Clear up the inherited pointer to broker */
11636 : break;
11637 : case MG_EV_MQTT_CONNECT:
11638 : if (nc->priv_2 == NULL) {
11639 : mg_mqtt_broker_handle_connect(brk, nc);
11640 : } else {
11641 : /* Repeated CONNECT */
11642 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
11643 : }
11644 : break;
11645 : case MG_EV_MQTT_SUBSCRIBE:
11646 : if (nc->priv_2 != NULL) {
11647 : mg_mqtt_broker_handle_subscribe(nc, msg);
11648 : } else {
11649 : /* Subscribe before CONNECT */
11650 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
11651 : }
11652 : break;
11653 : case MG_EV_MQTT_PUBLISH:
11654 : if (nc->priv_2 != NULL) {
11655 : mg_mqtt_broker_handle_publish(brk, msg);
11656 : } else {
11657 : /* Publish before CONNECT */
11658 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
11659 : }
11660 : break;
11661 : case MG_EV_CLOSE:
11662 : if (nc->listener && nc->priv_2 != NULL) {
11663 : mg_mqtt_close_session((struct mg_mqtt_session *) nc->priv_2);
11664 : }
11665 : break;
11666 : }
11667 : }
11668 :
11669 : struct mg_mqtt_session *mg_mqtt_next(struct mg_mqtt_broker *brk,
11670 : struct mg_mqtt_session *s) {
11671 : return s == NULL ? LIST_FIRST(&brk->sessions) : LIST_NEXT(s, link);
11672 : }
11673 :
11674 : #endif /* MG_ENABLE_MQTT_BROKER */
11675 : #ifdef MG_MODULE_LINES
11676 : #line 1 "mongoose/src/mg_dns.c"
11677 : #endif
11678 : /*
11679 : * Copyright (c) 2014 Cesanta Software Limited
11680 : * All rights reserved
11681 : */
11682 :
11683 : #if MG_ENABLE_DNS
11684 :
11685 : /* Amalgamated: #include "mg_internal.h" */
11686 : /* Amalgamated: #include "mg_dns.h" */
11687 :
11688 : static int mg_dns_tid = 0xa0;
11689 :
11690 : struct mg_dns_header {
11691 : uint16_t transaction_id;
11692 : uint16_t flags;
11693 : uint16_t num_questions;
11694 : uint16_t num_answers;
11695 : uint16_t num_authority_prs;
11696 : uint16_t num_other_prs;
11697 : };
11698 :
11699 0 : struct mg_dns_resource_record *mg_dns_next_record(
11700 : struct mg_dns_message *msg, int query,
11701 : struct mg_dns_resource_record *prev) {
11702 : struct mg_dns_resource_record *rr;
11703 :
11704 0 : for (rr = (prev == NULL ? msg->answers : prev + 1);
11705 0 : rr - msg->answers < msg->num_answers; rr++) {
11706 0 : if (rr->rtype == query) {
11707 0 : return rr;
11708 : }
11709 : }
11710 0 : return NULL;
11711 : }
11712 :
11713 0 : int mg_dns_parse_record_data(struct mg_dns_message *msg,
11714 : struct mg_dns_resource_record *rr, void *data,
11715 : size_t data_len) {
11716 0 : switch (rr->rtype) {
11717 0 : case MG_DNS_A_RECORD:
11718 0 : if (data_len < sizeof(struct in_addr)) {
11719 0 : return -1;
11720 : }
11721 0 : if (rr->rdata.p + data_len > msg->pkt.p + msg->pkt.len) {
11722 0 : return -1;
11723 : }
11724 0 : memcpy(data, rr->rdata.p, data_len);
11725 0 : return 0;
11726 : #if MG_ENABLE_IPV6
11727 0 : case MG_DNS_AAAA_RECORD:
11728 0 : if (data_len < sizeof(struct in6_addr)) {
11729 : return -1; /* LCOV_EXCL_LINE */
11730 : }
11731 0 : memcpy(data, rr->rdata.p, data_len);
11732 0 : return 0;
11733 : #endif
11734 0 : case MG_DNS_CNAME_RECORD:
11735 0 : mg_dns_uncompress_name(msg, &rr->rdata, (char *) data, data_len);
11736 0 : return 0;
11737 : }
11738 :
11739 0 : return -1;
11740 : }
11741 :
11742 0 : int mg_dns_insert_header(struct mbuf *io, size_t pos,
11743 : struct mg_dns_message *msg) {
11744 : struct mg_dns_header header;
11745 :
11746 0 : memset(&header, 0, sizeof(header));
11747 0 : header.transaction_id = msg->transaction_id;
11748 0 : header.flags = htons(msg->flags);
11749 0 : header.num_questions = htons(msg->num_questions);
11750 0 : header.num_answers = htons(msg->num_answers);
11751 :
11752 0 : return mbuf_insert(io, pos, &header, sizeof(header));
11753 : }
11754 :
11755 0 : int mg_dns_copy_questions(struct mbuf *io, struct mg_dns_message *msg) {
11756 : unsigned char *begin, *end;
11757 : struct mg_dns_resource_record *last_q;
11758 0 : if (msg->num_questions <= 0) return 0;
11759 0 : begin = (unsigned char *) msg->pkt.p + sizeof(struct mg_dns_header);
11760 0 : last_q = &msg->questions[msg->num_questions - 1];
11761 0 : end = (unsigned char *) last_q->name.p + last_q->name.len + 4;
11762 0 : return mbuf_append(io, begin, end - begin);
11763 : }
11764 :
11765 0 : int mg_dns_encode_name(struct mbuf *io, const char *name, size_t len) {
11766 : const char *s;
11767 : unsigned char n;
11768 0 : size_t pos = io->len;
11769 :
11770 : do {
11771 0 : if ((s = strchr(name, '.')) == NULL) {
11772 0 : s = name + len;
11773 : }
11774 :
11775 0 : if (s - name > 127) {
11776 0 : return -1; /* TODO(mkm) cover */
11777 : }
11778 0 : n = s - name; /* chunk length */
11779 0 : mbuf_append(io, &n, 1); /* send length */
11780 0 : mbuf_append(io, name, n);
11781 :
11782 0 : if (*s == '.') {
11783 0 : n++;
11784 : }
11785 :
11786 0 : name += n;
11787 0 : len -= n;
11788 0 : } while (*s != '\0');
11789 0 : mbuf_append(io, "\0", 1); /* Mark end of host name */
11790 :
11791 0 : return io->len - pos;
11792 : }
11793 :
11794 0 : int mg_dns_encode_record(struct mbuf *io, struct mg_dns_resource_record *rr,
11795 : const char *name, size_t nlen, const void *rdata,
11796 : size_t rlen) {
11797 0 : size_t pos = io->len;
11798 : uint16_t u16;
11799 : uint32_t u32;
11800 :
11801 0 : if (rr->kind == MG_DNS_INVALID_RECORD) {
11802 : return -1; /* LCOV_EXCL_LINE */
11803 : }
11804 :
11805 0 : if (mg_dns_encode_name(io, name, nlen) == -1) {
11806 0 : return -1;
11807 : }
11808 :
11809 0 : u16 = htons(rr->rtype);
11810 0 : mbuf_append(io, &u16, 2);
11811 0 : u16 = htons(rr->rclass);
11812 0 : mbuf_append(io, &u16, 2);
11813 :
11814 0 : if (rr->kind == MG_DNS_ANSWER) {
11815 0 : u32 = htonl(rr->ttl);
11816 0 : mbuf_append(io, &u32, 4);
11817 :
11818 0 : if (rr->rtype == MG_DNS_CNAME_RECORD) {
11819 : int clen;
11820 : /* fill size after encoding */
11821 0 : size_t off = io->len;
11822 0 : mbuf_append(io, &u16, 2);
11823 0 : if ((clen = mg_dns_encode_name(io, (const char *) rdata, rlen)) == -1) {
11824 0 : return -1;
11825 : }
11826 0 : u16 = clen;
11827 0 : io->buf[off] = u16 >> 8;
11828 0 : io->buf[off + 1] = u16 & 0xff;
11829 : } else {
11830 0 : u16 = htons((uint16_t) rlen);
11831 0 : mbuf_append(io, &u16, 2);
11832 0 : mbuf_append(io, rdata, rlen);
11833 : }
11834 : }
11835 :
11836 0 : return io->len - pos;
11837 : }
11838 :
11839 0 : void mg_send_dns_query(struct mg_connection *nc, const char *name,
11840 : int query_type) {
11841 : struct mg_dns_message *msg =
11842 0 : (struct mg_dns_message *) MG_CALLOC(1, sizeof(*msg));
11843 : struct mbuf pkt;
11844 0 : struct mg_dns_resource_record *rr = &msg->questions[0];
11845 :
11846 0 : DBG(("%s %d", name, query_type));
11847 :
11848 0 : mbuf_init(&pkt, 64 /* Start small, it'll grow as needed. */);
11849 :
11850 0 : msg->transaction_id = ++mg_dns_tid;
11851 0 : msg->flags = 0x100;
11852 0 : msg->num_questions = 1;
11853 :
11854 0 : mg_dns_insert_header(&pkt, 0, msg);
11855 :
11856 0 : rr->rtype = query_type;
11857 0 : rr->rclass = 1; /* Class: inet */
11858 0 : rr->kind = MG_DNS_QUESTION;
11859 :
11860 0 : if (mg_dns_encode_record(&pkt, rr, name, strlen(name), NULL, 0) == -1) {
11861 : /* TODO(mkm): return an error code */
11862 : goto cleanup; /* LCOV_EXCL_LINE */
11863 : }
11864 :
11865 : /* TCP DNS requires messages to be prefixed with len */
11866 0 : if (!(nc->flags & MG_F_UDP)) {
11867 0 : uint16_t len = htons((uint16_t) pkt.len);
11868 0 : mbuf_insert(&pkt, 0, &len, 2);
11869 : }
11870 :
11871 0 : mg_send(nc, pkt.buf, pkt.len);
11872 0 : mbuf_free(&pkt);
11873 :
11874 0 : cleanup:
11875 0 : MG_FREE(msg);
11876 0 : }
11877 :
11878 0 : static unsigned char *mg_parse_dns_resource_record(
11879 : unsigned char *data, unsigned char *end, struct mg_dns_resource_record *rr,
11880 : int reply) {
11881 0 : unsigned char *name = data;
11882 : int chunk_len, data_len;
11883 :
11884 0 : while (data < end && (chunk_len = *data)) {
11885 0 : if (((unsigned char *) data)[0] & 0xc0) {
11886 0 : data += 1;
11887 0 : break;
11888 : }
11889 0 : data += chunk_len + 1;
11890 : }
11891 :
11892 0 : if (data > end - 5) {
11893 0 : return NULL;
11894 : }
11895 :
11896 0 : rr->name.p = (char *) name;
11897 0 : rr->name.len = data - name + 1;
11898 0 : data++;
11899 :
11900 0 : rr->rtype = data[0] << 8 | data[1];
11901 0 : data += 2;
11902 :
11903 0 : rr->rclass = data[0] << 8 | data[1];
11904 0 : data += 2;
11905 :
11906 0 : rr->kind = reply ? MG_DNS_ANSWER : MG_DNS_QUESTION;
11907 0 : if (reply) {
11908 0 : if (data >= end - 6) {
11909 0 : return NULL;
11910 : }
11911 :
11912 0 : rr->ttl = (uint32_t) data[0] << 24 | (uint32_t) data[1] << 16 |
11913 0 : data[2] << 8 | data[3];
11914 0 : data += 4;
11915 :
11916 0 : data_len = *data << 8 | *(data + 1);
11917 0 : data += 2;
11918 :
11919 0 : rr->rdata.p = (char *) data;
11920 0 : rr->rdata.len = data_len;
11921 0 : data += data_len;
11922 : }
11923 0 : return data;
11924 : }
11925 :
11926 0 : int mg_parse_dns(const char *buf, int len, struct mg_dns_message *msg) {
11927 0 : struct mg_dns_header *header = (struct mg_dns_header *) buf;
11928 0 : unsigned char *data = (unsigned char *) buf + sizeof(*header);
11929 0 : unsigned char *end = (unsigned char *) buf + len;
11930 : int i;
11931 :
11932 0 : memset(msg, 0, sizeof(*msg));
11933 0 : msg->pkt.p = buf;
11934 0 : msg->pkt.len = len;
11935 :
11936 0 : if (len < (int) sizeof(*header)) return -1;
11937 :
11938 0 : msg->transaction_id = header->transaction_id;
11939 0 : msg->flags = ntohs(header->flags);
11940 0 : msg->num_questions = ntohs(header->num_questions);
11941 0 : if (msg->num_questions > (int) ARRAY_SIZE(msg->questions)) {
11942 0 : msg->num_questions = (int) ARRAY_SIZE(msg->questions);
11943 : }
11944 0 : msg->num_answers = ntohs(header->num_answers);
11945 0 : if (msg->num_answers > (int) ARRAY_SIZE(msg->answers)) {
11946 0 : msg->num_answers = (int) ARRAY_SIZE(msg->answers);
11947 : }
11948 :
11949 0 : for (i = 0; i < msg->num_questions; i++) {
11950 0 : data = mg_parse_dns_resource_record(data, end, &msg->questions[i], 0);
11951 0 : if (data == NULL) return -1;
11952 : }
11953 :
11954 0 : for (i = 0; i < msg->num_answers; i++) {
11955 0 : data = mg_parse_dns_resource_record(data, end, &msg->answers[i], 1);
11956 0 : if (data == NULL) return -1;
11957 : }
11958 :
11959 0 : return 0;
11960 : }
11961 :
11962 0 : size_t mg_dns_uncompress_name(struct mg_dns_message *msg, struct mg_str *name,
11963 : char *dst, int dst_len) {
11964 0 : int chunk_len, num_ptrs = 0;
11965 0 : char *old_dst = dst;
11966 0 : const unsigned char *data = (unsigned char *) name->p;
11967 0 : const unsigned char *end = (unsigned char *) msg->pkt.p + msg->pkt.len;
11968 :
11969 0 : if (data >= end) {
11970 0 : return 0;
11971 : }
11972 :
11973 0 : while ((chunk_len = *data++)) {
11974 0 : int leeway = dst_len - (dst - old_dst);
11975 0 : if (data >= end) {
11976 0 : return 0;
11977 : }
11978 :
11979 0 : if ((chunk_len & 0xc0) == 0xc0) {
11980 0 : uint16_t off = (data[-1] & (~0xc0)) << 8 | data[0];
11981 0 : if (off >= msg->pkt.len) {
11982 0 : return 0;
11983 : }
11984 : /* Basic circular loop avoidance: allow up to 16 pointer hops. */
11985 0 : if (++num_ptrs > 15) {
11986 0 : return 0;
11987 : }
11988 0 : data = (unsigned char *) msg->pkt.p + off;
11989 0 : continue;
11990 0 : }
11991 0 : if (chunk_len > 63) {
11992 0 : return 0;
11993 : }
11994 0 : if (chunk_len > leeway) {
11995 0 : chunk_len = leeway;
11996 : }
11997 :
11998 0 : if (data + chunk_len >= end) {
11999 0 : return 0;
12000 : }
12001 :
12002 0 : memcpy(dst, data, chunk_len);
12003 0 : data += chunk_len;
12004 0 : dst += chunk_len;
12005 0 : leeway -= chunk_len;
12006 0 : if (leeway == 0) {
12007 0 : return dst - old_dst;
12008 : }
12009 0 : *dst++ = '.';
12010 : }
12011 :
12012 0 : if (dst != old_dst) {
12013 0 : *--dst = 0;
12014 : }
12015 0 : return dst - old_dst;
12016 : }
12017 :
12018 0 : static void dns_handler(struct mg_connection *nc, int ev,
12019 : void *ev_data MG_UD_ARG(void *user_data)) {
12020 0 : struct mbuf *io = &nc->recv_mbuf;
12021 : struct mg_dns_message msg;
12022 :
12023 : /* Pass low-level events to the user handler */
12024 0 : nc->handler(nc, ev, ev_data MG_UD_ARG(user_data));
12025 :
12026 0 : switch (ev) {
12027 0 : case MG_EV_RECV:
12028 0 : if (!(nc->flags & MG_F_UDP)) {
12029 0 : mbuf_remove(&nc->recv_mbuf, 2);
12030 : }
12031 0 : if (mg_parse_dns(nc->recv_mbuf.buf, nc->recv_mbuf.len, &msg) == -1) {
12032 : /* reply + recursion allowed + format error */
12033 0 : memset(&msg, 0, sizeof(msg));
12034 0 : msg.flags = 0x8081;
12035 0 : mg_dns_insert_header(io, 0, &msg);
12036 0 : if (!(nc->flags & MG_F_UDP)) {
12037 0 : uint16_t len = htons((uint16_t) io->len);
12038 0 : mbuf_insert(io, 0, &len, 2);
12039 : }
12040 0 : mg_send(nc, io->buf, io->len);
12041 : } else {
12042 : /* Call user handler with parsed message */
12043 0 : nc->handler(nc, MG_DNS_MESSAGE, &msg MG_UD_ARG(user_data));
12044 : }
12045 0 : mbuf_remove(io, io->len);
12046 0 : break;
12047 : }
12048 0 : }
12049 :
12050 0 : void mg_set_protocol_dns(struct mg_connection *nc) {
12051 0 : nc->proto_handler = dns_handler;
12052 0 : }
12053 :
12054 : #endif /* MG_ENABLE_DNS */
12055 : #ifdef MG_MODULE_LINES
12056 : #line 1 "mongoose/src/mg_dns_server.c"
12057 : #endif
12058 : /*
12059 : * Copyright (c) 2014 Cesanta Software Limited
12060 : * All rights reserved
12061 : */
12062 :
12063 : #if MG_ENABLE_DNS_SERVER
12064 :
12065 : /* Amalgamated: #include "mg_internal.h" */
12066 : /* Amalgamated: #include "dns-server.h" */
12067 :
12068 : struct mg_dns_reply mg_dns_create_reply(struct mbuf *io,
12069 : struct mg_dns_message *msg) {
12070 : struct mg_dns_reply rep;
12071 : rep.msg = msg;
12072 : rep.io = io;
12073 : rep.start = io->len;
12074 :
12075 : /* reply + recursion allowed */
12076 : msg->flags |= 0x8080;
12077 : mg_dns_copy_questions(io, msg);
12078 :
12079 : msg->num_answers = 0;
12080 : return rep;
12081 : }
12082 :
12083 : void mg_dns_send_reply(struct mg_connection *nc, struct mg_dns_reply *r) {
12084 : size_t sent = r->io->len - r->start;
12085 : mg_dns_insert_header(r->io, r->start, r->msg);
12086 : if (!(nc->flags & MG_F_UDP)) {
12087 : uint16_t len = htons((uint16_t) sent);
12088 : mbuf_insert(r->io, r->start, &len, 2);
12089 : }
12090 :
12091 : if (&nc->send_mbuf != r->io) {
12092 : mg_send(nc, r->io->buf + r->start, r->io->len - r->start);
12093 : r->io->len = r->start;
12094 : }
12095 : }
12096 :
12097 : int mg_dns_reply_record(struct mg_dns_reply *reply,
12098 : struct mg_dns_resource_record *question,
12099 : const char *name, int rtype, int ttl, const void *rdata,
12100 : size_t rdata_len) {
12101 : struct mg_dns_message *msg = (struct mg_dns_message *) reply->msg;
12102 : char rname[512];
12103 : struct mg_dns_resource_record *ans = &msg->answers[msg->num_answers];
12104 : if (msg->num_answers >= MG_MAX_DNS_ANSWERS) {
12105 : return -1; /* LCOV_EXCL_LINE */
12106 : }
12107 :
12108 : if (name == NULL) {
12109 : name = rname;
12110 : rname[511] = 0;
12111 : mg_dns_uncompress_name(msg, &question->name, rname, sizeof(rname) - 1);
12112 : }
12113 :
12114 : *ans = *question;
12115 : ans->kind = MG_DNS_ANSWER;
12116 : ans->rtype = rtype;
12117 : ans->ttl = ttl;
12118 :
12119 : if (mg_dns_encode_record(reply->io, ans, name, strlen(name), rdata,
12120 : rdata_len) == -1) {
12121 : return -1; /* LCOV_EXCL_LINE */
12122 : };
12123 :
12124 : msg->num_answers++;
12125 : return 0;
12126 : }
12127 :
12128 : #endif /* MG_ENABLE_DNS_SERVER */
12129 : #ifdef MG_MODULE_LINES
12130 : #line 1 "mongoose/src/mg_resolv.c"
12131 : #endif
12132 : /*
12133 : * Copyright (c) 2014 Cesanta Software Limited
12134 : * All rights reserved
12135 : */
12136 :
12137 : #if MG_ENABLE_ASYNC_RESOLVER
12138 :
12139 : /* Amalgamated: #include "mg_internal.h" */
12140 : /* Amalgamated: #include "mg_resolv.h" */
12141 :
12142 : #ifndef MG_DEFAULT_NAMESERVER
12143 : #define MG_DEFAULT_NAMESERVER "8.8.8.8"
12144 : #endif
12145 :
12146 : struct mg_resolve_async_request {
12147 : char name[1024];
12148 : int query;
12149 : mg_resolve_callback_t callback;
12150 : void *data;
12151 : time_t timeout;
12152 : int max_retries;
12153 : enum mg_resolve_err err;
12154 :
12155 : /* state */
12156 : time_t last_time;
12157 : int retries;
12158 : };
12159 :
12160 : /*
12161 : * Find what nameserver to use.
12162 : *
12163 : * Return 0 if OK, -1 if error
12164 : */
12165 0 : static int mg_get_ip_address_of_nameserver(char *name, size_t name_len) {
12166 0 : int ret = -1;
12167 :
12168 : #ifdef _WIN32
12169 : int i;
12170 : LONG err;
12171 : HKEY hKey, hSub;
12172 : wchar_t subkey[512], value[128],
12173 : *key = L"SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters\\Interfaces";
12174 :
12175 : if ((err = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hKey)) !=
12176 : ERROR_SUCCESS) {
12177 : fprintf(stderr, "cannot open reg key %S: %ld\n", key, err);
12178 : ret = -1;
12179 : } else {
12180 : for (ret = -1, i = 0; 1; i++) {
12181 : DWORD subkey_size = sizeof(subkey), type, len = sizeof(value);
12182 : if (RegEnumKeyExW(hKey, i, subkey, &subkey_size, NULL, NULL, NULL,
12183 : NULL) != ERROR_SUCCESS) {
12184 : break;
12185 : }
12186 : if (RegOpenKeyExW(hKey, subkey, 0, KEY_READ, &hSub) == ERROR_SUCCESS &&
12187 : ((RegQueryValueExW(hSub, L"NameServer", 0, &type, (void *) value,
12188 : &len) == ERROR_SUCCESS &&
12189 : value[0] != '\0') ||
12190 : (RegQueryValueExW(hSub, L"DhcpNameServer", 0, &type, (void *) value,
12191 : &len) == ERROR_SUCCESS &&
12192 : value[0] != '\0'))) {
12193 : /*
12194 : * See https://github.com/cesanta/mongoose/issues/176
12195 : * The value taken from the registry can be empty, a single
12196 : * IP address, or multiple IP addresses separated by comma.
12197 : * If it's empty, check the next interface.
12198 : * If it's multiple IP addresses, take the first one.
12199 : */
12200 : wchar_t *comma = wcschr(value, ',');
12201 : if (comma != NULL) {
12202 : *comma = '\0';
12203 : }
12204 : /* %S will convert wchar_t -> char */
12205 : snprintf(name, name_len, "%S", value);
12206 : ret = 0;
12207 : RegCloseKey(hSub);
12208 : break;
12209 : }
12210 : }
12211 : RegCloseKey(hKey);
12212 : }
12213 : #elif MG_ENABLE_FILESYSTEM && defined(MG_RESOLV_CONF_FILE_NAME)
12214 : FILE *fp;
12215 : char line[512];
12216 :
12217 0 : if ((fp = mg_fopen(MG_RESOLV_CONF_FILE_NAME, "r")) == NULL) {
12218 0 : ret = -1;
12219 : } else {
12220 : /* Try to figure out what nameserver to use */
12221 0 : for (ret = -1; fgets(line, sizeof(line), fp) != NULL;) {
12222 : unsigned int a, b, c, d;
12223 0 : if (sscanf(line, "nameserver %u.%u.%u.%u", &a, &b, &c, &d) == 4) {
12224 0 : snprintf(name, name_len, "%u.%u.%u.%u", a, b, c, d);
12225 0 : ret = 0;
12226 0 : break;
12227 : }
12228 : }
12229 0 : (void) fclose(fp);
12230 : }
12231 : #else
12232 : snprintf(name, name_len, "%s", MG_DEFAULT_NAMESERVER);
12233 : #endif /* _WIN32 */
12234 :
12235 0 : return ret;
12236 : }
12237 :
12238 0 : int mg_resolve_from_hosts_file(const char *name, union socket_address *usa) {
12239 : #if MG_ENABLE_FILESYSTEM && defined(MG_HOSTS_FILE_NAME)
12240 : /* TODO(mkm) cache /etc/hosts */
12241 : FILE *fp;
12242 : char line[1024];
12243 : char *p;
12244 : char alias[256];
12245 : unsigned int a, b, c, d;
12246 0 : int len = 0;
12247 :
12248 0 : if ((fp = mg_fopen(MG_HOSTS_FILE_NAME, "r")) == NULL) {
12249 0 : return -1;
12250 : }
12251 :
12252 0 : for (; fgets(line, sizeof(line), fp) != NULL;) {
12253 0 : if (line[0] == '#') continue;
12254 :
12255 0 : if (sscanf(line, "%u.%u.%u.%u%n", &a, &b, &c, &d, &len) == 0) {
12256 : /* TODO(mkm): handle ipv6 */
12257 0 : continue;
12258 : }
12259 0 : for (p = line + len; sscanf(p, "%s%n", alias, &len) == 1; p += len) {
12260 0 : if (strcmp(alias, name) == 0) {
12261 0 : usa->sin.sin_addr.s_addr = htonl(a << 24 | b << 16 | c << 8 | d);
12262 0 : fclose(fp);
12263 0 : return 0;
12264 : }
12265 : }
12266 : }
12267 :
12268 0 : fclose(fp);
12269 : #else
12270 : (void) name;
12271 : (void) usa;
12272 : #endif
12273 :
12274 0 : return -1;
12275 : }
12276 :
12277 0 : static void mg_resolve_async_eh(struct mg_connection *nc, int ev,
12278 : void *data MG_UD_ARG(void *user_data)) {
12279 0 : time_t now = (time_t) mg_time();
12280 : struct mg_resolve_async_request *req;
12281 : struct mg_dns_message *msg;
12282 : #if !MG_ENABLE_CALLBACK_USERDATA
12283 0 : void *user_data = nc->user_data;
12284 : #endif
12285 :
12286 0 : if (ev != MG_EV_POLL) {
12287 0 : DBG(("ev=%d user_data=%p", ev, user_data));
12288 : }
12289 :
12290 0 : req = (struct mg_resolve_async_request *) user_data;
12291 :
12292 0 : if (req == NULL) {
12293 0 : return;
12294 : }
12295 :
12296 0 : switch (ev) {
12297 0 : case MG_EV_POLL:
12298 0 : if (req->retries > req->max_retries) {
12299 0 : req->err = MG_RESOLVE_EXCEEDED_RETRY_COUNT;
12300 0 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
12301 0 : break;
12302 : }
12303 0 : if (nc->flags & MG_F_CONNECTING) break;
12304 : /* fallthrough */
12305 : case MG_EV_CONNECT:
12306 0 : if (req->retries == 0 || now - req->last_time >= req->timeout) {
12307 0 : mg_send_dns_query(nc, req->name, req->query);
12308 0 : req->last_time = now;
12309 0 : req->retries++;
12310 : }
12311 0 : break;
12312 0 : case MG_EV_RECV:
12313 0 : msg = (struct mg_dns_message *) MG_MALLOC(sizeof(*msg));
12314 0 : if (mg_parse_dns(nc->recv_mbuf.buf, *(int *) data, msg) == 0 &&
12315 0 : msg->num_answers > 0) {
12316 0 : req->callback(msg, req->data, MG_RESOLVE_OK);
12317 0 : nc->user_data = NULL;
12318 0 : MG_FREE(req);
12319 : } else {
12320 0 : req->err = MG_RESOLVE_NO_ANSWERS;
12321 : }
12322 0 : MG_FREE(msg);
12323 0 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
12324 0 : break;
12325 0 : case MG_EV_SEND:
12326 : /*
12327 : * If a send error occurs, prevent closing of the connection by the core.
12328 : * We will retry after timeout.
12329 : */
12330 0 : nc->flags &= ~MG_F_CLOSE_IMMEDIATELY;
12331 0 : mbuf_remove(&nc->send_mbuf, nc->send_mbuf.len);
12332 0 : break;
12333 0 : case MG_EV_TIMER:
12334 0 : req->err = MG_RESOLVE_TIMEOUT;
12335 0 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
12336 0 : break;
12337 0 : case MG_EV_CLOSE:
12338 : /* If we got here with request still not done, fire an error callback. */
12339 0 : if (req != NULL) {
12340 : char addr[32];
12341 0 : mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr), MG_SOCK_STRINGIFY_IP);
12342 : #ifdef MG_LOG_DNS_FAILURES
12343 : LOG(LL_ERROR, ("Failed to resolve '%s', server %s", req->name, addr));
12344 : #endif
12345 0 : req->callback(NULL, req->data, req->err);
12346 0 : nc->user_data = NULL;
12347 0 : MG_FREE(req);
12348 : }
12349 0 : break;
12350 : }
12351 : }
12352 :
12353 0 : int mg_resolve_async(struct mg_mgr *mgr, const char *name, int query,
12354 : mg_resolve_callback_t cb, void *data) {
12355 : struct mg_resolve_async_opts opts;
12356 0 : memset(&opts, 0, sizeof(opts));
12357 0 : return mg_resolve_async_opt(mgr, name, query, cb, data, opts);
12358 : }
12359 :
12360 0 : int mg_resolve_async_opt(struct mg_mgr *mgr, const char *name, int query,
12361 : mg_resolve_callback_t cb, void *data,
12362 : struct mg_resolve_async_opts opts) {
12363 : struct mg_resolve_async_request *req;
12364 : struct mg_connection *dns_nc;
12365 0 : const char *nameserver = opts.nameserver;
12366 : char dns_server_buff[17], nameserver_url[26];
12367 :
12368 0 : if (nameserver == NULL) {
12369 0 : nameserver = mgr->nameserver;
12370 : }
12371 :
12372 0 : DBG(("%s %d %p", name, query, opts.dns_conn));
12373 :
12374 : /* resolve with DNS */
12375 0 : req = (struct mg_resolve_async_request *) MG_CALLOC(1, sizeof(*req));
12376 0 : if (req == NULL) {
12377 0 : return -1;
12378 : }
12379 :
12380 0 : strncpy(req->name, name, sizeof(req->name));
12381 0 : req->name[sizeof(req->name) - 1] = '\0';
12382 :
12383 0 : req->query = query;
12384 0 : req->callback = cb;
12385 0 : req->data = data;
12386 : /* TODO(mkm): parse defaults out of resolve.conf */
12387 0 : req->max_retries = opts.max_retries ? opts.max_retries : 2;
12388 0 : req->timeout = opts.timeout ? opts.timeout : 5;
12389 :
12390 : /* Lazily initialize dns server */
12391 0 : if (nameserver == NULL) {
12392 0 : if (mg_get_ip_address_of_nameserver(dns_server_buff,
12393 0 : sizeof(dns_server_buff)) != -1) {
12394 0 : nameserver = dns_server_buff;
12395 : } else {
12396 0 : nameserver = MG_DEFAULT_NAMESERVER;
12397 : }
12398 : }
12399 :
12400 0 : snprintf(nameserver_url, sizeof(nameserver_url), "udp://%s:53", nameserver);
12401 :
12402 0 : dns_nc = mg_connect(mgr, nameserver_url, MG_CB(mg_resolve_async_eh, NULL));
12403 0 : if (dns_nc == NULL) {
12404 0 : MG_FREE(req);
12405 0 : return -1;
12406 : }
12407 0 : dns_nc->user_data = req;
12408 0 : if (opts.dns_conn != NULL) {
12409 0 : *opts.dns_conn = dns_nc;
12410 : }
12411 :
12412 0 : return 0;
12413 : }
12414 :
12415 0 : void mg_set_nameserver(struct mg_mgr *mgr, const char *nameserver) {
12416 0 : MG_FREE((char *) mgr->nameserver);
12417 0 : mgr->nameserver = NULL;
12418 0 : if (nameserver != NULL) {
12419 0 : mgr->nameserver = strdup(nameserver);
12420 : }
12421 0 : }
12422 :
12423 : #endif /* MG_ENABLE_ASYNC_RESOLVER */
12424 : #ifdef MG_MODULE_LINES
12425 : #line 1 "mongoose/src/mg_coap.c"
12426 : #endif
12427 : /*
12428 : * Copyright (c) 2015 Cesanta Software Limited
12429 : * All rights reserved
12430 : * This software is dual-licensed: you can redistribute it and/or modify
12431 : * it under the terms of the GNU General Public License version 2 as
12432 : * published by the Free Software Foundation. For the terms of this
12433 : * license, see <http://www.gnu.org/licenses/>.
12434 : *
12435 : * You are free to use this software under the terms of the GNU General
12436 : * Public License, but WITHOUT ANY WARRANTY; without even the implied
12437 : * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12438 : * See the GNU General Public License for more details.
12439 : *
12440 : * Alternatively, you can license this software under a commercial
12441 : * license, as set out in <https://www.cesanta.com/license>.
12442 : */
12443 :
12444 : /* Amalgamated: #include "mg_internal.h" */
12445 : /* Amalgamated: #include "mg_coap.h" */
12446 :
12447 : #if MG_ENABLE_COAP
12448 :
12449 : void mg_coap_free_options(struct mg_coap_message *cm) {
12450 : while (cm->options != NULL) {
12451 : struct mg_coap_option *next = cm->options->next;
12452 : MG_FREE(cm->options);
12453 : cm->options = next;
12454 : }
12455 : }
12456 :
12457 : struct mg_coap_option *mg_coap_add_option(struct mg_coap_message *cm,
12458 : uint32_t number, char *value,
12459 : size_t len) {
12460 : struct mg_coap_option *new_option =
12461 : (struct mg_coap_option *) MG_CALLOC(1, sizeof(*new_option));
12462 :
12463 : new_option->number = number;
12464 : new_option->value.p = value;
12465 : new_option->value.len = len;
12466 :
12467 : if (cm->options == NULL) {
12468 : cm->options = cm->optiomg_tail = new_option;
12469 : } else {
12470 : /*
12471 : * A very simple attention to help clients to compose options:
12472 : * CoAP wants to see options ASC ordered.
12473 : * Could be change by using sort in coap_compose
12474 : */
12475 : if (cm->optiomg_tail->number <= new_option->number) {
12476 : /* if option is already ordered just add it */
12477 : cm->optiomg_tail = cm->optiomg_tail->next = new_option;
12478 : } else {
12479 : /* looking for appropriate position */
12480 : struct mg_coap_option *current_opt = cm->options;
12481 : struct mg_coap_option *prev_opt = 0;
12482 :
12483 : while (current_opt != NULL) {
12484 : if (current_opt->number > new_option->number) {
12485 : break;
12486 : }
12487 : prev_opt = current_opt;
12488 : current_opt = current_opt->next;
12489 : }
12490 :
12491 : if (prev_opt != NULL) {
12492 : prev_opt->next = new_option;
12493 : new_option->next = current_opt;
12494 : } else {
12495 : /* insert new_option to the beginning */
12496 : new_option->next = cm->options;
12497 : cm->options = new_option;
12498 : }
12499 : }
12500 : }
12501 :
12502 : return new_option;
12503 : }
12504 :
12505 : /*
12506 : * Fills CoAP header in mg_coap_message.
12507 : *
12508 : * Helper function.
12509 : */
12510 : static char *coap_parse_header(char *ptr, struct mbuf *io,
12511 : struct mg_coap_message *cm) {
12512 : if (io->len < sizeof(uint32_t)) {
12513 : cm->flags |= MG_COAP_NOT_ENOUGH_DATA;
12514 : return NULL;
12515 : }
12516 :
12517 : /*
12518 : * Version (Ver): 2-bit unsigned integer. Indicates the CoAP version
12519 : * number. Implementations of this specification MUST set this field
12520 : * to 1 (01 binary). Other values are reserved for future versions.
12521 : * Messages with unknown version numbers MUST be silently ignored.
12522 : */
12523 : if (((uint8_t) *ptr >> 6) != 1) {
12524 : cm->flags |= MG_COAP_IGNORE;
12525 : return NULL;
12526 : }
12527 :
12528 : /*
12529 : * Type (T): 2-bit unsigned integer. Indicates if this message is of
12530 : * type Confirmable (0), Non-confirmable (1), Acknowledgement (2), or
12531 : * Reset (3).
12532 : */
12533 : cm->msg_type = ((uint8_t) *ptr & 0x30) >> 4;
12534 : cm->flags |= MG_COAP_MSG_TYPE_FIELD;
12535 :
12536 : /*
12537 : * Token Length (TKL): 4-bit unsigned integer. Indicates the length of
12538 : * the variable-length Token field (0-8 bytes). Lengths 9-15 are
12539 : * reserved, MUST NOT be sent, and MUST be processed as a message
12540 : * format error.
12541 : */
12542 : cm->token.len = *ptr & 0x0F;
12543 : if (cm->token.len > 8) {
12544 : cm->flags |= MG_COAP_FORMAT_ERROR;
12545 : return NULL;
12546 : }
12547 :
12548 : ptr++;
12549 :
12550 : /*
12551 : * Code: 8-bit unsigned integer, split into a 3-bit class (most
12552 : * significant bits) and a 5-bit detail (least significant bits)
12553 : */
12554 : cm->code_class = (uint8_t) *ptr >> 5;
12555 : cm->code_detail = *ptr & 0x1F;
12556 : cm->flags |= (MG_COAP_CODE_CLASS_FIELD | MG_COAP_CODE_DETAIL_FIELD);
12557 :
12558 : ptr++;
12559 :
12560 : /* Message ID: 16-bit unsigned integer in network byte order. */
12561 : cm->msg_id = (uint8_t) *ptr << 8 | (uint8_t) * (ptr + 1);
12562 : cm->flags |= MG_COAP_MSG_ID_FIELD;
12563 :
12564 : ptr += 2;
12565 :
12566 : return ptr;
12567 : }
12568 :
12569 : /*
12570 : * Fills token information in mg_coap_message.
12571 : *
12572 : * Helper function.
12573 : */
12574 : static char *coap_get_token(char *ptr, struct mbuf *io,
12575 : struct mg_coap_message *cm) {
12576 : if (cm->token.len != 0) {
12577 : if (ptr + cm->token.len > io->buf + io->len) {
12578 : cm->flags |= MG_COAP_NOT_ENOUGH_DATA;
12579 : return NULL;
12580 : } else {
12581 : cm->token.p = ptr;
12582 : ptr += cm->token.len;
12583 : cm->flags |= MG_COAP_TOKEN_FIELD;
12584 : }
12585 : }
12586 :
12587 : return ptr;
12588 : }
12589 :
12590 : /*
12591 : * Returns Option Delta or Length.
12592 : *
12593 : * Helper function.
12594 : */
12595 : static int coap_get_ext_opt(char *ptr, struct mbuf *io, uint16_t *opt_info) {
12596 : int ret = 0;
12597 :
12598 : if (*opt_info == 13) {
12599 : /*
12600 : * 13: An 8-bit unsigned integer follows the initial byte and
12601 : * indicates the Option Delta/Length minus 13.
12602 : */
12603 : if (ptr < io->buf + io->len) {
12604 : *opt_info = (uint8_t) *ptr + 13;
12605 : ret = sizeof(uint8_t);
12606 : } else {
12607 : ret = -1; /* LCOV_EXCL_LINE */
12608 : }
12609 : } else if (*opt_info == 14) {
12610 : /*
12611 : * 14: A 16-bit unsigned integer in network byte order follows the
12612 : * initial byte and indicates the Option Delta/Length minus 269.
12613 : */
12614 : if (ptr + sizeof(uint8_t) < io->buf + io->len) {
12615 : *opt_info = ((uint8_t) *ptr << 8 | (uint8_t) * (ptr + 1)) + 269;
12616 : ret = sizeof(uint16_t);
12617 : } else {
12618 : ret = -1; /* LCOV_EXCL_LINE */
12619 : }
12620 : }
12621 :
12622 : return ret;
12623 : }
12624 :
12625 : /*
12626 : * Fills options in mg_coap_message.
12627 : *
12628 : * Helper function.
12629 : *
12630 : * General options format:
12631 : * +---------------+---------------+
12632 : * | Option Delta | Option Length | 1 byte
12633 : * +---------------+---------------+
12634 : * \ Option Delta (extended) \ 0-2 bytes
12635 : * +-------------------------------+
12636 : * / Option Length (extended) \ 0-2 bytes
12637 : * +-------------------------------+
12638 : * \ Option Value \ 0 or more bytes
12639 : * +-------------------------------+
12640 : */
12641 : static char *coap_get_options(char *ptr, struct mbuf *io,
12642 : struct mg_coap_message *cm) {
12643 : uint16_t prev_opt = 0;
12644 :
12645 : if (ptr == io->buf + io->len) {
12646 : /* end of packet, ok */
12647 : return NULL;
12648 : }
12649 :
12650 : /* 0xFF is payload marker */
12651 : while (ptr < io->buf + io->len && (uint8_t) *ptr != 0xFF) {
12652 : uint16_t option_delta, option_lenght;
12653 : int optinfo_len;
12654 :
12655 : /* Option Delta: 4-bit unsigned integer */
12656 : option_delta = ((uint8_t) *ptr & 0xF0) >> 4;
12657 : /* Option Length: 4-bit unsigned integer */
12658 : option_lenght = *ptr & 0x0F;
12659 :
12660 : if (option_delta == 15 || option_lenght == 15) {
12661 : /*
12662 : * 15: Reserved for future use. If the field is set to this value,
12663 : * it MUST be processed as a message format error
12664 : */
12665 : cm->flags |= MG_COAP_FORMAT_ERROR;
12666 : break;
12667 : }
12668 :
12669 : ptr++;
12670 :
12671 : /* check for extended option delta */
12672 : optinfo_len = coap_get_ext_opt(ptr, io, &option_delta);
12673 : if (optinfo_len == -1) {
12674 : cm->flags |= MG_COAP_NOT_ENOUGH_DATA; /* LCOV_EXCL_LINE */
12675 : break; /* LCOV_EXCL_LINE */
12676 : }
12677 :
12678 : ptr += optinfo_len;
12679 :
12680 : /* check or extended option lenght */
12681 : optinfo_len = coap_get_ext_opt(ptr, io, &option_lenght);
12682 : if (optinfo_len == -1) {
12683 : cm->flags |= MG_COAP_NOT_ENOUGH_DATA; /* LCOV_EXCL_LINE */
12684 : break; /* LCOV_EXCL_LINE */
12685 : }
12686 :
12687 : ptr += optinfo_len;
12688 :
12689 : /*
12690 : * Instead of specifying the Option Number directly, the instances MUST
12691 : * appear in order of their Option Numbers and a delta encoding is used
12692 : * between them.
12693 : */
12694 : option_delta += prev_opt;
12695 :
12696 : mg_coap_add_option(cm, option_delta, ptr, option_lenght);
12697 :
12698 : prev_opt = option_delta;
12699 :
12700 : if (ptr + option_lenght > io->buf + io->len) {
12701 : cm->flags |= MG_COAP_NOT_ENOUGH_DATA; /* LCOV_EXCL_LINE */
12702 : break; /* LCOV_EXCL_LINE */
12703 : }
12704 :
12705 : ptr += option_lenght;
12706 : }
12707 :
12708 : if ((cm->flags & MG_COAP_ERROR) != 0) {
12709 : mg_coap_free_options(cm);
12710 : return NULL;
12711 : }
12712 :
12713 : cm->flags |= MG_COAP_OPTIOMG_FIELD;
12714 :
12715 : if (ptr == io->buf + io->len) {
12716 : /* end of packet, ok */
12717 : return NULL;
12718 : }
12719 :
12720 : ptr++;
12721 :
12722 : return ptr;
12723 : }
12724 :
12725 : uint32_t mg_coap_parse(struct mbuf *io, struct mg_coap_message *cm) {
12726 : char *ptr;
12727 :
12728 : memset(cm, 0, sizeof(*cm));
12729 :
12730 : if ((ptr = coap_parse_header(io->buf, io, cm)) == NULL) {
12731 : return cm->flags;
12732 : }
12733 :
12734 : if ((ptr = coap_get_token(ptr, io, cm)) == NULL) {
12735 : return cm->flags;
12736 : }
12737 :
12738 : if ((ptr = coap_get_options(ptr, io, cm)) == NULL) {
12739 : return cm->flags;
12740 : }
12741 :
12742 : /* the rest is payload */
12743 : cm->payload.len = io->len - (ptr - io->buf);
12744 : if (cm->payload.len != 0) {
12745 : cm->payload.p = ptr;
12746 : cm->flags |= MG_COAP_PAYLOAD_FIELD;
12747 : }
12748 :
12749 : return cm->flags;
12750 : }
12751 :
12752 : /*
12753 : * Calculates extended size of given Opt Number/Length in coap message.
12754 : *
12755 : * Helper function.
12756 : */
12757 : static size_t coap_get_ext_opt_size(uint32_t value) {
12758 : int ret = 0;
12759 :
12760 : if (value >= 13 && value <= 0xFF + 13) {
12761 : ret = sizeof(uint8_t);
12762 : } else if (value > 0xFF + 13 && value <= 0xFFFF + 269) {
12763 : ret = sizeof(uint16_t);
12764 : }
12765 :
12766 : return ret;
12767 : }
12768 :
12769 : /*
12770 : * Splits given Opt Number/Length into base and ext values.
12771 : *
12772 : * Helper function.
12773 : */
12774 : static int coap_split_opt(uint32_t value, uint8_t *base, uint16_t *ext) {
12775 : int ret = 0;
12776 :
12777 : if (value < 13) {
12778 : *base = value;
12779 : } else if (value >= 13 && value <= 0xFF + 13) {
12780 : *base = 13;
12781 : *ext = value - 13;
12782 : ret = sizeof(uint8_t);
12783 : } else if (value > 0xFF + 13 && value <= 0xFFFF + 269) {
12784 : *base = 14;
12785 : *ext = value - 269;
12786 : ret = sizeof(uint16_t);
12787 : }
12788 :
12789 : return ret;
12790 : }
12791 :
12792 : /*
12793 : * Puts uint16_t (in network order) into given char stream.
12794 : *
12795 : * Helper function.
12796 : */
12797 : static char *coap_add_uint16(char *ptr, uint16_t val) {
12798 : *ptr = val >> 8;
12799 : ptr++;
12800 : *ptr = val & 0x00FF;
12801 : ptr++;
12802 : return ptr;
12803 : }
12804 :
12805 : /*
12806 : * Puts extended value of Opt Number/Length into given char stream.
12807 : *
12808 : * Helper function.
12809 : */
12810 : static char *coap_add_opt_info(char *ptr, uint16_t val, size_t len) {
12811 : if (len == sizeof(uint8_t)) {
12812 : *ptr = (char) val;
12813 : ptr++;
12814 : } else if (len == sizeof(uint16_t)) {
12815 : ptr = coap_add_uint16(ptr, val);
12816 : }
12817 :
12818 : return ptr;
12819 : }
12820 :
12821 : /*
12822 : * Verifies given mg_coap_message and calculates message size for it.
12823 : *
12824 : * Helper function.
12825 : */
12826 : static uint32_t coap_calculate_packet_size(struct mg_coap_message *cm,
12827 : size_t *len) {
12828 : struct mg_coap_option *opt;
12829 : uint32_t prev_opt_number;
12830 :
12831 : *len = 4; /* header */
12832 : if (cm->msg_type > MG_COAP_MSG_MAX) {
12833 : return MG_COAP_ERROR | MG_COAP_MSG_TYPE_FIELD;
12834 : }
12835 : if (cm->token.len > 8) {
12836 : return MG_COAP_ERROR | MG_COAP_TOKEN_FIELD;
12837 : }
12838 : if (cm->code_class > 7) {
12839 : return MG_COAP_ERROR | MG_COAP_CODE_CLASS_FIELD;
12840 : }
12841 : if (cm->code_detail > 31) {
12842 : return MG_COAP_ERROR | MG_COAP_CODE_DETAIL_FIELD;
12843 : }
12844 :
12845 : *len += cm->token.len;
12846 : if (cm->payload.len != 0) {
12847 : *len += cm->payload.len + 1; /* ... + 1; add payload marker */
12848 : }
12849 :
12850 : opt = cm->options;
12851 : prev_opt_number = 0;
12852 : while (opt != NULL) {
12853 : *len += 1; /* basic delta/length */
12854 : *len += coap_get_ext_opt_size(opt->number - prev_opt_number);
12855 : *len += coap_get_ext_opt_size((uint32_t) opt->value.len);
12856 : /*
12857 : * Current implementation performs check if
12858 : * option_number > previous option_number and produces an error
12859 : * TODO(alashkin): write design doc with limitations
12860 : * May be resorting is more suitable solution.
12861 : */
12862 : if ((opt->next != NULL && opt->number > opt->next->number) ||
12863 : opt->value.len > 0xFFFF + 269 ||
12864 : opt->number - prev_opt_number > 0xFFFF + 269) {
12865 : return MG_COAP_ERROR | MG_COAP_OPTIOMG_FIELD;
12866 : }
12867 : *len += opt->value.len;
12868 : prev_opt_number = opt->number;
12869 : opt = opt->next;
12870 : }
12871 :
12872 : return 0;
12873 : }
12874 :
12875 : uint32_t mg_coap_compose(struct mg_coap_message *cm, struct mbuf *io) {
12876 : struct mg_coap_option *opt;
12877 : uint32_t res, prev_opt_number;
12878 : size_t prev_io_len, packet_size;
12879 : char *ptr;
12880 :
12881 : res = coap_calculate_packet_size(cm, &packet_size);
12882 : if (res != 0) {
12883 : return res;
12884 : }
12885 :
12886 : /* saving previous lenght to handle non-empty mbuf */
12887 : prev_io_len = io->len;
12888 : if (mbuf_append(io, NULL, packet_size) == 0) return MG_COAP_ERROR;
12889 : ptr = io->buf + prev_io_len;
12890 :
12891 : /*
12892 : * since cm is verified, it is possible to use bits shift operator
12893 : * without additional zeroing of unused bits
12894 : */
12895 :
12896 : /* ver: 2 bits, msg_type: 2 bits, toklen: 4 bits */
12897 : *ptr = (1 << 6) | (cm->msg_type << 4) | (uint8_t)(cm->token.len);
12898 : ptr++;
12899 :
12900 : /* code class: 3 bits, code detail: 5 bits */
12901 : *ptr = (cm->code_class << 5) | (cm->code_detail);
12902 : ptr++;
12903 :
12904 : ptr = coap_add_uint16(ptr, cm->msg_id);
12905 :
12906 : if (cm->token.len != 0) {
12907 : memcpy(ptr, cm->token.p, cm->token.len);
12908 : ptr += cm->token.len;
12909 : }
12910 :
12911 : opt = cm->options;
12912 : prev_opt_number = 0;
12913 : while (opt != NULL) {
12914 : uint8_t delta_base = 0, length_base = 0;
12915 : uint16_t delta_ext = 0, length_ext = 0;
12916 :
12917 : size_t opt_delta_len =
12918 : coap_split_opt(opt->number - prev_opt_number, &delta_base, &delta_ext);
12919 : size_t opt_lenght_len =
12920 : coap_split_opt((uint32_t) opt->value.len, &length_base, &length_ext);
12921 :
12922 : *ptr = (delta_base << 4) | length_base;
12923 : ptr++;
12924 :
12925 : ptr = coap_add_opt_info(ptr, delta_ext, opt_delta_len);
12926 : ptr = coap_add_opt_info(ptr, length_ext, opt_lenght_len);
12927 :
12928 : if (opt->value.len != 0) {
12929 : memcpy(ptr, opt->value.p, opt->value.len);
12930 : ptr += opt->value.len;
12931 : }
12932 :
12933 : prev_opt_number = opt->number;
12934 : opt = opt->next;
12935 : }
12936 :
12937 : if (cm->payload.len != 0) {
12938 : *ptr = (char) -1;
12939 : ptr++;
12940 : memcpy(ptr, cm->payload.p, cm->payload.len);
12941 : }
12942 :
12943 : return 0;
12944 : }
12945 :
12946 : uint32_t mg_coap_send_message(struct mg_connection *nc,
12947 : struct mg_coap_message *cm) {
12948 : struct mbuf packet_out;
12949 : uint32_t compose_res;
12950 :
12951 : mbuf_init(&packet_out, 0);
12952 : compose_res = mg_coap_compose(cm, &packet_out);
12953 : if (compose_res != 0) {
12954 : return compose_res; /* LCOV_EXCL_LINE */
12955 : }
12956 :
12957 : mg_send(nc, packet_out.buf, (int) packet_out.len);
12958 : mbuf_free(&packet_out);
12959 :
12960 : return 0;
12961 : }
12962 :
12963 : uint32_t mg_coap_send_ack(struct mg_connection *nc, uint16_t msg_id) {
12964 : struct mg_coap_message cm;
12965 : memset(&cm, 0, sizeof(cm));
12966 : cm.msg_type = MG_COAP_MSG_ACK;
12967 : cm.msg_id = msg_id;
12968 :
12969 : return mg_coap_send_message(nc, &cm);
12970 : }
12971 :
12972 : static void coap_handler(struct mg_connection *nc, int ev,
12973 : void *ev_data MG_UD_ARG(void *user_data)) {
12974 : struct mbuf *io = &nc->recv_mbuf;
12975 : struct mg_coap_message cm;
12976 : uint32_t parse_res;
12977 :
12978 : memset(&cm, 0, sizeof(cm));
12979 :
12980 : nc->handler(nc, ev, ev_data MG_UD_ARG(user_data));
12981 :
12982 : switch (ev) {
12983 : case MG_EV_RECV:
12984 : parse_res = mg_coap_parse(io, &cm);
12985 : if ((parse_res & MG_COAP_IGNORE) == 0) {
12986 : if ((cm.flags & MG_COAP_NOT_ENOUGH_DATA) != 0) {
12987 : /*
12988 : * Since we support UDP only
12989 : * MG_COAP_NOT_ENOUGH_DATA == MG_COAP_FORMAT_ERROR
12990 : */
12991 : cm.flags |= MG_COAP_FORMAT_ERROR; /* LCOV_EXCL_LINE */
12992 : } /* LCOV_EXCL_LINE */
12993 : nc->handler(nc, MG_COAP_EVENT_BASE + cm.msg_type,
12994 : &cm MG_UD_ARG(user_data));
12995 : }
12996 :
12997 : mg_coap_free_options(&cm);
12998 : mbuf_remove(io, io->len);
12999 : break;
13000 : }
13001 : }
13002 : /*
13003 : * Attach built-in CoAP event handler to the given connection.
13004 : *
13005 : * The user-defined event handler will receive following extra events:
13006 : *
13007 : * - MG_EV_COAP_CON
13008 : * - MG_EV_COAP_NOC
13009 : * - MG_EV_COAP_ACK
13010 : * - MG_EV_COAP_RST
13011 : */
13012 : int mg_set_protocol_coap(struct mg_connection *nc) {
13013 : /* supports UDP only */
13014 : if ((nc->flags & MG_F_UDP) == 0) {
13015 : return -1;
13016 : }
13017 :
13018 : nc->proto_handler = coap_handler;
13019 :
13020 : return 0;
13021 : }
13022 :
13023 : #endif /* MG_ENABLE_COAP */
13024 : #ifdef MG_MODULE_LINES
13025 : #line 1 "mongoose/src/mg_sntp.c"
13026 : #endif
13027 : /*
13028 : * Copyright (c) 2016 Cesanta Software Limited
13029 : * All rights reserved
13030 : */
13031 :
13032 : /* Amalgamated: #include "mg_internal.h" */
13033 : /* Amalgamated: #include "mg_sntp.h" */
13034 : /* Amalgamated: #include "mg_util.h" */
13035 :
13036 : #if MG_ENABLE_SNTP
13037 :
13038 : #define SNTP_TIME_OFFSET 2208988800
13039 :
13040 : #ifndef SNTP_TIMEOUT
13041 : #define SNTP_TIMEOUT 10
13042 : #endif
13043 :
13044 : #ifndef SNTP_ATTEMPTS
13045 : #define SNTP_ATTEMPTS 3
13046 : #endif
13047 :
13048 : static uint64_t mg_get_sec(uint64_t val) {
13049 : return (val & 0xFFFFFFFF00000000) >> 32;
13050 : }
13051 :
13052 : static uint64_t mg_get_usec(uint64_t val) {
13053 : uint64_t tmp = (val & 0x00000000FFFFFFFF);
13054 : tmp *= 1000000;
13055 : tmp >>= 32;
13056 : return tmp;
13057 : }
13058 :
13059 : static void mg_ntp_to_tv(uint64_t val, struct timeval *tv) {
13060 : uint64_t tmp;
13061 : tmp = mg_get_sec(val);
13062 : tmp -= SNTP_TIME_OFFSET;
13063 : tv->tv_sec = tmp;
13064 : tv->tv_usec = mg_get_usec(val);
13065 : }
13066 :
13067 : static void mg_get_ntp_ts(const char *ntp, uint64_t *val) {
13068 : uint32_t tmp;
13069 : memcpy(&tmp, ntp, sizeof(tmp));
13070 : tmp = ntohl(tmp);
13071 : *val = (uint64_t) tmp << 32;
13072 : memcpy(&tmp, ntp + 4, sizeof(tmp));
13073 : tmp = ntohl(tmp);
13074 : *val |= tmp;
13075 : }
13076 :
13077 : void mg_sntp_send_request(struct mg_connection *c) {
13078 : uint8_t buf[48] = {0};
13079 : /*
13080 : * header - 8 bit:
13081 : * LI (2 bit) - 3 (not in sync), VN (3 bit) - 4 (version),
13082 : * mode (3 bit) - 3 (client)
13083 : */
13084 : buf[0] = (3 << 6) | (4 << 3) | 3;
13085 :
13086 : /*
13087 : * Next fields should be empty in client request
13088 : * stratum, 8 bit
13089 : * poll interval, 8 bit
13090 : * rrecision, 8 bit
13091 : * root delay, 32 bit
13092 : * root dispersion, 32 bit
13093 : * ref id, 32 bit
13094 : * ref timestamp, 64 bit
13095 : * originate Timestamp, 64 bit
13096 : * receive Timestamp, 64 bit
13097 : */
13098 :
13099 : /*
13100 : * convert time to sntp format (sntp starts from 00:00:00 01.01.1900)
13101 : * according to rfc868 it is 2208988800L sec
13102 : * this information is used to correct roundtrip delay
13103 : * but if local clock is absolutely broken (and doesn't work even
13104 : * as simple timer), it is better to disable it
13105 : */
13106 : #ifndef MG_SNTP_NO_DELAY_CORRECTION
13107 : uint32_t sec;
13108 : sec = htonl((uint32_t)(mg_time() + SNTP_TIME_OFFSET));
13109 : memcpy(&buf[40], &sec, sizeof(sec));
13110 : #endif
13111 :
13112 : mg_send(c, buf, sizeof(buf));
13113 : }
13114 :
13115 : #ifndef MG_SNTP_NO_DELAY_CORRECTION
13116 : static uint64_t mg_calculate_delay(uint64_t t1, uint64_t t2, uint64_t t3) {
13117 : /* roundloop delay = (T4 - T1) - (T3 - T2) */
13118 : uint64_t d1 = ((mg_time() + SNTP_TIME_OFFSET) * 1000000) -
13119 : (mg_get_sec(t1) * 1000000 + mg_get_usec(t1));
13120 : uint64_t d2 = (mg_get_sec(t3) * 1000000 + mg_get_usec(t3)) -
13121 : (mg_get_sec(t2) * 1000000 + mg_get_usec(t2));
13122 :
13123 : return (d1 > d2) ? d1 - d2 : 0;
13124 : }
13125 : #endif
13126 :
13127 : MG_INTERNAL int mg_sntp_parse_reply(const char *buf, int len,
13128 : struct mg_sntp_message *msg) {
13129 : uint8_t hdr;
13130 : uint64_t trsm_ts_T3, delay = 0;
13131 : int mode;
13132 : struct timeval tv;
13133 :
13134 : if (len < 48) {
13135 : return -1;
13136 : }
13137 :
13138 : hdr = buf[0];
13139 :
13140 : if ((hdr & 0x38) >> 3 != 4) {
13141 : /* Wrong version */
13142 : return -1;
13143 : }
13144 :
13145 : mode = hdr & 0x7;
13146 : if (mode != 4 && mode != 5) {
13147 : /* Not a server reply */
13148 : return -1;
13149 : }
13150 :
13151 : memset(msg, 0, sizeof(*msg));
13152 :
13153 : msg->kiss_of_death = (buf[1] == 0); /* Server asks to not send requests */
13154 :
13155 : mg_get_ntp_ts(&buf[40], &trsm_ts_T3);
13156 :
13157 : #ifndef MG_SNTP_NO_DELAY_CORRECTION
13158 : {
13159 : uint64_t orig_ts_T1, recv_ts_T2;
13160 : mg_get_ntp_ts(&buf[24], &orig_ts_T1);
13161 : mg_get_ntp_ts(&buf[32], &recv_ts_T2);
13162 : delay = mg_calculate_delay(orig_ts_T1, recv_ts_T2, trsm_ts_T3);
13163 : }
13164 : #endif
13165 :
13166 : mg_ntp_to_tv(trsm_ts_T3, &tv);
13167 :
13168 : msg->time = (double) tv.tv_sec + (((double) tv.tv_usec + delay) / 1000000.0);
13169 :
13170 : return 0;
13171 : }
13172 :
13173 : static void mg_sntp_handler(struct mg_connection *c, int ev,
13174 : void *ev_data MG_UD_ARG(void *user_data)) {
13175 : struct mbuf *io = &c->recv_mbuf;
13176 : struct mg_sntp_message msg;
13177 :
13178 : c->handler(c, ev, ev_data MG_UD_ARG(user_data));
13179 :
13180 : switch (ev) {
13181 : case MG_EV_RECV: {
13182 : if (mg_sntp_parse_reply(io->buf, io->len, &msg) < 0) {
13183 : DBG(("Invalid SNTP packet received (%d)", (int) io->len));
13184 : c->handler(c, MG_SNTP_MALFORMED_REPLY, NULL MG_UD_ARG(user_data));
13185 : } else {
13186 : c->handler(c, MG_SNTP_REPLY, (void *) &msg MG_UD_ARG(user_data));
13187 : }
13188 :
13189 : mbuf_remove(io, io->len);
13190 : break;
13191 : }
13192 : }
13193 : }
13194 :
13195 : int mg_set_protocol_sntp(struct mg_connection *c) {
13196 : if ((c->flags & MG_F_UDP) == 0) {
13197 : return -1;
13198 : }
13199 :
13200 : c->proto_handler = mg_sntp_handler;
13201 :
13202 : return 0;
13203 : }
13204 :
13205 : struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr,
13206 : MG_CB(mg_event_handler_t event_handler,
13207 : void *user_data),
13208 : const char *sntp_server_name) {
13209 : struct mg_connection *c = NULL;
13210 : char url[100], *p_url = url;
13211 : const char *proto = "", *port = "", *tmp;
13212 :
13213 : /* If port is not specified, use default (123) */
13214 : tmp = strchr(sntp_server_name, ':');
13215 : if (tmp != NULL && *(tmp + 1) == '/') {
13216 : tmp = strchr(tmp + 1, ':');
13217 : }
13218 :
13219 : if (tmp == NULL) {
13220 : port = ":123";
13221 : }
13222 :
13223 : /* Add udp:// if needed */
13224 : if (strncmp(sntp_server_name, "udp://", 6) != 0) {
13225 : proto = "udp://";
13226 : }
13227 :
13228 : mg_asprintf(&p_url, sizeof(url), "%s%s%s", proto, sntp_server_name, port);
13229 :
13230 : c = mg_connect(mgr, p_url, event_handler MG_UD_ARG(user_data));
13231 :
13232 : if (c == NULL) {
13233 : goto cleanup;
13234 : }
13235 :
13236 : mg_set_protocol_sntp(c);
13237 :
13238 : cleanup:
13239 : if (p_url != url) {
13240 : MG_FREE(p_url);
13241 : }
13242 :
13243 : return c;
13244 : }
13245 :
13246 : struct sntp_data {
13247 : mg_event_handler_t hander;
13248 : int count;
13249 : };
13250 :
13251 : static void mg_sntp_util_ev_handler(struct mg_connection *c, int ev,
13252 : void *ev_data MG_UD_ARG(void *user_data)) {
13253 : #if !MG_ENABLE_CALLBACK_USERDATA
13254 : void *user_data = c->user_data;
13255 : #endif
13256 : struct sntp_data *sd = (struct sntp_data *) user_data;
13257 :
13258 : switch (ev) {
13259 : case MG_EV_CONNECT:
13260 : if (*(int *) ev_data != 0) {
13261 : mg_call(c, sd->hander, c->user_data, MG_SNTP_FAILED, NULL);
13262 : break;
13263 : }
13264 : /* fallthrough */
13265 : case MG_EV_TIMER:
13266 : if (sd->count <= SNTP_ATTEMPTS) {
13267 : mg_sntp_send_request(c);
13268 : mg_set_timer(c, mg_time() + 10);
13269 : sd->count++;
13270 : } else {
13271 : mg_call(c, sd->hander, c->user_data, MG_SNTP_FAILED, NULL);
13272 : c->flags |= MG_F_CLOSE_IMMEDIATELY;
13273 : }
13274 : break;
13275 : case MG_SNTP_MALFORMED_REPLY:
13276 : mg_call(c, sd->hander, c->user_data, MG_SNTP_FAILED, NULL);
13277 : c->flags |= MG_F_CLOSE_IMMEDIATELY;
13278 : break;
13279 : case MG_SNTP_REPLY:
13280 : mg_call(c, sd->hander, c->user_data, MG_SNTP_REPLY, ev_data);
13281 : c->flags |= MG_F_CLOSE_IMMEDIATELY;
13282 : break;
13283 : case MG_EV_CLOSE:
13284 : MG_FREE(user_data);
13285 : c->user_data = NULL;
13286 : break;
13287 : }
13288 : }
13289 :
13290 : struct mg_connection *mg_sntp_get_time(struct mg_mgr *mgr,
13291 : mg_event_handler_t event_handler,
13292 : const char *sntp_server_name) {
13293 : struct mg_connection *c;
13294 : struct sntp_data *sd = (struct sntp_data *) MG_CALLOC(1, sizeof(*sd));
13295 : if (sd == NULL) {
13296 : return NULL;
13297 : }
13298 :
13299 : c = mg_sntp_connect(mgr, MG_CB(mg_sntp_util_ev_handler, sd),
13300 : sntp_server_name);
13301 : if (c == NULL) {
13302 : MG_FREE(sd);
13303 : return NULL;
13304 : }
13305 :
13306 : sd->hander = event_handler;
13307 : #if !MG_ENABLE_CALLBACK_USERDATA
13308 : c->user_data = sd;
13309 : #endif
13310 :
13311 : return c;
13312 : }
13313 :
13314 : #endif /* MG_ENABLE_SNTP */
13315 : #ifdef MG_MODULE_LINES
13316 : #line 1 "mongoose/src/mg_socks.c"
13317 : #endif
13318 : /*
13319 : * Copyright (c) 2017 Cesanta Software Limited
13320 : * All rights reserved
13321 : */
13322 :
13323 : #if MG_ENABLE_SOCKS
13324 :
13325 : /* Amalgamated: #include "mg_socks.h" */
13326 : /* Amalgamated: #include "mg_internal.h" */
13327 :
13328 : /*
13329 : * https://www.ietf.org/rfc/rfc1928.txt paragraph 3, handle client handshake
13330 : *
13331 : * +----+----------+----------+
13332 : * |VER | NMETHODS | METHODS |
13333 : * +----+----------+----------+
13334 : * | 1 | 1 | 1 to 255 |
13335 : * +----+----------+----------+
13336 : */
13337 : static void mg_socks5_handshake(struct mg_connection *c) {
13338 : struct mbuf *r = &c->recv_mbuf;
13339 : if (r->buf[0] != MG_SOCKS_VERSION) {
13340 : c->flags |= MG_F_CLOSE_IMMEDIATELY;
13341 : } else if (r->len > 2 && (size_t) r->buf[1] + 2 <= r->len) {
13342 : /* https://www.ietf.org/rfc/rfc1928.txt paragraph 3 */
13343 : unsigned char reply[2] = {MG_SOCKS_VERSION, MG_SOCKS_HANDSHAKE_FAILURE};
13344 : int i;
13345 : for (i = 2; i < r->buf[1] + 2; i++) {
13346 : /* TODO(lsm): support other auth methods */
13347 : if (r->buf[i] == MG_SOCKS_HANDSHAKE_NOAUTH) reply[1] = r->buf[i];
13348 : }
13349 : mbuf_remove(r, 2 + r->buf[1]);
13350 : mg_send(c, reply, sizeof(reply));
13351 : c->flags |= MG_SOCKS_HANDSHAKE_DONE; /* Mark handshake done */
13352 : }
13353 : }
13354 :
13355 : static void disband(struct mg_connection *c) {
13356 : struct mg_connection *c2 = (struct mg_connection *) c->user_data;
13357 : if (c2 != NULL) {
13358 : c2->flags |= MG_F_SEND_AND_CLOSE;
13359 : c2->user_data = NULL;
13360 : }
13361 : c->flags |= MG_F_SEND_AND_CLOSE;
13362 : c->user_data = NULL;
13363 : }
13364 :
13365 : static void relay_data(struct mg_connection *c) {
13366 : struct mg_connection *c2 = (struct mg_connection *) c->user_data;
13367 : if (c2 != NULL) {
13368 : mg_send(c2, c->recv_mbuf.buf, c->recv_mbuf.len);
13369 : mbuf_remove(&c->recv_mbuf, c->recv_mbuf.len);
13370 : } else {
13371 : c->flags |= MG_F_SEND_AND_CLOSE;
13372 : }
13373 : }
13374 :
13375 : static void serv_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
13376 : if (ev == MG_EV_CLOSE) {
13377 : disband(c);
13378 : } else if (ev == MG_EV_RECV) {
13379 : relay_data(c);
13380 : } else if (ev == MG_EV_CONNECT) {
13381 : int res = *(int *) ev_data;
13382 : if (res != 0) LOG(LL_ERROR, ("connect error: %d", res));
13383 : }
13384 : }
13385 :
13386 : static void mg_socks5_connect(struct mg_connection *c, const char *addr) {
13387 : struct mg_connection *serv = mg_connect(c->mgr, addr, serv_ev_handler);
13388 : serv->user_data = c;
13389 : c->user_data = serv;
13390 : }
13391 :
13392 : /*
13393 : * Request, https://www.ietf.org/rfc/rfc1928.txt paragraph 4
13394 : *
13395 : * +----+-----+-------+------+----------+----------+
13396 : * |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
13397 : * +----+-----+-------+------+----------+----------+
13398 : * | 1 | 1 | X'00' | 1 | Variable | 2 |
13399 : * +----+-----+-------+------+----------+----------+
13400 : */
13401 : static void mg_socks5_handle_request(struct mg_connection *c) {
13402 : struct mbuf *r = &c->recv_mbuf;
13403 : unsigned char *p = (unsigned char *) r->buf;
13404 : unsigned char addr_len = 4, reply = MG_SOCKS_SUCCESS;
13405 : int ver, cmd, atyp;
13406 : char addr[300];
13407 :
13408 : if (r->len < 8) return; /* return if not fully buffered. min DST.ADDR is 2 */
13409 : ver = p[0];
13410 : cmd = p[1];
13411 : atyp = p[3];
13412 :
13413 : /* TODO(lsm): support other commands */
13414 : if (ver != MG_SOCKS_VERSION || cmd != MG_SOCKS_CMD_CONNECT) {
13415 : reply = MG_SOCKS_CMD_NOT_SUPPORTED;
13416 : } else if (atyp == MG_SOCKS_ADDR_IPV4) {
13417 : addr_len = 4;
13418 : if (r->len < (size_t) addr_len + 6) return; /* return if not buffered */
13419 : snprintf(addr, sizeof(addr), "%d.%d.%d.%d:%d", p[4], p[5], p[6], p[7],
13420 : p[8] << 8 | p[9]);
13421 : mg_socks5_connect(c, addr);
13422 : } else if (atyp == MG_SOCKS_ADDR_IPV6) {
13423 : addr_len = 16;
13424 : if (r->len < (size_t) addr_len + 6) return; /* return if not buffered */
13425 : snprintf(addr, sizeof(addr), "[%x:%x:%x:%x:%x:%x:%x:%x]:%d",
13426 : p[4] << 8 | p[5], p[6] << 8 | p[7], p[8] << 8 | p[9],
13427 : p[10] << 8 | p[11], p[12] << 8 | p[13], p[14] << 8 | p[15],
13428 : p[16] << 8 | p[17], p[18] << 8 | p[19], p[20] << 8 | p[21]);
13429 : mg_socks5_connect(c, addr);
13430 : } else if (atyp == MG_SOCKS_ADDR_DOMAIN) {
13431 : addr_len = p[4] + 1;
13432 : if (r->len < (size_t) addr_len + 6) return; /* return if not buffered */
13433 : snprintf(addr, sizeof(addr), "%.*s:%d", p[4], p + 5,
13434 : p[4 + addr_len] << 8 | p[4 + addr_len + 1]);
13435 : mg_socks5_connect(c, addr);
13436 : } else {
13437 : reply = MG_SOCKS_ADDR_NOT_SUPPORTED;
13438 : }
13439 :
13440 : /*
13441 : * Reply, https://www.ietf.org/rfc/rfc1928.txt paragraph 5
13442 : *
13443 : * +----+-----+-------+------+----------+----------+
13444 : * |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
13445 : * +----+-----+-------+------+----------+----------+
13446 : * | 1 | 1 | X'00' | 1 | Variable | 2 |
13447 : * +----+-----+-------+------+----------+----------+
13448 : */
13449 : {
13450 : unsigned char buf[] = {MG_SOCKS_VERSION, reply, 0};
13451 : mg_send(c, buf, sizeof(buf));
13452 : }
13453 : mg_send(c, r->buf + 3, addr_len + 1 + 2);
13454 :
13455 : mbuf_remove(r, 6 + addr_len); /* Remove request from the input stream */
13456 : c->flags |= MG_SOCKS_CONNECT_DONE; /* Mark ourselves as connected */
13457 : }
13458 :
13459 : static void socks_handler(struct mg_connection *c, int ev, void *ev_data) {
13460 : if (ev == MG_EV_RECV) {
13461 : if (!(c->flags & MG_SOCKS_HANDSHAKE_DONE)) mg_socks5_handshake(c);
13462 : if (c->flags & MG_SOCKS_HANDSHAKE_DONE &&
13463 : !(c->flags & MG_SOCKS_CONNECT_DONE)) {
13464 : mg_socks5_handle_request(c);
13465 : }
13466 : if (c->flags & MG_SOCKS_CONNECT_DONE) relay_data(c);
13467 : } else if (ev == MG_EV_CLOSE) {
13468 : disband(c);
13469 : }
13470 : (void) ev_data;
13471 : }
13472 :
13473 : void mg_set_protocol_socks(struct mg_connection *c) {
13474 : c->proto_handler = socks_handler;
13475 : }
13476 : #endif
13477 : #ifdef MG_MODULE_LINES
13478 : #line 1 "common/platforms/cc3200/cc3200_libc.c"
13479 : #endif
13480 : /*
13481 : * Copyright (c) 2014-2018 Cesanta Software Limited
13482 : * All rights reserved
13483 : *
13484 : * Licensed under the Apache License, Version 2.0 (the ""License"");
13485 : * you may not use this file except in compliance with the License.
13486 : * You may obtain a copy of the License at
13487 : *
13488 : * http://www.apache.org/licenses/LICENSE-2.0
13489 : *
13490 : * Unless required by applicable law or agreed to in writing, software
13491 : * distributed under the License is distributed on an ""AS IS"" BASIS,
13492 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13493 : * See the License for the specific language governing permissions and
13494 : * limitations under the License.
13495 : */
13496 :
13497 : #if CS_PLATFORM == CS_P_CC3200
13498 :
13499 : /* Amalgamated: #include "common/mg_mem.h" */
13500 : #include <stdio.h>
13501 : #include <string.h>
13502 :
13503 : #ifndef __TI_COMPILER_VERSION__
13504 : #include <reent.h>
13505 : #include <sys/stat.h>
13506 : #include <sys/time.h>
13507 : #include <unistd.h>
13508 : #endif
13509 :
13510 : #include <inc/hw_types.h>
13511 : #include <inc/hw_memmap.h>
13512 : #include <driverlib/prcm.h>
13513 : #include <driverlib/rom.h>
13514 : #include <driverlib/rom_map.h>
13515 : #include <driverlib/uart.h>
13516 : #include <driverlib/utils.h>
13517 :
13518 : #define CONSOLE_UART UARTA0_BASE
13519 :
13520 : #ifdef __TI_COMPILER_VERSION__
13521 : int asprintf(char **strp, const char *fmt, ...) {
13522 : va_list ap;
13523 : int len;
13524 :
13525 : *strp = MG_MALLOC(BUFSIZ);
13526 : if (*strp == NULL) return -1;
13527 :
13528 : va_start(ap, fmt);
13529 : len = vsnprintf(*strp, BUFSIZ, fmt, ap);
13530 : va_end(ap);
13531 :
13532 : if (len > 0) {
13533 : *strp = MG_REALLOC(*strp, len + 1);
13534 : if (*strp == NULL) return -1;
13535 : }
13536 :
13537 : if (len >= BUFSIZ) {
13538 : va_start(ap, fmt);
13539 : len = vsnprintf(*strp, len + 1, fmt, ap);
13540 : va_end(ap);
13541 : }
13542 :
13543 : return len;
13544 : }
13545 :
13546 : #if MG_TI_NO_HOST_INTERFACE
13547 : time_t HOSTtime() {
13548 : struct timeval tp;
13549 : gettimeofday(&tp, NULL);
13550 : return tp.tv_sec;
13551 : }
13552 : #endif
13553 :
13554 : #endif /* __TI_COMPILER_VERSION__ */
13555 :
13556 : void fprint_str(FILE *fp, const char *str) {
13557 : while (*str != '\0') {
13558 : if (*str == '\n') MAP_UARTCharPut(CONSOLE_UART, '\r');
13559 : MAP_UARTCharPut(CONSOLE_UART, *str++);
13560 : }
13561 : }
13562 :
13563 : void _exit(int status) {
13564 : fprint_str(stderr, "_exit\n");
13565 : /* cause an unaligned access exception, that will drop you into gdb */
13566 : *(int *) 1 = status;
13567 : while (1)
13568 : ; /* avoid gcc warning because stdlib abort() has noreturn attribute */
13569 : }
13570 :
13571 : void _not_implemented(const char *what) {
13572 : fprint_str(stderr, what);
13573 : fprint_str(stderr, " is not implemented\n");
13574 : _exit(42);
13575 : }
13576 :
13577 : int _kill(int pid, int sig) {
13578 : (void) pid;
13579 : (void) sig;
13580 : _not_implemented("_kill");
13581 : return -1;
13582 : }
13583 :
13584 : int _getpid() {
13585 : fprint_str(stderr, "_getpid is not implemented\n");
13586 : return 42;
13587 : }
13588 :
13589 : int _isatty(int fd) {
13590 : /* 0, 1 and 2 are TTYs. */
13591 : return fd < 2;
13592 : }
13593 :
13594 : #endif /* CS_PLATFORM == CS_P_CC3200 */
13595 : #ifdef MG_MODULE_LINES
13596 : #line 1 "common/platforms/msp432/msp432_libc.c"
13597 : #endif
13598 : /*
13599 : * Copyright (c) 2014-2018 Cesanta Software Limited
13600 : * All rights reserved
13601 : *
13602 : * Licensed under the Apache License, Version 2.0 (the ""License"");
13603 : * you may not use this file except in compliance with the License.
13604 : * You may obtain a copy of the License at
13605 : *
13606 : * http://www.apache.org/licenses/LICENSE-2.0
13607 : *
13608 : * Unless required by applicable law or agreed to in writing, software
13609 : * distributed under the License is distributed on an ""AS IS"" BASIS,
13610 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13611 : * See the License for the specific language governing permissions and
13612 : * limitations under the License.
13613 : */
13614 :
13615 : #if CS_PLATFORM == CS_P_MSP432
13616 :
13617 : #include <ti/sysbios/BIOS.h>
13618 : #include <ti/sysbios/knl/Clock.h>
13619 :
13620 : int gettimeofday(struct timeval *tp, void *tzp) {
13621 : uint32_t ticks = Clock_getTicks();
13622 : tp->tv_sec = ticks / 1000;
13623 : tp->tv_usec = (ticks % 1000) * 1000;
13624 : return 0;
13625 : }
13626 :
13627 : #endif /* CS_PLATFORM == CS_P_MSP432 */
13628 : #ifdef MG_MODULE_LINES
13629 : #line 1 "common/platforms/nrf5/nrf5_libc.c"
13630 : #endif
13631 : /*
13632 : * Copyright (c) 2014-2018 Cesanta Software Limited
13633 : * All rights reserved
13634 : *
13635 : * Licensed under the Apache License, Version 2.0 (the ""License"");
13636 : * you may not use this file except in compliance with the License.
13637 : * You may obtain a copy of the License at
13638 : *
13639 : * http://www.apache.org/licenses/LICENSE-2.0
13640 : *
13641 : * Unless required by applicable law or agreed to in writing, software
13642 : * distributed under the License is distributed on an ""AS IS"" BASIS,
13643 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13644 : * See the License for the specific language governing permissions and
13645 : * limitations under the License.
13646 : */
13647 :
13648 : #if (CS_PLATFORM == CS_P_NRF51 || CS_PLATFORM == CS_P_NRF52) && \
13649 : defined(__ARMCC_VERSION)
13650 : int gettimeofday(struct timeval *tp, void *tzp) {
13651 : /* TODO */
13652 : tp->tv_sec = 0;
13653 : tp->tv_usec = 0;
13654 : return 0;
13655 : }
13656 : #endif
13657 : #ifdef MG_MODULE_LINES
13658 : #line 1 "common/platforms/simplelink/sl_fs_slfs.h"
13659 : #endif
13660 : /*
13661 : * Copyright (c) 2014-2018 Cesanta Software Limited
13662 : * All rights reserved
13663 : *
13664 : * Licensed under the Apache License, Version 2.0 (the ""License"");
13665 : * you may not use this file except in compliance with the License.
13666 : * You may obtain a copy of the License at
13667 : *
13668 : * http://www.apache.org/licenses/LICENSE-2.0
13669 : *
13670 : * Unless required by applicable law or agreed to in writing, software
13671 : * distributed under the License is distributed on an ""AS IS"" BASIS,
13672 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13673 : * See the License for the specific language governing permissions and
13674 : * limitations under the License.
13675 : */
13676 :
13677 : #ifndef CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_
13678 : #define CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_
13679 :
13680 : #if defined(MG_FS_SLFS)
13681 :
13682 : #include <stdio.h>
13683 : #ifndef __TI_COMPILER_VERSION__
13684 : #include <unistd.h>
13685 : #include <sys/stat.h>
13686 : #endif
13687 :
13688 : #define MAX_OPEN_SLFS_FILES 8
13689 :
13690 : /* Indirect libc interface - same functions, different names. */
13691 : int fs_slfs_open(const char *pathname, int flags, mode_t mode);
13692 : int fs_slfs_close(int fd);
13693 : ssize_t fs_slfs_read(int fd, void *buf, size_t count);
13694 : ssize_t fs_slfs_write(int fd, const void *buf, size_t count);
13695 : int fs_slfs_stat(const char *pathname, struct stat *s);
13696 : int fs_slfs_fstat(int fd, struct stat *s);
13697 : off_t fs_slfs_lseek(int fd, off_t offset, int whence);
13698 : int fs_slfs_unlink(const char *filename);
13699 : int fs_slfs_rename(const char *from, const char *to);
13700 :
13701 : void fs_slfs_set_file_size(const char *name, size_t size);
13702 : void fs_slfs_set_file_flags(const char *name, uint32_t flags, uint32_t *token);
13703 : void fs_slfs_unset_file_flags(const char *name);
13704 :
13705 : #endif /* defined(MG_FS_SLFS) */
13706 :
13707 : #endif /* CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_ */
13708 : #ifdef MG_MODULE_LINES
13709 : #line 1 "common/platforms/simplelink/sl_fs_slfs.c"
13710 : #endif
13711 : /*
13712 : * Copyright (c) 2014-2018 Cesanta Software Limited
13713 : * All rights reserved
13714 : *
13715 : * Licensed under the Apache License, Version 2.0 (the ""License"");
13716 : * you may not use this file except in compliance with the License.
13717 : * You may obtain a copy of the License at
13718 : *
13719 : * http://www.apache.org/licenses/LICENSE-2.0
13720 : *
13721 : * Unless required by applicable law or agreed to in writing, software
13722 : * distributed under the License is distributed on an ""AS IS"" BASIS,
13723 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13724 : * See the License for the specific language governing permissions and
13725 : * limitations under the License.
13726 : */
13727 :
13728 : /* Standard libc interface to TI SimpleLink FS. */
13729 :
13730 : #if defined(MG_FS_SLFS) || defined(CC3200_FS_SLFS)
13731 :
13732 : /* Amalgamated: #include "common/platforms/simplelink/sl_fs_slfs.h" */
13733 :
13734 : #include <errno.h>
13735 :
13736 : #if CS_PLATFORM == CS_P_CC3200
13737 : #include <inc/hw_types.h>
13738 : #endif
13739 :
13740 : /* Amalgamated: #include "common/cs_dbg.h" */
13741 : /* Amalgamated: #include "common/mg_mem.h" */
13742 :
13743 : #if SL_MAJOR_VERSION_NUM < 2
13744 : int slfs_open(const unsigned char *fname, uint32_t flags, uint32_t *token) {
13745 : _i32 fh;
13746 : _i32 r = sl_FsOpen(fname, flags, (unsigned long *) token, &fh);
13747 : return (r < 0 ? r : fh);
13748 : }
13749 : #else /* SL_MAJOR_VERSION_NUM >= 2 */
13750 : int slfs_open(const unsigned char *fname, uint32_t flags, uint32_t *token) {
13751 : return sl_FsOpen(fname, flags, (unsigned long *) token);
13752 : }
13753 : #endif
13754 :
13755 : /* From sl_fs.c */
13756 : int set_errno(int e);
13757 : const char *drop_dir(const char *fname, bool *is_slfs);
13758 :
13759 : /*
13760 : * With SLFS, you have to pre-declare max file size. Yes. Really.
13761 : * 64K should be enough for everyone. Right?
13762 : */
13763 : #ifndef FS_SLFS_MAX_FILE_SIZE
13764 : #define FS_SLFS_MAX_FILE_SIZE (64 * 1024)
13765 : #endif
13766 :
13767 : struct sl_file_open_info {
13768 : char *name;
13769 : size_t size;
13770 : uint32_t flags;
13771 : uint32_t *token;
13772 : };
13773 :
13774 : struct sl_fd_info {
13775 : _i32 fh;
13776 : _off_t pos;
13777 : size_t size;
13778 : };
13779 :
13780 : static struct sl_fd_info s_sl_fds[MAX_OPEN_SLFS_FILES];
13781 : static struct sl_file_open_info s_sl_file_open_infos[MAX_OPEN_SLFS_FILES];
13782 :
13783 : static struct sl_file_open_info *fs_slfs_find_foi(const char *name,
13784 : bool create);
13785 :
13786 : static int sl_fs_to_errno(_i32 r) {
13787 : DBG(("SL error: %d", (int) r));
13788 : switch (r) {
13789 : case SL_FS_OK:
13790 : return 0;
13791 : case SL_ERROR_FS_FILE_NAME_EXIST:
13792 : return EEXIST;
13793 : case SL_ERROR_FS_WRONG_FILE_NAME:
13794 : return EINVAL;
13795 : case SL_ERROR_FS_NO_AVAILABLE_NV_INDEX:
13796 : case SL_ERROR_FS_NOT_ENOUGH_STORAGE_SPACE:
13797 : return ENOSPC;
13798 : case SL_ERROR_FS_FAILED_TO_ALLOCATE_MEM:
13799 : return ENOMEM;
13800 : case SL_ERROR_FS_FILE_NOT_EXISTS:
13801 : return ENOENT;
13802 : case SL_ERROR_FS_NOT_SUPPORTED:
13803 : return ENOTSUP;
13804 : }
13805 : return ENXIO;
13806 : }
13807 :
13808 : int fs_slfs_open(const char *pathname, int flags, mode_t mode) {
13809 : int fd;
13810 : for (fd = 0; fd < MAX_OPEN_SLFS_FILES; fd++) {
13811 : if (s_sl_fds[fd].fh <= 0) break;
13812 : }
13813 : if (fd >= MAX_OPEN_SLFS_FILES) return set_errno(ENOMEM);
13814 : struct sl_fd_info *fi = &s_sl_fds[fd];
13815 :
13816 : /*
13817 : * Apply path manipulations again, in case we got here directly
13818 : * (via TI libc's "add_device").
13819 : */
13820 : pathname = drop_dir(pathname, NULL);
13821 :
13822 : _u32 am = 0;
13823 : fi->size = (size_t) -1;
13824 : int rw = (flags & 3);
13825 : size_t new_size = 0;
13826 : struct sl_file_open_info *foi =
13827 : fs_slfs_find_foi(pathname, false /* create */);
13828 : if (foi != NULL) {
13829 : LOG(LL_DEBUG, ("FOI for %s: %d 0x%x %p", pathname, (int) foi->size,
13830 : (unsigned int) foi->flags, foi->token));
13831 : }
13832 : if (rw == O_RDONLY) {
13833 : SlFsFileInfo_t sl_fi;
13834 : _i32 r = sl_FsGetInfo((const _u8 *) pathname, 0, &sl_fi);
13835 : if (r == SL_FS_OK) {
13836 : fi->size = SL_FI_FILE_SIZE(sl_fi);
13837 : }
13838 : am = SL_FS_READ;
13839 : } else {
13840 : if (!(flags & O_TRUNC) || (flags & O_APPEND)) {
13841 : // FailFS files cannot be opened for append and will be truncated
13842 : // when opened for write.
13843 : return set_errno(ENOTSUP);
13844 : }
13845 : if (flags & O_CREAT) {
13846 : if (foi->size > 0) {
13847 : new_size = foi->size;
13848 : } else {
13849 : new_size = FS_SLFS_MAX_FILE_SIZE;
13850 : }
13851 : am = FS_MODE_OPEN_CREATE(new_size, 0);
13852 : } else {
13853 : am = SL_FS_WRITE;
13854 : }
13855 : #if SL_MAJOR_VERSION_NUM >= 2
13856 : am |= SL_FS_OVERWRITE;
13857 : #endif
13858 : }
13859 : uint32_t *token = NULL;
13860 : if (foi != NULL) {
13861 : am |= foi->flags;
13862 : token = foi->token;
13863 : }
13864 : fi->fh = slfs_open((_u8 *) pathname, am, token);
13865 : LOG(LL_DEBUG, ("sl_FsOpen(%s, 0x%x, %p) sz %u = %d", pathname, (int) am,
13866 : token, (unsigned int) new_size, (int) fi->fh));
13867 : int r;
13868 : if (fi->fh >= 0) {
13869 : fi->pos = 0;
13870 : r = fd;
13871 : } else {
13872 : r = set_errno(sl_fs_to_errno(fi->fh));
13873 : }
13874 : return r;
13875 : }
13876 :
13877 : int fs_slfs_close(int fd) {
13878 : struct sl_fd_info *fi = &s_sl_fds[fd];
13879 : if (fi->fh <= 0) return set_errno(EBADF);
13880 : _i32 r = sl_FsClose(fi->fh, NULL, NULL, 0);
13881 : LOG(LL_DEBUG, ("sl_FsClose(%d) = %d", (int) fi->fh, (int) r));
13882 : s_sl_fds[fd].fh = -1;
13883 : return set_errno(sl_fs_to_errno(r));
13884 : }
13885 :
13886 : ssize_t fs_slfs_read(int fd, void *buf, size_t count) {
13887 : struct sl_fd_info *fi = &s_sl_fds[fd];
13888 : if (fi->fh <= 0) return set_errno(EBADF);
13889 : /* Simulate EOF. sl_FsRead @ file_size return SL_FS_ERR_OFFSET_OUT_OF_RANGE.
13890 : */
13891 : if (fi->pos == fi->size) return 0;
13892 : _i32 r = sl_FsRead(fi->fh, fi->pos, buf, count);
13893 : DBG(("sl_FsRead(%d, %d, %d) = %d", (int) fi->fh, (int) fi->pos, (int) count,
13894 : (int) r));
13895 : if (r >= 0) {
13896 : fi->pos += r;
13897 : return r;
13898 : }
13899 : return set_errno(sl_fs_to_errno(r));
13900 : }
13901 :
13902 : ssize_t fs_slfs_write(int fd, const void *buf, size_t count) {
13903 : struct sl_fd_info *fi = &s_sl_fds[fd];
13904 : if (fi->fh <= 0) return set_errno(EBADF);
13905 : _i32 r = sl_FsWrite(fi->fh, fi->pos, (_u8 *) buf, count);
13906 : DBG(("sl_FsWrite(%d, %d, %d) = %d", (int) fi->fh, (int) fi->pos, (int) count,
13907 : (int) r));
13908 : if (r >= 0) {
13909 : fi->pos += r;
13910 : return r;
13911 : }
13912 : return set_errno(sl_fs_to_errno(r));
13913 : }
13914 :
13915 : int fs_slfs_stat(const char *pathname, struct stat *s) {
13916 : SlFsFileInfo_t sl_fi;
13917 : /*
13918 : * Apply path manipulations again, in case we got here directly
13919 : * (via TI libc's "add_device").
13920 : */
13921 : pathname = drop_dir(pathname, NULL);
13922 : _i32 r = sl_FsGetInfo((const _u8 *) pathname, 0, &sl_fi);
13923 : if (r == SL_FS_OK) {
13924 : s->st_mode = S_IFREG | 0666;
13925 : s->st_nlink = 1;
13926 : s->st_size = SL_FI_FILE_SIZE(sl_fi);
13927 : return 0;
13928 : }
13929 : return set_errno(sl_fs_to_errno(r));
13930 : }
13931 :
13932 : int fs_slfs_fstat(int fd, struct stat *s) {
13933 : struct sl_fd_info *fi = &s_sl_fds[fd];
13934 : if (fi->fh <= 0) return set_errno(EBADF);
13935 : s->st_mode = 0666;
13936 : s->st_mode = S_IFREG | 0666;
13937 : s->st_nlink = 1;
13938 : s->st_size = fi->size;
13939 : return 0;
13940 : }
13941 :
13942 : off_t fs_slfs_lseek(int fd, off_t offset, int whence) {
13943 : if (s_sl_fds[fd].fh <= 0) return set_errno(EBADF);
13944 : switch (whence) {
13945 : case SEEK_SET:
13946 : s_sl_fds[fd].pos = offset;
13947 : break;
13948 : case SEEK_CUR:
13949 : s_sl_fds[fd].pos += offset;
13950 : break;
13951 : case SEEK_END:
13952 : return set_errno(ENOTSUP);
13953 : }
13954 : return 0;
13955 : }
13956 :
13957 : int fs_slfs_unlink(const char *pathname) {
13958 : /*
13959 : * Apply path manipulations again, in case we got here directly
13960 : * (via TI libc's "add_device").
13961 : */
13962 : pathname = drop_dir(pathname, NULL);
13963 : return set_errno(sl_fs_to_errno(sl_FsDel((const _u8 *) pathname, 0)));
13964 : }
13965 :
13966 : int fs_slfs_rename(const char *from, const char *to) {
13967 : return set_errno(ENOTSUP);
13968 : }
13969 :
13970 : static struct sl_file_open_info *fs_slfs_find_foi(const char *name,
13971 : bool create) {
13972 : int i = 0;
13973 : for (i = 0; i < MAX_OPEN_SLFS_FILES; i++) {
13974 : if (s_sl_file_open_infos[i].name != NULL &&
13975 : strcmp(drop_dir(s_sl_file_open_infos[i].name, NULL), name) == 0) {
13976 : break;
13977 : }
13978 : }
13979 : if (i != MAX_OPEN_SLFS_FILES) return &s_sl_file_open_infos[i];
13980 : if (!create) return NULL;
13981 : for (i = 0; i < MAX_OPEN_SLFS_FILES; i++) {
13982 : if (s_sl_file_open_infos[i].name == NULL) break;
13983 : }
13984 : if (i == MAX_OPEN_SLFS_FILES) {
13985 : i = 0; /* Evict a random slot. */
13986 : }
13987 : if (s_sl_file_open_infos[i].name != NULL) {
13988 : free(s_sl_file_open_infos[i].name);
13989 : }
13990 : s_sl_file_open_infos[i].name = strdup(name);
13991 : return &s_sl_file_open_infos[i];
13992 : }
13993 :
13994 : void fs_slfs_set_file_size(const char *name, size_t size) {
13995 : struct sl_file_open_info *foi = fs_slfs_find_foi(name, true /* create */);
13996 : foi->size = size;
13997 : }
13998 :
13999 : void fs_slfs_set_file_flags(const char *name, uint32_t flags, uint32_t *token) {
14000 : struct sl_file_open_info *foi = fs_slfs_find_foi(name, true /* create */);
14001 : foi->flags = flags;
14002 : foi->token = token;
14003 : }
14004 :
14005 : void fs_slfs_unset_file_flags(const char *name) {
14006 : struct sl_file_open_info *foi = fs_slfs_find_foi(name, false /* create */);
14007 : if (foi == NULL) return;
14008 : free(foi->name);
14009 : memset(foi, 0, sizeof(*foi));
14010 : }
14011 :
14012 : #endif /* defined(MG_FS_SLFS) || defined(CC3200_FS_SLFS) */
14013 : #ifdef MG_MODULE_LINES
14014 : #line 1 "common/platforms/simplelink/sl_fs.c"
14015 : #endif
14016 : /*
14017 : * Copyright (c) 2014-2018 Cesanta Software Limited
14018 : * All rights reserved
14019 : *
14020 : * Licensed under the Apache License, Version 2.0 (the ""License"");
14021 : * you may not use this file except in compliance with the License.
14022 : * You may obtain a copy of the License at
14023 : *
14024 : * http://www.apache.org/licenses/LICENSE-2.0
14025 : *
14026 : * Unless required by applicable law or agreed to in writing, software
14027 : * distributed under the License is distributed on an ""AS IS"" BASIS,
14028 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14029 : * See the License for the specific language governing permissions and
14030 : * limitations under the License.
14031 : */
14032 :
14033 : #if MG_NET_IF == MG_NET_IF_SIMPLELINK && \
14034 : (defined(MG_FS_SLFS) || defined(MG_FS_SPIFFS))
14035 :
14036 : int set_errno(int e) {
14037 : errno = e;
14038 : return (e == 0 ? 0 : -1);
14039 : }
14040 :
14041 : const char *drop_dir(const char *fname, bool *is_slfs) {
14042 : if (is_slfs != NULL) {
14043 : *is_slfs = (strncmp(fname, "SL:", 3) == 0);
14044 : if (*is_slfs) fname += 3;
14045 : }
14046 : /* Drop "./", if any */
14047 : if (fname[0] == '.' && fname[1] == '/') {
14048 : fname += 2;
14049 : }
14050 : /*
14051 : * Drop / if it is the only one in the path.
14052 : * This allows use of /pretend/directories but serves /file.txt as normal.
14053 : */
14054 : if (fname[0] == '/' && strchr(fname + 1, '/') == NULL) {
14055 : fname++;
14056 : }
14057 : return fname;
14058 : }
14059 :
14060 : #if !defined(MG_FS_NO_VFS)
14061 :
14062 : #include <errno.h>
14063 : #include <stdbool.h>
14064 : #include <stdio.h>
14065 : #include <stdlib.h>
14066 : #include <string.h>
14067 : #ifdef __TI_COMPILER_VERSION__
14068 : #include <file.h>
14069 : #endif
14070 :
14071 : /* Amalgamated: #include "common/cs_dbg.h" */
14072 : /* Amalgamated: #include "common/platform.h" */
14073 :
14074 : #ifdef CC3200_FS_SPIFFS
14075 : /* Amalgamated: #include "cc3200_fs_spiffs.h" */
14076 : #endif
14077 :
14078 : #ifdef MG_FS_SLFS
14079 : /* Amalgamated: #include "sl_fs_slfs.h" */
14080 : #endif
14081 :
14082 : #define NUM_SYS_FDS 3
14083 : #define SPIFFS_FD_BASE 10
14084 : #define SLFS_FD_BASE 100
14085 :
14086 : #if !defined(MG_UART_CHAR_PUT) && !defined(MG_UART_WRITE)
14087 : #if CS_PLATFORM == CS_P_CC3200
14088 : #include <inc/hw_types.h>
14089 : #include <inc/hw_memmap.h>
14090 : #include <driverlib/rom.h>
14091 : #include <driverlib/rom_map.h>
14092 : #include <driverlib/uart.h>
14093 : #define MG_UART_CHAR_PUT(fd, c) MAP_UARTCharPut(UARTA0_BASE, c);
14094 : #else
14095 : #define MG_UART_WRITE(fd, buf, len)
14096 : #endif /* CS_PLATFORM == CS_P_CC3200 */
14097 : #endif /* !MG_UART_CHAR_PUT */
14098 :
14099 : enum fd_type {
14100 : FD_INVALID,
14101 : FD_SYS,
14102 : #ifdef CC3200_FS_SPIFFS
14103 : FD_SPIFFS,
14104 : #endif
14105 : #ifdef MG_FS_SLFS
14106 : FD_SLFS
14107 : #endif
14108 : };
14109 : static int fd_type(int fd) {
14110 : if (fd >= 0 && fd < NUM_SYS_FDS) return FD_SYS;
14111 : #ifdef CC3200_FS_SPIFFS
14112 : if (fd >= SPIFFS_FD_BASE && fd < SPIFFS_FD_BASE + MAX_OPEN_SPIFFS_FILES) {
14113 : return FD_SPIFFS;
14114 : }
14115 : #endif
14116 : #ifdef MG_FS_SLFS
14117 : if (fd >= SLFS_FD_BASE && fd < SLFS_FD_BASE + MAX_OPEN_SLFS_FILES) {
14118 : return FD_SLFS;
14119 : }
14120 : #endif
14121 : return FD_INVALID;
14122 : }
14123 :
14124 : #if MG_TI_NO_HOST_INTERFACE
14125 : int open(const char *pathname, unsigned flags, int mode) {
14126 : #else
14127 : int _open(const char *pathname, int flags, mode_t mode) {
14128 : #endif
14129 : int fd = -1;
14130 : bool is_sl;
14131 : const char *fname = drop_dir(pathname, &is_sl);
14132 : if (is_sl) {
14133 : #ifdef MG_FS_SLFS
14134 : fd = fs_slfs_open(fname, flags, mode);
14135 : if (fd >= 0) fd += SLFS_FD_BASE;
14136 : #endif
14137 : } else {
14138 : #ifdef CC3200_FS_SPIFFS
14139 : fd = fs_spiffs_open(fname, flags, mode);
14140 : if (fd >= 0) fd += SPIFFS_FD_BASE;
14141 : #endif
14142 : }
14143 : LOG(LL_DEBUG,
14144 : ("open(%s, 0x%x) = %d, fname = %s", pathname, flags, fd, fname));
14145 : return fd;
14146 : }
14147 :
14148 : int _stat(const char *pathname, struct stat *st) {
14149 : int res = -1;
14150 : bool is_sl;
14151 : const char *fname = drop_dir(pathname, &is_sl);
14152 : memset(st, 0, sizeof(*st));
14153 : /* Simulate statting the root directory. */
14154 : if (fname[0] == '\0' || strcmp(fname, ".") == 0) {
14155 : st->st_ino = 0;
14156 : st->st_mode = S_IFDIR | 0777;
14157 : st->st_nlink = 1;
14158 : st->st_size = 0;
14159 : return 0;
14160 : }
14161 : if (is_sl) {
14162 : #ifdef MG_FS_SLFS
14163 : res = fs_slfs_stat(fname, st);
14164 : #endif
14165 : } else {
14166 : #ifdef CC3200_FS_SPIFFS
14167 : res = fs_spiffs_stat(fname, st);
14168 : #endif
14169 : }
14170 : LOG(LL_DEBUG, ("stat(%s) = %d; fname = %s", pathname, res, fname));
14171 : return res;
14172 : }
14173 :
14174 : #if MG_TI_NO_HOST_INTERFACE
14175 : int close(int fd) {
14176 : #else
14177 : int _close(int fd) {
14178 : #endif
14179 : int r = -1;
14180 : switch (fd_type(fd)) {
14181 : case FD_INVALID:
14182 : r = set_errno(EBADF);
14183 : break;
14184 : case FD_SYS:
14185 : r = set_errno(EACCES);
14186 : break;
14187 : #ifdef CC3200_FS_SPIFFS
14188 : case FD_SPIFFS:
14189 : r = fs_spiffs_close(fd - SPIFFS_FD_BASE);
14190 : break;
14191 : #endif
14192 : #ifdef MG_FS_SLFS
14193 : case FD_SLFS:
14194 : r = fs_slfs_close(fd - SLFS_FD_BASE);
14195 : break;
14196 : #endif
14197 : }
14198 : DBG(("close(%d) = %d", fd, r));
14199 : return r;
14200 : }
14201 :
14202 : #if MG_TI_NO_HOST_INTERFACE
14203 : off_t lseek(int fd, off_t offset, int whence) {
14204 : #else
14205 : off_t _lseek(int fd, off_t offset, int whence) {
14206 : #endif
14207 : int r = -1;
14208 : switch (fd_type(fd)) {
14209 : case FD_INVALID:
14210 : r = set_errno(EBADF);
14211 : break;
14212 : case FD_SYS:
14213 : r = set_errno(ESPIPE);
14214 : break;
14215 : #ifdef CC3200_FS_SPIFFS
14216 : case FD_SPIFFS:
14217 : r = fs_spiffs_lseek(fd - SPIFFS_FD_BASE, offset, whence);
14218 : break;
14219 : #endif
14220 : #ifdef MG_FS_SLFS
14221 : case FD_SLFS:
14222 : r = fs_slfs_lseek(fd - SLFS_FD_BASE, offset, whence);
14223 : break;
14224 : #endif
14225 : }
14226 : DBG(("lseek(%d, %d, %d) = %d", fd, (int) offset, whence, r));
14227 : return r;
14228 : }
14229 :
14230 : int _fstat(int fd, struct stat *s) {
14231 : int r = -1;
14232 : memset(s, 0, sizeof(*s));
14233 : switch (fd_type(fd)) {
14234 : case FD_INVALID:
14235 : r = set_errno(EBADF);
14236 : break;
14237 : case FD_SYS: {
14238 : /* Create barely passable stats for STD{IN,OUT,ERR}. */
14239 : memset(s, 0, sizeof(*s));
14240 : s->st_ino = fd;
14241 : s->st_mode = S_IFCHR | 0666;
14242 : r = 0;
14243 : break;
14244 : }
14245 : #ifdef CC3200_FS_SPIFFS
14246 : case FD_SPIFFS:
14247 : r = fs_spiffs_fstat(fd - SPIFFS_FD_BASE, s);
14248 : break;
14249 : #endif
14250 : #ifdef MG_FS_SLFS
14251 : case FD_SLFS:
14252 : r = fs_slfs_fstat(fd - SLFS_FD_BASE, s);
14253 : break;
14254 : #endif
14255 : }
14256 : DBG(("fstat(%d) = %d", fd, r));
14257 : return r;
14258 : }
14259 :
14260 : #if MG_TI_NO_HOST_INTERFACE
14261 : int read(int fd, char *buf, unsigned count) {
14262 : #else
14263 : ssize_t _read(int fd, void *buf, size_t count) {
14264 : #endif
14265 : int r = -1;
14266 : switch (fd_type(fd)) {
14267 : case FD_INVALID:
14268 : r = set_errno(EBADF);
14269 : break;
14270 : case FD_SYS: {
14271 : if (fd != 0) {
14272 : r = set_errno(EACCES);
14273 : break;
14274 : }
14275 : /* Should we allow reading from stdin = uart? */
14276 : r = set_errno(ENOTSUP);
14277 : break;
14278 : }
14279 : #ifdef CC3200_FS_SPIFFS
14280 : case FD_SPIFFS:
14281 : r = fs_spiffs_read(fd - SPIFFS_FD_BASE, buf, count);
14282 : break;
14283 : #endif
14284 : #ifdef MG_FS_SLFS
14285 : case FD_SLFS:
14286 : r = fs_slfs_read(fd - SLFS_FD_BASE, buf, count);
14287 : break;
14288 : #endif
14289 : }
14290 : DBG(("read(%d, %u) = %d", fd, count, r));
14291 : return r;
14292 : }
14293 :
14294 : #if MG_TI_NO_HOST_INTERFACE
14295 : int write(int fd, const char *buf, unsigned count) {
14296 : #else
14297 : ssize_t _write(int fd, const void *buf, size_t count) {
14298 : #endif
14299 : int r = -1;
14300 : switch (fd_type(fd)) {
14301 : case FD_INVALID:
14302 : r = set_errno(EBADF);
14303 : break;
14304 : case FD_SYS: {
14305 : if (fd == 0) {
14306 : r = set_errno(EACCES);
14307 : break;
14308 : }
14309 : #ifdef MG_UART_WRITE
14310 : MG_UART_WRITE(fd, buf, count);
14311 : #elif defined(MG_UART_CHAR_PUT)
14312 : {
14313 : size_t i;
14314 : for (i = 0; i < count; i++) {
14315 : const char c = ((const char *) buf)[i];
14316 : if (c == '\n') MG_UART_CHAR_PUT(fd, '\r');
14317 : MG_UART_CHAR_PUT(fd, c);
14318 : }
14319 : }
14320 : #endif
14321 : r = count;
14322 : break;
14323 : }
14324 : #ifdef CC3200_FS_SPIFFS
14325 : case FD_SPIFFS:
14326 : r = fs_spiffs_write(fd - SPIFFS_FD_BASE, buf, count);
14327 : break;
14328 : #endif
14329 : #ifdef MG_FS_SLFS
14330 : case FD_SLFS:
14331 : r = fs_slfs_write(fd - SLFS_FD_BASE, buf, count);
14332 : break;
14333 : #endif
14334 : }
14335 : return r;
14336 : }
14337 :
14338 : /*
14339 : * On Newlib we override rename directly too, because the default
14340 : * implementation using _link and _unlink doesn't work for us.
14341 : */
14342 : #if MG_TI_NO_HOST_INTERFACE || defined(_NEWLIB_VERSION)
14343 : int rename(const char *frompath, const char *topath) {
14344 : int r = -1;
14345 : bool is_sl_from, is_sl_to;
14346 : const char *from = drop_dir(frompath, &is_sl_from);
14347 : const char *to = drop_dir(topath, &is_sl_to);
14348 : if (is_sl_from || is_sl_to) {
14349 : set_errno(ENOTSUP);
14350 : } else {
14351 : #ifdef CC3200_FS_SPIFFS
14352 : r = fs_spiffs_rename(from, to);
14353 : #endif
14354 : }
14355 : DBG(("rename(%s, %s) = %d", from, to, r));
14356 : return r;
14357 : }
14358 : #endif /* MG_TI_NO_HOST_INTERFACE || defined(_NEWLIB_VERSION) */
14359 :
14360 : #if MG_TI_NO_HOST_INTERFACE
14361 : int unlink(const char *pathname) {
14362 : #else
14363 : int _unlink(const char *pathname) {
14364 : #endif
14365 : int r = -1;
14366 : bool is_sl;
14367 : const char *fname = drop_dir(pathname, &is_sl);
14368 : if (is_sl) {
14369 : #ifdef MG_FS_SLFS
14370 : r = fs_slfs_unlink(fname);
14371 : #endif
14372 : } else {
14373 : #ifdef CC3200_FS_SPIFFS
14374 : r = fs_spiffs_unlink(fname);
14375 : #endif
14376 : }
14377 : DBG(("unlink(%s) = %d, fname = %s", pathname, r, fname));
14378 : return r;
14379 : }
14380 :
14381 : #ifdef CC3200_FS_SPIFFS /* FailFS does not support listing files. */
14382 : DIR *opendir(const char *dir_name) {
14383 : DIR *r = NULL;
14384 : bool is_sl;
14385 : drop_dir(dir_name, &is_sl);
14386 : if (is_sl) {
14387 : r = NULL;
14388 : set_errno(ENOTSUP);
14389 : } else {
14390 : r = fs_spiffs_opendir(dir_name);
14391 : }
14392 : DBG(("opendir(%s) = %p", dir_name, r));
14393 : return r;
14394 : }
14395 :
14396 : struct dirent *readdir(DIR *dir) {
14397 : struct dirent *res = fs_spiffs_readdir(dir);
14398 : DBG(("readdir(%p) = %p", dir, res));
14399 : return res;
14400 : }
14401 :
14402 : int closedir(DIR *dir) {
14403 : int res = fs_spiffs_closedir(dir);
14404 : DBG(("closedir(%p) = %d", dir, res));
14405 : return res;
14406 : }
14407 :
14408 : int rmdir(const char *path) {
14409 : return fs_spiffs_rmdir(path);
14410 : }
14411 :
14412 : int mkdir(const char *path, mode_t mode) {
14413 : (void) path;
14414 : (void) mode;
14415 : /* for spiffs supports only root dir, which comes from mongoose as '.' */
14416 : return (strlen(path) == 1 && *path == '.') ? 0 : ENOTDIR;
14417 : }
14418 : #endif
14419 :
14420 : int sl_fs_init(void) {
14421 : int ret = 1;
14422 : #ifdef __TI_COMPILER_VERSION__
14423 : #ifdef MG_FS_SLFS
14424 : #pragma diag_push
14425 : #pragma diag_suppress 169 /* Nothing we can do about the prototype mismatch. \
14426 : */
14427 : ret = (add_device("SL", _MSA, fs_slfs_open, fs_slfs_close, fs_slfs_read,
14428 : fs_slfs_write, fs_slfs_lseek, fs_slfs_unlink,
14429 : fs_slfs_rename) == 0);
14430 : #pragma diag_pop
14431 : #endif
14432 : #endif
14433 : return ret;
14434 : }
14435 :
14436 : #endif /* !defined(MG_FS_NO_VFS) */
14437 : #endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK && (defined(MG_FS_SLFS) || \
14438 : defined(MG_FS_SPIFFS)) */
14439 : #ifdef MG_MODULE_LINES
14440 : #line 1 "common/platforms/simplelink/sl_socket.c"
14441 : #endif
14442 : /*
14443 : * Copyright (c) 2014-2018 Cesanta Software Limited
14444 : * All rights reserved
14445 : *
14446 : * Licensed under the Apache License, Version 2.0 (the ""License"");
14447 : * you may not use this file except in compliance with the License.
14448 : * You may obtain a copy of the License at
14449 : *
14450 : * http://www.apache.org/licenses/LICENSE-2.0
14451 : *
14452 : * Unless required by applicable law or agreed to in writing, software
14453 : * distributed under the License is distributed on an ""AS IS"" BASIS,
14454 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14455 : * See the License for the specific language governing permissions and
14456 : * limitations under the License.
14457 : */
14458 :
14459 : #if MG_NET_IF == MG_NET_IF_SIMPLELINK
14460 :
14461 : #include <errno.h>
14462 : #include <stdio.h>
14463 :
14464 : /* Amalgamated: #include "common/platform.h" */
14465 :
14466 : const char *inet_ntop(int af, const void *src, char *dst, socklen_t size) {
14467 : int res;
14468 : struct in_addr *in = (struct in_addr *) src;
14469 : if (af != AF_INET) {
14470 : errno = ENOTSUP;
14471 : return NULL;
14472 : }
14473 : res = snprintf(dst, size, "%lu.%lu.%lu.%lu", SL_IPV4_BYTE(in->s_addr, 0),
14474 : SL_IPV4_BYTE(in->s_addr, 1), SL_IPV4_BYTE(in->s_addr, 2),
14475 : SL_IPV4_BYTE(in->s_addr, 3));
14476 : return res > 0 ? dst : NULL;
14477 : }
14478 :
14479 : char *inet_ntoa(struct in_addr n) {
14480 : static char a[16];
14481 : return (char *) inet_ntop(AF_INET, &n, a, sizeof(a));
14482 : }
14483 :
14484 : int inet_pton(int af, const char *src, void *dst) {
14485 : uint32_t a0, a1, a2, a3;
14486 : uint8_t *db = (uint8_t *) dst;
14487 : if (af != AF_INET) {
14488 : errno = ENOTSUP;
14489 : return 0;
14490 : }
14491 : if (sscanf(src, "%lu.%lu.%lu.%lu", &a0, &a1, &a2, &a3) != 4) {
14492 : return 0;
14493 : }
14494 : *db = a3;
14495 : *(db + 1) = a2;
14496 : *(db + 2) = a1;
14497 : *(db + 3) = a0;
14498 : return 1;
14499 : }
14500 :
14501 : #endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */
14502 : #ifdef MG_MODULE_LINES
14503 : #line 1 "common/platforms/simplelink/sl_mg_task.c"
14504 : #endif
14505 : #if MG_NET_IF == MG_NET_IF_SIMPLELINK && !defined(MG_SIMPLELINK_NO_OSI)
14506 :
14507 : /* Amalgamated: #include "mg_task.h" */
14508 :
14509 : #include <oslib/osi.h>
14510 :
14511 : enum mg_q_msg_type {
14512 : MG_Q_MSG_CB,
14513 : };
14514 : struct mg_q_msg {
14515 : enum mg_q_msg_type type;
14516 : void (*cb)(struct mg_mgr *mgr, void *arg);
14517 : void *arg;
14518 : };
14519 : static OsiMsgQ_t s_mg_q;
14520 : static void mg_task(void *arg);
14521 :
14522 : bool mg_start_task(int priority, int stack_size, mg_init_cb mg_init) {
14523 : if (osi_MsgQCreate(&s_mg_q, "MG", sizeof(struct mg_q_msg), 16) != OSI_OK) {
14524 : return false;
14525 : }
14526 : if (osi_TaskCreate(mg_task, (const signed char *) "MG", stack_size,
14527 : (void *) mg_init, priority, NULL) != OSI_OK) {
14528 : return false;
14529 : }
14530 : return true;
14531 : }
14532 :
14533 : static void mg_task(void *arg) {
14534 : struct mg_mgr mgr;
14535 : mg_init_cb mg_init = (mg_init_cb) arg;
14536 : mg_mgr_init(&mgr, NULL);
14537 : mg_init(&mgr);
14538 : while (1) {
14539 : struct mg_q_msg msg;
14540 : mg_mgr_poll(&mgr, 1);
14541 : if (osi_MsgQRead(&s_mg_q, &msg, 1) != OSI_OK) continue;
14542 : switch (msg.type) {
14543 : case MG_Q_MSG_CB: {
14544 : msg.cb(&mgr, msg.arg);
14545 : }
14546 : }
14547 : }
14548 : }
14549 :
14550 : void mg_run_in_task(void (*cb)(struct mg_mgr *mgr, void *arg), void *cb_arg) {
14551 : struct mg_q_msg msg = {MG_Q_MSG_CB, cb, cb_arg};
14552 : osi_MsgQWrite(&s_mg_q, &msg, OSI_NO_WAIT);
14553 : }
14554 :
14555 : #endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK && !defined(MG_SIMPLELINK_NO_OSI) \
14556 : */
14557 : #ifdef MG_MODULE_LINES
14558 : #line 1 "common/platforms/simplelink/sl_net_if.h"
14559 : #endif
14560 : /*
14561 : * Copyright (c) 2014-2018 Cesanta Software Limited
14562 : * All rights reserved
14563 : *
14564 : * Licensed under the Apache License, Version 2.0 (the ""License"");
14565 : * you may not use this file except in compliance with the License.
14566 : * You may obtain a copy of the License at
14567 : *
14568 : * http://www.apache.org/licenses/LICENSE-2.0
14569 : *
14570 : * Unless required by applicable law or agreed to in writing, software
14571 : * distributed under the License is distributed on an ""AS IS"" BASIS,
14572 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14573 : * See the License for the specific language governing permissions and
14574 : * limitations under the License.
14575 : */
14576 :
14577 : #ifndef CS_COMMON_PLATFORMS_SIMPLELINK_SL_NET_IF_H_
14578 : #define CS_COMMON_PLATFORMS_SIMPLELINK_SL_NET_IF_H_
14579 :
14580 : /* Amalgamated: #include "mongoose/src/net_if.h" */
14581 :
14582 : #ifdef __cplusplus
14583 : extern "C" {
14584 : #endif /* __cplusplus */
14585 :
14586 : #ifndef MG_ENABLE_NET_IF_SIMPLELINK
14587 : #define MG_ENABLE_NET_IF_SIMPLELINK MG_NET_IF == MG_NET_IF_SIMPLELINK
14588 : #endif
14589 :
14590 : extern const struct mg_iface_vtable mg_simplelink_iface_vtable;
14591 :
14592 : #ifdef __cplusplus
14593 : }
14594 : #endif /* __cplusplus */
14595 :
14596 : #endif /* CS_COMMON_PLATFORMS_SIMPLELINK_SL_NET_IF_H_ */
14597 : #ifdef MG_MODULE_LINES
14598 : #line 1 "common/platforms/simplelink/sl_net_if.c"
14599 : #endif
14600 : /*
14601 : * Copyright (c) 2014-2018 Cesanta Software Limited
14602 : * All rights reserved
14603 : *
14604 : * Licensed under the Apache License, Version 2.0 (the ""License"");
14605 : * you may not use this file except in compliance with the License.
14606 : * You may obtain a copy of the License at
14607 : *
14608 : * http://www.apache.org/licenses/LICENSE-2.0
14609 : *
14610 : * Unless required by applicable law or agreed to in writing, software
14611 : * distributed under the License is distributed on an ""AS IS"" BASIS,
14612 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14613 : * See the License for the specific language governing permissions and
14614 : * limitations under the License.
14615 : */
14616 :
14617 : /* Amalgamated: #include "common/platforms/simplelink/sl_net_if.h" */
14618 :
14619 : #if MG_ENABLE_NET_IF_SIMPLELINK
14620 :
14621 : /* Amalgamated: #include "mongoose/src/internal.h" */
14622 : /* Amalgamated: #include "mongoose/src/util.h" */
14623 :
14624 : #define MG_TCP_RECV_BUFFER_SIZE 1024
14625 : #define MG_UDP_RECV_BUFFER_SIZE 1500
14626 :
14627 : static sock_t mg_open_listening_socket(struct mg_connection *nc,
14628 : union socket_address *sa, int type,
14629 : int proto);
14630 :
14631 : static void mg_set_non_blocking_mode(sock_t sock) {
14632 : SlSockNonblocking_t opt;
14633 : #if SL_MAJOR_VERSION_NUM < 2
14634 : opt.NonblockingEnabled = 1;
14635 : #else
14636 : opt.NonBlockingEnabled = 1;
14637 : #endif
14638 : sl_SetSockOpt(sock, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &opt, sizeof(opt));
14639 : }
14640 :
14641 : static int mg_is_error(int n) {
14642 : return (n < 0 && n != SL_ERROR_BSD_EALREADY && n != SL_ERROR_BSD_EAGAIN);
14643 : }
14644 :
14645 : static void mg_sl_if_connect_tcp(struct mg_connection *nc,
14646 : const union socket_address *sa) {
14647 : int proto = 0;
14648 : #if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
14649 : if (nc->flags & MG_F_SSL) proto = SL_SEC_SOCKET;
14650 : #endif
14651 : sock_t sock = sl_Socket(AF_INET, SOCK_STREAM, proto);
14652 : if (sock < 0) {
14653 : nc->err = sock;
14654 : goto out;
14655 : }
14656 : mg_sock_set(nc, sock);
14657 : #if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
14658 : nc->err = sl_set_ssl_opts(sock, nc);
14659 : if (nc->err != 0) goto out;
14660 : #endif
14661 : nc->err = sl_Connect(sock, &sa->sa, sizeof(sa->sin));
14662 : out:
14663 : DBG(("%p to %s:%d sock %d %d err %d", nc, inet_ntoa(sa->sin.sin_addr),
14664 : ntohs(sa->sin.sin_port), nc->sock, proto, nc->err));
14665 : }
14666 :
14667 : static void mg_sl_if_connect_udp(struct mg_connection *nc) {
14668 : sock_t sock = sl_Socket(AF_INET, SOCK_DGRAM, 0);
14669 : if (sock < 0) {
14670 : nc->err = sock;
14671 : return;
14672 : }
14673 : mg_sock_set(nc, sock);
14674 : nc->err = 0;
14675 : }
14676 :
14677 : static int mg_sl_if_listen_tcp(struct mg_connection *nc,
14678 : union socket_address *sa) {
14679 : int proto = 0;
14680 : if (nc->flags & MG_F_SSL) proto = SL_SEC_SOCKET;
14681 : sock_t sock = mg_open_listening_socket(nc, sa, SOCK_STREAM, proto);
14682 : if (sock < 0) return sock;
14683 : mg_sock_set(nc, sock);
14684 : return 0;
14685 : }
14686 :
14687 : static int mg_sl_if_listen_udp(struct mg_connection *nc,
14688 : union socket_address *sa) {
14689 : sock_t sock = mg_open_listening_socket(nc, sa, SOCK_DGRAM, 0);
14690 : if (sock == INVALID_SOCKET) return (errno ? errno : 1);
14691 : mg_sock_set(nc, sock);
14692 : return 0;
14693 : }
14694 :
14695 : static int mg_sl_if_tcp_send(struct mg_connection *nc, const void *buf,
14696 : size_t len) {
14697 : int n = (int) sl_Send(nc->sock, buf, len, 0);
14698 : if (n < 0 && !mg_is_error(n)) n = 0;
14699 : return n;
14700 : }
14701 :
14702 : static int mg_sl_if_udp_send(struct mg_connection *nc, const void *buf,
14703 : size_t len) {
14704 : int n = sl_SendTo(nc->sock, buf, len, 0, &nc->sa.sa, sizeof(nc->sa.sin));
14705 : if (n < 0 && !mg_is_error(n)) n = 0;
14706 : return n;
14707 : }
14708 :
14709 : static int mg_sl_if_tcp_recv(struct mg_connection *nc, void *buf, size_t len) {
14710 : int n = sl_Recv(nc->sock, buf, len, 0);
14711 : if (n == 0) {
14712 : /* Orderly shutdown of the socket, try flushing output. */
14713 : nc->flags |= MG_F_SEND_AND_CLOSE;
14714 : } else if (n < 0 && !mg_is_error(n)) {
14715 : n = 0;
14716 : }
14717 : return n;
14718 : }
14719 :
14720 : static int mg_sl_if_udp_recv(struct mg_connection *nc, void *buf, size_t len,
14721 : union socket_address *sa, size_t *sa_len) {
14722 : SlSocklen_t sa_len_t = *sa_len;
14723 : int n = sl_RecvFrom(nc->sock, buf, MG_UDP_RECV_BUFFER_SIZE, 0,
14724 : (SlSockAddr_t *) sa, &sa_len_t);
14725 : *sa_len = sa_len_t;
14726 : if (n < 0 && !mg_is_error(n)) n = 0;
14727 : return n;
14728 : }
14729 :
14730 : static int mg_sl_if_create_conn(struct mg_connection *nc) {
14731 : (void) nc;
14732 : return 1;
14733 : }
14734 :
14735 : void mg_sl_if_destroy_conn(struct mg_connection *nc) {
14736 : if (nc->sock == INVALID_SOCKET) return;
14737 : /* For UDP, only close outgoing sockets or listeners. */
14738 : if (!(nc->flags & MG_F_UDP) || nc->listener == NULL) {
14739 : sl_Close(nc->sock);
14740 : }
14741 : nc->sock = INVALID_SOCKET;
14742 : }
14743 :
14744 : static int mg_accept_conn(struct mg_connection *lc) {
14745 : struct mg_connection *nc;
14746 : union socket_address sa;
14747 : socklen_t sa_len = sizeof(sa);
14748 : sock_t sock = sl_Accept(lc->sock, &sa.sa, &sa_len);
14749 : if (sock < 0) {
14750 : DBG(("%p: failed to accept: %d", lc, sock));
14751 : return 0;
14752 : }
14753 : nc = mg_if_accept_new_conn(lc);
14754 : if (nc == NULL) {
14755 : sl_Close(sock);
14756 : return 0;
14757 : }
14758 : DBG(("%p conn from %s:%d", nc, inet_ntoa(sa.sin.sin_addr),
14759 : ntohs(sa.sin.sin_port)));
14760 : mg_sock_set(nc, sock);
14761 : mg_if_accept_tcp_cb(nc, &sa, sa_len);
14762 : return 1;
14763 : }
14764 :
14765 : /* 'sa' must be an initialized address to bind to */
14766 : static sock_t mg_open_listening_socket(struct mg_connection *nc,
14767 : union socket_address *sa, int type,
14768 : int proto) {
14769 : int r;
14770 : socklen_t sa_len =
14771 : (sa->sa.sa_family == AF_INET) ? sizeof(sa->sin) : sizeof(sa->sin6);
14772 : sock_t sock = sl_Socket(sa->sa.sa_family, type, proto);
14773 : if (sock < 0) return sock;
14774 : #if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
14775 : if ((r = sl_set_ssl_opts(sock, nc)) < 0) goto clean;
14776 : #endif
14777 : if ((r = sl_Bind(sock, &sa->sa, sa_len)) < 0) goto clean;
14778 : if (type != SOCK_DGRAM) {
14779 : if ((r = sl_Listen(sock, SOMAXCONN)) < 0) goto clean;
14780 : }
14781 : mg_set_non_blocking_mode(sock);
14782 : clean:
14783 : if (r < 0) {
14784 : sl_Close(sock);
14785 : sock = r;
14786 : }
14787 : return sock;
14788 : }
14789 :
14790 : #define _MG_F_FD_CAN_READ 1
14791 : #define _MG_F_FD_CAN_WRITE 1 << 1
14792 : #define _MG_F_FD_ERROR 1 << 2
14793 :
14794 : void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
14795 : DBG(("%p fd=%d fd_flags=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock,
14796 : fd_flags, nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
14797 :
14798 : if (!mg_if_poll(nc, now)) return;
14799 :
14800 : if (nc->flags & MG_F_CONNECTING) {
14801 : if ((nc->flags & MG_F_UDP) || nc->err != SL_ERROR_BSD_EALREADY) {
14802 : mg_if_connect_cb(nc, nc->err);
14803 : } else {
14804 : /* In SimpleLink, to get status of non-blocking connect() we need to wait
14805 : * until socket is writable and repeat the call to sl_Connect again,
14806 : * which will now return the real status. */
14807 : if (fd_flags & _MG_F_FD_CAN_WRITE) {
14808 : nc->err = sl_Connect(nc->sock, &nc->sa.sa, sizeof(nc->sa.sin));
14809 : DBG(("%p conn res=%d", nc, nc->err));
14810 : if (nc->err == SL_ERROR_BSD_ESECSNOVERIFY ||
14811 : /* TODO(rojer): Provide API to set the date for verification. */
14812 : nc->err == SL_ERROR_BSD_ESECDATEERROR
14813 : #if SL_MAJOR_VERSION_NUM >= 2
14814 : /* Per SWRU455, this error does not mean verification failed,
14815 : * it only means that the cert used is not present in the trusted
14816 : * root CA catalog. Which is perfectly fine. */
14817 : ||
14818 : nc->err == SL_ERROR_BSD_ESECUNKNOWNROOTCA
14819 : #endif
14820 : ) {
14821 : nc->err = 0;
14822 : }
14823 : mg_if_connect_cb(nc, nc->err);
14824 : }
14825 : }
14826 : /* Ignore read/write in further processing, we've handled it. */
14827 : fd_flags &= ~(_MG_F_FD_CAN_READ | _MG_F_FD_CAN_WRITE);
14828 : }
14829 :
14830 : if (fd_flags & _MG_F_FD_CAN_READ) {
14831 : if (nc->flags & MG_F_UDP) {
14832 : mg_if_can_recv_cb(nc);
14833 : } else {
14834 : if (nc->flags & MG_F_LISTENING) {
14835 : mg_accept_conn(nc);
14836 : } else {
14837 : mg_if_can_recv_cb(nc);
14838 : }
14839 : }
14840 : }
14841 :
14842 : if (fd_flags & _MG_F_FD_CAN_WRITE) {
14843 : mg_if_can_send_cb(nc);
14844 : }
14845 :
14846 : DBG(("%p after fd=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock, nc->flags,
14847 : (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
14848 : }
14849 :
14850 : /* Associate a socket to a connection. */
14851 : void mg_sl_if_sock_set(struct mg_connection *nc, sock_t sock) {
14852 : mg_set_non_blocking_mode(sock);
14853 : nc->sock = sock;
14854 : DBG(("%p %d", nc, sock));
14855 : }
14856 :
14857 : void mg_sl_if_init(struct mg_iface *iface) {
14858 : (void) iface;
14859 : DBG(("%p using sl_Select()", iface->mgr));
14860 : }
14861 :
14862 : void mg_sl_if_free(struct mg_iface *iface) {
14863 : (void) iface;
14864 : }
14865 :
14866 : void mg_sl_if_add_conn(struct mg_connection *nc) {
14867 : (void) nc;
14868 : }
14869 :
14870 : void mg_sl_if_remove_conn(struct mg_connection *nc) {
14871 : (void) nc;
14872 : }
14873 :
14874 : time_t mg_sl_if_poll(struct mg_iface *iface, int timeout_ms) {
14875 : struct mg_mgr *mgr = iface->mgr;
14876 : double now = mg_time();
14877 : double min_timer;
14878 : struct mg_connection *nc, *tmp;
14879 : struct SlTimeval_t tv;
14880 : SlFdSet_t read_set, write_set, err_set;
14881 : sock_t max_fd = INVALID_SOCKET;
14882 : int num_fds, num_ev = 0, num_timers = 0;
14883 :
14884 : SL_SOCKET_FD_ZERO(&read_set);
14885 : SL_SOCKET_FD_ZERO(&write_set);
14886 : SL_SOCKET_FD_ZERO(&err_set);
14887 :
14888 : /*
14889 : * Note: it is ok to have connections with sock == INVALID_SOCKET in the list,
14890 : * e.g. timer-only "connections".
14891 : */
14892 : min_timer = 0;
14893 : for (nc = mgr->active_connections, num_fds = 0; nc != NULL; nc = tmp) {
14894 : tmp = nc->next;
14895 :
14896 : if (nc->sock != INVALID_SOCKET) {
14897 : num_fds++;
14898 :
14899 : if (!(nc->flags & MG_F_WANT_WRITE) &&
14900 : nc->recv_mbuf.len < nc->recv_mbuf_limit &&
14901 : (!(nc->flags & MG_F_UDP) || nc->listener == NULL)) {
14902 : SL_SOCKET_FD_SET(nc->sock, &read_set);
14903 : if (max_fd == INVALID_SOCKET || nc->sock > max_fd) max_fd = nc->sock;
14904 : }
14905 :
14906 : if (((nc->flags & MG_F_CONNECTING) && !(nc->flags & MG_F_WANT_READ)) ||
14907 : (nc->send_mbuf.len > 0 && !(nc->flags & MG_F_CONNECTING))) {
14908 : SL_SOCKET_FD_SET(nc->sock, &write_set);
14909 : SL_SOCKET_FD_SET(nc->sock, &err_set);
14910 : if (max_fd == INVALID_SOCKET || nc->sock > max_fd) max_fd = nc->sock;
14911 : }
14912 : }
14913 :
14914 : if (nc->ev_timer_time > 0) {
14915 : if (num_timers == 0 || nc->ev_timer_time < min_timer) {
14916 : min_timer = nc->ev_timer_time;
14917 : }
14918 : num_timers++;
14919 : }
14920 : }
14921 :
14922 : /*
14923 : * If there is a timer to be fired earlier than the requested timeout,
14924 : * adjust the timeout.
14925 : */
14926 : if (num_timers > 0) {
14927 : double timer_timeout_ms = (min_timer - mg_time()) * 1000 + 1 /* rounding */;
14928 : if (timer_timeout_ms < timeout_ms) {
14929 : timeout_ms = timer_timeout_ms;
14930 : }
14931 : }
14932 : if (timeout_ms < 0) timeout_ms = 0;
14933 :
14934 : tv.tv_sec = timeout_ms / 1000;
14935 : tv.tv_usec = (timeout_ms % 1000) * 1000;
14936 :
14937 : if (num_fds > 0) {
14938 : num_ev = sl_Select((int) max_fd + 1, &read_set, &write_set, &err_set, &tv);
14939 : }
14940 :
14941 : now = mg_time();
14942 : DBG(("sl_Select @ %ld num_ev=%d of %d, timeout=%d", (long) now, num_ev,
14943 : num_fds, timeout_ms));
14944 :
14945 : for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
14946 : int fd_flags = 0;
14947 : if (nc->sock != INVALID_SOCKET) {
14948 : if (num_ev > 0) {
14949 : fd_flags =
14950 : (SL_SOCKET_FD_ISSET(nc->sock, &read_set) &&
14951 : (!(nc->flags & MG_F_UDP) || nc->listener == NULL)
14952 : ? _MG_F_FD_CAN_READ
14953 : : 0) |
14954 : (SL_SOCKET_FD_ISSET(nc->sock, &write_set) ? _MG_F_FD_CAN_WRITE
14955 : : 0) |
14956 : (SL_SOCKET_FD_ISSET(nc->sock, &err_set) ? _MG_F_FD_ERROR : 0);
14957 : }
14958 : /* SimpleLink does not report UDP sockets as writable. */
14959 : if (nc->flags & MG_F_UDP && nc->send_mbuf.len > 0) {
14960 : fd_flags |= _MG_F_FD_CAN_WRITE;
14961 : }
14962 : }
14963 : tmp = nc->next;
14964 : mg_mgr_handle_conn(nc, fd_flags, now);
14965 : }
14966 :
14967 : return now;
14968 : }
14969 :
14970 : void mg_sl_if_get_conn_addr(struct mg_connection *nc, int remote,
14971 : union socket_address *sa) {
14972 : /* SimpleLink does not provide a way to get socket's peer address after
14973 : * accept or connect. Address should have been preserved in the connection,
14974 : * so we do our best here by using it. */
14975 : if (remote) memcpy(sa, &nc->sa, sizeof(*sa));
14976 : }
14977 :
14978 : void sl_restart_cb(struct mg_mgr *mgr) {
14979 : /*
14980 : * SimpleLink has been restarted, meaning all sockets have been invalidated.
14981 : * We try our best - we'll restart the listeners, but for outgoing
14982 : * connections we have no option but to terminate.
14983 : */
14984 : struct mg_connection *nc;
14985 : for (nc = mg_next(mgr, NULL); nc != NULL; nc = mg_next(mgr, nc)) {
14986 : if (nc->sock == INVALID_SOCKET) continue; /* Could be a timer */
14987 : if (nc->flags & MG_F_LISTENING) {
14988 : DBG(("restarting %p %s:%d", nc, inet_ntoa(nc->sa.sin.sin_addr),
14989 : ntohs(nc->sa.sin.sin_port)));
14990 : int res = (nc->flags & MG_F_UDP ? mg_sl_if_listen_udp(nc, &nc->sa)
14991 : : mg_sl_if_listen_tcp(nc, &nc->sa));
14992 : if (res == 0) continue;
14993 : /* Well, we tried and failed. Fall through to closing. */
14994 : }
14995 : nc->sock = INVALID_SOCKET;
14996 : DBG(("terminating %p %s:%d", nc, inet_ntoa(nc->sa.sin.sin_addr),
14997 : ntohs(nc->sa.sin.sin_port)));
14998 : /* TODO(rojer): Outgoing UDP? */
14999 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
15000 : }
15001 : }
15002 :
15003 : /* clang-format off */
15004 : #define MG_SL_IFACE_VTABLE \
15005 : { \
15006 : mg_sl_if_init, \
15007 : mg_sl_if_free, \
15008 : mg_sl_if_add_conn, \
15009 : mg_sl_if_remove_conn, \
15010 : mg_sl_if_poll, \
15011 : mg_sl_if_listen_tcp, \
15012 : mg_sl_if_listen_udp, \
15013 : mg_sl_if_connect_tcp, \
15014 : mg_sl_if_connect_udp, \
15015 : mg_sl_if_tcp_send, \
15016 : mg_sl_if_udp_send, \
15017 : mg_sl_if_tcp_recv, \
15018 : mg_sl_if_udp_recv, \
15019 : mg_sl_if_create_conn, \
15020 : mg_sl_if_destroy_conn, \
15021 : mg_sl_if_sock_set, \
15022 : mg_sl_if_get_conn_addr, \
15023 : }
15024 : /* clang-format on */
15025 :
15026 : const struct mg_iface_vtable mg_simplelink_iface_vtable = MG_SL_IFACE_VTABLE;
15027 : #if MG_NET_IF == MG_NET_IF_SIMPLELINK
15028 : const struct mg_iface_vtable mg_default_iface_vtable = MG_SL_IFACE_VTABLE;
15029 : #endif
15030 :
15031 : #endif /* MG_ENABLE_NET_IF_SIMPLELINK */
15032 : #ifdef MG_MODULE_LINES
15033 : #line 1 "common/platforms/simplelink/sl_ssl_if.c"
15034 : #endif
15035 : /*
15036 : * Copyright (c) 2014-2018 Cesanta Software Limited
15037 : * All rights reserved
15038 : *
15039 : * Licensed under the Apache License, Version 2.0 (the ""License"");
15040 : * you may not use this file except in compliance with the License.
15041 : * You may obtain a copy of the License at
15042 : *
15043 : * http://www.apache.org/licenses/LICENSE-2.0
15044 : *
15045 : * Unless required by applicable law or agreed to in writing, software
15046 : * distributed under the License is distributed on an ""AS IS"" BASIS,
15047 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15048 : * See the License for the specific language governing permissions and
15049 : * limitations under the License.
15050 : */
15051 :
15052 : #if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
15053 :
15054 : /* Amalgamated: #include "common/mg_mem.h" */
15055 :
15056 : #ifndef MG_SSL_IF_SIMPLELINK_SLFS_PREFIX
15057 : #define MG_SSL_IF_SIMPLELINK_SLFS_PREFIX "SL:"
15058 : #endif
15059 :
15060 : #define MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN \
15061 : (sizeof(MG_SSL_IF_SIMPLELINK_SLFS_PREFIX) - 1)
15062 :
15063 : struct mg_ssl_if_ctx {
15064 : char *ssl_cert;
15065 : char *ssl_key;
15066 : char *ssl_ca_cert;
15067 : char *ssl_server_name;
15068 : };
15069 :
15070 : void mg_ssl_if_init() {
15071 : }
15072 :
15073 : enum mg_ssl_if_result mg_ssl_if_conn_init(
15074 : struct mg_connection *nc, const struct mg_ssl_if_conn_params *params,
15075 : const char **err_msg) {
15076 : struct mg_ssl_if_ctx *ctx =
15077 : (struct mg_ssl_if_ctx *) MG_CALLOC(1, sizeof(*ctx));
15078 : if (ctx == NULL) {
15079 : MG_SET_PTRPTR(err_msg, "Out of memory");
15080 : return MG_SSL_ERROR;
15081 : }
15082 : nc->ssl_if_data = ctx;
15083 :
15084 : if (params->cert != NULL || params->key != NULL) {
15085 : if (params->cert != NULL && params->key != NULL) {
15086 : ctx->ssl_cert = strdup(params->cert);
15087 : ctx->ssl_key = strdup(params->key);
15088 : } else {
15089 : MG_SET_PTRPTR(err_msg, "Both cert and key are required.");
15090 : return MG_SSL_ERROR;
15091 : }
15092 : }
15093 : if (params->ca_cert != NULL && strcmp(params->ca_cert, "*") != 0) {
15094 : ctx->ssl_ca_cert = strdup(params->ca_cert);
15095 : }
15096 : /* TODO(rojer): cipher_suites. */
15097 : if (params->server_name != NULL) {
15098 : ctx->ssl_server_name = strdup(params->server_name);
15099 : }
15100 : return MG_SSL_OK;
15101 : }
15102 :
15103 : enum mg_ssl_if_result mg_ssl_if_conn_accept(struct mg_connection *nc,
15104 : struct mg_connection *lc) {
15105 : /* SimpleLink does everything for us, nothing for us to do. */
15106 : (void) nc;
15107 : (void) lc;
15108 : return MG_SSL_OK;
15109 : }
15110 :
15111 : enum mg_ssl_if_result mg_ssl_if_handshake(struct mg_connection *nc) {
15112 : /* SimpleLink has already performed the handshake, nothing to do. */
15113 : return MG_SSL_OK;
15114 : }
15115 :
15116 : int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t len) {
15117 : /* SimpelLink handles TLS, so this is just a pass-through. */
15118 : int n = nc->iface->vtable->tcp_recv(nc, buf, len);
15119 : if (n == 0) nc->flags |= MG_F_WANT_READ;
15120 : return n;
15121 : }
15122 :
15123 : int mg_ssl_if_write(struct mg_connection *nc, const void *buf, size_t len) {
15124 : /* SimpelLink handles TLS, so this is just a pass-through. */
15125 : return nc->iface->vtable->tcp_send(nc, buf, len);
15126 : }
15127 :
15128 : void mg_ssl_if_conn_close_notify(struct mg_connection *nc) {
15129 : /* Nothing to do */
15130 : (void) nc;
15131 : }
15132 :
15133 : void mg_ssl_if_conn_free(struct mg_connection *nc) {
15134 : struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
15135 : if (ctx == NULL) return;
15136 : nc->ssl_if_data = NULL;
15137 : MG_FREE(ctx->ssl_cert);
15138 : MG_FREE(ctx->ssl_key);
15139 : MG_FREE(ctx->ssl_ca_cert);
15140 : MG_FREE(ctx->ssl_server_name);
15141 : memset(ctx, 0, sizeof(*ctx));
15142 : MG_FREE(ctx);
15143 : }
15144 :
15145 : bool pem_to_der(const char *pem_file, const char *der_file) {
15146 : bool ret = false;
15147 : FILE *pf = NULL, *df = NULL;
15148 : bool writing = false;
15149 : pf = fopen(pem_file, "r");
15150 : if (pf == NULL) goto clean;
15151 : remove(der_file);
15152 : fs_slfs_set_file_size(der_file + MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN, 2048);
15153 : df = fopen(der_file, "w");
15154 : fs_slfs_unset_file_flags(der_file + MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN);
15155 : if (df == NULL) goto clean;
15156 : while (1) {
15157 : char pem_buf[70];
15158 : char der_buf[48];
15159 : if (!fgets(pem_buf, sizeof(pem_buf), pf)) break;
15160 : if (writing) {
15161 : if (strstr(pem_buf, "-----END ") != NULL) {
15162 : ret = true;
15163 : break;
15164 : }
15165 : int l = 0;
15166 : while (!isspace((unsigned int) pem_buf[l])) l++;
15167 : int der_len = 0;
15168 : cs_base64_decode((const unsigned char *) pem_buf, sizeof(pem_buf),
15169 : der_buf, &der_len);
15170 : if (der_len <= 0) break;
15171 : if (fwrite(der_buf, 1, der_len, df) != der_len) break;
15172 : } else if (strstr(pem_buf, "-----BEGIN ") != NULL) {
15173 : writing = true;
15174 : }
15175 : }
15176 :
15177 : clean:
15178 : if (pf != NULL) fclose(pf);
15179 : if (df != NULL) {
15180 : fclose(df);
15181 : if (!ret) remove(der_file);
15182 : }
15183 : return ret;
15184 : }
15185 :
15186 : #if MG_ENABLE_FILESYSTEM && defined(MG_FS_SLFS)
15187 : /* If the file's extension is .pem, convert it to DER format and put on SLFS. */
15188 : static char *sl_pem2der(const char *pem_file) {
15189 : const char *pem_ext = strstr(pem_file, ".pem");
15190 : if (pem_ext == NULL || *(pem_ext + 4) != '\0') {
15191 : return strdup(pem_file);
15192 : }
15193 : char *der_file = NULL;
15194 : /* DER file must be located on SLFS, add prefix. */
15195 : int l = mg_asprintf(&der_file, 0, MG_SSL_IF_SIMPLELINK_SLFS_PREFIX "%.*s.der",
15196 : (int) (pem_ext - pem_file), pem_file);
15197 : if (der_file == NULL) return NULL;
15198 : bool result = false;
15199 : cs_stat_t st;
15200 : if (mg_stat(der_file, &st) != 0) {
15201 : result = pem_to_der(pem_file, der_file);
15202 : LOG(LL_DEBUG, ("%s -> %s = %d", pem_file, der_file, result));
15203 : } else {
15204 : /* File exists, assume it's already been converted. */
15205 : result = true;
15206 : }
15207 : if (result) {
15208 : /* Strip the SL: prefix we added since NWP does not expect it. */
15209 : memmove(der_file, der_file + MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN,
15210 : l - 2 /* including \0 */);
15211 : } else {
15212 : MG_FREE(der_file);
15213 : der_file = NULL;
15214 : }
15215 : return der_file;
15216 : }
15217 : #else
15218 : static char *sl_pem2der(const char *pem_file) {
15219 : return strdup(pem_file);
15220 : }
15221 : #endif
15222 :
15223 : int sl_set_ssl_opts(int sock, struct mg_connection *nc) {
15224 : int err;
15225 : const struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
15226 : DBG(("%p ssl ctx: %p", nc, ctx));
15227 :
15228 : if (ctx == NULL) return 0;
15229 : DBG(("%p %s,%s,%s,%s", nc, (ctx->ssl_cert ? ctx->ssl_cert : "-"),
15230 : (ctx->ssl_key ? ctx->ssl_cert : "-"),
15231 : (ctx->ssl_ca_cert ? ctx->ssl_ca_cert : "-"),
15232 : (ctx->ssl_server_name ? ctx->ssl_server_name : "-")));
15233 : if (ctx->ssl_cert != NULL && ctx->ssl_key != NULL) {
15234 : char *ssl_cert = sl_pem2der(ctx->ssl_cert), *ssl_key = NULL;
15235 : if (ssl_cert != NULL) {
15236 : err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
15237 : SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME, ssl_cert,
15238 : strlen(ssl_cert));
15239 : MG_FREE(ssl_cert);
15240 : LOG(LL_DEBUG, ("CERTIFICATE_FILE_NAME %s -> %d", ssl_cert, err));
15241 : ssl_key = sl_pem2der(ctx->ssl_key);
15242 : if (ssl_key != NULL) {
15243 : err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
15244 : SL_SO_SECURE_FILES_PRIVATE_KEY_FILE_NAME, ssl_key,
15245 : strlen(ssl_key));
15246 : MG_FREE(ssl_key);
15247 : LOG(LL_DEBUG, ("PRIVATE_KEY_FILE_NAME %s -> %d", ssl_key, err));
15248 : } else {
15249 : err = -1;
15250 : }
15251 : } else {
15252 : err = -1;
15253 : }
15254 : if (err != 0) return err;
15255 : }
15256 : if (ctx->ssl_ca_cert != NULL) {
15257 : if (ctx->ssl_ca_cert[0] != '\0') {
15258 : char *ssl_ca_cert = sl_pem2der(ctx->ssl_ca_cert);
15259 : if (ssl_ca_cert != NULL) {
15260 : err =
15261 : sl_SetSockOpt(sock, SL_SOL_SOCKET, SL_SO_SECURE_FILES_CA_FILE_NAME,
15262 : ssl_ca_cert, strlen(ssl_ca_cert));
15263 : LOG(LL_DEBUG, ("CA_FILE_NAME %s -> %d", ssl_ca_cert, err));
15264 : } else {
15265 : err = -1;
15266 : }
15267 : MG_FREE(ssl_ca_cert);
15268 : if (err != 0) return err;
15269 : }
15270 : }
15271 : if (ctx->ssl_server_name != NULL) {
15272 : err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
15273 : SL_SO_SECURE_DOMAIN_NAME_VERIFICATION,
15274 : ctx->ssl_server_name, strlen(ctx->ssl_server_name));
15275 : DBG(("DOMAIN_NAME_VERIFICATION %s -> %d", ctx->ssl_server_name, err));
15276 : /* Domain name verificationw as added in a NWP service pack, older
15277 : * versions return SL_ERROR_BSD_ENOPROTOOPT. There isn't much we can do
15278 : * about it,
15279 : * so we ignore the error. */
15280 : if (err != 0 && err != SL_ERROR_BSD_ENOPROTOOPT) return err;
15281 : }
15282 : return 0;
15283 : }
15284 :
15285 : #endif /* MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK */
15286 : #ifdef MG_MODULE_LINES
15287 : #line 1 "common/platforms/lwip/mg_lwip_net_if.h"
15288 : #endif
15289 : /*
15290 : * Copyright (c) 2014-2018 Cesanta Software Limited
15291 : * All rights reserved
15292 : *
15293 : * Licensed under the Apache License, Version 2.0 (the ""License"");
15294 : * you may not use this file except in compliance with the License.
15295 : * You may obtain a copy of the License at
15296 : *
15297 : * http://www.apache.org/licenses/LICENSE-2.0
15298 : *
15299 : * Unless required by applicable law or agreed to in writing, software
15300 : * distributed under the License is distributed on an ""AS IS"" BASIS,
15301 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15302 : * See the License for the specific language governing permissions and
15303 : * limitations under the License.
15304 : */
15305 :
15306 : #ifndef CS_COMMON_PLATFORMS_LWIP_MG_NET_IF_LWIP_H_
15307 : #define CS_COMMON_PLATFORMS_LWIP_MG_NET_IF_LWIP_H_
15308 :
15309 : #ifndef MG_ENABLE_NET_IF_LWIP_LOW_LEVEL
15310 : #define MG_ENABLE_NET_IF_LWIP_LOW_LEVEL MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL
15311 : #endif
15312 :
15313 : #if MG_ENABLE_NET_IF_LWIP_LOW_LEVEL
15314 :
15315 : #include <stdint.h>
15316 :
15317 : extern const struct mg_iface_vtable mg_lwip_iface_vtable;
15318 :
15319 : struct mg_lwip_conn_state {
15320 : struct mg_connection *nc;
15321 : struct mg_connection *lc;
15322 : union {
15323 : struct tcp_pcb *tcp;
15324 : struct udp_pcb *udp;
15325 : } pcb;
15326 : err_t err;
15327 : size_t num_sent; /* Number of acknowledged bytes to be reported to the core */
15328 : struct pbuf *rx_chain; /* Chain of incoming data segments. */
15329 : size_t rx_offset; /* Offset within the first pbuf (if partially consumed) */
15330 : /* Last SSL write size, for retries. */
15331 : int last_ssl_write_size;
15332 : /* Whether MG_SIG_RECV is already pending for this connection */
15333 : int recv_pending;
15334 : /* Whether the connection is about to close, just `rx_chain` needs to drain */
15335 : int draining_rx_chain;
15336 : };
15337 :
15338 : enum mg_sig_type {
15339 : MG_SIG_CONNECT_RESULT = 1,
15340 : MG_SIG_RECV = 2,
15341 : MG_SIG_CLOSE_CONN = 3,
15342 : MG_SIG_TOMBSTONE = 4,
15343 : MG_SIG_ACCEPT = 5,
15344 : };
15345 :
15346 : void mg_lwip_post_signal(enum mg_sig_type sig, struct mg_connection *nc);
15347 :
15348 : /* To be implemented by the platform. */
15349 : void mg_lwip_mgr_schedule_poll(struct mg_mgr *mgr);
15350 :
15351 : #endif /* MG_ENABLE_NET_IF_LWIP_LOW_LEVEL */
15352 :
15353 : #endif /* CS_COMMON_PLATFORMS_LWIP_MG_NET_IF_LWIP_H_ */
15354 : #ifdef MG_MODULE_LINES
15355 : #line 1 "common/platforms/lwip/mg_lwip_net_if.c"
15356 : #endif
15357 : /*
15358 : * Copyright (c) 2014-2018 Cesanta Software Limited
15359 : * All rights reserved
15360 : *
15361 : * Licensed under the Apache License, Version 2.0 (the ""License"");
15362 : * you may not use this file except in compliance with the License.
15363 : * You may obtain a copy of the License at
15364 : *
15365 : * http://www.apache.org/licenses/LICENSE-2.0
15366 : *
15367 : * Unless required by applicable law or agreed to in writing, software
15368 : * distributed under the License is distributed on an ""AS IS"" BASIS,
15369 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15370 : * See the License for the specific language governing permissions and
15371 : * limitations under the License.
15372 : */
15373 :
15374 : #if MG_ENABLE_NET_IF_LWIP_LOW_LEVEL
15375 :
15376 : /* Amalgamated: #include "common/mg_mem.h" */
15377 :
15378 : #include <lwip/init.h>
15379 : #include <lwip/pbuf.h>
15380 : #include <lwip/tcp.h>
15381 : #include <lwip/tcpip.h>
15382 : #if ((LWIP_VERSION_MAJOR << 8) | LWIP_VERSION_MINOR) >= 0x0105
15383 : #include <lwip/priv/tcp_priv.h> /* For tcp_seg */
15384 : #include <lwip/priv/tcpip_priv.h> /* For tcpip_api_call */
15385 : #else
15386 : #include <lwip/tcp_impl.h>
15387 : #endif
15388 : #include <lwip/udp.h>
15389 :
15390 : /* Amalgamated: #include "common/cs_dbg.h" */
15391 :
15392 : /*
15393 : * Newest versions of LWIP have ip_2_ip4, older have ipX_2_ip,
15394 : * even older have nothing.
15395 : */
15396 : #ifndef ip_2_ip4
15397 : #ifdef ipX_2_ip
15398 : #define ip_2_ip4(addr) ipX_2_ip(addr)
15399 : #else
15400 : #define ip_2_ip4(addr) (addr)
15401 : #endif
15402 : #endif
15403 :
15404 : /*
15405 : * Depending on whether Mongoose is compiled with ipv6 support, use right
15406 : * lwip functions
15407 : */
15408 : #if MG_ENABLE_IPV6
15409 : #define TCP_NEW tcp_new_ip6
15410 : #define TCP_BIND tcp_bind_ip6
15411 : #define UDP_BIND udp_bind_ip6
15412 : #define IPADDR_NTOA(x) ip6addr_ntoa((const ip6_addr_t *)(x))
15413 : #define SET_ADDR(dst, src) \
15414 : memcpy((dst)->sin6.sin6_addr.s6_addr, (src)->ip6.addr, \
15415 : sizeof((dst)->sin6.sin6_addr.s6_addr))
15416 : #else
15417 : #define TCP_NEW tcp_new
15418 : #define TCP_BIND tcp_bind
15419 : #define UDP_BIND udp_bind
15420 : #define IPADDR_NTOA ipaddr_ntoa
15421 : #define SET_ADDR(dst, src) (dst)->sin.sin_addr.s_addr = ip_2_ip4(src)->addr
15422 : #endif
15423 :
15424 : #if !NO_SYS
15425 : #if LWIP_TCPIP_CORE_LOCKING
15426 : /* With locking tcpip_api_call is just a function call wrapped in lock/unlock,
15427 : * so we can get away with just casting. */
15428 : void mg_lwip_netif_run_on_tcpip(void (*fn)(void *), void *arg) {
15429 : tcpip_api_call((tcpip_api_call_fn) fn, (struct tcpip_api_call_data *) arg);
15430 : }
15431 : #else
15432 : static sys_sem_t s_tcpip_call_lock_sem = NULL;
15433 : static sys_sem_t s_tcpip_call_sync_sem = NULL;
15434 : struct mg_lwip_netif_tcpip_call_ctx {
15435 : void (*fn)(void *);
15436 : void *arg;
15437 : };
15438 : static void xxx_tcpip(void *arg) {
15439 : struct mg_lwip_netif_tcpip_call_ctx *ctx =
15440 : (struct mg_lwip_netif_tcpip_call_ctx *) arg;
15441 : ctx->fn(ctx->arg);
15442 : sys_sem_signal(&s_tcpip_call_sync_sem);
15443 : }
15444 : void mg_lwip_netif_run_on_tcpip(void (*fn)(void *), void *arg) {
15445 : struct mg_lwip_netif_tcpip_call_ctx ctx = {.fn = fn, .arg = arg};
15446 : sys_arch_sem_wait(&s_tcpip_call_lock_sem, 0);
15447 : tcpip_send_msg_wait_sem(xxx_tcpip, &ctx, &s_tcpip_call_sync_sem);
15448 : sys_sem_signal(&s_tcpip_call_lock_sem);
15449 : }
15450 : #endif
15451 : #else
15452 : #define mg_lwip_netif_run_on_tcpip(fn, arg) (fn)(arg)
15453 : #endif
15454 :
15455 : void mg_lwip_if_init(struct mg_iface *iface);
15456 : void mg_lwip_if_free(struct mg_iface *iface);
15457 : void mg_lwip_if_add_conn(struct mg_connection *nc);
15458 : void mg_lwip_if_remove_conn(struct mg_connection *nc);
15459 : time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms);
15460 :
15461 : // If compiling for Mongoose OS.
15462 : #ifdef MGOS
15463 : extern void mgos_lock();
15464 : extern void mgos_unlock();
15465 : #else
15466 : #define mgos_lock()
15467 : #define mgos_unlock()
15468 : #endif
15469 :
15470 : static void mg_lwip_recv_common(struct mg_connection *nc, struct pbuf *p);
15471 :
15472 : #if LWIP_TCP_KEEPALIVE
15473 : void mg_lwip_set_keepalive_params(struct mg_connection *nc, int idle,
15474 : int interval, int count) {
15475 : if (nc->sock == INVALID_SOCKET || nc->flags & MG_F_UDP) {
15476 : return;
15477 : }
15478 : struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15479 : struct tcp_pcb *tpcb = cs->pcb.tcp;
15480 : if (idle > 0 && interval > 0 && count > 0) {
15481 : tpcb->keep_idle = idle * 1000;
15482 : tpcb->keep_intvl = interval * 1000;
15483 : tpcb->keep_cnt = count;
15484 : tpcb->so_options |= SOF_KEEPALIVE;
15485 : } else {
15486 : tpcb->so_options &= ~SOF_KEEPALIVE;
15487 : }
15488 : }
15489 : #elif !defined(MG_NO_LWIP_TCP_KEEPALIVE)
15490 : #warning LWIP TCP keepalive is disabled. Please consider enabling it.
15491 : #endif /* LWIP_TCP_KEEPALIVE */
15492 :
15493 : static err_t mg_lwip_tcp_conn_cb(void *arg, struct tcp_pcb *tpcb, err_t err) {
15494 : struct mg_connection *nc = (struct mg_connection *) arg;
15495 : DBG(("%p connect to %s:%u = %d", nc, IPADDR_NTOA(ipX_2_ip(&tpcb->remote_ip)),
15496 : tpcb->remote_port, err));
15497 : if (nc == NULL) {
15498 : tcp_abort(tpcb);
15499 : return ERR_ARG;
15500 : }
15501 : struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15502 : cs->err = err;
15503 : #if LWIP_TCP_KEEPALIVE
15504 : if (err == 0) mg_lwip_set_keepalive_params(nc, 60, 10, 6);
15505 : #endif
15506 : mg_lwip_post_signal(MG_SIG_CONNECT_RESULT, nc);
15507 : return ERR_OK;
15508 : }
15509 :
15510 : static void mg_lwip_tcp_error_cb(void *arg, err_t err) {
15511 : struct mg_connection *nc = (struct mg_connection *) arg;
15512 : DBG(("%p conn error %d", nc, err));
15513 : if (nc == NULL || (nc->flags & MG_F_CLOSE_IMMEDIATELY)) return;
15514 : struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15515 : cs->pcb.tcp = NULL; /* Has already been deallocated */
15516 : if (nc->flags & MG_F_CONNECTING) {
15517 : cs->err = err;
15518 : mg_lwip_post_signal(MG_SIG_CONNECT_RESULT, nc);
15519 : } else {
15520 : mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
15521 : }
15522 : }
15523 :
15524 : static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb,
15525 : struct pbuf *p, err_t err) {
15526 : struct mg_connection *nc = (struct mg_connection *) arg;
15527 : struct mg_lwip_conn_state *cs =
15528 : (nc ? (struct mg_lwip_conn_state *) nc->sock : NULL);
15529 : DBG(("%p %p %p %p %u %d", nc, cs, tpcb, p, (p != NULL ? p->tot_len : 0),
15530 : err));
15531 : if (p == NULL) {
15532 : if (nc != NULL && !(nc->flags & MG_F_CLOSE_IMMEDIATELY)) {
15533 : if (cs->rx_chain != NULL) {
15534 : /*
15535 : * rx_chain still contains non-consumed data, don't close the
15536 : * connection
15537 : */
15538 : cs->draining_rx_chain = 1;
15539 : } else {
15540 : mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
15541 : }
15542 : } else {
15543 : /* Tombstoned connection, do nothing. */
15544 : }
15545 : return ERR_OK;
15546 : } else if (nc == NULL) {
15547 : tcp_abort(tpcb);
15548 : return ERR_ARG;
15549 : }
15550 : /*
15551 : * If we get a chain of more than one segment at once, we need to bump
15552 : * refcount on the subsequent bufs to make them independent.
15553 : */
15554 : if (p->next != NULL) {
15555 : struct pbuf *q = p->next;
15556 : for (; q != NULL; q = q->next) pbuf_ref(q);
15557 : }
15558 : mgos_lock();
15559 : if (cs->rx_chain == NULL) {
15560 : cs->rx_offset = 0;
15561 : } else if (pbuf_clen(cs->rx_chain) >= 4) {
15562 : /* ESP SDK has a limited pool of 5 pbufs. We must not hog them all or RX
15563 : * will be completely blocked. We already have at least 4 in the chain,
15564 : * this one is the last, so we have to make a copy and release this one. */
15565 : struct pbuf *np = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
15566 : if (np != NULL) {
15567 : pbuf_copy(np, p);
15568 : pbuf_free(p);
15569 : p = np;
15570 : }
15571 : }
15572 : mg_lwip_recv_common(nc, p);
15573 : mgos_unlock();
15574 : (void) err;
15575 : return ERR_OK;
15576 : }
15577 :
15578 : static err_t mg_lwip_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb,
15579 : u16_t num_sent) {
15580 : struct mg_connection *nc = (struct mg_connection *) arg;
15581 : DBG(("%p %p %u %p %p", nc, tpcb, num_sent, tpcb->unsent, tpcb->unacked));
15582 : if (nc == NULL) return ERR_OK;
15583 : if ((nc->flags & MG_F_SEND_AND_CLOSE) && !(nc->flags & MG_F_WANT_WRITE) &&
15584 : nc->send_mbuf.len == 0 && tpcb->unsent == NULL && tpcb->unacked == NULL) {
15585 : mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
15586 : }
15587 : if (nc->send_mbuf.len > 0 || (nc->flags & MG_F_WANT_WRITE)) {
15588 : mg_lwip_mgr_schedule_poll(nc->mgr);
15589 : }
15590 : (void) num_sent;
15591 : return ERR_OK;
15592 : }
15593 :
15594 : struct mg_lwip_if_connect_tcp_ctx {
15595 : struct mg_connection *nc;
15596 : const union socket_address *sa;
15597 : };
15598 :
15599 : static void mg_lwip_if_connect_tcp_tcpip(void *arg) {
15600 : struct mg_lwip_if_connect_tcp_ctx *ctx =
15601 : (struct mg_lwip_if_connect_tcp_ctx *) arg;
15602 : struct mg_connection *nc = ctx->nc;
15603 : const union socket_address *sa = ctx->sa;
15604 :
15605 : struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15606 : struct tcp_pcb *tpcb = TCP_NEW();
15607 : cs->pcb.tcp = tpcb;
15608 : ip_addr_t *ip = (ip_addr_t *) &sa->sin.sin_addr.s_addr;
15609 : u16_t port = ntohs(sa->sin.sin_port);
15610 : tcp_arg(tpcb, nc);
15611 : tcp_err(tpcb, mg_lwip_tcp_error_cb);
15612 : tcp_sent(tpcb, mg_lwip_tcp_sent_cb);
15613 : tcp_recv(tpcb, mg_lwip_tcp_recv_cb);
15614 : cs->err = TCP_BIND(tpcb, IP_ADDR_ANY, 0 /* any port */);
15615 : DBG(("%p tcp_bind = %d", nc, cs->err));
15616 : if (cs->err != ERR_OK) {
15617 : mg_lwip_post_signal(MG_SIG_CONNECT_RESULT, nc);
15618 : return;
15619 : }
15620 : cs->err = tcp_connect(tpcb, ip, port, mg_lwip_tcp_conn_cb);
15621 : DBG(("%p tcp_connect %p = %d", nc, tpcb, cs->err));
15622 : if (cs->err != ERR_OK) {
15623 : mg_lwip_post_signal(MG_SIG_CONNECT_RESULT, nc);
15624 : return;
15625 : }
15626 : }
15627 :
15628 : void mg_lwip_if_connect_tcp(struct mg_connection *nc,
15629 : const union socket_address *sa) {
15630 : struct mg_lwip_if_connect_tcp_ctx ctx = {.nc = nc, .sa = sa};
15631 : mg_lwip_netif_run_on_tcpip(mg_lwip_if_connect_tcp_tcpip, &ctx);
15632 : }
15633 :
15634 : /*
15635 : * Lwip included in the SDKs for nRF5x chips has different type for the
15636 : * callback of `udp_recv()`
15637 : */
15638 : #if ((LWIP_VERSION_MAJOR << 8) | LWIP_VERSION_MINOR) >= 0x0105
15639 : static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p,
15640 : const ip_addr_t *addr, u16_t port)
15641 : #else
15642 : static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p,
15643 : ip_addr_t *addr, u16_t port)
15644 : #endif
15645 : {
15646 : struct mg_connection *nc = (struct mg_connection *) arg;
15647 : DBG(("%p %s:%u %p %u %u", nc, IPADDR_NTOA(addr), port, p, p->ref, p->len));
15648 : /* Put address in a separate pbuf and tack it onto the packet. */
15649 : struct pbuf *sap =
15650 : pbuf_alloc(PBUF_RAW, sizeof(union socket_address), PBUF_RAM);
15651 : if (sap == NULL) {
15652 : pbuf_free(p);
15653 : return;
15654 : }
15655 : union socket_address *sa = (union socket_address *) sap->payload;
15656 : #if ((LWIP_VERSION_MAJOR << 8) | LWIP_VERSION_MINOR) >= 0x0105
15657 : sa->sin.sin_addr.s_addr = ip_2_ip4(addr)->addr;
15658 : #else
15659 : sa->sin.sin_addr.s_addr = addr->addr;
15660 : #endif
15661 : sa->sin.sin_port = htons(port);
15662 : /* Logic in the recv handler requires that there be exactly one data pbuf. */
15663 : p = pbuf_coalesce(p, PBUF_RAW);
15664 : pbuf_chain(sap, p);
15665 : mgos_lock();
15666 : mg_lwip_recv_common(nc, sap);
15667 : mgos_unlock();
15668 : (void) pcb;
15669 : }
15670 :
15671 : static void mg_lwip_recv_common(struct mg_connection *nc, struct pbuf *p) {
15672 : struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15673 : if (cs->rx_chain == NULL) {
15674 : cs->rx_chain = p;
15675 : } else {
15676 : pbuf_chain(cs->rx_chain, p);
15677 : }
15678 : if (!cs->recv_pending) {
15679 : cs->recv_pending = 1;
15680 : mg_lwip_post_signal(MG_SIG_RECV, nc);
15681 : }
15682 : }
15683 :
15684 : static int mg_lwip_if_udp_recv(struct mg_connection *nc, void *buf, size_t len,
15685 : union socket_address *sa, size_t *sa_len) {
15686 : /*
15687 : * For UDP, RX chain consists of interleaved address and packet bufs:
15688 : * Address pbuf followed by exactly one data pbuf (recv_cb took care of that).
15689 : */
15690 : int res = 0;
15691 : struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15692 : if (nc->sock == INVALID_SOCKET) return -1;
15693 : mgos_lock();
15694 : if (cs->rx_chain != NULL) {
15695 : struct pbuf *ap = cs->rx_chain;
15696 : struct pbuf *dp = ap->next;
15697 : cs->rx_chain = pbuf_dechain(dp);
15698 : res = MIN(dp->len, len);
15699 : pbuf_copy_partial(dp, buf, res, 0);
15700 : pbuf_free(dp);
15701 : pbuf_copy_partial(ap, sa, MIN(*sa_len, ap->len), 0);
15702 : pbuf_free(ap);
15703 : }
15704 : mgos_unlock();
15705 : return res;
15706 : }
15707 :
15708 : static void mg_lwip_if_connect_udp_tcpip(void *arg) {
15709 : struct mg_connection *nc = (struct mg_connection *) arg;
15710 : struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15711 : struct udp_pcb *upcb = udp_new();
15712 : cs->err = UDP_BIND(upcb, IP_ADDR_ANY, 0 /* any port */);
15713 : DBG(("%p udp_bind %p = %d", nc, upcb, cs->err));
15714 : if (cs->err == ERR_OK) {
15715 : udp_recv(upcb, mg_lwip_udp_recv_cb, nc);
15716 : cs->pcb.udp = upcb;
15717 : } else {
15718 : udp_remove(upcb);
15719 : }
15720 : mg_lwip_post_signal(MG_SIG_CONNECT_RESULT, nc);
15721 : }
15722 :
15723 : void mg_lwip_if_connect_udp(struct mg_connection *nc) {
15724 : mg_lwip_netif_run_on_tcpip(mg_lwip_if_connect_udp_tcpip, nc);
15725 : }
15726 :
15727 : static void tcp_close_tcpip(void *arg) {
15728 : tcp_close((struct tcp_pcb *) arg);
15729 : }
15730 :
15731 : void mg_lwip_handle_accept(struct mg_connection *nc) {
15732 : struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15733 : if (cs->pcb.tcp == NULL) return;
15734 : union socket_address sa;
15735 : struct tcp_pcb *tpcb = cs->pcb.tcp;
15736 : SET_ADDR(&sa, &tpcb->remote_ip);
15737 : sa.sin.sin_port = htons(tpcb->remote_port);
15738 : mg_if_accept_tcp_cb(nc, &sa, sizeof(sa.sin));
15739 : }
15740 :
15741 : static err_t mg_lwip_accept_cb(void *arg, struct tcp_pcb *newtpcb, err_t err) {
15742 : struct mg_connection *lc = (struct mg_connection *) arg, *nc;
15743 : struct mg_lwip_conn_state *lcs, *cs;
15744 : struct tcp_pcb_listen *lpcb;
15745 : LOG(LL_DEBUG,
15746 : ("%p conn %p from %s:%u", lc, newtpcb,
15747 : IPADDR_NTOA(ipX_2_ip(&newtpcb->remote_ip)), newtpcb->remote_port));
15748 : if (lc == NULL) {
15749 : tcp_abort(newtpcb);
15750 : return ERR_ABRT;
15751 : }
15752 : lcs = (struct mg_lwip_conn_state *) lc->sock;
15753 : lpcb = (struct tcp_pcb_listen *) lcs->pcb.tcp;
15754 : #if TCP_LISTEN_BACKLOG
15755 : tcp_accepted(lpcb);
15756 : #endif
15757 : nc = mg_if_accept_new_conn(lc);
15758 : if (nc == NULL) {
15759 : tcp_abort(newtpcb);
15760 : return ERR_ABRT;
15761 : }
15762 : cs = (struct mg_lwip_conn_state *) nc->sock;
15763 : cs->lc = lc;
15764 : cs->pcb.tcp = newtpcb;
15765 : /* We need to set up callbacks before returning because data may start
15766 : * arriving immediately. */
15767 : tcp_arg(newtpcb, nc);
15768 : tcp_err(newtpcb, mg_lwip_tcp_error_cb);
15769 : tcp_sent(newtpcb, mg_lwip_tcp_sent_cb);
15770 : tcp_recv(newtpcb, mg_lwip_tcp_recv_cb);
15771 : #if LWIP_TCP_KEEPALIVE
15772 : mg_lwip_set_keepalive_params(nc, 60, 10, 6);
15773 : #endif
15774 : mg_lwip_post_signal(MG_SIG_ACCEPT, nc);
15775 : (void) err;
15776 : (void) lpcb;
15777 : return ERR_OK;
15778 : }
15779 :
15780 : struct mg_lwip_if_listen_ctx {
15781 : struct mg_connection *nc;
15782 : union socket_address *sa;
15783 : int ret;
15784 : };
15785 :
15786 : static void mg_lwip_if_listen_tcp_tcpip(void *arg) {
15787 : struct mg_lwip_if_listen_ctx *ctx = (struct mg_lwip_if_listen_ctx *) arg;
15788 : struct mg_connection *nc = ctx->nc;
15789 : union socket_address *sa = ctx->sa;
15790 : struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15791 : struct tcp_pcb *tpcb = TCP_NEW();
15792 : ip_addr_t *ip = (ip_addr_t *) &sa->sin.sin_addr.s_addr;
15793 : u16_t port = ntohs(sa->sin.sin_port);
15794 : cs->err = TCP_BIND(tpcb, ip, port);
15795 : DBG(("%p tcp_bind(%s:%u) = %d", nc, IPADDR_NTOA(ip), port, cs->err));
15796 : if (cs->err != ERR_OK) {
15797 : tcp_close(tpcb);
15798 : ctx->ret = -1;
15799 : return;
15800 : }
15801 : tcp_arg(tpcb, nc);
15802 : tpcb = tcp_listen(tpcb);
15803 : cs->pcb.tcp = tpcb;
15804 : tcp_accept(tpcb, mg_lwip_accept_cb);
15805 : ctx->ret = 0;
15806 : }
15807 :
15808 : int mg_lwip_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) {
15809 : struct mg_lwip_if_listen_ctx ctx = {.nc = nc, .sa = sa};
15810 : mg_lwip_netif_run_on_tcpip(mg_lwip_if_listen_tcp_tcpip, &ctx);
15811 : return ctx.ret;
15812 : }
15813 :
15814 : static void mg_lwip_if_listen_udp_tcpip(void *arg) {
15815 : struct mg_lwip_if_listen_ctx *ctx = (struct mg_lwip_if_listen_ctx *) arg;
15816 : struct mg_connection *nc = ctx->nc;
15817 : union socket_address *sa = ctx->sa;
15818 : struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15819 : struct udp_pcb *upcb = udp_new();
15820 : ip_addr_t *ip = (ip_addr_t *) &sa->sin.sin_addr.s_addr;
15821 : u16_t port = ntohs(sa->sin.sin_port);
15822 : cs->err = UDP_BIND(upcb, ip, port);
15823 : DBG(("%p udb_bind(%s:%u) = %d", nc, IPADDR_NTOA(ip), port, cs->err));
15824 : if (cs->err != ERR_OK) {
15825 : udp_remove(upcb);
15826 : ctx->ret = -1;
15827 : } else {
15828 : udp_recv(upcb, mg_lwip_udp_recv_cb, nc);
15829 : cs->pcb.udp = upcb;
15830 : ctx->ret = 0;
15831 : }
15832 : }
15833 :
15834 : int mg_lwip_if_listen_udp(struct mg_connection *nc, union socket_address *sa) {
15835 : struct mg_lwip_if_listen_ctx ctx = {.nc = nc, .sa = sa};
15836 : mg_lwip_netif_run_on_tcpip(mg_lwip_if_listen_udp_tcpip, &ctx);
15837 : return ctx.ret;
15838 : }
15839 :
15840 : struct mg_lwip_tcp_write_ctx {
15841 : struct mg_connection *nc;
15842 : const void *data;
15843 : uint16_t len;
15844 : int ret;
15845 : };
15846 :
15847 : static void tcp_output_tcpip(void *arg) {
15848 : tcp_output((struct tcp_pcb *) arg);
15849 : }
15850 :
15851 : static void mg_lwip_tcp_write_tcpip(void *arg) {
15852 : struct mg_lwip_tcp_write_ctx *ctx = (struct mg_lwip_tcp_write_ctx *) arg;
15853 : struct mg_connection *nc = ctx->nc;
15854 : struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15855 : struct tcp_pcb *tpcb = cs->pcb.tcp;
15856 : size_t len = MIN(tpcb->mss, MIN(ctx->len, tpcb->snd_buf));
15857 : size_t unsent, unacked;
15858 : if (len == 0) {
15859 : DBG(("%p no buf avail %u %u %p %p", tpcb, tpcb->snd_buf, tpcb->snd_queuelen,
15860 : tpcb->unsent, tpcb->unacked));
15861 : mg_lwip_netif_run_on_tcpip(tcp_output_tcpip, tpcb);
15862 : ctx->ret = 0;
15863 : return;
15864 : }
15865 : unsent = (tpcb->unsent != NULL ? tpcb->unsent->len : 0);
15866 : unacked = (tpcb->unacked != NULL ? tpcb->unacked->len : 0);
15867 : /*
15868 : * On ESP8266 we only allow one TCP segment in flight at any given time.
15869 : * This may increase latency and reduce efficiency of tcp windowing,
15870 : * but memory is scarce and precious on that platform so we do this to
15871 : * reduce footprint.
15872 : */
15873 : #if CS_PLATFORM == CS_P_ESP8266
15874 : if (unacked > 0) {
15875 : ctx->ret = 0;
15876 : return;
15877 : }
15878 : len = MIN(len, (TCP_MSS - unsent));
15879 : #endif
15880 : cs->err = tcp_write(tpcb, ctx->data, len, TCP_WRITE_FLAG_COPY);
15881 : unsent = (tpcb->unsent != NULL ? tpcb->unsent->len : 0);
15882 : unacked = (tpcb->unacked != NULL ? tpcb->unacked->len : 0);
15883 : DBG(("%p tcp_write %u = %d, %u %u", tpcb, len, cs->err, unsent, unacked));
15884 : if (cs->err != ERR_OK) {
15885 : /*
15886 : * We ignore ERR_MEM because memory will be freed up when the data is sent
15887 : * and we'll retry.
15888 : */
15889 : ctx->ret = (cs->err == ERR_MEM ? 0 : -1);
15890 : return;
15891 : }
15892 : ctx->ret = len;
15893 : (void) unsent;
15894 : (void) unacked;
15895 : }
15896 :
15897 : int mg_lwip_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len) {
15898 : struct mg_lwip_tcp_write_ctx ctx = {.nc = nc, .data = buf, .len = len};
15899 : struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15900 : if (nc->sock == INVALID_SOCKET) return -1;
15901 : struct tcp_pcb *tpcb = cs->pcb.tcp;
15902 : if (tpcb == NULL) return -1;
15903 : if (tpcb->snd_buf <= 0) return 0;
15904 : mg_lwip_netif_run_on_tcpip(mg_lwip_tcp_write_tcpip, &ctx);
15905 : return ctx.ret;
15906 : }
15907 :
15908 : struct udp_sendto_ctx {
15909 : struct udp_pcb *upcb;
15910 : struct pbuf *p;
15911 : ip_addr_t *ip;
15912 : uint16_t port;
15913 : int ret;
15914 : };
15915 :
15916 : static void udp_sendto_tcpip(void *arg) {
15917 : struct udp_sendto_ctx *ctx = (struct udp_sendto_ctx *) arg;
15918 : ctx->ret = udp_sendto(ctx->upcb, ctx->p, ctx->ip, ctx->port);
15919 : }
15920 :
15921 : static int mg_lwip_if_udp_send(struct mg_connection *nc, const void *data,
15922 : size_t len) {
15923 : struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15924 : if (nc->sock == INVALID_SOCKET || cs->pcb.udp == NULL) return -1;
15925 : struct udp_pcb *upcb = cs->pcb.udp;
15926 : struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
15927 : #if defined(LWIP_IPV4) && LWIP_IPV4 && defined(LWIP_IPV6) && LWIP_IPV6
15928 : ip_addr_t ip = {.u_addr.ip4.addr = nc->sa.sin.sin_addr.s_addr, .type = 0};
15929 : #else
15930 : ip_addr_t ip = {.addr = nc->sa.sin.sin_addr.s_addr};
15931 : #endif
15932 : u16_t port = ntohs(nc->sa.sin.sin_port);
15933 : if (p == NULL) return 0;
15934 : memcpy(p->payload, data, len);
15935 : struct udp_sendto_ctx ctx = {.upcb = upcb, .p = p, .ip = &ip, .port = port};
15936 : mg_lwip_netif_run_on_tcpip(udp_sendto_tcpip, &ctx);
15937 : cs->err = ctx.ret;
15938 : pbuf_free(p);
15939 : return (cs->err == ERR_OK ? (int) len : -2);
15940 : }
15941 :
15942 : static int mg_lwip_if_can_send(struct mg_connection *nc,
15943 : struct mg_lwip_conn_state *cs) {
15944 : int can_send = 0;
15945 : if (nc->send_mbuf.len > 0 || (nc->flags & MG_F_WANT_WRITE)) {
15946 : /* We have stuff to send, but can we? */
15947 : if (nc->flags & MG_F_UDP) {
15948 : /* UDP is always ready for sending. */
15949 : can_send = (cs->pcb.udp != NULL);
15950 : } else {
15951 : can_send = (cs->pcb.tcp != NULL && cs->pcb.tcp->snd_buf > 0);
15952 : /* See comment above. */
15953 : #if CS_PLATFORM == CS_P_ESP8266
15954 : if (cs->pcb.tcp->unacked != NULL) can_send = 0;
15955 : #endif
15956 : }
15957 : }
15958 : return can_send;
15959 : }
15960 :
15961 : struct tcp_recved_ctx {
15962 : struct tcp_pcb *tpcb;
15963 : size_t len;
15964 : };
15965 :
15966 : void tcp_recved_tcpip(void *arg) {
15967 : struct tcp_recved_ctx *ctx = (struct tcp_recved_ctx *) arg;
15968 : if (ctx->tpcb != NULL) tcp_recved(ctx->tpcb, ctx->len);
15969 : }
15970 :
15971 : static int mg_lwip_if_tcp_recv(struct mg_connection *nc, void *buf,
15972 : size_t len) {
15973 : int res = 0;
15974 : char *bufp = buf;
15975 : struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15976 : if (nc->sock == INVALID_SOCKET) return -1;
15977 : mgos_lock();
15978 : while (cs->rx_chain != NULL && len > 0) {
15979 : struct pbuf *seg = cs->rx_chain;
15980 : size_t seg_len = (seg->len - cs->rx_offset);
15981 : size_t copy_len = MIN(len, seg_len);
15982 :
15983 : pbuf_copy_partial(seg, bufp, copy_len, cs->rx_offset);
15984 : len -= copy_len;
15985 : res += copy_len;
15986 : bufp += copy_len;
15987 : cs->rx_offset += copy_len;
15988 : if (cs->rx_offset == cs->rx_chain->len) {
15989 : cs->rx_chain = pbuf_dechain(cs->rx_chain);
15990 : pbuf_free(seg);
15991 : cs->rx_offset = 0;
15992 : }
15993 : }
15994 : mgos_unlock();
15995 : if (res > 0) {
15996 : struct tcp_recved_ctx ctx = {.tpcb = cs->pcb.tcp, .len = res};
15997 : mg_lwip_netif_run_on_tcpip(tcp_recved_tcpip, &ctx);
15998 : }
15999 : return res;
16000 : }
16001 :
16002 : int mg_lwip_if_create_conn(struct mg_connection *nc) {
16003 : struct mg_lwip_conn_state *cs =
16004 : (struct mg_lwip_conn_state *) MG_CALLOC(1, sizeof(*cs));
16005 : if (cs == NULL) return 0;
16006 : cs->nc = nc;
16007 : nc->sock = (intptr_t) cs;
16008 : return 1;
16009 : }
16010 :
16011 : static void udp_remove_tcpip(void *arg) {
16012 : udp_remove((struct udp_pcb *) arg);
16013 : }
16014 :
16015 : void mg_lwip_if_destroy_conn(struct mg_connection *nc) {
16016 : if (nc->sock == INVALID_SOCKET) return;
16017 : struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
16018 : if (!(nc->flags & MG_F_UDP)) {
16019 : struct tcp_pcb *tpcb = cs->pcb.tcp;
16020 : if (tpcb != NULL) {
16021 : tcp_arg(tpcb, NULL);
16022 : DBG(("%p tcp_close %p", nc, tpcb));
16023 : tcp_arg(tpcb, NULL);
16024 : mg_lwip_netif_run_on_tcpip(tcp_close_tcpip, tpcb);
16025 : }
16026 : while (cs->rx_chain != NULL) {
16027 : struct pbuf *seg = cs->rx_chain;
16028 : cs->rx_chain = pbuf_dechain(cs->rx_chain);
16029 : pbuf_free(seg);
16030 : }
16031 : memset(cs, 0, sizeof(*cs));
16032 : MG_FREE(cs);
16033 : } else if (nc->listener == NULL) {
16034 : /* Only close outgoing UDP pcb or listeners. */
16035 : struct udp_pcb *upcb = cs->pcb.udp;
16036 : if (upcb != NULL) {
16037 : DBG(("%p udp_remove %p", nc, upcb));
16038 : mg_lwip_netif_run_on_tcpip(udp_remove_tcpip, upcb);
16039 : }
16040 : memset(cs, 0, sizeof(*cs));
16041 : MG_FREE(cs);
16042 : }
16043 : nc->sock = INVALID_SOCKET;
16044 : }
16045 :
16046 : void mg_lwip_if_get_conn_addr(struct mg_connection *nc, int remote,
16047 : union socket_address *sa) {
16048 : memset(sa, 0, sizeof(*sa));
16049 : if (nc == NULL || nc->sock == INVALID_SOCKET) return;
16050 : struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
16051 : if (nc->flags & MG_F_UDP) {
16052 : struct udp_pcb *upcb = cs->pcb.udp;
16053 : if (remote) {
16054 : memcpy(sa, &nc->sa, sizeof(*sa));
16055 : } else if (upcb != NULL) {
16056 : sa->sin.sin_port = htons(upcb->local_port);
16057 : SET_ADDR(sa, &upcb->local_ip);
16058 : }
16059 : } else {
16060 : struct tcp_pcb *tpcb = cs->pcb.tcp;
16061 : if (remote) {
16062 : memcpy(sa, &nc->sa, sizeof(*sa));
16063 : } else if (tpcb != NULL) {
16064 : sa->sin.sin_port = htons(tpcb->local_port);
16065 : SET_ADDR(sa, &tpcb->local_ip);
16066 : }
16067 : }
16068 : }
16069 :
16070 : void mg_lwip_if_sock_set(struct mg_connection *nc, sock_t sock) {
16071 : nc->sock = sock;
16072 : }
16073 :
16074 : /* clang-format off */
16075 : #define MG_LWIP_IFACE_VTABLE \
16076 : { \
16077 : mg_lwip_if_init, \
16078 : mg_lwip_if_free, \
16079 : mg_lwip_if_add_conn, \
16080 : mg_lwip_if_remove_conn, \
16081 : mg_lwip_if_poll, \
16082 : mg_lwip_if_listen_tcp, \
16083 : mg_lwip_if_listen_udp, \
16084 : mg_lwip_if_connect_tcp, \
16085 : mg_lwip_if_connect_udp, \
16086 : mg_lwip_if_tcp_send, \
16087 : mg_lwip_if_udp_send, \
16088 : mg_lwip_if_tcp_recv, \
16089 : mg_lwip_if_udp_recv, \
16090 : mg_lwip_if_create_conn, \
16091 : mg_lwip_if_destroy_conn, \
16092 : mg_lwip_if_sock_set, \
16093 : mg_lwip_if_get_conn_addr, \
16094 : }
16095 : /* clang-format on */
16096 :
16097 : const struct mg_iface_vtable mg_lwip_iface_vtable = MG_LWIP_IFACE_VTABLE;
16098 : #if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL
16099 : const struct mg_iface_vtable mg_default_iface_vtable = MG_LWIP_IFACE_VTABLE;
16100 : #endif
16101 :
16102 : #endif /* MG_ENABLE_NET_IF_LWIP_LOW_LEVEL */
16103 : #ifdef MG_MODULE_LINES
16104 : #line 1 "common/platforms/lwip/mg_lwip_ev_mgr.c"
16105 : #endif
16106 : /*
16107 : * Copyright (c) 2014-2018 Cesanta Software Limited
16108 : * All rights reserved
16109 : *
16110 : * Licensed under the Apache License, Version 2.0 (the ""License"");
16111 : * you may not use this file except in compliance with the License.
16112 : * You may obtain a copy of the License at
16113 : *
16114 : * http://www.apache.org/licenses/LICENSE-2.0
16115 : *
16116 : * Unless required by applicable law or agreed to in writing, software
16117 : * distributed under the License is distributed on an ""AS IS"" BASIS,
16118 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16119 : * See the License for the specific language governing permissions and
16120 : * limitations under the License.
16121 : */
16122 :
16123 : #if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL
16124 :
16125 : #ifndef MG_SIG_QUEUE_LEN
16126 : #define MG_SIG_QUEUE_LEN 32
16127 : #endif
16128 :
16129 : struct mg_ev_mgr_lwip_signal {
16130 : int sig;
16131 : struct mg_connection *nc;
16132 : };
16133 :
16134 : struct mg_ev_mgr_lwip_data {
16135 : struct mg_ev_mgr_lwip_signal sig_queue[MG_SIG_QUEUE_LEN];
16136 : int sig_queue_len;
16137 : int start_index;
16138 : };
16139 :
16140 : void mg_lwip_post_signal(enum mg_sig_type sig, struct mg_connection *nc) {
16141 : struct mg_ev_mgr_lwip_data *md =
16142 : (struct mg_ev_mgr_lwip_data *) nc->iface->data;
16143 : mgos_lock();
16144 : if (md->sig_queue_len >= MG_SIG_QUEUE_LEN) {
16145 : mgos_unlock();
16146 : return;
16147 : }
16148 : int end_index = (md->start_index + md->sig_queue_len) % MG_SIG_QUEUE_LEN;
16149 : md->sig_queue[end_index].sig = sig;
16150 : md->sig_queue[end_index].nc = nc;
16151 : md->sig_queue_len++;
16152 : mg_lwip_mgr_schedule_poll(nc->mgr);
16153 : mgos_unlock();
16154 : }
16155 :
16156 : void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) {
16157 : struct mg_ev_mgr_lwip_data *md =
16158 : (struct mg_ev_mgr_lwip_data *) mgr->ifaces[MG_MAIN_IFACE]->data;
16159 : while (md->sig_queue_len > 0) {
16160 : mgos_lock();
16161 : int i = md->start_index;
16162 : int sig = md->sig_queue[i].sig;
16163 : struct mg_connection *nc = md->sig_queue[i].nc;
16164 : struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
16165 : md->start_index = (i + 1) % MG_SIG_QUEUE_LEN;
16166 : md->sig_queue_len--;
16167 : mgos_unlock();
16168 : if (nc->iface == NULL || nc->mgr == NULL) continue;
16169 : switch (sig) {
16170 : case MG_SIG_CONNECT_RESULT: {
16171 : mg_if_connect_cb(nc, cs->err);
16172 : break;
16173 : }
16174 : case MG_SIG_CLOSE_CONN: {
16175 : mg_close_conn(nc);
16176 : break;
16177 : }
16178 : case MG_SIG_RECV: {
16179 : cs->recv_pending = 0;
16180 : mg_if_can_recv_cb(nc);
16181 : mbuf_trim(&nc->recv_mbuf);
16182 : break;
16183 : }
16184 : case MG_SIG_TOMBSTONE: {
16185 : break;
16186 : }
16187 : case MG_SIG_ACCEPT: {
16188 : mg_lwip_handle_accept(nc);
16189 : break;
16190 : }
16191 : }
16192 : }
16193 : }
16194 :
16195 : void mg_lwip_if_init(struct mg_iface *iface) {
16196 : LOG(LL_INFO, ("Mongoose %s, LwIP %u.%u.%u", MG_VERSION, LWIP_VERSION_MAJOR,
16197 : LWIP_VERSION_MINOR, LWIP_VERSION_REVISION));
16198 : iface->data = MG_CALLOC(1, sizeof(struct mg_ev_mgr_lwip_data));
16199 : #if !NO_SYS && !LWIP_TCPIP_CORE_LOCKING
16200 : sys_sem_new(&s_tcpip_call_lock_sem, 1);
16201 : sys_sem_new(&s_tcpip_call_sync_sem, 0);
16202 : #endif
16203 : }
16204 :
16205 : void mg_lwip_if_free(struct mg_iface *iface) {
16206 : MG_FREE(iface->data);
16207 : iface->data = NULL;
16208 : }
16209 :
16210 : void mg_lwip_if_add_conn(struct mg_connection *nc) {
16211 : (void) nc;
16212 : }
16213 :
16214 : void mg_lwip_if_remove_conn(struct mg_connection *nc) {
16215 : struct mg_ev_mgr_lwip_data *md =
16216 : (struct mg_ev_mgr_lwip_data *) nc->iface->data;
16217 : /* Walk the queue and null-out further signals for this conn. */
16218 : for (int i = 0; i < MG_SIG_QUEUE_LEN; i++) {
16219 : if (md->sig_queue[i].nc == nc) {
16220 : md->sig_queue[i].sig = MG_SIG_TOMBSTONE;
16221 : }
16222 : }
16223 : }
16224 :
16225 : time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms) {
16226 : struct mg_mgr *mgr = iface->mgr;
16227 : int n = 0;
16228 : double now = mg_time();
16229 : struct mg_connection *nc, *tmp;
16230 : double min_timer = 0;
16231 : int num_timers = 0;
16232 : #if 0
16233 : DBG(("begin poll @%u", (unsigned int) (now * 1000)));
16234 : #endif
16235 : mg_ev_mgr_lwip_process_signals(mgr);
16236 : for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
16237 : struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
16238 : tmp = nc->next;
16239 : n++;
16240 : if (!mg_if_poll(nc, now)) continue;
16241 : if (nc->sock != INVALID_SOCKET &&
16242 : !(nc->flags & (MG_F_UDP | MG_F_LISTENING)) && cs->pcb.tcp != NULL &&
16243 : cs->pcb.tcp->unsent != NULL) {
16244 : mg_lwip_netif_run_on_tcpip(tcp_output_tcpip, cs->pcb.tcp);
16245 : }
16246 : if (nc->ev_timer_time > 0) {
16247 : if (num_timers == 0 || nc->ev_timer_time < min_timer) {
16248 : min_timer = nc->ev_timer_time;
16249 : }
16250 : num_timers++;
16251 : }
16252 :
16253 : if (nc->sock != INVALID_SOCKET) {
16254 : if (mg_lwip_if_can_send(nc, cs)) {
16255 : mg_if_can_send_cb(nc);
16256 : mbuf_trim(&nc->send_mbuf);
16257 : }
16258 : if (cs->rx_chain != NULL) {
16259 : mg_if_can_recv_cb(nc);
16260 : } else if (cs->draining_rx_chain) {
16261 : /*
16262 : * If the connection is about to close, and rx_chain is finally empty,
16263 : * send the MG_SIG_CLOSE_CONN signal
16264 : */
16265 : mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
16266 : }
16267 : }
16268 : }
16269 : #if 0
16270 : DBG(("end poll @%u, %d conns, %d timers (min %u), next in %d ms",
16271 : (unsigned int) (now * 1000), n, num_timers,
16272 : (unsigned int) (min_timer * 1000), timeout_ms));
16273 : #endif
16274 : (void) timeout_ms;
16275 : return now;
16276 : }
16277 :
16278 : #endif /* MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL */
16279 : #ifdef MG_MODULE_LINES
16280 : #line 1 "common/platforms/wince/wince_libc.c"
16281 : #endif
16282 : /*
16283 : * Copyright (c) 2014-2018 Cesanta Software Limited
16284 : * All rights reserved
16285 : *
16286 : * Licensed under the Apache License, Version 2.0 (the ""License"");
16287 : * you may not use this file except in compliance with the License.
16288 : * You may obtain a copy of the License at
16289 : *
16290 : * http://www.apache.org/licenses/LICENSE-2.0
16291 : *
16292 : * Unless required by applicable law or agreed to in writing, software
16293 : * distributed under the License is distributed on an ""AS IS"" BASIS,
16294 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16295 : * See the License for the specific language governing permissions and
16296 : * limitations under the License.
16297 : */
16298 :
16299 : #ifdef WINCE
16300 :
16301 : const char *strerror(int err) {
16302 : /*
16303 : * TODO(alashkin): there is no strerror on WinCE;
16304 : * look for similar wce_xxxx function
16305 : */
16306 : static char buf[10];
16307 : snprintf(buf, sizeof(buf), "%d", err);
16308 : return buf;
16309 : }
16310 :
16311 : int open(const char *filename, int oflag, int pmode) {
16312 : /*
16313 : * TODO(alashkin): mg_open function is not used in mongoose
16314 : * but exists in documentation as utility function
16315 : * Shall we delete it at all or implement for WinCE as well?
16316 : */
16317 : DebugBreak();
16318 : return 0; /* for compiler */
16319 : }
16320 :
16321 : int _wstati64(const wchar_t *path, cs_stat_t *st) {
16322 : DWORD fa = GetFileAttributesW(path);
16323 : if (fa == INVALID_FILE_ATTRIBUTES) {
16324 : return -1;
16325 : }
16326 : memset(st, 0, sizeof(*st));
16327 : if ((fa & FILE_ATTRIBUTE_DIRECTORY) == 0) {
16328 : HANDLE h;
16329 : FILETIME ftime;
16330 : st->st_mode |= _S_IFREG;
16331 : h = CreateFileW(path, GENERIC_READ, 0, NULL, OPEN_EXISTING,
16332 : FILE_ATTRIBUTE_NORMAL, NULL);
16333 : if (h == INVALID_HANDLE_VALUE) {
16334 : return -1;
16335 : }
16336 : st->st_size = GetFileSize(h, NULL);
16337 : GetFileTime(h, NULL, NULL, &ftime);
16338 : st->st_mtime = (uint32_t)((((uint64_t) ftime.dwLowDateTime +
16339 : ((uint64_t) ftime.dwHighDateTime << 32)) /
16340 : 10000000.0) -
16341 : 11644473600);
16342 : CloseHandle(h);
16343 : } else {
16344 : st->st_mode |= _S_IFDIR;
16345 : }
16346 : return 0;
16347 : }
16348 :
16349 : /* Windows CE doesn't have neither gmtime nor strftime */
16350 : static void mg_gmt_time_string(char *buf, size_t buf_len, time_t *t) {
16351 : FILETIME ft;
16352 : SYSTEMTIME systime;
16353 : if (t != NULL) {
16354 : uint64_t filetime = (*t + 11644473600) * 10000000;
16355 : ft.dwLowDateTime = filetime & 0xFFFFFFFF;
16356 : ft.dwHighDateTime = (filetime & 0xFFFFFFFF00000000) >> 32;
16357 : FileTimeToSystemTime(&ft, &systime);
16358 : } else {
16359 : GetSystemTime(&systime);
16360 : }
16361 : /* There is no PRIu16 in WinCE SDK */
16362 : snprintf(buf, buf_len, "%d.%d.%d %d:%d:%d GMT", (int) systime.wYear,
16363 : (int) systime.wMonth, (int) systime.wDay, (int) systime.wHour,
16364 : (int) systime.wMinute, (int) systime.wSecond);
16365 : }
16366 :
16367 : #endif
16368 : #ifdef MG_MODULE_LINES
16369 : #line 1 "common/platforms/pic32/pic32_net_if.h"
16370 : #endif
16371 : /*
16372 : * Copyright (c) 2014-2018 Cesanta Software Limited
16373 : * All rights reserved
16374 : *
16375 : * Licensed under the Apache License, Version 2.0 (the ""License"");
16376 : * you may not use this file except in compliance with the License.
16377 : * You may obtain a copy of the License at
16378 : *
16379 : * http://www.apache.org/licenses/LICENSE-2.0
16380 : *
16381 : * Unless required by applicable law or agreed to in writing, software
16382 : * distributed under the License is distributed on an ""AS IS"" BASIS,
16383 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16384 : * See the License for the specific language governing permissions and
16385 : * limitations under the License.
16386 : */
16387 :
16388 : #ifndef CS_COMMON_PLATFORMS_PIC32_NET_IF_H_
16389 : #define CS_COMMON_PLATFORMS_PIC32_NET_IF_H_
16390 :
16391 : /* Amalgamated: #include "mongoose/src/net_if.h" */
16392 :
16393 : #ifdef __cplusplus
16394 : extern "C" {
16395 : #endif /* __cplusplus */
16396 :
16397 : #ifndef MG_ENABLE_NET_IF_PIC32
16398 : #define MG_ENABLE_NET_IF_PIC32 MG_NET_IF == MG_NET_IF_PIC32
16399 : #endif
16400 :
16401 : extern const struct mg_iface_vtable mg_pic32_iface_vtable;
16402 :
16403 : #ifdef __cplusplus
16404 : }
16405 : #endif /* __cplusplus */
16406 :
16407 : #endif /* CS_COMMON_PLATFORMS_PIC32_NET_IF_H_ */
16408 : #ifdef MG_MODULE_LINES
16409 : #line 1 "common/platforms/pic32/pic32_net_if.c"
16410 : #endif
16411 : /*
16412 : * Copyright (c) 2014-2018 Cesanta Software Limited
16413 : * All rights reserved
16414 : *
16415 : * Licensed under the Apache License, Version 2.0 (the ""License"");
16416 : * you may not use this file except in compliance with the License.
16417 : * You may obtain a copy of the License at
16418 : *
16419 : * http://www.apache.org/licenses/LICENSE-2.0
16420 : *
16421 : * Unless required by applicable law or agreed to in writing, software
16422 : * distributed under the License is distributed on an ""AS IS"" BASIS,
16423 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16424 : * See the License for the specific language governing permissions and
16425 : * limitations under the License.
16426 : */
16427 :
16428 : #if MG_ENABLE_NET_IF_PIC32
16429 :
16430 : int mg_pic32_if_create_conn(struct mg_connection *nc) {
16431 : (void) nc;
16432 : return 1;
16433 : }
16434 :
16435 : void mg_pic32_if_recved(struct mg_connection *nc, size_t len) {
16436 : (void) nc;
16437 : (void) len;
16438 : }
16439 :
16440 : void mg_pic32_if_add_conn(struct mg_connection *nc) {
16441 : (void) nc;
16442 : }
16443 :
16444 : void mg_pic32_if_init(struct mg_iface *iface) {
16445 : (void) iface;
16446 : (void) mg_get_errno(); /* Shutup compiler */
16447 : }
16448 :
16449 : void mg_pic32_if_free(struct mg_iface *iface) {
16450 : (void) iface;
16451 : }
16452 :
16453 : void mg_pic32_if_remove_conn(struct mg_connection *nc) {
16454 : (void) nc;
16455 : }
16456 :
16457 : void mg_pic32_if_destroy_conn(struct mg_connection *nc) {
16458 : if (nc->sock == INVALID_SOCKET) return;
16459 : /* For UDP, only close outgoing sockets or listeners. */
16460 : if (!(nc->flags & MG_F_UDP)) {
16461 : /* Close TCP */
16462 : TCPIP_TCP_Close((TCP_SOCKET) nc->sock);
16463 : } else if (nc->listener == NULL) {
16464 : /* Only close outgoing UDP or listeners. */
16465 : TCPIP_UDP_Close((UDP_SOCKET) nc->sock);
16466 : }
16467 :
16468 : nc->sock = INVALID_SOCKET;
16469 : }
16470 :
16471 : int mg_pic32_if_listen_udp(struct mg_connection *nc, union socket_address *sa) {
16472 : nc->sock = TCPIP_UDP_ServerOpen(
16473 : sa->sin.sin_family == AF_INET ? IP_ADDRESS_TYPE_IPV4
16474 : : IP_ADDRESS_TYPE_IPV6,
16475 : ntohs(sa->sin.sin_port),
16476 : sa->sin.sin_addr.s_addr == 0 ? 0 : (IP_MULTI_ADDRESS *) &sa->sin);
16477 : if (nc->sock == INVALID_SOCKET) {
16478 : return -1;
16479 : }
16480 : return 0;
16481 : }
16482 :
16483 : void mg_pic32_if_udp_send(struct mg_connection *nc, const void *buf,
16484 : size_t len) {
16485 : mbuf_append(&nc->send_mbuf, buf, len);
16486 : }
16487 :
16488 : void mg_pic32_if_tcp_send(struct mg_connection *nc, const void *buf,
16489 : size_t len) {
16490 : mbuf_append(&nc->send_mbuf, buf, len);
16491 : }
16492 :
16493 : int mg_pic32_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) {
16494 : nc->sock = TCPIP_TCP_ServerOpen(
16495 : sa->sin.sin_family == AF_INET ? IP_ADDRESS_TYPE_IPV4
16496 : : IP_ADDRESS_TYPE_IPV6,
16497 : ntohs(sa->sin.sin_port),
16498 : sa->sin.sin_addr.s_addr == 0 ? 0 : (IP_MULTI_ADDRESS *) &sa->sin);
16499 : memcpy(&nc->sa, sa, sizeof(*sa));
16500 : if (nc->sock == INVALID_SOCKET) {
16501 : return -1;
16502 : }
16503 : return 0;
16504 : }
16505 :
16506 : static int mg_accept_conn(struct mg_connection *lc) {
16507 : struct mg_connection *nc;
16508 : TCP_SOCKET_INFO si;
16509 : union socket_address sa;
16510 :
16511 : nc = mg_if_accept_new_conn(lc);
16512 :
16513 : if (nc == NULL) {
16514 : return 0;
16515 : }
16516 :
16517 : nc->sock = lc->sock;
16518 : nc->flags &= ~MG_F_LISTENING;
16519 :
16520 : if (!TCPIP_TCP_SocketInfoGet((TCP_SOCKET) nc->sock, &si)) {
16521 : return 0;
16522 : }
16523 :
16524 : if (si.addressType == IP_ADDRESS_TYPE_IPV4) {
16525 : sa.sin.sin_family = AF_INET;
16526 : sa.sin.sin_port = htons(si.remotePort);
16527 : sa.sin.sin_addr.s_addr = si.remoteIPaddress.v4Add.Val;
16528 : } else {
16529 : /* TODO(alashkin): do something with _potential_ IPv6 */
16530 : memset(&sa, 0, sizeof(sa));
16531 : }
16532 :
16533 : mg_if_accept_tcp_cb(nc, (union socket_address *) &sa, sizeof(sa));
16534 :
16535 : return mg_pic32_if_listen_tcp(lc, &lc->sa) >= 0;
16536 : }
16537 :
16538 : char *inet_ntoa(struct in_addr in) {
16539 : static char addr[17];
16540 : snprintf(addr, sizeof(addr), "%d.%d.%d.%d", (int) in.S_un.S_un_b.s_b1,
16541 : (int) in.S_un.S_un_b.s_b2, (int) in.S_un.S_un_b.s_b3,
16542 : (int) in.S_un.S_un_b.s_b4);
16543 : return addr;
16544 : }
16545 :
16546 : static void mg_handle_send(struct mg_connection *nc) {
16547 : uint16_t bytes_written = 0;
16548 : if (nc->flags & MG_F_UDP) {
16549 : if (!TCPIP_UDP_RemoteBind(
16550 : (UDP_SOCKET) nc->sock,
16551 : nc->sa.sin.sin_family == AF_INET ? IP_ADDRESS_TYPE_IPV4
16552 : : IP_ADDRESS_TYPE_IPV6,
16553 : ntohs(nc->sa.sin.sin_port), (IP_MULTI_ADDRESS *) &nc->sa.sin)) {
16554 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
16555 : return;
16556 : }
16557 : bytes_written = TCPIP_UDP_TxPutIsReady((UDP_SOCKET) nc->sock, 0);
16558 : if (bytes_written >= nc->send_mbuf.len) {
16559 : if (TCPIP_UDP_ArrayPut((UDP_SOCKET) nc->sock,
16560 : (uint8_t *) nc->send_mbuf.buf,
16561 : nc->send_mbuf.len) != nc->send_mbuf.len) {
16562 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
16563 : bytes_written = 0;
16564 : }
16565 : }
16566 : } else {
16567 : bytes_written = TCPIP_TCP_FifoTxFreeGet((TCP_SOCKET) nc->sock);
16568 : if (bytes_written != 0) {
16569 : if (bytes_written > nc->send_mbuf.len) {
16570 : bytes_written = nc->send_mbuf.len;
16571 : }
16572 : if (TCPIP_TCP_ArrayPut((TCP_SOCKET) nc->sock,
16573 : (uint8_t *) nc->send_mbuf.buf,
16574 : bytes_written) != bytes_written) {
16575 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
16576 : bytes_written = 0;
16577 : }
16578 : }
16579 : }
16580 :
16581 : mg_if_sent_cb(nc, bytes_written);
16582 : }
16583 :
16584 : static void mg_handle_recv(struct mg_connection *nc) {
16585 : uint16_t bytes_read = 0;
16586 : uint8_t *buf = NULL;
16587 : if (nc->flags & MG_F_UDP) {
16588 : bytes_read = TCPIP_UDP_GetIsReady((UDP_SOCKET) nc->sock);
16589 : if (bytes_read != 0 &&
16590 : (nc->recv_mbuf_limit == -1 ||
16591 : nc->recv_mbuf.len + bytes_read < nc->recv_mbuf_limit)) {
16592 : buf = (uint8_t *) MG_MALLOC(bytes_read);
16593 : if (TCPIP_UDP_ArrayGet((UDP_SOCKET) nc->sock, buf, bytes_read) !=
16594 : bytes_read) {
16595 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
16596 : bytes_read = 0;
16597 : MG_FREE(buf);
16598 : }
16599 : }
16600 : } else {
16601 : bytes_read = TCPIP_TCP_GetIsReady((TCP_SOCKET) nc->sock);
16602 : if (bytes_read != 0) {
16603 : if (nc->recv_mbuf_limit != -1 &&
16604 : nc->recv_mbuf_limit - nc->recv_mbuf.len > bytes_read) {
16605 : bytes_read = nc->recv_mbuf_limit - nc->recv_mbuf.len;
16606 : }
16607 : buf = (uint8_t *) MG_MALLOC(bytes_read);
16608 : if (TCPIP_TCP_ArrayGet((TCP_SOCKET) nc->sock, buf, bytes_read) !=
16609 : bytes_read) {
16610 : nc->flags |= MG_F_CLOSE_IMMEDIATELY;
16611 : MG_FREE(buf);
16612 : bytes_read = 0;
16613 : }
16614 : }
16615 : }
16616 :
16617 : if (bytes_read != 0) {
16618 : mg_if_recv_tcp_cb(nc, buf, bytes_read, 1 /* own */);
16619 : }
16620 : }
16621 :
16622 : time_t mg_pic32_if_poll(struct mg_iface *iface, int timeout_ms) {
16623 : struct mg_mgr *mgr = iface->mgr;
16624 : double now = mg_time();
16625 : struct mg_connection *nc, *tmp;
16626 :
16627 : for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
16628 : tmp = nc->next;
16629 :
16630 : if (nc->flags & MG_F_CONNECTING) {
16631 : /* processing connections */
16632 : if (nc->flags & MG_F_UDP ||
16633 : TCPIP_TCP_IsConnected((TCP_SOCKET) nc->sock)) {
16634 : mg_if_connect_cb(nc, 0);
16635 : }
16636 : } else if (nc->flags & MG_F_LISTENING) {
16637 : if (TCPIP_TCP_IsConnected((TCP_SOCKET) nc->sock)) {
16638 : /* accept new connections */
16639 : mg_accept_conn(nc);
16640 : }
16641 : } else {
16642 : if (nc->send_mbuf.len != 0) {
16643 : mg_handle_send(nc);
16644 : }
16645 :
16646 : if (nc->recv_mbuf_limit == -1 ||
16647 : nc->recv_mbuf.len < nc->recv_mbuf_limit) {
16648 : mg_handle_recv(nc);
16649 : }
16650 : }
16651 : }
16652 :
16653 : for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
16654 : tmp = nc->next;
16655 : if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) ||
16656 : (nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE))) {
16657 : mg_close_conn(nc);
16658 : }
16659 : }
16660 :
16661 : return now;
16662 : }
16663 :
16664 : void mg_pic32_if_sock_set(struct mg_connection *nc, sock_t sock) {
16665 : nc->sock = sock;
16666 : }
16667 :
16668 : void mg_pic32_if_get_conn_addr(struct mg_connection *nc, int remote,
16669 : union socket_address *sa) {
16670 : /* TODO(alaskin): not implemented yet */
16671 : }
16672 :
16673 : void mg_pic32_if_connect_tcp(struct mg_connection *nc,
16674 : const union socket_address *sa) {
16675 : nc->sock = TCPIP_TCP_ClientOpen(
16676 : sa->sin.sin_family == AF_INET ? IP_ADDRESS_TYPE_IPV4
16677 : : IP_ADDRESS_TYPE_IPV6,
16678 : ntohs(sa->sin.sin_port), (IP_MULTI_ADDRESS *) &sa->sin);
16679 : nc->err = (nc->sock == INVALID_SOCKET) ? -1 : 0;
16680 : }
16681 :
16682 : void mg_pic32_if_connect_udp(struct mg_connection *nc) {
16683 : nc->sock = TCPIP_UDP_ClientOpen(IP_ADDRESS_TYPE_ANY, 0, NULL);
16684 : nc->err = (nc->sock == INVALID_SOCKET) ? -1 : 0;
16685 : }
16686 :
16687 : /* clang-format off */
16688 : #define MG_PIC32_IFACE_VTABLE \
16689 : { \
16690 : mg_pic32_if_init, \
16691 : mg_pic32_if_free, \
16692 : mg_pic32_if_add_conn, \
16693 : mg_pic32_if_remove_conn, \
16694 : mg_pic32_if_poll, \
16695 : mg_pic32_if_listen_tcp, \
16696 : mg_pic32_if_listen_udp, \
16697 : mg_pic32_if_connect_tcp, \
16698 : mg_pic32_if_connect_udp, \
16699 : mg_pic32_if_tcp_send, \
16700 : mg_pic32_if_udp_send, \
16701 : mg_pic32_if_recved, \
16702 : mg_pic32_if_create_conn, \
16703 : mg_pic32_if_destroy_conn, \
16704 : mg_pic32_if_sock_set, \
16705 : mg_pic32_if_get_conn_addr, \
16706 : }
16707 : /* clang-format on */
16708 :
16709 : const struct mg_iface_vtable mg_pic32_iface_vtable = MG_PIC32_IFACE_VTABLE;
16710 : #if MG_NET_IF == MG_NET_IF_PIC32
16711 : const struct mg_iface_vtable mg_default_iface_vtable = MG_PIC32_IFACE_VTABLE;
16712 : #endif
16713 :
16714 : #endif /* MG_ENABLE_NET_IF_PIC32 */
16715 : #ifdef MG_MODULE_LINES
16716 : #line 1 "common/platforms/windows/windows_direct.c"
16717 : #endif
16718 : /*
16719 : * Copyright (c) 2014-2018 Cesanta Software Limited
16720 : * All rights reserved
16721 : *
16722 : * Licensed under the Apache License, Version 2.0 (the ""License"");
16723 : * you may not use this file except in compliance with the License.
16724 : * You may obtain a copy of the License at
16725 : *
16726 : * http://www.apache.org/licenses/LICENSE-2.0
16727 : *
16728 : * Unless required by applicable law or agreed to in writing, software
16729 : * distributed under the License is distributed on an ""AS IS"" BASIS,
16730 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16731 : * See the License for the specific language governing permissions and
16732 : * limitations under the License.
16733 : */
16734 :
16735 : #ifdef _WIN32
16736 :
16737 : int rmdir(const char *dirname) {
16738 : return _rmdir(dirname);
16739 : }
16740 :
16741 : unsigned int sleep(unsigned int seconds) {
16742 : Sleep(seconds * 1000);
16743 : return 0;
16744 : }
16745 :
16746 : #endif /* _WIN32 */
|