MIDAS
Loading...
Searching...
No Matches
mongoose614.cxx
Go to the documentation of this file.
1#include "mongoose614.h"
2#ifdef MG_MODULE_LINES
3#line 1 "mongoose/src/mg_internal.h"
4#endif
5/*
6 * Copyright (c) 2014 Cesanta Software Limited
7 * All rights reserved
8 */
9
10#ifndef CS_MONGOOSE_SRC_INTERNAL_H_
11#define CS_MONGOOSE_SRC_INTERNAL_H_
12
13/* Amalgamated: #include "common/mg_mem.h" */
14
15#ifndef MBUF_REALLOC
16#define MBUF_REALLOC MG_REALLOC
17#endif
18
19#ifndef MBUF_FREE
20#define MBUF_FREE MG_FREE
21#endif
22
23#define MG_SET_PTRPTR(_ptr, _v) \
24 do { \
25 if (_ptr) *(_ptr) = _v; \
26 } while (0)
27
28#ifndef MG_INTERNAL
29#define MG_INTERNAL static
30#endif
31
32#ifdef PICOTCP
33#define NO_LIBC
34#define MG_DISABLE_PFS
35#endif
36
37/* Amalgamated: #include "common/cs_dbg.h" */
38/* Amalgamated: #include "mg_http.h" */
39/* Amalgamated: #include "mg_net.h" */
40
41#ifndef MG_CTL_MSG_MESSAGE_SIZE
42#define MG_CTL_MSG_MESSAGE_SIZE 8192
43#endif
44
45/* internals that need to be accessible in unit tests */
47 int proto,
48 union socket_address *sa);
49
50MG_INTERNAL int mg_parse_address(const char *str, union socket_address *sa,
51 int *proto, char *host, size_t host_len);
52MG_INTERNAL void mg_call(struct mg_connection *nc,
54 void *ev_data);
55void mg_forward(struct mg_connection *from, struct mg_connection *to);
56MG_INTERNAL void mg_add_conn(struct mg_mgr *mgr, struct mg_connection *c);
60 struct mg_add_sock_opts opts);
61#ifdef _WIN32
62/* Retur value is the same as for MultiByteToWideChar. */
63int to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len);
64#endif
65
66struct ctl_msg {
69};
70
71#if MG_ENABLE_MQTT
72struct mg_mqtt_message;
73
74#define MG_MQTT_ERROR_INCOMPLETE_MSG -1
75#define MG_MQTT_ERROR_MALFORMED_MSG -2
76
77MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm);
78#endif
79
80/* Forward declarations for testing. */
81extern void *(*test_malloc)(size_t size);
82extern void *(*test_calloc)(size_t count, size_t size);
83
84#ifndef MIN
85#define MIN(a, b) ((a) < (b) ? (a) : (b))
86#endif
87
88#if MG_ENABLE_HTTP
90
91/*
92 * Reassemble the content of the buffer (buf, blen) which should be
93 * in the HTTP chunked encoding, by collapsing data chunks to the
94 * beginning of the buffer.
95 *
96 * If chunks get reassembled, modify hm->body to point to the reassembled
97 * body and fire MG_EV_HTTP_CHUNK event. If handler sets MG_F_DELETE_CHUNK
98 * in nc->flags, delete reassembled body from the mbuf.
99 *
100 * Return reassembled body size.
101 */
103 struct http_message *hm, char *buf,
104 size_t blen);
105
106#if MG_ENABLE_FILESYSTEM
108 const struct mg_serve_http_opts *opts,
109 char **local_path,
110 struct mg_str *remainder);
113#endif
114#if MG_ENABLE_HTTP_CGI
115MG_INTERNAL void mg_handle_cgi(struct mg_connection *nc, const char *prog,
116 const struct mg_str *path_info,
117 const struct http_message *hm,
118 const struct mg_serve_http_opts *opts);
121#endif
122#if MG_ENABLE_HTTP_SSI
124 struct http_message *hm,
125 const char *path,
126 const struct mg_serve_http_opts *opts);
127#endif
128#if MG_ENABLE_HTTP_WEBDAV
129MG_INTERNAL int mg_is_dav_request(const struct mg_str *s);
130MG_INTERNAL void mg_handle_propfind(struct mg_connection *nc, const char *path,
131 cs_stat_t *stp, struct http_message *hm,
132 struct mg_serve_http_opts *opts);
133MG_INTERNAL void mg_handle_lock(struct mg_connection *nc, const char *path);
134MG_INTERNAL void mg_handle_mkcol(struct mg_connection *nc, const char *path,
135 struct http_message *hm);
137 const struct mg_serve_http_opts *opts,
138 const char *path, struct http_message *hm);
140 const struct mg_serve_http_opts *opts,
141 const char *path);
142MG_INTERNAL void mg_handle_put(struct mg_connection *nc, const char *path,
143 struct http_message *hm);
144#endif
145#if MG_ENABLE_HTTP_WEBSOCKET
146MG_INTERNAL void mg_ws_handler(struct mg_connection *nc, int ev,
147 void *ev_data MG_UD_ARG(void *user_data));
149 const struct mg_str *key,
150 struct http_message *);
151#endif
152#endif /* MG_ENABLE_HTTP */
153
154MG_INTERNAL int mg_get_errno(void);
155
156MG_INTERNAL void mg_close_conn(struct mg_connection *conn);
157
158#if MG_ENABLE_SNTP
159MG_INTERNAL int mg_sntp_parse_reply(const char *buf, int len,
160 struct mg_sntp_message *msg);
161#endif
162
163#endif /* CS_MONGOOSE_SRC_INTERNAL_H_ */
164#ifdef MG_MODULE_LINES
165#line 1 "common/mg_mem.h"
166#endif
167/*
168 * Copyright (c) 2014-2018 Cesanta Software Limited
169 * All rights reserved
170 *
171 * Licensed under the Apache License, Version 2.0 (the ""License"");
172 * you may not use this file except in compliance with the License.
173 * You may obtain a copy of the License at
174 *
175 * http://www.apache.org/licenses/LICENSE-2.0
176 *
177 * Unless required by applicable law or agreed to in writing, software
178 * distributed under the License is distributed on an ""AS IS"" BASIS,
179 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
180 * See the License for the specific language governing permissions and
181 * limitations under the License.
182 */
183
184#ifndef CS_COMMON_MG_MEM_H_
185#define CS_COMMON_MG_MEM_H_
186
187#ifdef __cplusplus
188extern "C" {
189#endif
190
191#ifndef MG_MALLOC
192#define MG_MALLOC malloc
193#endif
194
195#ifndef MG_CALLOC
196#define MG_CALLOC calloc
197#endif
198
199#ifndef MG_REALLOC
200#define MG_REALLOC realloc
201#endif
202
203#ifndef MG_FREE
204#define MG_FREE free
205#endif
206
207#ifdef __cplusplus
208}
209#endif
210
211#endif /* CS_COMMON_MG_MEM_H_ */
212#ifdef MG_MODULE_LINES
213#line 1 "common/cs_base64.c"
214#endif
215/*
216 * Copyright (c) 2014-2018 Cesanta Software Limited
217 * All rights reserved
218 *
219 * Licensed under the Apache License, Version 2.0 (the ""License"");
220 * you may not use this file except in compliance with the License.
221 * You may obtain a copy of the License at
222 *
223 * http://www.apache.org/licenses/LICENSE-2.0
224 *
225 * Unless required by applicable law or agreed to in writing, software
226 * distributed under the License is distributed on an ""AS IS"" BASIS,
227 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
228 * See the License for the specific language governing permissions and
229 * limitations under the License.
230 */
231
232#ifndef EXCLUDE_COMMON
233
234/* Amalgamated: #include "common/cs_base64.h" */
235
236#include <string.h>
237
238/* Amalgamated: #include "common/cs_dbg.h" */
239
240/* ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ */
241
242#define NUM_UPPERCASES ('Z' - 'A' + 1)
243#define NUM_LETTERS (NUM_UPPERCASES * 2)
244#define NUM_DIGITS ('9' - '0' + 1)
245
246/*
247 * Emit a base64 code char.
248 *
249 * Doesn't use memory, thus it's safe to use to safely dump memory in crashdumps
250 */
251static void cs_base64_emit_code(struct cs_base64_ctx *ctx, int v) {
252 if (v < NUM_UPPERCASES) {
253 ctx->b64_putc(v + 'A', ctx->user_data);
254 } else if (v < (NUM_LETTERS)) {
255 ctx->b64_putc(v - NUM_UPPERCASES + 'a', ctx->user_data);
256 } else if (v < (NUM_LETTERS + NUM_DIGITS)) {
257 ctx->b64_putc(v - NUM_LETTERS + '0', ctx->user_data);
258 } else {
259 ctx->b64_putc(v - NUM_LETTERS - NUM_DIGITS == 0 ? '+' : '/',
260 ctx->user_data);
261 }
262}
263
264static void cs_base64_emit_chunk(struct cs_base64_ctx *ctx) {
265 int a, b, c;
266
267 a = ctx->chunk[0];
268 b = ctx->chunk[1];
269 c = ctx->chunk[2];
270
271 cs_base64_emit_code(ctx, a >> 2);
272 cs_base64_emit_code(ctx, ((a & 3) << 4) | (b >> 4));
273 if (ctx->chunk_size > 1) {
274 cs_base64_emit_code(ctx, (b & 15) << 2 | (c >> 6));
275 }
276 if (ctx->chunk_size > 2) {
277 cs_base64_emit_code(ctx, c & 63);
278 }
279}
280
282 void *user_data) {
283 ctx->chunk_size = 0;
284 ctx->b64_putc = b64_putc;
285 ctx->user_data = user_data;
286}
287
288void cs_base64_update(struct cs_base64_ctx *ctx, const char *str, size_t len) {
289 const unsigned char *src = (const unsigned char *) str;
290 size_t i;
291 for (i = 0; i < len; i++) {
292 ctx->chunk[ctx->chunk_size++] = src[i];
293 if (ctx->chunk_size == 3) {
295 ctx->chunk_size = 0;
296 }
297 }
298}
299
301 if (ctx->chunk_size > 0) {
302 int i;
303 memset(&ctx->chunk[ctx->chunk_size], 0, 3 - ctx->chunk_size);
305 for (i = 0; i < (3 - ctx->chunk_size); i++) {
306 ctx->b64_putc('=', ctx->user_data);
307 }
308 }
309}
310
311#define BASE64_ENCODE_BODY \
312 static const char *b64 = \
313 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; \
314 int i, j, a, b, c; \
315 \
316 for (i = j = 0; i < src_len; i += 3) { \
317 a = src[i]; \
318 b = i + 1 >= src_len ? 0 : src[i + 1]; \
319 c = i + 2 >= src_len ? 0 : src[i + 2]; \
320 \
321 BASE64_OUT(b64[a >> 2]); \
322 BASE64_OUT(b64[((a & 3) << 4) | (b >> 4)]); \
323 if (i + 1 < src_len) { \
324 BASE64_OUT(b64[(b & 15) << 2 | (c >> 6)]); \
325 } \
326 if (i + 2 < src_len) { \
327 BASE64_OUT(b64[c & 63]); \
328 } \
329 } \
330 \
331 while (j % 4 != 0) { \
332 BASE64_OUT('='); \
333 } \
334 BASE64_FLUSH()
335
336#define BASE64_OUT(ch) \
337 do { \
338 dst[j++] = (ch); \
339 } while (0)
340
341#define BASE64_FLUSH() \
342 do { \
343 dst[j++] = '\0'; \
344 } while (0)
345
346void cs_base64_encode(const unsigned char *src, int src_len, char *dst) {
348}
349
350#undef BASE64_OUT
351#undef BASE64_FLUSH
352
353#if CS_ENABLE_STDIO
354#define BASE64_OUT(ch) \
355 do { \
356 fprintf(f, "%c", (ch)); \
357 j++; \
358 } while (0)
359
360#define BASE64_FLUSH()
361
362void cs_fprint_base64(FILE *f, const unsigned char *src, int src_len) {
364}
365
366#undef BASE64_OUT
367#undef BASE64_FLUSH
368#endif /* CS_ENABLE_STDIO */
369
370/* Convert one byte of encoded base64 input stream to 6-bit chunk */
371static unsigned char from_b64(unsigned char ch) {
372 /* Inverse lookup map */
373 static const unsigned char tab[128] = {
374 255, 255, 255, 255,
375 255, 255, 255, 255, /* 0 */
376 255, 255, 255, 255,
377 255, 255, 255, 255, /* 8 */
378 255, 255, 255, 255,
379 255, 255, 255, 255, /* 16 */
380 255, 255, 255, 255,
381 255, 255, 255, 255, /* 24 */
382 255, 255, 255, 255,
383 255, 255, 255, 255, /* 32 */
384 255, 255, 255, 62,
385 255, 255, 255, 63, /* 40 */
386 52, 53, 54, 55,
387 56, 57, 58, 59, /* 48 */
388 60, 61, 255, 255,
389 255, 200, 255, 255, /* 56 '=' is 200, on index 61 */
390 255, 0, 1, 2,
391 3, 4, 5, 6, /* 64 */
392 7, 8, 9, 10,
393 11, 12, 13, 14, /* 72 */
394 15, 16, 17, 18,
395 19, 20, 21, 22, /* 80 */
396 23, 24, 25, 255,
397 255, 255, 255, 255, /* 88 */
398 255, 26, 27, 28,
399 29, 30, 31, 32, /* 96 */
400 33, 34, 35, 36,
401 37, 38, 39, 40, /* 104 */
402 41, 42, 43, 44,
403 45, 46, 47, 48, /* 112 */
404 49, 50, 51, 255,
405 255, 255, 255, 255, /* 120 */
406 };
407 return tab[ch & 127];
408}
409
410int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len) {
411 unsigned char a, b, c, d;
412 int orig_len = len;
413 char *orig_dst = dst;
414 while (len >= 4 && (a = from_b64(s[0])) != 255 &&
415 (b = from_b64(s[1])) != 255 && (c = from_b64(s[2])) != 255 &&
416 (d = from_b64(s[3])) != 255) {
417 s += 4;
418 len -= 4;
419 if (a == 200 || b == 200) break; /* '=' can't be there */
420 *dst++ = a << 2 | b >> 4;
421 if (c == 200) break;
422 *dst++ = b << 4 | c >> 2;
423 if (d == 200) break;
424 *dst++ = c << 6 | d;
425 }
426 *dst = 0;
427 if (dec_len != NULL) *dec_len = (dst - orig_dst);
428 return orig_len - len;
429}
430
431#endif /* EXCLUDE_COMMON */
432#ifdef MG_MODULE_LINES
433#line 1 "common/cs_dbg.h"
434#endif
435/*
436 * Copyright (c) 2014-2018 Cesanta Software Limited
437 * All rights reserved
438 *
439 * Licensed under the Apache License, Version 2.0 (the ""License"");
440 * you may not use this file except in compliance with the License.
441 * You may obtain a copy of the License at
442 *
443 * http://www.apache.org/licenses/LICENSE-2.0
444 *
445 * Unless required by applicable law or agreed to in writing, software
446 * distributed under the License is distributed on an ""AS IS"" BASIS,
447 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
448 * See the License for the specific language governing permissions and
449 * limitations under the License.
450 */
451
452#ifndef CS_COMMON_CS_DBG_H_
453#define CS_COMMON_CS_DBG_H_
454
455/* Amalgamated: #include "common/platform.h" */
456
457#if CS_ENABLE_STDIO
458#include <stdio.h>
459#endif
460
461#ifndef CS_ENABLE_DEBUG
462#define CS_ENABLE_DEBUG 0
463#endif
464
465#ifndef CS_LOG_PREFIX_LEN
466#define CS_LOG_PREFIX_LEN 24
467#endif
468
469#ifndef CS_LOG_ENABLE_TS_DIFF
470#define CS_LOG_ENABLE_TS_DIFF 0
471#endif
472
473#ifdef __cplusplus
474extern "C" {
475#endif /* __cplusplus */
476
477/*
478 * Log level; `LL_INFO` is the default. Use `cs_log_set_level()` to change it.
479 */
491
492/*
493 * Set max log level to print; messages with the level above the given one will
494 * not be printed.
495 */
497
498/*
499 * A comma-separated set of prefix=level.
500 * prefix is matched against the log prefix exactly as printed, including line
501 * number, but partial match is ok. Check stops on first matching entry.
502 * If nothing matches, default level is used.
503 *
504 * Examples:
505 * main.c:=4 - everything from main C at verbose debug level.
506 * mongoose.c=1,mjs.c=1,=4 - everything at verbose debug except mg_* and mjs_*
507 *
508 */
509void cs_log_set_file_level(const char *file_level);
510
511/*
512 * Helper function which prints message prefix with the given `level`.
513 * If message should be printed (according to the current log level
514 * and filter), prints the prefix and returns 1, otherwise returns 0.
515 *
516 * Clients should typically just use `LOG()` macro.
517 */
518int cs_log_print_prefix(enum cs_log_level level, const char *fname, int line);
519
520extern enum cs_log_level cs_log_level;
521
522#if CS_ENABLE_STDIO
523
524/*
525 * Set file to write logs into. If `NULL`, logs go to `stderr`.
526 */
528
529/*
530 * Prints log to the current log file, appends "\n" in the end and flushes the
531 * stream.
532 */
533void cs_log_printf(const char *fmt, ...) PRINTF_LIKE(1, 2);
534
535#if CS_ENABLE_STDIO
536
537/*
538 * Format and print message `x` with the given level `l`. Example:
539 *
540 * ```c
541 * LOG(LL_INFO, ("my info message: %d", 123));
542 * LOG(LL_DEBUG, ("my debug message: %d", 123));
543 * ```
544 */
545#define LOG(l, x) \
546 do { \
547 if (cs_log_print_prefix(l, __FILE__, __LINE__)) { \
548 cs_log_printf x; \
549 } \
550 } while (0)
551
552#else
553
554#define LOG(l, x) ((void) l)
555
556#endif
557
558#ifndef CS_NDEBUG
559
560/*
561 * Shortcut for `LOG(LL_VERBOSE_DEBUG, (...))`
562 */
563#define DBG(x) LOG(LL_VERBOSE_DEBUG, x)
564
565#else /* NDEBUG */
566
567#define DBG(x)
568
569#endif
570
571#else /* CS_ENABLE_STDIO */
572
573#define LOG(l, x)
574#define DBG(x)
575
576#endif
577
578#ifdef __cplusplus
579}
580#endif /* __cplusplus */
581
582#endif /* CS_COMMON_CS_DBG_H_ */
583#ifdef MG_MODULE_LINES
584#line 1 "common/cs_dbg.c"
585#endif
586/*
587 * Copyright (c) 2014-2018 Cesanta Software Limited
588 * All rights reserved
589 *
590 * Licensed under the Apache License, Version 2.0 (the ""License"");
591 * you may not use this file except in compliance with the License.
592 * You may obtain a copy of the License at
593 *
594 * http://www.apache.org/licenses/LICENSE-2.0
595 *
596 * Unless required by applicable law or agreed to in writing, software
597 * distributed under the License is distributed on an ""AS IS"" BASIS,
598 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
599 * See the License for the specific language governing permissions and
600 * limitations under the License.
601 */
602
603/* Amalgamated: #include "common/cs_dbg.h" */
604
605#include <stdarg.h>
606#include <stdio.h>
607#include <string.h>
608
609/* Amalgamated: #include "common/cs_time.h" */
610/* Amalgamated: #include "common/str_util.h" */
611
613#if CS_ENABLE_DEBUG
615#else
616 LL_ERROR;
617#endif
618
619#if CS_ENABLE_STDIO
620static char *s_file_level = NULL;
621
622void cs_log_set_file_level(const char *file_level) WEAK;
623
625
626#if CS_LOG_ENABLE_TS_DIFF
627double cs_log_ts WEAK;
628#endif
629
631
632void cs_log_set_file_level(const char *file_level) {
633 char *fl = s_file_level;
634 if (file_level != NULL) {
636 } else {
638 }
639 free(fl);
640}
641
642int cs_log_print_prefix(enum cs_log_level level, const char *file, int ln) WEAK;
643int cs_log_print_prefix(enum cs_log_level level, const char *file, int ln) {
644 char prefix[CS_LOG_PREFIX_LEN], *q;
645 const char *p;
646 size_t fl = 0, ll = 0, pl = 0;
647
648 if (level > cs_log_level && s_file_level == NULL) return 0;
649
650 p = file + strlen(file);
651
652 while (p != file) {
653 const char c = *(p - 1);
654 if (c == '/' || c == '\\') break;
655 p--;
656 fl++;
657 }
658
659 ll = (ln < 10000 ? (ln < 1000 ? (ln < 100 ? (ln < 10 ? 1 : 2) : 3) : 4) : 5);
660 if (fl > (sizeof(prefix) - ll - 2)) fl = (sizeof(prefix) - ll - 2);
661
662 pl = fl + 1 + ll;
663 memcpy(prefix, p, fl);
664 q = prefix + pl;
665 memset(q, ' ', sizeof(prefix) - pl);
666 do {
667 *(--q) = '0' + (ln % 10);
668 ln /= 10;
669 } while (ln > 0);
670 *(--q) = ':';
671
672 if (s_file_level != NULL) {
675 struct mg_str k, v;
676 while ((fl = mg_next_comma_list_entry_n(fl, &k, &v)).p != NULL) {
677 bool yes = !(!mg_str_starts_with(ps, k) || v.len == 0);
678 if (!yes) continue;
679 pll = (enum cs_log_level)(*v.p - '0');
680 break;
681 }
682 if (level > pll) return 0;
683 }
684
687 fwrite(prefix, 1, sizeof(prefix), cs_log_file);
688#if CS_LOG_ENABLE_TS_DIFF
689 {
690 double now = cs_time();
691 fprintf(cs_log_file, "%7u ", (unsigned int) ((now - cs_log_ts) * 1000000));
692 cs_log_ts = now;
693 }
694#endif
695 return 1;
696}
697
698void cs_log_printf(const char *fmt, ...) WEAK;
699void cs_log_printf(const char *fmt, ...) {
700 va_list ap;
701 va_start(ap, fmt);
702 vfprintf(cs_log_file, fmt, ap);
703 va_end(ap);
704 fputc('\n', cs_log_file);
707}
708
712}
713
714#else
715
718}
719
720#endif /* CS_ENABLE_STDIO */
721
725#if CS_LOG_ENABLE_TS_DIFF && CS_ENABLE_STDIO
726 cs_log_ts = cs_time();
727#endif
728}
729#ifdef MG_MODULE_LINES
730#line 1 "common/cs_dirent.h"
731#endif
732/*
733 * Copyright (c) 2014-2018 Cesanta Software Limited
734 * All rights reserved
735 *
736 * Licensed under the Apache License, Version 2.0 (the ""License"");
737 * you may not use this file except in compliance with the License.
738 * You may obtain a copy of the License at
739 *
740 * http://www.apache.org/licenses/LICENSE-2.0
741 *
742 * Unless required by applicable law or agreed to in writing, software
743 * distributed under the License is distributed on an ""AS IS"" BASIS,
744 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
745 * See the License for the specific language governing permissions and
746 * limitations under the License.
747 */
748
749#ifndef CS_COMMON_CS_DIRENT_H_
750#define CS_COMMON_CS_DIRENT_H_
751
752#include <limits.h>
753
754/* Amalgamated: #include "common/platform.h" */
755
756#ifdef __cplusplus
757extern "C" {
758#endif /* __cplusplus */
759
760#ifdef CS_DEFINE_DIRENT
761typedef struct { int dummy; } DIR;
762
763struct dirent {
764 int d_ino;
765#ifdef _WIN32
766 char d_name[MAX_PATH];
767#else
768 /* TODO(rojer): Use PATH_MAX but make sure it's sane on every platform */
769 char d_name[256];
770#endif
771};
772
773DIR *opendir(const char *dir_name);
774int closedir(DIR *dir);
775struct dirent *readdir(DIR *dir);
776#endif /* CS_DEFINE_DIRENT */
777
778#ifdef __cplusplus
779}
780#endif /* __cplusplus */
781
782#endif /* CS_COMMON_CS_DIRENT_H_ */
783#ifdef MG_MODULE_LINES
784#line 1 "common/cs_dirent.c"
785#endif
786/*
787 * Copyright (c) 2014-2018 Cesanta Software Limited
788 * All rights reserved
789 *
790 * Licensed under the Apache License, Version 2.0 (the ""License"");
791 * you may not use this file except in compliance with the License.
792 * You may obtain a copy of the License at
793 *
794 * http://www.apache.org/licenses/LICENSE-2.0
795 *
796 * Unless required by applicable law or agreed to in writing, software
797 * distributed under the License is distributed on an ""AS IS"" BASIS,
798 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
799 * See the License for the specific language governing permissions and
800 * limitations under the License.
801 */
802
803#ifndef EXCLUDE_COMMON
804
805/* Amalgamated: #include "common/mg_mem.h" */
806/* Amalgamated: #include "common/cs_dirent.h" */
807
808/*
809 * This file contains POSIX opendir/closedir/readdir API implementation
810 * for systems which do not natively support it (e.g. Windows).
811 */
812
813#ifdef _WIN32
814struct win32_dir {
815 DIR d;
816 HANDLE handle;
818 struct dirent result;
819};
820
821DIR *opendir(const char *name) {
822 struct win32_dir *dir = NULL;
823 wchar_t wpath[MAX_PATH];
824 DWORD attrs;
825
826 if (name == NULL) {
828 } else if ((dir = (struct win32_dir *) MG_MALLOC(sizeof(*dir))) == NULL) {
830 } else {
833 if (attrs != 0xFFFFFFFF && (attrs & FILE_ATTRIBUTE_DIRECTORY)) {
834 (void) wcscat(wpath, L"\\*");
835 dir->handle = FindFirstFileW(wpath, &dir->info);
836 dir->result.d_name[0] = '\0';
837 } else {
838 MG_FREE(dir);
839 dir = NULL;
840 }
841 }
842
843 return (DIR *) dir;
844}
845
846int closedir(DIR *d) {
847 struct win32_dir *dir = (struct win32_dir *) d;
848 int result = 0;
849
850 if (dir != NULL) {
851 if (dir->handle != INVALID_HANDLE_VALUE)
852 result = FindClose(dir->handle) ? 0 : -1;
853 MG_FREE(dir);
854 } else {
855 result = -1;
857 }
858
859 return result;
860}
861
862struct dirent *readdir(DIR *d) {
863 struct win32_dir *dir = (struct win32_dir *) d;
864 struct dirent *result = NULL;
865
866 if (dir) {
867 memset(&dir->result, 0, sizeof(dir->result));
868 if (dir->handle != INVALID_HANDLE_VALUE) {
869 result = &dir->result;
870 (void) WideCharToMultiByte(CP_UTF8, 0, dir->info.cFileName, -1,
871 result->d_name, sizeof(result->d_name), NULL,
872 NULL);
873
874 if (!FindNextFileW(dir->handle, &dir->info)) {
875 (void) FindClose(dir->handle);
876 dir->handle = INVALID_HANDLE_VALUE;
877 }
878
879 } else {
881 }
882 } else {
884 }
885
886 return result;
887}
888#endif
889
890#endif /* EXCLUDE_COMMON */
891
892/* ISO C requires a translation unit to contain at least one declaration */
893typedef int cs_dirent_dummy;
894#ifdef MG_MODULE_LINES
895#line 1 "common/cs_time.c"
896#endif
897/*
898 * Copyright (c) 2014-2018 Cesanta Software Limited
899 * All rights reserved
900 *
901 * Licensed under the Apache License, Version 2.0 (the ""License"");
902 * you may not use this file except in compliance with the License.
903 * You may obtain a copy of the License at
904 *
905 * http://www.apache.org/licenses/LICENSE-2.0
906 *
907 * Unless required by applicable law or agreed to in writing, software
908 * distributed under the License is distributed on an ""AS IS"" BASIS,
909 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
910 * See the License for the specific language governing permissions and
911 * limitations under the License.
912 */
913
914/* Amalgamated: #include "common/cs_time.h" */
915
916#ifndef _WIN32
917#include <stddef.h>
918/*
919 * There is no sys/time.h on ARMCC.
920 */
921#if !(defined(__ARMCC_VERSION) || defined(__ICCARM__)) && \
922 !defined(__TI_COMPILER_VERSION__) && \
923 (!defined(CS_PLATFORM) || CS_PLATFORM != CS_P_NXP_LPC)
924#include <sys/time.h>
925#endif
926#else
927#include <windows.h>
928#endif
929
930double cs_time(void) WEAK;
931double cs_time(void) {
932 double now;
933#ifndef _WIN32
934 struct timeval tv;
935 if (gettimeofday(&tv, NULL /* tz */) != 0) return 0;
936 now = (double) tv.tv_sec + (((double) tv.tv_usec) / 1000000.0);
937#else
942 /*
943 * 1. VC 6.0 doesn't support conversion uint64 -> double, so, using int64
944 * This should not cause a problems in this (21th) century
945 * 2. Windows FILETIME is a number of 100-nanosecond intervals since January
946 * 1, 1601 while time_t is a number of _seconds_ since January 1, 1970 UTC,
947 * thus, we need to convert to seconds and adjust amount (subtract 11644473600
948 * seconds)
949 */
950 now = (double) (((int64_t) ftime.dwLowDateTime +
951 ((int64_t) ftime.dwHighDateTime << 32)) /
952 10000000.0) -
953 11644473600;
954#endif /* _WIN32 */
955 return now;
956}
957
958double cs_timegm(const struct tm *tm) {
959 /* Month-to-day offset for non-leap-years. */
960 static const int month_day[12] = {0, 31, 59, 90, 120, 151,
961 181, 212, 243, 273, 304, 334};
962
963 /* Most of the calculation is easy; leap years are the main difficulty. */
964 int month = tm->tm_mon % 12;
965 int year = tm->tm_year + tm->tm_mon / 12;
966 int year_for_leap;
967 int64_t rt;
968
969 if (month < 0) { /* Negative values % 12 are still negative. */
970 month += 12;
971 --year;
972 }
973
974 /* This is the number of Februaries since 1900. */
975 year_for_leap = (month > 1) ? year + 1 : year;
976
977 rt =
978 tm->tm_sec /* Seconds */
979 +
980 60 *
981 (tm->tm_min /* Minute = 60 seconds */
982 +
983 60 * (tm->tm_hour /* Hour = 60 minutes */
984 +
985 24 * (month_day[month] + tm->tm_mday - 1 /* Day = 24 hours */
986 + 365 * (year - 70) /* Year = 365 days */
987 + (year_for_leap - 69) / 4 /* Every 4 years is leap... */
988 - (year_for_leap - 1) / 100 /* Except centuries... */
989 + (year_for_leap + 299) / 400))); /* Except 400s. */
990 return rt < 0 ? -1 : (double) rt;
991}
992#ifdef MG_MODULE_LINES
993#line 1 "common/cs_endian.h"
994#endif
995/*
996 * Copyright (c) 2014-2018 Cesanta Software Limited
997 * All rights reserved
998 *
999 * Licensed under the Apache License, Version 2.0 (the ""License"");
1000 * you may not use this file except in compliance with the License.
1001 * You may obtain a copy of the License at
1002 *
1003 * http://www.apache.org/licenses/LICENSE-2.0
1004 *
1005 * Unless required by applicable law or agreed to in writing, software
1006 * distributed under the License is distributed on an ""AS IS"" BASIS,
1007 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1008 * See the License for the specific language governing permissions and
1009 * limitations under the License.
1010 */
1011
1012#ifndef CS_COMMON_CS_ENDIAN_H_
1013#define CS_COMMON_CS_ENDIAN_H_
1014
1015#ifdef __cplusplus
1016extern "C" {
1017#endif
1018
1020 * clang with std=-c99 uses __LITTLE_ENDIAN, by default
1021 * while for ex, RTOS gcc - LITTLE_ENDIAN, by default
1022 * it depends on __USE_BSD, but let's have everything
1023 */
1024#if !defined(BYTE_ORDER) && defined(__BYTE_ORDER)
1025#define BYTE_ORDER __BYTE_ORDER
1026#ifndef LITTLE_ENDIAN
1027#define LITTLE_ENDIAN __LITTLE_ENDIAN
1028#endif /* LITTLE_ENDIAN */
1029#ifndef BIG_ENDIAN
1030#define BIG_ENDIAN __LITTLE_ENDIAN
1031#endif /* BIG_ENDIAN */
1032#endif /* BYTE_ORDER */
1033
1034#ifdef __cplusplus
1035}
1036#endif
1037
1038#endif /* CS_COMMON_CS_ENDIAN_H_ */
1039#ifdef MG_MODULE_LINES
1040#line 1 "common/cs_md5.c"
1041#endif
1042/*
1043 * This code implements the MD5 message-digest algorithm.
1044 * The algorithm is due to Ron Rivest. This code was
1045 * written by Colin Plumb in 1993, no copyright is claimed.
1046 * This code is in the public domain; do with it what you wish.
1047 *
1048 * Equivalent code is available from RSA Data Security, Inc.
1049 * This code has been tested against that, and is equivalent,
1050 * except that you don't need to include two pages of legalese
1051 * with every copy.
1052 *
1053 * To compute the message digest of a chunk of bytes, declare an
1054 * MD5Context structure, pass it to MD5Init, call MD5Update as
1055 * needed on buffers full of bytes, and then call MD5Final, which
1056 * will fill a supplied 16-byte array with the digest.
1057 */
1058
1059/* Amalgamated: #include "common/cs_md5.h" */
1060/* Amalgamated: #include "common/str_util.h" */
1061
1062#if !defined(EXCLUDE_COMMON)
1063#if !CS_DISABLE_MD5
1064
1065/* Amalgamated: #include "common/cs_endian.h" */
1066
1067static void byteReverse(unsigned char *buf, unsigned longs) {
1068/* Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN */
1069#if BYTE_ORDER == BIG_ENDIAN
1070 do {
1071 uint32_t t = (uint32_t)((unsigned) buf[3] << 8 | buf[2]) << 16 |
1072 ((unsigned) buf[1] << 8 | buf[0]);
1073 *(uint32_t *) buf = t;
1074 buf += 4;
1075 } while (--longs);
1076#else
1077 (void) buf;
1078 (void) longs;
1079#endif
1080}
1081
1082#define F1(x, y, z) (z ^ (x & (y ^ z)))
1083#define F2(x, y, z) F1(z, x, y)
1084#define F3(x, y, z) (x ^ y ^ z)
1085#define F4(x, y, z) (y ^ (x | ~z))
1086
1087#define MD5STEP(f, w, x, y, z, data, s) \
1088 (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x)
1089
1090/*
1091 * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
1092 * initialization constants.
1093 */
1095 ctx->buf[0] = 0x67452301;
1096 ctx->buf[1] = 0xefcdab89;
1097 ctx->buf[2] = 0x98badcfe;
1098 ctx->buf[3] = 0x10325476;
1099
1100 ctx->bits[0] = 0;
1101 ctx->bits[1] = 0;
1102}
1103
1104static void cs_md5_transform(uint32_t buf[4], uint32_t const in[16]) {
1105 register uint32_t a, b, c, d;
1106
1107 a = buf[0];
1108 b = buf[1];
1109 c = buf[2];
1110 d = buf[3];
1111
1112 MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
1113 MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
1114 MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
1115 MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
1116 MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
1117 MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
1118 MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
1119 MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
1120 MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
1121 MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
1122 MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
1123 MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
1124 MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
1125 MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
1126 MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
1127 MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
1128
1129 MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
1130 MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
1131 MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
1132 MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
1133 MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
1134 MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
1135 MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
1136 MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
1137 MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
1138 MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
1139 MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
1140 MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
1141 MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
1142 MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
1143 MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
1144 MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
1145
1146 MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
1147 MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
1148 MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
1149 MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
1150 MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
1151 MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
1152 MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
1153 MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
1154 MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
1155 MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
1156 MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
1157 MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
1158 MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
1159 MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
1160 MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
1161 MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
1162
1163 MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
1164 MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
1165 MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
1166 MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
1167 MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
1168 MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
1169 MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
1170 MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
1171 MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
1172 MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
1173 MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
1174 MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
1175 MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
1176 MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
1177 MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
1178 MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
1179
1180 buf[0] += a;
1181 buf[1] += b;
1182 buf[2] += c;
1183 buf[3] += d;
1184}
1185
1186void cs_md5_update(cs_md5_ctx *ctx, const unsigned char *buf, size_t len) {
1187 uint32_t t;
1188
1189 t = ctx->bits[0];
1190 if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) ctx->bits[1]++;
1191 ctx->bits[1] += (uint32_t) len >> 29;
1192
1193 t = (t >> 3) & 0x3f;
1194
1195 if (t) {
1196 unsigned char *p = (unsigned char *) ctx->in + t;
1197
1198 t = 64 - t;
1199 if (len < t) {
1200 memcpy(p, buf, len);
1201 return;
1202 }
1203 memcpy(p, buf, t);
1204 byteReverse(ctx->in, 16);
1205 cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
1206 buf += t;
1207 len -= t;
1208 }
1209
1210 while (len >= 64) {
1211 memcpy(ctx->in, buf, 64);
1212 byteReverse(ctx->in, 16);
1213 cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
1214 buf += 64;
1215 len -= 64;
1216 }
1217
1218 memcpy(ctx->in, buf, len);
1219}
1220
1221void cs_md5_final(unsigned char digest[16], cs_md5_ctx *ctx) {
1222 unsigned count;
1223 unsigned char *p;
1224 uint32_t *a;
1225
1226 count = (ctx->bits[0] >> 3) & 0x3F;
1227
1228 p = ctx->in + count;
1229 *p++ = 0x80;
1230 count = 64 - 1 - count;
1231 if (count < 8) {
1232 memset(p, 0, count);
1233 byteReverse(ctx->in, 16);
1234 cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
1235 memset(ctx->in, 0, 56);
1236 } else {
1237 memset(p, 0, count - 8);
1238 }
1239 byteReverse(ctx->in, 14);
1240
1241 a = (uint32_t *) ctx->in;
1242 a[14] = ctx->bits[0];
1243 a[15] = ctx->bits[1];
1244
1245 cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
1246 byteReverse((unsigned char *) ctx->buf, 4);
1247 memcpy(digest, ctx->buf, 16);
1248 memset((char *) ctx, 0, sizeof(*ctx));
1249}
1250
1251#endif /* CS_DISABLE_MD5 */
1252#endif /* EXCLUDE_COMMON */
1253#ifdef MG_MODULE_LINES
1254#line 1 "common/cs_sha1.c"
1255#endif
1256/* Copyright(c) By Steve Reid <steve@edmweb.com> */
1257/* 100% Public Domain */
1258
1259/* Amalgamated: #include "common/cs_sha1.h" */
1260
1261#if !CS_DISABLE_SHA1 && !defined(EXCLUDE_COMMON)
1262
1263/* Amalgamated: #include "common/cs_endian.h" */
1264
1265#define SHA1HANDSOFF
1266#if defined(__sun)
1267/* Amalgamated: #include "common/solarisfixes.h" */
1268#endif
1269
1270union char64long16 {
1271 unsigned char c[64];
1272 uint32_t l[16];
1273};
1274
1275#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
1276
1277static uint32_t blk0(union char64long16 *block, int i) {
1278/* Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN */
1279#if BYTE_ORDER == LITTLE_ENDIAN
1280 block->l[i] =
1281 (rol(block->l[i], 24) & 0xFF00FF00) | (rol(block->l[i], 8) & 0x00FF00FF);
1282#endif
1283 return block->l[i];
1284}
1285
1286/* Avoid redefine warning (ARM /usr/include/sys/ucontext.h define R0~R4) */
1287#undef blk
1288#undef R0
1289#undef R1
1290#undef R2
1291#undef R3
1292#undef R4
1293
1294#define blk(i) \
1295 (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ \
1296 block->l[(i + 2) & 15] ^ block->l[i & 15], \
1297 1))
1298#define R0(v, w, x, y, z, i) \
1299 z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \
1300 w = rol(w, 30);
1301#define R1(v, w, x, y, z, i) \
1302 z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
1303 w = rol(w, 30);
1304#define R2(v, w, x, y, z, i) \
1305 z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
1306 w = rol(w, 30);
1307#define R3(v, w, x, y, z, i) \
1308 z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
1309 w = rol(w, 30);
1310#define R4(v, w, x, y, z, i) \
1311 z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
1312 w = rol(w, 30);
1313
1314void cs_sha1_transform(uint32_t state[5], const unsigned char buffer[64]) {
1315 uint32_t a, b, c, d, e;
1316 union char64long16 block[1];
1317
1318 memcpy(block, buffer, 64);
1319 a = state[0];
1320 b = state[1];
1321 c = state[2];
1322 d = state[3];
1323 e = state[4];
1324 R0(a, b, c, d, e, 0);
1325 R0(e, a, b, c, d, 1);
1326 R0(d, e, a, b, c, 2);
1327 R0(c, d, e, a, b, 3);
1328 R0(b, c, d, e, a, 4);
1329 R0(a, b, c, d, e, 5);
1330 R0(e, a, b, c, d, 6);
1331 R0(d, e, a, b, c, 7);
1332 R0(c, d, e, a, b, 8);
1333 R0(b, c, d, e, a, 9);
1334 R0(a, b, c, d, e, 10);
1335 R0(e, a, b, c, d, 11);
1336 R0(d, e, a, b, c, 12);
1337 R0(c, d, e, a, b, 13);
1338 R0(b, c, d, e, a, 14);
1339 R0(a, b, c, d, e, 15);
1340 R1(e, a, b, c, d, 16);
1341 R1(d, e, a, b, c, 17);
1342 R1(c, d, e, a, b, 18);
1343 R1(b, c, d, e, a, 19);
1344 R2(a, b, c, d, e, 20);
1345 R2(e, a, b, c, d, 21);
1346 R2(d, e, a, b, c, 22);
1347 R2(c, d, e, a, b, 23);
1348 R2(b, c, d, e, a, 24);
1349 R2(a, b, c, d, e, 25);
1350 R2(e, a, b, c, d, 26);
1351 R2(d, e, a, b, c, 27);
1352 R2(c, d, e, a, b, 28);
1353 R2(b, c, d, e, a, 29);
1354 R2(a, b, c, d, e, 30);
1355 R2(e, a, b, c, d, 31);
1356 R2(d, e, a, b, c, 32);
1357 R2(c, d, e, a, b, 33);
1358 R2(b, c, d, e, a, 34);
1359 R2(a, b, c, d, e, 35);
1360 R2(e, a, b, c, d, 36);
1361 R2(d, e, a, b, c, 37);
1362 R2(c, d, e, a, b, 38);
1363 R2(b, c, d, e, a, 39);
1364 R3(a, b, c, d, e, 40);
1365 R3(e, a, b, c, d, 41);
1366 R3(d, e, a, b, c, 42);
1367 R3(c, d, e, a, b, 43);
1368 R3(b, c, d, e, a, 44);
1369 R3(a, b, c, d, e, 45);
1370 R3(e, a, b, c, d, 46);
1371 R3(d, e, a, b, c, 47);
1372 R3(c, d, e, a, b, 48);
1373 R3(b, c, d, e, a, 49);
1374 R3(a, b, c, d, e, 50);
1375 R3(e, a, b, c, d, 51);
1376 R3(d, e, a, b, c, 52);
1377 R3(c, d, e, a, b, 53);
1378 R3(b, c, d, e, a, 54);
1379 R3(a, b, c, d, e, 55);
1380 R3(e, a, b, c, d, 56);
1381 R3(d, e, a, b, c, 57);
1382 R3(c, d, e, a, b, 58);
1383 R3(b, c, d, e, a, 59);
1384 R4(a, b, c, d, e, 60);
1385 R4(e, a, b, c, d, 61);
1386 R4(d, e, a, b, c, 62);
1387 R4(c, d, e, a, b, 63);
1388 R4(b, c, d, e, a, 64);
1389 R4(a, b, c, d, e, 65);
1390 R4(e, a, b, c, d, 66);
1391 R4(d, e, a, b, c, 67);
1392 R4(c, d, e, a, b, 68);
1393 R4(b, c, d, e, a, 69);
1394 R4(a, b, c, d, e, 70);
1395 R4(e, a, b, c, d, 71);
1396 R4(d, e, a, b, c, 72);
1397 R4(c, d, e, a, b, 73);
1398 R4(b, c, d, e, a, 74);
1399 R4(a, b, c, d, e, 75);
1400 R4(e, a, b, c, d, 76);
1401 R4(d, e, a, b, c, 77);
1402 R4(c, d, e, a, b, 78);
1403 R4(b, c, d, e, a, 79);
1404 state[0] += a;
1405 state[1] += b;
1406 state[2] += c;
1407 state[3] += d;
1408 state[4] += e;
1409 /* Erase working structures. The order of operations is important,
1410 * used to ensure that compiler doesn't optimize those out. */
1411 memset(block, 0, sizeof(block));
1412 a = b = c = d = e = 0;
1413 (void) a;
1414 (void) b;
1415 (void) c;
1416 (void) d;
1417 (void) e;
1418}
1419
1421 context->state[0] = 0x67452301;
1422 context->state[1] = 0xEFCDAB89;
1423 context->state[2] = 0x98BADCFE;
1424 context->state[3] = 0x10325476;
1425 context->state[4] = 0xC3D2E1F0;
1426 context->count[0] = context->count[1] = 0;
1427}
1428
1429void cs_sha1_update(cs_sha1_ctx *context, const unsigned char *data,
1430 uint32_t len) {
1431 uint32_t i, j;
1432
1433 j = context->count[0];
1434 if ((context->count[0] += len << 3) < j) context->count[1]++;
1435 context->count[1] += (len >> 29);
1436 j = (j >> 3) & 63;
1437 if ((j + len) > 63) {
1438 memcpy(&context->buffer[j], data, (i = 64 - j));
1439 cs_sha1_transform(context->state, context->buffer);
1440 for (; i + 63 < len; i += 64) {
1441 cs_sha1_transform(context->state, &data[i]);
1442 }
1443 j = 0;
1444 } else
1445 i = 0;
1446 memcpy(&context->buffer[j], &data[i], len - i);
1447}
1448
1449void cs_sha1_final(unsigned char digest[20], cs_sha1_ctx *context) {
1450 unsigned i;
1451 unsigned char finalcount[8], c;
1452
1453 for (i = 0; i < 8; i++) {
1454 finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >>
1455 ((3 - (i & 3)) * 8)) &
1456 255);
1457 }
1458 c = 0200;
1459 cs_sha1_update(context, &c, 1);
1460 while ((context->count[0] & 504) != 448) {
1461 c = 0000;
1462 cs_sha1_update(context, &c, 1);
1463 }
1464 cs_sha1_update(context, finalcount, 8);
1465 for (i = 0; i < 20; i++) {
1466 digest[i] =
1467 (unsigned char) ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
1468 }
1469 memset(context, '\0', sizeof(*context));
1470 memset(&finalcount, '\0', sizeof(finalcount));
1471}
1472
1473void cs_hmac_sha1(const unsigned char *key, size_t keylen,
1474 const unsigned char *data, size_t datalen,
1475 unsigned char out[20]) {
1476 cs_sha1_ctx ctx;
1477 unsigned char buf1[64], buf2[64], tmp_key[20], i;
1478
1479 if (keylen > sizeof(buf1)) {
1480 cs_sha1_init(&ctx);
1481 cs_sha1_update(&ctx, key, keylen);
1482 cs_sha1_final(tmp_key, &ctx);
1483 key = tmp_key;
1484 keylen = sizeof(tmp_key);
1485 }
1486
1487 memset(buf1, 0, sizeof(buf1));
1488 memset(buf2, 0, sizeof(buf2));
1489 memcpy(buf1, key, keylen);
1490 memcpy(buf2, key, keylen);
1491
1492 for (i = 0; i < sizeof(buf1); i++) {
1493 buf1[i] ^= 0x36;
1494 buf2[i] ^= 0x5c;
1495 }
1496
1497 cs_sha1_init(&ctx);
1498 cs_sha1_update(&ctx, buf1, sizeof(buf1));
1499 cs_sha1_update(&ctx, data, datalen);
1500 cs_sha1_final(out, &ctx);
1501
1502 cs_sha1_init(&ctx);
1503 cs_sha1_update(&ctx, buf2, sizeof(buf2));
1504 cs_sha1_update(&ctx, out, 20);
1505 cs_sha1_final(out, &ctx);
1506}
1507
1508#endif /* EXCLUDE_COMMON */
1509#ifdef MG_MODULE_LINES
1510#line 1 "common/mbuf.c"
1511#endif
1512/*
1513 * Copyright (c) 2014-2018 Cesanta Software Limited
1514 * All rights reserved
1515 *
1516 * Licensed under the Apache License, Version 2.0 (the ""License"");
1517 * you may not use this file except in compliance with the License.
1518 * You may obtain a copy of the License at
1519 *
1520 * http://www.apache.org/licenses/LICENSE-2.0
1521 *
1522 * Unless required by applicable law or agreed to in writing, software
1523 * distributed under the License is distributed on an ""AS IS"" BASIS,
1524 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1525 * See the License for the specific language governing permissions and
1526 * limitations under the License.
1527 */
1528
1529#ifndef EXCLUDE_COMMON
1530
1531#include <assert.h>
1532#include <string.h>
1533/* Amalgamated: #include "common/mbuf.h" */
1534
1535#ifndef MBUF_REALLOC
1536#define MBUF_REALLOC realloc
1537#endif
1538
1539#ifndef MBUF_FREE
1540#define MBUF_FREE free
1541#endif
1542
1543void mbuf_init(struct mbuf *mbuf, size_t initial_size) WEAK;
1544void mbuf_init(struct mbuf *mbuf, size_t initial_size) {
1545 mbuf->len = mbuf->size = 0;
1546 mbuf->buf = NULL;
1548}
1549
1550void mbuf_free(struct mbuf *mbuf) WEAK;
1551void mbuf_free(struct mbuf *mbuf) {
1552 if (mbuf->buf != NULL) {
1553 MBUF_FREE(mbuf->buf);
1554 mbuf_init(mbuf, 0);
1555 }
1556}
1557
1558void mbuf_resize(struct mbuf *a, size_t new_size) WEAK;
1559void mbuf_resize(struct mbuf *a, size_t new_size) {
1560 if (new_size > a->size || (new_size < a->size && new_size >= a->len)) {
1561 char *buf = (char *) MBUF_REALLOC(a->buf, new_size);
1562 /*
1563 * In case realloc fails, there's not much we can do, except keep things as
1564 * they are. Note that NULL is a valid return value from realloc when
1565 * size == 0, but that is covered too.
1566 */
1567 if (buf == NULL && new_size != 0) return;
1568 a->buf = buf;
1569 a->size = new_size;
1570 }
1571}
1572
1573void mbuf_trim(struct mbuf *mbuf) WEAK;
1574void mbuf_trim(struct mbuf *mbuf) {
1576}
1577
1578size_t mbuf_insert(struct mbuf *a, size_t off, const void *buf, size_t) WEAK;
1579size_t mbuf_insert(struct mbuf *a, size_t off, const void *buf, size_t len) {
1580 char *p = NULL;
1581
1582 assert(a != NULL);
1583 assert(a->len <= a->size);
1584 assert(off <= a->len);
1585
1586 /* check overflow */
1587 if (~(size_t) 0 - (size_t) a->buf < len) return 0;
1588
1589 if (a->len + len <= a->size) {
1590 memmove(a->buf + off + len, a->buf + off, a->len - off);
1591 if (buf != NULL) {
1592 memcpy(a->buf + off, buf, len);
1593 }
1594 a->len += len;
1595 } else {
1596 size_t min_size = (a->len + len);
1600 }
1601 p = (char *) MBUF_REALLOC(a->buf, new_size);
1602 if (p == NULL && new_size != min_size) {
1604 p = (char *) MBUF_REALLOC(a->buf, new_size);
1605 }
1606 if (p != NULL) {
1607 a->buf = p;
1608 if (off != a->len) {
1609 memmove(a->buf + off + len, a->buf + off, a->len - off);
1610 }
1611 if (buf != NULL) memcpy(a->buf + off, buf, len);
1612 a->len += len;
1613 a->size = new_size;
1614 } else {
1615 len = 0;
1616 }
1617 }
1618
1619 return len;
1620}
1621
1622size_t mbuf_append(struct mbuf *a, const void *buf, size_t len) WEAK;
1623size_t mbuf_append(struct mbuf *a, const void *buf, size_t len) {
1624 return mbuf_insert(a, a->len, buf, len);
1625}
1626
1627size_t mbuf_append_and_free(struct mbuf *a, void *buf, size_t len) WEAK;
1628size_t mbuf_append_and_free(struct mbuf *a, void *data, size_t len) {
1629 size_t ret;
1630 /* Optimization: if the buffer is currently empty,
1631 * take over the user-provided buffer. */
1632 if (a->len == 0) {
1633 if (a->buf != NULL) free(a->buf);
1634 a->buf = (char *) data;
1635 a->len = a->size = len;
1636 return len;
1637 }
1638 ret = mbuf_insert(a, a->len, data, len);
1639 free(data);
1640 return ret;
1641}
1642
1643void mbuf_remove(struct mbuf *mb, size_t n) WEAK;
1644void mbuf_remove(struct mbuf *mb, size_t n) {
1645 if (n > 0 && n <= mb->len) {
1646 memmove(mb->buf, mb->buf + n, mb->len - n);
1647 mb->len -= n;
1648 }
1649}
1650
1651void mbuf_clear(struct mbuf *mb) WEAK;
1652void mbuf_clear(struct mbuf *mb) {
1653 mb->len = 0;
1654}
1655
1656void mbuf_move(struct mbuf *from, struct mbuf *to) WEAK;
1657void mbuf_move(struct mbuf *from, struct mbuf *to) {
1658 memcpy(to, from, sizeof(*to));
1659 memset(from, 0, sizeof(*from));
1660}
1661
1662#endif /* EXCLUDE_COMMON */
1663#ifdef MG_MODULE_LINES
1664#line 1 "common/mg_str.c"
1665#endif
1666/*
1667 * Copyright (c) 2014-2018 Cesanta Software Limited
1668 * All rights reserved
1669 *
1670 * Licensed under the Apache License, Version 2.0 (the ""License"");
1671 * you may not use this file except in compliance with the License.
1672 * You may obtain a copy of the License at
1673 *
1674 * http://www.apache.org/licenses/LICENSE-2.0
1675 *
1676 * Unless required by applicable law or agreed to in writing, software
1677 * distributed under the License is distributed on an ""AS IS"" BASIS,
1678 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1679 * See the License for the specific language governing permissions and
1680 * limitations under the License.
1681 */
1682
1683/* Amalgamated: #include "common/mg_mem.h" */
1684/* Amalgamated: #include "common/mg_str.h" */
1685/* Amalgamated: #include "common/platform.h" */
1686
1687#include <ctype.h>
1688#include <stdlib.h>
1689#include <string.h>
1690
1691int mg_ncasecmp(const char *s1, const char *s2, size_t len) WEAK;
1692
1693struct mg_str mg_mk_str(const char *s) WEAK;
1695 struct mg_str ret = {s, 0};
1696 if (s != NULL) ret.len = strlen(s);
1697 return ret;
1698}
1699
1700struct mg_str mg_mk_str_n(const char *s, size_t len) WEAK;
1701struct mg_str mg_mk_str_n(const char *s, size_t len) {
1702 struct mg_str ret = {s, len};
1703 return ret;
1704}
1705
1706int mg_vcmp(const struct mg_str *str1, const char *str2) WEAK;
1707int mg_vcmp(const struct mg_str *str1, const char *str2) {
1708 size_t n2 = strlen(str2), n1 = str1->len;
1709 int r = strncmp(str1->p, str2, (n1 < n2) ? n1 : n2);
1710 if (r == 0) {
1711 return n1 - n2;
1712 }
1713 return r;
1714}
1715
1716int mg_vcasecmp(const struct mg_str *str1, const char *str2) WEAK;
1717int mg_vcasecmp(const struct mg_str *str1, const char *str2) {
1718 size_t n2 = strlen(str2), n1 = str1->len;
1719 int r = mg_ncasecmp(str1->p, str2, (n1 < n2) ? n1 : n2);
1720 if (r == 0) {
1721 return n1 - n2;
1722 }
1723 return r;
1724}
1725
1728 struct mg_str r = {NULL, 0};
1729 if (s.len > 0 && s.p != NULL) {
1730 char *sc = (char *) MG_MALLOC(s.len + (nul_terminate ? 1 : 0));
1731 if (sc != NULL) {
1732 memcpy(sc, s.p, s.len);
1733 if (nul_terminate) sc[s.len] = '\0';
1734 r.p = sc;
1735 r.len = s.len;
1736 }
1737 }
1738 return r;
1739}
1740
1743 return mg_strdup_common(s, 0 /* NUL-terminate */);
1744}
1745
1748 return mg_strdup_common(s, 1 /* NUL-terminate */);
1749}
1750
1751const char *mg_strchr(const struct mg_str s, int c) WEAK;
1752const char *mg_strchr(const struct mg_str s, int c) {
1753 size_t i;
1754 for (i = 0; i < s.len; i++) {
1755 if (s.p[i] == c) return &s.p[i];
1756 }
1757 return NULL;
1758}
1759
1760int mg_strcmp(const struct mg_str str1, const struct mg_str str2) WEAK;
1761int mg_strcmp(const struct mg_str str1, const struct mg_str str2) {
1762 size_t i = 0;
1763 while (i < str1.len && i < str2.len) {
1764 if (str1.p[i] < str2.p[i]) return -1;
1765 if (str1.p[i] > str2.p[i]) return 1;
1766 i++;
1767 }
1768 if (i < str1.len) return 1;
1769 if (i < str2.len) return -1;
1770 return 0;
1771}
1772
1773int mg_strncmp(const struct mg_str, const struct mg_str, size_t n) WEAK;
1774int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n) {
1775 struct mg_str s1 = str1;
1776 struct mg_str s2 = str2;
1777
1778 if (s1.len > n) {
1779 s1.len = n;
1780 }
1781 if (s2.len > n) {
1782 s2.len = n;
1783 }
1784 return mg_strcmp(s1, s2);
1785}
1786
1787void mg_strfree(struct mg_str *s) WEAK;
1788void mg_strfree(struct mg_str *s) {
1789 char *sp = (char *) s->p;
1790 s->p = NULL;
1791 s->len = 0;
1792 if (sp != NULL) free(sp);
1793}
1794
1795const char *mg_strstr(const struct mg_str haystack,
1796 const struct mg_str needle) WEAK;
1797const char *mg_strstr(const struct mg_str haystack,
1798 const struct mg_str needle) {
1799 size_t i;
1800 if (needle.len > haystack.len) return NULL;
1801 for (i = 0; i <= haystack.len - needle.len; i++) {
1802 if (memcmp(haystack.p + i, needle.p, needle.len) == 0) {
1803 return haystack.p + i;
1804 }
1805 }
1806 return NULL;
1807}
1808
1811 while (s.len > 0 && isspace((int) *s.p)) {
1812 s.p++;
1813 s.len--;
1814 }
1815 while (s.len > 0 && isspace((int) *(s.p + s.len - 1))) {
1816 s.len--;
1817 }
1818 return s;
1819}
1820
1821int mg_str_starts_with(struct mg_str s, struct mg_str prefix) WEAK;
1823 const struct mg_str sp = MG_MK_STR_N(s.p, prefix.len);
1824 if (s.len < prefix.len) return 0;
1825 return (mg_strcmp(sp, prefix) == 0);
1826}
1827#ifdef MG_MODULE_LINES
1828#line 1 "common/str_util.c"
1829#endif
1830/*
1831 * Copyright (c) 2014-2018 Cesanta Software Limited
1832 * All rights reserved
1833 *
1834 * Licensed under the Apache License, Version 2.0 (the ""License"");
1835 * you may not use this file except in compliance with the License.
1836 * You may obtain a copy of the License at
1837 *
1838 * http://www.apache.org/licenses/LICENSE-2.0
1839 *
1840 * Unless required by applicable law or agreed to in writing, software
1841 * distributed under the License is distributed on an ""AS IS"" BASIS,
1842 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1843 * See the License for the specific language governing permissions and
1844 * limitations under the License.
1845 */
1846
1847#ifndef EXCLUDE_COMMON
1848
1849/* Amalgamated: #include "common/str_util.h" */
1850/* Amalgamated: #include "common/mg_mem.h" */
1851/* Amalgamated: #include "common/platform.h" */
1852
1853#ifndef C_DISABLE_BUILTIN_SNPRINTF
1854#define C_DISABLE_BUILTIN_SNPRINTF 0
1855#endif
1856
1857/* Amalgamated: #include "common/mg_mem.h" */
1858
1859size_t c_strnlen(const char *s, size_t maxlen) WEAK;
1860size_t c_strnlen(const char *s, size_t maxlen) {
1861 size_t l = 0;
1862 for (; l < maxlen && s[l] != '\0'; l++) {
1863 }
1864 return l;
1865}
1866
1867#define C_SNPRINTF_APPEND_CHAR(ch) \
1868 do { \
1869 if (i < (int) buf_size) buf[i] = ch; \
1870 i++; \
1871 } while (0)
1872
1873#define C_SNPRINTF_FLAG_ZERO 1
1874
1875#if C_DISABLE_BUILTIN_SNPRINTF
1876int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) WEAK;
1877int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) {
1878 return vsnprintf(buf, buf_size, fmt, ap);
1879}
1880#else
1881static int c_itoa(char *buf, size_t buf_size, int64_t num, int base, int flags,
1882 int field_width) {
1883 char tmp[40];
1884 int i = 0, k = 0, neg = 0;
1885
1886 if (num < 0) {
1887 neg++;
1888 num = -num;
1889 }
1890
1891 /* Print into temporary buffer - in reverse order */
1892 do {
1893 int rem = num % base;
1894 if (rem < 10) {
1895 tmp[k++] = '0' + rem;
1896 } else {
1897 tmp[k++] = 'a' + (rem - 10);
1898 }
1899 num /= base;
1900 } while (num > 0);
1901
1902 /* Zero padding */
1903 if (flags && C_SNPRINTF_FLAG_ZERO) {
1904 while (k < field_width && k < (int) sizeof(tmp) - 1) {
1905 tmp[k++] = '0';
1906 }
1907 }
1908
1909 /* And sign */
1910 if (neg) {
1911 tmp[k++] = '-';
1912 }
1913
1914 /* Now output */
1915 while (--k >= 0) {
1917 }
1918
1919 return i;
1920}
1921
1922int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) WEAK;
1923int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) {
1924 int ch, i = 0, len_mod, flags, precision, field_width;
1925
1926 while ((ch = *fmt++) != '\0') {
1927 if (ch != '%') {
1929 } else {
1930 /*
1931 * Conversion specification:
1932 * zero or more flags (one of: # 0 - <space> + ')
1933 * an optional minimum field width (digits)
1934 * an optional precision (. followed by digits, or *)
1935 * an optional length modifier (one of: hh h l ll L q j z t)
1936 * conversion specifier (one of: d i o u x X e E f F g G a A c s p n)
1937 */
1938 flags = field_width = precision = len_mod = 0;
1939
1940 /* Flags. only zero-pad flag is supported. */
1941 if (*fmt == '0') {
1942 flags |= C_SNPRINTF_FLAG_ZERO;
1943 }
1944
1945 /* Field width */
1946 while (*fmt >= '0' && *fmt <= '9') {
1947 field_width *= 10;
1948 field_width += *fmt++ - '0';
1949 }
1950 /* Dynamic field width */
1951 if (*fmt == '*') {
1952 field_width = va_arg(ap, int);
1953 fmt++;
1954 }
1955
1956 /* Precision */
1957 if (*fmt == '.') {
1958 fmt++;
1959 if (*fmt == '*') {
1960 precision = va_arg(ap, int);
1961 fmt++;
1962 } else {
1963 while (*fmt >= '0' && *fmt <= '9') {
1964 precision *= 10;
1965 precision += *fmt++ - '0';
1966 }
1967 }
1968 }
1969
1970 /* Length modifier */
1971 switch (*fmt) {
1972 case 'h':
1973 case 'l':
1974 case 'L':
1975 case 'I':
1976 case 'q':
1977 case 'j':
1978 case 'z':
1979 case 't':
1980 len_mod = *fmt++;
1981 if (*fmt == 'h') {
1982 len_mod = 'H';
1983 fmt++;
1984 }
1985 if (*fmt == 'l') {
1986 len_mod = 'q';
1987 fmt++;
1988 }
1989 break;
1990 }
1991
1992 ch = *fmt++;
1993 if (ch == 's') {
1994 const char *s = va_arg(ap, const char *); /* Always fetch parameter */
1995 int j;
1996 int pad = field_width - (precision >= 0 ? c_strnlen(s, precision) : 0);
1997 for (j = 0; j < pad; j++) {
1999 }
2000
2001 /* `s` may be NULL in case of %.*s */
2002 if (s != NULL) {
2003 /* Ignore negative and 0 precisions */
2004 for (j = 0; (precision <= 0 || j < precision) && s[j] != '\0'; j++) {
2006 }
2007 }
2008 } else if (ch == 'c') {
2009 ch = va_arg(ap, int); /* Always fetch parameter */
2011 } else if (ch == 'd' && len_mod == 0) {
2012 i += c_itoa(buf + i, buf_size - i, va_arg(ap, int), 10, flags,
2013 field_width);
2014 } else if (ch == 'd' && len_mod == 'l') {
2015 i += c_itoa(buf + i, buf_size - i, va_arg(ap, long), 10, flags,
2016 field_width);
2017#ifdef SSIZE_MAX
2018 } else if (ch == 'd' && len_mod == 'z') {
2019 i += c_itoa(buf + i, buf_size - i, va_arg(ap, ssize_t), 10, flags,
2020 field_width);
2021#endif
2022 } else if (ch == 'd' && len_mod == 'q') {
2023 i += c_itoa(buf + i, buf_size - i, va_arg(ap, int64_t), 10, flags,
2024 field_width);
2025 } else if ((ch == 'x' || ch == 'u') && len_mod == 0) {
2026 i += c_itoa(buf + i, buf_size - i, va_arg(ap, unsigned),
2027 ch == 'x' ? 16 : 10, flags, field_width);
2028 } else if ((ch == 'x' || ch == 'u') && len_mod == 'l') {
2029 i += c_itoa(buf + i, buf_size - i, va_arg(ap, unsigned long),
2030 ch == 'x' ? 16 : 10, flags, field_width);
2031 } else if ((ch == 'x' || ch == 'u') && len_mod == 'z') {
2032 i += c_itoa(buf + i, buf_size - i, va_arg(ap, size_t),
2033 ch == 'x' ? 16 : 10, flags, field_width);
2034 } else if (ch == 'p') {
2035 unsigned long num = (unsigned long) (uintptr_t) va_arg(ap, void *);
2038 i += c_itoa(buf + i, buf_size - i, num, 16, flags, 0);
2039 } else {
2040#ifndef NO_LIBC
2041 /*
2042 * TODO(lsm): abort is not nice in a library, remove it
2043 * Also, ESP8266 SDK doesn't have it
2044 */
2045 abort();
2046#endif
2047 }
2048 }
2049 }
2050
2051 /* Zero-terminate the result */
2052 if (buf_size > 0) {
2053 buf[i < (int) buf_size ? i : (int) buf_size - 1] = '\0';
2054 }
2055
2056 return i;
2057}
2058#endif
2059
2060int c_snprintf(char *buf, size_t buf_size, const char *fmt, ...) WEAK;
2061int c_snprintf(char *buf, size_t buf_size, const char *fmt, ...) {
2062 int result;
2063 va_list ap;
2064 va_start(ap, fmt);
2065 result = c_vsnprintf(buf, buf_size, fmt, ap);
2066 va_end(ap);
2067 return result;
2068}
2069
2070#ifdef _WIN32
2071int to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len) {
2072 int ret;
2073 char buf[MAX_PATH * 2], buf2[MAX_PATH * 2], *p;
2074
2075 strncpy(buf, path, sizeof(buf));
2076 buf[sizeof(buf) - 1] = '\0';
2077
2078 /* Trim trailing slashes. Leave backslash for paths like "X:\" */
2079 p = buf + strlen(buf) - 1;
2080 while (p > buf && p[-1] != ':' && (p[0] == '\\' || p[0] == '/')) *p-- = '\0';
2081
2082 memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
2083 ret = MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
2084
2085 /*
2086 * Convert back to Unicode. If doubly-converted string does not match the
2087 * original, something is fishy, reject.
2088 */
2089 WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
2090 NULL, NULL);
2091 if (strcmp(buf, buf2) != 0) {
2092 wbuf[0] = L'\0';
2093 ret = 0;
2094 }
2095
2096 return ret;
2097}
2098#endif /* _WIN32 */
2099
2100/* The simplest O(mn) algorithm. Better implementation are GPLed */
2101const char *c_strnstr(const char *s, const char *find, size_t slen) WEAK;
2102const char *c_strnstr(const char *s, const char *find, size_t slen) {
2103 size_t find_length = strlen(find);
2104 size_t i;
2105
2106 for (i = 0; i < slen; i++) {
2107 if (i + find_length > slen) {
2108 return NULL;
2109 }
2110
2111 if (strncmp(&s[i], find, find_length) == 0) {
2112 return &s[i];
2113 }
2114 }
2115
2116 return NULL;
2117}
2118
2119#if CS_ENABLE_STRDUP
2120char *strdup(const char *src) WEAK;
2121char *strdup(const char *src) {
2122 size_t len = strlen(src) + 1;
2123 char *ret = MG_MALLOC(len);
2124 if (ret != NULL) {
2125 strcpy(ret, src);
2126 }
2127 return ret;
2128}
2129#endif
2130
2131void cs_to_hex(char *to, const unsigned char *p, size_t len) WEAK;
2132void cs_to_hex(char *to, const unsigned char *p, size_t len) {
2133 static const char *hex = "0123456789abcdef";
2134
2135 for (; len--; p++) {
2136 *to++ = hex[p[0] >> 4];
2137 *to++ = hex[p[0] & 0x0f];
2138 }
2139 *to = '\0';
2140}
2141
2142static int fourbit(int ch) {
2143 if (ch >= '0' && ch <= '9') {
2144 return ch - '0';
2145 } else if (ch >= 'a' && ch <= 'f') {
2146 return ch - 'a' + 10;
2147 } else if (ch >= 'A' && ch <= 'F') {
2148 return ch - 'A' + 10;
2149 }
2150 return 0;
2151}
2152
2153void cs_from_hex(char *to, const char *p, size_t len) WEAK;
2154void cs_from_hex(char *to, const char *p, size_t len) {
2155 size_t i;
2156
2157 for (i = 0; i < len; i += 2) {
2158 *to++ = (fourbit(p[i]) << 4) + fourbit(p[i + 1]);
2159 }
2160 *to = '\0';
2161}
2162
2163#if CS_ENABLE_TO64
2164int64_t cs_to64(const char *s) WEAK;
2165int64_t cs_to64(const char *s) {
2166 int64_t result = 0;
2167 int64_t neg = 1;
2168 while (*s && isspace((unsigned char) *s)) s++;
2169 if (*s == '-') {
2170 neg = -1;
2171 s++;
2172 }
2173 while (isdigit((unsigned char) *s)) {
2174 result *= 10;
2175 result += (*s - '0');
2176 s++;
2177 }
2178 return result * neg;
2179}
2180#endif
2181
2182static int str_util_lowercase(const char *s) {
2183 return tolower(*(const unsigned char *) s);
2184}
2185
2186int mg_ncasecmp(const char *s1, const char *s2, size_t len) WEAK;
2187int mg_ncasecmp(const char *s1, const char *s2, size_t len) {
2188 int diff = 0;
2189
2190 if (len > 0) do {
2192 } while (diff == 0 && s1[-1] != '\0' && --len > 0);
2193
2194 return diff;
2195}
2196
2197int mg_casecmp(const char *s1, const char *s2) WEAK;
2198int mg_casecmp(const char *s1, const char *s2) {
2199 return mg_ncasecmp(s1, s2, (size_t) ~0);
2200}
2201
2202int mg_asprintf(char **buf, size_t size, const char *fmt, ...) WEAK;
2203int mg_asprintf(char **buf, size_t size, const char *fmt, ...) {
2204 int ret;
2205 va_list ap;
2206 va_start(ap, fmt);
2207 ret = mg_avprintf(buf, size, fmt, ap);
2208 va_end(ap);
2209 return ret;
2210}
2211
2212int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap) WEAK;
2213int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap) {
2215 int len;
2216
2217 va_copy(ap_copy, ap);
2218 len = vsnprintf(*buf, size, fmt, ap_copy);
2219 va_end(ap_copy);
2220
2221 if (len < 0) {
2222 /* eCos and Windows are not standard-compliant and return -1 when
2223 * the buffer is too small. Keep allocating larger buffers until we
2224 * succeed or out of memory. */
2225 *buf = NULL; /* LCOV_EXCL_START */
2226 while (len < 0) {
2227 MG_FREE(*buf);
2228 if (size == 0) {
2229 size = 5;
2230 }
2231 size *= 2;
2232 if ((*buf = (char *) MG_MALLOC(size)) == NULL) {
2233 len = -1;
2234 break;
2235 }
2236 va_copy(ap_copy, ap);
2237 len = vsnprintf(*buf, size - 1, fmt, ap_copy);
2238 va_end(ap_copy);
2239 }
2240
2241 /*
2242 * Microsoft version of vsnprintf() is not always null-terminated, so put
2243 * the terminator manually
2244 */
2245 (*buf)[len] = 0;
2246 /* LCOV_EXCL_STOP */
2247 } else if (len >= (int) size) {
2248 /* Standard-compliant code path. Allocate a buffer that is large enough. */
2249 if ((*buf = (char *) MG_MALLOC(len + 1)) == NULL) {
2250 len = -1; /* LCOV_EXCL_LINE */
2251 } else { /* LCOV_EXCL_LINE */
2252 va_copy(ap_copy, ap);
2253 len = vsnprintf(*buf, len + 1, fmt, ap_copy);
2254 va_end(ap_copy);
2255 }
2256 }
2257
2258 return len;
2259}
2260
2261const char *mg_next_comma_list_entry(const char *, struct mg_str *,
2262 struct mg_str *) WEAK;
2263const char *mg_next_comma_list_entry(const char *list, struct mg_str *val,
2264 struct mg_str *eq_val) {
2266 return ret.p;
2267}
2268
2270 struct mg_str *eq_val) WEAK;
2272 struct mg_str *eq_val) {
2273 if (list.len == 0) {
2274 /* End of the list */
2275 list = mg_mk_str(NULL);
2276 } else {
2277 const char *chr = NULL;
2278 *val = list;
2279
2280 if ((chr = mg_strchr(*val, ',')) != NULL) {
2281 /* Comma found. Store length and shift the list ptr */
2282 val->len = chr - val->p;
2283 chr++;
2284 list.len -= (chr - list.p);
2285 list.p = chr;
2286 } else {
2287 /* This value is the last one */
2288 list = mg_mk_str_n(list.p + list.len, 0);
2289 }
2290
2291 if (eq_val != NULL) {
2292 /* Value has form "x=y", adjust pointers and lengths */
2293 /* so that val points to "x", and eq_val points to "y". */
2294 eq_val->len = 0;
2295 eq_val->p = (const char *) memchr(val->p, '=', val->len);
2296 if (eq_val->p != NULL) {
2297 eq_val->p++; /* Skip over '=' character */
2298 eq_val->len = val->p + val->len - eq_val->p;
2299 val->len = (eq_val->p - val->p) - 1;
2300 }
2301 }
2302 }
2303
2304 return list;
2305}
2306
2307size_t mg_match_prefix_n(const struct mg_str, const struct mg_str) WEAK;
2308size_t mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str) {
2309 const char *or_str;
2310 size_t res = 0, len = 0, i = 0, j = 0;
2311
2312 if ((or_str = (const char *) memchr(pattern.p, '|', pattern.len)) != NULL ||
2313 (or_str = (const char *) memchr(pattern.p, ',', pattern.len)) != NULL) {
2314 struct mg_str pstr = {pattern.p, (size_t)(or_str - pattern.p)};
2316 if (res > 0) return res;
2317 pstr.p = or_str + 1;
2318 pstr.len = (pattern.p + pattern.len) - (or_str + 1);
2319 return mg_match_prefix_n(pstr, str);
2320 }
2321
2322 for (; i < pattern.len && j < str.len; i++, j++) {
2323 if (pattern.p[i] == '?') {
2324 continue;
2325 } else if (pattern.p[i] == '*') {
2326 i++;
2327 if (i < pattern.len && pattern.p[i] == '*') {
2328 i++;
2329 len = str.len - j;
2330 } else {
2331 len = 0;
2332 while (j + len < str.len && str.p[j + len] != '/') len++;
2333 }
2334 if (i == pattern.len || (pattern.p[i] == '$' && i == pattern.len - 1))
2335 return j + len;
2336 do {
2337 const struct mg_str pstr = {pattern.p + i, pattern.len - i};
2338 const struct mg_str sstr = {str.p + j + len, str.len - j - len};
2340 } while (res == 0 && len != 0 && len-- > 0);
2341 return res == 0 ? 0 : j + res + len;
2342 } else if (str_util_lowercase(&pattern.p[i]) !=
2343 str_util_lowercase(&str.p[j])) {
2344 break;
2345 }
2346 }
2347 if (i < pattern.len && pattern.p[i] == '$') {
2348 return j == str.len ? str.len : 0;
2349 }
2350 return i == pattern.len ? j : 0;
2351}
2352
2353size_t mg_match_prefix(const char *, int, const char *) WEAK;
2354size_t mg_match_prefix(const char *pattern, int pattern_len, const char *str) {
2355 const struct mg_str pstr = {pattern, (size_t) pattern_len};
2356 struct mg_str s = {str, 0};
2357 if (str != NULL) s.len = strlen(str);
2358 return mg_match_prefix_n(pstr, s);
2359}
2360
2361#endif /* EXCLUDE_COMMON */
2362#ifdef MG_MODULE_LINES
2363#line 1 "mongoose/src/mg_net.c"
2364#endif
2365/*
2366 * Copyright (c) 2014 Cesanta Software Limited
2367 * All rights reserved
2368 *
2369 * This software is dual-licensed: you can redistribute it and/or modify
2370 * it under the terms of the GNU General Public License version 2 as
2371 * published by the Free Software Foundation. For the terms of this
2372 * license, see <http://www.gnu.org/licenses/>.
2373 *
2374 * You are free to use this software under the terms of the GNU General
2375 * Public License, but WITHOUT ANY WARRANTY; without even the implied
2376 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
2377 * See the GNU General Public License for more details.
2378 *
2379 * Alternatively, you can license this software under a commercial
2380 * license, as set out in <https://www.cesanta.com/license>.
2381 */
2382
2383/* Amalgamated: #include "common/cs_time.h" */
2384/* Amalgamated: #include "mg_dns.h" */
2385/* Amalgamated: #include "mg_internal.h" */
2386/* Amalgamated: #include "mg_resolv.h" */
2387/* Amalgamated: #include "mg_util.h" */
2388
2389#define MG_MAX_HOST_LEN 200
2390
2391#ifndef MG_TCP_IO_SIZE
2392#define MG_TCP_IO_SIZE 1460
2393#endif
2394#ifndef MG_UDP_IO_SIZE
2395#define MG_UDP_IO_SIZE 1460
2396#endif
2397
2398#define MG_COPY_COMMON_CONNECTION_OPTIONS(dst, src) \
2399 memcpy(dst, src, sizeof(*dst));
2400
2401/* Which flags can be pre-set by the user at connection creation time. */
2402#define _MG_ALLOWED_CONNECT_FLAGS_MASK \
2403 (MG_F_USER_1 | MG_F_USER_2 | MG_F_USER_3 | MG_F_USER_4 | MG_F_USER_5 | \
2404 MG_F_USER_6 | MG_F_WEBSOCKET_NO_DEFRAG | MG_F_ENABLE_BROADCAST)
2405/* Which flags should be modifiable by user's callbacks. */
2406#define _MG_CALLBACK_MODIFIABLE_FLAGS_MASK \
2407 (MG_F_USER_1 | MG_F_USER_2 | MG_F_USER_3 | MG_F_USER_4 | MG_F_USER_5 | \
2408 MG_F_USER_6 | MG_F_WEBSOCKET_NO_DEFRAG | MG_F_SEND_AND_CLOSE | \
2409 MG_F_CLOSE_IMMEDIATELY | MG_F_IS_WEBSOCKET | MG_F_DELETE_CHUNK)
2410
2411#ifndef intptr_t
2412#define intptr_t long
2413#endif
2414
2415MG_INTERNAL void mg_add_conn(struct mg_mgr *mgr, struct mg_connection *c) {
2416 DBG(("%p %p", mgr, c));
2417 c->mgr = mgr;
2418 c->next = mgr->active_connections;
2419 mgr->active_connections = c;
2420 c->prev = NULL;
2421 if (c->next != NULL) c->next->prev = c;
2422 if (c->sock != INVALID_SOCKET) {
2423 c->iface->vtable->add_conn(c);
2424 }
2425}
2426
2428 if (conn->prev == NULL) conn->mgr->active_connections = conn->next;
2429 if (conn->prev) conn->prev->next = conn->next;
2430 if (conn->next) conn->next->prev = conn->prev;
2431 conn->prev = conn->next = NULL;
2432 conn->iface->vtable->remove_conn(conn);
2433}
2434
2436 mg_event_handler_t ev_handler, void *user_data, int ev,
2437 void *ev_data) {
2438 if (ev_handler == NULL) {
2439 /*
2440 * If protocol handler is specified, call it. Otherwise, call user-specified
2441 * event handler.
2442 */
2444 }
2445 if (ev != MG_EV_POLL) {
2446 DBG(("%p %s ev=%d ev_data=%p flags=0x%lx rmbl=%d smbl=%d", nc,
2447 ev_handler == nc->handler ? "user" : "proto", ev, ev_data, nc->flags,
2448 (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
2449 }
2450
2451#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
2452 if (nc->mgr->hexdump_file != NULL && ev != MG_EV_POLL && ev != MG_EV_RECV &&
2453 ev != MG_EV_SEND /* handled separately */) {
2455 }
2456#endif
2457 if (ev_handler != NULL) {
2458 unsigned long flags_before = nc->flags;
2459 ev_handler(nc, ev, ev_data MG_UD_ARG(user_data));
2460 /* Prevent user handler from fiddling with system flags. */
2461 if (ev_handler == nc->handler && nc->flags != flags_before) {
2464 }
2465 }
2466 if (ev != MG_EV_POLL) nc->mgr->num_calls++;
2467 if (ev != MG_EV_POLL) {
2468 DBG(("%p after %s flags=0x%lx rmbl=%d smbl=%d", nc,
2469 ev_handler == nc->handler ? "user" : "proto", nc->flags,
2470 (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
2471 }
2472#if !MG_ENABLE_CALLBACK_USERDATA
2473 (void) user_data;
2474#endif
2475}
2476
2477MG_INTERNAL void mg_timer(struct mg_connection *c, double now) {
2478 if (c->ev_timer_time > 0 && now >= c->ev_timer_time) {
2479 double old_value = c->ev_timer_time;
2480 c->ev_timer_time = 0;
2481 mg_call(c, NULL, c->user_data, MG_EV_TIMER, &old_value);
2482 }
2483}
2484
2485MG_INTERNAL size_t recv_avail_size(struct mg_connection *conn, size_t max) {
2486 size_t avail;
2487 if (conn->recv_mbuf_limit < conn->recv_mbuf.len) return 0;
2488 avail = conn->recv_mbuf_limit - conn->recv_mbuf.len;
2489 return avail > max ? max : avail;
2490}
2491
2492static int mg_do_recv(struct mg_connection *nc);
2493
2494int mg_if_poll(struct mg_connection *nc, double now) {
2495 if (nc->flags & MG_F_CLOSE_IMMEDIATELY) {
2496 mg_close_conn(nc);
2497 return 0;
2498 } else if (nc->flags & MG_F_SEND_AND_CLOSE) {
2499 if (nc->send_mbuf.len == 0) {
2501 mg_close_conn(nc);
2502 return 0;
2503 }
2504 } else if (nc->flags & MG_F_RECV_AND_CLOSE) {
2505 mg_close_conn(nc);
2506 return 0;
2507 }
2508#if MG_ENABLE_SSL
2509 if ((nc->flags & (MG_F_SSL | MG_F_LISTENING | MG_F_CONNECTING)) == MG_F_SSL) {
2510 /* SSL library may have data to be delivered to the app in its buffers,
2511 * drain them. */
2512 int recved = 0;
2513 do {
2514 if (nc->flags & (MG_F_WANT_READ | MG_F_WANT_WRITE)) break;
2515 if (recv_avail_size(nc, MG_TCP_IO_SIZE) <= 0) break;
2516 recved = mg_do_recv(nc);
2517 } while (recved > 0);
2518 }
2519#endif /* MG_ENABLE_SSL */
2520 mg_timer(nc, now);
2521 {
2522 time_t now_t = (time_t) now;
2523 mg_call(nc, NULL, nc->user_data, MG_EV_POLL, &now_t);
2524 }
2525 return 1;
2526}
2527
2529 if (conn->sock != INVALID_SOCKET) { /* Don't print timer-only conns */
2530 LOG(LL_DEBUG, ("%p 0x%lx %d", conn, conn->flags, destroy_if));
2531 }
2532 if (destroy_if) conn->iface->vtable->destroy_conn(conn);
2533 if (conn->proto_data != NULL && conn->proto_data_destructor != NULL) {
2534 conn->proto_data_destructor(conn->proto_data);
2535 }
2536#if MG_ENABLE_SSL
2537 mg_ssl_if_conn_free(conn);
2538#endif
2539 mbuf_free(&conn->recv_mbuf);
2540 mbuf_free(&conn->send_mbuf);
2541
2542 memset(conn, 0, sizeof(*conn));
2543 MG_FREE(conn);
2544}
2545
2546void mg_close_conn(struct mg_connection *conn) {
2547 /* See if there's any remaining data to deliver. Skip if user completely
2548 * throttled the connection there will be no progress anyway. */
2549 if (conn->sock != INVALID_SOCKET && mg_do_recv(conn) == -2) {
2550 /* Receive is throttled, wait. */
2551 conn->flags |= MG_F_RECV_AND_CLOSE;
2552 return;
2553 }
2554#if MG_ENABLE_SSL
2555 if (conn->flags & MG_F_SSL_HANDSHAKE_DONE) {
2557 }
2558#endif
2559 /*
2560 * Clearly mark the connection as going away (if not already).
2561 * Some net_if impls (LwIP) need this for cleanly handling half-dead conns.
2562 */
2564 mg_remove_conn(conn);
2565 conn->iface->vtable->destroy_conn(conn);
2566 mg_call(conn, NULL, conn->user_data, MG_EV_CLOSE, NULL);
2567 mg_destroy_conn(conn, 0 /* destroy_if */);
2568}
2569
2570void mg_mgr_init(struct mg_mgr *m, void *user_data) {
2571 struct mg_mgr_init_opts opts;
2572 memset(&opts, 0, sizeof(opts));
2573 mg_mgr_init_opt(m, user_data, opts);
2574}
2575
2576void mg_mgr_init_opt(struct mg_mgr *m, void *user_data,
2577 struct mg_mgr_init_opts opts) {
2578 memset(m, 0, sizeof(*m));
2579#if MG_ENABLE_BROADCAST
2580 m->ctl[0] = m->ctl[1] = INVALID_SOCKET;
2581#endif
2582 m->user_data = user_data;
2583
2584#ifdef _WIN32
2585 {
2586 WSADATA data;
2587 WSAStartup(MAKEWORD(2, 2), &data);
2588 }
2589#elif defined(__unix__)
2590 /* Ignore SIGPIPE signal, so if client cancels the request, it
2591 * won't kill the whole process. */
2593#endif
2594
2595 {
2596 int i;
2597 if (opts.num_ifaces == 0) {
2598 opts.num_ifaces = mg_num_ifaces;
2599 opts.ifaces = mg_ifaces;
2600 }
2601 if (opts.main_iface != NULL) {
2602 opts.ifaces[MG_MAIN_IFACE] = opts.main_iface;
2603 }
2604 m->num_ifaces = opts.num_ifaces;
2605 m->ifaces =
2606 (struct mg_iface **) MG_MALLOC(sizeof(*m->ifaces) * opts.num_ifaces);
2607 for (i = 0; i < opts.num_ifaces; i++) {
2608 m->ifaces[i] = mg_if_create_iface(opts.ifaces[i], m);
2609 m->ifaces[i]->vtable->init(m->ifaces[i]);
2610 }
2611 }
2612 if (opts.nameserver != NULL) {
2613 m->nameserver = strdup(opts.nameserver);
2614 }
2615 DBG(("=================================="));
2616 DBG(("init mgr=%p", m));
2617#if MG_ENABLE_SSL
2618 {
2619 static int init_done;
2620 if (!init_done) {
2622 init_done++;
2623 }
2624 }
2625#endif
2626}
2627
2628void mg_mgr_free(struct mg_mgr *m) {
2629 struct mg_connection *conn, *tmp_conn;
2630
2631 DBG(("%p", m));
2632 if (m == NULL) return;
2633 /* Do one last poll, see https://github.com/cesanta/mongoose/issues/286 */
2634 mg_mgr_poll(m, 0);
2635
2636#if MG_ENABLE_BROADCAST
2637 if (m->ctl[0] != INVALID_SOCKET) closesocket(m->ctl[0]);
2638 if (m->ctl[1] != INVALID_SOCKET) closesocket(m->ctl[1]);
2639 m->ctl[0] = m->ctl[1] = INVALID_SOCKET;
2640#endif
2641
2642 for (conn = m->active_connections; conn != NULL; conn = tmp_conn) {
2643 tmp_conn = conn->next;
2645 mg_close_conn(conn);
2646 }
2647
2648 {
2649 int i;
2650 for (i = 0; i < m->num_ifaces; i++) {
2651 m->ifaces[i]->vtable->free(m->ifaces[i]);
2652 MG_FREE(m->ifaces[i]);
2653 }
2654 MG_FREE(m->ifaces);
2655 }
2656
2657 MG_FREE((char *) m->nameserver);
2658}
2659
2660int mg_mgr_poll(struct mg_mgr *m, int timeout_ms) {
2661 int i, num_calls_before = m->num_calls;
2662
2663 for (i = 0; i < m->num_ifaces; i++) {
2664 m->ifaces[i]->vtable->poll(m->ifaces[i], timeout_ms);
2665 }
2666
2667 return (m->num_calls - num_calls_before);
2668}
2669
2670int mg_vprintf(struct mg_connection *nc, const char *fmt, va_list ap) {
2672 int len;
2673
2674 if ((len = mg_avprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
2675 mg_send(nc, buf, len);
2676 }
2677 if (buf != mem && buf != NULL) {
2678 MG_FREE(buf); /* LCOV_EXCL_LINE */
2679 } /* LCOV_EXCL_LINE */
2680
2681 return len;
2682}
2683
2684int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
2685 int len;
2686 va_list ap;
2687 va_start(ap, fmt);
2688 len = mg_vprintf(conn, fmt, ap);
2689 va_end(ap);
2690 return len;
2691}
2692
2693#if MG_ENABLE_SYNC_RESOLVER
2694/* TODO(lsm): use non-blocking resolver */
2695static int mg_resolve2(const char *host, struct in_addr *ina) {
2696#if MG_ENABLE_GETADDRINFO
2697 int rv = 0;
2698 struct addrinfo hints, *servinfo, *p;
2699 struct sockaddr_in *h = NULL;
2700 memset(&hints, 0, sizeof hints);
2701 hints.ai_family = AF_INET;
2702 hints.ai_socktype = SOCK_STREAM;
2703 if ((rv = getaddrinfo(host, NULL, NULL, &servinfo)) != 0) {
2704 DBG(("getaddrinfo(%s) failed: %s", host, strerror(mg_get_errno())));
2705 return 0;
2706 }
2707 for (p = servinfo; p != NULL; p = p->ai_next) {
2708 memcpy(&h, &p->ai_addr, sizeof(struct sockaddr_in *));
2709 memcpy(ina, &h->sin_addr, sizeof(ina));
2710 }
2712 return 1;
2713#else
2714 struct hostent *he;
2715 if ((he = gethostbyname(host)) == NULL) {
2716 DBG(("gethostbyname(%s) failed: %s", host, strerror(mg_get_errno())));
2717 } else {
2718 memcpy(ina, he->h_addr_list[0], sizeof(*ina));
2719 return 1;
2720 }
2721 return 0;
2722#endif /* MG_ENABLE_GETADDRINFO */
2723}
2724
2725int mg_resolve(const char *host, char *buf, size_t n) {
2726 struct in_addr ad;
2727 return mg_resolve2(host, &ad) ? snprintf(buf, n, "%s", inet_ntoa(ad)) : 0;
2728}
2729#endif /* MG_ENABLE_SYNC_RESOLVER */
2730
2733 struct mg_add_sock_opts opts) {
2734 struct mg_connection *conn;
2735
2736 if ((conn = (struct mg_connection *) MG_CALLOC(1, sizeof(*conn))) != NULL) {
2737 conn->sock = INVALID_SOCKET;
2738 conn->handler = callback;
2739 conn->mgr = mgr;
2740 conn->last_io_time = (time_t) mg_time();
2741 conn->iface =
2742 (opts.iface != NULL ? opts.iface : mgr->ifaces[MG_MAIN_IFACE]);
2744 conn->user_data = opts.user_data;
2745 /*
2746 * SIZE_MAX is defined as a long long constant in
2747 * system headers on some platforms and so it
2748 * doesn't compile with pedantic ansi flags.
2749 */
2750 conn->recv_mbuf_limit = ~0;
2751 } else {
2752 MG_SET_PTRPTR(opts.error_string, "failed to create connection");
2753 }
2754
2755 return conn;
2756}
2757
2760 struct mg_add_sock_opts opts) {
2762
2763 if (conn != NULL && !conn->iface->vtable->create_conn(conn)) {
2764 MG_FREE(conn);
2765 conn = NULL;
2766 }
2767 if (conn == NULL) {
2768 MG_SET_PTRPTR(opts.error_string, "failed to init connection");
2769 }
2770
2771 return conn;
2772}
2773
2774/*
2775 * Address format: [PROTO://][HOST]:PORT
2776 *
2777 * HOST could be IPv4/IPv6 address or a host name.
2778 * `host` is a destination buffer to hold parsed HOST part. Should be at least
2779 * MG_MAX_HOST_LEN bytes long.
2780 * `proto` is a returned socket type, either SOCK_STREAM or SOCK_DGRAM
2781 *
2782 * Return:
2783 * -1 on parse error
2784 * 0 if HOST needs DNS lookup
2785 * >0 length of the address string
2786 */
2788 int *proto, char *host, size_t host_len) {
2789 unsigned int a, b, c, d, port = 0;
2790 int ch, len = 0;
2791#if MG_ENABLE_IPV6
2792 char buf[100];
2793#endif
2794
2795 /*
2796 * MacOS needs that. If we do not zero it, subsequent bind() will fail.
2797 * Also, all-zeroes in the socket address means binding to all addresses
2798 * for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT).
2799 */
2800 memset(sa, 0, sizeof(*sa));
2801 sa->sin.sin_family = AF_INET;
2802
2803 *proto = SOCK_STREAM;
2804
2805 if (strncmp(str, "udp://", 6) == 0) {
2806 str += 6;
2807 *proto = SOCK_DGRAM;
2808 } else if (strncmp(str, "tcp://", 6) == 0) {
2809 str += 6;
2810 }
2811
2812 if (sscanf(str, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len) == 5) {
2813 /* Bind to a specific IPv4 address, e.g. 192.168.1.5:8080 */
2814 sa->sin.sin_addr.s_addr =
2815 htonl(((uint32_t) a << 24) | ((uint32_t) b << 16) | c << 8 | d);
2816 sa->sin.sin_port = htons((uint16_t) port);
2817#if MG_ENABLE_IPV6
2818 } else if (sscanf(str, "[%99[^]]]:%u%n", buf, &port, &len) == 2 &&
2819 inet_pton(AF_INET6, buf, &sa->sin6.sin6_addr)) {
2820 /* IPv6 address, e.g. [3ffe:2a00:100:7031::1]:8080 */
2821 sa->sin6.sin6_family = AF_INET6;
2822 sa->sin.sin_port = htons((uint16_t) port);
2823#endif
2824#if MG_ENABLE_ASYNC_RESOLVER
2825 } else if (strlen(str) < host_len &&
2826 sscanf(str, "%[^ :]:%u%n", host, &port, &len) == 2) {
2827 sa->sin.sin_port = htons((uint16_t) port);
2828 if (mg_resolve_from_hosts_file(host, sa) != 0) {
2829 /*
2830 * if resolving from hosts file failed and the host
2831 * we are trying to resolve is `localhost` - we should
2832 * try to resolve it using `gethostbyname` and do not try
2833 * to resolve it via DNS server if gethostbyname has failed too
2834 */
2835 if (mg_ncasecmp(host, "localhost", 9) != 0) {
2836 return 0;
2837 }
2838
2839#if MG_ENABLE_SYNC_RESOLVER
2840 if (!mg_resolve2(host, &sa->sin.sin_addr)) {
2841 return -1;
2842 }
2843#else
2844 return -1;
2845#endif
2846 }
2847#endif
2848 } else if (sscanf(str, ":%u%n", &port, &len) == 1 ||
2849 sscanf(str, "%u%n", &port, &len) == 1) {
2850 /* If only port is specified, bind to IPv4, INADDR_ANY */
2851 sa->sin.sin_port = htons((uint16_t) port);
2852 } else {
2853 return -1;
2854 }
2855
2856 /* Required for MG_ENABLE_ASYNC_RESOLVER=0 */
2857 (void) host;
2858 (void) host_len;
2859
2860 ch = str[len]; /* Character that follows the address */
2861 return port < 0xffffUL && (ch == '\0' || ch == ',' || isspace(ch)) ? len : -1;
2862}
2863
2864#if MG_ENABLE_SSL
2866 int err = 0;
2867 int server_side = (nc->listener != NULL);
2868 enum mg_ssl_if_result res;
2869 if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) return;
2871
2872 if (res == MG_SSL_OK) {
2875 if (server_side) {
2876 mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
2877 } else {
2878 mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err);
2879 }
2880 } else if (res == MG_SSL_WANT_READ) {
2881 nc->flags |= MG_F_WANT_READ;
2882 } else if (res == MG_SSL_WANT_WRITE) {
2883 nc->flags |= MG_F_WANT_WRITE;
2884 } else {
2885 if (!server_side) {
2886 err = res;
2887 mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err);
2888 }
2890 }
2891}
2892#endif /* MG_ENABLE_SSL */
2893
2895 struct mg_add_sock_opts opts;
2896 struct mg_connection *nc;
2897 memset(&opts, 0, sizeof(opts));
2898 nc = mg_create_connection(lc->mgr, lc->handler, opts);
2899 if (nc == NULL) return NULL;
2900 nc->listener = lc;
2901 nc->proto_handler = lc->proto_handler;
2902 nc->user_data = lc->user_data;
2904 nc->iface = lc->iface;
2905 if (lc->flags & MG_F_SSL) nc->flags |= MG_F_SSL;
2906 mg_add_conn(nc->mgr, nc);
2907 LOG(LL_DEBUG, ("%p %p %d %d", lc, nc, nc->sock, (int) nc->flags));
2908 return nc;
2909}
2910
2912 size_t sa_len) {
2913 LOG(LL_DEBUG, ("%p %s://%s:%hu", nc, (nc->flags & MG_F_UDP ? "udp" : "tcp"),
2914 inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port)));
2915 nc->sa = *sa;
2916#if MG_ENABLE_SSL
2917 if (nc->listener->flags & MG_F_SSL) {
2918 nc->flags |= MG_F_SSL;
2919 if (mg_ssl_if_conn_accept(nc, nc->listener) == MG_SSL_OK) {
2920 mg_ssl_handshake(nc);
2921 } else {
2922 mg_close_conn(nc);
2923 }
2924 } else
2925#endif
2926 {
2927 mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
2928 }
2929 (void) sa_len;
2930}
2931
2932void mg_send(struct mg_connection *nc, const void *buf, int len) {
2933 nc->last_io_time = (time_t) mg_time();
2934 mbuf_append(&nc->send_mbuf, buf, len);
2935}
2936
2937static int mg_recv_tcp(struct mg_connection *nc, char *buf, size_t len);
2938static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len);
2939
2940static int mg_do_recv(struct mg_connection *nc) {
2941 int res = 0;
2942 char *buf = NULL;
2943 size_t len = (nc->flags & MG_F_UDP ? MG_UDP_IO_SIZE : MG_TCP_IO_SIZE);
2945 ((nc->flags & MG_F_LISTENING) && !(nc->flags & MG_F_UDP))) {
2946 return -1;
2947 }
2948 do {
2949 len = recv_avail_size(nc, len);
2950 if (len == 0) {
2951 res = -2;
2952 break;
2953 }
2954 if (nc->recv_mbuf.size < nc->recv_mbuf.len + len) {
2955 mbuf_resize(&nc->recv_mbuf, nc->recv_mbuf.len + len);
2956 }
2957 buf = nc->recv_mbuf.buf + nc->recv_mbuf.len;
2958 len = nc->recv_mbuf.size - nc->recv_mbuf.len;
2959 if (nc->flags & MG_F_UDP) {
2960 res = mg_recv_udp(nc, buf, len);
2961 } else {
2962 res = mg_recv_tcp(nc, buf, len);
2963 }
2964 } while (res > 0 && !(nc->flags & (MG_F_CLOSE_IMMEDIATELY | MG_F_UDP)));
2965 return res;
2966}
2967
2969 mg_do_recv(nc);
2970}
2971
2972static int mg_recv_tcp(struct mg_connection *nc, char *buf, size_t len) {
2973 int n = 0;
2974#if MG_ENABLE_SSL
2975 if (nc->flags & MG_F_SSL) {
2976 if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
2977 n = mg_ssl_if_read(nc, buf, len);
2978 DBG(("%p <- %d bytes (SSL)", nc, n));
2979 if (n < 0) {
2980 if (n == MG_SSL_WANT_READ) {
2981 nc->flags |= MG_F_WANT_READ;
2982 n = 0;
2983 } else {
2985 }
2986 } else if (n > 0) {
2987 nc->flags &= ~MG_F_WANT_READ;
2988 }
2989 } else {
2990 mg_ssl_handshake(nc);
2991 }
2992 } else
2993#endif
2994 {
2995 n = nc->iface->vtable->tcp_recv(nc, buf, len);
2996 DBG(("%p <- %d bytes", nc, n));
2997 }
2998 if (n > 0) {
2999 nc->recv_mbuf.len += n;
3000 nc->last_io_time = (time_t) mg_time();
3001#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
3002 if (nc->mgr && nc->mgr->hexdump_file != NULL) {
3004 }
3005#endif
3006 mbuf_trim(&nc->recv_mbuf);
3007 mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n);
3008 } else if (n < 0) {
3010 }
3011 mbuf_trim(&nc->recv_mbuf);
3012 return n;
3013}
3014
3015static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len) {
3016 int n = 0;
3017 struct mg_connection *lc = nc;
3018 union socket_address sa;
3019 size_t sa_len = sizeof(sa);
3020 n = nc->iface->vtable->udp_recv(lc, buf, len, &sa, &sa_len);
3021 if (n < 0) {
3023 goto out;
3024 }
3025 if (nc->flags & MG_F_LISTENING) {
3026 /*
3027 * Do we have an existing connection for this source?
3028 * This is very inefficient for long connection lists.
3029 */
3030 lc = nc;
3031 for (nc = mg_next(lc->mgr, NULL); nc != NULL; nc = mg_next(lc->mgr, nc)) {
3032 if (memcmp(&nc->sa.sa, &sa.sa, sa_len) == 0 && nc->listener == lc) {
3033 break;
3034 }
3035 }
3036 if (nc == NULL) {
3037 struct mg_add_sock_opts opts;
3038 memset(&opts, 0, sizeof(opts));
3039 /* Create fake connection w/out sock initialization */
3040 nc = mg_create_connection_base(lc->mgr, lc->handler, opts);
3041 if (nc != NULL) {
3042 nc->sock = lc->sock;
3043 nc->listener = lc;
3044 nc->sa = sa;
3045 nc->proto_handler = lc->proto_handler;
3046 nc->user_data = lc->user_data;
3048 nc->flags = MG_F_UDP;
3049 /*
3050 * Long-lived UDP "connections" i.e. interactions that involve more
3051 * than one request and response are rare, most are transactional:
3052 * response is sent and the "connection" is closed. Or - should be.
3053 * But users (including ourselves) tend to forget about that part,
3054 * because UDP is connectionless and one does not think about
3055 * processing a UDP request as handling a connection that needs to be
3056 * closed. Thus, we begin with SEND_AND_CLOSE flag set, which should
3057 * be a reasonable default for most use cases, but it is possible to
3058 * turn it off the connection should be kept alive after processing.
3059 */
3061 mg_add_conn(lc->mgr, nc);
3062 mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
3063 }
3064 }
3065 }
3066 if (nc != NULL) {
3067 DBG(("%p <- %d bytes from %s:%d", nc, n, inet_ntoa(nc->sa.sin.sin_addr),
3068 ntohs(nc->sa.sin.sin_port)));
3069 if (nc == lc) {
3070 nc->recv_mbuf.len += n;
3071 } else {
3072 mbuf_append(&nc->recv_mbuf, buf, n);
3073 }
3074 mbuf_trim(&lc->recv_mbuf);
3075 lc->last_io_time = nc->last_io_time = (time_t) mg_time();
3076#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
3077 if (nc->mgr && nc->mgr->hexdump_file != NULL) {
3079 }
3080#endif
3081 if (n != 0) {
3082 mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n);
3083 }
3084 }
3085
3086out:
3087 mbuf_free(&lc->recv_mbuf);
3088 return n;
3089}
3090
3092 int n = 0;
3093 const char *buf = nc->send_mbuf.buf;
3094 size_t len = nc->send_mbuf.len;
3095
3097 return;
3098 }
3099 if (!(nc->flags & MG_F_UDP)) {
3100 if (nc->flags & MG_F_LISTENING) return;
3101 if (len > MG_TCP_IO_SIZE) len = MG_TCP_IO_SIZE;
3102 }
3103#if MG_ENABLE_SSL
3104 if (nc->flags & MG_F_SSL) {
3105 if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
3106 if (len > 0) {
3107 n = mg_ssl_if_write(nc, buf, len);
3108 DBG(("%p -> %d bytes (SSL)", nc, n));
3109 }
3110 if (n < 0) {
3111 if (n == MG_SSL_WANT_WRITE) {
3112 nc->flags |= MG_F_WANT_WRITE;
3113 n = 0;
3114 } else {
3116 }
3117 } else {
3118 nc->flags &= ~MG_F_WANT_WRITE;
3119 }
3120 } else {
3121 mg_ssl_handshake(nc);
3122 }
3123 } else
3124#endif
3125 if (len > 0) {
3126 if (nc->flags & MG_F_UDP) {
3127 n = nc->iface->vtable->udp_send(nc, buf, len);
3128 } else {
3129 n = nc->iface->vtable->tcp_send(nc, buf, len);
3130 }
3131 DBG(("%p -> %d bytes", nc, n));
3132 }
3133
3134#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
3135 if (n > 0 && nc->mgr && nc->mgr->hexdump_file != NULL) {
3137 }
3138#endif
3139 if (n < 0) {
3141 } else if (n > 0) {
3142 nc->last_io_time = (time_t) mg_time();
3143 mbuf_remove(&nc->send_mbuf, n);
3144 mbuf_trim(&nc->send_mbuf);
3145 }
3146 if (n != 0) mg_call(nc, NULL, nc->user_data, MG_EV_SEND, &n);
3147}
3148
3149/*
3150 * Schedules an async connect for a resolved address and proto.
3151 * Called from two places: `mg_connect_opt()` and from async resolver.
3152 * When called from the async resolver, it must trigger `MG_EV_CONNECT` event
3153 * with a failure flag to indicate connection failure.
3154 */
3156 int proto,
3157 union socket_address *sa) {
3158 LOG(LL_DEBUG, ("%p %s://%s:%hu", nc, proto == SOCK_DGRAM ? "udp" : "tcp",
3159 inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port)));
3160
3161 nc->flags |= MG_F_CONNECTING;
3162 if (proto == SOCK_DGRAM) {
3163 nc->iface->vtable->connect_udp(nc);
3164 } else {
3165 nc->iface->vtable->connect_tcp(nc, sa);
3166 }
3167 mg_add_conn(nc->mgr, nc);
3168 return nc;
3169}
3170
3171void mg_if_connect_cb(struct mg_connection *nc, int err) {
3172 LOG(LL_DEBUG,
3173 ("%p %s://%s:%hu -> %d", nc, (nc->flags & MG_F_UDP ? "udp" : "tcp"),
3174 inet_ntoa(nc->sa.sin.sin_addr), ntohs(nc->sa.sin.sin_port), err));
3175 nc->flags &= ~MG_F_CONNECTING;
3176 if (err != 0) {
3178 }
3179#if MG_ENABLE_SSL
3180 if (err == 0 && (nc->flags & MG_F_SSL)) {
3181 mg_ssl_handshake(nc);
3182 } else
3183#endif
3184 {
3185 mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err);
3186 }
3187}
3188
3189#if MG_ENABLE_ASYNC_RESOLVER
3190/*
3191 * Callback for the async resolver on mg_connect_opt() call.
3192 * Main task of this function is to trigger MG_EV_CONNECT event with
3193 * either failure (and dealloc the connection)
3194 * or success (and proceed with connect()
3195 */
3196static void resolve_cb(struct mg_dns_message *msg, void *data,
3197 enum mg_resolve_err e) {
3198 struct mg_connection *nc = (struct mg_connection *) data;
3199 int i;
3200 int failure = -1;
3201
3202 nc->flags &= ~MG_F_RESOLVING;
3203 if (msg != NULL) {
3204 /*
3205 * Take the first DNS A answer and run...
3206 */
3207 for (i = 0; i < msg->num_answers; i++) {
3208 if (msg->answers[i].rtype == MG_DNS_A_RECORD) {
3209 /*
3210 * Async resolver guarantees that there is at least one answer.
3211 * TODO(lsm): handle IPv6 answers too
3212 */
3213 mg_dns_parse_record_data(msg, &msg->answers[i], &nc->sa.sin.sin_addr,
3214 4);
3216 &nc->sa);
3217 return;
3218 }
3219 }
3220 }
3221
3222 if (e == MG_RESOLVE_TIMEOUT) {
3223 double now = mg_time();
3224 mg_call(nc, NULL, nc->user_data, MG_EV_TIMER, &now);
3225 }
3226
3227 /*
3228 * If we get there was no MG_DNS_A_RECORD in the answer
3229 */
3230 mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &failure);
3232 mg_destroy_conn(nc, 1 /* destroy_if */);
3233}
3234#endif
3235
3236struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *address,
3238 void *user_data)) {
3239 struct mg_connect_opts opts;
3240 memset(&opts, 0, sizeof(opts));
3241 return mg_connect_opt(mgr, address, MG_CB(callback, user_data), opts);
3242}
3243
3244struct mg_connection *mg_connect_opt(struct mg_mgr *mgr, const char *address,
3246 void *user_data),
3247 struct mg_connect_opts opts) {
3248 struct mg_connection *nc = NULL;
3249 int proto, rc;
3251 char host[MG_MAX_HOST_LEN];
3252
3254
3255 if ((nc = mg_create_connection(mgr, callback, add_sock_opts)) == NULL) {
3256 return NULL;
3257 }
3258
3259 if ((rc = mg_parse_address(address, &nc->sa, &proto, host, sizeof(host))) <
3260 0) {
3261 /* Address is malformed */
3262 MG_SET_PTRPTR(opts.error_string, "cannot parse address");
3263 mg_destroy_conn(nc, 1 /* destroy_if */);
3264 return NULL;
3265 }
3266
3268 nc->flags |= (proto == SOCK_DGRAM) ? MG_F_UDP : 0;
3269#if MG_ENABLE_CALLBACK_USERDATA
3270 nc->user_data = user_data;
3271#else
3272 nc->user_data = opts.user_data;
3273#endif
3274
3275#if MG_ENABLE_SSL
3276 LOG(LL_DEBUG,
3277 ("%p %s %s,%s,%s", nc, address, (opts.ssl_cert ? opts.ssl_cert : "-"),
3278 (opts.ssl_key ? opts.ssl_key : "-"),
3279 (opts.ssl_ca_cert ? opts.ssl_ca_cert : "-")));
3280
3281 if (opts.ssl_cert != NULL || opts.ssl_ca_cert != NULL ||
3282 opts.ssl_psk_identity != NULL) {
3283 const char *err_msg = NULL;
3284 struct mg_ssl_if_conn_params params;
3285 if (nc->flags & MG_F_UDP) {
3286 MG_SET_PTRPTR(opts.error_string, "SSL for UDP is not supported");
3287 mg_destroy_conn(nc, 1 /* destroy_if */);
3288 return NULL;
3289 }
3290 memset(&params, 0, sizeof(params));
3291 params.cert = opts.ssl_cert;
3292 params.key = opts.ssl_key;
3293 params.ca_cert = opts.ssl_ca_cert;
3294 params.cipher_suites = opts.ssl_cipher_suites;
3295 params.psk_identity = opts.ssl_psk_identity;
3296 params.psk_key = opts.ssl_psk_key;
3297 if (opts.ssl_ca_cert != NULL) {
3298 if (opts.ssl_server_name != NULL) {
3299 if (strcmp(opts.ssl_server_name, "*") != 0) {
3300 params.server_name = opts.ssl_server_name;
3301 }
3302 } else if (rc == 0) { /* If it's a DNS name, use host. */
3303 params.server_name = host;
3304 }
3305 }
3306 if (mg_ssl_if_conn_init(nc, &params, &err_msg) != MG_SSL_OK) {
3307 MG_SET_PTRPTR(opts.error_string, err_msg);
3308 mg_destroy_conn(nc, 1 /* destroy_if */);
3309 return NULL;
3310 }
3311 nc->flags |= MG_F_SSL;
3312 }
3313#endif /* MG_ENABLE_SSL */
3314
3315 if (rc == 0) {
3316#if MG_ENABLE_ASYNC_RESOLVER
3317 /*
3318 * DNS resolution is required for host.
3319 * mg_parse_address() fills port in nc->sa, which we pass to resolve_cb()
3320 */
3321 struct mg_connection *dns_conn = NULL;
3322 struct mg_resolve_async_opts o;
3323 memset(&o, 0, sizeof(o));
3324 o.dns_conn = &dns_conn;
3325 o.nameserver = opts.nameserver;
3327 o) != 0) {
3328 MG_SET_PTRPTR(opts.error_string, "cannot schedule DNS lookup");
3329 mg_destroy_conn(nc, 1 /* destroy_if */);
3330 return NULL;
3331 }
3332 nc->priv_2 = dns_conn;
3333 nc->flags |= MG_F_RESOLVING;
3334 return nc;
3335#else
3336 MG_SET_PTRPTR(opts.error_string, "Resolver is disabled");
3337 mg_destroy_conn(nc, 1 /* destroy_if */);
3338 return NULL;
3339#endif
3340 } else {
3341 /* Address is parsed and resolved to IP. proceed with connect() */
3342 return mg_do_connect(nc, proto, &nc->sa);
3343 }
3344}
3345
3346struct mg_connection *mg_bind(struct mg_mgr *srv, const char *address,
3347 MG_CB(mg_event_handler_t event_handler,
3348 void *user_data)) {
3349 struct mg_bind_opts opts;
3350 memset(&opts, 0, sizeof(opts));
3351 return mg_bind_opt(srv, address, MG_CB(event_handler, user_data), opts);
3352}
3353
3354struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address,
3356 void *user_data),
3357 struct mg_bind_opts opts) {
3358 union socket_address sa;
3359 struct mg_connection *nc = NULL;
3360 int proto, rc;
3362 char host[MG_MAX_HOST_LEN];
3363
3364#if MG_ENABLE_CALLBACK_USERDATA
3366#endif
3367
3368 if (callback == NULL) {
3369 MG_SET_PTRPTR(opts.error_string, "handler is required");
3370 return NULL;
3371 }
3372
3374
3375 if (mg_parse_address(address, &sa, &proto, host, sizeof(host)) <= 0) {
3376 MG_SET_PTRPTR(opts.error_string, "cannot parse address");
3377 return NULL;
3378 }
3379
3381 if (nc == NULL) {
3382 return NULL;
3383 }
3384
3385 nc->sa = sa;
3386 nc->flags |= MG_F_LISTENING;
3387 if (proto == SOCK_DGRAM) nc->flags |= MG_F_UDP;
3388
3389#if MG_ENABLE_SSL
3390 DBG(("%p %s %s,%s,%s", nc, address, (opts.ssl_cert ? opts.ssl_cert : "-"),
3391 (opts.ssl_key ? opts.ssl_key : "-"),
3392 (opts.ssl_ca_cert ? opts.ssl_ca_cert : "-")));
3393
3394 if (opts.ssl_cert != NULL || opts.ssl_ca_cert != NULL) {
3395 const char *err_msg = NULL;
3396 struct mg_ssl_if_conn_params params;
3397 if (nc->flags & MG_F_UDP) {
3398 MG_SET_PTRPTR(opts.error_string, "SSL for UDP is not supported");
3399 mg_destroy_conn(nc, 1 /* destroy_if */);
3400 return NULL;
3401 }
3402 memset(&params, 0, sizeof(params));
3403 params.cert = opts.ssl_cert;
3404 params.key = opts.ssl_key;
3405 params.ca_cert = opts.ssl_ca_cert;
3406 params.cipher_suites = opts.ssl_cipher_suites;
3407 if (mg_ssl_if_conn_init(nc, &params, &err_msg) != MG_SSL_OK) {
3408 MG_SET_PTRPTR(opts.error_string, err_msg);
3409 mg_destroy_conn(nc, 1 /* destroy_if */);
3410 return NULL;
3411 }
3412 nc->flags |= MG_F_SSL;
3413 }
3414#endif /* MG_ENABLE_SSL */
3415
3416 if (nc->flags & MG_F_UDP) {
3417 rc = nc->iface->vtable->listen_udp(nc, &nc->sa);
3418 } else {
3419 rc = nc->iface->vtable->listen_tcp(nc, &nc->sa);
3420 }
3421 if (rc != 0) {
3422 DBG(("Failed to open listener: %d", rc));
3423 MG_SET_PTRPTR(opts.error_string, "failed to open listener");
3424 mg_destroy_conn(nc, 1 /* destroy_if */);
3425 return NULL;
3426 }
3427 mg_add_conn(nc->mgr, nc);
3428
3429 return nc;
3430}
3431
3432struct mg_connection *mg_next(struct mg_mgr *s, struct mg_connection *conn) {
3433 return conn == NULL ? s->active_connections : conn->next;
3434}
3435
3436#if MG_ENABLE_BROADCAST
3437void mg_broadcast(struct mg_mgr *mgr, mg_event_handler_t cb, void *data,
3438 size_t len) {
3439 struct ctl_msg ctl_msg;
3440
3441 /*
3442 * Mongoose manager has a socketpair, `struct mg_mgr::ctl`,
3443 * where `mg_broadcast()` pushes the message.
3444 * `mg_mgr_poll()` wakes up, reads a message from the socket pair, and calls
3445 * specified callback for each connection. Thus the callback function executes
3446 * in event manager thread.
3447 */
3448 if (mgr->ctl[0] != INVALID_SOCKET && data != NULL &&
3449 len < sizeof(ctl_msg.message)) {
3450 size_t dummy;
3451
3452 ctl_msg.callback = cb;
3453 memcpy(ctl_msg.message, data, len);
3454 dummy = MG_SEND_FUNC(mgr->ctl[0], (char *) &ctl_msg,
3455 offsetof(struct ctl_msg, message) + len, 0);
3456 dummy = MG_RECV_FUNC(mgr->ctl[0], (char *) &len, 1, 0);
3457 (void) dummy; /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25509 */
3458 }
3459}
3460#endif /* MG_ENABLE_BROADCAST */
3461
3462static int isbyte(int n) {
3463 return n >= 0 && n <= 255;
3464}
3465
3466static int parse_net(const char *spec, uint32_t *net, uint32_t *mask) {
3467 int n, a, b, c, d, slash = 32, len = 0;
3468
3469 if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5 ||
3470 sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) &&
3471 isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) && slash >= 0 &&
3472 slash < 33) {
3473 len = n;
3474 *net =
3475 ((uint32_t) a << 24) | ((uint32_t) b << 16) | ((uint32_t) c << 8) | d;
3476 *mask = slash ? 0xffffffffU << (32 - slash) : 0;
3477 }
3478
3479 return len;
3480}
3481
3482int mg_check_ip_acl(const char *acl, uint32_t remote_ip) {
3483 int allowed, flag;
3484 uint32_t net, mask;
3485 struct mg_str vec;
3486
3487 /* If any ACL is set, deny by default */
3488 allowed = (acl == NULL || *acl == '\0') ? '+' : '-';
3489
3490 while ((acl = mg_next_comma_list_entry(acl, &vec, NULL)) != NULL) {
3491 flag = vec.p[0];
3492 if ((flag != '+' && flag != '-') ||
3493 parse_net(&vec.p[1], &net, &mask) == 0) {
3494 return -1;
3495 }
3496
3497 if (net == (remote_ip & mask)) {
3498 allowed = flag;
3499 }
3500 }
3501
3502 DBG(("%08x %c", (unsigned int) remote_ip, allowed));
3503 return allowed == '+';
3504}
3505
3506/* Move data from one connection to another */
3508 mg_send(to, from->recv_mbuf.buf, from->recv_mbuf.len);
3509 mbuf_remove(&from->recv_mbuf, from->recv_mbuf.len);
3510}
3511
3512double mg_set_timer(struct mg_connection *c, double timestamp) {
3513 double result = c->ev_timer_time;
3514 c->ev_timer_time = timestamp;
3515 /*
3516 * If this connection is resolving, it's not in the list of active
3517 * connections, so not processed yet. It has a DNS resolver connection
3518 * linked to it. Set up a timer for the DNS connection.
3519 */
3520 DBG(("%p %p %d -> %lu", c, c->priv_2, (c->flags & MG_F_RESOLVING ? 1 : 0),
3521 (unsigned long) timestamp));
3522 if ((c->flags & MG_F_RESOLVING) && c->priv_2 != NULL) {
3523 mg_set_timer((struct mg_connection *) c->priv_2, timestamp);
3524 }
3525 return result;
3526}
3527
3528void mg_sock_set(struct mg_connection *nc, sock_t sock) {
3529 if (sock != INVALID_SOCKET) {
3530 nc->iface->vtable->sock_set(nc, sock);
3531 }
3532}
3533
3535 union socket_address *sa) {
3536 nc->iface->vtable->get_conn_addr(nc, remote, sa);
3537}
3538
3541 void *user_data),
3542 struct mg_add_sock_opts opts) {
3543#if MG_ENABLE_CALLBACK_USERDATA
3545#endif
3546
3548 if (nc != NULL) {
3549 mg_sock_set(nc, sock);
3550 mg_add_conn(nc->mgr, nc);
3551 }
3552 return nc;
3553}
3554
3557 void *user_data)) {
3558 struct mg_add_sock_opts opts;
3559 memset(&opts, 0, sizeof(opts));
3560 return mg_add_sock_opt(s, sock, MG_CB(callback, user_data), opts);
3561}
3562
3563double mg_time(void) {
3564 return cs_time();
3565}
3566#ifdef MG_MODULE_LINES
3567#line 1 "mongoose/src/mg_net_if_socket.h"
3568#endif
3569/*
3570 * Copyright (c) 2014-2016 Cesanta Software Limited
3571 * All rights reserved
3572 */
3573
3574#ifndef CS_MONGOOSE_SRC_NET_IF_SOCKET_H_
3575#define CS_MONGOOSE_SRC_NET_IF_SOCKET_H_
3576
3577/* Amalgamated: #include "mg_net_if.h" */
3578
3579#ifdef __cplusplus
3580extern "C" {
3581#endif /* __cplusplus */
3582
3583#ifndef MG_ENABLE_NET_IF_SOCKET
3584#define MG_ENABLE_NET_IF_SOCKET MG_NET_IF == MG_NET_IF_SOCKET
3585#endif
3586
3587extern const struct mg_iface_vtable mg_socket_iface_vtable;
3588
3589#ifdef __cplusplus
3590}
3591#endif /* __cplusplus */
3592
3593#endif /* CS_MONGOOSE_SRC_NET_IF_SOCKET_H_ */
3594#ifdef MG_MODULE_LINES
3595#line 1 "mongoose/src/mg_net_if_socks.h"
3596#endif
3597/*
3598* Copyright (c) 2014-2017 Cesanta Software Limited
3599* All rights reserved
3600*/
3601
3602#ifndef CS_MONGOOSE_SRC_NET_IF_SOCKS_H_
3603#define CS_MONGOOSE_SRC_NET_IF_SOCKS_H_
3604
3605#if MG_ENABLE_SOCKS
3606/* Amalgamated: #include "mg_net_if.h" */
3607
3608#ifdef __cplusplus
3609extern "C" {
3610#endif /* __cplusplus */
3611
3612extern const struct mg_iface_vtable mg_socks_iface_vtable;
3613
3614#ifdef __cplusplus
3615}
3616#endif /* __cplusplus */
3617#endif /* MG_ENABLE_SOCKS */
3618#endif /* CS_MONGOOSE_SRC_NET_IF_SOCKS_H_ */
3619#ifdef MG_MODULE_LINES
3620#line 1 "mongoose/src/mg_net_if.c"
3621#endif
3622/* Amalgamated: #include "mg_net_if.h" */
3623/* Amalgamated: #include "mg_internal.h" */
3624/* Amalgamated: #include "mg_net_if_socket.h" */
3625
3626extern const struct mg_iface_vtable mg_default_iface_vtable;
3627
3628const struct mg_iface_vtable *mg_ifaces[] = {
3630};
3631
3632int mg_num_ifaces = (int) (sizeof(mg_ifaces) / sizeof(mg_ifaces[0]));
3633
3635 struct mg_mgr *mgr) {
3636 struct mg_iface *iface = (struct mg_iface *) MG_CALLOC(1, sizeof(*iface));
3637 iface->mgr = mgr;
3638 iface->data = NULL;
3639 iface->vtable = vtable;
3640 return iface;
3641}
3642
3644 const struct mg_iface_vtable *vtable,
3645 struct mg_iface *from) {
3646 int i = 0;
3647 if (from != NULL) {
3648 for (i = 0; i < mgr->num_ifaces; i++) {
3649 if (mgr->ifaces[i] == from) {
3650 i++;
3651 break;
3652 }
3653 }
3654 }
3655
3656 for (; i < mgr->num_ifaces; i++) {
3657 if (mgr->ifaces[i]->vtable == vtable) {
3658 return mgr->ifaces[i];
3659 }
3660 }
3661 return NULL;
3662}
3663
3664double mg_mgr_min_timer(const struct mg_mgr *mgr) {
3665 double min_timer = 0;
3666 struct mg_connection *nc;
3667 for (nc = mgr->active_connections; nc != NULL; nc = nc->next) {
3668 if (nc->ev_timer_time <= 0) continue;
3669 if (min_timer == 0 || nc->ev_timer_time < min_timer) {
3671 }
3672 }
3673 return min_timer;
3674}
3675#ifdef MG_MODULE_LINES
3676#line 1 "mongoose/src/mg_net_if_null.c"
3677#endif
3678/*
3679 * Copyright (c) 2018 Cesanta Software Limited
3680 * All rights reserved
3681 *
3682 * This software is dual-licensed: you can redistribute it and/or modify
3683 * it under the terms of the GNU General Public License version 2 as
3684 * published by the Free Software Foundation. For the terms of this
3685 * license, see <http://www.gnu.org/licenses/>.
3686 *
3687 * You are free to use this software under the terms of the GNU General
3688 * Public License, but WITHOUT ANY WARRANTY; without even the implied
3689 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
3690 * See the GNU General Public License for more details.
3691 *
3692 * Alternatively, you can license this software under a commercial
3693 * license, as set out in <https://www.cesanta.com/license>.
3694 */
3695
3697 const union socket_address *sa) {
3698 c->flags |= MG_F_CLOSE_IMMEDIATELY;
3699 (void) sa;
3700}
3701
3703 c->flags |= MG_F_CLOSE_IMMEDIATELY;
3704}
3705
3707 union socket_address *sa) {
3708 (void) c;
3709 (void) sa;
3710 return -1;
3711}
3712
3714 union socket_address *sa) {
3715 (void) c;
3716 (void) sa;
3717 return -1;
3718}
3719
3720static int mg_null_if_tcp_send(struct mg_connection *c, const void *buf,
3721 size_t len) {
3722 (void) c;
3723 (void) buf;
3724 (void) len;
3725 return -1;
3726}
3727
3728static int mg_null_if_udp_send(struct mg_connection *c, const void *buf,
3729 size_t len) {
3730 (void) c;
3731 (void) buf;
3732 (void) len;
3733 return -1;
3734}
3735
3736int mg_null_if_tcp_recv(struct mg_connection *c, void *buf, size_t len) {
3737 (void) c;
3738 (void) buf;
3739 (void) len;
3740 return -1;
3741}
3742
3743int mg_null_if_udp_recv(struct mg_connection *c, void *buf, size_t len,
3744 union socket_address *sa, size_t *sa_len) {
3745 (void) c;
3746 (void) buf;
3747 (void) len;
3748 (void) sa;
3749 (void) sa_len;
3750 return -1;
3751}
3752
3754 (void) c;
3755 return 1;
3756}
3757
3759 (void) c;
3760}
3761
3763 (void) c;
3764 (void) sock;
3765}
3766
3767static void mg_null_if_init(struct mg_iface *iface) {
3768 (void) iface;
3769}
3770
3771static void mg_null_if_free(struct mg_iface *iface) {
3772 (void) iface;
3773}
3774
3776 c->sock = INVALID_SOCKET;
3777 c->flags |= MG_F_CLOSE_IMMEDIATELY;
3778}
3779
3781 (void) c;
3782}
3783
3785 struct mg_mgr *mgr = iface->mgr;
3786 struct mg_connection *nc, *tmp;
3787 double now = mg_time();
3788 /* We basically just run timers and poll. */
3789 for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
3790 tmp = nc->next;
3791 mg_if_poll(nc, now);
3792 }
3793 (void) timeout_ms;
3794 return (time_t) now;
3795}
3796
3798 union socket_address *sa) {
3799 (void) c;
3800 (void) remote;
3801 (void) sa;
3802}
3803
3804#define MG_NULL_IFACE_VTABLE \
3805 { \
3806 mg_null_if_init, mg_null_if_free, mg_null_if_add_conn, \
3807 mg_null_if_remove_conn, mg_null_if_poll, mg_null_if_listen_tcp, \
3808 mg_null_if_listen_udp, mg_null_if_connect_tcp, mg_null_if_connect_udp, \
3809 mg_null_if_tcp_send, mg_null_if_udp_send, mg_null_if_tcp_recv, \
3810 mg_null_if_udp_recv, mg_null_if_create_conn, mg_null_if_destroy_conn, \
3811 mg_null_if_sock_set, mg_null_if_get_conn_addr, \
3812 }
3813
3815
3816#if MG_NET_IF == MG_NET_IF_NULL
3818#endif /* MG_NET_IF == MG_NET_IF_NULL */
3819#ifdef MG_MODULE_LINES
3820#line 1 "mongoose/src/mg_net_if_socket.c"
3821#endif
3822/*
3823 * Copyright (c) 2014-2016 Cesanta Software Limited
3824 * All rights reserved
3825 */
3826
3827#if MG_ENABLE_NET_IF_SOCKET
3828
3829/* Amalgamated: #include "mg_net_if_socket.h" */
3830/* Amalgamated: #include "mg_internal.h" */
3831/* Amalgamated: #include "mg_util.h" */
3832
3834 int proto);
3835
3837#ifdef _WIN32
3838 unsigned long on = 1;
3839 ioctlsocket(sock, FIONBIO, &on);
3840#else
3841 int flags = fcntl(sock, F_GETFL, 0);
3842 fcntl(sock, F_SETFL, flags | O_NONBLOCK);
3843#endif
3844}
3845
3846static int mg_is_error(void) {
3847 int err = mg_get_errno();
3848 return err != EINPROGRESS && err != EWOULDBLOCK
3849#ifndef WINCE
3850 && err != EAGAIN && err != EINTR
3851#endif
3852#ifdef _WIN32
3854#endif
3855 ;
3856}
3857
3859 const union socket_address *sa) {
3860 int rc, proto = 0;
3861 nc->sock = socket(AF_INET, SOCK_STREAM, proto);
3862 if (nc->sock == INVALID_SOCKET) {
3863 nc->err = mg_get_errno() ? mg_get_errno() : 1;
3864 return;
3865 }
3866#if !defined(MG_ESP8266)
3868#endif
3869 rc = connect(nc->sock, &sa->sa, sizeof(sa->sin));
3870 nc->err = rc < 0 && mg_is_error() ? mg_get_errno() : 0;
3871 DBG(("%p sock %d rc %d errno %d err %d", nc, nc->sock, rc, mg_get_errno(),
3872 nc->err));
3873}
3874
3876 nc->sock = socket(AF_INET, SOCK_DGRAM, 0);
3877 if (nc->sock == INVALID_SOCKET) {
3878 nc->err = mg_get_errno() ? mg_get_errno() : 1;
3879 return;
3880 }
3881 if (nc->flags & MG_F_ENABLE_BROADCAST) {
3882 int optval = 1;
3883 if (setsockopt(nc->sock, SOL_SOCKET, SO_BROADCAST, (const char *) &optval,
3884 sizeof(optval)) < 0) {
3885 nc->err = mg_get_errno() ? mg_get_errno() : 1;
3886 return;
3887 }
3888 }
3889 nc->err = 0;
3890}
3891
3893 union socket_address *sa) {
3894 int proto = 0;
3895 sock_t sock = mg_open_listening_socket(sa, SOCK_STREAM, proto);
3896 if (sock == INVALID_SOCKET) {
3897 return (mg_get_errno() ? mg_get_errno() : 1);
3898 }
3899 mg_sock_set(nc, sock);
3900 return 0;
3901}
3902
3904 union socket_address *sa) {
3906 if (sock == INVALID_SOCKET) return (mg_get_errno() ? mg_get_errno() : 1);
3907 mg_sock_set(nc, sock);
3908 return 0;
3909}
3910
3911static int mg_socket_if_tcp_send(struct mg_connection *nc, const void *buf,
3912 size_t len) {
3913 int n = (int) MG_SEND_FUNC(nc->sock, buf, len, 0);
3914 if (n < 0 && !mg_is_error()) n = 0;
3915 return n;
3916}
3917
3918static int mg_socket_if_udp_send(struct mg_connection *nc, const void *buf,
3919 size_t len) {
3920 int n = sendto(nc->sock, buf, len, 0, &nc->sa.sa, sizeof(nc->sa.sin));
3921 if (n < 0 && !mg_is_error()) n = 0;
3922 return n;
3923}
3924
3925static int mg_socket_if_tcp_recv(struct mg_connection *nc, void *buf,
3926 size_t len) {
3927 int n = (int) MG_RECV_FUNC(nc->sock, buf, len, 0);
3928 if (n == 0) {
3929 /* Orderly shutdown of the socket, try flushing output. */
3931 } else if (n < 0 && !mg_is_error()) {
3932 n = 0;
3933 }
3934 return n;
3935}
3936
3937static int mg_socket_if_udp_recv(struct mg_connection *nc, void *buf,
3938 size_t len, union socket_address *sa,
3939 size_t *sa_len) {
3941 int n = recvfrom(nc->sock, buf, len, 0, &sa->sa, &sa_len_st);
3942 *sa_len = sa_len_st;
3943 if (n < 0 && !mg_is_error()) n = 0;
3944 return n;
3945}
3946
3948 (void) nc;
3949 return 1;
3950}
3951
3953 if (nc->sock == INVALID_SOCKET) return;
3954 if (!(nc->flags & MG_F_UDP)) {
3955 closesocket(nc->sock);
3956 } else {
3957 /* Only close outgoing UDP sockets or listeners. */
3958 if (nc->listener == NULL) closesocket(nc->sock);
3959 }
3960 nc->sock = INVALID_SOCKET;
3961}
3962
3963static int mg_accept_conn(struct mg_connection *lc) {
3964 struct mg_connection *nc;
3965 union socket_address sa;
3966 socklen_t sa_len = sizeof(sa);
3967 /* NOTE(lsm): on Windows, sock is always > FD_SETSIZE */
3968 sock_t sock = accept(lc->sock, &sa.sa, &sa_len);
3969 if (sock == INVALID_SOCKET) {
3970 if (mg_is_error()) {
3971 DBG(("%p: failed to accept: %d", lc, mg_get_errno()));
3972 }
3973 return 0;
3974 }
3975 nc = mg_if_accept_new_conn(lc);
3976 if (nc == NULL) {
3977 closesocket(sock);
3978 return 0;
3979 }
3980 DBG(("%p conn from %s:%d", nc, inet_ntoa(sa.sin.sin_addr),
3981 ntohs(sa.sin.sin_port)));
3982 mg_sock_set(nc, sock);
3984 return 1;
3985}
3986
3987/* 'sa' must be an initialized address to bind to */
3989 int proto) {
3991 (sa->sa.sa_family == AF_INET) ? sizeof(sa->sin) : sizeof(sa->sin6);
3992 sock_t sock = INVALID_SOCKET;
3993#if !MG_LWIP
3994 int on = 1;
3995#endif
3996
3997 if ((sock = socket(sa->sa.sa_family, type, proto)) != INVALID_SOCKET &&
3998#if !MG_LWIP /* LWIP doesn't support either */
4000 /* "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE" http://goo.gl/RmrFTm */
4001 !setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &on,
4002 sizeof(on)) &&
4003#endif
4004
4005#if !defined(_WIN32) || !defined(SO_EXCLUSIVEADDRUSE)
4006 /*
4007 * SO_RESUSEADDR is not enabled on Windows because the semantics of
4008 * SO_REUSEADDR on UNIX and Windows is different. On Windows,
4009 * SO_REUSEADDR allows to bind a socket to a port without error even if
4010 * the port is already open by another program. This is not the behavior
4011 * SO_REUSEADDR was designed for, and leads to hard-to-track failure
4012 * scenarios. Therefore, SO_REUSEADDR was disabled on Windows unless
4013 * SO_EXCLUSIVEADDRUSE is supported and set on a socket.
4014 */
4015 !setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) &&
4016#endif
4017#endif /* !MG_LWIP */
4018
4019 !bind(sock, &sa->sa, sa_len) &&
4020 (type == SOCK_DGRAM || listen(sock, SOMAXCONN) == 0)) {
4021#if !MG_LWIP
4023 /* In case port was set to 0, get the real port number */
4024 (void) getsockname(sock, &sa->sa, &sa_len);
4025#endif
4026 } else if (sock != INVALID_SOCKET) {
4027 closesocket(sock);
4028 sock = INVALID_SOCKET;
4029 }
4030
4031 return sock;
4032}
4033
4034#define _MG_F_FD_CAN_READ 1
4035#define _MG_F_FD_CAN_WRITE 1 << 1
4036#define _MG_F_FD_ERROR 1 << 2
4037
4038void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
4039 int worth_logging =
4040 fd_flags != 0 || (nc->flags & (MG_F_WANT_READ | MG_F_WANT_WRITE));
4041 if (worth_logging) {
4042 DBG(("%p fd=%d fd_flags=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock,
4043 fd_flags, nc->flags, (int) nc->recv_mbuf.len,
4044 (int) nc->send_mbuf.len));
4045 }
4046
4047 if (!mg_if_poll(nc, now)) return;
4048
4049 if (nc->flags & MG_F_CONNECTING) {
4050 if (fd_flags != 0) {
4051 int err = 0;
4052#if !defined(MG_ESP8266)
4053 if (!(nc->flags & MG_F_UDP)) {
4054 socklen_t len = sizeof(err);
4055 int ret =
4056 getsockopt(nc->sock, SOL_SOCKET, SO_ERROR, (char *) &err, &len);
4057 if (ret != 0) {
4058 err = 1;
4059 } else if (err == EAGAIN || err == EWOULDBLOCK) {
4060 err = 0;
4061 }
4062 }
4063#else
4064 /*
4065 * On ESP8266 we use blocking connect.
4066 */
4067 err = nc->err;
4068#endif
4069 mg_if_connect_cb(nc, err);
4070 } else if (nc->err != 0) {
4071 mg_if_connect_cb(nc, nc->err);
4072 }
4073 }
4074
4076 if (nc->flags & MG_F_UDP) {
4078 } else {
4079 if (nc->flags & MG_F_LISTENING) {
4080 /*
4081 * We're not looping here, and accepting just one connection at
4082 * a time. The reason is that eCos does not respect non-blocking
4083 * flag on a listening socket and hangs in a loop.
4084 */
4085 mg_accept_conn(nc);
4086 } else {
4088 }
4089 }
4090 }
4091
4093
4094 if (worth_logging) {
4095 DBG(("%p after fd=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock,
4096 nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
4097 }
4098}
4099
4100#if MG_ENABLE_BROADCAST
4101static void mg_mgr_handle_ctl_sock(struct mg_mgr *mgr) {
4102 struct ctl_msg ctl_msg;
4103 int len =
4104 (int) MG_RECV_FUNC(mgr->ctl[1], (char *) &ctl_msg, sizeof(ctl_msg), 0);
4105 size_t dummy = MG_SEND_FUNC(mgr->ctl[1], ctl_msg.message, 1, 0);
4106 DBG(("read %d from ctl socket", len));
4107 (void) dummy; /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25509 */
4108 if (len >= (int) sizeof(ctl_msg.callback) && ctl_msg.callback != NULL) {
4109 struct mg_connection *nc;
4110 for (nc = mg_next(mgr, NULL); nc != NULL; nc = mg_next(mgr, nc)) {
4113 }
4114 }
4115}
4116#endif
4117
4118/* Associate a socket to a connection. */
4122 nc->sock = sock;
4123 DBG(("%p %d", nc, sock));
4124}
4125
4127 (void) iface;
4128 DBG(("%p using select()", iface->mgr));
4129#if MG_ENABLE_BROADCAST
4131#endif
4132}
4133
4135 (void) iface;
4136}
4137
4139 (void) nc;
4140}
4141
4143 (void) nc;
4144}
4145
4147 if (sock != INVALID_SOCKET
4149 && sock < (sock_t) FD_SETSIZE
4150#endif
4151 ) {
4152 FD_SET(sock, set);
4153 if (*max_fd == INVALID_SOCKET || sock > *max_fd) {
4154 *max_fd = sock;
4155 }
4156 }
4157}
4158
4160 struct mg_mgr *mgr = iface->mgr;
4161 double now = mg_time();
4162 double min_timer;
4163 struct mg_connection *nc, *tmp;
4164 struct timeval tv;
4167 int num_fds, num_ev, num_timers = 0;
4168#ifdef __unix__
4169 int try_dup = 1;
4170#endif
4171
4172 FD_ZERO(&read_set);
4174 FD_ZERO(&err_set);
4175#if MG_ENABLE_BROADCAST
4176 mg_add_to_set(mgr->ctl[1], &read_set, &max_fd);
4177#endif
4178
4179 /*
4180 * Note: it is ok to have connections with sock == INVALID_SOCKET in the list,
4181 * e.g. timer-only "connections".
4182 */
4183 min_timer = 0;
4184 for (nc = mgr->active_connections, num_fds = 0; nc != NULL; nc = tmp) {
4185 tmp = nc->next;
4186
4187 if (nc->sock != INVALID_SOCKET) {
4188 num_fds++;
4189
4190#ifdef __unix__
4191 /* A hack to make sure all our file descriptos fit into FD_SETSIZE. */
4192 if (nc->sock >= (sock_t) FD_SETSIZE && try_dup) {
4193 int new_sock = dup(nc->sock);
4194 if (new_sock >= 0) {
4195 if (new_sock < (sock_t) FD_SETSIZE) {
4196 closesocket(nc->sock);
4197 DBG(("new sock %d -> %d", nc->sock, new_sock));
4198 nc->sock = new_sock;
4199 } else {
4201 DBG(("new sock is still larger than FD_SETSIZE, disregard"));
4202 try_dup = 0;
4203 }
4204 } else {
4205 try_dup = 0;
4206 }
4207 }
4208#endif
4209
4210 if (nc->recv_mbuf.len < nc->recv_mbuf_limit &&
4211 (!(nc->flags & MG_F_UDP) || nc->listener == NULL)) {
4213 }
4214
4215 if (((nc->flags & MG_F_CONNECTING) && !(nc->flags & MG_F_WANT_READ)) ||
4216 (nc->send_mbuf.len > 0 && !(nc->flags & MG_F_CONNECTING))) {
4219 }
4220 }
4221
4222 if (nc->ev_timer_time > 0) {
4223 if (num_timers == 0 || nc->ev_timer_time < min_timer) {
4225 }
4226 num_timers++;
4227 }
4228 }
4229
4230 /*
4231 * If there is a timer to be fired earlier than the requested timeout,
4232 * adjust the timeout.
4233 */
4234 if (num_timers > 0) {
4235 double timer_timeout_ms = (min_timer - mg_time()) * 1000 + 1 /* rounding */;
4238 }
4239 }
4240 if (timeout_ms < 0) timeout_ms = 0;
4241
4242 tv.tv_sec = timeout_ms / 1000;
4243 tv.tv_usec = (timeout_ms % 1000) * 1000;
4244
4245 num_ev = select((int) max_fd + 1, &read_set, &write_set, &err_set, &tv);
4246 now = mg_time();
4247#if 0
4248 DBG(("select @ %ld num_ev=%d of %d, timeout=%d", (long) now, num_ev, num_fds,
4249 timeout_ms));
4250#endif
4251
4252#if MG_ENABLE_BROADCAST
4253 if (num_ev > 0 && mgr->ctl[1] != INVALID_SOCKET &&
4254 FD_ISSET(mgr->ctl[1], &read_set)) {
4256 }
4257#endif
4258
4259 for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
4260 int fd_flags = 0;
4261 if (nc->sock != INVALID_SOCKET) {
4262 if (num_ev > 0) {
4263 fd_flags = (FD_ISSET(nc->sock, &read_set) &&
4264 (!(nc->flags & MG_F_UDP) || nc->listener == NULL)
4266 : 0) |
4267 (FD_ISSET(nc->sock, &write_set) ? _MG_F_FD_CAN_WRITE : 0) |
4268 (FD_ISSET(nc->sock, &err_set) ? _MG_F_FD_ERROR : 0);
4269 }
4270#if MG_LWIP
4271 /* With LWIP socket emulation layer, we don't get write events for UDP */
4272 if ((nc->flags & MG_F_UDP) && nc->listener == NULL) {
4274 }
4275#endif
4276 }
4277 tmp = nc->next;
4279 }
4280
4281 return (time_t) now;
4282}
4283
4284#if MG_ENABLE_BROADCAST
4286 while (1) {
4287 if (closesocket(*sock) == -1 && errno == EINTR) continue;
4288 break;
4289 }
4290 *sock = INVALID_SOCKET;
4291}
4292
4295 sock_t rc;
4296 while (1) {
4297 if ((rc = accept(sock, &sa->sa, &sa_len)) == INVALID_SOCKET &&
4298 errno == EINTR)
4299 continue;
4300 break;
4301 }
4302 return rc;
4303}
4304
4305int mg_socketpair(sock_t sp[2], int sock_type) {
4306 union socket_address sa, sa2;
4307 sock_t sock;
4308 socklen_t len = sizeof(sa.sin);
4309 int ret = 0;
4310
4311 sock = sp[0] = sp[1] = INVALID_SOCKET;
4312
4313 (void) memset(&sa, 0, sizeof(sa));
4314 sa.sin.sin_family = AF_INET;
4315 sa.sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
4316 sa2 = sa;
4317
4318 if ((sock = socket(AF_INET, sock_type, 0)) == INVALID_SOCKET) {
4319 } else if (bind(sock, &sa.sa, len) != 0) {
4320 } else if (sock_type == SOCK_STREAM && listen(sock, 1) != 0) {
4321 } else if (getsockname(sock, &sa.sa, &len) != 0) {
4322 } else if ((sp[0] = socket(AF_INET, sock_type, 0)) == INVALID_SOCKET) {
4323 } else if (sock_type == SOCK_STREAM && connect(sp[0], &sa.sa, len) != 0) {
4324 } else if (sock_type == SOCK_DGRAM &&
4325 (bind(sp[0], &sa2.sa, len) != 0 ||
4326 getsockname(sp[0], &sa2.sa, &len) != 0 ||
4327 connect(sp[0], &sa.sa, len) != 0 ||
4328 connect(sock, &sa2.sa, len) != 0)) {
4329 } else if ((sp[1] = (sock_type == SOCK_DGRAM ? sock : mg_socketpair_accept(
4330 sock, &sa, len))) ==
4332 } else {
4336 ret = 1;
4337 }
4338
4339 if (!ret) {
4340 if (sp[0] != INVALID_SOCKET) mg_socketpair_close(&sp[0]);
4341 if (sp[1] != INVALID_SOCKET) mg_socketpair_close(&sp[1]);
4342 if (sock != INVALID_SOCKET) mg_socketpair_close(&sock);
4343 }
4344
4345 return ret;
4346}
4347#endif /* MG_ENABLE_BROADCAST */
4348
4349static void mg_sock_get_addr(sock_t sock, int remote,
4350 union socket_address *sa) {
4351 socklen_t slen = sizeof(*sa);
4352 memset(sa, 0, slen);
4353 if (remote) {
4354 getpeername(sock, &sa->sa, &slen);
4355 } else {
4356 getsockname(sock, &sa->sa, &slen);
4357 }
4358}
4359
4360void mg_sock_to_str(sock_t sock, char *buf, size_t len, int flags) {
4361 union socket_address sa;
4363 mg_sock_addr_to_str(&sa, buf, len, flags);
4364}
4365
4367 union socket_address *sa) {
4368 if ((nc->flags & MG_F_UDP) && remote) {
4369 memcpy(sa, &nc->sa, sizeof(*sa));
4370 return;
4371 }
4373}
4374
4375/* clang-format off */
4376#define MG_SOCKET_IFACE_VTABLE \
4377 { \
4378 mg_socket_if_init, \
4379 mg_socket_if_free, \
4380 mg_socket_if_add_conn, \
4381 mg_socket_if_remove_conn, \
4382 mg_socket_if_poll, \
4383 mg_socket_if_listen_tcp, \
4384 mg_socket_if_listen_udp, \
4385 mg_socket_if_connect_tcp, \
4386 mg_socket_if_connect_udp, \
4387 mg_socket_if_tcp_send, \
4388 mg_socket_if_udp_send, \
4389 mg_socket_if_tcp_recv, \
4390 mg_socket_if_udp_recv, \
4391 mg_socket_if_create_conn, \
4392 mg_socket_if_destroy_conn, \
4393 mg_socket_if_sock_set, \
4394 mg_socket_if_get_conn_addr, \
4395 }
4396/* clang-format on */
4397
4399#if MG_NET_IF == MG_NET_IF_SOCKET
4401#endif
4402
4403#endif /* MG_ENABLE_NET_IF_SOCKET */
4404#ifdef MG_MODULE_LINES
4405#line 1 "mongoose/src/mg_net_if_socks.c"
4406#endif
4407/*
4408 * Copyright (c) 2014-2016 Cesanta Software Limited
4409 * All rights reserved
4410 */
4411
4412#if MG_ENABLE_SOCKS
4413
4414struct socksdata {
4415 char *proxy_addr; /* HOST:PORT of the socks5 proxy server */
4416 struct mg_connection *s; /* Respective connection to the server */
4417 struct mg_connection *c; /* Connection to the client */
4418};
4419
4420static void socks_if_disband(struct socksdata *d) {
4421 LOG(LL_DEBUG, ("disbanding proxy %p %p", d->c, d->s));
4422 if (d->c) {
4423 d->c->flags |= MG_F_SEND_AND_CLOSE;
4424 d->c->user_data = NULL;
4425 d->c = NULL;
4426 }
4427 if (d->s) {
4428 d->s->flags |= MG_F_SEND_AND_CLOSE;
4429 d->s->user_data = NULL;
4430 d->s = NULL;
4431 }
4432}
4433
4434static void socks_if_relay(struct mg_connection *s) {
4435 struct socksdata *d = (struct socksdata *) s->user_data;
4436 if (d == NULL || d->c == NULL || !(s->flags & MG_SOCKS_CONNECT_DONE) ||
4437 d->s == NULL) {
4438 return;
4439 }
4440 if (s->recv_mbuf.len > 0) mg_if_can_recv_cb(d->c);
4441 if (d->c->send_mbuf.len > 0 && s->send_mbuf.len == 0) mg_if_can_send_cb(d->c);
4442}
4443
4444static void socks_if_handler(struct mg_connection *c, int ev, void *ev_data) {
4445 struct socksdata *d = (struct socksdata *) c->user_data;
4446 if (d == NULL) return;
4447 if (ev == MG_EV_CONNECT) {
4448 int res = *(int *) ev_data;
4449 if (res == 0) {
4450 /* Send handshake to the proxy server */
4451 unsigned char buf[] = {MG_SOCKS_VERSION, 1, MG_SOCKS_HANDSHAKE_NOAUTH};
4452 mg_send(d->s, buf, sizeof(buf));
4453 LOG(LL_DEBUG, ("Sent handshake to %s", d->proxy_addr));
4454 } else {
4455 LOG(LL_ERROR, ("Cannot connect to %s: %d", d->proxy_addr, res));
4456 d->c->flags |= MG_F_CLOSE_IMMEDIATELY;
4457 }
4458 } else if (ev == MG_EV_CLOSE) {
4460 } else if (ev == MG_EV_RECV) {
4461 /* Handle handshake reply */
4462 if (!(c->flags & MG_SOCKS_HANDSHAKE_DONE)) {
4463 /* TODO(lsm): process IPv6 too */
4464 unsigned char buf[10] = {MG_SOCKS_VERSION, MG_SOCKS_CMD_CONNECT, 0,
4466 if (c->recv_mbuf.len < 2) return;
4467 if ((unsigned char) c->recv_mbuf.buf[1] == MG_SOCKS_HANDSHAKE_FAILURE) {
4468 LOG(LL_ERROR, ("Server kicked us out"));
4470 return;
4471 }
4472 mbuf_remove(&c->recv_mbuf, 2);
4473 c->flags |= MG_SOCKS_HANDSHAKE_DONE;
4474
4475 /* Send connect request */
4476 memcpy(buf + 4, &d->c->sa.sin.sin_addr, 4);
4477 memcpy(buf + 8, &d->c->sa.sin.sin_port, 2);
4478 mg_send(c, buf, sizeof(buf));
4479 LOG(LL_DEBUG, ("%p Sent connect request", c));
4480 }
4481 /* Process connect request */
4482 if ((c->flags & MG_SOCKS_HANDSHAKE_DONE) &&
4483 !(c->flags & MG_SOCKS_CONNECT_DONE)) {
4484 if (c->recv_mbuf.len < 10) return;
4485 if (c->recv_mbuf.buf[1] != MG_SOCKS_SUCCESS) {
4486 LOG(LL_ERROR, ("Socks connection error: %d", c->recv_mbuf.buf[1]));
4488 return;
4489 }
4490 mbuf_remove(&c->recv_mbuf, 10);
4491 c->flags |= MG_SOCKS_CONNECT_DONE;
4492 LOG(LL_DEBUG, ("%p Connect done %p", c, d->c));
4493 mg_if_connect_cb(d->c, 0);
4494 }
4496 } else if (ev == MG_EV_SEND || ev == MG_EV_POLL) {
4498 }
4499}
4500
4501static void mg_socks_if_connect_tcp(struct mg_connection *c,
4502 const union socket_address *sa) {
4503 struct socksdata *d = (struct socksdata *) c->iface->data;
4504 d->c = c;
4505 d->s = mg_connect(c->mgr, d->proxy_addr, socks_if_handler);
4506 d->s->user_data = d;
4507 LOG(LL_DEBUG, ("%p %s %p %p", c, d->proxy_addr, d, d->s));
4508 (void) sa;
4509}
4510
4511static void mg_socks_if_connect_udp(struct mg_connection *c) {
4512 (void) c;
4513}
4514
4515static int mg_socks_if_listen_tcp(struct mg_connection *c,
4516 union socket_address *sa) {
4517 (void) c;
4518 (void) sa;
4519 return 0;
4520}
4521
4522static int mg_socks_if_listen_udp(struct mg_connection *c,
4523 union socket_address *sa) {
4524 (void) c;
4525 (void) sa;
4526 return -1;
4527}
4528
4529static int mg_socks_if_tcp_send(struct mg_connection *c, const void *buf,
4530 size_t len) {
4531 int res;
4532 struct socksdata *d = (struct socksdata *) c->iface->data;
4533 if (d->s == NULL) return -1;
4534 res = (int) mbuf_append(&d->s->send_mbuf, buf, len);
4535 DBG(("%p -> %d -> %p", c, res, d->s));
4536 return res;
4537}
4538
4539static int mg_socks_if_udp_send(struct mg_connection *c, const void *buf,
4540 size_t len) {
4541 (void) c;
4542 (void) buf;
4543 (void) len;
4544 return -1;
4545}
4546
4547int mg_socks_if_tcp_recv(struct mg_connection *c, void *buf, size_t len) {
4548 struct socksdata *d = (struct socksdata *) c->iface->data;
4549 if (d->s == NULL) return -1;
4550 if (len > d->s->recv_mbuf.len) len = d->s->recv_mbuf.len;
4551 if (len > 0) {
4552 memcpy(buf, d->s->recv_mbuf.buf, len);
4553 mbuf_remove(&d->s->recv_mbuf, len);
4554 }
4555 DBG(("%p <- %d <- %p", c, (int) len, d->s));
4556 return len;
4557}
4558
4559int mg_socks_if_udp_recv(struct mg_connection *c, void *buf, size_t len,
4560 union socket_address *sa, size_t *sa_len) {
4561 (void) c;
4562 (void) buf;
4563 (void) len;
4564 (void) sa;
4565 (void) sa_len;
4566 return -1;
4567}
4568
4569static int mg_socks_if_create_conn(struct mg_connection *c) {
4570 (void) c;
4571 return 1;
4572}
4573
4574static void mg_socks_if_destroy_conn(struct mg_connection *c) {
4575 c->iface->vtable->free(c->iface);
4576 MG_FREE(c->iface);
4577 c->iface = NULL;
4578 LOG(LL_DEBUG, ("%p", c));
4579}
4580
4581static void mg_socks_if_sock_set(struct mg_connection *c, sock_t sock) {
4582 (void) c;
4583 (void) sock;
4584}
4585
4586static void mg_socks_if_init(struct mg_iface *iface) {
4587 (void) iface;
4588}
4589
4590static void mg_socks_if_free(struct mg_iface *iface) {
4591 struct socksdata *d = (struct socksdata *) iface->data;
4592 LOG(LL_DEBUG, ("%p", iface));
4593 if (d != NULL) {
4595 MG_FREE(d->proxy_addr);
4596 MG_FREE(d);
4597 iface->data = NULL;
4598 }
4599}
4600
4601static void mg_socks_if_add_conn(struct mg_connection *c) {
4602 c->sock = INVALID_SOCKET;
4603}
4604
4605static void mg_socks_if_remove_conn(struct mg_connection *c) {
4606 (void) c;
4607}
4608
4609static time_t mg_socks_if_poll(struct mg_iface *iface, int timeout_ms) {
4610 LOG(LL_DEBUG, ("%p", iface));
4611 (void) iface;
4612 (void) timeout_ms;
4613 return (time_t) cs_time();
4614}
4615
4616static void mg_socks_if_get_conn_addr(struct mg_connection *c, int remote,
4617 union socket_address *sa) {
4618 LOG(LL_DEBUG, ("%p", c));
4619 (void) c;
4620 (void) remote;
4621 (void) sa;
4622}
4623
4634};
4635
4636struct mg_iface *mg_socks_mk_iface(struct mg_mgr *mgr, const char *proxy_addr) {
4638 iface->data = MG_CALLOC(1, sizeof(struct socksdata));
4639 ((struct socksdata *) iface->data)->proxy_addr = strdup(proxy_addr);
4640 return iface;
4641}
4642
4643#endif
4644#ifdef MG_MODULE_LINES
4645#line 1 "mongoose/src/mg_ssl_if_openssl.c"
4646#endif
4647/*
4648 * Copyright (c) 2014-2016 Cesanta Software Limited
4649 * All rights reserved
4650 */
4651
4652#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_OPENSSL
4653
4654#ifdef __APPLE__
4655#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
4656#endif
4657
4658#include <openssl/ssl.h>
4659#ifndef KR_VERSION
4660#include <openssl/tls1.h>
4661#endif
4662
4663struct mg_ssl_if_ctx {
4664 SSL *ssl;
4665 SSL_CTX *ssl_ctx;
4666 struct mbuf psk;
4667 size_t identity_len;
4668};
4669
4670void mg_ssl_if_init() {
4672}
4673
4675 struct mg_connection *lc) {
4676 struct mg_ssl_if_ctx *ctx =
4677 (struct mg_ssl_if_ctx *) MG_CALLOC(1, sizeof(*ctx));
4678 struct mg_ssl_if_ctx *lc_ctx = (struct mg_ssl_if_ctx *) lc->ssl_if_data;
4679 nc->ssl_if_data = ctx;
4680 if (ctx == NULL || lc_ctx == NULL) return MG_SSL_ERROR;
4681 ctx->ssl_ctx = lc_ctx->ssl_ctx;
4682 if ((ctx->ssl = SSL_new(ctx->ssl_ctx)) == NULL) {
4683 return MG_SSL_ERROR;
4684 }
4685 return MG_SSL_OK;
4686}
4687
4688static enum mg_ssl_if_result mg_use_cert(SSL_CTX *ctx, const char *cert,
4689 const char *key, const char **err_msg);
4690static enum mg_ssl_if_result mg_use_ca_cert(SSL_CTX *ctx, const char *cert);
4691static enum mg_ssl_if_result mg_set_cipher_list(SSL_CTX *ctx, const char *cl);
4693 const char *identity,
4694 const char *key_str);
4695
4697 struct mg_connection *nc, const struct mg_ssl_if_conn_params *params,
4698 const char **err_msg) {
4699 struct mg_ssl_if_ctx *ctx =
4700 (struct mg_ssl_if_ctx *) MG_CALLOC(1, sizeof(*ctx));
4701 DBG(("%p %s,%s,%s", nc, (params->cert ? params->cert : ""),
4702 (params->key ? params->key : ""),
4703 (params->ca_cert ? params->ca_cert : "")));
4704 if (ctx == NULL) {
4705 MG_SET_PTRPTR(err_msg, "Out of memory");
4706 return MG_SSL_ERROR;
4707 }
4708 nc->ssl_if_data = ctx;
4709 if (nc->flags & MG_F_LISTENING) {
4710 ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
4711 } else {
4712 ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
4713 }
4714 if (ctx->ssl_ctx == NULL) {
4715 MG_SET_PTRPTR(err_msg, "Failed to create SSL context");
4716 return MG_SSL_ERROR;
4717 }
4718
4719#ifndef KR_VERSION
4720 /* Disable deprecated protocols. */
4721 SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2);
4722 SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv3);
4723 SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1);
4724#ifdef MG_SSL_OPENSSL_NO_COMPRESSION
4726#endif
4727#ifdef MG_SSL_OPENSSL_CIPHER_SERVER_PREFERENCE
4729#endif
4730#else
4731/* Krypton only supports TLSv1.2 anyway. */
4732#endif
4733
4734 if (params->cert != NULL &&
4735 mg_use_cert(ctx->ssl_ctx, params->cert, params->key, err_msg) !=
4736 MG_SSL_OK) {
4737 return MG_SSL_ERROR;
4738 }
4739
4740 if (params->ca_cert != NULL &&
4741 mg_use_ca_cert(ctx->ssl_ctx, params->ca_cert) != MG_SSL_OK) {
4742 MG_SET_PTRPTR(err_msg, "Invalid SSL CA cert");
4743 return MG_SSL_ERROR;
4744 }
4745
4746 if (mg_set_cipher_list(ctx->ssl_ctx, params->cipher_suites) != MG_SSL_OK) {
4747 MG_SET_PTRPTR(err_msg, "Invalid cipher suite list");
4748 return MG_SSL_ERROR;
4749 }
4750
4751 mbuf_init(&ctx->psk, 0);
4752 if (mg_ssl_if_ossl_set_psk(ctx, params->psk_identity, params->psk_key) !=
4753 MG_SSL_OK) {
4754 MG_SET_PTRPTR(err_msg, "Invalid PSK settings");
4755 return MG_SSL_ERROR;
4756 }
4757
4758 if (!(nc->flags & MG_F_LISTENING) &&
4759 (ctx->ssl = SSL_new(ctx->ssl_ctx)) == NULL) {
4760 MG_SET_PTRPTR(err_msg, "Failed to create SSL session");
4761 return MG_SSL_ERROR;
4762 }
4763
4764 if (params->server_name != NULL) {
4765#ifdef KR_VERSION
4766 SSL_CTX_kr_set_verify_name(ctx->ssl_ctx, params->server_name);
4767#else
4768 SSL_set_tlsext_host_name(ctx->ssl, params->server_name);
4769#endif
4770 }
4771
4772 nc->flags |= MG_F_SSL;
4773
4774 return MG_SSL_OK;
4775}
4776
4777static enum mg_ssl_if_result mg_ssl_if_ssl_err(struct mg_connection *nc,
4778 int res) {
4779 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
4780 int err = SSL_get_error(ctx->ssl, res);
4781 if (err == SSL_ERROR_WANT_READ) return MG_SSL_WANT_READ;
4782 if (err == SSL_ERROR_WANT_WRITE) return MG_SSL_WANT_WRITE;
4783 DBG(("%p %p SSL error: %d %d", nc, ctx->ssl_ctx, res, err));
4784 nc->err = err;
4785 return MG_SSL_ERROR;
4786}
4787
4789 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
4790 int server_side = (nc->listener != NULL);
4791 int res;
4792 /* If descriptor is not yet set, do it now. */
4793 if (SSL_get_fd(ctx->ssl) < 0) {
4794 if (SSL_set_fd(ctx->ssl, nc->sock) != 1) return MG_SSL_ERROR;
4795 }
4796 res = server_side ? SSL_accept(ctx->ssl) : SSL_connect(ctx->ssl);
4797 if (res != 1) return mg_ssl_if_ssl_err(nc, res);
4798 return MG_SSL_OK;
4799}
4800
4801int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t buf_size) {
4802 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
4803 int n = SSL_read(ctx->ssl, buf, buf_size);
4804 DBG(("%p %d -> %d", nc, (int) buf_size, n));
4805 if (n < 0) return mg_ssl_if_ssl_err(nc, n);
4806 if (n == 0) nc->flags |= MG_F_CLOSE_IMMEDIATELY;
4807 return n;
4808}
4809
4810int mg_ssl_if_write(struct mg_connection *nc, const void *data, size_t len) {
4811 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
4812 int n = SSL_write(ctx->ssl, data, len);
4813 DBG(("%p %d -> %d", nc, (int) len, n));
4814 if (n <= 0) return mg_ssl_if_ssl_err(nc, n);
4815 return n;
4816}
4817
4819 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
4820 if (ctx == NULL) return;
4821 SSL_shutdown(ctx->ssl);
4822}
4823
4824void mg_ssl_if_conn_free(struct mg_connection *nc) {
4825 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
4826 if (ctx == NULL) return;
4827 nc->ssl_if_data = NULL;
4828 if (ctx->ssl != NULL) SSL_free(ctx->ssl);
4829 if (ctx->ssl_ctx != NULL && nc->listener == NULL) SSL_CTX_free(ctx->ssl_ctx);
4830 mbuf_free(&ctx->psk);
4831 memset(ctx, 0, sizeof(*ctx));
4832 MG_FREE(ctx);
4833}
4834
4835/*
4836 * Cipher suite options used for TLS negotiation.
4837 * https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations
4838 */
4839static const char mg_s_cipher_list[] =
4840#if defined(MG_SSL_CRYPTO_MODERN)
4841 "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:"
4842 "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:"
4843 "DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:"
4844 "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:"
4845 "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:"
4846 "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:"
4847 "DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:"
4848 "DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:"
4849 "!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK"
4850#elif defined(MG_SSL_CRYPTO_OLD)
4851 "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:"
4852 "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:"
4853 "DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:"
4854 "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:"
4855 "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:"
4856 "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:"
4857 "DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:"
4858 "DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:"
4859 "ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:"
4860 "AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:"
4861 "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:"
4862 "!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"
4863#else /* Default - intermediate. */
4864 "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:"
4865 "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:"
4866 "DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:"
4867 "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:"
4868 "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:"
4869 "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:"
4870 "DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:"
4871 "DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:"
4872 "AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:"
4873 "DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:"
4874 "!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"
4875#endif
4876 ;
4877
4878/*
4879 * Default DH params for PFS cipher negotiation. This is a 2048-bit group.
4880 * Will be used if none are provided by the user in the certificate file.
4881 */
4882#if !MG_DISABLE_PFS && !defined(KR_VERSION)
4883static const char mg_s_default_dh_params[] =
4884 "\
4885-----BEGIN DH PARAMETERS-----\n\
4886MIIBCAKCAQEAlvbgD/qh9znWIlGFcV0zdltD7rq8FeShIqIhkQ0C7hYFThrBvF2E\n\
4887Z9bmgaP+sfQwGpVlv9mtaWjvERbu6mEG7JTkgmVUJrUt/wiRzwTaCXBqZkdUO8Tq\n\
4888+E6VOEQAilstG90ikN1Tfo+K6+X68XkRUIlgawBTKuvKVwBhuvlqTGerOtnXWnrt\n\
4889ym//hd3cd5PBYGBix0i7oR4xdghvfR2WLVu0LgdThTBb6XP7gLd19cQ1JuBtAajZ\n\
4890wMuPn7qlUkEFDIkAZy59/Hue/H2Q2vU/JsvVhHWCQBL4F1ofEAt50il6ZxR1QfFK\n\
48919VGKDC4oOgm9DlxwwBoC2FjqmvQlqVV3kwIBAg==\n\
4892-----END DH PARAMETERS-----\n";
4893#endif
4894
4895static enum mg_ssl_if_result mg_use_ca_cert(SSL_CTX *ctx, const char *cert) {
4896 if (cert == NULL || strcmp(cert, "*") == 0) {
4897 return MG_SSL_OK;
4898 }
4901 : MG_SSL_ERROR;
4902}
4903
4904static enum mg_ssl_if_result mg_use_cert(SSL_CTX *ctx, const char *cert,
4905 const char *key,
4906 const char **err_msg) {
4907 if (key == NULL) key = cert;
4908 if (cert == NULL || cert[0] == '\0' || key == NULL || key[0] == '\0') {
4909 return MG_SSL_OK;
4910 } else if (SSL_CTX_use_certificate_file(ctx, cert, 1) == 0) {
4911 MG_SET_PTRPTR(err_msg, "Invalid SSL cert");
4912 return MG_SSL_ERROR;
4913 } else if (SSL_CTX_use_PrivateKey_file(ctx, key, 1) == 0) {
4914 MG_SET_PTRPTR(err_msg, "Invalid SSL key");
4915 return MG_SSL_ERROR;
4916 } else if (SSL_CTX_use_certificate_chain_file(ctx, cert) == 0) {
4917 MG_SET_PTRPTR(err_msg, "Invalid CA bundle");
4918 return MG_SSL_ERROR;
4919 } else {
4921#if !MG_DISABLE_PFS && !defined(KR_VERSION)
4922 BIO *bio = NULL;
4923 DH *dh = NULL;
4924
4925 /* Try to read DH parameters from the cert/key file. */
4926 bio = BIO_new_file(cert, "r");
4927 if (bio != NULL) {
4929 BIO_free(bio);
4930 }
4931 /*
4932 * If there are no DH params in the file, fall back to hard-coded ones.
4933 * Not ideal, but better than nothing.
4934 */
4935 if (dh == NULL) {
4938 BIO_free(bio);
4939 }
4940 if (dh != NULL) {
4941 SSL_CTX_set_tmp_dh(ctx, dh);
4943 DH_free(dh);
4944 }
4945#if OPENSSL_VERSION_NUMBER > 0x10002000L
4946 SSL_CTX_set_ecdh_auto(ctx, 1);
4947#endif
4948#endif
4949 }
4950 return MG_SSL_OK;
4951}
4952
4953static enum mg_ssl_if_result mg_set_cipher_list(SSL_CTX *ctx, const char *cl) {
4954 return (SSL_CTX_set_cipher_list(ctx, cl ? cl : mg_s_cipher_list) == 1
4955 ? MG_SSL_OK
4956 : MG_SSL_ERROR);
4957}
4958
4959#ifndef KR_VERSION
4960static unsigned int mg_ssl_if_ossl_psk_cb(SSL *ssl, const char *hint,
4961 char *identity,
4962 unsigned int max_identity_len,
4963 unsigned char *psk,
4964 unsigned int max_psk_len) {
4965 struct mg_ssl_if_ctx *ctx =
4967 size_t key_len = ctx->psk.len - ctx->identity_len - 1;
4968 DBG(("hint: '%s'", (hint ? hint : "")));
4969 if (ctx->identity_len + 1 > max_identity_len) {
4970 DBG(("identity too long"));
4971 return 0;
4972 }
4973 if (key_len > max_psk_len) {
4974 DBG(("key too long"));
4975 return 0;
4976 }
4977 memcpy(identity, ctx->psk.buf, ctx->identity_len + 1);
4978 memcpy(psk, ctx->psk.buf + ctx->identity_len + 1, key_len);
4979 (void) ssl;
4980 return key_len;
4981}
4982
4984 const char *identity,
4985 const char *key_str) {
4986 unsigned char key[32];
4987 size_t key_len;
4988 size_t i = 0;
4989 if (identity == NULL && key_str == NULL) return MG_SSL_OK;
4990 if (identity == NULL || key_str == NULL) return MG_SSL_ERROR;
4992 if (key_len != 32 && key_len != 64) return MG_SSL_ERROR;
4993 memset(key, 0, sizeof(key));
4994 key_len = 0;
4995 for (i = 0; key_str[i] != '\0'; i++) {
4996 unsigned char c;
4997 char hc = tolower((int) key_str[i]);
4998 if (hc >= '0' && hc <= '9') {
4999 c = hc - '0';
5000 } else if (hc >= 'a' && hc <= 'f') {
5001 c = hc - 'a' + 0xa;
5002 } else {
5003 return MG_SSL_ERROR;
5004 }
5005 key_len = i / 2;
5006 key[key_len] <<= 4;
5007 key[key_len] |= c;
5008 }
5009 key_len++;
5010 DBG(("identity = '%s', key = (%u)", identity, (unsigned int) key_len));
5011 ctx->identity_len = strlen(identity);
5012 mbuf_append(&ctx->psk, identity, ctx->identity_len + 1);
5013 mbuf_append(&ctx->psk, key, key_len);
5015 SSL_CTX_set_app_data(ctx->ssl_ctx, ctx);
5016 return MG_SSL_OK;
5017}
5018#else
5020 const char *identity,
5021 const char *key_str) {
5022 (void) ctx;
5023 (void) identity;
5024 (void) key_str;
5025 /* Krypton does not support PSK. */
5026 return MG_SSL_ERROR;
5027}
5028#endif /* defined(KR_VERSION) */
5029
5030const char *mg_set_ssl(struct mg_connection *nc, const char *cert,
5031 const char *ca_cert) {
5032 const char *err_msg = NULL;
5033 struct mg_ssl_if_conn_params params;
5034 memset(&params, 0, sizeof(params));
5035 params.cert = cert;
5036 params.ca_cert = ca_cert;
5037 if (mg_ssl_if_conn_init(nc, &params, &err_msg) != MG_SSL_OK) {
5038 return err_msg;
5039 }
5040 return NULL;
5041}
5042
5043#endif /* MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_OPENSSL */
5044#ifdef MG_MODULE_LINES
5045#line 1 "mongoose/src/mg_ssl_if_mbedtls.c"
5046#endif
5047/*
5048 * Copyright (c) 2014-2016 Cesanta Software Limited
5049 * All rights reserved
5050 */
5051
5052#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_MBEDTLS
5053
5054#include <mbedtls/debug.h>
5055#include <mbedtls/ecp.h>
5056#include <mbedtls/net.h>
5057#include <mbedtls/platform.h>
5058#include <mbedtls/ssl.h>
5059#include <mbedtls/ssl_internal.h>
5060#include <mbedtls/x509_crt.h>
5061#include <mbedtls/version.h>
5062
5063static void mg_ssl_mbed_log(void *ctx, int level, const char *file, int line,
5064 const char *str) {
5066 switch (level) {
5067 case 1:
5069 break;
5070 case 2:
5071 cs_level = LL_INFO;
5072 break;
5073 case 3:
5075 break;
5076 default:
5078 }
5079 /* mbedTLS passes strings with \n at the end, strip it. */
5080 LOG(cs_level, ("%p %.*s", ctx, (int) (strlen(str) - 1), str));
5081 (void) ctx;
5082 (void) str;
5083 (void) file;
5084 (void) line;
5085 (void) cs_level;
5086}
5087
5088struct mg_ssl_if_ctx {
5094 struct mbuf cipher_suites;
5095 size_t saved_len;
5096};
5097
5098/* Must be provided by the platform. ctx is struct mg_connection. */
5099extern int mg_ssl_if_mbed_random(void *ctx, unsigned char *buf, size_t len);
5100
5101void mg_ssl_if_init() {
5103}
5104
5106 struct mg_connection *lc) {
5107 struct mg_ssl_if_ctx *ctx =
5108 (struct mg_ssl_if_ctx *) MG_CALLOC(1, sizeof(*ctx));
5109 struct mg_ssl_if_ctx *lc_ctx = (struct mg_ssl_if_ctx *) lc->ssl_if_data;
5110 nc->ssl_if_data = ctx;
5111 if (ctx == NULL || lc_ctx == NULL) return MG_SSL_ERROR;
5112 ctx->ssl = (mbedtls_ssl_context *) MG_CALLOC(1, sizeof(*ctx->ssl));
5113 if (mbedtls_ssl_setup(ctx->ssl, lc_ctx->conf) != 0) {
5114 return MG_SSL_ERROR;
5115 }
5116 return MG_SSL_OK;
5117}
5118
5119static enum mg_ssl_if_result mg_use_cert(struct mg_ssl_if_ctx *ctx,
5120 const char *cert, const char *key,
5121 const char **err_msg);
5122static enum mg_ssl_if_result mg_use_ca_cert(struct mg_ssl_if_ctx *ctx,
5123 const char *cert);
5124static enum mg_ssl_if_result mg_set_cipher_list(struct mg_ssl_if_ctx *ctx,
5125 const char *ciphers);
5126#ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED
5128 const char *identity,
5129 const char *key);
5130#endif
5131
5133 struct mg_connection *nc, const struct mg_ssl_if_conn_params *params,
5134 const char **err_msg) {
5135 struct mg_ssl_if_ctx *ctx =
5136 (struct mg_ssl_if_ctx *) MG_CALLOC(1, sizeof(*ctx));
5137 DBG(("%p %s,%s,%s", nc, (params->cert ? params->cert : ""),
5138 (params->key ? params->key : ""),
5139 (params->ca_cert ? params->ca_cert : "")));
5140
5141 if (ctx == NULL) {
5142 MG_SET_PTRPTR(err_msg, "Out of memory");
5143 return MG_SSL_ERROR;
5144 }
5145 nc->ssl_if_data = ctx;
5146 ctx->conf = (mbedtls_ssl_config *) MG_CALLOC(1, sizeof(*ctx->conf));
5147 mbuf_init(&ctx->cipher_suites, 0);
5148 mbedtls_ssl_config_init(ctx->conf);
5149 mbedtls_ssl_conf_dbg(ctx->conf, mg_ssl_mbed_log, nc);
5151 ctx->conf, (nc->flags & MG_F_LISTENING ? MBEDTLS_SSL_IS_SERVER
5154 MG_SET_PTRPTR(err_msg, "Failed to init SSL config");
5155 return MG_SSL_ERROR;
5156 }
5157
5158 /* TLS 1.2 and up */
5162
5163 if (params->cert != NULL &&
5164 mg_use_cert(ctx, params->cert, params->key, err_msg) != MG_SSL_OK) {
5165 return MG_SSL_ERROR;
5166 }
5167
5168 if (params->ca_cert != NULL &&
5169 mg_use_ca_cert(ctx, params->ca_cert) != MG_SSL_OK) {
5170 MG_SET_PTRPTR(err_msg, "Invalid SSL CA cert");
5171 return MG_SSL_ERROR;
5172 }
5173
5174 if (mg_set_cipher_list(ctx, params->cipher_suites) != MG_SSL_OK) {
5175 MG_SET_PTRPTR(err_msg, "Invalid cipher suite list");
5176 return MG_SSL_ERROR;
5177 }
5178
5179#ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED
5180 if (mg_ssl_if_mbed_set_psk(ctx, params->psk_identity, params->psk_key) !=
5181 MG_SSL_OK) {
5182 MG_SET_PTRPTR(err_msg, "Invalid PSK settings");
5183 return MG_SSL_ERROR;
5184 }
5185#endif
5186
5187 if (!(nc->flags & MG_F_LISTENING)) {
5188 ctx->ssl = (mbedtls_ssl_context *) MG_CALLOC(1, sizeof(*ctx->ssl));
5189 mbedtls_ssl_init(ctx->ssl);
5190 if (mbedtls_ssl_setup(ctx->ssl, ctx->conf) != 0) {
5191 MG_SET_PTRPTR(err_msg, "Failed to create SSL session");
5192 return MG_SSL_ERROR;
5193 }
5194 if (params->server_name != NULL &&
5195 mbedtls_ssl_set_hostname(ctx->ssl, params->server_name) != 0) {
5196 return MG_SSL_ERROR;
5197 }
5198 }
5199
5200#ifdef MG_SSL_IF_MBEDTLS_MAX_FRAG_LEN
5201 if (mbedtls_ssl_conf_max_frag_len(ctx->conf,
5210#else
5212#endif
5213 ) != 0) {
5214 return MG_SSL_ERROR;
5215 }
5216#endif
5217
5218 nc->flags |= MG_F_SSL;
5219
5220 return MG_SSL_OK;
5221}
5222
5223static int mg_ssl_if_mbed_send(void *ctx, const unsigned char *buf,
5224 size_t len) {
5225 struct mg_connection *nc = (struct mg_connection *) ctx;
5226 int n = nc->iface->vtable->tcp_send(nc, buf, len);
5227 if (n > 0) return n;
5228 if (n == 0) return MBEDTLS_ERR_SSL_WANT_WRITE;
5230}
5231
5232static int mg_ssl_if_mbed_recv(void *ctx, unsigned char *buf, size_t len) {
5233 struct mg_connection *nc = (struct mg_connection *) ctx;
5234 int n = nc->iface->vtable->tcp_recv(nc, buf, len);
5235 if (n > 0) return n;
5236 if (n == 0) return MBEDTLS_ERR_SSL_WANT_READ;
5238}
5239
5241 int ret) {
5243 if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
5245 } else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
5247 } else if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
5248 LOG(LL_DEBUG, ("%p TLS connection closed by peer", nc));
5250 res = MG_SSL_OK;
5251 } else {
5252 LOG(LL_ERROR, ("%p mbedTLS error: -0x%04x", nc, -ret));
5254 res = MG_SSL_ERROR;
5255 }
5256 nc->err = ret;
5257 return res;
5258}
5259
5261 if (ctx->cert != NULL) {
5263 MG_FREE(ctx->cert);
5264 ctx->cert = NULL;
5265 mbedtls_pk_free(ctx->key);
5266 MG_FREE(ctx->key);
5267 ctx->key = NULL;
5268 }
5269 if (ctx->ca_cert != NULL) {
5271#ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK
5272 if (ctx->conf->ca_chain_file != NULL) {
5273 MG_FREE((void *) ctx->conf->ca_chain_file);
5274 ctx->conf->ca_chain_file = NULL;
5275 }
5276#endif
5277 mbedtls_x509_crt_free(ctx->ca_cert);
5278 MG_FREE(ctx->ca_cert);
5279 ctx->ca_cert = NULL;
5280 }
5281}
5282
5284 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
5285 int err;
5286 /* If bio is not yet set, do it now. */
5287 if (ctx->ssl->p_bio == NULL) {
5289 NULL);
5290 }
5291 err = mbedtls_ssl_handshake(ctx->ssl);
5292 if (err != 0) return mg_ssl_if_mbed_err(nc, err);
5293#ifdef MG_SSL_IF_MBEDTLS_FREE_CERTS
5294 /*
5295 * Free the peer certificate, we don't need it after handshake.
5296 * Note that this effectively disables renegotiation.
5297 */
5298 mbedtls_x509_crt_free(ctx->ssl->session->peer_cert);
5299 mbedtls_free(ctx->ssl->session->peer_cert);
5300 ctx->ssl->session->peer_cert = NULL;
5301 /* On a client connection we can also free our own and CA certs. */
5302 if (nc->listener == NULL) {
5303 if (ctx->conf->key_cert != NULL) {
5304 /* Note that this assumes one key_cert entry, which matches our init. */
5305 MG_FREE(ctx->conf->key_cert);
5306 ctx->conf->key_cert = NULL;
5307 }
5308 mbedtls_ssl_conf_ca_chain(ctx->conf, NULL, NULL);
5310 }
5311#endif
5312 return MG_SSL_OK;
5313}
5314
5315int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t len) {
5316 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
5317 int n = mbedtls_ssl_read(ctx->ssl, (unsigned char *) buf, len);
5318 DBG(("%p %d -> %d", nc, (int) len, n));
5319 if (n < 0) return mg_ssl_if_mbed_err(nc, n);
5320 if (n == 0) nc->flags |= MG_F_CLOSE_IMMEDIATELY;
5321 return n;
5322}
5323
5324int mg_ssl_if_write(struct mg_connection *nc, const void *buf, size_t len) {
5325 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
5326 /* Per mbedTLS docs, if write returns WANT_READ or WANT_WRITE, the operation
5327 * should be retried with the same data and length.
5328 * Here we assume that the data being pushed will remain the same but the
5329 * amount may grow between calls so we save the length that was used and
5330 * retry. The assumption being that the data itself won't change and won't
5331 * be removed. */
5332 size_t l = len;
5333 if (ctx->saved_len > 0 && ctx->saved_len < l) l = ctx->saved_len;
5334 int n = mbedtls_ssl_write(ctx->ssl, (const unsigned char *) buf, l);
5335 DBG(("%p %d,%d,%d -> %d", nc, (int) len, (int) ctx->saved_len, (int) l, n));
5336 if (n < 0) {
5338 ctx->saved_len = len;
5339 }
5340 return mg_ssl_if_mbed_err(nc, n);
5341 } else if (n > 0) {
5342 ctx->saved_len = 0;
5343 }
5344 return n;
5345}
5346
5348 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
5349 if (ctx == NULL) return;
5350 mbedtls_ssl_close_notify(ctx->ssl);
5351}
5352
5353void mg_ssl_if_conn_free(struct mg_connection *nc) {
5354 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
5355 if (ctx == NULL) return;
5356 nc->ssl_if_data = NULL;
5357 if (ctx->ssl != NULL) {
5358 mbedtls_ssl_free(ctx->ssl);
5359 MG_FREE(ctx->ssl);
5360 }
5362 if (ctx->conf != NULL) {
5363 mbedtls_ssl_config_free(ctx->conf);
5364 MG_FREE(ctx->conf);
5365 }
5366 mbuf_free(&ctx->cipher_suites);
5367 memset(ctx, 0, sizeof(*ctx));
5368 MG_FREE(ctx);
5369}
5370
5371static enum mg_ssl_if_result mg_use_ca_cert(struct mg_ssl_if_ctx *ctx,
5372 const char *ca_cert) {
5373 if (ca_cert == NULL || strcmp(ca_cert, "*") == 0) {
5375 return MG_SSL_OK;
5376 }
5377 ctx->ca_cert = (mbedtls_x509_crt *) MG_CALLOC(1, sizeof(*ctx->ca_cert));
5378 mbedtls_x509_crt_init(ctx->ca_cert);
5379#ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK
5382#else
5383 if (mbedtls_x509_crt_parse_file(ctx->ca_cert, ca_cert) != 0) {
5384 return MG_SSL_ERROR;
5385 }
5386 mbedtls_ssl_conf_ca_chain(ctx->conf, ctx->ca_cert, NULL);
5387#endif
5389 return MG_SSL_OK;
5390}
5391
5392static enum mg_ssl_if_result mg_use_cert(struct mg_ssl_if_ctx *ctx,
5393 const char *cert, const char *key,
5394 const char **err_msg) {
5395 if (key == NULL) key = cert;
5396 if (cert == NULL || cert[0] == '\0' || key == NULL || key[0] == '\0') {
5397 return MG_SSL_OK;
5398 }
5399 ctx->cert = (mbedtls_x509_crt *) MG_CALLOC(1, sizeof(*ctx->cert));
5400 mbedtls_x509_crt_init(ctx->cert);
5401 ctx->key = (mbedtls_pk_context *) MG_CALLOC(1, sizeof(*ctx->key));
5402 mbedtls_pk_init(ctx->key);
5403 if (mbedtls_x509_crt_parse_file(ctx->cert, cert) != 0) {
5404 MG_SET_PTRPTR(err_msg, "Invalid SSL cert");
5405 return MG_SSL_ERROR;
5406 }
5407 if (mbedtls_pk_parse_keyfile(ctx->key, key, NULL) != 0) {
5408 MG_SET_PTRPTR(err_msg, "Invalid SSL key");
5409 return MG_SSL_ERROR;
5410 }
5411 if (mbedtls_ssl_conf_own_cert(ctx->conf, ctx->cert, ctx->key) != 0) {
5412 MG_SET_PTRPTR(err_msg, "Invalid SSL key or cert");
5413 return MG_SSL_ERROR;
5414 }
5415 return MG_SSL_OK;
5416}
5417
5418static const int mg_s_cipher_list[] = {
5419#if CS_PLATFORM != CS_P_ESP8266
5435#else
5436 /*
5437 * ECDHE is way too slow on ESP8266 w/o cryptochip, this sometimes results
5438 * in WiFi STA deauths. Use weaker but faster cipher suites. Sad but true.
5439 * Disable DHE completely because it's just hopelessly slow.
5440 */
5454#endif /* CS_PLATFORM != CS_P_ESP8266 */
5455 0,
5456};
5457
5458/*
5459 * Ciphers can be specified as a colon-separated list of cipher suite names.
5460 * These can be found in
5461 * https://github.com/ARMmbed/mbedtls/blob/development/library/ssl_ciphersuites.c#L267
5462 * E.g.: TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-CCM
5463 */
5464static enum mg_ssl_if_result mg_set_cipher_list(struct mg_ssl_if_ctx *ctx,
5465 const char *ciphers) {
5466 if (ciphers != NULL) {
5467 int l, id;
5468 const char *s = ciphers, *e;
5469 char tmp[50];
5470 while (s != NULL) {
5471 e = strchr(s, ':');
5472 l = (e != NULL ? (e - s) : (int) strlen(s));
5473 strncpy(tmp, s, l);
5474 tmp[l] = '\0';
5476 DBG(("%s -> %04x", tmp, id));
5477 if (id != 0) {
5478 mbuf_append(&ctx->cipher_suites, &id, sizeof(id));
5479 }
5480 s = (e != NULL ? e + 1 : NULL);
5481 }
5482 if (ctx->cipher_suites.len == 0) return MG_SSL_ERROR;
5483 id = 0;
5484 mbuf_append(&ctx->cipher_suites, &id, sizeof(id));
5485 mbuf_trim(&ctx->cipher_suites);
5487 (const int *) ctx->cipher_suites.buf);
5488 } else {
5490 }
5491 return MG_SSL_OK;
5492}
5493
5494#ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED
5496 const char *identity,
5497 const char *key_str) {
5498 unsigned char key[32];
5499 size_t key_len;
5500 if (identity == NULL && key_str == NULL) return MG_SSL_OK;
5501 if (identity == NULL || key_str == NULL) return MG_SSL_ERROR;
5503 if (key_len != 32 && key_len != 64) return MG_SSL_ERROR;
5504 size_t i = 0;
5505 memset(key, 0, sizeof(key));
5506 key_len = 0;
5507 for (i = 0; key_str[i] != '\0'; i++) {
5508 unsigned char c;
5509 char hc = tolower((int) key_str[i]);
5510 if (hc >= '0' && hc <= '9') {
5511 c = hc - '0';
5512 } else if (hc >= 'a' && hc <= 'f') {
5513 c = hc - 'a' + 0xa;
5514 } else {
5515 return MG_SSL_ERROR;
5516 }
5517 key_len = i / 2;
5518 key[key_len] <<= 4;
5519 key[key_len] |= c;
5520 }
5521 key_len++;
5522 DBG(("identity = '%s', key = (%u)", identity, (unsigned int) key_len));
5523 /* mbedTLS makes copies of psk and identity. */
5524 if (mbedtls_ssl_conf_psk(ctx->conf, (const unsigned char *) key, key_len,
5525 (const unsigned char *) identity,
5526 strlen(identity)) != 0) {
5527 return MG_SSL_ERROR;
5528 }
5529 return MG_SSL_OK;
5530}
5531#endif
5532
5533const char *mg_set_ssl(struct mg_connection *nc, const char *cert,
5534 const char *ca_cert) {
5535 const char *err_msg = NULL;
5536 struct mg_ssl_if_conn_params params;
5537 memset(&params, 0, sizeof(params));
5538 params.cert = cert;
5539 params.ca_cert = ca_cert;
5540 if (mg_ssl_if_conn_init(nc, &params, &err_msg) != MG_SSL_OK) {
5541 return err_msg;
5542 }
5543 return NULL;
5544}
5545
5546/* Lazy RNG. Warning: it would be a bad idea to do this in production! */
5547#ifdef MG_SSL_MBED_DUMMY_RANDOM
5548int mg_ssl_if_mbed_random(void *ctx, unsigned char *buf, size_t len) {
5549 (void) ctx;
5550 while (len--) *buf++ = rand();
5551 return 0;
5552}
5553#endif
5554
5555#endif /* MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_MBEDTLS */
5556#ifdef MG_MODULE_LINES
5557#line 1 "mongoose/src/mg_uri.c"
5558#endif
5559/*
5560 * Copyright (c) 2014 Cesanta Software Limited
5561 * All rights reserved
5562 */
5563
5564/* Amalgamated: #include "mg_internal.h" */
5565/* Amalgamated: #include "mg_uri.h" */
5566
5567/*
5568 * scan string until encountering one of `seps`, keeping track of component
5569 * boundaries in `res`.
5570 *
5571 * `p` will point to the char after the separator or it will be `end`.
5572 */
5573static void parse_uri_component(const char **p, const char *end,
5574 const char *seps, struct mg_str *res) {
5575 const char *q;
5576 res->p = *p;
5577 for (; *p < end; (*p)++) {
5578 for (q = seps; *q != '\0'; q++) {
5579 if (**p == *q) break;
5580 }
5581 if (*q != '\0') break;
5582 }
5583 res->len = (*p) - res->p;
5584 if (*p < end) (*p)++;
5585}
5586
5587int mg_parse_uri(const struct mg_str uri, struct mg_str *scheme,
5588 struct mg_str *user_info, struct mg_str *host,
5589 unsigned int *port, struct mg_str *path, struct mg_str *query,
5590 struct mg_str *fragment) {
5591 struct mg_str rscheme = {0, 0}, ruser_info = {0, 0}, rhost = {0, 0},
5592 rpath = {0, 0}, rquery = {0, 0}, rfragment = {0, 0};
5593 unsigned int rport = 0;
5594 enum {
5595 P_START,
5598 P_HOST,
5599 P_PORT,
5600 P_REST
5601 } state = P_START;
5602
5603 const char *p = uri.p, *end = p + uri.len;
5604 while (p < end) {
5605 switch (state) {
5606 case P_START:
5607 /*
5608 * expecting on of:
5609 * - `scheme://xxxx`
5610 * - `xxxx:port`
5611 * - `[a:b:c]:port`
5612 * - `xxxx/path`
5613 */
5614 if (*p == '[') {
5615 state = P_HOST;
5616 break;
5617 }
5618 for (; p < end; p++) {
5619 if (*p == ':') {
5621 break;
5622 } else if (*p == '/') {
5623 state = P_REST;
5624 break;
5625 }
5626 }
5627 if (state == P_START || state == P_REST) {
5628 rhost.p = uri.p;
5629 rhost.len = p - uri.p;
5630 }
5631 break;
5632 case P_SCHEME_OR_PORT:
5633 if (end - p >= 3 && strncmp(p, "://", 3) == 0) {
5634 rscheme.p = uri.p;
5635 rscheme.len = p - uri.p;
5637 p += 3;
5638 } else {
5639 rhost.p = uri.p;
5640 rhost.len = p - uri.p;
5641 state = P_PORT;
5642 }
5643 break;
5644 case P_USER_INFO:
5645 ruser_info.p = p;
5646 for (; p < end; p++) {
5647 if (*p == '@' || *p == '[' || *p == '/') {
5648 break;
5649 }
5650 }
5651 if (p == end || *p == '/' || *p == '[') {
5652 /* backtrack and parse as host */
5653 p = ruser_info.p;
5654 }
5655 ruser_info.len = p - ruser_info.p;
5656 state = P_HOST;
5657 break;
5658 case P_HOST:
5659 if (*p == '@') p++;
5660 rhost.p = p;
5661 if (*p == '[') {
5662 int found = 0;
5663 for (; !found && p < end; p++) {
5664 found = (*p == ']');
5665 }
5666 if (!found) return -1;
5667 } else {
5668 for (; p < end; p++) {
5669 if (*p == ':' || *p == '/') break;
5670 }
5671 }
5672 rhost.len = p - rhost.p;
5673 if (p < end) {
5674 if (*p == ':') {
5675 state = P_PORT;
5676 break;
5677 } else if (*p == '/') {
5678 state = P_REST;
5679 break;
5680 }
5681 }
5682 break;
5683 case P_PORT:
5684 p++;
5685 for (; p < end; p++) {
5686 if (*p == '/') {
5687 state = P_REST;
5688 break;
5689 }
5690 rport *= 10;
5691 rport += *p - '0';
5692 }
5693 break;
5694 case P_REST:
5695 /* `p` points to separator. `path` includes the separator */
5696 parse_uri_component(&p, end, "?#", &rpath);
5697 if (p < end && *(p - 1) == '?') {
5698 parse_uri_component(&p, end, "#", &rquery);
5699 }
5701 break;
5702 }
5703 }
5704
5705 if (scheme != 0) *scheme = rscheme;
5706 if (user_info != 0) *user_info = ruser_info;
5707 if (host != 0) *host = rhost;
5708 if (port != 0) *port = rport;
5709 if (path != 0) *path = rpath;
5710 if (query != 0) *query = rquery;
5711 if (fragment != 0) *fragment = rfragment;
5712
5713 return 0;
5714}
5715
5716/* Normalize the URI path. Remove/resolve "." and "..". */
5717int mg_normalize_uri_path(const struct mg_str *in, struct mg_str *out) {
5718 const char *s = in->p, *se = s + in->len;
5719 char *cp = (char *) out->p, *d;
5720
5721 if (in->len == 0 || *s != '/') {
5722 out->len = 0;
5723 return 0;
5724 }
5725
5726 d = cp;
5727
5728 while (s < se) {
5729 const char *next = s;
5730 struct mg_str component;
5731 parse_uri_component(&next, se, "/", &component);
5732 if (mg_vcmp(&component, ".") == 0) {
5733 /* Yum. */
5734 } else if (mg_vcmp(&component, "..") == 0) {
5735 /* Backtrack to previous slash. */
5736 if (d > cp + 1 && *(d - 1) == '/') d--;
5737 while (d > cp && *(d - 1) != '/') d--;
5738 } else {
5739 memmove(d, s, next - s);
5740 d += next - s;
5741 }
5742 s = next;
5743 }
5744 if (d == cp) *d++ = '/';
5745
5746 out->p = cp;
5747 out->len = d - cp;
5748 return 1;
5749}
5750
5751int mg_assemble_uri(const struct mg_str *scheme, const struct mg_str *user_info,
5752 const struct mg_str *host, unsigned int port,
5753 const struct mg_str *path, const struct mg_str *query,
5754 const struct mg_str *fragment, int normalize_path,
5755 struct mg_str *uri) {
5756 int result = -1;
5757 struct mbuf out;
5758 mbuf_init(&out, 0);
5759
5760 if (scheme != NULL && scheme->len > 0) {
5761 mbuf_append(&out, scheme->p, scheme->len);
5762 mbuf_append(&out, "://", 3);
5763 }
5764
5765 if (user_info != NULL && user_info->len > 0) {
5766 mbuf_append(&out, user_info->p, user_info->len);
5767 mbuf_append(&out, "@", 1);
5768 }
5769
5770 if (host != NULL && host->len > 0) {
5771 mbuf_append(&out, host->p, host->len);
5772 }
5773
5774 if (port != 0) {
5775 char port_str[20];
5776 int port_str_len = sprintf(port_str, ":%u", port);
5778 }
5779
5780 if (path != NULL && path->len > 0) {
5781 if (normalize_path) {
5782 struct mg_str npath = mg_strdup(*path);
5783 if (npath.len != path->len) goto out;
5784 if (!mg_normalize_uri_path(path, &npath)) {
5785 free((void *) npath.p);
5786 goto out;
5787 }
5788 mbuf_append(&out, npath.p, npath.len);
5789 free((void *) npath.p);
5790 } else {
5791 mbuf_append(&out, path->p, path->len);
5792 }
5793 } else if (normalize_path) {
5794 mbuf_append(&out, "/", 1);
5795 }
5796
5797 if (query != NULL && query->len > 0) {
5798 mbuf_append(&out, "?", 1);
5799 mbuf_append(&out, query->p, query->len);
5800 }
5801
5802 if (fragment != NULL && fragment->len > 0) {
5803 mbuf_append(&out, "#", 1);
5804 mbuf_append(&out, fragment->p, fragment->len);
5805 }
5806
5807 result = 0;
5808
5809out:
5810 if (result == 0) {
5811 uri->p = out.buf;
5812 uri->len = out.len;
5813 } else {
5814 mbuf_free(&out);
5815 uri->p = NULL;
5816 uri->len = 0;
5817 }
5818 return result;
5819}
5820#ifdef MG_MODULE_LINES
5821#line 1 "mongoose/src/mg_http.c"
5822#endif
5823/*
5824 * Copyright (c) 2014 Cesanta Software Limited
5825 * All rights reserved
5826 */
5827
5828#if MG_ENABLE_HTTP
5829
5830/* Amalgamated: #include "common/cs_md5.h" */
5831/* Amalgamated: #include "mg_internal.h" */
5832/* Amalgamated: #include "mg_util.h" */
5833
5834/* altbuf {{{ */
5835
5836/*
5837 * Alternate buffer: fills the client-provided buffer with data; and if it's
5838 * not large enough, allocates another buffer (via mbuf), similar to asprintf.
5839 */
5840struct altbuf {
5841 struct mbuf m;
5842 char *user_buf;
5843 size_t len;
5844 size_t user_buf_size;
5845};
5846
5847/*
5848 * Initializes altbuf; `buf`, `buf_size` is the client-provided buffer.
5849 */
5850MG_INTERNAL void altbuf_init(struct altbuf *ab, char *buf, size_t buf_size) {
5851 mbuf_init(&ab->m, 0);
5852 ab->user_buf = buf;
5853 ab->user_buf_size = buf_size;
5854 ab->len = 0;
5855}
5856
5857/*
5858 * Appends a single char to the altbuf.
5859 */
5860MG_INTERNAL void altbuf_append(struct altbuf *ab, char c) {
5861 if (ab->len < ab->user_buf_size) {
5862 /* The data fits into the original buffer */
5863 ab->user_buf[ab->len++] = c;
5864 } else {
5865 /* The data can't fit into the original buffer, so write it to mbuf. */
5866
5867 /*
5868 * First of all, see if that's the first byte which overflows the original
5869 * buffer: if so, copy the existing data from there to a newly allocated
5870 * mbuf.
5871 */
5872 if (ab->len > 0 && ab->m.len == 0) {
5873 mbuf_append(&ab->m, ab->user_buf, ab->len);
5874 }
5875
5876 mbuf_append(&ab->m, &c, 1);
5877 ab->len = ab->m.len;
5878 }
5879}
5880
5881/*
5882 * Resets any data previously appended to altbuf.
5883 */
5884MG_INTERNAL void altbuf_reset(struct altbuf *ab) {
5885 mbuf_free(&ab->m);
5886 ab->len = 0;
5887}
5888
5889/*
5890 * Returns whether the additional buffer was allocated (and thus the data
5891 * is in the mbuf, not the client-provided buffer)
5892 */
5894 return ab->len > ab->user_buf_size;
5895}
5896
5897/*
5898 * Returns the actual buffer with data, either the client-provided or a newly
5899 * allocated one. If `trim` is non-zero, mbuf-backed buffer is trimmed first.
5900 */
5901MG_INTERNAL char *altbuf_get_buf(struct altbuf *ab, int trim) {
5902 if (altbuf_reallocated(ab)) {
5903 if (trim) {
5904 mbuf_trim(&ab->m);
5905 }
5906 return ab->m.buf;
5907 } else {
5908 return ab->user_buf;
5909 }
5910}
5911
5912/* }}} */
5913
5914static const char *mg_version_header = "Mongoose/" MG_VERSION;
5915
5917
5919 FILE *fp; /* Opened file. */
5920 int64_t cl; /* Content-Length. How many bytes to send. */
5921 int64_t sent; /* How many bytes have been already sent. */
5922 int keepalive; /* Keep connection open after sending. */
5924};
5925
5926#if MG_ENABLE_HTTP_CGI
5928 struct mg_connection *cgi_nc;
5929};
5930#endif
5931
5933 int64_t body_len; /* How many bytes of chunked body was reassembled. */
5934};
5935
5936struct mg_http_endpoint {
5937 struct mg_http_endpoint *next;
5938 struct mg_str uri_pattern; /* owned */
5939 char *auth_domain; /* owned */
5940 char *auth_file; /* owned */
5941
5943#if MG_ENABLE_CALLBACK_USERDATA
5944 void *user_data;
5945#endif
5946};
5947
5949 MPS_BEGIN,
5955};
5956
5958 const char *boundary;
5959 int boundary_len;
5960 const char *var_name;
5961 const char *file_name;
5962 void *user_data;
5964 int processing_part;
5965 int data_avail;
5966};
5967
5968struct mg_reverse_proxy_data {
5969 struct mg_connection *linked_conn;
5970};
5971
5972struct mg_ws_proto_data {
5973 /*
5974 * Defragmented size of the frame so far.
5975 *
5976 * First byte of nc->recv_mbuf.buf is an op, the rest of the data is
5977 * defragmented data.
5978 */
5979 size_t reass_len;
5980};
5981
5982struct mg_http_proto_data {
5983#if MG_ENABLE_FILESYSTEM
5985#endif
5986#if MG_ENABLE_HTTP_CGI
5988#endif
5989#if MG_ENABLE_HTTP_STREAMING_MULTIPART
5991#endif
5992#if MG_ENABLE_HTTP_WEBSOCKET
5994#endif
5999 size_t rcvd; /* How many bytes we have received. */
6000};
6001
6002static void mg_http_conn_destructor(void *proto_data);
6005 struct mg_connect_opts opts, const char *scheme1, const char *scheme2,
6006 const char *scheme_ssl1, const char *scheme_ssl2, const char *url,
6007 struct mg_str *path, struct mg_str *user_info, struct mg_str *host);
6008
6010 struct mg_connection *c) {
6011 if (c->proto_data == NULL) {
6012 c->proto_data = MG_CALLOC(1, sizeof(struct mg_http_proto_data));
6013 c->proto_data_destructor = mg_http_conn_destructor;
6014 }
6015
6016 return (struct mg_http_proto_data *) c->proto_data;
6017}
6018
6019#if MG_ENABLE_HTTP_STREAMING_MULTIPART
6021 struct mg_http_multipart_stream *mp) {
6022 MG_FREE((void *) mp->boundary);
6023 MG_FREE((void *) mp->var_name);
6024 MG_FREE((void *) mp->file_name);
6025 memset(mp, 0, sizeof(*mp));
6026}
6027#endif
6028
6029#if MG_ENABLE_FILESYSTEM
6031 if (d != NULL) {
6032 if (d->fp != NULL) {
6033 fclose(d->fp);
6034 }
6035 memset(d, 0, sizeof(struct mg_http_proto_data_file));
6036 }
6037}
6038#endif
6039
6040static void mg_http_free_proto_data_endpoints(struct mg_http_endpoint **ep) {
6041 struct mg_http_endpoint *current = *ep;
6042
6043 while (current != NULL) {
6044 struct mg_http_endpoint *tmp = current->next;
6045 MG_FREE((void *) current->uri_pattern.p);
6046 MG_FREE((void *) current->auth_domain);
6047 MG_FREE((void *) current->auth_file);
6049 current = tmp;
6050 }
6051
6052 ep = NULL;
6053}
6054
6056 if (rpd->linked_conn != NULL) {
6057 /*
6058 * Connection has linked one, we have to unlink & close it
6059 * since _this_ connection is going to die and
6060 * it doesn't make sense to keep another one
6061 */
6062 struct mg_http_proto_data *pd = mg_http_get_proto_data(rpd->linked_conn);
6063 if (pd->reverse_proxy_data.linked_conn != NULL) {
6064 pd->reverse_proxy_data.linked_conn->flags |= MG_F_SEND_AND_CLOSE;
6065 pd->reverse_proxy_data.linked_conn = NULL;
6066 }
6067 rpd->linked_conn = NULL;
6068 }
6069}
6070
6071static void mg_http_conn_destructor(void *proto_data) {
6072 struct mg_http_proto_data *pd = (struct mg_http_proto_data *) proto_data;
6073#if MG_ENABLE_FILESYSTEM
6075#endif
6076#if MG_ENABLE_HTTP_CGI
6078#endif
6079#if MG_ENABLE_HTTP_STREAMING_MULTIPART
6081#endif
6083 mg_http_free_reverse_proxy_data(&pd->reverse_proxy_data);
6084 MG_FREE(proto_data);
6085}
6086
6087#if MG_ENABLE_FILESYSTEM
6088
6089#define MIME_ENTRY(_ext, _type) \
6090 { _ext, sizeof(_ext) - 1, _type }
6091static const struct {
6092 const char *extension;
6093 size_t ext_len;
6094 const char *mime_type;
6096 MIME_ENTRY("html", "text/html"),
6097 MIME_ENTRY("html", "text/html"),
6098 MIME_ENTRY("htm", "text/html"),
6099 MIME_ENTRY("shtm", "text/html"),
6100 MIME_ENTRY("shtml", "text/html"),
6101 MIME_ENTRY("css", "text/css"),
6102 MIME_ENTRY("js", "application/x-javascript"),
6103 MIME_ENTRY("ico", "image/x-icon"),
6104 MIME_ENTRY("gif", "image/gif"),
6105 MIME_ENTRY("jpg", "image/jpeg"),
6106 MIME_ENTRY("jpeg", "image/jpeg"),
6107 MIME_ENTRY("png", "image/png"),
6108 MIME_ENTRY("svg", "image/svg+xml"),
6109 MIME_ENTRY("txt", "text/plain"),
6110 MIME_ENTRY("torrent", "application/x-bittorrent"),
6111 MIME_ENTRY("wav", "audio/x-wav"),
6112 MIME_ENTRY("mp3", "audio/x-mp3"),
6113 MIME_ENTRY("mid", "audio/mid"),
6114 MIME_ENTRY("m3u", "audio/x-mpegurl"),
6115 MIME_ENTRY("ogg", "application/ogg"),
6116 MIME_ENTRY("ram", "audio/x-pn-realaudio"),
6117 MIME_ENTRY("xml", "text/xml"),
6118 MIME_ENTRY("ttf", "application/x-font-ttf"),
6119 MIME_ENTRY("json", "application/json"),
6120 MIME_ENTRY("xslt", "application/xml"),
6121 MIME_ENTRY("xsl", "application/xml"),
6122 MIME_ENTRY("ra", "audio/x-pn-realaudio"),
6123 MIME_ENTRY("doc", "application/msword"),
6124 MIME_ENTRY("exe", "application/octet-stream"),
6125 MIME_ENTRY("zip", "application/x-zip-compressed"),
6126 MIME_ENTRY("xls", "application/excel"),
6127 MIME_ENTRY("tgz", "application/x-tar-gz"),
6128 MIME_ENTRY("tar", "application/x-tar"),
6129 MIME_ENTRY("gz", "application/x-gunzip"),
6130 MIME_ENTRY("arj", "application/x-arj-compressed"),
6131 MIME_ENTRY("rar", "application/x-rar-compressed"),
6132 MIME_ENTRY("rtf", "application/rtf"),
6133 MIME_ENTRY("pdf", "application/pdf"),
6134 MIME_ENTRY("swf", "application/x-shockwave-flash"),
6135 MIME_ENTRY("mpg", "video/mpeg"),
6136 MIME_ENTRY("webm", "video/webm"),
6137 MIME_ENTRY("mpeg", "video/mpeg"),
6138 MIME_ENTRY("mov", "video/quicktime"),
6139 MIME_ENTRY("mp4", "video/mp4"),
6140 MIME_ENTRY("m4v", "video/x-m4v"),
6141 MIME_ENTRY("asf", "video/x-ms-asf"),
6142 MIME_ENTRY("avi", "video/x-msvideo"),
6143 MIME_ENTRY("bmp", "image/bmp"),
6144 {NULL, 0, NULL}};
6145
6146static struct mg_str mg_get_mime_type(const char *path, const char *dflt,
6147 const struct mg_serve_http_opts *opts) {
6148 const char *ext, *overrides;
6149 size_t i, path_len;
6150 struct mg_str r, k, v;
6151
6152 path_len = strlen(path);
6153
6154 overrides = opts->custom_mime_types;
6155 while ((overrides = mg_next_comma_list_entry(overrides, &k, &v)) != NULL) {
6156 ext = path + (path_len - k.len);
6157 if (path_len > k.len && mg_vcasecmp(&k, ext) == 0) {
6158 return v;
6159 }
6160 }
6161
6162 for (i = 0; mg_static_builtin_mime_types[i].extension != NULL; i++) {
6163 ext = path + (path_len - mg_static_builtin_mime_types[i].ext_len);
6164 if (path_len > mg_static_builtin_mime_types[i].ext_len && ext[-1] == '.' &&
6166 r.p = mg_static_builtin_mime_types[i].mime_type;
6167 r.len = strlen(r.p);
6168 return r;
6169 }
6170 }
6171
6172 r.p = dflt;
6173 r.len = strlen(r.p);
6174 return r;
6175}
6176#endif
6177
6178/*
6179 * Check whether full request is buffered. Return:
6180 * -1 if request is malformed
6181 * 0 if request is not yet fully buffered
6182 * >0 actual request length, including last \r\n\r\n
6183 */
6184static int mg_http_get_request_len(const char *s, int buf_len) {
6185 const unsigned char *buf = (unsigned char *) s;
6186 int i;
6187
6188 for (i = 0; i < buf_len; i++) {
6189 if (!isprint(buf[i]) && buf[i] != '\r' && buf[i] != '\n' && buf[i] < 128) {
6190 return -1;
6191 } else if (buf[i] == '\n' && i + 1 < buf_len && buf[i + 1] == '\n') {
6192 return i + 2;
6193 } else if (buf[i] == '\n' && i + 2 < buf_len && buf[i + 1] == '\r' &&
6194 buf[i + 2] == '\n') {
6195 return i + 3;
6196 }
6197 }
6198
6199 return 0;
6200}
6201
6202static const char *mg_http_parse_headers(const char *s, const char *end,
6203 int len, struct http_message *req) {
6204 int i = 0;
6205 while (i < (int) ARRAY_SIZE(req->header_names) - 1) {
6206 struct mg_str *k = &req->header_names[i], *v = &req->header_values[i];
6207
6208 s = mg_skip(s, end, ": ", k);
6209 s = mg_skip(s, end, "\r\n", v);
6210
6211 while (v->len > 0 && v->p[v->len - 1] == ' ') {
6212 v->len--; /* Trim trailing spaces in header value */
6213 }
6214
6215 /*
6216 * If header value is empty - skip it and go to next (if any).
6217 * NOTE: Do not add it to headers_values because such addition changes API
6218 * behaviour
6219 */
6220 if (k->len != 0 && v->len == 0) {
6221 continue;
6222 }
6223
6224 if (k->len == 0 || v->len == 0) {
6225 k->p = v->p = NULL;
6226 k->len = v->len = 0;
6227 break;
6228 }
6229
6230 if (!mg_ncasecmp(k->p, "Content-Length", 14)) {
6231 req->body.len = (size_t) to64(v->p);
6232 req->message.len = len + req->body.len;
6233 }
6234
6235 i++;
6236 }
6237
6238 return s;
6239}
6240
6241int mg_parse_http(const char *s, int n, struct http_message *hm, int is_req) {
6242 const char *end, *qs;
6243 int len = mg_http_get_request_len(s, n);
6244
6245 if (len <= 0) return len;
6246
6247 memset(hm, 0, sizeof(*hm));
6248 hm->message.p = s;
6249 hm->body.p = s + len;
6250 hm->message.len = hm->body.len = (size_t) ~0;
6251 end = s + len;
6252
6253 /* Request is fully buffered. Skip leading whitespaces. */
6254 while (s < end && isspace(*(unsigned char *) s)) s++;
6255
6256 if (is_req) {
6257 /* Parse request line: method, URI, proto */
6258 s = mg_skip(s, end, " ", &hm->method);
6259 s = mg_skip(s, end, " ", &hm->uri);
6260 s = mg_skip(s, end, "\r\n", &hm->proto);
6261 if (hm->uri.p <= hm->method.p || hm->proto.p <= hm->uri.p) return -1;
6262
6263 /* If URI contains '?' character, initialize query_string */
6264 if ((qs = (char *) memchr(hm->uri.p, '?', hm->uri.len)) != NULL) {
6265 hm->query_string.p = qs + 1;
6266 hm->query_string.len = &hm->uri.p[hm->uri.len] - (qs + 1);
6267 hm->uri.len = qs - hm->uri.p;
6268 }
6269 } else {
6270 s = mg_skip(s, end, " ", &hm->proto);
6271 if (end - s < 4 || s[3] != ' ') return -1;
6272 hm->resp_code = atoi(s);
6273 if (hm->resp_code < 100 || hm->resp_code >= 600) return -1;
6274 s += 4;
6275 s = mg_skip(s, end, "\r\n", &hm->resp_status_msg);
6276 }
6277
6278 s = mg_http_parse_headers(s, end, len, hm);
6279
6280 /*
6281 * mg_parse_http() is used to parse both HTTP requests and HTTP
6282 * responses. If HTTP response does not have Content-Length set, then
6283 * body is read until socket is closed, i.e. body.len is infinite (~0).
6284 *
6285 * For HTTP requests though, according to
6286 * http://tools.ietf.org/html/rfc7231#section-8.1.3,
6287 * only POST and PUT methods have defined body semantics.
6288 * Therefore, if Content-Length is not specified and methods are
6289 * not one of PUT or POST, set body length to 0.
6290 *
6291 * So,
6292 * if it is HTTP request, and Content-Length is not set,
6293 * and method is not (PUT or POST) then reset body length to zero.
6294 */
6295 if (hm->body.len == (size_t) ~0 && is_req &&
6296 mg_vcasecmp(&hm->method, "PUT") != 0 &&
6297 mg_vcasecmp(&hm->method, "POST") != 0) {
6298 hm->body.len = 0;
6299 hm->message.len = len;
6300 }
6301
6302 return len;
6303}
6304
6305struct mg_str *mg_get_http_header(struct http_message *hm, const char *name) {
6306 size_t i, len = strlen(name);
6307
6308 for (i = 0; hm->header_names[i].len > 0; i++) {
6309 struct mg_str *h = &hm->header_names[i], *v = &hm->header_values[i];
6310 if (h->p != NULL && h->len == len && !mg_ncasecmp(h->p, name, len))
6311 return v;
6312 }
6313
6314 return NULL;
6315}
6316
6317#if MG_ENABLE_FILESYSTEM
6318static void mg_http_transfer_file_data(struct mg_connection *nc) {
6320 char buf[MG_MAX_HTTP_SEND_MBUF];
6321 size_t n = 0, to_read = 0, left = (size_t)(pd->file.cl - pd->file.sent);
6322
6323 if (pd->file.type == DATA_FILE) {
6324 struct mbuf *io = &nc->send_mbuf;
6325 if (io->len >= MG_MAX_HTTP_SEND_MBUF) {
6326 to_read = 0;
6327 } else {
6329 }
6330 if (to_read > left) {
6331 to_read = left;
6332 }
6333 if (to_read > 0) {
6334 n = mg_fread(buf, 1, to_read, pd->file.fp);
6335 if (n > 0) {
6336 mg_send(nc, buf, n);
6337 pd->file.sent += n;
6338 DBG(("%p sent %d (total %d)", nc, (int) n, (int) pd->file.sent));
6339 }
6340 } else {
6341 /* Rate-limited */
6342 }
6343 if (pd->file.sent >= pd->file.cl) {
6344 LOG(LL_DEBUG, ("%p done, %d bytes", nc, (int) pd->file.sent));
6345 if (!pd->file.keepalive) nc->flags |= MG_F_SEND_AND_CLOSE;
6347 }
6348 } else if (pd->file.type == DATA_PUT) {
6349 struct mbuf *io = &nc->recv_mbuf;
6350 size_t to_write = left <= 0 ? 0 : left < io->len ? (size_t) left : io->len;
6351 size_t n = mg_fwrite(io->buf, 1, to_write, pd->file.fp);
6352 if (n > 0) {
6353 mbuf_remove(io, n);
6354 pd->file.sent += n;
6355 }
6356 if (n == 0 || pd->file.sent >= pd->file.cl) {
6357 if (!pd->file.keepalive) nc->flags |= MG_F_SEND_AND_CLOSE;
6359 }
6360 }
6361#if MG_ENABLE_HTTP_CGI
6362 else if (pd->cgi.cgi_nc != NULL) {
6363 /* This is POST data that needs to be forwarded to the CGI process */
6364 if (pd->cgi.cgi_nc != NULL) {
6365 mg_forward(nc, pd->cgi.cgi_nc);
6366 } else {
6368 }
6369 }
6370#endif
6371}
6372#endif /* MG_ENABLE_FILESYSTEM */
6373
6374/*
6375 * Parse chunked-encoded buffer. Return 0 if the buffer is not encoded, or
6376 * if it's incomplete. If the chunk is fully buffered, return total number of
6377 * bytes in a chunk, and store data in `data`, `data_len`.
6378 */
6379static size_t mg_http_parse_chunk(char *buf, size_t len, char **chunk_data,
6380 size_t *chunk_len) {
6381 unsigned char *s = (unsigned char *) buf;
6382 size_t n = 0; /* scanned chunk length */
6383 size_t i = 0; /* index in s */
6384
6385 /* Scan chunk length. That should be a hexadecimal number. */
6386 while (i < len && isxdigit(s[i])) {
6387 n *= 16;
6388 n += (s[i] >= '0' && s[i] <= '9') ? s[i] - '0' : tolower(s[i]) - 'a' + 10;
6389 i++;
6390 if (i > 6) {
6391 /* Chunk size is unreasonable. */
6392 return 0;
6393 }
6394 }
6395
6396 /* Skip new line */
6397 if (i == 0 || i + 2 > len || s[i] != '\r' || s[i + 1] != '\n') {
6398 return 0;
6399 }
6400 i += 2;
6401
6402 /* Record where the data is */
6403 *chunk_data = (char *) s + i;
6404 *chunk_len = n;
6405
6406 /* Skip data */
6407 i += n;
6408
6409 /* Skip new line */
6410 if (i == 0 || i + 2 > len || s[i] != '\r' || s[i + 1] != '\n') {
6411 return 0;
6412 }
6413 return i + 2;
6414}
6415
6417 struct http_message *hm, char *buf,
6418 size_t blen) {
6420 char *data;
6421 size_t i, n, data_len, body_len, zero_chunk_received = 0;
6422 /* Find out piece of received data that is not yet reassembled */
6423 body_len = (size_t) pd->chunk.body_len;
6424 assert(blen >= body_len);
6425
6426 /* Traverse all fully buffered chunks */
6427 for (i = body_len;
6428 (n = mg_http_parse_chunk(buf + i, blen - i, &data, &data_len)) > 0;
6429 i += n) {
6430 /* Collapse chunk data to the rest of HTTP body */
6431 memmove(buf + body_len, data, data_len);
6432 body_len += data_len;
6433 hm->body.len = body_len;
6434
6435 if (data_len == 0) {
6437 i += n;
6438 break;
6439 }
6440 }
6441
6442 if (i > body_len) {
6443 /* Shift unparsed content to the parsed body */
6444 assert(i <= blen);
6445 memmove(buf + body_len, buf + i, blen - i);
6446 memset(buf + body_len + blen - i, 0, i - body_len);
6447 nc->recv_mbuf.len -= i - body_len;
6448 pd->chunk.body_len = body_len;
6449
6450 /* Send MG_EV_HTTP_CHUNK event */
6453
6454 /* Delete processed data if user set MG_F_DELETE_CHUNK flag */
6455 if (nc->flags & MG_F_DELETE_CHUNK) {
6456 memset(buf, 0, body_len);
6457 memmove(buf, buf + body_len, blen - i);
6458 nc->recv_mbuf.len -= body_len;
6459 hm->body.len = 0;
6460 pd->chunk.body_len = 0;
6461 }
6462
6463 if (zero_chunk_received) {
6464 /* Total message size is len(body) + len(headers) */
6465 hm->message.len =
6466 (size_t) pd->chunk.body_len + blen - i + (hm->body.p - hm->message.p);
6467 }
6468 }
6469
6470 return body_len;
6471}
6472
6474 struct mg_str *uri_path) {
6475 struct mg_http_proto_data *pd;
6476 struct mg_http_endpoint *ret = NULL;
6477 int matched, matched_max = 0;
6478 struct mg_http_endpoint *ep;
6479
6480 if (nc == NULL) {
6481 return NULL;
6482 }
6483
6485
6486 ep = pd->endpoints;
6487 while (ep != NULL) {
6488 if ((matched = mg_match_prefix_n(ep->uri_pattern, *uri_path)) > 0) {
6489 if (matched > matched_max) {
6490 /* Looking for the longest suitable handler */
6491 ret = ep;
6493 }
6494 }
6495
6496 ep = ep->next;
6497 }
6498
6499 return ret;
6500}
6501
6502#if MG_ENABLE_HTTP_STREAMING_MULTIPART
6503static void mg_http_multipart_continue(struct mg_connection *nc);
6504
6505static void mg_http_multipart_begin(struct mg_connection *nc,
6506 struct http_message *hm, int req_len);
6507
6508#endif
6509
6510static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev,
6511 struct http_message *hm);
6512
6513static void deliver_chunk(struct mg_connection *c, struct http_message *hm,
6514 int req_len) {
6515 /* Incomplete message received. Send MG_EV_HTTP_CHUNK event */
6516 hm->body.len = c->recv_mbuf.len - req_len;
6517 c->flags &= ~MG_F_DELETE_CHUNK;
6518 mg_call(c, c->handler, c->user_data, MG_EV_HTTP_CHUNK, hm);
6519 /* Delete processed data if user set MG_F_DELETE_CHUNK flag */
6520 if (c->flags & MG_F_DELETE_CHUNK) c->recv_mbuf.len = req_len;
6521}
6522
6523/*
6524 * lx106 compiler has a bug (TODO(mkm) report and insert tracking bug here)
6525 * If a big structure is declared in a big function, lx106 gcc will make it
6526 * even bigger (round up to 4k, from 700 bytes of actual size).
6527 */
6528#ifdef __xtensa__
6529static void mg_http_handler2(struct mg_connection *nc, int ev,
6530 void *ev_data MG_UD_ARG(void *user_data),
6532
6533void mg_http_handler(struct mg_connection *nc, int ev,
6534 void *ev_data MG_UD_ARG(void *user_data)) {
6535 struct http_message hm;
6536 mg_http_handler2(nc, ev, ev_data MG_UD_ARG(user_data), &hm);
6537}
6538
6539static void mg_http_handler2(struct mg_connection *nc, int ev,
6540 void *ev_data MG_UD_ARG(void *user_data),
6541 struct http_message *hm) {
6542#else /* !__XTENSA__ */
6543void mg_http_handler(struct mg_connection *nc, int ev,
6544 void *ev_data MG_UD_ARG(void *user_data)) {
6545 struct http_message shm, *hm = &shm;
6546#endif /* __XTENSA__ */
6548 struct mbuf *io = &nc->recv_mbuf;
6549 int req_len;
6550 const int is_req = (nc->listener != NULL);
6551#if MG_ENABLE_HTTP_WEBSOCKET
6552 struct mg_str *vec;
6553#endif
6554 if (ev == MG_EV_CLOSE) {
6555#if MG_ENABLE_HTTP_CGI
6556 /* Close associated CGI forwarder connection */
6557 if (pd->cgi.cgi_nc != NULL) {
6558 pd->cgi.cgi_nc->user_data = NULL;
6559 pd->cgi.cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY;
6560 }
6561#endif
6562#if MG_ENABLE_HTTP_STREAMING_MULTIPART
6563 if (pd->mp_stream.boundary != NULL) {
6564 /*
6565 * Multipart message is in progress, but connection is closed.
6566 * Finish part and request with an error flag.
6567 */
6569 memset(&mp, 0, sizeof(mp));
6570 mp.status = -1;
6571 mp.var_name = pd->mp_stream.var_name;
6572 mp.file_name = pd->mp_stream.file_name;
6573 mg_call(nc, (pd->endpoint_handler ? pd->endpoint_handler : nc->handler),
6575 mp.var_name = NULL;
6576 mp.file_name = NULL;
6577 mg_call(nc, (pd->endpoint_handler ? pd->endpoint_handler : nc->handler),
6579 } else
6580#endif
6581 if (io->len > 0 &&
6582 (req_len = mg_parse_http(io->buf, io->len, hm, is_req)) > 0) {
6583 /*
6584 * For HTTP messages without Content-Length, always send HTTP message
6585 * before MG_EV_CLOSE message.
6586 */
6588 hm->message.len = io->len;
6589 hm->body.len = io->buf + io->len - hm->body.p;
6590 deliver_chunk(nc, hm, req_len);
6592 }
6593 pd->rcvd = 0;
6594 if (pd->endpoint_handler != NULL && pd->endpoint_handler != nc->handler) {
6595 mg_call(nc, pd->endpoint_handler, nc->user_data, ev, NULL);
6596 }
6597 }
6598
6599#if MG_ENABLE_FILESYSTEM
6600 if (pd->file.fp != NULL) {
6602 }
6603#endif
6604
6605 mg_call(nc, nc->handler, nc->user_data, ev, ev_data);
6606
6607#if MG_ENABLE_HTTP_STREAMING_MULTIPART
6608 if (pd->mp_stream.boundary != NULL &&
6609 (ev == MG_EV_RECV || ev == MG_EV_POLL)) {
6610 if (ev == MG_EV_RECV) {
6611 pd->rcvd += *(int *) ev_data;
6613 } else if (pd->mp_stream.data_avail) {
6614 /* Try re-delivering the data. */
6616 }
6617 return;
6618 }
6619#endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
6620
6621 if (ev == MG_EV_RECV) {
6622 struct mg_str *s;
6623 pd->rcvd += *(int *) ev_data;
6624
6625 again:
6626 req_len = mg_parse_http(io->buf, io->len, hm, is_req);
6627
6628 if (req_len > 0 &&
6629 (s = mg_get_http_header(hm, "Transfer-Encoding")) != NULL &&
6630 mg_vcasecmp(s, "chunked") == 0) {
6631 mg_handle_chunked(nc, hm, io->buf + req_len, io->len - req_len);
6632 }
6633
6634#if MG_ENABLE_HTTP_STREAMING_MULTIPART
6635 if (req_len > 0 && (s = mg_get_http_header(hm, "Content-Type")) != NULL &&
6636 s->len >= 9 && strncmp(s->p, "multipart", 9) == 0) {
6639 return;
6640 }
6641#endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
6642
6643 /* TODO(alashkin): refactor this ifelseifelseifelseifelse */
6644 if ((req_len < 0 ||
6645 (req_len == 0 && io->len >= MG_MAX_HTTP_REQUEST_SIZE))) {
6646 DBG(("invalid request"));
6648 } else if (req_len == 0) {
6649 /* Do nothing, request is not yet fully buffered */
6650 }
6651#if MG_ENABLE_HTTP_WEBSOCKET
6652 else if (nc->listener == NULL && (nc->flags & MG_F_IS_WEBSOCKET)) {
6653 /* We're websocket client, got handshake response from server. */
6654 DBG(("%p WebSocket upgrade code %d", nc, hm->resp_code));
6655 if (hm->resp_code == 101 &&
6656 mg_get_http_header(hm, "Sec-WebSocket-Accept")) {
6657 /* TODO(lsm): check the validity of accept Sec-WebSocket-Accept */
6659 hm);
6662 mg_ws_handler(nc, MG_EV_RECV, ev_data MG_UD_ARG(user_data));
6663 } else {
6665 hm);
6668 }
6669 } else if (nc->listener != NULL &&
6670 (vec = mg_get_http_header(hm, "Sec-WebSocket-Key")) != NULL) {
6671 struct mg_http_endpoint *ep;
6672
6673 /* This is a websocket request. Switch protocol handlers. */
6676 nc->flags |= MG_F_IS_WEBSOCKET;
6677
6678 /*
6679 * If we have a handler set up with mg_register_http_endpoint(),
6680 * deliver subsequent websocket events to this handler after the
6681 * protocol switch.
6682 */
6683 ep = mg_http_get_endpoint_handler(nc->listener, &hm->uri);
6684 if (ep != NULL) {
6685 nc->handler = ep->handler;
6686#if MG_ENABLE_CALLBACK_USERDATA
6687 nc->user_data = ep->user_data;
6688#endif
6689 }
6690
6691 /* Send handshake */
6693 hm);
6695 if (nc->send_mbuf.len == 0) {
6696 mg_ws_handshake(nc, vec, hm);
6697 }
6699 hm);
6700 mg_ws_handler(nc, MG_EV_RECV, ev_data MG_UD_ARG(user_data));
6701 }
6702 }
6703#endif /* MG_ENABLE_HTTP_WEBSOCKET */
6704 else if (hm->message.len > pd->rcvd) {
6705 /* Not yet received all HTTP body, deliver MG_EV_HTTP_CHUNK */
6706 deliver_chunk(nc, hm, req_len);
6707 if (nc->recv_mbuf_limit > 0 && nc->recv_mbuf.len >= nc->recv_mbuf_limit) {
6708 LOG(LL_ERROR, ("%p recv buffer (%lu bytes) exceeds the limit "
6709 "%lu bytes, and not drained, closing",
6710 nc, (unsigned long) nc->recv_mbuf.len,
6711 (unsigned long) nc->recv_mbuf_limit));
6713 }
6714 } else {
6715 /* We did receive all HTTP body. */
6716 int request_done = 1;
6718 char addr[32];
6719 mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr),
6721 DBG(("%p %s %.*s %.*s", nc, addr, (int) hm->method.len, hm->method.p,
6722 (int) hm->uri.len, hm->uri.p));
6723 deliver_chunk(nc, hm, req_len);
6724 /* Whole HTTP message is fully buffered, call event handler */
6726 mbuf_remove(io, hm->message.len);
6727 pd->rcvd -= hm->message.len;
6728#if MG_ENABLE_FILESYSTEM
6729 /* We don't have a generic mechanism of communicating that we are done
6730 * responding to a request (should probably add one). But if we are
6731 * serving
6732 * a file, we are definitely not done. */
6733 if (pd->file.fp != NULL) request_done = 0;
6734#endif
6735#if MG_ENABLE_HTTP_CGI
6736 /* If this is a CGI request, we are not done either. */
6737 if (pd->cgi.cgi_nc != NULL) request_done = 0;
6738#endif
6739 if (request_done) {
6740 /* This request is done but we may receive another on this connection.
6741 */
6743 nc->proto_data = NULL;
6744 if (io->len > 0) {
6745 /* We already have data for the next one, restart parsing. */
6747 pd->rcvd = io->len;
6748 goto again;
6749 }
6750 }
6751 }
6752 }
6753}
6754
6755static size_t mg_get_line_len(const char *buf, size_t buf_len) {
6756 size_t len = 0;
6757 while (len < buf_len && buf[len] != '\n') len++;
6758 return len == buf_len ? 0 : len + 1;
6759}
6760
6761#if MG_ENABLE_HTTP_STREAMING_MULTIPART
6762static void mg_http_multipart_begin(struct mg_connection *nc,
6763 struct http_message *hm, int req_len) {
6765 struct mg_str *ct;
6766 struct mbuf *io = &nc->recv_mbuf;
6767
6768 char boundary_buf[100];
6769 char *boundary = boundary_buf;
6770 int boundary_len;
6771
6772 ct = mg_get_http_header(hm, "Content-Type");
6773 if (ct == NULL) {
6774 /* We need more data - or it isn't multipart mesage */
6775 goto exit_mp;
6776 }
6777
6778 /* Content-type should start with "multipart" */
6779 if (ct->len < 9 || strncmp(ct->p, "multipart", 9) != 0) {
6780 goto exit_mp;
6781 }
6782
6783 boundary_len =
6784 mg_http_parse_header2(ct, "boundary", &boundary, sizeof(boundary_buf));
6785 if (boundary_len == 0) {
6786 /*
6787 * Content type is multipart, but there is no boundary,
6788 * probably malformed request
6789 */
6791 DBG(("invalid request"));
6792 goto exit_mp;
6793 }
6794
6795 /* If we reach this place - that is multipart request */
6796
6797 if (pd->mp_stream.boundary != NULL) {
6798 /*
6799 * Another streaming request was in progress,
6800 * looks like protocol error
6801 */
6803 } else {
6804 struct mg_http_endpoint *ep = NULL;
6805 pd->mp_stream.state = MPS_BEGIN;
6806 pd->mp_stream.boundary = strdup(boundary);
6807 pd->mp_stream.boundary_len = strlen(boundary);
6808 pd->mp_stream.var_name = pd->mp_stream.file_name = NULL;
6809 pd->endpoint_handler = nc->handler;
6810
6811 ep = mg_http_get_endpoint_handler(nc->listener, &hm->uri);
6812 if (ep != NULL) {
6813 pd->endpoint_handler = ep->handler;
6814 }
6815
6817
6819 }
6820exit_mp:
6821 if (boundary != boundary_buf) MG_FREE(boundary);
6822}
6823
6824#define CONTENT_DISPOSITION "Content-Disposition: "
6825
6826static size_t mg_http_multipart_call_handler(struct mg_connection *c, int ev,
6827 const char *data,
6828 size_t data_len) {
6831 memset(&mp, 0, sizeof(mp));
6832
6833 mp.var_name = pd->mp_stream.var_name;
6834 mp.file_name = pd->mp_stream.file_name;
6835 mp.user_data = pd->mp_stream.user_data;
6836 mp.data.p = data;
6837 mp.data.len = data_len;
6838 mp.num_data_consumed = data_len;
6839 mg_call(c, pd->endpoint_handler, c->user_data, ev, &mp);
6840 pd->mp_stream.user_data = mp.user_data;
6841 pd->mp_stream.data_avail = (mp.num_data_consumed != data_len);
6842 return mp.num_data_consumed;
6843}
6844
6845static int mg_http_multipart_finalize(struct mg_connection *c) {
6847
6849 MG_FREE((void *) pd->mp_stream.file_name);
6850 pd->mp_stream.file_name = NULL;
6851 MG_FREE((void *) pd->mp_stream.var_name);
6852 pd->mp_stream.var_name = NULL;
6855 pd->mp_stream.state = MPS_FINISHED;
6856
6857 return 1;
6858}
6859
6861 const char *boundary;
6862 struct mbuf *io = &c->recv_mbuf;
6864
6865 if (pd->mp_stream.boundary == NULL) {
6866 pd->mp_stream.state = MPS_FINALIZE;
6867 DBG(("Invalid request: boundary not initialized"));
6868 return 0;
6869 }
6870
6871 if ((int) io->len < pd->mp_stream.boundary_len + 2) {
6872 return 0;
6873 }
6874
6875 boundary = c_strnstr(io->buf, pd->mp_stream.boundary, io->len);
6876 if (boundary != NULL) {
6877 const char *boundary_end = (boundary + pd->mp_stream.boundary_len);
6878 if (io->len - (boundary_end - io->buf) < 4) {
6879 return 0;
6880 }
6881 if (strncmp(boundary_end, "--\r\n", 4) == 0) {
6882 pd->mp_stream.state = MPS_FINALIZE;
6883 mbuf_remove(io, (boundary_end - io->buf) + 4);
6884 } else {
6885 pd->mp_stream.state = MPS_GOT_BOUNDARY;
6886 }
6887 } else {
6888 return 0;
6889 }
6890
6891 return 1;
6892}
6893
6894static void mg_http_parse_header_internal(struct mg_str *hdr,
6895 const char *var_name,
6896 struct altbuf *ab);
6897
6899 int data_size;
6900 const char *boundary, *block_begin;
6901 struct mbuf *io = &c->recv_mbuf;
6904 int line_len;
6905 boundary = c_strnstr(io->buf, pd->mp_stream.boundary, io->len);
6906 block_begin = boundary + pd->mp_stream.boundary_len + 2;
6907 data_size = io->len - (block_begin - io->buf);
6908
6911
6912 while (data_size > 0 &&
6913 (line_len = mg_get_line_len(block_begin, data_size)) != 0) {
6914 if (line_len > (int) sizeof(CONTENT_DISPOSITION) &&
6916 sizeof(CONTENT_DISPOSITION) - 1) == 0) {
6917 struct mg_str header;
6918
6919 header.p = block_begin + sizeof(CONTENT_DISPOSITION) - 1;
6920 header.len = line_len - sizeof(CONTENT_DISPOSITION) - 1;
6921
6923 mg_http_parse_header_internal(&header, "name", &ab_var_name);
6924
6926 mg_http_parse_header_internal(&header, "filename", &ab_file_name);
6927
6929 data_size -= line_len;
6930
6931 continue;
6932 }
6933
6934 if (line_len == 2 && mg_ncasecmp(block_begin, "\r\n", 2) == 0) {
6935 mbuf_remove(io, block_begin - io->buf + 2);
6936
6937 if (pd->mp_stream.processing_part != 0) {
6939 }
6940
6941 /* Reserve 2 bytes for "\r\n" in file_name and var_name */
6944 altbuf_append(&ab_var_name, '\0');
6945 altbuf_append(&ab_var_name, '\0');
6946
6947 MG_FREE((void *) pd->mp_stream.file_name);
6948 pd->mp_stream.file_name = altbuf_get_buf(&ab_file_name, 1 /* trim */);
6949 MG_FREE((void *) pd->mp_stream.var_name);
6950 pd->mp_stream.var_name = altbuf_get_buf(&ab_var_name, 1 /* trim */);
6951
6953 pd->mp_stream.state = MPS_WAITING_FOR_CHUNK;
6954 pd->mp_stream.processing_part++;
6955 return 1;
6956 }
6957
6959 }
6960
6961 pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY;
6962
6965
6966 return 0;
6967}
6968
6971 struct mbuf *io = &c->recv_mbuf;
6972
6973 const char *boundary;
6974 if ((int) io->len < pd->mp_stream.boundary_len + 6 /* \r\n, --, -- */) {
6975 return 0;
6976 }
6977
6978 boundary = c_strnstr(io->buf, pd->mp_stream.boundary, io->len);
6979 if (boundary == NULL) {
6980 int data_len = (io->len - (pd->mp_stream.boundary_len + 6));
6981 if (data_len > 0) {
6983 c, MG_EV_HTTP_PART_DATA, io->buf, (size_t) data_len);
6985 }
6986 return 0;
6987 } else if (boundary != NULL) {
6988 size_t data_len = ((size_t)(boundary - io->buf) - 4);
6990 io->buf, data_len);
6992 if (consumed == data_len) {
6993 mbuf_remove(io, 4);
6994 pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY;
6995 return 1;
6996 } else {
6997 return 0;
6998 }
6999 } else {
7000 return 0;
7001 }
7002}
7003
7004static void mg_http_multipart_continue(struct mg_connection *c) {
7006 while (1) {
7007 switch (pd->mp_stream.state) {
7008 case MPS_BEGIN: {
7009 pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY;
7010 break;
7011 }
7014 return;
7015 }
7016 break;
7017 }
7018 case MPS_GOT_BOUNDARY: {
7020 return;
7021 }
7022 break;
7023 }
7024 case MPS_WAITING_FOR_CHUNK: {
7026 return;
7027 }
7028 break;
7029 }
7030 case MPS_FINALIZE: {
7031 if (mg_http_multipart_finalize(c) == 0) {
7032 return;
7033 }
7034 break;
7035 }
7036 case MPS_FINISHED: {
7037 return;
7038 }
7039 }
7040 }
7041}
7042
7043struct file_upload_state {
7044 char *lfn;
7045 size_t num_recd;
7046 FILE *fp;
7047};
7048
7049#endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
7050
7053}
7054
7055const char *mg_status_message(int status_code) {
7056 switch (status_code) {
7057 case 206:
7058 return "Partial Content";
7059 case 301:
7060 return "Moved";
7061 case 302:
7062 return "Found";
7063 case 400:
7064 return "Bad Request";
7065 case 401:
7066 return "Unauthorized";
7067 case 403:
7068 return "Forbidden";
7069 case 404:
7070 return "Not Found";
7071 case 416:
7072 return "Requested Range Not Satisfiable";
7073 case 418:
7074 return "I'm a teapot";
7075 case 500:
7076 return "Internal Server Error";
7077 case 502:
7078 return "Bad Gateway";
7079 case 503:
7080 return "Service Unavailable";
7081
7082#if MG_ENABLE_EXTRA_ERRORS_DESC
7083 case 100:
7084 return "Continue";
7085 case 101:
7086 return "Switching Protocols";
7087 case 102:
7088 return "Processing";
7089 case 200:
7090 return "OK";
7091 case 201:
7092 return "Created";
7093 case 202:
7094 return "Accepted";
7095 case 203:
7096 return "Non-Authoritative Information";
7097 case 204:
7098 return "No Content";
7099 case 205:
7100 return "Reset Content";
7101 case 207:
7102 return "Multi-Status";
7103 case 208:
7104 return "Already Reported";
7105 case 226:
7106 return "IM Used";
7107 case 300:
7108 return "Multiple Choices";
7109 case 303:
7110 return "See Other";
7111 case 304:
7112 return "Not Modified";
7113 case 305:
7114 return "Use Proxy";
7115 case 306:
7116 return "Switch Proxy";
7117 case 307:
7118 return "Temporary Redirect";
7119 case 308:
7120 return "Permanent Redirect";
7121 case 402:
7122 return "Payment Required";
7123 case 405:
7124 return "Method Not Allowed";
7125 case 406:
7126 return "Not Acceptable";
7127 case 407:
7128 return "Proxy Authentication Required";
7129 case 408:
7130 return "Request Timeout";
7131 case 409:
7132 return "Conflict";
7133 case 410:
7134 return "Gone";
7135 case 411:
7136 return "Length Required";
7137 case 412:
7138 return "Precondition Failed";
7139 case 413:
7140 return "Payload Too Large";
7141 case 414:
7142 return "URI Too Long";
7143 case 415:
7144 return "Unsupported Media Type";
7145 case 417:
7146 return "Expectation Failed";
7147 case 422:
7148 return "Unprocessable Entity";
7149 case 423:
7150 return "Locked";
7151 case 424:
7152 return "Failed Dependency";
7153 case 426:
7154 return "Upgrade Required";
7155 case 428:
7156 return "Precondition Required";
7157 case 429:
7158 return "Too Many Requests";
7159 case 431:
7160 return "Request Header Fields Too Large";
7161 case 451:
7162 return "Unavailable For Legal Reasons";
7163 case 501:
7164 return "Not Implemented";
7165 case 504:
7166 return "Gateway Timeout";
7167 case 505:
7168 return "HTTP Version Not Supported";
7169 case 506:
7170 return "Variant Also Negotiates";
7171 case 507:
7172 return "Insufficient Storage";
7173 case 508:
7174 return "Loop Detected";
7175 case 510:
7176 return "Not Extended";
7177 case 511:
7178 return "Network Authentication Required";
7179#endif /* MG_ENABLE_EXTRA_ERRORS_DESC */
7180
7181 default:
7182 return "OK";
7183 }
7184}
7185
7186void mg_send_response_line_s(struct mg_connection *nc, int status_code,
7187 const struct mg_str extra_headers) {
7188 mg_printf(nc, "HTTP/1.1 %d %s\r\n", status_code,
7189 mg_status_message(status_code));
7190#ifndef MG_HIDE_SERVER_INFO
7191 mg_printf(nc, "Server: %s\r\n", mg_version_header);
7192#endif
7193 if (extra_headers.len > 0) {
7194 mg_printf(nc, "%.*s\r\n", (int) extra_headers.len, extra_headers.p);
7195 }
7196}
7197
7198void mg_send_response_line(struct mg_connection *nc, int status_code,
7199 const char *extra_headers) {
7200 mg_send_response_line_s(nc, status_code, mg_mk_str(extra_headers));
7201}
7202
7203void mg_http_send_redirect(struct mg_connection *nc, int status_code,
7204 const struct mg_str location,
7205 const struct mg_str extra_headers) {
7206 char bbody[100], *pbody = bbody;
7207 int bl = mg_asprintf(&pbody, sizeof(bbody),
7208 "<p>Moved <a href='%.*s'>here</a>.\r\n",
7209 (int) location.len, location.p);
7210 char bhead[150], *phead = bhead;
7211 mg_asprintf(&phead, sizeof(bhead),
7212 "Location: %.*s\r\n"
7213 "Content-Type: text/html\r\n"
7214 "Content-Length: %d\r\n"
7215 "Cache-Control: no-cache\r\n"
7216 "%.*s%s",
7217 (int) location.len, location.p, bl, (int) extra_headers.len,
7218 extra_headers.p, (extra_headers.len > 0 ? "\r\n" : ""));
7219 mg_send_response_line(nc, status_code, phead);
7220 if (phead != bhead) MG_FREE(phead);
7221 mg_send(nc, pbody, bl);
7222 if (pbody != bbody) MG_FREE(pbody);
7223}
7224
7225void mg_send_head(struct mg_connection *c, int status_code,
7226 int64_t content_length, const char *extra_headers) {
7227 mg_send_response_line(c, status_code, extra_headers);
7228 if (content_length < 0) {
7229 mg_printf(c, "%s", "Transfer-Encoding: chunked\r\n");
7230 } else {
7231 mg_printf(c, "Content-Length: %" INT64_FMT "\r\n", content_length);
7232 }
7233 mg_send(c, "\r\n", 2);
7234}
7235
7236void mg_http_send_error(struct mg_connection *nc, int code,
7237 const char *reason) {
7238 if (!reason) reason = mg_status_message(code);
7239 LOG(LL_DEBUG, ("%p %d %s", nc, code, reason));
7240 mg_send_head(nc, code, strlen(reason),
7241 "Content-Type: text/plain\r\nConnection: close");
7242 mg_send(nc, reason, strlen(reason));
7244}
7245
7246#if MG_ENABLE_FILESYSTEM
7247static void mg_http_construct_etag(char *buf, size_t buf_len,
7248 const cs_stat_t *st) {
7249 snprintf(buf, buf_len, "\"%lx.%" INT64_FMT "\"", (unsigned long) st->st_mtime,
7250 (int64_t) st->st_size);
7251}
7252
7253#ifndef WINCE
7254static void mg_gmt_time_string(char *buf, size_t buf_len, time_t *t) {
7255 strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(t));
7256}
7257#else
7258/* Look wince_lib.c for WindowsCE implementation */
7259static void mg_gmt_time_string(char *buf, size_t buf_len, time_t *t);
7260#endif
7261
7262static int mg_http_parse_range_header(const struct mg_str *header, int64_t *a,
7263 int64_t *b) {
7264 /*
7265 * There is no snscanf. Headers are not guaranteed to be NUL-terminated,
7266 * so we have this. Ugh.
7267 */
7268 int result;
7269 char *p = (char *) MG_MALLOC(header->len + 1);
7270 if (p == NULL) return 0;
7271 memcpy(p, header->p, header->len);
7272 p[header->len] = '\0';
7273 result = sscanf(p, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
7274 MG_FREE(p);
7275 return result;
7276}
7277
7278void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm,
7279 const char *path, const struct mg_str mime_type,
7280 const struct mg_str extra_headers) {
7282 cs_stat_t st;
7283 LOG(LL_DEBUG, ("%p [%s] %.*s", nc, path, (int) mime_type.len, mime_type.p));
7284 if (mg_stat(path, &st) != 0 || (pd->file.fp = mg_fopen(path, "rb")) == NULL) {
7285 int code, err = mg_get_errno();
7286 switch (err) {
7287 case EACCES:
7288 code = 403;
7289 break;
7290 case ENOENT:
7291 code = 404;
7292 break;
7293 default:
7294 code = 500;
7295 };
7296 mg_http_send_error(nc, code, "Open failed");
7297 } else {
7298 char etag[50], current_time[50], last_modified[50], range[70];
7299 time_t t = (time_t) mg_time();
7300 int64_t r1 = 0, r2 = 0, cl = st.st_size;
7301 struct mg_str *range_hdr = mg_get_http_header(hm, "Range");
7302 int n, status_code = 200;
7303
7304 /* Handle Range header */
7305 range[0] = '\0';
7306 if (range_hdr != NULL &&
7307 (n = mg_http_parse_range_header(range_hdr, &r1, &r2)) > 0 && r1 >= 0 &&
7308 r2 >= 0) {
7309 /* If range is specified like "400-", set second limit to content len */
7310 if (n == 1) {
7311 r2 = cl - 1;
7312 }
7313 if (r1 > r2 || r2 >= cl) {
7314 status_code = 416;
7315 cl = 0;
7316 snprintf(range, sizeof(range),
7317 "Content-Range: bytes */%" INT64_FMT "\r\n",
7318 (int64_t) st.st_size);
7319 } else {
7320 status_code = 206;
7321 cl = r2 - r1 + 1;
7322 snprintf(range, sizeof(range), "Content-Range: bytes %" INT64_FMT
7323 "-%" INT64_FMT "/%" INT64_FMT "\r\n",
7324 r1, r1 + cl - 1, (int64_t) st.st_size);
7325#if _FILE_OFFSET_BITS == 64 || _POSIX_C_SOURCE >= 200112L || \
7326 _XOPEN_SOURCE >= 600
7327 fseeko(pd->file.fp, r1, SEEK_SET);
7328#else
7329 fseek(pd->file.fp, (long) r1, SEEK_SET);
7330#endif
7331 }
7332 }
7333
7334#if !MG_DISABLE_HTTP_KEEP_ALIVE
7335 {
7336 struct mg_str *conn_hdr = mg_get_http_header(hm, "Connection");
7337 if (conn_hdr != NULL) {
7338 pd->file.keepalive = (mg_vcasecmp(conn_hdr, "keep-alive") == 0);
7339 } else {
7340 pd->file.keepalive = (mg_vcmp(&hm->proto, "HTTP/1.1") == 0);
7341 }
7342 }
7343#endif
7344
7345 mg_http_construct_etag(etag, sizeof(etag), &st);
7347 mg_gmt_time_string(last_modified, sizeof(last_modified), &st.st_mtime);
7348 /*
7349 * Content length casted to size_t because:
7350 * 1) that's the maximum buffer size anyway
7351 * 2) ESP8266 RTOS SDK newlib vprintf cannot contain a 64bit arg at non-last
7352 * position
7353 * TODO(mkm): fix ESP8266 RTOS SDK
7354 */
7355 mg_send_response_line_s(nc, status_code, extra_headers);
7356 mg_printf(nc,
7357 "Date: %s\r\n"
7358 "Last-Modified: %s\r\n"
7359 "Accept-Ranges: bytes\r\n"
7360 "Content-Type: %.*s\r\n"
7361 "Connection: %s\r\n"
7362 "Content-Length: %" SIZE_T_FMT
7363 "\r\n"
7364 "%sEtag: %s\r\n\r\n",
7366 (pd->file.keepalive ? "keep-alive" : "close"), (size_t) cl, range,
7367 etag);
7368
7369 pd->file.cl = cl;
7370 pd->file.type = DATA_FILE;
7372 }
7373}
7374
7375static void mg_http_serve_file2(struct mg_connection *nc, const char *path,
7376 struct http_message *hm,
7377 struct mg_serve_http_opts *opts) {
7378#if MG_ENABLE_HTTP_SSI
7379 if (mg_match_prefix(opts->ssi_pattern, strlen(opts->ssi_pattern), path) > 0) {
7380 mg_handle_ssi_request(nc, hm, path, opts);
7381 return;
7382 }
7383#endif
7384 mg_http_serve_file(nc, hm, path, mg_get_mime_type(path, "text/plain", opts),
7385 mg_mk_str(opts->extra_headers));
7386}
7387
7388#endif
7389
7390int mg_url_decode(const char *src, int src_len, char *dst, int dst_len,
7391 int is_form_url_encoded) {
7392 int i, j, a, b;
7393#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
7394
7395 for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
7396 if (src[i] == '%') {
7397 if (i < src_len - 2 && isxdigit(*(const unsigned char *) (src + i + 1)) &&
7398 isxdigit(*(const unsigned char *) (src + i + 2))) {
7399 a = tolower(*(const unsigned char *) (src + i + 1));
7400 b = tolower(*(const unsigned char *) (src + i + 2));
7401 dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b));
7402 i += 2;
7403 } else {
7404 return -1;
7405 }
7406 } else if (is_form_url_encoded && src[i] == '+') {
7407 dst[j] = ' ';
7408 } else {
7409 dst[j] = src[i];
7410 }
7411 }
7412
7413 dst[j] = '\0'; /* Null-terminate the destination */
7414
7415 return i >= src_len ? j : -1;
7416}
7417
7418int mg_get_http_var(const struct mg_str *buf, const char *name, char *dst,
7419 size_t dst_len) {
7420 const char *p, *e, *s;
7421 size_t name_len;
7422 int len;
7423
7424 /*
7425 * According to the documentation function returns negative
7426 * value in case of error. For debug purposes it returns:
7427 * -1 - src is wrong (NUUL)
7428 * -2 - dst is wrong (NULL)
7429 * -3 - failed to decode url or dst is to small
7430 * -4 - name does not exist
7431 */
7432 if (dst == NULL || dst_len == 0) {
7433 len = -2;
7434 } else if (buf->p == NULL || name == NULL || buf->len == 0) {
7435 len = -1;
7436 dst[0] = '\0';
7437 } else {
7438 name_len = strlen(name);
7439 e = buf->p + buf->len;
7440 len = -4;
7441 dst[0] = '\0';
7442
7443 for (p = buf->p; p + name_len < e; p++) {
7444 if ((p == buf->p || p[-1] == '&') && p[name_len] == '=' &&
7445 !mg_ncasecmp(name, p, name_len)) {
7446 p += name_len + 1;
7447 s = (const char *) memchr(p, '&', (size_t)(e - p));
7448 if (s == NULL) {
7449 s = e;
7450 }
7451 len = mg_url_decode(p, (size_t)(s - p), dst, dst_len, 1);
7452 /* -1 means: failed to decode or dst is too small */
7453 if (len == -1) {
7454 len = -3;
7455 }
7456 break;
7457 }
7458 }
7459 }
7460
7461 return len;
7462}
7463
7464void mg_send_http_chunk(struct mg_connection *nc, const char *buf, size_t len) {
7465 char chunk_size[50];
7466 int n;
7467
7468 n = snprintf(chunk_size, sizeof(chunk_size), "%lX\r\n", (unsigned long) len);
7469 mg_send(nc, chunk_size, n);
7470 mg_send(nc, buf, len);
7471 mg_send(nc, "\r\n", 2);
7472}
7473
7474void mg_printf_http_chunk(struct mg_connection *nc, const char *fmt, ...) {
7475 char mem[MG_VPRINTF_BUFFER_SIZE], *buf = mem;
7476 int len;
7477 va_list ap;
7478
7479 va_start(ap, fmt);
7480 len = mg_avprintf(&buf, sizeof(mem), fmt, ap);
7481 va_end(ap);
7482
7483 if (len >= 0) {
7484 mg_send_http_chunk(nc, buf, len);
7485 }
7486
7487 /* LCOV_EXCL_START */
7488 if (buf != mem && buf != NULL) {
7489 MG_FREE(buf);
7490 }
7491 /* LCOV_EXCL_STOP */
7492}
7493
7494void mg_printf_html_escape(struct mg_connection *nc, const char *fmt, ...) {
7495 char mem[MG_VPRINTF_BUFFER_SIZE], *buf = mem;
7496 int i, j, len;
7497 va_list ap;
7498
7499 va_start(ap, fmt);
7500 len = mg_avprintf(&buf, sizeof(mem), fmt, ap);
7501 va_end(ap);
7502
7503 if (len >= 0) {
7504 for (i = j = 0; i < len; i++) {
7505 if (buf[i] == '<' || buf[i] == '>') {
7506 mg_send(nc, buf + j, i - j);
7507 mg_send(nc, buf[i] == '<' ? "&lt;" : "&gt;", 4);
7508 j = i + 1;
7509 }
7510 }
7511 mg_send(nc, buf + j, i - j);
7512 }
7513
7514 /* LCOV_EXCL_START */
7515 if (buf != mem && buf != NULL) {
7516 MG_FREE(buf);
7517 }
7518 /* LCOV_EXCL_STOP */
7519}
7520
7521static void mg_http_parse_header_internal(struct mg_str *hdr,
7522 const char *var_name,
7523 struct altbuf *ab) {
7524 int ch = ' ', ch1 = ',', ch2 = ';', n = strlen(var_name);
7525 const char *p, *end = hdr ? hdr->p + hdr->len : NULL, *s = NULL;
7526
7527 /* Find where variable starts */
7528 for (s = hdr->p; s != NULL && s + n < end; s++) {
7529 if ((s == hdr->p || s[-1] == ch || s[-1] == ch1 || s[-1] == ';') &&
7530 s[n] == '=' && !strncmp(s, var_name, n))
7531 break;
7532 }
7533
7534 if (s != NULL && &s[n + 1] < end) {
7535 s += n + 1;
7536 if (*s == '"' || *s == '\'') {
7537 ch = ch1 = ch2 = *s++;
7538 }
7539 p = s;
7540 while (p < end && p[0] != ch && p[0] != ch1 && p[0] != ch2) {
7541 if (ch != ' ' && p[0] == '\\' && p[1] == ch) p++;
7542 altbuf_append(ab, *p++);
7543 }
7544
7545 if (ch != ' ' && *p != ch) {
7547 }
7548 }
7549
7550 /* If there is some data, append a NUL. */
7551 if (ab->len > 0) {
7552 altbuf_append(ab, '\0');
7553 }
7554}
7555
7556int mg_http_parse_header2(struct mg_str *hdr, const char *var_name, char **buf,
7557 size_t buf_size) {
7558 struct altbuf ab;
7559 altbuf_init(&ab, *buf, buf_size);
7560 if (hdr == NULL) return 0;
7561 if (*buf != NULL && buf_size > 0) *buf[0] = '\0';
7562
7564
7565 /*
7566 * Get a (trimmed) buffer, and return a len without a NUL byte which might
7567 * have been added.
7568 */
7569 *buf = altbuf_get_buf(&ab, 1 /* trim */);
7570 return ab.len > 0 ? ab.len - 1 : 0;
7571}
7572
7573int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf,
7574 size_t buf_size) {
7575 char *buf2 = buf;
7576
7577 int len = mg_http_parse_header2(hdr, var_name, &buf2, buf_size);
7578
7579 if (buf2 != buf) {
7580 /* Buffer was not enough and was reallocated: free it and just return 0 */
7581 MG_FREE(buf2);
7582 return 0;
7583 }
7584
7585 return len;
7586}
7587
7588int mg_get_http_basic_auth(struct http_message *hm, char *user, size_t user_len,
7589 char *pass, size_t pass_len) {
7590 struct mg_str *hdr = mg_get_http_header(hm, "Authorization");
7591 if (hdr == NULL) return -1;
7593}
7594
7595int mg_parse_http_basic_auth(struct mg_str *hdr, char *user, size_t user_len,
7596 char *pass, size_t pass_len) {
7597 char *buf = NULL;
7598 char fmt[64];
7599 int res = 0;
7600
7601 if (mg_strncmp(*hdr, mg_mk_str("Basic "), 6) != 0) return -1;
7602
7603 buf = (char *) MG_MALLOC(hdr->len);
7604 cs_base64_decode((unsigned char *) hdr->p + 6, hdr->len, buf, NULL);
7605
7606 /* e.g. "%123[^:]:%321[^\n]" */
7607 snprintf(fmt, sizeof(fmt), "%%%" SIZE_T_FMT "[^:]:%%%" SIZE_T_FMT "[^\n]",
7608 user_len - 1, pass_len - 1);
7609 if (sscanf(buf, fmt, user, pass) == 0) {
7610 res = -1;
7611 }
7612
7613 MG_FREE(buf);
7614 return res;
7615}
7616
7617#if MG_ENABLE_FILESYSTEM
7618static int mg_is_file_hidden(const char *path,
7619 const struct mg_serve_http_opts *opts,
7620 int exclude_specials) {
7621 const char *p1 = opts->per_directory_auth_file;
7622 const char *p2 = opts->hidden_file_pattern;
7623
7624 /* Strip directory path from the file name */
7625 const char *pdir = strrchr(path, DIRSEP);
7626 if (pdir != NULL) {
7627 path = pdir + 1;
7628 }
7629
7630 return (exclude_specials && (!strcmp(path, ".") || !strcmp(path, ".."))) ||
7631 (p1 != NULL && mg_match_prefix(p1, strlen(p1), path) == strlen(p1)) ||
7632 (p2 != NULL && mg_match_prefix(p2, strlen(p2), path) > 0);
7633}
7634
7635#if !MG_DISABLE_HTTP_DIGEST_AUTH
7636
7637#ifndef MG_EXT_MD5
7638void mg_hash_md5_v(size_t num_msgs, const uint8_t *msgs[],
7639 const size_t *msg_lens, uint8_t *digest) {
7640 size_t i;
7643 for (i = 0; i < num_msgs; i++) {
7645 }
7647}
7648#else
7649extern void mg_hash_md5_v(size_t num_msgs, const uint8_t *msgs[],
7650 const size_t *msg_lens, uint8_t *digest);
7651#endif
7652
7653void cs_md5(char buf[33], ...) {
7654 unsigned char hash[16];
7655 const uint8_t *msgs[20], *p;
7656 size_t msg_lens[20];
7657 size_t num_msgs = 0;
7658 va_list ap;
7659
7660 va_start(ap, buf);
7661 while ((p = va_arg(ap, const unsigned char *) ) != NULL) {
7662 msgs[num_msgs] = p;
7663 msg_lens[num_msgs] = va_arg(ap, size_t);
7664 num_msgs++;
7665 }
7666 va_end(ap);
7667
7669 cs_to_hex(buf, hash, sizeof(hash));
7670}
7671
7672static void mg_mkmd5resp(const char *method, size_t method_len, const char *uri,
7673 size_t uri_len, const char *ha1, size_t ha1_len,
7674 const char *nonce, size_t nonce_len, const char *nc,
7675 size_t nc_len, const char *cnonce, size_t cnonce_len,
7676 const char *qop, size_t qop_len, char *resp) {
7677 static const char colon[] = ":";
7678 static const size_t one = 1;
7679 char ha2[33];
7680 cs_md5(ha2, method, method_len, colon, one, uri, uri_len, NULL);
7681 cs_md5(resp, ha1, ha1_len, colon, one, nonce, nonce_len, colon, one, nc,
7682 nc_len, colon, one, cnonce, cnonce_len, colon, one, qop, qop_len,
7683 colon, one, ha2, sizeof(ha2) - 1, NULL);
7684}
7685
7686int mg_http_create_digest_auth_header(char *buf, size_t buf_len,
7687 const char *method, const char *uri,
7688 const char *auth_domain, const char *user,
7689 const char *passwd, const char *nonce) {
7690 static const char colon[] = ":", qop[] = "auth";
7691 static const size_t one = 1;
7692 char ha1[33], resp[33], cnonce[40];
7693
7694 snprintf(cnonce, sizeof(cnonce), "%lx", (unsigned long) mg_time());
7695 cs_md5(ha1, user, (size_t) strlen(user), colon, one, auth_domain,
7696 (size_t) strlen(auth_domain), colon, one, passwd,
7697 (size_t) strlen(passwd), NULL);
7698 mg_mkmd5resp(method, strlen(method), uri, strlen(uri), ha1, sizeof(ha1) - 1,
7699 nonce, strlen(nonce), "1", one, cnonce, strlen(cnonce), qop,
7700 sizeof(qop) - 1, resp);
7701 return snprintf(buf, buf_len,
7702 "Authorization: Digest username=\"%s\","
7703 "realm=\"%s\",uri=\"%s\",qop=%s,nc=1,cnonce=%s,"
7704 "nonce=%s,response=%s\r\n",
7705 user, auth_domain, uri, qop, cnonce, nonce, resp);
7706}
7707
7708/*
7709 * Check for authentication timeout.
7710 * Clients send time stamp encoded in nonce. Make sure it is not too old,
7711 * to prevent replay attacks.
7712 * Assumption: nonce is a hexadecimal number of seconds since 1970.
7713 */
7714static int mg_check_nonce(const char *nonce) {
7715 unsigned long now = (unsigned long) mg_time();
7716 unsigned long val = (unsigned long) strtoul(nonce, NULL, 16);
7717 return (now >= val) && (now - val < 60 * 60);
7718}
7719
7720int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain,
7721 FILE *fp) {
7722 int ret = 0;
7723 struct mg_str *hdr;
7724 char username_buf[50], cnonce_buf[64], response_buf[40], uri_buf[200],
7725 qop_buf[20], nc_buf[20], nonce_buf[16];
7726
7727 char *username = username_buf, *cnonce = cnonce_buf, *response = response_buf,
7728 *uri = uri_buf, *qop = qop_buf, *nc = nc_buf, *nonce = nonce_buf;
7729
7730 /* Parse "Authorization:" header, fail fast on parse error */
7731 if (hm == NULL || fp == NULL ||
7732 (hdr = mg_get_http_header(hm, "Authorization")) == NULL ||
7733 mg_http_parse_header2(hdr, "username", &username, sizeof(username_buf)) ==
7734 0 ||
7735 mg_http_parse_header2(hdr, "cnonce", &cnonce, sizeof(cnonce_buf)) == 0 ||
7736 mg_http_parse_header2(hdr, "response", &response, sizeof(response_buf)) ==
7737 0 ||
7738 mg_http_parse_header2(hdr, "uri", &uri, sizeof(uri_buf)) == 0 ||
7739 mg_http_parse_header2(hdr, "qop", &qop, sizeof(qop_buf)) == 0 ||
7740 mg_http_parse_header2(hdr, "nc", &nc, sizeof(nc_buf)) == 0 ||
7741 mg_http_parse_header2(hdr, "nonce", &nonce, sizeof(nonce_buf)) == 0 ||
7742 mg_check_nonce(nonce) == 0) {
7743 ret = 0;
7744 goto clean;
7745 }
7746
7747 /* NOTE(lsm): due to a bug in MSIE, we do not compare URIs */
7748
7750 hm->method,
7752 hm->uri.p,
7753 hm->uri.len + (hm->query_string.len ? hm->query_string.len + 1 : 0)),
7754 mg_mk_str(username), mg_mk_str(cnonce), mg_mk_str(response),
7755 mg_mk_str(qop), mg_mk_str(nc), mg_mk_str(nonce), mg_mk_str(auth_domain),
7756 fp);
7757
7758clean:
7759 if (username != username_buf) MG_FREE(username);
7760 if (cnonce != cnonce_buf) MG_FREE(cnonce);
7762 if (uri != uri_buf) MG_FREE(uri);
7763 if (qop != qop_buf) MG_FREE(qop);
7764 if (nc != nc_buf) MG_FREE(nc);
7765 if (nonce != nonce_buf) MG_FREE(nonce);
7766
7767 return ret;
7768}
7769
7770int mg_check_digest_auth(struct mg_str method, struct mg_str uri,
7771 struct mg_str username, struct mg_str cnonce,
7772 struct mg_str response, struct mg_str qop,
7773 struct mg_str nc, struct mg_str nonce,
7774 struct mg_str auth_domain, FILE *fp) {
7775 char buf[128], f_user[sizeof(buf)], f_ha1[sizeof(buf)], f_domain[sizeof(buf)];
7776 char exp_resp[33];
7777
7778 /*
7779 * Read passwords file line by line. If should have htdigest format,
7780 * i.e. each line should be a colon-separated sequence:
7781 * USER_NAME:DOMAIN_NAME:HA1_HASH_OF_USER_DOMAIN_AND_PASSWORD
7782 */
7783 while (fgets(buf, sizeof(buf), fp) != NULL) {
7784 if (sscanf(buf, "%[^:]:%[^:]:%s", f_user, f_domain, f_ha1) == 3 &&
7785 mg_vcmp(&username, f_user) == 0 &&
7786 mg_vcmp(&auth_domain, f_domain) == 0) {
7787 /* Username and domain matched, check the password */
7788 mg_mkmd5resp(method.p, method.len, uri.p, uri.len, f_ha1, strlen(f_ha1),
7789 nonce.p, nonce.len, nc.p, nc.len, cnonce.p, cnonce.len,
7790 qop.p, qop.len, exp_resp);
7791 LOG(LL_DEBUG, ("%.*s %s %.*s %s", (int) username.len, username.p,
7792 f_domain, (int) response.len, response.p, exp_resp));
7793 return mg_ncasecmp(response.p, exp_resp, strlen(exp_resp)) == 0;
7794 }
7795 }
7796
7797 /* None of the entries in the passwords file matched - return failure */
7798 return 0;
7799}
7800
7801int mg_http_is_authorized(struct http_message *hm, struct mg_str path,
7802 const char *domain, const char *passwords_file,
7803 int flags) {
7804 char buf[MG_MAX_PATH];
7805 const char *p;
7806 FILE *fp;
7807 int authorized = 1;
7808
7809 if (domain != NULL && passwords_file != NULL) {
7811 fp = mg_fopen(passwords_file, "r");
7812 } else if (flags & MG_AUTH_FLAG_IS_DIRECTORY) {
7813 snprintf(buf, sizeof(buf), "%.*s%c%s", (int) path.len, path.p, DIRSEP,
7815 fp = mg_fopen(buf, "r");
7816 } else {
7817 p = strrchr(path.p, DIRSEP);
7818 if (p == NULL) p = path.p;
7819 snprintf(buf, sizeof(buf), "%.*s%c%s", (int) (p - path.p), path.p, DIRSEP,
7821 fp = mg_fopen(buf, "r");
7822 }
7823
7824 if (fp != NULL) {
7826 fclose(fp);
7827 } else if (!(flags & MG_AUTH_FLAG_ALLOW_MISSING_FILE)) {
7828 authorized = 0;
7829 }
7830 }
7831
7832 LOG(LL_DEBUG, ("%.*s %s %x %d", (int) path.len, path.p,
7833 passwords_file ? passwords_file : "", flags, authorized));
7834 return authorized;
7835}
7836#else
7837int mg_http_is_authorized(struct http_message *hm, const struct mg_str path,
7838 const char *domain, const char *passwords_file,
7839 int flags) {
7840 (void) hm;
7841 (void) path;
7842 (void) domain;
7844 (void) flags;
7845 return 1;
7846}
7847#endif
7848
7849#if MG_ENABLE_DIRECTORY_LISTING
7850static void mg_escape(const char *src, char *dst, size_t dst_len) {
7851 size_t n = 0;
7852 while (*src != '\0' && n + 5 < dst_len) {
7853 unsigned char ch = *(unsigned char *) src++;
7854 if (ch == '<') {
7855 n += snprintf(dst + n, dst_len - n, "%s", "&lt;");
7856 } else {
7857 dst[n++] = ch;
7858 }
7859 }
7860 dst[n] = '\0';
7861}
7862
7863static void mg_print_dir_entry(struct mg_connection *nc, const char *file_name,
7864 cs_stat_t *stp) {
7865 char size[64], mod[64], path[MG_MAX_PATH];
7866 int64_t fsize = stp->st_size;
7867 int is_dir = S_ISDIR(stp->st_mode);
7868 const char *slash = is_dir ? "/" : "";
7869 struct mg_str href;
7870
7871 if (is_dir) {
7872 snprintf(size, sizeof(size), "%s", "[DIRECTORY]");
7873 } else {
7874 /*
7875 * We use (double) cast below because MSVC 6 compiler cannot
7876 * convert unsigned __int64 to double.
7877 */
7878 if (fsize < 1024) {
7879 snprintf(size, sizeof(size), "%d", (int) fsize);
7880 } else if (fsize < 0x100000) {
7881 snprintf(size, sizeof(size), "%.1fk", (double) fsize / 1024.0);
7882 } else if (fsize < 0x40000000) {
7883 snprintf(size, sizeof(size), "%.1fM", (double) fsize / 1048576);
7884 } else {
7885 snprintf(size, sizeof(size), "%.1fG", (double) fsize / 1073741824);
7886 }
7887 }
7888 strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&stp->st_mtime));
7889 mg_escape(file_name, path, sizeof(path));
7892 "<tr><td><a href=\"%s%s\">%s%s</a></td>"
7893 "<td>%s</td><td name=%" INT64_FMT ">%s</td></tr>\n",
7894 href.p, slash, path, slash, mod, is_dir ? -1 : fsize,
7895 size);
7896 free((void *) href.p);
7897}
7898
7899static void mg_scan_directory(struct mg_connection *nc, const char *dir,
7900 const struct mg_serve_http_opts *opts,
7901 void (*func)(struct mg_connection *, const char *,
7902 cs_stat_t *)) {
7903 char path[MG_MAX_PATH + 1];
7904 cs_stat_t st;
7905 struct dirent *dp;
7906 DIR *dirp;
7907
7908 LOG(LL_DEBUG, ("%p [%s]", nc, dir));
7909 if ((dirp = (opendir(dir))) != NULL) {
7910 while ((dp = readdir(dirp)) != NULL) {
7911 /* Do not show current dir and hidden files */
7912 if (mg_is_file_hidden((const char *) dp->d_name, opts, 1)) {
7913 continue;
7914 }
7915 snprintf(path, sizeof(path), "%s/%s", dir, dp->d_name);
7916 if (mg_stat(path, &st) == 0) {
7917 func(nc, (const char *) dp->d_name, &st);
7918 }
7919 }
7920 closedir(dirp);
7921 } else {
7922 LOG(LL_DEBUG, ("%p opendir(%s) -> %d", nc, dir, mg_get_errno()));
7923 }
7924}
7925
7926static void mg_send_directory_listing(struct mg_connection *nc, const char *dir,
7927 struct http_message *hm,
7928 struct mg_serve_http_opts *opts) {
7929 static const char *sort_js_code =
7930 "<script>function srt(tb, sc, so, d) {"
7931 "var tr = Array.prototype.slice.call(tb.rows, 0),"
7932 "tr = tr.sort(function (a, b) { var c1 = a.cells[sc], c2 = b.cells[sc],"
7933 "n1 = c1.getAttribute('name'), n2 = c2.getAttribute('name'), "
7934 "t1 = a.cells[2].getAttribute('name'), "
7935 "t2 = b.cells[2].getAttribute('name'); "
7936 "return so * (t1 < 0 && t2 >= 0 ? -1 : t2 < 0 && t1 >= 0 ? 1 : "
7937 "n1 ? parseInt(n2) - parseInt(n1) : "
7938 "c1.textContent.trim().localeCompare(c2.textContent.trim())); });";
7939 static const char *sort_js_code2 =
7940 "for (var i = 0; i < tr.length; i++) tb.appendChild(tr[i]); "
7941 "if (!d) window.location.hash = ('sc=' + sc + '&so=' + so); "
7942 "};"
7943 "window.onload = function() {"
7944 "var tb = document.getElementById('tb');"
7945 "var m = /sc=([012]).so=(1|-1)/.exec(window.location.hash) || [0, 2, 1];"
7946 "var sc = m[1], so = m[2]; document.onclick = function(ev) { "
7947 "var c = ev.target.rel; if (c) {if (c == sc) so *= -1; srt(tb, c, so); "
7948 "sc = c; ev.preventDefault();}};"
7949 "srt(tb, sc, so, true);"
7950 "}"
7951 "</script>";
7952
7953 mg_send_response_line(nc, 200, opts->extra_headers);
7954 mg_printf(nc, "%s: %s\r\n%s: %s\r\n\r\n", "Transfer-Encoding", "chunked",
7955 "Content-Type", "text/html; charset=utf-8");
7956
7958 nc,
7959 "<html><head><title>Index of %.*s</title>%s%s"
7960 "<style>th,td {text-align: left; padding-right: 1em; "
7961 "font-family: monospace; }</style></head>\n"
7962 "<body><h1>Index of %.*s</h1>\n<table cellpadding=0><thead>"
7963 "<tr><th><a href=# rel=0>Name</a></th><th>"
7964 "<a href=# rel=1>Modified</a</th>"
7965 "<th><a href=# rel=2>Size</a></th></tr>"
7966 "<tr><td colspan=3><hr></td></tr>\n"
7967 "</thead>\n"
7968 "<tbody id=tb>",
7969 (int) hm->uri.len, hm->uri.p, sort_js_code, sort_js_code2,
7970 (int) hm->uri.len, hm->uri.p);
7973 "</tbody><tr><td colspan=3><hr></td></tr>\n"
7974 "</table>\n"
7975 "<address>%s</address>\n"
7976 "</body></html>",
7978 mg_send_http_chunk(nc, "", 0);
7979 /* TODO(rojer): Remove when cesanta/dev/issues/197 is fixed. */
7981}
7982#endif /* MG_ENABLE_DIRECTORY_LISTING */
7983
7984/*
7985 * Given a directory path, find one of the files specified in the
7986 * comma-separated list of index files `list`.
7987 * First found index file wins. If an index file is found, then gets
7988 * appended to the `path`, stat-ed, and result of `stat()` passed to `stp`.
7989 * If index file is not found, then `path` and `stp` remain unchanged.
7990 */
7991MG_INTERNAL void mg_find_index_file(const char *path, const char *list,
7992 char **index_file, cs_stat_t *stp) {
7993 struct mg_str vec;
7994 size_t path_len = strlen(path);
7995 int found = 0;
7996 *index_file = NULL;
7997
7998 /* Traverse index files list. For each entry, append it to the given */
7999 /* path and see if the file exists. If it exists, break the loop */
8000 while ((list = mg_next_comma_list_entry(list, &vec, NULL)) != NULL) {
8001 cs_stat_t st;
8002 size_t len = path_len + 1 + vec.len + 1;
8003 *index_file = (char *) MG_REALLOC(*index_file, len);
8004 if (*index_file == NULL) break;
8005 snprintf(*index_file, len, "%s%c%.*s", path, DIRSEP, (int) vec.len, vec.p);
8006
8007 /* Does it exist? Is it a file? */
8008 if (mg_stat(*index_file, &st) == 0 && S_ISREG(st.st_mode)) {
8009 /* Yes it does, break the loop */
8010 *stp = st;
8011 found = 1;
8012 break;
8013 }
8014 }
8015 if (!found) {
8017 *index_file = NULL;
8018 }
8019 LOG(LL_DEBUG, ("[%s] [%s]", path, (*index_file ? *index_file : "")));
8020}
8021
8022#if MG_ENABLE_HTTP_URL_REWRITES
8024 struct mg_connection *c, struct http_message *hm,
8025 const struct mg_serve_http_opts *opts) {
8026 const char *rewrites = opts->url_rewrites;
8027 struct mg_str a, b;
8028 char local_port[20] = {'%'};
8029
8030 mg_conn_addr_to_str(c, local_port + 1, sizeof(local_port) - 1,
8032
8033 while ((rewrites = mg_next_comma_list_entry(rewrites, &a, &b)) != NULL) {
8034 if (mg_vcmp(&a, local_port) == 0) {
8036 mg_printf(c, "Content-Length: 0\r\nLocation: %.*s%.*s\r\n\r\n",
8037 (int) b.len, b.p, (int) (hm->proto.p - hm->uri.p - 1),
8038 hm->uri.p);
8039 return 1;
8040 }
8041 }
8042
8043 return 0;
8044}
8045
8046static void mg_reverse_proxy_handler(struct mg_connection *nc, int ev,
8047 void *ev_data MG_UD_ARG(void *user_data)) {
8048 struct http_message *hm = (struct http_message *) ev_data;
8050
8051 if (pd == NULL || pd->reverse_proxy_data.linked_conn == NULL) {
8052 DBG(("%p: upstream closed", nc));
8053 return;
8054 }
8055
8056 switch (ev) {
8057 case MG_EV_CONNECT:
8058 if (*(int *) ev_data != 0) {
8059 mg_http_send_error(pd->reverse_proxy_data.linked_conn, 502, NULL);
8060 }
8061 break;
8062 /* TODO(mkm): handle streaming */
8063 case MG_EV_HTTP_REPLY:
8064 mg_send(pd->reverse_proxy_data.linked_conn, hm->message.p,
8065 hm->message.len);
8066 pd->reverse_proxy_data.linked_conn->flags |= MG_F_SEND_AND_CLOSE;
8068 break;
8069 case MG_EV_CLOSE:
8070 pd->reverse_proxy_data.linked_conn->flags |= MG_F_SEND_AND_CLOSE;
8071 break;
8072 }
8073
8074#if MG_ENABLE_CALLBACK_USERDATA
8075 (void) user_data;
8076#endif
8077}
8078
8079void mg_http_reverse_proxy(struct mg_connection *nc,
8080 const struct http_message *hm, struct mg_str mount,
8081 struct mg_str upstream) {
8082 struct mg_connection *be;
8083 char burl[256], *purl = burl;
8084 int i;
8085 const char *error;
8086 struct mg_connect_opts opts;
8087 struct mg_str path = MG_NULL_STR, user_info = MG_NULL_STR, host = MG_NULL_STR;
8088 memset(&opts, 0, sizeof(opts));
8089 opts.error_string = &error;
8090
8091 mg_asprintf(&purl, sizeof(burl), "%.*s%.*s", (int) upstream.len, upstream.p,
8092 (int) (hm->uri.len - mount.len), hm->uri.p + mount.len);
8093
8095 opts, "http", NULL, "https", NULL, purl, &path,
8096 &user_info, &host);
8097 LOG(LL_DEBUG, ("Proxying %.*s to %s (rule: %.*s)", (int) hm->uri.len,
8098 hm->uri.p, purl, (int) mount.len, mount.p));
8099
8100 if (be == NULL) {
8101 LOG(LL_ERROR, ("Error connecting to %s: %s", purl, error));
8102 mg_http_send_error(nc, 502, NULL);
8103 goto cleanup;
8104 }
8105
8106 /* link connections to each other, they must live and die together */
8107 mg_http_get_proto_data(be)->reverse_proxy_data.linked_conn = nc;
8108 mg_http_get_proto_data(nc)->reverse_proxy_data.linked_conn = be;
8109
8110 /* send request upstream */
8111 mg_printf(be, "%.*s %.*s HTTP/1.1\r\n", (int) hm->method.len, hm->method.p,
8112 (int) path.len, path.p);
8113
8114 mg_printf(be, "Host: %.*s\r\n", (int) host.len, host.p);
8115 for (i = 0; i < MG_MAX_HTTP_HEADERS && hm->header_names[i].len > 0; i++) {
8116 struct mg_str hn = hm->header_names[i];
8117 struct mg_str hv = hm->header_values[i];
8118
8119 /* we rewrite the host header */
8120 if (mg_vcasecmp(&hn, "Host") == 0) continue;
8121 /*
8122 * Don't pass chunked transfer encoding to the client because hm->body is
8123 * already dechunked when we arrive here.
8124 */
8125 if (mg_vcasecmp(&hn, "Transfer-encoding") == 0 &&
8126 mg_vcasecmp(&hv, "chunked") == 0) {
8127 mg_printf(be, "Content-Length: %" SIZE_T_FMT "\r\n", hm->body.len);
8128 continue;
8129 }
8130 /* We don't support proxying Expect: 100-continue. */
8131 if (mg_vcasecmp(&hn, "Expect") == 0 &&
8132 mg_vcasecmp(&hv, "100-continue") == 0) {
8133 continue;
8134 }
8135
8136 mg_printf(be, "%.*s: %.*s\r\n", (int) hn.len, hn.p, (int) hv.len, hv.p);
8137 }
8138
8139 mg_send(be, "\r\n", 2);
8140 mg_send(be, hm->body.p, hm->body.len);
8141
8142cleanup:
8143 if (purl != burl) MG_FREE(purl);
8144}
8145
8146static int mg_http_handle_forwarding(struct mg_connection *nc,
8147 struct http_message *hm,
8148 const struct mg_serve_http_opts *opts) {
8149 const char *rewrites = opts->url_rewrites;
8150 struct mg_str a, b;
8151 struct mg_str p1 = MG_MK_STR("http://"), p2 = MG_MK_STR("https://");
8152
8153 while ((rewrites = mg_next_comma_list_entry(rewrites, &a, &b)) != NULL) {
8154 if (mg_strncmp(a, hm->uri, a.len) == 0) {
8155 if (mg_strncmp(b, p1, p1.len) == 0 || mg_strncmp(b, p2, p2.len) == 0) {
8156 mg_http_reverse_proxy(nc, hm, a, b);
8157 return 1;
8158 }
8159 }
8160 }
8161
8162 return 0;
8163}
8164#endif /* MG_ENABLE_FILESYSTEM */
8165
8167 const struct mg_serve_http_opts *opts,
8168 char **local_path,
8169 struct mg_str *remainder) {
8170 int ok = 1;
8171 const char *cp = hm->uri.p, *cp_end = hm->uri.p + hm->uri.len;
8172 struct mg_str root = {NULL, 0};
8173 const char *file_uri_start = cp;
8174 *local_path = NULL;
8175 remainder->p = NULL;
8176 remainder->len = 0;
8177
8178 { /* 1. Determine which root to use. */
8179
8180#if MG_ENABLE_HTTP_URL_REWRITES
8181 const char *rewrites = opts->url_rewrites;
8182#else
8183 const char *rewrites = "";
8184#endif
8185 struct mg_str *hh = mg_get_http_header(hm, "Host");
8186 struct mg_str a, b;
8187 /* Check rewrites first. */
8188 while ((rewrites = mg_next_comma_list_entry(rewrites, &a, &b)) != NULL) {
8189 if (a.len > 1 && a.p[0] == '@') {
8190 /* Host rewrite. */
8191 if (hh != NULL && hh->len == a.len - 1 &&
8192 mg_ncasecmp(a.p + 1, hh->p, a.len - 1) == 0) {
8193 root = b;
8194 break;
8195 }
8196 } else {
8197 /* Regular rewrite, URI=directory */
8198 size_t match_len = mg_match_prefix_n(a, hm->uri);
8199 if (match_len > 0) {
8200 file_uri_start = hm->uri.p + match_len;
8201 if (*file_uri_start == '/' || file_uri_start == cp_end) {
8202 /* Match ended at component boundary, ok. */
8203 } else if (*(file_uri_start - 1) == '/') {
8204 /* Pattern ends with '/', backtrack. */
8206 } else {
8207 /* No match: must fall on the component boundary. */
8208 continue;
8209 }
8210 root = b;
8211 break;
8212 }
8213 }
8214 }
8215 /* If no rewrite rules matched, use DAV or regular document root. */
8216 if (root.p == NULL) {
8217#if MG_ENABLE_HTTP_WEBDAV
8218 if (opts->dav_document_root != NULL && mg_is_dav_request(&hm->method)) {
8219 root.p = opts->dav_document_root;
8220 root.len = strlen(opts->dav_document_root);
8221 } else
8222#endif
8223 {
8224 root.p = opts->document_root;
8225 root.len = strlen(opts->document_root);
8226 }
8227 }
8228 assert(root.p != NULL && root.len > 0);
8229 }
8230
8231 { /* 2. Find where in the canonical URI path the local path ends. */
8232 const char *u = file_uri_start + 1;
8233 char *lp = (char *) MG_MALLOC(root.len + hm->uri.len + 1);
8234 char *lp_end = lp + root.len + hm->uri.len + 1;
8235 char *p = lp, *ps;
8236 int exists = 1;
8237 if (lp == NULL) {
8238 ok = 0;
8239 goto out;
8240 }
8241 memcpy(p, root.p, root.len);
8242 p += root.len;
8243 if (*(p - 1) == DIRSEP) p--;
8244 *p = '\0';
8245 ps = p;
8246
8247 /* Chop off URI path components one by one and build local path. */
8248 while (u <= cp_end) {
8249 const char *next = u;
8250 struct mg_str component;
8251 if (exists) {
8252 cs_stat_t st;
8253 exists = (mg_stat(lp, &st) == 0);
8254 if (exists && S_ISREG(st.st_mode)) {
8255 /* We found the terminal, the rest of the URI (if any) is path_info.
8256 */
8257 if (*(u - 1) == '/') u--;
8258 break;
8259 }
8260 }
8261 if (u >= cp_end) break;
8262 parse_uri_component((const char **) &next, cp_end, "/", &component);
8263 if (component.len > 0) {
8264 int len;
8265 memmove(p + 1, component.p, component.len);
8266 len = mg_url_decode(p + 1, component.len, p + 1, lp_end - p - 1, 0);
8267 if (len <= 0) {
8268 ok = 0;
8269 break;
8270 }
8271 component.p = p + 1;
8272 component.len = len;
8273 if (mg_vcmp(&component, ".") == 0) {
8274 /* Yum. */
8275 } else if (mg_vcmp(&component, "..") == 0) {
8276 while (p > ps && *p != DIRSEP) p--;
8277 *p = '\0';
8278 } else {
8279 size_t i;
8280#ifdef _WIN32
8281 /* On Windows, make sure it's valid Unicode (no funny stuff). */
8282 wchar_t buf[MG_MAX_PATH * 2];
8283 if (to_wchar(component.p, buf, MG_MAX_PATH) == 0) {
8284 DBG(("[%.*s] smells funny", (int) component.len, component.p));
8285 ok = 0;
8286 break;
8287 }
8288#endif
8289 *p++ = DIRSEP;
8290 /* No NULs and DIRSEPs in the component (percent-encoded). */
8291 for (i = 0; i < component.len; i++, p++) {
8292 if (*p == '\0' || *p == DIRSEP
8294 /* On Windows, "/" is also accepted, so check for that too. */
8295 ||
8296 *p == '/'
8297#endif
8298 ) {
8299 ok = 0;
8300 break;
8301 }
8302 }
8303 }
8304 }
8305 u = next;
8306 }
8307 if (ok) {
8308 *local_path = lp;
8309 if (u > cp_end) u = cp_end;
8310 remainder->p = u;
8311 remainder->len = cp_end - u;
8312 } else {
8313 MG_FREE(lp);
8314 }
8315 }
8316
8317out:
8318 LOG(LL_DEBUG,
8319 ("'%.*s' -> '%s' + '%.*s'", (int) hm->uri.len, hm->uri.p,
8320 *local_path ? *local_path : "", (int) remainder->len, remainder->p));
8321 return ok;
8322}
8323
8324static int mg_get_month_index(const char *s) {
8325 static const char *month_names[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
8326 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
8327 size_t i;
8328
8329 for (i = 0; i < ARRAY_SIZE(month_names); i++)
8330 if (!strcmp(s, month_names[i])) return (int) i;
8331
8332 return -1;
8333}
8334
8335static int mg_num_leap_years(int year) {
8336 return year / 4 - year / 100 + year / 400;
8337}
8338
8339/* Parse UTC date-time string, and return the corresponding time_t value. */
8341 static const unsigned short days_before_month[] = {
8342 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
8343 char month_str[32];
8345 time_t result = (time_t) 0;
8346
8347 if (((sscanf(datetime, "%d/%3s/%d %d:%d:%d", &day, month_str, &year, &hour,
8348 &minute, &second) == 6) ||
8349 (sscanf(datetime, "%d %3s %d %d:%d:%d", &day, month_str, &year, &hour,
8350 &minute, &second) == 6) ||
8351 (sscanf(datetime, "%*3s, %d %3s %d %d:%d:%d", &day, month_str, &year,
8352 &hour, &minute, &second) == 6) ||
8353 (sscanf(datetime, "%d-%3s-%d %d:%d:%d", &day, month_str, &year, &hour,
8354 &minute, &second) == 6)) &&
8355 year > 1970 && (month = mg_get_month_index(month_str)) != -1) {
8357 year -= 1970;
8358 days = year * 365 + days_before_month[month] + (day - 1) + leap_days;
8359 result = days * 24 * 3600 + hour * 3600 + minute * 60 + second;
8360 }
8361
8362 return result;
8363}
8364
8366 struct mg_str *hdr;
8367 if ((hdr = mg_get_http_header(hm, "If-None-Match")) != NULL) {
8368 char etag[64];
8370 return mg_vcasecmp(hdr, etag) == 0;
8371 } else if ((hdr = mg_get_http_header(hm, "If-Modified-Since")) != NULL) {
8372 return st->st_mtime <= mg_parse_date_string(hdr->p);
8373 } else {
8374 return 0;
8375 }
8376}
8377
8379 const char *domain) {
8380 mg_printf(c,
8381 "HTTP/1.1 401 Unauthorized\r\n"
8382 "WWW-Authenticate: Digest qop=\"auth\", "
8383 "realm=\"%s\", nonce=\"%lx\"\r\n"
8384 "Content-Length: 0\r\n\r\n",
8385 domain, (unsigned long) mg_time());
8386}
8387
8388static void mg_http_send_options(struct mg_connection *nc,
8389 struct mg_serve_http_opts *opts) {
8390 mg_send_response_line(nc, 200, opts->extra_headers);
8391 mg_printf(nc, "%s",
8392 "Allow: GET, POST, HEAD, CONNECT, OPTIONS"
8394 ", MKCOL, PUT, DELETE, PROPFIND, MOVE\r\nDAV: 1,2"
8395#endif
8396 "\r\n\r\n");
8398}
8399
8400static int mg_is_creation_request(const struct http_message *hm) {
8401 return mg_vcmp(&hm->method, "MKCOL") == 0 || mg_vcmp(&hm->method, "PUT") == 0;
8402}
8403
8404MG_INTERNAL void mg_send_http_file(struct mg_connection *nc, char *path,
8405 const struct mg_str *path_info,
8406 struct http_message *hm,
8407 struct mg_serve_http_opts *opts) {
8408 int exists, is_directory, is_cgi;
8409#if MG_ENABLE_HTTP_WEBDAV
8410 int is_dav = mg_is_dav_request(&hm->method);
8411#else
8412 int is_dav = 0;
8413#endif
8414 char *index_file = NULL;
8415 cs_stat_t st;
8416
8417 exists = (mg_stat(path, &st) == 0);
8418 is_directory = exists && S_ISDIR(st.st_mode);
8419
8420 if (is_directory)
8421 mg_find_index_file(path, opts->index_files, &index_file, &st);
8422
8423 is_cgi =
8424 (mg_match_prefix(opts->cgi_file_pattern, strlen(opts->cgi_file_pattern),
8425 index_file ? index_file : path) > 0);
8426
8427 LOG(LL_DEBUG,
8428 ("%p %.*s [%s] exists=%d is_dir=%d is_dav=%d is_cgi=%d index=%s", nc,
8429 (int) hm->method.len, hm->method.p, path, exists, is_directory, is_dav,
8430 is_cgi, index_file ? index_file : ""));
8431
8432 if (is_directory && hm->uri.p[hm->uri.len - 1] != '/' && !is_dav) {
8433 mg_printf(nc,
8434 "HTTP/1.1 301 Moved\r\nLocation: %.*s/\r\n"
8435 "Content-Length: 0\r\n\r\n",
8436 (int) hm->uri.len, hm->uri.p);
8438 return;
8439 }
8440
8441 /* If we have path_info, the only way to handle it is CGI. */
8442 if (path_info->len > 0 && !is_cgi) {
8443 mg_http_send_error(nc, 501, NULL);
8445 return;
8446 }
8447
8448 if (is_dav && opts->dav_document_root == NULL) {
8449 mg_http_send_error(nc, 501, NULL);
8450 } else if (!mg_http_is_authorized(
8451 hm, mg_mk_str(path), opts->auth_domain, opts->global_auth_file,
8452 ((is_directory ? MG_AUTH_FLAG_IS_DIRECTORY : 0) |
8456 hm, mg_mk_str(path), opts->auth_domain,
8457 opts->per_directory_auth_file,
8458 ((is_directory ? MG_AUTH_FLAG_IS_DIRECTORY : 0) |
8460 mg_http_send_digest_auth_request(nc, opts->auth_domain);
8461 } else if (is_cgi) {
8462#if MG_ENABLE_HTTP_CGI
8463 mg_handle_cgi(nc, index_file ? index_file : path, path_info, hm, opts);
8464#else
8465 mg_http_send_error(nc, 501, NULL);
8466#endif /* MG_ENABLE_HTTP_CGI */
8467 } else if ((!exists ||
8468 mg_is_file_hidden(path, opts, 0 /* specials are ok */)) &&
8470 mg_http_send_error(nc, 404, NULL);
8471#if MG_ENABLE_HTTP_WEBDAV
8472 } else if (!mg_vcmp(&hm->method, "PROPFIND")) {
8473 mg_handle_propfind(nc, path, &st, hm, opts);
8474#if !MG_DISABLE_DAV_AUTH
8475 } else if (is_dav &&
8476 (opts->dav_auth_file == NULL ||
8477 (strcmp(opts->dav_auth_file, "-") != 0 &&
8479 hm, mg_mk_str(path), opts->auth_domain, opts->dav_auth_file,
8480 ((is_directory ? MG_AUTH_FLAG_IS_DIRECTORY : 0) |
8483 mg_http_send_digest_auth_request(nc, opts->auth_domain);
8484#endif
8485 } else if (!mg_vcmp(&hm->method, "MKCOL")) {
8486 mg_handle_mkcol(nc, path, hm);
8487 } else if (!mg_vcmp(&hm->method, "DELETE")) {
8488 mg_handle_delete(nc, opts, path);
8489 } else if (!mg_vcmp(&hm->method, "PUT")) {
8490 mg_handle_put(nc, path, hm);
8491 } else if (!mg_vcmp(&hm->method, "MOVE")) {
8492 mg_handle_move(nc, opts, path, hm);
8493#if MG_ENABLE_FAKE_DAVLOCK
8494 } else if (!mg_vcmp(&hm->method, "LOCK")) {
8495 mg_handle_lock(nc, path);
8496#endif
8497#endif /* MG_ENABLE_HTTP_WEBDAV */
8498 } else if (!mg_vcmp(&hm->method, "OPTIONS")) {
8500 } else if (is_directory && index_file == NULL) {
8501#if MG_ENABLE_DIRECTORY_LISTING
8502 if (strcmp(opts->enable_directory_listing, "yes") == 0) {
8503 mg_send_directory_listing(nc, path, hm, opts);
8504 } else {
8505 mg_http_send_error(nc, 403, NULL);
8506 }
8507#else
8508 mg_http_send_error(nc, 501, NULL);
8509#endif
8510 } else if (mg_is_not_modified(hm, &st)) {
8511 mg_http_send_error(nc, 304, "Not Modified");
8512 } else {
8514 }
8516}
8517
8518void mg_serve_http(struct mg_connection *nc, struct http_message *hm,
8519 struct mg_serve_http_opts opts) {
8520 char *path = NULL;
8521 struct mg_str *hdr, path_info;
8522 uint32_t remote_ip = ntohl(*(uint32_t *) &nc->sa.sin.sin_addr);
8523
8524 if (mg_check_ip_acl(opts.ip_acl, remote_ip) != 1) {
8525 /* Not allowed to connect */
8526 mg_http_send_error(nc, 403, NULL);
8528 return;
8529 }
8530
8531#if MG_ENABLE_HTTP_URL_REWRITES
8532 if (mg_http_handle_forwarding(nc, hm, &opts)) {
8533 return;
8534 }
8535
8537 return;
8538 }
8539#endif
8540
8541 if (opts.document_root == NULL) {
8542 opts.document_root = ".";
8543 }
8544 if (opts.per_directory_auth_file == NULL) {
8545 opts.per_directory_auth_file = ".htpasswd";
8546 }
8547 if (opts.enable_directory_listing == NULL) {
8548 opts.enable_directory_listing = "yes";
8549 }
8550 if (opts.cgi_file_pattern == NULL) {
8551 opts.cgi_file_pattern = "**.cgi$|**.php$";
8552 }
8553 if (opts.ssi_pattern == NULL) {
8554 opts.ssi_pattern = "**.shtml$|**.shtm$";
8555 }
8556 if (opts.index_files == NULL) {
8557 opts.index_files = "index.html,index.htm,index.shtml,index.cgi,index.php";
8558 }
8559 /* Normalize path - resolve "." and ".." (in-place). */
8560 if (!mg_normalize_uri_path(&hm->uri, &hm->uri)) {
8561 mg_http_send_error(nc, 400, NULL);
8562 return;
8563 }
8564 if (mg_uri_to_local_path(hm, &opts, &path, &path_info) == 0) {
8565 mg_http_send_error(nc, 404, NULL);
8566 return;
8567 }
8568 mg_send_http_file(nc, path, &path_info, hm, &opts);
8569
8570 MG_FREE(path);
8571 path = NULL;
8572
8573 /* Close connection for non-keep-alive requests */
8574 if (mg_vcmp(&hm->proto, "HTTP/1.1") != 0 ||
8575 ((hdr = mg_get_http_header(hm, "Connection")) != NULL &&
8576 mg_vcmp(hdr, "keep-alive") != 0)) {
8577#if 0
8579#endif
8580 }
8581}
8582
8583#if MG_ENABLE_HTTP_STREAMING_MULTIPART
8584void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data,
8586 MG_UD_ARG(void *user_data)) {
8587 switch (ev) {
8588 case MG_EV_HTTP_PART_BEGIN: {
8589 struct mg_http_multipart_part *mp =
8591 struct file_upload_state *fus;
8592 struct mg_str lfn = local_name_fn(nc, mg_mk_str(mp->file_name));
8593 mp->user_data = NULL;
8594 if (lfn.p == NULL || lfn.len == 0) {
8595 LOG(LL_ERROR, ("%p Not allowed to upload %s", nc, mp->file_name));
8596 mg_printf(nc,
8597 "HTTP/1.1 403 Not Allowed\r\n"
8598 "Content-Type: text/plain\r\n"
8599 "Connection: close\r\n\r\n"
8600 "Not allowed to upload %s\r\n",
8601 mp->file_name);
8603 return;
8604 }
8605 fus = (struct file_upload_state *) MG_CALLOC(1, sizeof(*fus));
8606 if (fus == NULL) {
8608 return;
8609 }
8610 fus->lfn = (char *) MG_MALLOC(lfn.len + 1);
8611 memcpy(fus->lfn, lfn.p, lfn.len);
8612 fus->lfn[lfn.len] = '\0';
8613 if (lfn.p != mp->file_name) MG_FREE((char *) lfn.p);
8614 LOG(LL_DEBUG,
8615 ("%p Receiving file %s -> %s", nc, mp->file_name, fus->lfn));
8616 fus->fp = mg_fopen(fus->lfn, "wb");
8617 if (fus->fp == NULL) {
8618 mg_printf(nc,
8619 "HTTP/1.1 500 Internal Server Error\r\n"
8620 "Content-Type: text/plain\r\n"
8621 "Connection: close\r\n\r\n");
8622 LOG(LL_ERROR, ("Failed to open %s: %d\n", fus->lfn, mg_get_errno()));
8623 mg_printf(nc, "Failed to open %s: %d\n", fus->lfn, mg_get_errno());
8624 /* Do not close the connection just yet, discard remainder of the data.
8625 * This is because at the time of writing some browsers (Chrome) fail to
8626 * render response before all the data is sent. */
8627 }
8628 mp->user_data = (void *) fus;
8629 break;
8630 }
8631 case MG_EV_HTTP_PART_DATA: {
8632 struct mg_http_multipart_part *mp =
8634 struct file_upload_state *fus =
8635 (struct file_upload_state *) mp->user_data;
8636 if (fus == NULL || fus->fp == NULL) break;
8637 if (mg_fwrite(mp->data.p, 1, mp->data.len, fus->fp) != mp->data.len) {
8638 LOG(LL_ERROR, ("Failed to write to %s: %d, wrote %d", fus->lfn,
8639 mg_get_errno(), (int) fus->num_recd));
8640 if (mg_get_errno() == ENOSPC
8643#endif
8644 ) {
8645 mg_printf(nc,
8646 "HTTP/1.1 413 Payload Too Large\r\n"
8647 "Content-Type: text/plain\r\n"
8648 "Connection: close\r\n\r\n");
8649 mg_printf(nc, "Failed to write to %s: no space left; wrote %d\r\n",
8650 fus->lfn, (int) fus->num_recd);
8651 } else {
8652 mg_printf(nc,
8653 "HTTP/1.1 500 Internal Server Error\r\n"
8654 "Content-Type: text/plain\r\n"
8655 "Connection: close\r\n\r\n");
8656 mg_printf(nc, "Failed to write to %s: %d, wrote %d", mp->file_name,
8657 mg_get_errno(), (int) fus->num_recd);
8658 }
8659 fclose(fus->fp);
8660 remove(fus->lfn);
8661 fus->fp = NULL;
8662 /* Do not close the connection just yet, discard remainder of the data.
8663 * This is because at the time of writing some browsers (Chrome) fail to
8664 * render response before all the data is sent. */
8665 return;
8666 }
8667 fus->num_recd += mp->data.len;
8668 LOG(LL_DEBUG, ("%p rec'd %d bytes, %d total", nc, (int) mp->data.len,
8669 (int) fus->num_recd));
8670 break;
8671 }
8672 case MG_EV_HTTP_PART_END: {
8673 struct mg_http_multipart_part *mp =
8675 struct file_upload_state *fus =
8676 (struct file_upload_state *) mp->user_data;
8677 if (fus == NULL) break;
8678 if (mp->status >= 0 && fus->fp != NULL) {
8679 LOG(LL_DEBUG, ("%p Uploaded %s (%s), %d bytes", nc, mp->file_name,
8680 fus->lfn, (int) fus->num_recd));
8681 } else {
8682 LOG(LL_ERROR, ("Failed to store %s (%s)", mp->file_name, fus->lfn));
8683 /*
8684 * mp->status < 0 means connection was terminated, so no reason to send
8685 * HTTP reply
8686 */
8687 }
8688 if (fus->fp != NULL) fclose(fus->fp);
8689 MG_FREE(fus->lfn);
8690 MG_FREE(fus);
8691 mp->user_data = NULL;
8692 /* Don't close the connection yet, there may be more files to come. */
8693 break;
8694 }
8696 mg_printf(nc,
8697 "HTTP/1.1 200 OK\r\n"
8698 "Content-Type: text/plain\r\n"
8699 "Connection: close\r\n\r\n"
8700 "Ok.\r\n");
8702 break;
8703 }
8704 }
8705
8706#if MG_ENABLE_CALLBACK_USERDATA
8707 (void) user_data;
8708#endif
8709}
8710
8711#endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
8712#endif /* MG_ENABLE_FILESYSTEM */
8713
8716 struct mg_connect_opts opts, const char *scheme1, const char *scheme2,
8717 const char *scheme_ssl1, const char *scheme_ssl2, const char *url,
8718 struct mg_str *path, struct mg_str *user_info, struct mg_str *host) {
8719 struct mg_connection *nc = NULL;
8720 unsigned int port_i = 0;
8721 int use_ssl = 0;
8722 struct mg_str scheme, query, fragment;
8723 char conn_addr_buf[2];
8724 char *conn_addr = conn_addr_buf;
8725
8726 if (mg_parse_uri(mg_mk_str(url), &scheme, user_info, host, &port_i, path,
8727 &query, &fragment) != 0) {
8728 MG_SET_PTRPTR(opts.error_string, "cannot parse url");
8729 goto out;
8730 }
8731
8732 /* If query is present, do not strip it. Pass to the caller. */
8733 if (query.len > 0) path->len += query.len + 1;
8734
8735 if (scheme.len == 0 || mg_vcmp(&scheme, scheme1) == 0 ||
8736 (scheme2 != NULL && mg_vcmp(&scheme, scheme2) == 0)) {
8737 use_ssl = 0;
8738 if (port_i == 0) port_i = 80;
8739 } else if (mg_vcmp(&scheme, scheme_ssl1) == 0 ||
8740 (scheme2 != NULL && mg_vcmp(&scheme, scheme_ssl2) == 0)) {
8741 use_ssl = 1;
8742 if (port_i == 0) port_i = 443;
8743 } else {
8744 goto out;
8745 }
8746
8747 mg_asprintf(&conn_addr, sizeof(conn_addr_buf), "tcp://%.*s:%u",
8748 (int) host->len, host->p, port_i);
8749 if (conn_addr == NULL) goto out;
8750
8751 LOG(LL_DEBUG, ("%s use_ssl? %d %s", url, use_ssl, conn_addr));
8752 if (use_ssl) {
8753#if MG_ENABLE_SSL
8754 /*
8755 * Schema requires SSL, but no SSL parameters were provided in opts.
8756 * In order to maintain backward compatibility, use a faux-SSL with no
8757 * verification.
8758 */
8759 if (opts.ssl_ca_cert == NULL) {
8760 opts.ssl_ca_cert = "*";
8761 }
8762#else
8763 MG_SET_PTRPTR(opts.error_string, "ssl is disabled");
8764 goto out;
8765#endif
8766 }
8767
8768 if ((nc = mg_connect_opt(mgr, conn_addr, MG_CB(ev_handler, user_data),
8769 opts)) != NULL) {
8771 }
8772
8773out:
8775 return nc;
8776}
8777
8780 struct mg_connect_opts opts, const char *url, const char *extra_headers,
8781 const char *post_data) {
8782 struct mg_str user = MG_NULL_STR, null_str = MG_NULL_STR;
8783 struct mg_str host = MG_NULL_STR, path = MG_NULL_STR;
8784 struct mbuf auth;
8785 struct mg_connection *nc =
8787 NULL, "https", NULL, url, &path, &user, &host);
8788
8789 if (nc == NULL) {
8790 return NULL;
8791 }
8792
8793 mbuf_init(&auth, 0);
8794 if (user.len > 0) {
8796 }
8797
8798 if (post_data == NULL) post_data = "";
8799 if (extra_headers == NULL) extra_headers = "";
8800 if (path.len == 0) path = mg_mk_str("/");
8801 if (host.len == 0) host = mg_mk_str("");
8802
8803 mg_printf(nc, "%s %.*s HTTP/1.1\r\nHost: %.*s\r\nContent-Length: %" SIZE_T_FMT
8804 "\r\n%.*s%s\r\n%s",
8805 (post_data[0] == '\0' ? "GET" : "POST"), (int) path.len, path.p,
8806 (int) (path.p - host.p), host.p, strlen(post_data), (int) auth.len,
8807 (auth.buf == NULL ? "" : auth.buf), extra_headers, post_data);
8808
8809 mbuf_free(&auth);
8810 return nc;
8811}
8812
8815 const char *url, const char *extra_headers, const char *post_data) {
8816 struct mg_connect_opts opts;
8817 memset(&opts, 0, sizeof(opts));
8819 extra_headers, post_data);
8820}
8821
8822size_t mg_parse_multipart(const char *buf, size_t buf_len, char *var_name,
8823 size_t var_name_len, char *file_name,
8824 size_t file_name_len, const char **data,
8825 size_t *data_len) {
8826 static const char cd[] = "Content-Disposition: ";
8827 size_t hl, bl, n, ll, pos, cdl = sizeof(cd) - 1;
8828 int shl;
8829
8830 if (buf == NULL || buf_len <= 0) return 0;
8831 if ((shl = mg_http_get_request_len(buf, buf_len)) <= 0) return 0;
8832 hl = shl;
8833 if (buf[0] != '-' || buf[1] != '-' || buf[2] == '\n') return 0;
8834
8835 /* Get boundary length */
8836 bl = mg_get_line_len(buf, buf_len);
8837
8838 /* Loop through headers, fetch variable name and file name */
8839 var_name[0] = file_name[0] = '\0';
8840 for (n = bl; (ll = mg_get_line_len(buf + n, hl - n)) > 0; n += ll) {
8841 if (mg_ncasecmp(cd, buf + n, cdl) == 0) {
8842 struct mg_str header;
8843 header.p = buf + n + cdl;
8844 header.len = ll - (cdl + 2);
8845 {
8846 char *var_name2 = var_name;
8847 mg_http_parse_header2(&header, "name", &var_name2, var_name_len);
8848 /* TODO: handle reallocated buffer correctly */
8849 if (var_name2 != var_name) {
8851 var_name[0] = '\0';
8852 }
8853 }
8854 {
8855 char *file_name2 = file_name;
8856 mg_http_parse_header2(&header, "filename", &file_name2, file_name_len);
8857 /* TODO: handle reallocated buffer correctly */
8858 if (file_name2 != file_name) {
8860 file_name[0] = '\0';
8861 }
8862 }
8863 }
8864 }
8865
8866 /* Scan through the body, search for terminating boundary */
8867 for (pos = hl; pos + (bl - 2) < buf_len; pos++) {
8868 if (buf[pos] == '-' && !strncmp(buf, &buf[pos], bl - 2)) {
8869 if (data_len != NULL) *data_len = (pos - 2) - hl;
8870 if (data != NULL) *data = buf + hl;
8871 return pos;
8872 }
8873 }
8874
8875 return 0;
8876}
8877
8879 const char *uri_path,
8880 mg_event_handler_t handler,
8881 struct mg_http_endpoint_opts opts) {
8882 struct mg_http_proto_data *pd = NULL;
8883 struct mg_http_endpoint *new_ep = NULL;
8884
8885 if (nc == NULL) return;
8886 new_ep = (struct mg_http_endpoint *) MG_CALLOC(1, sizeof(*new_ep));
8887 if (new_ep == NULL) return;
8888
8890 new_ep->uri_pattern = mg_strdup(mg_mk_str(uri_path));
8891 if (opts.auth_domain != NULL && opts.auth_file != NULL) {
8892 new_ep->auth_domain = strdup(opts.auth_domain);
8893 new_ep->auth_file = strdup(opts.auth_file);
8894 }
8895 new_ep->handler = handler;
8896#if MG_ENABLE_CALLBACK_USERDATA
8897 new_ep->user_data = opts.user_data;
8898#endif
8899 new_ep->next = pd->endpoints;
8900 pd->endpoints = new_ep;
8901}
8902
8903static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev,
8904 struct http_message *hm) {
8906 void *user_data = nc->user_data;
8907
8908 if (ev == MG_EV_HTTP_REQUEST
8911#endif
8912 ) {
8913 struct mg_http_endpoint *ep =
8915 if (ep != NULL) {
8916#if MG_ENABLE_FILESYSTEM && !MG_DISABLE_HTTP_DIGEST_AUTH
8917 if (!mg_http_is_authorized(hm, hm->uri, ep->auth_domain, ep->auth_file,
8919 mg_http_send_digest_auth_request(nc, ep->auth_domain);
8920 return;
8921 }
8922#endif
8923 pd->endpoint_handler = ep->handler;
8924#if MG_ENABLE_CALLBACK_USERDATA
8925 user_data = ep->user_data;
8926#endif
8927 }
8928 }
8929 mg_call(nc, pd->endpoint_handler ? pd->endpoint_handler : nc->handler,
8930 user_data, ev, hm);
8931}
8932
8933void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path,
8935 void *user_data)) {
8937 memset(&opts, 0, sizeof(opts));
8938#if MG_ENABLE_CALLBACK_USERDATA
8939 opts.user_data = user_data;
8940#endif
8942}
8943
8944#endif /* MG_ENABLE_HTTP */
8945#ifdef MG_MODULE_LINES
8946#line 1 "mongoose/src/mg_http_cgi.c"
8947#endif
8948/*
8949 * Copyright (c) 2014-2016 Cesanta Software Limited
8950 * All rights reserved
8951 */
8952
8953#ifndef _WIN32
8954#include <signal.h>
8955#endif
8956
8957#if MG_ENABLE_HTTP && MG_ENABLE_HTTP_CGI
8958
8959#ifndef MG_MAX_CGI_ENVIR_VARS
8960#define MG_MAX_CGI_ENVIR_VARS 64
8961#endif
8962
8963#ifndef MG_ENV_EXPORT_TO_CGI
8964#define MG_ENV_EXPORT_TO_CGI "MONGOOSE_CGI"
8965#endif
8966
8967#define MG_F_HTTP_CGI_PARSE_HEADERS MG_F_USER_1
8968
8969/*
8970 * This structure helps to create an environment for the spawned CGI program.
8971 * Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
8972 * last element must be NULL.
8973 * However, on Windows there is a requirement that all these VARIABLE=VALUE\0
8974 * strings must reside in a contiguous buffer. The end of the buffer is
8975 * marked by two '\0' characters.
8976 * We satisfy both worlds: we create an envp array (which is vars), all
8977 * entries are actually pointers inside buf.
8978 */
8979struct mg_cgi_env_block {
8980 struct mg_connection *nc;
8981 char buf[MG_CGI_ENVIRONMENT_SIZE]; /* Environment buffer */
8982 const char *vars[MG_MAX_CGI_ENVIR_VARS]; /* char *envp[] */
8983 int len; /* Space taken */
8984 int nvars; /* Number of variables in envp[] */
8985};
8986
8987#ifdef _WIN32
8988struct mg_threadparam {
8989 sock_t s;
8990 HANDLE hPipe;
8991};
8992
8993static int mg_wait_until_ready(sock_t sock, int for_read) {
8994 fd_set set;
8995 FD_ZERO(&set);
8996 FD_SET(sock, &set);
8997 return select(sock + 1, for_read ? &set : 0, for_read ? 0 : &set, 0, 0) == 1;
8998}
8999
9000static void *mg_push_to_stdin(void *arg) {
9001 struct mg_threadparam *tp = (struct mg_threadparam *) arg;
9002 int n, sent, stop = 0;
9003 DWORD k;
9004 char buf[BUFSIZ];
9005
9006 while (!stop && mg_wait_until_ready(tp->s, 1) &&
9007 (n = recv(tp->s, buf, sizeof(buf), 0)) > 0) {
9008 if (n == -1 && GetLastError() == WSAEWOULDBLOCK) continue;
9009 for (sent = 0; !stop && sent < n; sent += k) {
9010 if (!WriteFile(tp->hPipe, buf + sent, n - sent, &k, 0)) stop = 1;
9011 }
9012 }
9013 DBG(("%s", "FORWARED EVERYTHING TO CGI"));
9014 CloseHandle(tp->hPipe);
9015 MG_FREE(tp);
9016 return NULL;
9017}
9018
9019static void *mg_pull_from_stdout(void *arg) {
9020 struct mg_threadparam *tp = (struct mg_threadparam *) arg;
9021 int k = 0, stop = 0;
9022 DWORD n, sent;
9023 char buf[BUFSIZ];
9024
9025 while (!stop && ReadFile(tp->hPipe, buf, sizeof(buf), &n, NULL)) {
9026 for (sent = 0; !stop && sent < n; sent += k) {
9027 if (mg_wait_until_ready(tp->s, 0) &&
9028 (k = send(tp->s, buf + sent, n - sent, 0)) <= 0)
9029 stop = 1;
9030 }
9031 }
9032 DBG(("%s", "EOF FROM CGI"));
9033 CloseHandle(tp->hPipe);
9034 shutdown(tp->s, 2); // Without this, IO thread may get truncated data
9035 closesocket(tp->s);
9036 MG_FREE(tp);
9037 return NULL;
9038}
9039
9040static void mg_spawn_stdio_thread(sock_t sock, HANDLE hPipe,
9041 void *(*func)(void *)) {
9042 struct mg_threadparam *tp = (struct mg_threadparam *) MG_MALLOC(sizeof(*tp));
9043 if (tp != NULL) {
9044 tp->s = sock;
9045 tp->hPipe = hPipe;
9046 mg_start_thread(func, tp);
9047 }
9048}
9049
9050static void mg_abs_path(const char *utf8_path, char *abs_path, size_t len) {
9051 wchar_t buf[MG_MAX_PATH], buf2[MG_MAX_PATH];
9052 to_wchar(utf8_path, buf, ARRAY_SIZE(buf));
9054 WideCharToMultiByte(CP_UTF8, 0, buf2, wcslen(buf2) + 1, abs_path, len, 0, 0);
9055}
9056
9057static int mg_start_process(const char *interp, const char *cmd,
9058 const char *env, const char *envp[],
9059 const char *dir, sock_t sock) {
9062 HANDLE a[2], b[2], me = GetCurrentProcess();
9067 FILE *fp;
9068
9069 memset(&si, 0, sizeof(si));
9070 memset(&pi, 0, sizeof(pi));
9071
9072 si.cb = sizeof(si);
9074 si.wShowWindow = SW_HIDE;
9075 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
9076
9077 CreatePipe(&a[0], &a[1], NULL, 0);
9078 CreatePipe(&b[0], &b[1], NULL, 0);
9079 DuplicateHandle(me, a[0], me, &si.hStdInput, 0, TRUE, flags);
9080 DuplicateHandle(me, b[1], me, &si.hStdOutput, 0, TRUE, flags);
9081
9082 if (interp == NULL && (fp = mg_fopen(cmd, "r")) != NULL) {
9083 buf[0] = buf[1] = '\0';
9084 fgets(buf, sizeof(buf), fp);
9085 buf[sizeof(buf) - 1] = '\0';
9086 if (buf[0] == '#' && buf[1] == '!') {
9087 interp = buf + 2;
9088 /* Trim leading spaces: https://github.com/cesanta/mongoose/issues/489 */
9089 while (*interp != '\0' && isspace(*(unsigned char *) interp)) {
9090 interp++;
9091 }
9092 }
9093 fclose(fp);
9094 }
9095
9096 snprintf(buf, sizeof(buf), "%s/%s", dir, cmd);
9098
9101
9102 if (interp != NULL) {
9104 snprintf(cmdline, sizeof(cmdline), "%s \"%s\"", buf4, buf2);
9105 } else {
9106 snprintf(cmdline, sizeof(cmdline), "\"%s\"", buf2);
9107 }
9109
9111 (void *) env, full_dir, &si, &pi) != 0) {
9114
9115 CloseHandle(si.hStdOutput);
9116 CloseHandle(si.hStdInput);
9117
9118 CloseHandle(pi.hThread);
9119 CloseHandle(pi.hProcess);
9120 } else {
9121 CloseHandle(a[1]);
9122 CloseHandle(b[0]);
9123 closesocket(sock);
9124 }
9125 DBG(("CGI command: [%ls] -> %p", wcmd, pi.hProcess));
9126
9127 /* Not closing a[0] and b[1] because we've used DUPLICATE_CLOSE_SOURCE */
9128 (void) envp;
9129 return (pi.hProcess != NULL);
9130}
9131#else
9132static int mg_start_process(const char *interp, const char *cmd,
9133 const char *env, const char *envp[],
9134 const char *dir, sock_t sock) {
9135 char buf[500];
9136 pid_t pid = fork();
9137 (void) env;
9138
9139 if (pid == 0) {
9140 /*
9141 * In Linux `chdir` declared with `warn_unused_result` attribute
9142 * To shutup compiler we have yo use result in some way
9143 */
9144 int tmp = chdir(dir);
9145 (void) tmp;
9146 (void) dup2(sock, 0);
9147 (void) dup2(sock, 1);
9148 closesocket(sock);
9149
9150 /*
9151 * After exec, all signal handlers are restored to their default values,
9152 * with one exception of SIGCHLD. According to POSIX.1-2001 and Linux's
9153 * implementation, SIGCHLD's handler will leave unchanged after exec
9154 * if it was set to be ignored. Restore it to default action.
9155 */
9157
9158 if (interp == NULL) {
9159 execle(cmd, cmd, (char *) 0, envp); /* (char *) 0 to squash warning */
9160 } else {
9161 execle(interp, interp, cmd, (char *) 0, envp);
9162 }
9163 snprintf(buf, sizeof(buf),
9164 "Status: 500\r\n\r\n"
9165 "500 Server Error: %s%s%s: %s",
9166 interp == NULL ? "" : interp, interp == NULL ? "" : " ", cmd,
9167 strerror(errno));
9168 send(1, buf, strlen(buf), 0);
9169 _exit(EXIT_FAILURE); /* exec call failed */
9170 }
9171
9172 return (pid != 0);
9173}
9174#endif /* _WIN32 */
9175
9176/*
9177 * Append VARIABLE=VALUE\0 string to the buffer, and add a respective
9178 * pointer into the vars array.
9179 */
9180static char *mg_addenv(struct mg_cgi_env_block *block, const char *fmt, ...) {
9181 int n, space;
9182 char *added = block->buf + block->len;
9183 va_list ap;
9184
9185 /* Calculate how much space is left in the buffer */
9186 space = sizeof(block->buf) - (block->len + 2);
9187 if (space > 0) {
9188 /* Copy VARIABLE=VALUE\0 string into the free space */
9189 va_start(ap, fmt);
9190 n = vsnprintf(added, (size_t) space, fmt, ap);
9191 va_end(ap);
9192
9193 /* Make sure we do not overflow buffer and the envp array */
9194 if (n > 0 && n + 1 < space &&
9195 block->nvars < (int) ARRAY_SIZE(block->vars) - 2) {
9196 /* Append a pointer to the added string into the envp array */
9197 block->vars[block->nvars++] = added;
9198 /* Bump up used length counter. Include \0 terminator */
9199 block->len += n + 1;
9200 }
9201 }
9202
9203 return added;
9204}
9205
9206static void mg_addenv2(struct mg_cgi_env_block *blk, const char *name) {
9207 const char *s;
9208 if ((s = getenv(name)) != NULL) mg_addenv(blk, "%s=%s", name, s);
9209}
9210
9211static void mg_prepare_cgi_environment(struct mg_connection *nc,
9212 const char *prog,
9213 const struct mg_str *path_info,
9214 const struct http_message *hm,
9215 const struct mg_serve_http_opts *opts,
9216 struct mg_cgi_env_block *blk) {
9217 const char *s;
9218 struct mg_str *h;
9219 char *p;
9220 size_t i;
9221 char buf[100];
9222 size_t path_info_len = path_info != NULL ? path_info->len : 0;
9223
9224 blk->len = blk->nvars = 0;
9225 blk->nc = nc;
9226
9227 if ((s = getenv("SERVER_NAME")) != NULL) {
9228 mg_addenv(blk, "SERVER_NAME=%s", s);
9229 } else {
9230 mg_sock_to_str(nc->sock, buf, sizeof(buf), 3);
9231 mg_addenv(blk, "SERVER_NAME=%s", buf);
9232 }
9233 mg_addenv(blk, "SERVER_ROOT=%s", opts->document_root);
9234 mg_addenv(blk, "DOCUMENT_ROOT=%s", opts->document_root);
9235 mg_addenv(blk, "SERVER_SOFTWARE=%s/%s", "Mongoose", MG_VERSION);
9236
9237 /* Prepare the environment block */
9238 mg_addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
9239 mg_addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
9240 mg_addenv(blk, "%s", "REDIRECT_STATUS=200"); /* For PHP */
9241
9242 mg_addenv(blk, "REQUEST_METHOD=%.*s", (int) hm->method.len, hm->method.p);
9243
9244 mg_addenv(blk, "REQUEST_URI=%.*s%s%.*s", (int) hm->uri.len, hm->uri.p,
9245 hm->query_string.len == 0 ? "" : "?", (int) hm->query_string.len,
9246 hm->query_string.p);
9247
9248 mg_conn_addr_to_str(nc, buf, sizeof(buf),
9250 mg_addenv(blk, "REMOTE_ADDR=%s", buf);
9251 mg_conn_addr_to_str(nc, buf, sizeof(buf), MG_SOCK_STRINGIFY_PORT);
9252 mg_addenv(blk, "SERVER_PORT=%s", buf);
9253
9254 s = hm->uri.p + hm->uri.len - path_info_len - 1;
9255 if (*s == '/') {
9256 const char *base_name = strrchr(prog, DIRSEP);
9257 mg_addenv(blk, "SCRIPT_NAME=%.*s/%s", (int) (s - hm->uri.p), hm->uri.p,
9258 (base_name != NULL ? base_name + 1 : prog));
9259 } else {
9260 mg_addenv(blk, "SCRIPT_NAME=%.*s", (int) (s - hm->uri.p + 1), hm->uri.p);
9261 }
9262 mg_addenv(blk, "SCRIPT_FILENAME=%s", prog);
9263
9264 if (path_info != NULL && path_info->len > 0) {
9265 mg_addenv(blk, "PATH_INFO=%.*s", (int) path_info->len, path_info->p);
9266 /* Not really translated... */
9267 mg_addenv(blk, "PATH_TRANSLATED=%.*s", (int) path_info->len, path_info->p);
9268 }
9269
9270#if MG_ENABLE_SSL
9271 mg_addenv(blk, "HTTPS=%s", (nc->flags & MG_F_SSL ? "on" : "off"));
9272#else
9273 mg_addenv(blk, "HTTPS=off");
9274#endif
9275
9276 if ((h = mg_get_http_header((struct http_message *) hm, "Content-Type")) !=
9277 NULL) {
9278 mg_addenv(blk, "CONTENT_TYPE=%.*s", (int) h->len, h->p);
9279 }
9280
9281 if (hm->query_string.len > 0) {
9282 mg_addenv(blk, "QUERY_STRING=%.*s", (int) hm->query_string.len,
9283 hm->query_string.p);
9284 }
9285
9286 if ((h = mg_get_http_header((struct http_message *) hm, "Content-Length")) !=
9287 NULL) {
9288 mg_addenv(blk, "CONTENT_LENGTH=%.*s", (int) h->len, h->p);
9289 }
9290
9291 mg_addenv2(blk, "PATH");
9292 mg_addenv2(blk, "TMP");
9293 mg_addenv2(blk, "TEMP");
9294 mg_addenv2(blk, "TMPDIR");
9295 mg_addenv2(blk, "PERLLIB");
9297
9298#ifdef _WIN32
9299 mg_addenv2(blk, "COMSPEC");
9300 mg_addenv2(blk, "SYSTEMROOT");
9301 mg_addenv2(blk, "SystemDrive");
9302 mg_addenv2(blk, "ProgramFiles");
9303 mg_addenv2(blk, "ProgramFiles(x86)");
9304 mg_addenv2(blk, "CommonProgramFiles(x86)");
9305#else
9306 mg_addenv2(blk, "LD_LIBRARY_PATH");
9307#endif /* _WIN32 */
9308
9309 /* Add all headers as HTTP_* variables */
9310 for (i = 0; hm->header_names[i].len > 0; i++) {
9311 p = mg_addenv(blk, "HTTP_%.*s=%.*s", (int) hm->header_names[i].len,
9312 hm->header_names[i].p, (int) hm->header_values[i].len,
9313 hm->header_values[i].p);
9314
9315 /* Convert variable name into uppercase, and change - to _ */
9316 for (; *p != '=' && *p != '\0'; p++) {
9317 if (*p == '-') *p = '_';
9318 *p = (char) toupper(*(unsigned char *) p);
9319 }
9320 }
9321
9322 blk->vars[blk->nvars++] = NULL;
9323 blk->buf[blk->len++] = '\0';
9324}
9325
9326static void mg_cgi_ev_handler(struct mg_connection *cgi_nc, int ev,
9327 void *ev_data MG_UD_ARG(void *user_data)) {
9328#if !MG_ENABLE_CALLBACK_USERDATA
9329 void *user_data = cgi_nc->user_data;
9330#endif
9331 struct mg_connection *nc = (struct mg_connection *) user_data;
9332 (void) ev_data;
9333
9334 if (nc == NULL) {
9335 /* The corresponding network connection was closed. */
9336 cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY;
9337 return;
9338 }
9339
9340 switch (ev) {
9341 case MG_EV_RECV:
9342 /*
9343 * CGI script does not output reply line, like "HTTP/1.1 CODE XXXXX\n"
9344 * It outputs headers, then body. Headers might include "Status"
9345 * header, which changes CODE, and it might include "Location" header
9346 * which changes CODE to 302.
9347 *
9348 * Therefore we do not send the output from the CGI script to the user
9349 * until all CGI headers are received.
9350 *
9351 * Here we parse the output from the CGI script, and if all headers has
9352 * been received, send appropriate reply line, and forward all
9353 * received headers to the client.
9354 */
9356 struct mbuf *io = &cgi_nc->recv_mbuf;
9357 int len = mg_http_get_request_len(io->buf, io->len);
9358
9359 if (len == 0) break;
9361 cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY;
9362 mg_http_send_error(nc, 500, "Bad headers");
9363 } else {
9364 struct http_message hm;
9365 struct mg_str *h;
9366 mg_http_parse_headers(io->buf, io->buf + io->len, io->len, &hm);
9367 if (mg_get_http_header(&hm, "Location") != NULL) {
9368 mg_printf(nc, "%s", "HTTP/1.1 302 Moved\r\n");
9369 } else if ((h = mg_get_http_header(&hm, "Status")) != NULL) {
9370 mg_printf(nc, "HTTP/1.1 %.*s\r\n", (int) h->len, h->p);
9371 } else {
9372 mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\n");
9373 }
9374 }
9376 }
9377 if (!(nc->flags & MG_F_HTTP_CGI_PARSE_HEADERS)) {
9378 mg_forward(cgi_nc, nc);
9379 }
9380 break;
9381 case MG_EV_CLOSE:
9382 DBG(("%p CLOSE", cgi_nc));
9385 break;
9386 }
9387}
9388
9389MG_INTERNAL void mg_handle_cgi(struct mg_connection *nc, const char *prog,
9390 const struct mg_str *path_info,
9391 const struct http_message *hm,
9392 const struct mg_serve_http_opts *opts) {
9393 struct mg_cgi_env_block blk;
9394 char dir[MG_MAX_PATH];
9395 const char *p;
9396 sock_t fds[2];
9397
9398 DBG(("%p [%s]", nc, prog));
9399 mg_prepare_cgi_environment(nc, prog, path_info, hm, opts, &blk);
9400 /*
9401 * CGI must be executed in its own directory. 'dir' must point to the
9402 * directory containing executable program, 'p' must point to the
9403 * executable program name relative to 'dir'.
9404 */
9405 if ((p = strrchr(prog, DIRSEP)) == NULL) {
9406 snprintf(dir, sizeof(dir), "%s", ".");
9407 } else {
9408 snprintf(dir, sizeof(dir), "%.*s", (int) (p - prog), prog);
9409 prog = p + 1;
9410 }
9411
9412 if (!mg_socketpair(fds, SOCK_STREAM)) {
9414 return;
9415 }
9416
9417#ifndef _WIN32
9418 struct sigaction sa;
9419
9420 sigemptyset(&sa.sa_mask);
9421 sa.sa_handler = SIG_IGN;
9422 sa.sa_flags = 0;
9423 sigaction(SIGCHLD, &sa, NULL);
9424#endif
9425
9426 if (mg_start_process(opts->cgi_interpreter, prog, blk.buf, blk.vars, dir,
9427 fds[1]) != 0) {
9428 struct mg_connection *cgi_nc =
9431 cgi_pd->cgi.cgi_nc = cgi_nc;
9432#if !MG_ENABLE_CALLBACK_USERDATA
9433 cgi_pd->cgi.cgi_nc->user_data = nc;
9434#endif
9436 /* Push POST data to the CGI */
9437 if (hm->body.len > 0) {
9438 mg_send(cgi_pd->cgi.cgi_nc, hm->body.p, hm->body.len);
9439 }
9441 } else {
9442 closesocket(fds[0]);
9443 mg_http_send_error(nc, 500, "CGI failure");
9444 }
9445
9446#ifndef _WIN32
9447 closesocket(fds[1]); /* On Windows, CGI stdio thread closes that socket */
9448#endif
9449}
9450
9452 if (d == NULL) return;
9453 if (d->cgi_nc != NULL) {
9454 d->cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY;
9455 d->cgi_nc->user_data = NULL;
9456 }
9457 memset(d, 0, sizeof(*d));
9458}
9459
9460#endif /* MG_ENABLE_HTTP && MG_ENABLE_HTTP_CGI */
9461#ifdef MG_MODULE_LINES
9462#line 1 "mongoose/src/mg_http_ssi.c"
9463#endif
9464/*
9465 * Copyright (c) 2014-2016 Cesanta Software Limited
9466 * All rights reserved
9467 */
9468
9469#if MG_ENABLE_HTTP && MG_ENABLE_HTTP_SSI && MG_ENABLE_FILESYSTEM
9470
9471static void mg_send_ssi_file(struct mg_connection *nc, struct http_message *hm,
9472 const char *path, FILE *fp, int include_level,
9473 const struct mg_serve_http_opts *opts);
9474
9475static void mg_send_file_data(struct mg_connection *nc, FILE *fp) {
9476 char buf[BUFSIZ];
9477 size_t n;
9478 while ((n = mg_fread(buf, 1, sizeof(buf), fp)) > 0) {
9479 mg_send(nc, buf, n);
9480 }
9481}
9482
9483static void mg_do_ssi_include(struct mg_connection *nc, struct http_message *hm,
9484 const char *ssi, char *tag, int include_level,
9485 const struct mg_serve_http_opts *opts) {
9486 char file_name[MG_MAX_PATH], path[MG_MAX_PATH], *p;
9487 FILE *fp;
9488
9489 /*
9490 * sscanf() is safe here, since send_ssi_file() also uses buffer
9491 * of size MG_BUF_LEN to get the tag. So strlen(tag) is always < MG_BUF_LEN.
9492 */
9493 if (sscanf(tag, " virtual=\"%[^\"]\"", file_name) == 1) {
9494 /* File name is relative to the webserver root */
9495 snprintf(path, sizeof(path), "%s/%s", opts->document_root, file_name);
9496 } else if (sscanf(tag, " abspath=\"%[^\"]\"", file_name) == 1) {
9497 /*
9498 * File name is relative to the webserver working directory
9499 * or it is absolute system path
9500 */
9501 snprintf(path, sizeof(path), "%s", file_name);
9502 } else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1 ||
9503 sscanf(tag, " \"%[^\"]\"", file_name) == 1) {
9504 /* File name is relative to the currect document */
9505 snprintf(path, sizeof(path), "%s", ssi);
9506 if ((p = strrchr(path, DIRSEP)) != NULL) {
9507 p[1] = '\0';
9508 }
9509 snprintf(path + strlen(path), sizeof(path) - strlen(path), "%s", file_name);
9510 } else {
9511 mg_printf(nc, "Bad SSI #include: [%s]", tag);
9512 return;
9513 }
9514
9515 if ((fp = mg_fopen(path, "rb")) == NULL) {
9516 mg_printf(nc, "SSI include error: mg_fopen(%s): %s", path,
9518 } else {
9520 if (mg_match_prefix(opts->ssi_pattern, strlen(opts->ssi_pattern), path) >
9521 0) {
9522 mg_send_ssi_file(nc, hm, path, fp, include_level + 1, opts);
9523 } else {
9524 mg_send_file_data(nc, fp);
9525 }
9526 fclose(fp);
9527 }
9528}
9529
9530#if MG_ENABLE_HTTP_SSI_EXEC
9531static void do_ssi_exec(struct mg_connection *nc, char *tag) {
9532 char cmd[BUFSIZ];
9533 FILE *fp;
9534
9535 if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) {
9536 mg_printf(nc, "Bad SSI #exec: [%s]", tag);
9537 } else if ((fp = popen(cmd, "r")) == NULL) {
9538 mg_printf(nc, "Cannot SSI #exec: [%s]: %s", cmd, strerror(mg_get_errno()));
9539 } else {
9540 mg_send_file_data(nc, fp);
9541 pclose(fp);
9542 }
9543}
9544#endif /* MG_ENABLE_HTTP_SSI_EXEC */
9545
9546/*
9547 * SSI directive has the following format:
9548 * <!--#directive parameter=value parameter=value -->
9549 */
9550static void mg_send_ssi_file(struct mg_connection *nc, struct http_message *hm,
9551 const char *path, FILE *fp, int include_level,
9552 const struct mg_serve_http_opts *opts) {
9553 static const struct mg_str btag = MG_MK_STR("<!--#");
9554 static const struct mg_str d_include = MG_MK_STR("include");
9555 static const struct mg_str d_call = MG_MK_STR("call");
9556#if MG_ENABLE_HTTP_SSI_EXEC
9557 static const struct mg_str d_exec = MG_MK_STR("exec");
9558#endif
9559 char buf[BUFSIZ], *p = buf + btag.len; /* p points to SSI directive */
9560 int ch, len, in_ssi_tag;
9561
9562 if (include_level > 10) {
9563 mg_printf(nc, "SSI #include level is too deep (%s)", path);
9564 return;
9565 }
9566
9567 in_ssi_tag = len = 0;
9568 while ((ch = fgetc(fp)) != EOF) {
9569 if (in_ssi_tag && ch == '>' && buf[len - 1] == '-' && buf[len - 2] == '-') {
9570 size_t i = len - 2;
9571 in_ssi_tag = 0;
9572
9573 /* Trim closing --> */
9574 buf[i--] = '\0';
9575 while (i > 0 && buf[i] == ' ') {
9576 buf[i--] = '\0';
9577 }
9578
9579 /* Handle known SSI directives */
9580 if (strncmp(p, d_include.p, d_include.len) == 0) {
9581 mg_do_ssi_include(nc, hm, path, p + d_include.len + 1, include_level,
9582 opts);
9583 } else if (strncmp(p, d_call.p, d_call.len) == 0) {
9584 struct mg_ssi_call_ctx cctx;
9585 memset(&cctx, 0, sizeof(cctx));
9586 cctx.req = hm;
9587 cctx.file = mg_mk_str(path);
9588 cctx.arg = mg_mk_str(p + d_call.len + 1);
9590 (void *) cctx.arg.p); /* NUL added above */
9592#if MG_ENABLE_HTTP_SSI_EXEC
9593 } else if (strncmp(p, d_exec.p, d_exec.len) == 0) {
9594 do_ssi_exec(nc, p + d_exec.len + 1);
9595#endif
9596 } else {
9597 /* Silently ignore unknown SSI directive. */
9598 }
9599 len = 0;
9600 } else if (ch == '<') {
9601 in_ssi_tag = 1;
9602 if (len > 0) {
9603 mg_send(nc, buf, (size_t) len);
9604 }
9605 len = 0;
9606 buf[len++] = ch & 0xff;
9607 } else if (in_ssi_tag) {
9608 if (len == (int) btag.len && strncmp(buf, btag.p, btag.len) != 0) {
9609 /* Not an SSI tag */
9610 in_ssi_tag = 0;
9611 } else if (len == (int) sizeof(buf) - 2) {
9612 mg_printf(nc, "%s: SSI tag is too large", path);
9613 len = 0;
9614 }
9615 buf[len++] = ch & 0xff;
9616 } else {
9617 buf[len++] = ch & 0xff;
9618 if (len == (int) sizeof(buf)) {
9619 mg_send(nc, buf, (size_t) len);
9620 len = 0;
9621 }
9622 }
9623 }
9624
9625 /* Send the rest of buffered data */
9626 if (len > 0) {
9627 mg_send(nc, buf, (size_t) len);
9628 }
9629}
9630
9632 struct http_message *hm,
9633 const char *path,
9634 const struct mg_serve_http_opts *opts) {
9635 FILE *fp;
9636 struct mg_str mime_type;
9637 DBG(("%p %s", nc, path));
9638
9639 if ((fp = mg_fopen(path, "rb")) == NULL) {
9640 mg_http_send_error(nc, 404, NULL);
9641 } else {
9643
9644 mime_type = mg_get_mime_type(path, "text/plain", opts);
9645 mg_send_response_line(nc, 200, opts->extra_headers);
9646 mg_printf(nc,
9647 "Content-Type: %.*s\r\n"
9648 "Connection: close\r\n\r\n",
9649 (int) mime_type.len, mime_type.p);
9650 mg_send_ssi_file(nc, hm, path, fp, 0, opts);
9651 fclose(fp);
9653 }
9654}
9655
9656#endif /* MG_ENABLE_HTTP_SSI && MG_ENABLE_HTTP && MG_ENABLE_FILESYSTEM */
9657#ifdef MG_MODULE_LINES
9658#line 1 "mongoose/src/mg_http_webdav.c"
9659#endif
9660/*
9661 * Copyright (c) 2014-2016 Cesanta Software Limited
9662 * All rights reserved
9663 */
9664
9665#if MG_ENABLE_HTTP && MG_ENABLE_HTTP_WEBDAV
9666
9667MG_INTERNAL int mg_is_dav_request(const struct mg_str *s) {
9668 static const char *methods[] = {
9669 "PUT",
9670 "DELETE",
9671 "MKCOL",
9672 "PROPFIND",
9673 "MOVE"
9674#if MG_ENABLE_FAKE_DAVLOCK
9675 ,
9676 "LOCK",
9677 "UNLOCK"
9678#endif
9679 };
9680 size_t i;
9681
9682 for (i = 0; i < ARRAY_SIZE(methods); i++) {
9683 if (mg_vcmp(s, methods[i]) == 0) {
9684 return 1;
9685 }
9686 }
9687
9688 return 0;
9689}
9690
9691static int mg_mkdir(const char *path, uint32_t mode) {
9692#ifndef _WIN32
9693 return mkdir(path, mode);
9694#else
9695 (void) mode;
9696 return _mkdir(path);
9697#endif
9698}
9699
9700static void mg_print_props(struct mg_connection *nc, const char *name,
9701 cs_stat_t *stp) {
9702 char mtime[64];
9703 time_t t = stp->st_mtime; /* store in local variable for NDK compile */
9705 mg_gmt_time_string(mtime, sizeof(mtime), &t);
9706 mg_printf(nc,
9707 "<d:response>"
9708 "<d:href>%s</d:href>"
9709 "<d:propstat>"
9710 "<d:prop>"
9711 "<d:resourcetype>%s</d:resourcetype>"
9712 "<d:getcontentlength>%" INT64_FMT
9713 "</d:getcontentlength>"
9714 "<d:getlastmodified>%s</d:getlastmodified>"
9715 "</d:prop>"
9716 "<d:status>HTTP/1.1 200 OK</d:status>"
9717 "</d:propstat>"
9718 "</d:response>\n",
9719 name_esc.p, S_ISDIR(stp->st_mode) ? "<d:collection/>" : "",
9720 (int64_t) stp->st_size, mtime);
9721 free((void *) name_esc.p);
9722}
9723
9724MG_INTERNAL void mg_handle_propfind(struct mg_connection *nc, const char *path,
9725 cs_stat_t *stp, struct http_message *hm,
9726 struct mg_serve_http_opts *opts) {
9727 static const char header[] =
9728 "HTTP/1.1 207 Multi-Status\r\n"
9729 "Connection: close\r\n"
9730 "Content-Type: text/xml; charset=utf-8\r\n\r\n"
9731 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
9732 "<d:multistatus xmlns:d='DAV:'>\n";
9733 static const char footer[] = "</d:multistatus>\n";
9734 const struct mg_str *depth = mg_get_http_header(hm, "Depth");
9735
9736 /* Print properties for the requested resource itself */
9737 if (S_ISDIR(stp->st_mode) &&
9738 strcmp(opts->enable_directory_listing, "yes") != 0) {
9739 mg_printf(nc, "%s", "HTTP/1.1 403 Directory Listing Denied\r\n\r\n");
9740 } else {
9741 char uri[MG_MAX_PATH];
9742 mg_send(nc, header, sizeof(header) - 1);
9743 snprintf(uri, sizeof(uri), "%.*s", (int) hm->uri.len, hm->uri.p);
9744 mg_print_props(nc, uri, stp);
9745 if (S_ISDIR(stp->st_mode) && (depth == NULL || mg_vcmp(depth, "0") != 0)) {
9747 }
9748 mg_send(nc, footer, sizeof(footer) - 1);
9750 }
9751}
9752
9753#if MG_ENABLE_FAKE_DAVLOCK
9754/*
9755 * Windows explorer (probably there are another WebDav clients like it)
9756 * requires LOCK support in webdav. W/out this, it still works, but fails
9757 * to save file: shows error message and offers "Save As".
9758 * "Save as" works, but this message is very annoying.
9759 * This is fake lock, which doesn't lock something, just returns LOCK token,
9760 * UNLOCK always answers "OK".
9761 * With this fake LOCK Windows Explorer looks happy and saves file.
9762 * NOTE: that is not DAV LOCK imlementation, it is just a way to shut up
9763 * Windows native DAV client. This is why FAKE LOCK is not enabed by default
9764 */
9765MG_INTERNAL void mg_handle_lock(struct mg_connection *nc, const char *path) {
9766 static const char *reply =
9767 "HTTP/1.1 207 Multi-Status\r\n"
9768 "Connection: close\r\n"
9769 "Content-Type: text/xml; charset=utf-8\r\n\r\n"
9770 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
9771 "<d:multistatus xmlns:d='DAV:'>\n"
9772 "<D:lockdiscovery>\n"
9773 "<D:activelock>\n"
9774 "<D:locktoken>\n"
9775 "<D:href>\n"
9776 "opaquelocktoken:%s%u"
9777 "</D:href>"
9778 "</D:locktoken>"
9779 "</D:activelock>\n"
9780 "</D:lockdiscovery>"
9781 "</d:multistatus>\n";
9782 mg_printf(nc, reply, path, (unsigned int) mg_time());
9784}
9785#endif
9786
9787MG_INTERNAL void mg_handle_mkcol(struct mg_connection *nc, const char *path,
9788 struct http_message *hm) {
9789 int status_code = 500;
9790 if (hm->body.len != (size_t) ~0 && hm->body.len > 0) {
9791 status_code = 415;
9792 } else if (!mg_mkdir(path, 0755)) {
9793 status_code = 201;
9794 } else if (errno == EEXIST) {
9795 status_code = 405;
9796 } else if (errno == EACCES) {
9797 status_code = 403;
9798 } else if (errno == ENOENT) {
9799 status_code = 409;
9800 } else {
9801 status_code = 500;
9802 }
9803 mg_http_send_error(nc, status_code, NULL);
9804}
9805
9806static int mg_remove_directory(const struct mg_serve_http_opts *opts,
9807 const char *dir) {
9808 char path[MG_MAX_PATH];
9809 struct dirent *dp;
9810 cs_stat_t st;
9811 DIR *dirp;
9812
9813 if ((dirp = opendir(dir)) == NULL) return 0;
9814
9815 while ((dp = readdir(dirp)) != NULL) {
9816 if (mg_is_file_hidden((const char *) dp->d_name, opts, 1)) {
9817 continue;
9818 }
9819 snprintf(path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
9820 mg_stat(path, &st);
9821 if (S_ISDIR(st.st_mode)) {
9823 } else {
9824 remove(path);
9825 }
9826 }
9827 closedir(dirp);
9828 rmdir(dir);
9829
9830 return 1;
9831}
9832
9834 const struct mg_serve_http_opts *opts,
9835 const char *path, struct http_message *hm) {
9836 const struct mg_str *dest = mg_get_http_header(hm, "Destination");
9837 if (dest == NULL) {
9838 mg_http_send_error(c, 411, NULL);
9839 } else {
9840 const char *p = (char *) memchr(dest->p, '/', dest->len);
9841 if (p != NULL && p[1] == '/' &&
9842 (p = (char *) memchr(p + 2, '/', dest->p + dest->len - p)) != NULL) {
9843 char buf[MG_MAX_PATH];
9844 snprintf(buf, sizeof(buf), "%s%.*s", opts->dav_document_root,
9845 (int) (dest->p + dest->len - p), p);
9846 if (rename(path, buf) == 0) {
9847 mg_http_send_error(c, 200, NULL);
9848 } else {
9849 mg_http_send_error(c, 418, NULL);
9850 }
9851 } else {
9852 mg_http_send_error(c, 500, NULL);
9853 }
9854 }
9855}
9856
9858 const struct mg_serve_http_opts *opts,
9859 const char *path) {
9860 cs_stat_t st;
9861 if (mg_stat(path, &st) != 0) {
9862 mg_http_send_error(nc, 404, NULL);
9863 } else if (S_ISDIR(st.st_mode)) {
9865 mg_http_send_error(nc, 204, NULL);
9866 } else if (remove(path) == 0) {
9867 mg_http_send_error(nc, 204, NULL);
9868 } else {
9869 mg_http_send_error(nc, 423, NULL);
9870 }
9871}
9872
9873/* Return -1 on error, 1 on success. */
9874static int mg_create_itermediate_directories(const char *path) {
9875 const char *s;
9876
9877 /* Create intermediate directories if they do not exist */
9878 for (s = path + 1; *s != '\0'; s++) {
9879 if (*s == '/') {
9880 char buf[MG_MAX_PATH];
9881 cs_stat_t st;
9882 snprintf(buf, sizeof(buf), "%.*s", (int) (s - path), path);
9883 buf[sizeof(buf) - 1] = '\0';
9884 if (mg_stat(buf, &st) != 0 && mg_mkdir(buf, 0755) != 0) {
9885 return -1;
9886 }
9887 }
9888 }
9889
9890 return 1;
9891}
9892
9893MG_INTERNAL void mg_handle_put(struct mg_connection *nc, const char *path,
9894 struct http_message *hm) {
9896 cs_stat_t st;
9897 const struct mg_str *cl_hdr = mg_get_http_header(hm, "Content-Length");
9898 int rc, status_code = mg_stat(path, &st) == 0 ? 200 : 201;
9899
9901 if ((rc = mg_create_itermediate_directories(path)) == 0) {
9902 mg_printf(nc, "HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n", status_code);
9903 } else if (rc == -1) {
9904 mg_http_send_error(nc, 500, NULL);
9905 } else if (cl_hdr == NULL) {
9906 mg_http_send_error(nc, 411, NULL);
9907 } else if ((pd->file.fp = mg_fopen(path, "w+b")) == NULL) {
9908 mg_http_send_error(nc, 500, NULL);
9909 } else {
9910 const struct mg_str *range_hdr = mg_get_http_header(hm, "Content-Range");
9911 int64_t r1 = 0, r2 = 0;
9912 pd->file.type = DATA_PUT;
9913 mg_set_close_on_exec((sock_t) fileno(pd->file.fp));
9914 pd->file.cl = to64(cl_hdr->p);
9915 if (range_hdr != NULL &&
9917 status_code = 206;
9918 fseeko(pd->file.fp, r1, SEEK_SET);
9919 pd->file.cl = r2 > r1 ? r2 - r1 + 1 : pd->file.cl - r1;
9920 }
9921 mg_printf(nc, "HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n", status_code);
9922 /* Remove HTTP request from the mbuf, leave only payload */
9923 mbuf_remove(&nc->recv_mbuf, hm->message.len - hm->body.len);
9925 }
9926}
9927
9928#endif /* MG_ENABLE_HTTP && MG_ENABLE_HTTP_WEBDAV */
9929#ifdef MG_MODULE_LINES
9930#line 1 "mongoose/src/mg_http_websocket.c"
9931#endif
9932/*
9933 * Copyright (c) 2014 Cesanta Software Limited
9934 * All rights reserved
9935 */
9936
9937#if MG_ENABLE_HTTP && MG_ENABLE_HTTP_WEBSOCKET
9938
9939/* Amalgamated: #include "common/cs_sha1.h" */
9940
9941#ifndef MG_WEBSOCKET_PING_INTERVAL_SECONDS
9942#define MG_WEBSOCKET_PING_INTERVAL_SECONDS 5
9943#endif
9944
9945#define FLAGS_MASK_FIN (1 << 7)
9946#define FLAGS_MASK_OP 0x0f
9947
9948static int mg_is_ws_fragment(unsigned char flags) {
9949 return (flags & FLAGS_MASK_FIN) == 0 ||
9951}
9952
9953static int mg_is_ws_first_fragment(unsigned char flags) {
9954 return (flags & FLAGS_MASK_FIN) == 0 &&
9956}
9957
9958static int mg_is_ws_control_frame(unsigned char flags) {
9959 unsigned char op = (flags & FLAGS_MASK_OP);
9960 return op == WEBSOCKET_OP_CLOSE || op == WEBSOCKET_OP_PING ||
9962}
9963
9965 struct websocket_message *wsm) {
9966 if (wsm->flags & 0x8) {
9968 } else {
9970 }
9971}
9972
9973static struct mg_ws_proto_data *mg_ws_get_proto_data(struct mg_connection *nc) {
9975 return (htd != NULL ? &htd->ws_data : NULL);
9976}
9977
9978/*
9979 * Sends a Close websocket frame with the given data, and closes the underlying
9980 * connection. If `len` is ~0, strlen(data) is used.
9981 */
9982static void mg_ws_close(struct mg_connection *nc, const void *data,
9983 size_t len) {
9984 if ((int) len == ~0) {
9985 len = strlen((const char *) data);
9986 }
9989}
9990
9991static int mg_deliver_websocket_data(struct mg_connection *nc) {
9992 /* Using unsigned char *, cause of integer arithmetic below */
9993 uint64_t i, data_len = 0, frame_len = 0, new_data_len = nc->recv_mbuf.len,
9994 len, mask_len = 0, header_len = 0;
9996 unsigned char *new_data = (unsigned char *) nc->recv_mbuf.buf,
9997 *e = (unsigned char *) nc->recv_mbuf.buf + nc->recv_mbuf.len;
9998 uint8_t flags;
9999 int ok, reass;
10000
10001 if (wsd->reass_len > 0) {
10002 /*
10003 * We already have some previously received data which we need to
10004 * reassemble and deliver to the client code when we get the final
10005 * fragment.
10006 *
10007 * NOTE: it doesn't mean that the current message must be a continuation:
10008 * it might be a control frame (Close, Ping or Pong), which should be
10009 * handled without breaking the fragmented message.
10010 */
10011
10012 size_t existing_len = wsd->reass_len;
10013 assert(new_data_len >= existing_len);
10014
10017 }
10018
10019 flags = new_data[0];
10020
10021 reass = new_data_len > 0 && mg_is_ws_fragment(flags) &&
10023
10024 if (reass && mg_is_ws_control_frame(flags)) {
10025 /*
10026 * Control frames can't be fragmented, so if we encounter fragmented
10027 * control frame, close connection immediately.
10028 */
10029 mg_ws_close(nc, "fragmented control frames are illegal", ~0);
10030 return 0;
10031 } else if (new_data_len > 0 && !reass && !mg_is_ws_control_frame(flags) &&
10032 wsd->reass_len > 0) {
10033 /*
10034 * When in the middle of a fragmented message, only the continuations
10035 * and control frames are allowed.
10036 */
10037 mg_ws_close(nc, "non-continuation in the middle of a fragmented message",
10038 ~0);
10039 return 0;
10040 }
10041
10042 if (new_data_len >= 2) {
10043 len = new_data[1] & 0x7f;
10044 mask_len = new_data[1] & FLAGS_MASK_FIN ? 4 : 0;
10046 data_len = len;
10047 header_len = 2 + mask_len;
10048 } else if (len == 126 && new_data_len >= 4 + mask_len) {
10049 header_len = 4 + mask_len;
10050 data_len = ntohs(*(uint16_t *) &new_data[2]);
10051 } else if (new_data_len >= 10 + mask_len) {
10052 header_len = 10 + mask_len;
10053 data_len = (((uint64_t) ntohl(*(uint32_t *) &new_data[2])) << 32) +
10054 ntohl(*(uint32_t *) &new_data[6]);
10055 }
10056 }
10057
10058 frame_len = header_len + data_len;
10059 ok = (frame_len > 0 && frame_len <= new_data_len);
10060
10061 /* Check for overflow */
10062 if (frame_len < header_len || frame_len < data_len) {
10063 ok = 0;
10064 mg_ws_close(nc, "overflowed message", ~0);
10065 }
10066
10067 if (ok) {
10068 size_t cleanup_len = 0;
10069 struct websocket_message wsm;
10070
10071 wsm.size = (size_t) data_len;
10072 wsm.data = new_data + header_len;
10073 wsm.flags = flags;
10074
10075 /* Apply mask if necessary */
10076 if (mask_len > 0) {
10077 for (i = 0; i < data_len; i++) {
10079 }
10080 }
10081
10082 if (reass) {
10083 /* This is a message fragment */
10084
10086 /*
10087 * On the first fragmented frame, skip the first byte (op) and also
10088 * reset size to 1 (op), it'll be incremented with the data len below.
10089 */
10090 new_data += 1;
10091 wsd->reass_len = 1 /* op */;
10092 }
10093
10094 /* Append this frame to the reassembled buffer */
10095 memmove(new_data, wsm.data, e - wsm.data);
10096 wsd->reass_len += wsm.size;
10097 nc->recv_mbuf.len -= wsm.data - new_data;
10098
10099 if (flags & FLAGS_MASK_FIN) {
10100 /* On last fragmented frame - call user handler and remove data */
10101 wsm.flags = FLAGS_MASK_FIN | nc->recv_mbuf.buf[0];
10102 wsm.data = (unsigned char *) nc->recv_mbuf.buf + 1 /* op */;
10103 wsm.size = wsd->reass_len - 1 /* op */;
10104 cleanup_len = wsd->reass_len;
10105 wsd->reass_len = 0;
10106
10107 /* Pass reassembled message to the client code. */
10109 mbuf_remove(&nc->recv_mbuf, cleanup_len); /* Cleanup frame */
10110 }
10111 } else {
10112 /*
10113 * This is a complete message, not a fragment. It might happen in between
10114 * of a fragmented message (in this case, WebSocket protocol requires
10115 * current message to be a control frame).
10116 */
10118
10119 /* First of all, check if we need to react on a control frame. */
10120 switch (flags & FLAGS_MASK_OP) {
10121 case WEBSOCKET_OP_PING:
10123 break;
10124
10125 case WEBSOCKET_OP_CLOSE:
10126 mg_ws_close(nc, wsm.data, wsm.size);
10127 break;
10128 }
10129
10130 /* Pass received message to the client code. */
10132
10133 /* Cleanup frame */
10134 memmove(nc->recv_mbuf.buf + wsd->reass_len,
10135 nc->recv_mbuf.buf + wsd->reass_len + cleanup_len,
10136 nc->recv_mbuf.len - wsd->reass_len - cleanup_len);
10137 nc->recv_mbuf.len -= cleanup_len;
10138 }
10139 }
10140
10141 return ok;
10142}
10143
10144struct ws_mask_ctx {
10145 size_t pos; /* zero means unmasked */
10146 uint32_t mask;
10147};
10148
10149static uint32_t mg_ws_random_mask(void) {
10150 uint32_t mask;
10151/*
10152 * The spec requires WS client to generate hard to
10153 * guess mask keys. From RFC6455, Section 5.3:
10154 *
10155 * The unpredictability of the masking key is essential to prevent
10156 * authors of malicious applications from selecting the bytes that appear on
10157 * the wire.
10158 *
10159 * Hence this feature is essential when the actual end user of this API
10160 * is untrusted code that wouldn't have access to a lower level net API
10161 * anyway (e.g. web browsers). Hence this feature is low prio for most
10162 * mongoose use cases and thus can be disabled, e.g. when porting to a platform
10163 * that lacks rand().
10164 */
10165#if MG_DISABLE_WS_RANDOM_MASK
10166 mask = 0xefbeadde; /* generated with a random number generator, I swear */
10167#else
10168 if (sizeof(long) >= 4) {
10169 mask = (uint32_t) rand();
10170 } else if (sizeof(long) == 2) {
10171 mask = (uint32_t) rand() << 16 | (uint32_t) rand();
10172 }
10173#endif
10174 return mask;
10175}
10176
10177static void mg_send_ws_header(struct mg_connection *nc, int op, size_t len,
10178 struct ws_mask_ctx *ctx) {
10179 int header_len;
10180 unsigned char header[10];
10181
10182 header[0] =
10184 if (len < 126) {
10185 header[1] = (unsigned char) len;
10186 header_len = 2;
10187 } else if (len < 65535) {
10188 uint16_t tmp = htons((uint16_t) len);
10189 header[1] = 126;
10190 memcpy(&header[2], &tmp, sizeof(tmp));
10191 header_len = 4;
10192 } else {
10193 uint32_t tmp;
10194 header[1] = 127;
10195 tmp = htonl((uint32_t)((uint64_t) len >> 32));
10196 memcpy(&header[2], &tmp, sizeof(tmp));
10197 tmp = htonl((uint32_t)(len & 0xffffffff));
10198 memcpy(&header[6], &tmp, sizeof(tmp));
10199 header_len = 10;
10200 }
10201
10202 /* client connections enable masking */
10203 if (nc->listener == NULL) {
10204 header[1] |= 1 << 7; /* set masking flag */
10205 mg_send(nc, header, header_len);
10206 ctx->mask = mg_ws_random_mask();
10207 mg_send(nc, &ctx->mask, sizeof(ctx->mask));
10208 ctx->pos = nc->send_mbuf.len;
10209 } else {
10210 mg_send(nc, header, header_len);
10211 ctx->pos = 0;
10212 }
10213}
10214
10215static void mg_ws_mask_frame(struct mbuf *mbuf, struct ws_mask_ctx *ctx) {
10216 size_t i;
10217 if (ctx->pos == 0) return;
10218 for (i = 0; i < (mbuf->len - ctx->pos); i++) {
10219 mbuf->buf[ctx->pos + i] ^= ((char *) &ctx->mask)[i % 4];
10220 }
10221}
10222
10223void mg_send_websocket_frame(struct mg_connection *nc, int op, const void *data,
10224 size_t len) {
10225 struct ws_mask_ctx ctx;
10226 DBG(("%p %d %d", nc, op, (int) len));
10227 mg_send_ws_header(nc, op, len, &ctx);
10228 mg_send(nc, data, len);
10229
10230 mg_ws_mask_frame(&nc->send_mbuf, &ctx);
10231
10232 if (op == WEBSOCKET_OP_CLOSE) {
10234 }
10235}
10236
10237void mg_send_websocket_framev(struct mg_connection *nc, int op,
10238 const struct mg_str *strv, int strvcnt) {
10239 struct ws_mask_ctx ctx;
10240 int i;
10241 int len = 0;
10242 for (i = 0; i < strvcnt; i++) {
10243 len += strv[i].len;
10244 }
10245
10246 mg_send_ws_header(nc, op, len, &ctx);
10247
10248 for (i = 0; i < strvcnt; i++) {
10249 mg_send(nc, strv[i].p, strv[i].len);
10250 }
10251
10252 mg_ws_mask_frame(&nc->send_mbuf, &ctx);
10253
10254 if (op == WEBSOCKET_OP_CLOSE) {
10256 }
10257}
10258
10259void mg_printf_websocket_frame(struct mg_connection *nc, int op,
10260 const char *fmt, ...) {
10261 char mem[MG_VPRINTF_BUFFER_SIZE], *buf = mem;
10262 va_list ap;
10263 int len;
10264
10265 va_start(ap, fmt);
10266 if ((len = mg_avprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
10267 mg_send_websocket_frame(nc, op, buf, len);
10268 }
10269 va_end(ap);
10270
10271 if (buf != mem && buf != NULL) {
10272 MG_FREE(buf);
10273 }
10274}
10275
10276MG_INTERNAL void mg_ws_handler(struct mg_connection *nc, int ev,
10277 void *ev_data MG_UD_ARG(void *user_data)) {
10278 mg_call(nc, nc->handler, nc->user_data, ev, ev_data);
10279
10280 switch (ev) {
10281 case MG_EV_RECV:
10282 do {
10283 } while (mg_deliver_websocket_data(nc));
10284 break;
10285 case MG_EV_POLL:
10286 /* Ping idle websocket connections */
10287 {
10288 time_t now = *(time_t *) ev_data;
10289 if (nc->flags & MG_F_IS_WEBSOCKET &&
10292 }
10293 }
10294 break;
10295 default:
10296 break;
10297 }
10298#if MG_ENABLE_CALLBACK_USERDATA
10299 (void) user_data;
10300#endif
10301}
10302
10303#ifndef MG_EXT_SHA1
10304void mg_hash_sha1_v(size_t num_msgs, const uint8_t *msgs[],
10305 const size_t *msg_lens, uint8_t *digest) {
10306 size_t i;
10309 for (i = 0; i < num_msgs; i++) {
10311 }
10313}
10314#else
10315extern void mg_hash_sha1_v(size_t num_msgs, const uint8_t *msgs[],
10316 const size_t *msg_lens, uint8_t *digest);
10317#endif
10318
10320 const struct mg_str *key,
10321 struct http_message *hm) {
10322 static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
10323 const uint8_t *msgs[2] = {(const uint8_t *) key->p, (const uint8_t *) magic};
10324 const size_t msg_lens[2] = {key->len, 36};
10325 unsigned char sha[20];
10326 char b64_sha[30];
10327 struct mg_str *s;
10328
10330 mg_base64_encode(sha, sizeof(sha), b64_sha);
10331 mg_printf(nc, "%s",
10332 "HTTP/1.1 101 Switching Protocols\r\n"
10333 "Upgrade: websocket\r\n"
10334 "Connection: Upgrade\r\n");
10335
10336 s = mg_get_http_header(hm, "Sec-WebSocket-Protocol");
10337 if (s != NULL) {
10338 mg_printf(nc, "Sec-WebSocket-Protocol: %.*s\r\n", (int) s->len, s->p);
10339 }
10340 mg_printf(nc, "Sec-WebSocket-Accept: %s%s", b64_sha, "\r\n\r\n");
10341
10342 DBG(("%p %.*s %s", nc, (int) key->len, key->p, b64_sha));
10343}
10344
10345void mg_send_websocket_handshake2(struct mg_connection *nc, const char *path,
10346 const char *host, const char *protocol,
10347 const char *extra_headers) {
10348 mg_send_websocket_handshake3(nc, path, host, protocol, extra_headers, NULL,
10349 NULL);
10350}
10351
10352void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path,
10353 const char *host, const char *protocol,
10354 const char *extra_headers, const char *user,
10355 const char *pass) {
10357 mg_mk_str(protocol), mg_mk_str(extra_headers),
10358 mg_mk_str(user), mg_mk_str(pass));
10359}
10360
10362 const struct mg_str path,
10363 const struct mg_str host,
10364 const struct mg_str protocol,
10365 const struct mg_str extra_headers,
10366 const struct mg_str user,
10367 const struct mg_str pass) {
10368 struct mbuf auth;
10369 char key[25];
10370 uint32_t nonce[4];
10371 nonce[0] = mg_ws_random_mask();
10372 nonce[1] = mg_ws_random_mask();
10373 nonce[2] = mg_ws_random_mask();
10374 nonce[3] = mg_ws_random_mask();
10375 mg_base64_encode((unsigned char *) &nonce, sizeof(nonce), key);
10376
10377 mbuf_init(&auth, 0);
10378 if (user.len > 0) {
10380 }
10381
10382 /*
10383 * NOTE: the (auth.buf == NULL ? "" : auth.buf) is because cc3200 libc is
10384 * broken: it doesn't like zero length to be passed to %.*s
10385 * i.e. sprintf("f%.*so", (int)0, NULL), yields `f\0o`.
10386 * because it handles NULL specially (and incorrectly).
10387 */
10388 mg_printf(nc,
10389 "GET %.*s HTTP/1.1\r\n"
10390 "Upgrade: websocket\r\n"
10391 "Connection: Upgrade\r\n"
10392 "%.*s"
10393 "Sec-WebSocket-Version: 13\r\n"
10394 "Sec-WebSocket-Key: %s\r\n",
10395 (int) path.len, path.p, (int) auth.len,
10396 (auth.buf == NULL ? "" : auth.buf), key);
10397
10398 /* TODO(mkm): take default hostname from http proto data if host == NULL */
10399 if (host.len > 0) {
10400 int host_len = (int) (path.p - host.p); /* Account for possible :PORT */
10401 mg_printf(nc, "Host: %.*s\r\n", host_len, host.p);
10402 }
10403 if (protocol.len > 0) {
10404 mg_printf(nc, "Sec-WebSocket-Protocol: %.*s\r\n", (int) protocol.len,
10405 protocol.p);
10406 }
10407 if (extra_headers.len > 0) {
10408 mg_printf(nc, "%.*s", (int) extra_headers.len, extra_headers.p);
10409 }
10410 mg_printf(nc, "\r\n");
10411
10412 nc->flags |= MG_F_IS_WEBSOCKET;
10413
10414 mbuf_free(&auth);
10415}
10416
10417void mg_send_websocket_handshake(struct mg_connection *nc, const char *path,
10418 const char *extra_headers) {
10419 struct mg_str null_str = MG_NULL_STR;
10421 nc, mg_mk_str(path), null_str /* host */, null_str /* protocol */,
10422 mg_mk_str(extra_headers), null_str /* user */, null_str /* pass */);
10423}
10424
10427 struct mg_connect_opts opts, const char *url, const char *protocol,
10428 const char *extra_headers) {
10429 struct mg_str null_str = MG_NULL_STR;
10430 struct mg_str host = MG_NULL_STR, path = MG_NULL_STR, user_info = MG_NULL_STR;
10431 struct mg_connection *nc =
10433 "ws", "https", "wss", url, &path, &user_info, &host);
10434 if (nc != NULL) {
10436 mg_mk_str(extra_headers), user_info,
10437 null_str);
10438 }
10439 return nc;
10440}
10441
10444 const char *url, const char *protocol, const char *extra_headers) {
10445 struct mg_connect_opts opts;
10446 memset(&opts, 0, sizeof(opts));
10448 protocol, extra_headers);
10449}
10450#endif /* MG_ENABLE_HTTP && MG_ENABLE_HTTP_WEBSOCKET */
10451#ifdef MG_MODULE_LINES
10452#line 1 "mongoose/src/mg_util.c"
10453#endif
10454/*
10455 * Copyright (c) 2014 Cesanta Software Limited
10456 * All rights reserved
10457 */
10458
10459/* Amalgamated: #include "common/cs_base64.h" */
10460/* Amalgamated: #include "mg_internal.h" */
10461/* Amalgamated: #include "mg_util.h" */
10462
10463/* For platforms with limited libc */
10464#ifndef MAX
10465#define MAX(a, b) ((a) > (b) ? (a) : (b))
10466#endif
10467
10468const char *mg_skip(const char *s, const char *end, const char *delims,
10469 struct mg_str *v) {
10470 v->p = s;
10471 while (s < end && strchr(delims, *(unsigned char *) s) == NULL) s++;
10472 v->len = s - v->p;
10473 while (s < end && strchr(delims, *(unsigned char *) s) != NULL) s++;
10474 return s;
10475}
10476
10477#if MG_ENABLE_FILESYSTEM && !defined(MG_USER_FILE_FUNCTIONS)
10478int mg_stat(const char *path, cs_stat_t *st) {
10479#ifdef _WIN32
10480 wchar_t wpath[MG_MAX_PATH];
10481 to_wchar(path, wpath, ARRAY_SIZE(wpath));
10482 DBG(("[%ls] -> %d", wpath, _wstati64(wpath, st)));
10483 return _wstati64(wpath, st);
10484#else
10485 return stat(path, st);
10486#endif
10487}
10488
10489FILE *mg_fopen(const char *path, const char *mode) {
10490#ifdef _WIN32
10491 wchar_t wpath[MG_MAX_PATH], wmode[10];
10492 to_wchar(path, wpath, ARRAY_SIZE(wpath));
10494 return _wfopen(wpath, wmode);
10495#else
10496 return fopen(path, mode);
10497#endif
10498}
10499
10500int mg_open(const char *path, int flag, int mode) { /* LCOV_EXCL_LINE */
10501#if defined(_WIN32) && !defined(WINCE)
10502 wchar_t wpath[MG_MAX_PATH];
10503 to_wchar(path, wpath, ARRAY_SIZE(wpath));
10504 return _wopen(wpath, flag, mode);
10505#else
10506 return open(path, flag, mode); /* LCOV_EXCL_LINE */
10507#endif
10508}
10509
10510size_t mg_fread(void *ptr, size_t size, size_t count, FILE *f) {
10511 return fread(ptr, size, count, f);
10512}
10513
10514size_t mg_fwrite(const void *ptr, size_t size, size_t count, FILE *f) {
10515 return fwrite(ptr, size, count, f);
10516}
10517#endif
10518
10519void mg_base64_encode(const unsigned char *src, int src_len, char *dst) {
10520 cs_base64_encode(src, src_len, dst);
10521}
10522
10523int mg_base64_decode(const unsigned char *s, int len, char *dst) {
10524 return cs_base64_decode(s, len, dst, NULL);
10525}
10526
10527#if MG_ENABLE_THREADS
10528void *mg_start_thread(void *(*f)(void *), void *p) {
10529#ifdef WINCE
10530 return (void *) CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) f, p, 0, NULL);
10531#elif defined(_WIN32)
10532 return (void *) _beginthread((void(__cdecl *) (void *) ) f, 0, p);
10533#else
10534 pthread_t thread_id = (pthread_t) 0;
10536
10539
10540#if defined(MG_STACK_SIZE) && MG_STACK_SIZE > 1
10542#endif
10543
10544 pthread_create(&thread_id, &attr, f, p);
10546
10547 return (void *) thread_id;
10548#endif
10549}
10550#endif /* MG_ENABLE_THREADS */
10551
10552/* Set close-on-exec bit for a given socket. */
10554#if defined(_WIN32) && !defined(WINCE)
10556#elif defined(__unix__)
10557 fcntl(sock, F_SETFD, FD_CLOEXEC);
10558#else
10559 (void) sock;
10560#endif
10561}
10562
10563int mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len,
10564 int flags) {
10565 int is_v6;
10566 if (buf == NULL || len <= 0) return 0;
10567 memset(buf, 0, len);
10568#if MG_ENABLE_IPV6
10569 is_v6 = sa->sa.sa_family == AF_INET6;
10570#else
10571 is_v6 = 0;
10572#endif
10574#if MG_ENABLE_IPV6
10575 const void *addr = NULL;
10576 char *start = buf;
10577 socklen_t capacity = len;
10578 if (!is_v6) {
10579 addr = &sa->sin.sin_addr;
10580 } else {
10581 addr = (void *) &sa->sin6.sin6_addr;
10583 *buf = '[';
10584 start++;
10585 capacity--;
10586 }
10587 }
10588 if (inet_ntop(sa->sa.sa_family, addr, start, capacity) == NULL) {
10589 goto cleanup;
10590 }
10591#elif defined(_WIN32) || MG_LWIP || (MG_NET_IF == MG_NET_IF_PIC32)
10592 /* Only Windoze Vista (and newer) have inet_ntop() */
10593 char *addr_str = inet_ntoa(sa->sin.sin_addr);
10594 if (addr_str != NULL) {
10595 strncpy(buf, inet_ntoa(sa->sin.sin_addr), len - 1);
10596 } else {
10597 goto cleanup;
10598 }
10599#else
10600 if (inet_ntop(AF_INET, (void *) &sa->sin.sin_addr, buf, len) == NULL) {
10601 goto cleanup;
10602 }
10603#endif
10604 }
10606 int port = ntohs(sa->sin.sin_port);
10608 int buf_len = strlen(buf);
10609 snprintf(buf + buf_len, len - (buf_len + 1), "%s:%d", (is_v6 ? "]" : ""),
10610 port);
10611 } else {
10612 snprintf(buf, len, "%d", port);
10613 }
10614 }
10615
10616 return strlen(buf);
10617
10618cleanup:
10619 *buf = '\0';
10620 return 0;
10621}
10622
10623int mg_conn_addr_to_str(struct mg_connection *nc, char *buf, size_t len,
10624 int flags) {
10625 union socket_address sa;
10626 memset(&sa, 0, sizeof(sa));
10628 return mg_sock_addr_to_str(&sa, buf, len, flags);
10629}
10630
10631#if MG_ENABLE_HEXDUMP
10632static int mg_hexdump_n(const void *buf, int len, char *dst, int dst_len,
10633 int offset) {
10634 const unsigned char *p = (const unsigned char *) buf;
10635 char ascii[17] = "";
10636 int i, idx, n = 0;
10637
10638 for (i = 0; i < len; i++) {
10639 idx = i % 16;
10640 if (idx == 0) {
10641 if (i > 0) n += snprintf(dst + n, MAX(dst_len - n, 0), " %s\n", ascii);
10642 n += snprintf(dst + n, MAX(dst_len - n, 0), "%04x ", i + offset);
10643 }
10644 if (dst_len - n < 0) {
10645 return n;
10646 }
10647 n += snprintf(dst + n, MAX(dst_len - n, 0), " %02x", p[i]);
10648 ascii[idx] = p[i] < 0x20 || p[i] > 0x7e ? '.' : p[i];
10649 ascii[idx + 1] = '\0';
10650 }
10651
10652 while (i++ % 16) n += snprintf(dst + n, MAX(dst_len - n, 0), "%s", " ");
10653 n += snprintf(dst + n, MAX(dst_len - n, 0), " %s\n", ascii);
10654
10655 return n;
10656}
10657
10658int mg_hexdump(const void *buf, int len, char *dst, int dst_len) {
10659 return mg_hexdump_n(buf, len, dst, dst_len, 0);
10660}
10661
10662void mg_hexdumpf(FILE *fp, const void *buf, int len) {
10663 char tmp[80];
10664 int offset = 0, n;
10665 while (len > 0) {
10666 n = (len < 16 ? len : 16);
10667 mg_hexdump_n(((const char *) buf) + offset, n, tmp, sizeof(tmp), offset);
10668 fputs(tmp, fp);
10669 offset += n;
10670 len -= n;
10671 }
10672}
10673
10674void mg_hexdump_connection(struct mg_connection *nc, const char *path,
10675 const void *buf, int num_bytes, int ev) {
10676 FILE *fp = NULL;
10677 char src[60], dst[60];
10678 const char *tag = NULL;
10679 switch (ev) {
10680 case MG_EV_RECV:
10681 tag = "<-";
10682 break;
10683 case MG_EV_SEND:
10684 tag = "->";
10685 break;
10686 case MG_EV_ACCEPT:
10687 tag = "<A";
10688 break;
10689 case MG_EV_CONNECT:
10690 tag = "C>";
10691 break;
10692 case MG_EV_CLOSE:
10693 tag = "XX";
10694 break;
10695 }
10696 if (tag == NULL) return; /* Don't log MG_EV_TIMER, etc */
10697
10698 if (strcmp(path, "-") == 0) {
10699 fp = stdout;
10700 } else if (strcmp(path, "--") == 0) {
10701 fp = stderr;
10702#if MG_ENABLE_FILESYSTEM
10703 } else {
10704 fp = mg_fopen(path, "a");
10705#endif
10706 }
10707 if (fp == NULL) return;
10708
10709 mg_conn_addr_to_str(nc, src, sizeof(src),
10711 mg_conn_addr_to_str(nc, dst, sizeof(dst), MG_SOCK_STRINGIFY_IP |
10714 fprintf(fp, "%lu %p %s %s %s %d\n", (unsigned long) mg_time(), (void *) nc,
10715 src, tag, dst, (int) num_bytes);
10716 if (num_bytes > 0) {
10717 mg_hexdumpf(fp, buf, num_bytes);
10718 }
10719 if (fp != stdout && fp != stderr) fclose(fp);
10720}
10721#endif
10722
10724 static const int n = 1;
10725 /* TODO(mkm) use compiletime check with 4-byte char literal */
10726 return ((char *) &n)[0] == 0;
10727}
10728
10730#ifndef WINCE
10731 return errno;
10732#else
10733 /* TODO(alashkin): translate error codes? */
10734 return GetLastError();
10735#endif
10736}
10737
10738void mg_mbuf_append_base64_putc(char ch, void *user_data) {
10739 struct mbuf *mbuf = (struct mbuf *) user_data;
10740 mbuf_append(mbuf, &ch, sizeof(ch));
10741}
10742
10743void mg_mbuf_append_base64(struct mbuf *mbuf, const void *data, size_t len) {
10744 struct cs_base64_ctx ctx;
10746 cs_base64_update(&ctx, (const char *) data, len);
10747 cs_base64_finish(&ctx);
10748}
10749
10750void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass,
10751 struct mbuf *buf) {
10752 const char *header_prefix = "Authorization: Basic ";
10753 const char *header_suffix = "\r\n";
10754
10755 struct cs_base64_ctx ctx;
10757
10759
10760 cs_base64_update(&ctx, user.p, user.len);
10761 if (pass.len > 0) {
10762 cs_base64_update(&ctx, ":", 1);
10763 cs_base64_update(&ctx, pass.p, pass.len);
10764 }
10765 cs_base64_finish(&ctx);
10767}
10768
10771 const char *hex =
10772 (flags & MG_URL_ENCODE_F_UPPERCASE_HEX ? "0123456789ABCDEF"
10773 : "0123456789abcdef");
10774 size_t i = 0;
10775 struct mbuf mb;
10776 mbuf_init(&mb, src.len);
10777
10778 for (i = 0; i < src.len; i++) {
10779 const unsigned char c = *((const unsigned char *) src.p + i);
10780 if (isalnum(c) || mg_strchr(safe, c) != NULL) {
10781 mbuf_append(&mb, &c, 1);
10782 } else if (c == ' ' && (flags & MG_URL_ENCODE_F_SPACE_AS_PLUS)) {
10783 mbuf_append(&mb, "+", 1);
10784 } else {
10785 mbuf_append(&mb, "%", 1);
10786 mbuf_append(&mb, &hex[c >> 4], 1);
10787 mbuf_append(&mb, &hex[c & 15], 1);
10788 }
10789 }
10790 mbuf_append(&mb, "", 1);
10791 mbuf_trim(&mb);
10792 return mg_mk_str_n(mb.buf, mb.len - 1);
10793}
10794
10796 return mg_url_encode_opt(src, mg_mk_str("._-$,;~()/"), 0);
10797}
10798#ifdef MG_MODULE_LINES
10799#line 1 "mongoose/src/mg_mqtt.c"
10800#endif
10801/*
10802 * Copyright (c) 2014 Cesanta Software Limited
10803 * All rights reserved
10804 */
10805
10806#if MG_ENABLE_MQTT
10807
10808#include <string.h>
10809
10810/* Amalgamated: #include "mg_internal.h" */
10811/* Amalgamated: #include "mg_mqtt.h" */
10812
10813static uint16_t getu16(const char *p) {
10814 const uint8_t *up = (const uint8_t *) p;
10815 return (up[0] << 8) + up[1];
10816}
10817
10818static const char *scanto(const char *p, struct mg_str *s) {
10819 s->len = getu16(p);
10820 s->p = p + 2;
10821 return s->p + s->len;
10822}
10823
10824MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm) {
10825 uint8_t header;
10826 size_t len = 0, len_len = 0;
10827 const char *p, *end;
10828 unsigned char lc = 0;
10829 int cmd;
10830
10831 if (io->len < 2) return MG_MQTT_ERROR_INCOMPLETE_MSG;
10832 header = io->buf[0];
10833 cmd = header >> 4;
10834
10835 /* decode mqtt variable length */
10836 len = len_len = 0;
10837 p = io->buf + 1;
10838 while ((size_t)(p - io->buf) < io->len) {
10839 lc = *((const unsigned char *) p++);
10840 len += (lc & 0x7f) << 7 * len_len;
10841 len_len++;
10842 if (!(lc & 0x80)) break;
10843 if (len_len > 4) return MG_MQTT_ERROR_MALFORMED_MSG;
10844 }
10845
10846 end = p + len;
10847 if (lc & 0x80 || len > (io->len - (p - io->buf))) {
10849 }
10850
10851 mm->cmd = cmd;
10852 mm->qos = MG_MQTT_GET_QOS(header);
10853
10854 switch (cmd) {
10855 case MG_MQTT_CMD_CONNECT: {
10856 p = scanto(p, &mm->protocol_name);
10857 if (p > end - 4) return MG_MQTT_ERROR_MALFORMED_MSG;
10858 mm->protocol_version = *(uint8_t *) p++;
10859 mm->connect_flags = *(uint8_t *) p++;
10860 mm->keep_alive_timer = getu16(p);
10861 p += 2;
10862 if (p >= end) return MG_MQTT_ERROR_MALFORMED_MSG;
10863 p = scanto(p, &mm->client_id);
10864 if (p > end) return MG_MQTT_ERROR_MALFORMED_MSG;
10865 if (mm->connect_flags & MG_MQTT_HAS_WILL) {
10866 if (p >= end) return MG_MQTT_ERROR_MALFORMED_MSG;
10867 p = scanto(p, &mm->will_topic);
10868 }
10869 if (mm->connect_flags & MG_MQTT_HAS_WILL) {
10870 if (p >= end) return MG_MQTT_ERROR_MALFORMED_MSG;
10871 p = scanto(p, &mm->will_message);
10872 }
10873 if (mm->connect_flags & MG_MQTT_HAS_USER_NAME) {
10874 if (p >= end) return MG_MQTT_ERROR_MALFORMED_MSG;
10875 p = scanto(p, &mm->user_name);
10876 }
10877 if (mm->connect_flags & MG_MQTT_HAS_PASSWORD) {
10878 if (p >= end) return MG_MQTT_ERROR_MALFORMED_MSG;
10879 p = scanto(p, &mm->password);
10880 }
10881 if (p != end) return MG_MQTT_ERROR_MALFORMED_MSG;
10882
10883 LOG(LL_DEBUG,
10884 ("%d %2x %d proto [%.*s] client_id [%.*s] will_topic [%.*s] "
10885 "will_msg [%.*s] user_name [%.*s] password [%.*s]",
10886 (int) len, (int) mm->connect_flags, (int) mm->keep_alive_timer,
10887 (int) mm->protocol_name.len, mm->protocol_name.p,
10888 (int) mm->client_id.len, mm->client_id.p, (int) mm->will_topic.len,
10889 mm->will_topic.p, (int) mm->will_message.len, mm->will_message.p,
10890 (int) mm->user_name.len, mm->user_name.p, (int) mm->password.len,
10891 mm->password.p));
10892 break;
10893 }
10895 if (end - p < 2) return MG_MQTT_ERROR_MALFORMED_MSG;
10896 mm->connack_ret_code = p[1];
10897 break;
10898 case MG_MQTT_CMD_PUBACK:
10899 case MG_MQTT_CMD_PUBREC:
10900 case MG_MQTT_CMD_PUBREL:
10902 case MG_MQTT_CMD_SUBACK:
10903 mm->message_id = getu16(p);
10904 break;
10905 case MG_MQTT_CMD_PUBLISH: {
10906 p = scanto(p, &mm->topic);
10907 if (p > end) return MG_MQTT_ERROR_MALFORMED_MSG;
10908 if (mm->qos > 0) {
10909 if (end - p < 2) return MG_MQTT_ERROR_MALFORMED_MSG;
10910 mm->message_id = getu16(p);
10911 p += 2;
10912 }
10913 mm->payload.p = p;
10914 mm->payload.len = end - p;
10915 break;
10916 }
10918 if (end - p < 2) return MG_MQTT_ERROR_MALFORMED_MSG;
10919 mm->message_id = getu16(p);
10920 p += 2;
10921 /*
10922 * topic expressions are left in the payload and can be parsed with
10923 * `mg_mqtt_next_subscribe_topic`
10924 */
10925 mm->payload.p = p;
10926 mm->payload.len = end - p;
10927 break;
10928 default:
10929 /* Unhandled command */
10930 break;
10931 }
10932
10933 mm->len = end - io->buf;
10934 return mm->len;
10935}
10936
10937static void mqtt_handler(struct mg_connection *nc, int ev,
10938 void *ev_data MG_UD_ARG(void *user_data)) {
10939 struct mbuf *io = &nc->recv_mbuf;
10940 struct mg_mqtt_message mm;
10941 memset(&mm, 0, sizeof(mm));
10942
10943 nc->handler(nc, ev, ev_data MG_UD_ARG(user_data));
10944
10945 switch (ev) {
10946 case MG_EV_ACCEPT:
10947 if (nc->proto_data == NULL) mg_set_protocol_mqtt(nc);
10948 break;
10949 case MG_EV_RECV: {
10950 /* There can be multiple messages in the buffer, process them all. */
10951 while (1) {
10952 int len = parse_mqtt(io, &mm);
10953 if (len < 0) {
10955 /* Protocol error. */
10957 } else if (len == MG_MQTT_ERROR_INCOMPLETE_MSG) {
10958 /* Not fully buffered, let's check if we have a chance to get more
10959 * data later */
10960 if (nc->recv_mbuf_limit > 0 &&
10961 nc->recv_mbuf.len >= nc->recv_mbuf_limit) {
10962 LOG(LL_ERROR, ("%p recv buffer (%lu bytes) exceeds the limit "
10963 "%lu bytes, and not drained, closing",
10964 nc, (unsigned long) nc->recv_mbuf.len,
10965 (unsigned long) nc->recv_mbuf_limit));
10967 }
10968 } else {
10969 /* Should never be here */
10970 LOG(LL_ERROR, ("%p invalid len: %d, closing", nc, len));
10972 }
10973 break;
10974 }
10975
10976 nc->handler(nc, MG_MQTT_EVENT_BASE + mm.cmd, &mm MG_UD_ARG(user_data));
10977 mbuf_remove(io, len);
10978 }
10979 break;
10980 }
10981 case MG_EV_POLL: {
10982 struct mg_mqtt_proto_data *pd =
10983 (struct mg_mqtt_proto_data *) nc->proto_data;
10984 double now = mg_time();
10985 if (pd->keep_alive > 0 && pd->last_control_time > 0 &&
10986 (now - pd->last_control_time) > pd->keep_alive) {
10987 LOG(LL_DEBUG, ("Send PINGREQ"));
10988 mg_mqtt_ping(nc);
10989 }
10990 break;
10991 }
10992 }
10993}
10994
10995static void mg_mqtt_proto_data_destructor(void *proto_data) {
10996 MG_FREE(proto_data);
10997}
10998
10999static struct mg_str mg_mqtt_next_topic_component(struct mg_str *topic) {
11000 struct mg_str res = *topic;
11001 const char *c = mg_strchr(*topic, '/');
11002 if (c != NULL) {
11003 res.len = (c - topic->p);
11004 topic->len -= (res.len + 1);
11005 topic->p += (res.len + 1);
11006 } else {
11007 topic->len = 0;
11008 }
11009 return res;
11010}
11011
11012/* Refernce: https://mosquitto.org/man/mqtt-7.html */
11013int mg_mqtt_match_topic_expression(struct mg_str exp, struct mg_str topic) {
11014 struct mg_str ec, tc;
11015 if (exp.len == 0) return 0;
11016 while (1) {
11019 if (ec.len == 0) {
11020 if (tc.len != 0) return 0;
11021 if (exp.len == 0) break;
11022 continue;
11023 }
11024 if (mg_vcmp(&ec, "+") == 0) {
11025 if (tc.len == 0 && topic.len == 0) return 0;
11026 continue;
11027 }
11028 if (mg_vcmp(&ec, "#") == 0) {
11029 /* Must be the last component in the expression or it's invalid. */
11030 return (exp.len == 0);
11031 }
11032 if (mg_strcmp(ec, tc) != 0) {
11033 return 0;
11034 }
11035 }
11036 return (tc.len == 0 && topic.len == 0);
11037}
11038
11039int mg_mqtt_vmatch_topic_expression(const char *exp, struct mg_str topic) {
11041}
11042
11043void mg_set_protocol_mqtt(struct mg_connection *nc) {
11045 nc->proto_data = MG_CALLOC(1, sizeof(struct mg_mqtt_proto_data));
11047}
11048
11049static void mg_send_mqtt_header(struct mg_connection *nc, uint8_t cmd,
11050 uint8_t flags, size_t len) {
11051 struct mg_mqtt_proto_data *pd = (struct mg_mqtt_proto_data *) nc->proto_data;
11052 uint8_t buf[1 + sizeof(size_t)];
11053 uint8_t *vlen = &buf[1];
11054
11055 buf[0] = (cmd << 4) | flags;
11056
11057 /* mqtt variable length encoding */
11058 do {
11059 *vlen = len % 0x80;
11060 len /= 0x80;
11061 if (len > 0) *vlen |= 0x80;
11062 vlen++;
11063 } while (len > 0);
11064
11065 mg_send(nc, buf, vlen - buf);
11066 pd->last_control_time = mg_time();
11067}
11068
11069void mg_send_mqtt_handshake(struct mg_connection *nc, const char *client_id) {
11070 static struct mg_send_mqtt_handshake_opts opts;
11071 mg_send_mqtt_handshake_opt(nc, client_id, opts);
11072}
11073
11074void mg_send_mqtt_handshake_opt(struct mg_connection *nc, const char *client_id,
11076 struct mg_mqtt_proto_data *pd = (struct mg_mqtt_proto_data *) nc->proto_data;
11077 uint16_t id_len = 0, wt_len = 0, wm_len = 0, user_len = 0, pw_len = 0;
11079 size_t total_len;
11080
11081 if (client_id != NULL) {
11082 id_len = strlen(client_id);
11083 }
11084
11085 total_len = 7 + 1 + 2 + 2 + id_len;
11086
11087 if (opts.user_name != NULL) {
11088 opts.flags |= MG_MQTT_HAS_USER_NAME;
11089 }
11090 if (opts.password != NULL) {
11091 opts.flags |= MG_MQTT_HAS_PASSWORD;
11092 }
11093 if (opts.will_topic != NULL && opts.will_message != NULL) {
11094 wt_len = strlen(opts.will_topic);
11095 wm_len = strlen(opts.will_message);
11096 opts.flags |= MG_MQTT_HAS_WILL;
11097 }
11098 if (opts.keep_alive == 0) {
11099 opts.keep_alive = 60;
11100 }
11101
11102 if (opts.flags & MG_MQTT_HAS_WILL) {
11103 total_len += 2 + wt_len + 2 + wm_len;
11104 }
11105 if (opts.flags & MG_MQTT_HAS_USER_NAME) {
11106 user_len = strlen(opts.user_name);
11107 total_len += 2 + user_len;
11108 }
11109 if (opts.flags & MG_MQTT_HAS_PASSWORD) {
11110 pw_len = strlen(opts.password);
11111 total_len += 2 + pw_len;
11112 }
11113
11115 mg_send(nc, "\00\04MQTT\04", 7);
11116 mg_send(nc, &opts.flags, 1);
11117
11118 netbytes = htons(opts.keep_alive);
11119 mg_send(nc, &netbytes, 2);
11120
11122 mg_send(nc, &netbytes, 2);
11123 mg_send(nc, client_id, id_len);
11124
11125 if (opts.flags & MG_MQTT_HAS_WILL) {
11127 mg_send(nc, &netbytes, 2);
11128 mg_send(nc, opts.will_topic, wt_len);
11129
11131 mg_send(nc, &netbytes, 2);
11132 mg_send(nc, opts.will_message, wm_len);
11133 }
11134
11135 if (opts.flags & MG_MQTT_HAS_USER_NAME) {
11137 mg_send(nc, &netbytes, 2);
11138 mg_send(nc, opts.user_name, user_len);
11139 }
11140 if (opts.flags & MG_MQTT_HAS_PASSWORD) {
11142 mg_send(nc, &netbytes, 2);
11143 mg_send(nc, opts.password, pw_len);
11144 }
11145
11146 if (pd != NULL) {
11147 pd->keep_alive = opts.keep_alive;
11148 }
11149}
11150
11151void mg_mqtt_publish(struct mg_connection *nc, const char *topic,
11152 uint16_t message_id, int flags, const void *data,
11153 size_t len) {
11155 uint16_t topic_len = strlen(topic);
11156
11157 size_t total_len = 2 + topic_len + len;
11158 if (MG_MQTT_GET_QOS(flags) > 0) {
11159 total_len += 2;
11160 }
11161
11163
11165 mg_send(nc, &netbytes, 2);
11166 mg_send(nc, topic, topic_len);
11167
11168 if (MG_MQTT_GET_QOS(flags) > 0) {
11169 netbytes = htons(message_id);
11170 mg_send(nc, &netbytes, 2);
11171 }
11172
11173 mg_send(nc, data, len);
11174}
11175
11176void mg_mqtt_subscribe(struct mg_connection *nc,
11177 const struct mg_mqtt_topic_expression *topics,
11178 size_t topics_len, uint16_t message_id) {
11180 size_t i;
11182 size_t total_len = 2;
11183
11184 for (i = 0; i < topics_len; i++) {
11185 total_len += 2 + strlen(topics[i].topic) + 1;
11186 }
11187
11189
11190 netbytes = htons(message_id);
11191 mg_send(nc, (char *) &netbytes, 2);
11192
11193 for (i = 0; i < topics_len; i++) {
11194 topic_len = strlen(topics[i].topic);
11196 mg_send(nc, &netbytes, 2);
11197 mg_send(nc, topics[i].topic, topic_len);
11198 mg_send(nc, &topics[i].qos, 1);
11199 }
11200}
11201
11203 struct mg_str *topic, uint8_t *qos, int pos) {
11204 unsigned char *buf = (unsigned char *) msg->payload.p + pos;
11205 int new_pos;
11206
11207 if ((size_t) pos >= msg->payload.len) return -1;
11208
11209 topic->len = buf[0] << 8 | buf[1];
11210 topic->p = (char *) buf + 2;
11211 new_pos = pos + 2 + topic->len + 1;
11212 if ((size_t) new_pos > msg->payload.len) return -1;
11213 *qos = buf[2 + topic->len];
11214 return new_pos;
11215}
11216
11217void mg_mqtt_unsubscribe(struct mg_connection *nc, char **topics,
11218 size_t topics_len, uint16_t message_id) {
11220 size_t i;
11222 size_t total_len = 2;
11223
11224 for (i = 0; i < topics_len; i++) {
11225 total_len += 2 + strlen(topics[i]);
11226 }
11227
11229
11230 netbytes = htons(message_id);
11231 mg_send(nc, (char *) &netbytes, 2);
11232
11233 for (i = 0; i < topics_len; i++) {
11236 mg_send(nc, &netbytes, 2);
11237 mg_send(nc, topics[i], topic_len);
11238 }
11239}
11240
11242 uint8_t unused = 0;
11244 mg_send(nc, &unused, 1);
11245 mg_send(nc, &return_code, 1);
11246}
11247
11248/*
11249 * Sends a command which contains only a `message_id` and a QoS level of 1.
11250 *
11251 * Helper function.
11252 */
11253static void mg_send_mqtt_short_command(struct mg_connection *nc, uint8_t cmd,
11254 uint16_t message_id) {
11256 uint8_t flags = (cmd == MG_MQTT_CMD_PUBREL ? 2 : 0);
11257
11258 mg_send_mqtt_header(nc, cmd, flags, 2 /* len */);
11259
11260 netbytes = htons(message_id);
11261 mg_send(nc, &netbytes, 2);
11262}
11263
11264void mg_mqtt_puback(struct mg_connection *nc, uint16_t message_id) {
11266}
11267
11268void mg_mqtt_pubrec(struct mg_connection *nc, uint16_t message_id) {
11270}
11271
11272void mg_mqtt_pubrel(struct mg_connection *nc, uint16_t message_id) {
11274}
11275
11276void mg_mqtt_pubcomp(struct mg_connection *nc, uint16_t message_id) {
11278}
11279
11280void mg_mqtt_suback(struct mg_connection *nc, uint8_t *qoss, size_t qoss_len,
11281 uint16_t message_id) {
11282 size_t i;
11284
11286
11287 netbytes = htons(message_id);
11288 mg_send(nc, &netbytes, 2);
11289
11290 for (i = 0; i < qoss_len; i++) {
11291 mg_send(nc, &qoss[i], 1);
11292 }
11293}
11294
11295void mg_mqtt_unsuback(struct mg_connection *nc, uint16_t message_id) {
11297}
11298
11299void mg_mqtt_ping(struct mg_connection *nc) {
11301}
11302
11303void mg_mqtt_pong(struct mg_connection *nc) {
11305}
11306
11307void mg_mqtt_disconnect(struct mg_connection *nc) {
11309}
11310
11311#endif /* MG_ENABLE_MQTT */
11312#ifdef MG_MODULE_LINES
11313#line 1 "mongoose/src/mg_mqtt_server.c"
11314#endif
11315/*
11316 * Copyright (c) 2014 Cesanta Software Limited
11317 * All rights reserved
11318 */
11319
11320/* Amalgamated: #include "mg_internal.h" */
11321/* Amalgamated: #include "mg_mqtt_server.h" */
11322
11323#if MG_ENABLE_MQTT_BROKER
11324
11325static void mg_mqtt_session_init(struct mg_mqtt_broker *brk,
11326 struct mg_mqtt_session *s,
11327 struct mg_connection *nc) {
11328 s->brk = brk;
11329 s->subscriptions = NULL;
11330 s->num_subscriptions = 0;
11331 s->nc = nc;
11332}
11333
11334static void mg_mqtt_add_session(struct mg_mqtt_session *s) {
11335 LIST_INSERT_HEAD(&s->brk->sessions, s, link);
11336}
11337
11338static void mg_mqtt_remove_session(struct mg_mqtt_session *s) {
11339 LIST_REMOVE(s, link);
11340}
11341
11342static void mg_mqtt_destroy_session(struct mg_mqtt_session *s) {
11343 size_t i;
11344 for (i = 0; i < s->num_subscriptions; i++) {
11345 MG_FREE((void *) s->subscriptions[i].topic);
11346 }
11347 MG_FREE(s->subscriptions);
11348 MG_FREE(s);
11349}
11350
11351static void mg_mqtt_close_session(struct mg_mqtt_session *s) {
11354}
11355
11356void mg_mqtt_broker_init(struct mg_mqtt_broker *brk, void *user_data) {
11357 LIST_INIT(&brk->sessions);
11358 brk->user_data = user_data;
11359}
11360
11362 struct mg_connection *nc) {
11363 struct mg_mqtt_session *s =
11364 (struct mg_mqtt_session *) MG_CALLOC(1, sizeof *s);
11365 if (s == NULL) {
11366 /* LCOV_EXCL_START */
11368 return;
11369 /* LCOV_EXCL_STOP */
11370 }
11371
11372 /* TODO(mkm): check header (magic and version) */
11373
11374 mg_mqtt_session_init(brk, s, nc);
11375 nc->priv_2 = s;
11377
11379}
11380
11381static void mg_mqtt_broker_handle_subscribe(struct mg_connection *nc,
11382 struct mg_mqtt_message *msg) {
11383 struct mg_mqtt_session *ss = (struct mg_mqtt_session *) nc->priv_2;
11385 size_t num_subs = 0;
11386 struct mg_str topic;
11387 uint8_t qos;
11388 int pos;
11390
11391 for (pos = 0;
11392 (pos = mg_mqtt_next_subscribe_topic(msg, &topic, &qos, pos)) != -1;) {
11394 (ss->num_subscriptions + num_subs >=
11397 return;
11398 }
11399 qoss[num_subs++] = qos;
11400 }
11401
11402 if (num_subs > 0) {
11404 ss->subscriptions,
11405 sizeof(*ss->subscriptions) * (ss->num_subscriptions + num_subs));
11406 if (te == NULL) {
11408 return;
11409 }
11410 ss->subscriptions = te;
11411 for (pos = 0;
11412 pos < (int) msg->payload.len &&
11413 (pos = mg_mqtt_next_subscribe_topic(msg, &topic, &qos, pos)) != -1;
11414 ss->num_subscriptions++) {
11415 te = &ss->subscriptions[ss->num_subscriptions];
11416 te->topic = (char *) MG_MALLOC(topic.len + 1);
11417 te->qos = qos;
11418 memcpy((char *) te->topic, topic.p, topic.len);
11419 ((char *) te->topic)[topic.len] = '\0';
11420 }
11421 }
11422
11423 if (pos == (int) msg->payload.len) {
11424 mg_mqtt_suback(nc, qoss, num_subs, msg->message_id);
11425 } else {
11426 /* We did not fully parse the payload, something must be wrong. */
11428 }
11429}
11430
11432 struct mg_mqtt_message *msg) {
11433 struct mg_mqtt_session *s;
11434 size_t i;
11435
11436 for (s = mg_mqtt_next(brk, NULL); s != NULL; s = mg_mqtt_next(brk, s)) {
11437 for (i = 0; i < s->num_subscriptions; i++) {
11438 if (mg_mqtt_vmatch_topic_expression(s->subscriptions[i].topic,
11439 msg->topic)) {
11440 char buf[100], *p = buf;
11441 mg_asprintf(&p, sizeof(buf), "%.*s", (int) msg->topic.len,
11442 msg->topic.p);
11443 if (p == NULL) {
11444 return;
11445 }
11446 mg_mqtt_publish(s->nc, p, 0, 0, msg->payload.p, msg->payload.len);
11447 if (p != buf) {
11448 MG_FREE(p);
11449 }
11450 break;
11451 }
11452 }
11453 }
11454}
11455
11456void mg_mqtt_broker(struct mg_connection *nc, int ev, void *data) {
11457 struct mg_mqtt_message *msg = (struct mg_mqtt_message *) data;
11458 struct mg_mqtt_broker *brk;
11459
11460 if (nc->listener) {
11461 brk = (struct mg_mqtt_broker *) nc->listener->priv_2;
11462 } else {
11463 brk = (struct mg_mqtt_broker *) nc->priv_2;
11464 }
11465
11466 switch (ev) {
11467 case MG_EV_ACCEPT:
11468 if (nc->proto_data == NULL) mg_set_protocol_mqtt(nc);
11469 nc->priv_2 = NULL; /* Clear up the inherited pointer to broker */
11470 break;
11471 case MG_EV_MQTT_CONNECT:
11472 if (nc->priv_2 == NULL) {
11474 } else {
11475 /* Repeated CONNECT */
11477 }
11478 break;
11480 if (nc->priv_2 != NULL) {
11482 } else {
11483 /* Subscribe before CONNECT */
11485 }
11486 break;
11487 case MG_EV_MQTT_PUBLISH:
11488 if (nc->priv_2 != NULL) {
11490 } else {
11491 /* Publish before CONNECT */
11493 }
11494 break;
11495 case MG_EV_CLOSE:
11496 if (nc->listener && nc->priv_2 != NULL) {
11498 }
11499 break;
11500 }
11501}
11502
11504 struct mg_mqtt_session *s) {
11505 return s == NULL ? LIST_FIRST(&brk->sessions) : LIST_NEXT(s, link);
11506}
11507
11508#endif /* MG_ENABLE_MQTT_BROKER */
11509#ifdef MG_MODULE_LINES
11510#line 1 "mongoose/src/mg_dns.c"
11511#endif
11512/*
11513 * Copyright (c) 2014 Cesanta Software Limited
11514 * All rights reserved
11515 */
11516
11517#if MG_ENABLE_DNS
11518
11519/* Amalgamated: #include "mg_internal.h" */
11520/* Amalgamated: #include "mg_dns.h" */
11521
11522static int mg_dns_tid = 0xa0;
11523
11524struct mg_dns_header {
11531};
11532
11534 struct mg_dns_message *msg, int query,
11535 struct mg_dns_resource_record *prev) {
11536 struct mg_dns_resource_record *rr;
11537
11538 for (rr = (prev == NULL ? msg->answers : prev + 1);
11539 rr - msg->answers < msg->num_answers; rr++) {
11540 if (rr->rtype == query) {
11541 return rr;
11542 }
11543 }
11544 return NULL;
11545}
11546
11548 struct mg_dns_resource_record *rr, void *data,
11549 size_t data_len) {
11550 switch (rr->rtype) {
11551 case MG_DNS_A_RECORD:
11552 if (data_len < sizeof(struct in_addr)) {
11553 return -1;
11554 }
11555 if (rr->rdata.p + data_len > msg->pkt.p + msg->pkt.len) {
11556 return -1;
11557 }
11558 memcpy(data, rr->rdata.p, data_len);
11559 return 0;
11560#if MG_ENABLE_IPV6
11561 case MG_DNS_AAAA_RECORD:
11562 if (data_len < sizeof(struct in6_addr)) {
11563 return -1; /* LCOV_EXCL_LINE */
11564 }
11565 memcpy(data, rr->rdata.p, data_len);
11566 return 0;
11567#endif
11569 mg_dns_uncompress_name(msg, &rr->rdata, (char *) data, data_len);
11570 return 0;
11571 }
11572
11573 return -1;
11574}
11575
11576int mg_dns_insert_header(struct mbuf *io, size_t pos,
11577 struct mg_dns_message *msg) {
11578 struct mg_dns_header header;
11579
11580 memset(&header, 0, sizeof(header));
11581 header.transaction_id = msg->transaction_id;
11582 header.flags = htons(msg->flags);
11583 header.num_questions = htons(msg->num_questions);
11584 header.num_answers = htons(msg->num_answers);
11585
11586 return mbuf_insert(io, pos, &header, sizeof(header));
11587}
11588
11589int mg_dns_copy_questions(struct mbuf *io, struct mg_dns_message *msg) {
11590 unsigned char *begin, *end;
11592 if (msg->num_questions <= 0) return 0;
11593 begin = (unsigned char *) msg->pkt.p + sizeof(struct mg_dns_header);
11594 last_q = &msg->questions[msg->num_questions - 1];
11595 end = (unsigned char *) last_q->name.p + last_q->name.len + 4;
11596 return mbuf_append(io, begin, end - begin);
11597}
11598
11599int mg_dns_encode_name(struct mbuf *io, const char *name, size_t len) {
11600 const char *s;
11601 unsigned char n;
11602 size_t pos = io->len;
11603
11604 do {
11605 if ((s = strchr(name, '.')) == NULL) {
11606 s = name + len;
11607 }
11608
11609 if (s - name > 127) {
11610 return -1; /* TODO(mkm) cover */
11611 }
11612 n = s - name; /* chunk length */
11613 mbuf_append(io, &n, 1); /* send length */
11614 mbuf_append(io, name, n);
11615
11616 if (*s == '.') {
11617 n++;
11618 }
11619
11620 name += n;
11621 len -= n;
11622 } while (*s != '\0');
11623 mbuf_append(io, "\0", 1); /* Mark end of host name */
11624
11625 return io->len - pos;
11626}
11627
11629 const char *name, size_t nlen, const void *rdata,
11630 size_t rlen) {
11631 size_t pos = io->len;
11632 uint16_t u16;
11633 uint32_t u32;
11634
11635 if (rr->kind == MG_DNS_INVALID_RECORD) {
11636 return -1; /* LCOV_EXCL_LINE */
11637 }
11638
11639 if (mg_dns_encode_name(io, name, nlen) == -1) {
11640 return -1;
11641 }
11642
11643 u16 = htons(rr->rtype);
11644 mbuf_append(io, &u16, 2);
11645 u16 = htons(rr->rclass);
11646 mbuf_append(io, &u16, 2);
11647
11648 if (rr->kind == MG_DNS_ANSWER) {
11649 u32 = htonl(rr->ttl);
11650 mbuf_append(io, &u32, 4);
11651
11652 if (rr->rtype == MG_DNS_CNAME_RECORD) {
11653 int clen;
11654 /* fill size after encoding */
11655 size_t off = io->len;
11656 mbuf_append(io, &u16, 2);
11657 if ((clen = mg_dns_encode_name(io, (const char *) rdata, rlen)) == -1) {
11658 return -1;
11659 }
11660 u16 = clen;
11661 io->buf[off] = u16 >> 8;
11662 io->buf[off + 1] = u16 & 0xff;
11663 } else {
11664 u16 = htons((uint16_t) rlen);
11665 mbuf_append(io, &u16, 2);
11667 }
11668 }
11669
11670 return io->len - pos;
11671}
11672
11673void mg_send_dns_query(struct mg_connection *nc, const char *name,
11674 int query_type) {
11675 struct mg_dns_message *msg =
11676 (struct mg_dns_message *) MG_CALLOC(1, sizeof(*msg));
11677 struct mbuf pkt;
11678 struct mg_dns_resource_record *rr = &msg->questions[0];
11679
11680 DBG(("%s %d", name, query_type));
11681
11682 mbuf_init(&pkt, 64 /* Start small, it'll grow as needed. */);
11683
11684 msg->transaction_id = ++mg_dns_tid;
11685 msg->flags = 0x100;
11686 msg->num_questions = 1;
11687
11688 mg_dns_insert_header(&pkt, 0, msg);
11689
11690 rr->rtype = query_type;
11691 rr->rclass = 1; /* Class: inet */
11692 rr->kind = MG_DNS_QUESTION;
11693
11694 if (mg_dns_encode_record(&pkt, rr, name, strlen(name), NULL, 0) == -1) {
11695 /* TODO(mkm): return an error code */
11696 goto cleanup; /* LCOV_EXCL_LINE */
11697 }
11698
11699 /* TCP DNS requires messages to be prefixed with len */
11700 if (!(nc->flags & MG_F_UDP)) {
11701 uint16_t len = htons((uint16_t) pkt.len);
11702 mbuf_insert(&pkt, 0, &len, 2);
11703 }
11704
11705 mg_send(nc, pkt.buf, pkt.len);
11706 mbuf_free(&pkt);
11707
11708cleanup:
11709 MG_FREE(msg);
11710}
11711
11712static unsigned char *mg_parse_dns_resource_record(
11713 unsigned char *data, unsigned char *end, struct mg_dns_resource_record *rr,
11714 int reply) {
11715 unsigned char *name = data;
11716 int chunk_len, data_len;
11717
11718 while (data < end && (chunk_len = *data)) {
11719 if (((unsigned char *) data)[0] & 0xc0) {
11720 data += 1;
11721 break;
11722 }
11723 data += chunk_len + 1;
11724 }
11725
11726 if (data > end - 5) {
11727 return NULL;
11728 }
11729
11730 rr->name.p = (char *) name;
11731 rr->name.len = data - name + 1;
11732 data++;
11733
11734 rr->rtype = data[0] << 8 | data[1];
11735 data += 2;
11736
11737 rr->rclass = data[0] << 8 | data[1];
11738 data += 2;
11739
11741 if (reply) {
11742 if (data >= end - 6) {
11743 return NULL;
11744 }
11745
11746 rr->ttl = (uint32_t) data[0] << 24 | (uint32_t) data[1] << 16 |
11747 data[2] << 8 | data[3];
11748 data += 4;
11749
11750 data_len = *data << 8 | *(data + 1);
11751 data += 2;
11752
11753 rr->rdata.p = (char *) data;
11754 rr->rdata.len = data_len;
11755 data += data_len;
11756 }
11757 return data;
11758}
11759
11760int mg_parse_dns(const char *buf, int len, struct mg_dns_message *msg) {
11761 struct mg_dns_header *header = (struct mg_dns_header *) buf;
11762 unsigned char *data = (unsigned char *) buf + sizeof(*header);
11763 unsigned char *end = (unsigned char *) buf + len;
11764 int i;
11765
11766 memset(msg, 0, sizeof(*msg));
11767 msg->pkt.p = buf;
11768 msg->pkt.len = len;
11769
11770 if (len < (int) sizeof(*header)) return -1;
11771
11772 msg->transaction_id = header->transaction_id;
11773 msg->flags = ntohs(header->flags);
11774 msg->num_questions = ntohs(header->num_questions);
11775 if (msg->num_questions > (int) ARRAY_SIZE(msg->questions)) {
11776 msg->num_questions = (int) ARRAY_SIZE(msg->questions);
11777 }
11778 msg->num_answers = ntohs(header->num_answers);
11779 if (msg->num_answers > (int) ARRAY_SIZE(msg->answers)) {
11780 msg->num_answers = (int) ARRAY_SIZE(msg->answers);
11781 }
11782
11783 for (i = 0; i < msg->num_questions; i++) {
11785 if (data == NULL) return -1;
11786 }
11787
11788 for (i = 0; i < msg->num_answers; i++) {
11790 if (data == NULL) return -1;
11791 }
11792
11793 return 0;
11794}
11795
11796size_t mg_dns_uncompress_name(struct mg_dns_message *msg, struct mg_str *name,
11797 char *dst, int dst_len) {
11798 int chunk_len, num_ptrs = 0;
11799 char *old_dst = dst;
11800 const unsigned char *data = (unsigned char *) name->p;
11801 const unsigned char *end = (unsigned char *) msg->pkt.p + msg->pkt.len;
11802
11803 if (data >= end) {
11804 return 0;
11805 }
11806
11807 while ((chunk_len = *data++)) {
11808 int leeway = dst_len - (dst - old_dst);
11809 if (data >= end) {
11810 return 0;
11811 }
11812
11813 if ((chunk_len & 0xc0) == 0xc0) {
11814 uint16_t off = (data[-1] & (~0xc0)) << 8 | data[0];
11815 if (off >= msg->pkt.len) {
11816 return 0;
11817 }
11818 /* Basic circular loop avoidance: allow up to 16 pointer hops. */
11819 if (++num_ptrs > 15) {
11820 return 0;
11821 }
11822 data = (unsigned char *) msg->pkt.p + off;
11823 continue;
11824 }
11825 if (chunk_len > 63) {
11826 return 0;
11827 }
11828 if (chunk_len > leeway) {
11829 chunk_len = leeway;
11830 }
11831
11832 if (data + chunk_len >= end) {
11833 return 0;
11834 }
11835
11836 memcpy(dst, data, chunk_len);
11837 data += chunk_len;
11838 dst += chunk_len;
11839 leeway -= chunk_len;
11840 if (leeway == 0) {
11841 return dst - old_dst;
11842 }
11843 *dst++ = '.';
11844 }
11845
11846 if (dst != old_dst) {
11847 *--dst = 0;
11848 }
11849 return dst - old_dst;
11850}
11851
11852static void dns_handler(struct mg_connection *nc, int ev,
11853 void *ev_data MG_UD_ARG(void *user_data)) {
11854 struct mbuf *io = &nc->recv_mbuf;
11855 struct mg_dns_message msg;
11856
11857 /* Pass low-level events to the user handler */
11858 nc->handler(nc, ev, ev_data MG_UD_ARG(user_data));
11859
11860 switch (ev) {
11861 case MG_EV_RECV:
11862 if (!(nc->flags & MG_F_UDP)) {
11863 mbuf_remove(&nc->recv_mbuf, 2);
11864 }
11865 if (mg_parse_dns(nc->recv_mbuf.buf, nc->recv_mbuf.len, &msg) == -1) {
11866 /* reply + recursion allowed + format error */
11867 memset(&msg, 0, sizeof(msg));
11868 msg.flags = 0x8081;
11869 mg_dns_insert_header(io, 0, &msg);
11870 if (!(nc->flags & MG_F_UDP)) {
11871 uint16_t len = htons((uint16_t) io->len);
11872 mbuf_insert(io, 0, &len, 2);
11873 }
11874 mg_send(nc, io->buf, io->len);
11875 } else {
11876 /* Call user handler with parsed message */
11877 nc->handler(nc, MG_DNS_MESSAGE, &msg MG_UD_ARG(user_data));
11878 }
11879 mbuf_remove(io, io->len);
11880 break;
11881 }
11882}
11883
11884void mg_set_protocol_dns(struct mg_connection *nc) {
11886}
11887
11888#endif /* MG_ENABLE_DNS */
11889#ifdef MG_MODULE_LINES
11890#line 1 "mongoose/src/mg_dns_server.c"
11891#endif
11892/*
11893 * Copyright (c) 2014 Cesanta Software Limited
11894 * All rights reserved
11895 */
11896
11897#if MG_ENABLE_DNS_SERVER
11898
11899/* Amalgamated: #include "mg_internal.h" */
11900/* Amalgamated: #include "dns-server.h" */
11901
11903 struct mg_dns_message *msg) {
11904 struct mg_dns_reply rep;
11905 rep.msg = msg;
11906 rep.io = io;
11907 rep.start = io->len;
11908
11909 /* reply + recursion allowed */
11910 msg->flags |= 0x8080;
11912
11913 msg->num_answers = 0;
11914 return rep;
11915}
11916
11917void mg_dns_send_reply(struct mg_connection *nc, struct mg_dns_reply *r) {
11918 size_t sent = r->io->len - r->start;
11919 mg_dns_insert_header(r->io, r->start, r->msg);
11920 if (!(nc->flags & MG_F_UDP)) {
11921 uint16_t len = htons((uint16_t) sent);
11922 mbuf_insert(r->io, r->start, &len, 2);
11923 }
11924
11925 if (&nc->send_mbuf != r->io) {
11926 mg_send(nc, r->io->buf + r->start, r->io->len - r->start);
11927 r->io->len = r->start;
11928 }
11929}
11930
11933 const char *name, int rtype, int ttl, const void *rdata,
11934 size_t rdata_len) {
11935 struct mg_dns_message *msg = (struct mg_dns_message *) reply->msg;
11936 char rname[512];
11937 struct mg_dns_resource_record *ans = &msg->answers[msg->num_answers];
11938 if (msg->num_answers >= MG_MAX_DNS_ANSWERS) {
11939 return -1; /* LCOV_EXCL_LINE */
11940 }
11941
11942 if (name == NULL) {
11943 name = rname;
11944 rname[511] = 0;
11945 mg_dns_uncompress_name(msg, &question->name, rname, sizeof(rname) - 1);
11946 }
11947
11948 *ans = *question;
11949 ans->kind = MG_DNS_ANSWER;
11950 ans->rtype = rtype;
11951 ans->ttl = ttl;
11952
11954 rdata_len) == -1) {
11955 return -1; /* LCOV_EXCL_LINE */
11956 };
11957
11958 msg->num_answers++;
11959 return 0;
11960}
11961
11962#endif /* MG_ENABLE_DNS_SERVER */
11963#ifdef MG_MODULE_LINES
11964#line 1 "mongoose/src/mg_resolv.c"
11965#endif
11966/*
11967 * Copyright (c) 2014 Cesanta Software Limited
11968 * All rights reserved
11969 */
11970
11971#if MG_ENABLE_ASYNC_RESOLVER
11972
11973/* Amalgamated: #include "mg_internal.h" */
11974/* Amalgamated: #include "mg_resolv.h" */
11975
11976#ifndef MG_DEFAULT_NAMESERVER
11977#define MG_DEFAULT_NAMESERVER "8.8.8.8"
11978#endif
11979
11981 char name[1024];
11982 int query;
11984 void *data;
11986 int max_retries;
11987 enum mg_resolve_err err;
11988
11989 /* state */
11991 int retries;
11992};
11993
11994/*
11995 * Find what nameserver to use.
11996 *
11997 * Return 0 if OK, -1 if error
11998 */
11999static int mg_get_ip_address_of_nameserver(char *name, size_t name_len) {
12000 int ret = -1;
12001
12002#ifdef _WIN32
12003 int i;
12004 LONG err;
12005 HKEY hKey, hSub;
12006 wchar_t subkey[512], value[128],
12007 *key = L"SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters\\Interfaces";
12008
12009 if ((err = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hKey)) !=
12010 ERROR_SUCCESS) {
12011 fprintf(stderr, "cannot open reg key %S: %ld\n", key, err);
12012 ret = -1;
12013 } else {
12014 for (ret = -1, i = 0; 1; i++) {
12015 DWORD subkey_size = sizeof(subkey), type, len = sizeof(value);
12017 NULL) != ERROR_SUCCESS) {
12018 break;
12019 }
12021 ((RegQueryValueExW(hSub, L"NameServer", 0, &type, (void *) value,
12022 &len) == ERROR_SUCCESS &&
12023 value[0] != '\0') ||
12024 (RegQueryValueExW(hSub, L"DhcpNameServer", 0, &type, (void *) value,
12025 &len) == ERROR_SUCCESS &&
12026 value[0] != '\0'))) {
12027 /*
12028 * See https://github.com/cesanta/mongoose/issues/176
12029 * The value taken from the registry can be empty, a single
12030 * IP address, or multiple IP addresses separated by comma.
12031 * If it's empty, check the next interface.
12032 * If it's multiple IP addresses, take the first one.
12033 */
12034 wchar_t *comma = wcschr(value, ',');
12035 if (comma != NULL) {
12036 *comma = '\0';
12037 }
12038 /* %S will convert wchar_t -> char */
12039 snprintf(name, name_len, "%S", value);
12040 ret = 0;
12042 break;
12043 }
12044 }
12046 }
12047#elif MG_ENABLE_FILESYSTEM && defined(MG_RESOLV_CONF_FILE_NAME)
12048 FILE *fp;
12049 char line[512];
12050
12051 if ((fp = mg_fopen(MG_RESOLV_CONF_FILE_NAME, "r")) == NULL) {
12052 ret = -1;
12053 } else {
12054 /* Try to figure out what nameserver to use */
12055 for (ret = -1; fgets(line, sizeof(line), fp) != NULL;) {
12056 unsigned int a, b, c, d;
12057 if (sscanf(line, "nameserver %u.%u.%u.%u", &a, &b, &c, &d) == 4) {
12058 snprintf(name, name_len, "%u.%u.%u.%u", a, b, c, d);
12059 ret = 0;
12060 break;
12061 }
12062 }
12063 (void) fclose(fp);
12064 }
12065#else
12066 snprintf(name, name_len, "%s", MG_DEFAULT_NAMESERVER);
12067#endif /* _WIN32 */
12068
12069 return ret;
12070}
12071
12072int mg_resolve_from_hosts_file(const char *name, union socket_address *usa) {
12073#if MG_ENABLE_FILESYSTEM && defined(MG_HOSTS_FILE_NAME)
12074 /* TODO(mkm) cache /etc/hosts */
12075 FILE *fp;
12076 char line[1024];
12077 char *p;
12078 char alias[256];
12079 unsigned int a, b, c, d;
12080 int len = 0;
12081
12082 if ((fp = mg_fopen(MG_HOSTS_FILE_NAME, "r")) == NULL) {
12083 return -1;
12084 }
12085
12086 for (; fgets(line, sizeof(line), fp) != NULL;) {
12087 if (line[0] == '#') continue;
12088
12089 if (sscanf(line, "%u.%u.%u.%u%n", &a, &b, &c, &d, &len) == 0) {
12090 /* TODO(mkm): handle ipv6 */
12091 continue;
12092 }
12093 for (p = line + len; sscanf(p, "%s%n", alias, &len) == 1; p += len) {
12094 if (strcmp(alias, name) == 0) {
12095 usa->sin.sin_addr.s_addr = htonl(a << 24 | b << 16 | c << 8 | d);
12096 fclose(fp);
12097 return 0;
12098 }
12099 }
12100 }
12101
12102 fclose(fp);
12103#else
12104 (void) name;
12105 (void) usa;
12106#endif
12107
12108 return -1;
12109}
12110
12111static void mg_resolve_async_eh(struct mg_connection *nc, int ev,
12112 void *data MG_UD_ARG(void *user_data)) {
12113 time_t now = (time_t) mg_time();
12114 struct mg_resolve_async_request *req;
12115 struct mg_dns_message *msg;
12116#if !MG_ENABLE_CALLBACK_USERDATA
12117 void *user_data = nc->user_data;
12118#endif
12119
12120 if (ev != MG_EV_POLL) {
12121 DBG(("ev=%d user_data=%p", ev, user_data));
12122 }
12123
12124 req = (struct mg_resolve_async_request *) user_data;
12125
12126 if (req == NULL) {
12127 return;
12128 }
12129
12130 switch (ev) {
12131 case MG_EV_POLL:
12132 if (req->retries > req->max_retries) {
12135 break;
12136 }
12137 if (nc->flags & MG_F_CONNECTING) break;
12138 /* fallthrough */
12139 case MG_EV_CONNECT:
12140 if (req->retries == 0 || now - req->last_time >= req->timeout) {
12141 mg_send_dns_query(nc, req->name, req->query);
12142 req->last_time = now;
12143 req->retries++;
12144 }
12145 break;
12146 case MG_EV_RECV:
12147 msg = (struct mg_dns_message *) MG_MALLOC(sizeof(*msg));
12148 if (mg_parse_dns(nc->recv_mbuf.buf, *(int *) data, msg) == 0 &&
12149 msg->num_answers > 0) {
12150 req->callback(msg, req->data, MG_RESOLVE_OK);
12151 nc->user_data = NULL;
12152 MG_FREE(req);
12153 } else {
12155 }
12156 MG_FREE(msg);
12158 break;
12159 case MG_EV_SEND:
12160 /*
12161 * If a send error occurs, prevent closing of the connection by the core.
12162 * We will retry after timeout.
12163 */
12166 break;
12167 case MG_EV_TIMER:
12168 req->err = MG_RESOLVE_TIMEOUT;
12170 break;
12171 case MG_EV_CLOSE:
12172 /* If we got here with request still not done, fire an error callback. */
12173 if (req != NULL) {
12174 char addr[32];
12176#ifdef MG_LOG_DNS_FAILURES
12177 LOG(LL_ERROR, ("Failed to resolve '%s', server %s", req->name, addr));
12178#endif
12179 req->callback(NULL, req->data, req->err);
12180 nc->user_data = NULL;
12181 MG_FREE(req);
12182 }
12183 break;
12184 }
12185}
12186
12187int mg_resolve_async(struct mg_mgr *mgr, const char *name, int query,
12188 mg_resolve_callback_t cb, void *data) {
12190 memset(&opts, 0, sizeof(opts));
12191 return mg_resolve_async_opt(mgr, name, query, cb, data, opts);
12192}
12193
12194int mg_resolve_async_opt(struct mg_mgr *mgr, const char *name, int query,
12195 mg_resolve_callback_t cb, void *data,
12196 struct mg_resolve_async_opts opts) {
12197 struct mg_resolve_async_request *req;
12198 struct mg_connection *dns_nc;
12199 const char *nameserver = opts.nameserver;
12200 char dns_server_buff[17], nameserver_url[26];
12201
12202 if (nameserver == NULL) {
12203 nameserver = mgr->nameserver;
12204 }
12205
12206 DBG(("%s %d %p", name, query, opts.dns_conn));
12207
12208 /* resolve with DNS */
12209 req = (struct mg_resolve_async_request *) MG_CALLOC(1, sizeof(*req));
12210 if (req == NULL) {
12211 return -1;
12212 }
12213
12214 strncpy(req->name, name, sizeof(req->name));
12215 req->name[sizeof(req->name) - 1] = '\0';
12216
12217 req->query = query;
12218 req->callback = cb;
12219 req->data = data;
12220 /* TODO(mkm): parse defaults out of resolve.conf */
12221 req->max_retries = opts.max_retries ? opts.max_retries : 2;
12222 req->timeout = opts.timeout ? opts.timeout : 5;
12223
12224 /* Lazily initialize dns server */
12225 if (nameserver == NULL) {
12227 sizeof(dns_server_buff)) != -1) {
12228 nameserver = dns_server_buff;
12229 } else {
12230 nameserver = MG_DEFAULT_NAMESERVER;
12231 }
12232 }
12233
12234 snprintf(nameserver_url, sizeof(nameserver_url), "udp://%s:53", nameserver);
12235
12236 dns_nc = mg_connect(mgr, nameserver_url, MG_CB(mg_resolve_async_eh, NULL));
12237 if (dns_nc == NULL) {
12238 MG_FREE(req);
12239 return -1;
12240 }
12241 dns_nc->user_data = req;
12242 if (opts.dns_conn != NULL) {
12243 *opts.dns_conn = dns_nc;
12244 }
12245
12246 return 0;
12247}
12248
12249void mg_set_nameserver(struct mg_mgr *mgr, const char *nameserver) {
12250 MG_FREE((char *) mgr->nameserver);
12251 mgr->nameserver = NULL;
12252 if (nameserver != NULL) {
12253 mgr->nameserver = strdup(nameserver);
12254 }
12255}
12256
12257#endif /* MG_ENABLE_ASYNC_RESOLVER */
12258#ifdef MG_MODULE_LINES
12259#line 1 "mongoose/src/mg_coap.c"
12260#endif
12261/*
12262 * Copyright (c) 2015 Cesanta Software Limited
12263 * All rights reserved
12264 * This software is dual-licensed: you can redistribute it and/or modify
12265 * it under the terms of the GNU General Public License version 2 as
12266 * published by the Free Software Foundation. For the terms of this
12267 * license, see <http://www.gnu.org/licenses/>.
12268 *
12269 * You are free to use this software under the terms of the GNU General
12270 * Public License, but WITHOUT ANY WARRANTY; without even the implied
12271 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12272 * See the GNU General Public License for more details.
12273 *
12274 * Alternatively, you can license this software under a commercial
12275 * license, as set out in <https://www.cesanta.com/license>.
12276 */
12277
12278/* Amalgamated: #include "mg_internal.h" */
12279/* Amalgamated: #include "mg_coap.h" */
12280
12281#if MG_ENABLE_COAP
12282
12284 while (cm->options != NULL) {
12285 struct mg_coap_option *next = cm->options->next;
12286 MG_FREE(cm->options);
12287 cm->options = next;
12288 }
12289}
12290
12292 uint32_t number, char *value,
12293 size_t len) {
12294 struct mg_coap_option *new_option =
12295 (struct mg_coap_option *) MG_CALLOC(1, sizeof(*new_option));
12296
12297 new_option->number = number;
12298 new_option->value.p = value;
12299 new_option->value.len = len;
12300
12301 if (cm->options == NULL) {
12302 cm->options = cm->optiomg_tail = new_option;
12303 } else {
12304 /*
12305 * A very simple attention to help clients to compose options:
12306 * CoAP wants to see options ASC ordered.
12307 * Could be change by using sort in coap_compose
12308 */
12309 if (cm->optiomg_tail->number <= new_option->number) {
12310 /* if option is already ordered just add it */
12311 cm->optiomg_tail = cm->optiomg_tail->next = new_option;
12312 } else {
12313 /* looking for appropriate position */
12314 struct mg_coap_option *current_opt = cm->options;
12315 struct mg_coap_option *prev_opt = 0;
12316
12317 while (current_opt != NULL) {
12318 if (current_opt->number > new_option->number) {
12319 break;
12320 }
12322 current_opt = current_opt->next;
12323 }
12324
12325 if (prev_opt != NULL) {
12326 prev_opt->next = new_option;
12327 new_option->next = current_opt;
12328 } else {
12329 /* insert new_option to the beginning */
12330 new_option->next = cm->options;
12331 cm->options = new_option;
12332 }
12333 }
12334 }
12335
12336 return new_option;
12337}
12338
12339/*
12340 * Fills CoAP header in mg_coap_message.
12341 *
12342 * Helper function.
12343 */
12344static char *coap_parse_header(char *ptr, struct mbuf *io,
12345 struct mg_coap_message *cm) {
12346 if (io->len < sizeof(uint32_t)) {
12347 cm->flags |= MG_COAP_NOT_ENOUGH_DATA;
12348 return NULL;
12349 }
12350
12351 /*
12352 * Version (Ver): 2-bit unsigned integer. Indicates the CoAP version
12353 * number. Implementations of this specification MUST set this field
12354 * to 1 (01 binary). Other values are reserved for future versions.
12355 * Messages with unknown version numbers MUST be silently ignored.
12356 */
12357 if (((uint8_t) *ptr >> 6) != 1) {
12358 cm->flags |= MG_COAP_IGNORE;
12359 return NULL;
12360 }
12361
12362 /*
12363 * Type (T): 2-bit unsigned integer. Indicates if this message is of
12364 * type Confirmable (0), Non-confirmable (1), Acknowledgement (2), or
12365 * Reset (3).
12366 */
12367 cm->msg_type = ((uint8_t) *ptr & 0x30) >> 4;
12368 cm->flags |= MG_COAP_MSG_TYPE_FIELD;
12369
12370 /*
12371 * Token Length (TKL): 4-bit unsigned integer. Indicates the length of
12372 * the variable-length Token field (0-8 bytes). Lengths 9-15 are
12373 * reserved, MUST NOT be sent, and MUST be processed as a message
12374 * format error.
12375 */
12376 cm->token.len = *ptr & 0x0F;
12377 if (cm->token.len > 8) {
12378 cm->flags |= MG_COAP_FORMAT_ERROR;
12379 return NULL;
12380 }
12381
12382 ptr++;
12383
12384 /*
12385 * Code: 8-bit unsigned integer, split into a 3-bit class (most
12386 * significant bits) and a 5-bit detail (least significant bits)
12387 */
12388 cm->code_class = (uint8_t) *ptr >> 5;
12389 cm->code_detail = *ptr & 0x1F;
12391
12392 ptr++;
12393
12394 /* Message ID: 16-bit unsigned integer in network byte order. */
12395 cm->msg_id = (uint8_t) *ptr << 8 | (uint8_t) * (ptr + 1);
12396 cm->flags |= MG_COAP_MSG_ID_FIELD;
12397
12398 ptr += 2;
12399
12400 return ptr;
12401}
12402
12403/*
12404 * Fills token information in mg_coap_message.
12405 *
12406 * Helper function.
12407 */
12408static char *coap_get_token(char *ptr, struct mbuf *io,
12409 struct mg_coap_message *cm) {
12410 if (cm->token.len != 0) {
12411 if (ptr + cm->token.len > io->buf + io->len) {
12412 cm->flags |= MG_COAP_NOT_ENOUGH_DATA;
12413 return NULL;
12414 } else {
12415 cm->token.p = ptr;
12416 ptr += cm->token.len;
12417 cm->flags |= MG_COAP_TOKEN_FIELD;
12418 }
12419 }
12420
12421 return ptr;
12422}
12423
12424/*
12425 * Returns Option Delta or Length.
12426 *
12427 * Helper function.
12428 */
12429static int coap_get_ext_opt(char *ptr, struct mbuf *io, uint16_t *opt_info) {
12430 int ret = 0;
12431
12432 if (*opt_info == 13) {
12433 /*
12434 * 13: An 8-bit unsigned integer follows the initial byte and
12435 * indicates the Option Delta/Length minus 13.
12436 */
12437 if (ptr < io->buf + io->len) {
12438 *opt_info = (uint8_t) *ptr + 13;
12439 ret = sizeof(uint8_t);
12440 } else {
12441 ret = -1; /* LCOV_EXCL_LINE */
12442 }
12443 } else if (*opt_info == 14) {
12444 /*
12445 * 14: A 16-bit unsigned integer in network byte order follows the
12446 * initial byte and indicates the Option Delta/Length minus 269.
12447 */
12448 if (ptr + sizeof(uint8_t) < io->buf + io->len) {
12449 *opt_info = ((uint8_t) *ptr << 8 | (uint8_t) * (ptr + 1)) + 269;
12450 ret = sizeof(uint16_t);
12451 } else {
12452 ret = -1; /* LCOV_EXCL_LINE */
12453 }
12454 }
12455
12456 return ret;
12457}
12458
12459/*
12460 * Fills options in mg_coap_message.
12461 *
12462 * Helper function.
12463 *
12464 * General options format:
12465 * +---------------+---------------+
12466 * | Option Delta | Option Length | 1 byte
12467 * +---------------+---------------+
12468 * \ Option Delta (extended) \ 0-2 bytes
12469 * +-------------------------------+
12470 * / Option Length (extended) \ 0-2 bytes
12471 * +-------------------------------+
12472 * \ Option Value \ 0 or more bytes
12473 * +-------------------------------+
12474 */
12475static char *coap_get_options(char *ptr, struct mbuf *io,
12476 struct mg_coap_message *cm) {
12477 uint16_t prev_opt = 0;
12478
12479 if (ptr == io->buf + io->len) {
12480 /* end of packet, ok */
12481 return NULL;
12482 }
12483
12484 /* 0xFF is payload marker */
12485 while (ptr < io->buf + io->len && (uint8_t) *ptr != 0xFF) {
12487 int optinfo_len;
12488
12489 /* Option Delta: 4-bit unsigned integer */
12490 option_delta = ((uint8_t) *ptr & 0xF0) >> 4;
12491 /* Option Length: 4-bit unsigned integer */
12492 option_lenght = *ptr & 0x0F;
12493
12494 if (option_delta == 15 || option_lenght == 15) {
12495 /*
12496 * 15: Reserved for future use. If the field is set to this value,
12497 * it MUST be processed as a message format error
12498 */
12499 cm->flags |= MG_COAP_FORMAT_ERROR;
12500 break;
12501 }
12502
12503 ptr++;
12504
12505 /* check for extended option delta */
12507 if (optinfo_len == -1) {
12508 cm->flags |= MG_COAP_NOT_ENOUGH_DATA; /* LCOV_EXCL_LINE */
12509 break; /* LCOV_EXCL_LINE */
12510 }
12511
12512 ptr += optinfo_len;
12513
12514 /* check or extended option lenght */
12516 if (optinfo_len == -1) {
12517 cm->flags |= MG_COAP_NOT_ENOUGH_DATA; /* LCOV_EXCL_LINE */
12518 break; /* LCOV_EXCL_LINE */
12519 }
12520
12521 ptr += optinfo_len;
12522
12523 /*
12524 * Instead of specifying the Option Number directly, the instances MUST
12525 * appear in order of their Option Numbers and a delta encoding is used
12526 * between them.
12527 */
12529
12531
12533
12534 if (ptr + option_lenght > io->buf + io->len) {
12535 cm->flags |= MG_COAP_NOT_ENOUGH_DATA; /* LCOV_EXCL_LINE */
12536 break; /* LCOV_EXCL_LINE */
12537 }
12538
12539 ptr += option_lenght;
12540 }
12541
12542 if ((cm->flags & MG_COAP_ERROR) != 0) {
12544 return NULL;
12545 }
12546
12547 cm->flags |= MG_COAP_OPTIOMG_FIELD;
12548
12549 if (ptr == io->buf + io->len) {
12550 /* end of packet, ok */
12551 return NULL;
12552 }
12553
12554 ptr++;
12555
12556 return ptr;
12557}
12558
12559uint32_t mg_coap_parse(struct mbuf *io, struct mg_coap_message *cm) {
12560 char *ptr;
12561
12562 memset(cm, 0, sizeof(*cm));
12563
12564 if ((ptr = coap_parse_header(io->buf, io, cm)) == NULL) {
12565 return cm->flags;
12566 }
12567
12568 if ((ptr = coap_get_token(ptr, io, cm)) == NULL) {
12569 return cm->flags;
12570 }
12571
12572 if ((ptr = coap_get_options(ptr, io, cm)) == NULL) {
12573 return cm->flags;
12574 }
12575
12576 /* the rest is payload */
12577 cm->payload.len = io->len - (ptr - io->buf);
12578 if (cm->payload.len != 0) {
12579 cm->payload.p = ptr;
12580 cm->flags |= MG_COAP_PAYLOAD_FIELD;
12581 }
12582
12583 return cm->flags;
12584}
12585
12586/*
12587 * Calculates extended size of given Opt Number/Length in coap message.
12588 *
12589 * Helper function.
12590 */
12591static size_t coap_get_ext_opt_size(uint32_t value) {
12592 int ret = 0;
12593
12594 if (value >= 13 && value <= 0xFF + 13) {
12595 ret = sizeof(uint8_t);
12596 } else if (value > 0xFF + 13 && value <= 0xFFFF + 269) {
12597 ret = sizeof(uint16_t);
12598 }
12599
12600 return ret;
12601}
12602
12603/*
12604 * Splits given Opt Number/Length into base and ext values.
12605 *
12606 * Helper function.
12607 */
12608static int coap_split_opt(uint32_t value, uint8_t *base, uint16_t *ext) {
12609 int ret = 0;
12610
12611 if (value < 13) {
12612 *base = value;
12613 } else if (value >= 13 && value <= 0xFF + 13) {
12614 *base = 13;
12615 *ext = value - 13;
12616 ret = sizeof(uint8_t);
12617 } else if (value > 0xFF + 13 && value <= 0xFFFF + 269) {
12618 *base = 14;
12619 *ext = value - 269;
12620 ret = sizeof(uint16_t);
12621 }
12622
12623 return ret;
12624}
12625
12626/*
12627 * Puts uint16_t (in network order) into given char stream.
12628 *
12629 * Helper function.
12630 */
12631static char *coap_add_uint16(char *ptr, uint16_t val) {
12632 *ptr = val >> 8;
12633 ptr++;
12634 *ptr = val & 0x00FF;
12635 ptr++;
12636 return ptr;
12637}
12638
12639/*
12640 * Puts extended value of Opt Number/Length into given char stream.
12641 *
12642 * Helper function.
12643 */
12644static char *coap_add_opt_info(char *ptr, uint16_t val, size_t len) {
12645 if (len == sizeof(uint8_t)) {
12646 *ptr = (char) val;
12647 ptr++;
12648 } else if (len == sizeof(uint16_t)) {
12649 ptr = coap_add_uint16(ptr, val);
12650 }
12651
12652 return ptr;
12653}
12654
12655/*
12656 * Verifies given mg_coap_message and calculates message size for it.
12657 *
12658 * Helper function.
12659 */
12661 size_t *len) {
12662 struct mg_coap_option *opt;
12664
12665 *len = 4; /* header */
12666 if (cm->msg_type > MG_COAP_MSG_MAX) {
12668 }
12669 if (cm->token.len > 8) {
12671 }
12672 if (cm->code_class > 7) {
12674 }
12675 if (cm->code_detail > 31) {
12677 }
12678
12679 *len += cm->token.len;
12680 if (cm->payload.len != 0) {
12681 *len += cm->payload.len + 1; /* ... + 1; add payload marker */
12682 }
12683
12684 opt = cm->options;
12685 prev_opt_number = 0;
12686 while (opt != NULL) {
12687 *len += 1; /* basic delta/length */
12688 *len += coap_get_ext_opt_size(opt->number - prev_opt_number);
12689 *len += coap_get_ext_opt_size((uint32_t) opt->value.len);
12690 /*
12691 * Current implementation performs check if
12692 * option_number > previous option_number and produces an error
12693 * TODO(alashkin): write design doc with limitations
12694 * May be resorting is more suitable solution.
12695 */
12696 if ((opt->next != NULL && opt->number > opt->next->number) ||
12697 opt->value.len > 0xFFFF + 269 ||
12698 opt->number - prev_opt_number > 0xFFFF + 269) {
12700 }
12701 *len += opt->value.len;
12702 prev_opt_number = opt->number;
12703 opt = opt->next;
12704 }
12705
12706 return 0;
12707}
12708
12710 struct mg_coap_option *opt;
12712 size_t prev_io_len, packet_size;
12713 char *ptr;
12714
12716 if (res != 0) {
12717 return res;
12718 }
12719
12720 /* saving previous lenght to handle non-empty mbuf */
12721 prev_io_len = io->len;
12722 if (mbuf_append(io, NULL, packet_size) == 0) return MG_COAP_ERROR;
12723 ptr = io->buf + prev_io_len;
12724
12725 /*
12726 * since cm is verified, it is possible to use bits shift operator
12727 * without additional zeroing of unused bits
12728 */
12729
12730 /* ver: 2 bits, msg_type: 2 bits, toklen: 4 bits */
12731 *ptr = (1 << 6) | (cm->msg_type << 4) | (uint8_t)(cm->token.len);
12732 ptr++;
12733
12734 /* code class: 3 bits, code detail: 5 bits */
12735 *ptr = (cm->code_class << 5) | (cm->code_detail);
12736 ptr++;
12737
12738 ptr = coap_add_uint16(ptr, cm->msg_id);
12739
12740 if (cm->token.len != 0) {
12741 memcpy(ptr, cm->token.p, cm->token.len);
12742 ptr += cm->token.len;
12743 }
12744
12745 opt = cm->options;
12746 prev_opt_number = 0;
12747 while (opt != NULL) {
12749 uint16_t delta_ext = 0, length_ext = 0;
12750
12751 size_t opt_delta_len =
12753 size_t opt_lenght_len =
12755
12756 *ptr = (delta_base << 4) | length_base;
12757 ptr++;
12758
12761
12762 if (opt->value.len != 0) {
12763 memcpy(ptr, opt->value.p, opt->value.len);
12764 ptr += opt->value.len;
12765 }
12766
12767 prev_opt_number = opt->number;
12768 opt = opt->next;
12769 }
12770
12771 if (cm->payload.len != 0) {
12772 *ptr = (char) -1;
12773 ptr++;
12774 memcpy(ptr, cm->payload.p, cm->payload.len);
12775 }
12776
12777 return 0;
12778}
12779
12781 struct mg_coap_message *cm) {
12782 struct mbuf packet_out;
12784
12785 mbuf_init(&packet_out, 0);
12787 if (compose_res != 0) {
12788 return compose_res; /* LCOV_EXCL_LINE */
12789 }
12790
12791 mg_send(nc, packet_out.buf, (int) packet_out.len);
12793
12794 return 0;
12795}
12796
12798 struct mg_coap_message cm;
12799 memset(&cm, 0, sizeof(cm));
12800 cm.msg_type = MG_COAP_MSG_ACK;
12801 cm.msg_id = msg_id;
12802
12803 return mg_coap_send_message(nc, &cm);
12804}
12805
12806static void coap_handler(struct mg_connection *nc, int ev,
12807 void *ev_data MG_UD_ARG(void *user_data)) {
12808 struct mbuf *io = &nc->recv_mbuf;
12809 struct mg_coap_message cm;
12811
12812 memset(&cm, 0, sizeof(cm));
12813
12814 nc->handler(nc, ev, ev_data MG_UD_ARG(user_data));
12815
12816 switch (ev) {
12817 case MG_EV_RECV:
12819 if ((parse_res & MG_COAP_IGNORE) == 0) {
12820 if ((cm.flags & MG_COAP_NOT_ENOUGH_DATA) != 0) {
12821 /*
12822 * Since we support UDP only
12823 * MG_COAP_NOT_ENOUGH_DATA == MG_COAP_FORMAT_ERROR
12824 */
12825 cm.flags |= MG_COAP_FORMAT_ERROR; /* LCOV_EXCL_LINE */
12826 } /* LCOV_EXCL_LINE */
12827 nc->handler(nc, MG_COAP_EVENT_BASE + cm.msg_type,
12828 &cm MG_UD_ARG(user_data));
12829 }
12830
12832 mbuf_remove(io, io->len);
12833 break;
12834 }
12835}
12836/*
12837 * Attach built-in CoAP event handler to the given connection.
12838 *
12839 * The user-defined event handler will receive following extra events:
12840 *
12841 * - MG_EV_COAP_CON
12842 * - MG_EV_COAP_NOC
12843 * - MG_EV_COAP_ACK
12844 * - MG_EV_COAP_RST
12845 */
12846int mg_set_protocol_coap(struct mg_connection *nc) {
12847 /* supports UDP only */
12848 if ((nc->flags & MG_F_UDP) == 0) {
12849 return -1;
12850 }
12851
12853
12854 return 0;
12855}
12856
12857#endif /* MG_ENABLE_COAP */
12858#ifdef MG_MODULE_LINES
12859#line 1 "mongoose/src/mg_sntp.c"
12860#endif
12861/*
12862 * Copyright (c) 2016 Cesanta Software Limited
12863 * All rights reserved
12864 */
12865
12866/* Amalgamated: #include "mg_internal.h" */
12867/* Amalgamated: #include "mg_sntp.h" */
12868/* Amalgamated: #include "mg_util.h" */
12869
12870#if MG_ENABLE_SNTP
12871
12872#define SNTP_TIME_OFFSET 2208988800
12873
12874#ifndef SNTP_TIMEOUT
12875#define SNTP_TIMEOUT 10
12876#endif
12877
12878#ifndef SNTP_ATTEMPTS
12879#define SNTP_ATTEMPTS 3
12880#endif
12881
12883 return (val & 0xFFFFFFFF00000000) >> 32;
12884}
12885
12887 uint64_t tmp = (val & 0x00000000FFFFFFFF);
12888 tmp *= 1000000;
12889 tmp >>= 32;
12890 return tmp;
12891}
12892
12893static void mg_ntp_to_tv(uint64_t val, struct timeval *tv) {
12894 uint64_t tmp;
12895 tmp = mg_get_sec(val);
12897 tv->tv_sec = tmp;
12898 tv->tv_usec = mg_get_usec(val);
12899}
12900
12901static void mg_get_ntp_ts(const char *ntp, uint64_t *val) {
12902 uint32_t tmp;
12903 memcpy(&tmp, ntp, sizeof(tmp));
12904 tmp = ntohl(tmp);
12905 *val = (uint64_t) tmp << 32;
12906 memcpy(&tmp, ntp + 4, sizeof(tmp));
12907 tmp = ntohl(tmp);
12908 *val |= tmp;
12909}
12910
12911void mg_sntp_send_request(struct mg_connection *c) {
12912 uint8_t buf[48] = {0};
12913 /*
12914 * header - 8 bit:
12915 * LI (2 bit) - 3 (not in sync), VN (3 bit) - 4 (version),
12916 * mode (3 bit) - 3 (client)
12917 */
12918 buf[0] = (3 << 6) | (4 << 3) | 3;
12919
12920/*
12921 * Next fields should be empty in client request
12922 * stratum, 8 bit
12923 * poll interval, 8 bit
12924 * rrecision, 8 bit
12925 * root delay, 32 bit
12926 * root dispersion, 32 bit
12927 * ref id, 32 bit
12928 * ref timestamp, 64 bit
12929 * originate Timestamp, 64 bit
12930 * receive Timestamp, 64 bit
12931*/
12932
12933/*
12934 * convert time to sntp format (sntp starts from 00:00:00 01.01.1900)
12935 * according to rfc868 it is 2208988800L sec
12936 * this information is used to correct roundtrip delay
12937 * but if local clock is absolutely broken (and doesn't work even
12938 * as simple timer), it is better to disable it
12939*/
12940#ifndef MG_SNTP_NO_DELAY_CORRECTION
12941 uint32_t sec;
12943 memcpy(&buf[40], &sec, sizeof(sec));
12944#endif
12945
12946 mg_send(c, buf, sizeof(buf));
12947}
12948
12949#ifndef MG_SNTP_NO_DELAY_CORRECTION
12951 /* roundloop delay = (T4 - T1) - (T3 - T2) */
12952 uint64_t d1 = ((mg_time() + SNTP_TIME_OFFSET) * 1000000) -
12953 (mg_get_sec(t1) * 1000000 + mg_get_usec(t1));
12954 uint64_t d2 = (mg_get_sec(t3) * 1000000 + mg_get_usec(t3)) -
12955 (mg_get_sec(t2) * 1000000 + mg_get_usec(t2));
12956
12957 return (d1 > d2) ? d1 - d2 : 0;
12958}
12959#endif
12960
12961MG_INTERNAL int mg_sntp_parse_reply(const char *buf, int len,
12962 struct mg_sntp_message *msg) {
12963 uint8_t hdr;
12964 uint64_t trsm_ts_T3, delay = 0;
12965 int mode;
12966 struct timeval tv;
12967
12968 if (len < 48) {
12969 return -1;
12970 }
12971
12972 hdr = buf[0];
12973
12974 if ((hdr & 0x38) >> 3 != 4) {
12975 /* Wrong version */
12976 return -1;
12977 }
12978
12979 mode = hdr & 0x7;
12980 if (mode != 4 && mode != 5) {
12981 /* Not a server reply */
12982 return -1;
12983 }
12984
12985 memset(msg, 0, sizeof(*msg));
12986
12987 msg->kiss_of_death = (buf[1] == 0); /* Server asks to not send requests */
12988
12989 mg_get_ntp_ts(&buf[40], &trsm_ts_T3);
12990
12991#ifndef MG_SNTP_NO_DELAY_CORRECTION
12992 {
12994 mg_get_ntp_ts(&buf[24], &orig_ts_T1);
12995 mg_get_ntp_ts(&buf[32], &recv_ts_T2);
12997 }
12998#endif
12999
13001
13002 msg->time = (double) tv.tv_sec + (((double) tv.tv_usec + delay) / 1000000.0);
13003
13004 return 0;
13005}
13006
13007static void mg_sntp_handler(struct mg_connection *c, int ev,
13008 void *ev_data MG_UD_ARG(void *user_data)) {
13009 struct mbuf *io = &c->recv_mbuf;
13010 struct mg_sntp_message msg;
13011
13012 c->handler(c, ev, ev_data MG_UD_ARG(user_data));
13013
13014 switch (ev) {
13015 case MG_EV_RECV: {
13016 if (mg_sntp_parse_reply(io->buf, io->len, &msg) < 0) {
13017 DBG(("Invalid SNTP packet received (%d)", (int) io->len));
13018 c->handler(c, MG_SNTP_MALFORMED_REPLY, NULL MG_UD_ARG(user_data));
13019 } else {
13020 c->handler(c, MG_SNTP_REPLY, (void *) &msg MG_UD_ARG(user_data));
13021 }
13022
13023 mbuf_remove(io, io->len);
13024 break;
13025 }
13026 }
13027}
13028
13030 if ((c->flags & MG_F_UDP) == 0) {
13031 return -1;
13032 }
13033
13034 c->proto_handler = mg_sntp_handler;
13035
13036 return 0;
13037}
13038
13039struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr,
13040 MG_CB(mg_event_handler_t event_handler,
13041 void *user_data),
13042 const char *sntp_server_name) {
13043 struct mg_connection *c = NULL;
13044 char url[100], *p_url = url;
13045 const char *proto = "", *port = "", *tmp;
13046
13047 /* If port is not specified, use default (123) */
13048 tmp = strchr(sntp_server_name, ':');
13049 if (tmp != NULL && *(tmp + 1) == '/') {
13050 tmp = strchr(tmp + 1, ':');
13051 }
13052
13053 if (tmp == NULL) {
13054 port = ":123";
13055 }
13056
13057 /* Add udp:// if needed */
13058 if (strncmp(sntp_server_name, "udp://", 6) != 0) {
13059 proto = "udp://";
13060 }
13061
13062 mg_asprintf(&p_url, sizeof(url), "%s%s%s", proto, sntp_server_name, port);
13063
13064 c = mg_connect(mgr, p_url, event_handler MG_UD_ARG(user_data));
13065
13066 if (c == NULL) {
13067 goto cleanup;
13068 }
13069
13071
13072cleanup:
13073 if (p_url != url) {
13074 MG_FREE(p_url);
13075 }
13076
13077 return c;
13078}
13079
13080struct sntp_data {
13082 int count;
13083};
13084
13085static void mg_sntp_util_ev_handler(struct mg_connection *c, int ev,
13086 void *ev_data MG_UD_ARG(void *user_data)) {
13087#if !MG_ENABLE_CALLBACK_USERDATA
13088 void *user_data = c->user_data;
13089#endif
13090 struct sntp_data *sd = (struct sntp_data *) user_data;
13091
13092 switch (ev) {
13093 case MG_EV_CONNECT:
13094 if (*(int *) ev_data != 0) {
13095 mg_call(c, sd->hander, c->user_data, MG_SNTP_FAILED, NULL);
13096 break;
13097 }
13098 /* fallthrough */
13099 case MG_EV_TIMER:
13100 if (sd->count <= SNTP_ATTEMPTS) {
13102 mg_set_timer(c, mg_time() + 10);
13103 sd->count++;
13104 } else {
13105 mg_call(c, sd->hander, c->user_data, MG_SNTP_FAILED, NULL);
13106 c->flags |= MG_F_CLOSE_IMMEDIATELY;
13107 }
13108 break;
13110 mg_call(c, sd->hander, c->user_data, MG_SNTP_FAILED, NULL);
13111 c->flags |= MG_F_CLOSE_IMMEDIATELY;
13112 break;
13113 case MG_SNTP_REPLY:
13114 mg_call(c, sd->hander, c->user_data, MG_SNTP_REPLY, ev_data);
13115 c->flags |= MG_F_CLOSE_IMMEDIATELY;
13116 break;
13117 case MG_EV_CLOSE:
13118 MG_FREE(user_data);
13119 c->user_data = NULL;
13120 break;
13121 }
13122}
13123
13125 mg_event_handler_t event_handler,
13126 const char *sntp_server_name) {
13127 struct mg_connection *c;
13128 struct sntp_data *sd = (struct sntp_data *) MG_CALLOC(1, sizeof(*sd));
13129 if (sd == NULL) {
13130 return NULL;
13131 }
13132
13135 if (c == NULL) {
13136 MG_FREE(sd);
13137 return NULL;
13138 }
13139
13140 sd->hander = event_handler;
13141#if !MG_ENABLE_CALLBACK_USERDATA
13142 c->user_data = sd;
13143#endif
13144
13145 return c;
13146}
13147
13148#endif /* MG_ENABLE_SNTP */
13149#ifdef MG_MODULE_LINES
13150#line 1 "mongoose/src/mg_socks.c"
13151#endif
13152/*
13153 * Copyright (c) 2017 Cesanta Software Limited
13154 * All rights reserved
13155 */
13156
13157#if MG_ENABLE_SOCKS
13158
13159/* Amalgamated: #include "mg_socks.h" */
13160/* Amalgamated: #include "mg_internal.h" */
13161
13162/*
13163 * https://www.ietf.org/rfc/rfc1928.txt paragraph 3, handle client handshake
13164 *
13165 * +----+----------+----------+
13166 * |VER | NMETHODS | METHODS |
13167 * +----+----------+----------+
13168 * | 1 | 1 | 1 to 255 |
13169 * +----+----------+----------+
13170 */
13171static void mg_socks5_handshake(struct mg_connection *c) {
13172 struct mbuf *r = &c->recv_mbuf;
13173 if (r->buf[0] != MG_SOCKS_VERSION) {
13174 c->flags |= MG_F_CLOSE_IMMEDIATELY;
13175 } else if (r->len > 2 && (size_t) r->buf[1] + 2 <= r->len) {
13176 /* https://www.ietf.org/rfc/rfc1928.txt paragraph 3 */
13178 int i;
13179 for (i = 2; i < r->buf[1] + 2; i++) {
13180 /* TODO(lsm): support other auth methods */
13181 if (r->buf[i] == MG_SOCKS_HANDSHAKE_NOAUTH) reply[1] = r->buf[i];
13182 }
13183 mbuf_remove(r, 2 + r->buf[1]);
13184 mg_send(c, reply, sizeof(reply));
13185 c->flags |= MG_SOCKS_HANDSHAKE_DONE; /* Mark handshake done */
13186 }
13187}
13188
13189static void disband(struct mg_connection *c) {
13190 struct mg_connection *c2 = (struct mg_connection *) c->user_data;
13191 if (c2 != NULL) {
13192 c2->flags |= MG_F_SEND_AND_CLOSE;
13193 c2->user_data = NULL;
13194 }
13195 c->flags |= MG_F_SEND_AND_CLOSE;
13196 c->user_data = NULL;
13197}
13198
13199static void relay_data(struct mg_connection *c) {
13200 struct mg_connection *c2 = (struct mg_connection *) c->user_data;
13201 if (c2 != NULL) {
13202 mg_send(c2, c->recv_mbuf.buf, c->recv_mbuf.len);
13203 mbuf_remove(&c->recv_mbuf, c->recv_mbuf.len);
13204 } else {
13205 c->flags |= MG_F_SEND_AND_CLOSE;
13206 }
13207}
13208
13209static void serv_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
13210 if (ev == MG_EV_CLOSE) {
13211 disband(c);
13212 } else if (ev == MG_EV_RECV) {
13213 relay_data(c);
13214 } else if (ev == MG_EV_CONNECT) {
13215 int res = *(int *) ev_data;
13216 if (res != 0) LOG(LL_ERROR, ("connect error: %d", res));
13217 }
13218}
13219
13220static void mg_socks5_connect(struct mg_connection *c, const char *addr) {
13222 serv->user_data = c;
13223 c->user_data = serv;
13224}
13225
13226/*
13227 * Request, https://www.ietf.org/rfc/rfc1928.txt paragraph 4
13228 *
13229 * +----+-----+-------+------+----------+----------+
13230 * |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
13231 * +----+-----+-------+------+----------+----------+
13232 * | 1 | 1 | X'00' | 1 | Variable | 2 |
13233 * +----+-----+-------+------+----------+----------+
13234 */
13235static void mg_socks5_handle_request(struct mg_connection *c) {
13236 struct mbuf *r = &c->recv_mbuf;
13237 unsigned char *p = (unsigned char *) r->buf;
13238 unsigned char addr_len = 4, reply = MG_SOCKS_SUCCESS;
13239 int ver, cmd, atyp;
13240 char addr[300];
13241
13242 if (r->len < 8) return; /* return if not fully buffered. min DST.ADDR is 2 */
13243 ver = p[0];
13244 cmd = p[1];
13245 atyp = p[3];
13246
13247 /* TODO(lsm): support other commands */
13248 if (ver != MG_SOCKS_VERSION || cmd != MG_SOCKS_CMD_CONNECT) {
13250 } else if (atyp == MG_SOCKS_ADDR_IPV4) {
13251 addr_len = 4;
13252 if (r->len < (size_t) addr_len + 6) return; /* return if not buffered */
13253 snprintf(addr, sizeof(addr), "%d.%d.%d.%d:%d", p[4], p[5], p[6], p[7],
13254 p[8] << 8 | p[9]);
13256 } else if (atyp == MG_SOCKS_ADDR_IPV6) {
13257 addr_len = 16;
13258 if (r->len < (size_t) addr_len + 6) return; /* return if not buffered */
13259 snprintf(addr, sizeof(addr), "[%x:%x:%x:%x:%x:%x:%x:%x]:%d",
13260 p[4] << 8 | p[5], p[6] << 8 | p[7], p[8] << 8 | p[9],
13261 p[10] << 8 | p[11], p[12] << 8 | p[13], p[14] << 8 | p[15],
13262 p[16] << 8 | p[17], p[18] << 8 | p[19], p[20] << 8 | p[21]);
13264 } else if (atyp == MG_SOCKS_ADDR_DOMAIN) {
13265 addr_len = p[4] + 1;
13266 if (r->len < (size_t) addr_len + 6) return; /* return if not buffered */
13267 snprintf(addr, sizeof(addr), "%.*s:%d", p[4], p + 5,
13268 p[4 + addr_len] << 8 | p[4 + addr_len + 1]);
13270 } else {
13272 }
13273
13274 /*
13275 * Reply, https://www.ietf.org/rfc/rfc1928.txt paragraph 5
13276 *
13277 * +----+-----+-------+------+----------+----------+
13278 * |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
13279 * +----+-----+-------+------+----------+----------+
13280 * | 1 | 1 | X'00' | 1 | Variable | 2 |
13281 * +----+-----+-------+------+----------+----------+
13282 */
13283 {
13284 unsigned char buf[] = {MG_SOCKS_VERSION, reply, 0};
13285 mg_send(c, buf, sizeof(buf));
13286 }
13287 mg_send(c, r->buf + 3, addr_len + 1 + 2);
13288
13289 mbuf_remove(r, 6 + addr_len); /* Remove request from the input stream */
13290 c->flags |= MG_SOCKS_CONNECT_DONE; /* Mark ourselves as connected */
13291}
13292
13293static void socks_handler(struct mg_connection *c, int ev, void *ev_data) {
13294 if (ev == MG_EV_RECV) {
13296 if (c->flags & MG_SOCKS_HANDSHAKE_DONE &&
13297 !(c->flags & MG_SOCKS_CONNECT_DONE)) {
13299 }
13300 if (c->flags & MG_SOCKS_CONNECT_DONE) relay_data(c);
13301 } else if (ev == MG_EV_CLOSE) {
13302 disband(c);
13303 }
13304 (void) ev_data;
13305}
13306
13308 c->proto_handler = socks_handler;
13309}
13310#endif
13311#ifdef MG_MODULE_LINES
13312#line 1 "common/platforms/cc3200/cc3200_libc.c"
13313#endif
13314/*
13315 * Copyright (c) 2014-2018 Cesanta Software Limited
13316 * All rights reserved
13317 *
13318 * Licensed under the Apache License, Version 2.0 (the ""License"");
13319 * you may not use this file except in compliance with the License.
13320 * You may obtain a copy of the License at
13321 *
13322 * http://www.apache.org/licenses/LICENSE-2.0
13323 *
13324 * Unless required by applicable law or agreed to in writing, software
13325 * distributed under the License is distributed on an ""AS IS"" BASIS,
13326 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13327 * See the License for the specific language governing permissions and
13328 * limitations under the License.
13329 */
13330
13331#if CS_PLATFORM == CS_P_CC3200
13332
13333/* Amalgamated: #include "common/mg_mem.h" */
13334#include <stdio.h>
13335#include <string.h>
13336
13337#ifndef __TI_COMPILER_VERSION__
13338#include <reent.h>
13339#include <sys/stat.h>
13340#include <sys/time.h>
13341#include <unistd.h>
13342#endif
13343
13344#include <inc/hw_types.h>
13345#include <inc/hw_memmap.h>
13346#include <driverlib/prcm.h>
13347#include <driverlib/rom.h>
13348#include <driverlib/rom_map.h>
13349#include <driverlib/uart.h>
13350#include <driverlib/utils.h>
13351
13352#define CONSOLE_UART UARTA0_BASE
13353
13354#ifdef __TI_COMPILER_VERSION__
13355int asprintf(char **strp, const char *fmt, ...) {
13356 va_list ap;
13357 int len;
13358
13359 *strp = MG_MALLOC(BUFSIZ);
13360 if (*strp == NULL) return -1;
13361
13362 va_start(ap, fmt);
13363 len = vsnprintf(*strp, BUFSIZ, fmt, ap);
13364 va_end(ap);
13365
13366 if (len > 0) {
13367 *strp = MG_REALLOC(*strp, len + 1);
13368 if (*strp == NULL) return -1;
13369 }
13370
13371 if (len >= BUFSIZ) {
13372 va_start(ap, fmt);
13373 len = vsnprintf(*strp, len + 1, fmt, ap);
13374 va_end(ap);
13375 }
13376
13377 return len;
13378}
13379
13380#if MG_TI_NO_HOST_INTERFACE
13381time_t HOSTtime() {
13382 struct timeval tp;
13383 gettimeofday(&tp, NULL);
13384 return tp.tv_sec;
13385}
13386#endif
13387
13388#endif /* __TI_COMPILER_VERSION__ */
13389
13390void fprint_str(FILE *fp, const char *str) {
13391 while (*str != '\0') {
13392 if (*str == '\n') MAP_UARTCharPut(CONSOLE_UART, '\r');
13394 }
13395}
13396
13397void _exit(int status) {
13398 fprint_str(stderr, "_exit\n");
13399 /* cause an unaligned access exception, that will drop you into gdb */
13400 *(int *) 1 = status;
13401 while (1)
13402 ; /* avoid gcc warning because stdlib abort() has noreturn attribute */
13403}
13404
13405void _not_implemented(const char *what) {
13406 fprint_str(stderr, what);
13407 fprint_str(stderr, " is not implemented\n");
13408 _exit(42);
13409}
13410
13411int _kill(int pid, int sig) {
13412 (void) pid;
13413 (void) sig;
13414 _not_implemented("_kill");
13415 return -1;
13416}
13417
13418int _getpid() {
13419 fprint_str(stderr, "_getpid is not implemented\n");
13420 return 42;
13421}
13422
13423int _isatty(int fd) {
13424 /* 0, 1 and 2 are TTYs. */
13425 return fd < 2;
13426}
13427
13428#endif /* CS_PLATFORM == CS_P_CC3200 */
13429#ifdef MG_MODULE_LINES
13430#line 1 "common/platforms/msp432/msp432_libc.c"
13431#endif
13432/*
13433 * Copyright (c) 2014-2018 Cesanta Software Limited
13434 * All rights reserved
13435 *
13436 * Licensed under the Apache License, Version 2.0 (the ""License"");
13437 * you may not use this file except in compliance with the License.
13438 * You may obtain a copy of the License at
13439 *
13440 * http://www.apache.org/licenses/LICENSE-2.0
13441 *
13442 * Unless required by applicable law or agreed to in writing, software
13443 * distributed under the License is distributed on an ""AS IS"" BASIS,
13444 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13445 * See the License for the specific language governing permissions and
13446 * limitations under the License.
13447 */
13448
13449#if CS_PLATFORM == CS_P_MSP432
13450
13451#include <ti/sysbios/BIOS.h>
13452#include <ti/sysbios/knl/Clock.h>
13453
13454int gettimeofday(struct timeval *tp, void *tzp) {
13456 tp->tv_sec = ticks / 1000;
13457 tp->tv_usec = (ticks % 1000) * 1000;
13458 return 0;
13459}
13460
13461#endif /* CS_PLATFORM == CS_P_MSP432 */
13462#ifdef MG_MODULE_LINES
13463#line 1 "common/platforms/nrf5/nrf5_libc.c"
13464#endif
13465/*
13466 * Copyright (c) 2014-2018 Cesanta Software Limited
13467 * All rights reserved
13468 *
13469 * Licensed under the Apache License, Version 2.0 (the ""License"");
13470 * you may not use this file except in compliance with the License.
13471 * You may obtain a copy of the License at
13472 *
13473 * http://www.apache.org/licenses/LICENSE-2.0
13474 *
13475 * Unless required by applicable law or agreed to in writing, software
13476 * distributed under the License is distributed on an ""AS IS"" BASIS,
13477 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13478 * See the License for the specific language governing permissions and
13479 * limitations under the License.
13480 */
13481
13482#if (CS_PLATFORM == CS_P_NRF51 || CS_PLATFORM == CS_P_NRF52) && \
13483 defined(__ARMCC_VERSION)
13484int gettimeofday(struct timeval *tp, void *tzp) {
13485 /* TODO */
13486 tp->tv_sec = 0;
13487 tp->tv_usec = 0;
13488 return 0;
13489}
13490#endif
13491#ifdef MG_MODULE_LINES
13492#line 1 "common/platforms/simplelink/sl_fs_slfs.h"
13493#endif
13494/*
13495 * Copyright (c) 2014-2018 Cesanta Software Limited
13496 * All rights reserved
13497 *
13498 * Licensed under the Apache License, Version 2.0 (the ""License"");
13499 * you may not use this file except in compliance with the License.
13500 * You may obtain a copy of the License at
13501 *
13502 * http://www.apache.org/licenses/LICENSE-2.0
13503 *
13504 * Unless required by applicable law or agreed to in writing, software
13505 * distributed under the License is distributed on an ""AS IS"" BASIS,
13506 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13507 * See the License for the specific language governing permissions and
13508 * limitations under the License.
13509 */
13510
13511#ifndef CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_
13512#define CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_
13513
13514#if defined(MG_FS_SLFS)
13515
13516#include <stdio.h>
13517#ifndef __TI_COMPILER_VERSION__
13518#include <unistd.h>
13519#include <sys/stat.h>
13520#endif
13521
13522#define MAX_OPEN_SLFS_FILES 8
13523
13524/* Indirect libc interface - same functions, different names. */
13525int fs_slfs_open(const char *pathname, int flags, mode_t mode);
13526int fs_slfs_close(int fd);
13527ssize_t fs_slfs_read(int fd, void *buf, size_t count);
13528ssize_t fs_slfs_write(int fd, const void *buf, size_t count);
13529int fs_slfs_stat(const char *pathname, struct stat *s);
13530int fs_slfs_fstat(int fd, struct stat *s);
13531off_t fs_slfs_lseek(int fd, off_t offset, int whence);
13532int fs_slfs_unlink(const char *filename);
13533int fs_slfs_rename(const char *from, const char *to);
13534
13535void fs_slfs_set_file_size(const char *name, size_t size);
13536void fs_slfs_set_file_flags(const char *name, uint32_t flags, uint32_t *token);
13537void fs_slfs_unset_file_flags(const char *name);
13538
13539#endif /* defined(MG_FS_SLFS) */
13540
13541#endif /* CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_ */
13542#ifdef MG_MODULE_LINES
13543#line 1 "common/platforms/simplelink/sl_fs_slfs.c"
13544#endif
13545/*
13546 * Copyright (c) 2014-2018 Cesanta Software Limited
13547 * All rights reserved
13548 *
13549 * Licensed under the Apache License, Version 2.0 (the ""License"");
13550 * you may not use this file except in compliance with the License.
13551 * You may obtain a copy of the License at
13552 *
13553 * http://www.apache.org/licenses/LICENSE-2.0
13554 *
13555 * Unless required by applicable law or agreed to in writing, software
13556 * distributed under the License is distributed on an ""AS IS"" BASIS,
13557 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13558 * See the License for the specific language governing permissions and
13559 * limitations under the License.
13560 */
13561
13562/* Standard libc interface to TI SimpleLink FS. */
13563
13564#if defined(MG_FS_SLFS) || defined(CC3200_FS_SLFS)
13565
13566/* Amalgamated: #include "common/platforms/simplelink/sl_fs_slfs.h" */
13567
13568#include <errno.h>
13569
13570#if CS_PLATFORM == CS_P_CC3200
13571#include <inc/hw_types.h>
13572#endif
13573
13574/* Amalgamated: #include "common/cs_dbg.h" */
13575/* Amalgamated: #include "common/mg_mem.h" */
13576
13577#if SL_MAJOR_VERSION_NUM < 2
13578int slfs_open(const unsigned char *fname, uint32_t flags, uint32_t *token) {
13579 _i32 fh;
13580 _i32 r = sl_FsOpen(fname, flags, (unsigned long *) token, &fh);
13581 return (r < 0 ? r : fh);
13582}
13583#else /* SL_MAJOR_VERSION_NUM >= 2 */
13584int slfs_open(const unsigned char *fname, uint32_t flags, uint32_t *token) {
13585 return sl_FsOpen(fname, flags, (unsigned long *) token);
13586}
13587#endif
13588
13589/* From sl_fs.c */
13590int set_errno(int e);
13591const char *drop_dir(const char *fname, bool *is_slfs);
13592
13593/*
13594 * With SLFS, you have to pre-declare max file size. Yes. Really.
13595 * 64K should be enough for everyone. Right?
13596 */
13597#ifndef FS_SLFS_MAX_FILE_SIZE
13598#define FS_SLFS_MAX_FILE_SIZE (64 * 1024)
13599#endif
13600
13601struct sl_file_open_info {
13602 char *name;
13603 size_t size;
13604 uint32_t flags;
13605 uint32_t *token;
13606};
13607
13608struct sl_fd_info {
13609 _i32 fh;
13610 _off_t pos;
13611 size_t size;
13612};
13613
13616
13617static struct sl_file_open_info *fs_slfs_find_foi(const char *name,
13618 bool create);
13619
13620static int sl_fs_to_errno(_i32 r) {
13621 DBG(("SL error: %d", (int) r));
13622 switch (r) {
13623 case SL_FS_OK:
13624 return 0;
13626 return EEXIST;
13628 return EINVAL;
13631 return ENOSPC;
13633 return ENOMEM;
13635 return ENOENT;
13637 return ENOTSUP;
13638 }
13639 return ENXIO;
13640}
13641
13642int fs_slfs_open(const char *pathname, int flags, mode_t mode) {
13643 int fd;
13644 for (fd = 0; fd < MAX_OPEN_SLFS_FILES; fd++) {
13645 if (s_sl_fds[fd].fh <= 0) break;
13646 }
13647 if (fd >= MAX_OPEN_SLFS_FILES) return set_errno(ENOMEM);
13648 struct sl_fd_info *fi = &s_sl_fds[fd];
13649
13650 /*
13651 * Apply path manipulations again, in case we got here directly
13652 * (via TI libc's "add_device").
13653 */
13655
13656 _u32 am = 0;
13657 fi->size = (size_t) -1;
13658 int rw = (flags & 3);
13659 size_t new_size = 0;
13660 struct sl_file_open_info *foi =
13661 fs_slfs_find_foi(pathname, false /* create */);
13662 if (foi != NULL) {
13663 LOG(LL_DEBUG, ("FOI for %s: %d 0x%x %p", pathname, (int) foi->size,
13664 (unsigned int) foi->flags, foi->token));
13665 }
13666 if (rw == O_RDONLY) {
13668 _i32 r = sl_FsGetInfo((const _u8 *) pathname, 0, &sl_fi);
13669 if (r == SL_FS_OK) {
13670 fi->size = SL_FI_FILE_SIZE(sl_fi);
13671 }
13672 am = SL_FS_READ;
13673 } else {
13674 if (!(flags & O_TRUNC) || (flags & O_APPEND)) {
13675 // FailFS files cannot be opened for append and will be truncated
13676 // when opened for write.
13677 return set_errno(ENOTSUP);
13678 }
13679 if (flags & O_CREAT) {
13680 if (foi->size > 0) {
13681 new_size = foi->size;
13682 } else {
13684 }
13686 } else {
13687 am = SL_FS_WRITE;
13688 }
13689#if SL_MAJOR_VERSION_NUM >= 2
13690 am |= SL_FS_OVERWRITE;
13691#endif
13692 }
13693 uint32_t *token = NULL;
13694 if (foi != NULL) {
13695 am |= foi->flags;
13696 token = foi->token;
13697 }
13698 fi->fh = slfs_open((_u8 *) pathname, am, token);
13699 LOG(LL_DEBUG, ("sl_FsOpen(%s, 0x%x, %p) sz %u = %d", pathname, (int) am,
13700 token, (unsigned int) new_size, (int) fi->fh));
13701 int r;
13702 if (fi->fh >= 0) {
13703 fi->pos = 0;
13704 r = fd;
13705 } else {
13706 r = set_errno(sl_fs_to_errno(fi->fh));
13707 }
13708 return r;
13709}
13710
13711int fs_slfs_close(int fd) {
13712 struct sl_fd_info *fi = &s_sl_fds[fd];
13713 if (fi->fh <= 0) return set_errno(EBADF);
13714 _i32 r = sl_FsClose(fi->fh, NULL, NULL, 0);
13715 LOG(LL_DEBUG, ("sl_FsClose(%d) = %d", (int) fi->fh, (int) r));
13716 s_sl_fds[fd].fh = -1;
13717 return set_errno(sl_fs_to_errno(r));
13718}
13719
13720ssize_t fs_slfs_read(int fd, void *buf, size_t count) {
13721 struct sl_fd_info *fi = &s_sl_fds[fd];
13722 if (fi->fh <= 0) return set_errno(EBADF);
13723 /* Simulate EOF. sl_FsRead @ file_size return SL_FS_ERR_OFFSET_OUT_OF_RANGE.
13724 */
13725 if (fi->pos == fi->size) return 0;
13726 _i32 r = sl_FsRead(fi->fh, fi->pos, buf, count);
13727 DBG(("sl_FsRead(%d, %d, %d) = %d", (int) fi->fh, (int) fi->pos, (int) count,
13728 (int) r));
13729 if (r >= 0) {
13730 fi->pos += r;
13731 return r;
13732 }
13733 return set_errno(sl_fs_to_errno(r));
13734}
13735
13736ssize_t fs_slfs_write(int fd, const void *buf, size_t count) {
13737 struct sl_fd_info *fi = &s_sl_fds[fd];
13738 if (fi->fh <= 0) return set_errno(EBADF);
13739 _i32 r = sl_FsWrite(fi->fh, fi->pos, (_u8 *) buf, count);
13740 DBG(("sl_FsWrite(%d, %d, %d) = %d", (int) fi->fh, (int) fi->pos, (int) count,
13741 (int) r));
13742 if (r >= 0) {
13743 fi->pos += r;
13744 return r;
13745 }
13746 return set_errno(sl_fs_to_errno(r));
13747}
13748
13749int fs_slfs_stat(const char *pathname, struct stat *s) {
13751 /*
13752 * Apply path manipulations again, in case we got here directly
13753 * (via TI libc's "add_device").
13754 */
13756 _i32 r = sl_FsGetInfo((const _u8 *) pathname, 0, &sl_fi);
13757 if (r == SL_FS_OK) {
13758 s->st_mode = S_IFREG | 0666;
13759 s->st_nlink = 1;
13760 s->st_size = SL_FI_FILE_SIZE(sl_fi);
13761 return 0;
13762 }
13763 return set_errno(sl_fs_to_errno(r));
13764}
13765
13766int fs_slfs_fstat(int fd, struct stat *s) {
13767 struct sl_fd_info *fi = &s_sl_fds[fd];
13768 if (fi->fh <= 0) return set_errno(EBADF);
13769 s->st_mode = 0666;
13770 s->st_mode = S_IFREG | 0666;
13771 s->st_nlink = 1;
13772 s->st_size = fi->size;
13773 return 0;
13774}
13775
13776off_t fs_slfs_lseek(int fd, off_t offset, int whence) {
13777 if (s_sl_fds[fd].fh <= 0) return set_errno(EBADF);
13778 switch (whence) {
13779 case SEEK_SET:
13780 s_sl_fds[fd].pos = offset;
13781 break;
13782 case SEEK_CUR:
13783 s_sl_fds[fd].pos += offset;
13784 break;
13785 case SEEK_END:
13786 return set_errno(ENOTSUP);
13787 }
13788 return 0;
13789}
13790
13791int fs_slfs_unlink(const char *pathname) {
13792 /*
13793 * Apply path manipulations again, in case we got here directly
13794 * (via TI libc's "add_device").
13795 */
13797 return set_errno(sl_fs_to_errno(sl_FsDel((const _u8 *) pathname, 0)));
13798}
13799
13800int fs_slfs_rename(const char *from, const char *to) {
13801 return set_errno(ENOTSUP);
13802}
13803
13804static struct sl_file_open_info *fs_slfs_find_foi(const char *name,
13805 bool create) {
13806 int i = 0;
13807 for (i = 0; i < MAX_OPEN_SLFS_FILES; i++) {
13808 if (s_sl_file_open_infos[i].name != NULL &&
13810 break;
13811 }
13812 }
13814 if (!create) return NULL;
13815 for (i = 0; i < MAX_OPEN_SLFS_FILES; i++) {
13816 if (s_sl_file_open_infos[i].name == NULL) break;
13817 }
13818 if (i == MAX_OPEN_SLFS_FILES) {
13819 i = 0; /* Evict a random slot. */
13820 }
13821 if (s_sl_file_open_infos[i].name != NULL) {
13823 }
13825 return &s_sl_file_open_infos[i];
13826}
13827
13828void fs_slfs_set_file_size(const char *name, size_t size) {
13829 struct sl_file_open_info *foi = fs_slfs_find_foi(name, true /* create */);
13830 foi->size = size;
13831}
13832
13833void fs_slfs_set_file_flags(const char *name, uint32_t flags, uint32_t *token) {
13834 struct sl_file_open_info *foi = fs_slfs_find_foi(name, true /* create */);
13835 foi->flags = flags;
13836 foi->token = token;
13837}
13838
13839void fs_slfs_unset_file_flags(const char *name) {
13840 struct sl_file_open_info *foi = fs_slfs_find_foi(name, false /* create */);
13841 if (foi == NULL) return;
13842 free(foi->name);
13843 memset(foi, 0, sizeof(*foi));
13844}
13845
13846#endif /* defined(MG_FS_SLFS) || defined(CC3200_FS_SLFS) */
13847#ifdef MG_MODULE_LINES
13848#line 1 "common/platforms/simplelink/sl_fs.c"
13849#endif
13850/*
13851 * Copyright (c) 2014-2018 Cesanta Software Limited
13852 * All rights reserved
13853 *
13854 * Licensed under the Apache License, Version 2.0 (the ""License"");
13855 * you may not use this file except in compliance with the License.
13856 * You may obtain a copy of the License at
13857 *
13858 * http://www.apache.org/licenses/LICENSE-2.0
13859 *
13860 * Unless required by applicable law or agreed to in writing, software
13861 * distributed under the License is distributed on an ""AS IS"" BASIS,
13862 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13863 * See the License for the specific language governing permissions and
13864 * limitations under the License.
13865 */
13866
13867#if MG_NET_IF == MG_NET_IF_SIMPLELINK && \
13868 (defined(MG_FS_SLFS) || defined(MG_FS_SPIFFS))
13869
13870int set_errno(int e) {
13871 errno = e;
13872 return (e == 0 ? 0 : -1);
13873}
13874
13875const char *drop_dir(const char *fname, bool *is_slfs) {
13876 if (is_slfs != NULL) {
13877 *is_slfs = (strncmp(fname, "SL:", 3) == 0);
13878 if (*is_slfs) fname += 3;
13879 }
13880 /* Drop "./", if any */
13881 if (fname[0] == '.' && fname[1] == '/') {
13882 fname += 2;
13883 }
13884 /*
13885 * Drop / if it is the only one in the path.
13886 * This allows use of /pretend/directories but serves /file.txt as normal.
13887 */
13888 if (fname[0] == '/' && strchr(fname + 1, '/') == NULL) {
13889 fname++;
13890 }
13891 return fname;
13892}
13893
13894#if !defined(MG_FS_NO_VFS)
13895
13896#include <errno.h>
13897#include <stdbool.h>
13898#include <stdio.h>
13899#include <stdlib.h>
13900#include <string.h>
13901#ifdef __TI_COMPILER_VERSION__
13902#include <file.h>
13903#endif
13904
13905/* Amalgamated: #include "common/cs_dbg.h" */
13906/* Amalgamated: #include "common/platform.h" */
13907
13908#ifdef CC3200_FS_SPIFFS
13909/* Amalgamated: #include "cc3200_fs_spiffs.h" */
13910#endif
13911
13912#ifdef MG_FS_SLFS
13913/* Amalgamated: #include "sl_fs_slfs.h" */
13914#endif
13915
13916#define NUM_SYS_FDS 3
13917#define SPIFFS_FD_BASE 10
13918#define SLFS_FD_BASE 100
13919
13920#if !defined(MG_UART_CHAR_PUT) && !defined(MG_UART_WRITE)
13921#if CS_PLATFORM == CS_P_CC3200
13922#include <inc/hw_types.h>
13923#include <inc/hw_memmap.h>
13924#include <driverlib/rom.h>
13925#include <driverlib/rom_map.h>
13926#include <driverlib/uart.h>
13927#define MG_UART_CHAR_PUT(fd, c) MAP_UARTCharPut(UARTA0_BASE, c);
13928#else
13929#define MG_UART_WRITE(fd, buf, len)
13930#endif /* CS_PLATFORM == CS_P_CC3200 */
13931#endif /* !MG_UART_CHAR_PUT */
13932
13933enum fd_type {
13934 FD_INVALID,
13935 FD_SYS,
13936#ifdef CC3200_FS_SPIFFS
13937 FD_SPIFFS,
13938#endif
13939#ifdef MG_FS_SLFS
13940 FD_SLFS
13941#endif
13942};
13943static int fd_type(int fd) {
13944 if (fd >= 0 && fd < NUM_SYS_FDS) return FD_SYS;
13945#ifdef CC3200_FS_SPIFFS
13947 return FD_SPIFFS;
13948 }
13949#endif
13950#ifdef MG_FS_SLFS
13951 if (fd >= SLFS_FD_BASE && fd < SLFS_FD_BASE + MAX_OPEN_SLFS_FILES) {
13952 return FD_SLFS;
13953 }
13954#endif
13955 return FD_INVALID;
13956}
13957
13958#if MG_TI_NO_HOST_INTERFACE
13959int open(const char *pathname, unsigned flags, int mode) {
13960#else
13961int _open(const char *pathname, int flags, mode_t mode) {
13962#endif
13963 int fd = -1;
13964 bool is_sl;
13965 const char *fname = drop_dir(pathname, &is_sl);
13966 if (is_sl) {
13967#ifdef MG_FS_SLFS
13968 fd = fs_slfs_open(fname, flags, mode);
13969 if (fd >= 0) fd += SLFS_FD_BASE;
13970#endif
13971 } else {
13972#ifdef CC3200_FS_SPIFFS
13973 fd = fs_spiffs_open(fname, flags, mode);
13974 if (fd >= 0) fd += SPIFFS_FD_BASE;
13975#endif
13976 }
13977 LOG(LL_DEBUG,
13978 ("open(%s, 0x%x) = %d, fname = %s", pathname, flags, fd, fname));
13979 return fd;
13980}
13981
13982int _stat(const char *pathname, struct stat *st) {
13983 int res = -1;
13984 bool is_sl;
13985 const char *fname = drop_dir(pathname, &is_sl);
13986 memset(st, 0, sizeof(*st));
13987 /* Simulate statting the root directory. */
13988 if (fname[0] == '\0' || strcmp(fname, ".") == 0) {
13989 st->st_ino = 0;
13990 st->st_mode = S_IFDIR | 0777;
13991 st->st_nlink = 1;
13992 st->st_size = 0;
13993 return 0;
13994 }
13995 if (is_sl) {
13996#ifdef MG_FS_SLFS
13998#endif
13999 } else {
14000#ifdef CC3200_FS_SPIFFS
14002#endif
14003 }
14004 LOG(LL_DEBUG, ("stat(%s) = %d; fname = %s", pathname, res, fname));
14005 return res;
14006}
14007
14008#if MG_TI_NO_HOST_INTERFACE
14009int close(int fd) {
14010#else
14011int _close(int fd) {
14012#endif
14013 int r = -1;
14014 switch (fd_type(fd)) {
14015 case FD_INVALID:
14016 r = set_errno(EBADF);
14017 break;
14018 case FD_SYS:
14019 r = set_errno(EACCES);
14020 break;
14021#ifdef CC3200_FS_SPIFFS
14022 case FD_SPIFFS:
14024 break;
14025#endif
14026#ifdef MG_FS_SLFS
14027 case FD_SLFS:
14028 r = fs_slfs_close(fd - SLFS_FD_BASE);
14029 break;
14030#endif
14031 }
14032 DBG(("close(%d) = %d", fd, r));
14033 return r;
14034}
14035
14036#if MG_TI_NO_HOST_INTERFACE
14037off_t lseek(int fd, off_t offset, int whence) {
14038#else
14039off_t _lseek(int fd, off_t offset, int whence) {
14040#endif
14041 int r = -1;
14042 switch (fd_type(fd)) {
14043 case FD_INVALID:
14044 r = set_errno(EBADF);
14045 break;
14046 case FD_SYS:
14047 r = set_errno(ESPIPE);
14048 break;
14049#ifdef CC3200_FS_SPIFFS
14050 case FD_SPIFFS:
14052 break;
14053#endif
14054#ifdef MG_FS_SLFS
14055 case FD_SLFS:
14057 break;
14058#endif
14059 }
14060 DBG(("lseek(%d, %d, %d) = %d", fd, (int) offset, whence, r));
14061 return r;
14062}
14063
14064int _fstat(int fd, struct stat *s) {
14065 int r = -1;
14066 memset(s, 0, sizeof(*s));
14067 switch (fd_type(fd)) {
14068 case FD_INVALID:
14069 r = set_errno(EBADF);
14070 break;
14071 case FD_SYS: {
14072 /* Create barely passable stats for STD{IN,OUT,ERR}. */
14073 memset(s, 0, sizeof(*s));
14074 s->st_ino = fd;
14075 s->st_mode = S_IFCHR | 0666;
14076 r = 0;
14077 break;
14078 }
14079#ifdef CC3200_FS_SPIFFS
14080 case FD_SPIFFS:
14081 r = fs_spiffs_fstat(fd - SPIFFS_FD_BASE, s);
14082 break;
14083#endif
14084#ifdef MG_FS_SLFS
14085 case FD_SLFS:
14086 r = fs_slfs_fstat(fd - SLFS_FD_BASE, s);
14087 break;
14088#endif
14089 }
14090 DBG(("fstat(%d) = %d", fd, r));
14091 return r;
14092}
14093
14094#if MG_TI_NO_HOST_INTERFACE
14095int read(int fd, char *buf, unsigned count) {
14096#else
14097ssize_t _read(int fd, void *buf, size_t count) {
14098#endif
14099 int r = -1;
14100 switch (fd_type(fd)) {
14101 case FD_INVALID:
14102 r = set_errno(EBADF);
14103 break;
14104 case FD_SYS: {
14105 if (fd != 0) {
14106 r = set_errno(EACCES);
14107 break;
14108 }
14109 /* Should we allow reading from stdin = uart? */
14110 r = set_errno(ENOTSUP);
14111 break;
14112 }
14113#ifdef CC3200_FS_SPIFFS
14114 case FD_SPIFFS:
14115 r = fs_spiffs_read(fd - SPIFFS_FD_BASE, buf, count);
14116 break;
14117#endif
14118#ifdef MG_FS_SLFS
14119 case FD_SLFS:
14120 r = fs_slfs_read(fd - SLFS_FD_BASE, buf, count);
14121 break;
14122#endif
14123 }
14124 DBG(("read(%d, %u) = %d", fd, count, r));
14125 return r;
14126}
14127
14128#if MG_TI_NO_HOST_INTERFACE
14129int write(int fd, const char *buf, unsigned count) {
14130#else
14131ssize_t _write(int fd, const void *buf, size_t count) {
14132#endif
14133 int r = -1;
14134 switch (fd_type(fd)) {
14135 case FD_INVALID:
14136 r = set_errno(EBADF);
14137 break;
14138 case FD_SYS: {
14139 if (fd == 0) {
14140 r = set_errno(EACCES);
14141 break;
14142 }
14143#ifdef MG_UART_WRITE
14144 MG_UART_WRITE(fd, buf, count);
14145#elif defined(MG_UART_CHAR_PUT)
14146 {
14147 size_t i;
14148 for (i = 0; i < count; i++) {
14149 const char c = ((const char *) buf)[i];
14150 if (c == '\n') MG_UART_CHAR_PUT(fd, '\r');
14151 MG_UART_CHAR_PUT(fd, c);
14152 }
14153 }
14154#endif
14155 r = count;
14156 break;
14157 }
14158#ifdef CC3200_FS_SPIFFS
14159 case FD_SPIFFS:
14160 r = fs_spiffs_write(fd - SPIFFS_FD_BASE, buf, count);
14161 break;
14162#endif
14163#ifdef MG_FS_SLFS
14164 case FD_SLFS:
14165 r = fs_slfs_write(fd - SLFS_FD_BASE, buf, count);
14166 break;
14167#endif
14168 }
14169 return r;
14170}
14171
14172/*
14173 * On Newlib we override rename directly too, because the default
14174 * implementation using _link and _unlink doesn't work for us.
14175 */
14176#if MG_TI_NO_HOST_INTERFACE || defined(_NEWLIB_VERSION)
14177int rename(const char *frompath, const char *topath) {
14178 int r = -1;
14179 bool is_sl_from, is_sl_to;
14180 const char *from = drop_dir(frompath, &is_sl_from);
14181 const char *to = drop_dir(topath, &is_sl_to);
14182 if (is_sl_from || is_sl_to) {
14184 } else {
14185#ifdef CC3200_FS_SPIFFS
14186 r = fs_spiffs_rename(from, to);
14187#endif
14188 }
14189 DBG(("rename(%s, %s) = %d", from, to, r));
14190 return r;
14191}
14192#endif /* MG_TI_NO_HOST_INTERFACE || defined(_NEWLIB_VERSION) */
14193
14194#if MG_TI_NO_HOST_INTERFACE
14195int unlink(const char *pathname) {
14196#else
14197int _unlink(const char *pathname) {
14198#endif
14199 int r = -1;
14200 bool is_sl;
14201 const char *fname = drop_dir(pathname, &is_sl);
14202 if (is_sl) {
14203#ifdef MG_FS_SLFS
14204 r = fs_slfs_unlink(fname);
14205#endif
14206 } else {
14207#ifdef CC3200_FS_SPIFFS
14209#endif
14210 }
14211 DBG(("unlink(%s) = %d, fname = %s", pathname, r, fname));
14212 return r;
14213}
14214
14215#ifdef CC3200_FS_SPIFFS /* FailFS does not support listing files. */
14216DIR *opendir(const char *dir_name) {
14217 DIR *r = NULL;
14218 bool is_sl;
14220 if (is_sl) {
14221 r = NULL;
14223 } else {
14225 }
14226 DBG(("opendir(%s) = %p", dir_name, r));
14227 return r;
14228}
14229
14230struct dirent *readdir(DIR *dir) {
14231 struct dirent *res = fs_spiffs_readdir(dir);
14232 DBG(("readdir(%p) = %p", dir, res));
14233 return res;
14234}
14235
14236int closedir(DIR *dir) {
14237 int res = fs_spiffs_closedir(dir);
14238 DBG(("closedir(%p) = %d", dir, res));
14239 return res;
14240}
14241
14242int rmdir(const char *path) {
14243 return fs_spiffs_rmdir(path);
14244}
14245
14246int mkdir(const char *path, mode_t mode) {
14247 (void) path;
14248 (void) mode;
14249 /* for spiffs supports only root dir, which comes from mongoose as '.' */
14250 return (strlen(path) == 1 && *path == '.') ? 0 : ENOTDIR;
14251}
14252#endif
14253
14254int sl_fs_init(void) {
14255 int ret = 1;
14256#ifdef __TI_COMPILER_VERSION__
14257#ifdef MG_FS_SLFS
14258#pragma diag_push
14259#pragma diag_suppress 169 /* Nothing we can do about the prototype mismatch. \
14260 */
14263 fs_slfs_rename) == 0);
14264#pragma diag_pop
14265#endif
14266#endif
14267 return ret;
14268}
14269
14270#endif /* !defined(MG_FS_NO_VFS) */
14271#endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK && (defined(MG_FS_SLFS) || \
14272 defined(MG_FS_SPIFFS)) */
14273#ifdef MG_MODULE_LINES
14274#line 1 "common/platforms/simplelink/sl_socket.c"
14275#endif
14276/*
14277 * Copyright (c) 2014-2018 Cesanta Software Limited
14278 * All rights reserved
14279 *
14280 * Licensed under the Apache License, Version 2.0 (the ""License"");
14281 * you may not use this file except in compliance with the License.
14282 * You may obtain a copy of the License at
14283 *
14284 * http://www.apache.org/licenses/LICENSE-2.0
14285 *
14286 * Unless required by applicable law or agreed to in writing, software
14287 * distributed under the License is distributed on an ""AS IS"" BASIS,
14288 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14289 * See the License for the specific language governing permissions and
14290 * limitations under the License.
14291 */
14292
14293#if MG_NET_IF == MG_NET_IF_SIMPLELINK
14294
14295#include <errno.h>
14296#include <stdio.h>
14297
14298/* Amalgamated: #include "common/platform.h" */
14299
14300const char *inet_ntop(int af, const void *src, char *dst, socklen_t size) {
14301 int res;
14302 struct in_addr *in = (struct in_addr *) src;
14303 if (af != AF_INET) {
14304 errno = ENOTSUP;
14305 return NULL;
14306 }
14307 res = snprintf(dst, size, "%lu.%lu.%lu.%lu", SL_IPV4_BYTE(in->s_addr, 0),
14308 SL_IPV4_BYTE(in->s_addr, 1), SL_IPV4_BYTE(in->s_addr, 2),
14309 SL_IPV4_BYTE(in->s_addr, 3));
14310 return res > 0 ? dst : NULL;
14311}
14312
14313char *inet_ntoa(struct in_addr n) {
14314 static char a[16];
14315 return (char *) inet_ntop(AF_INET, &n, a, sizeof(a));
14316}
14317
14318int inet_pton(int af, const char *src, void *dst) {
14319 uint32_t a0, a1, a2, a3;
14320 uint8_t *db = (uint8_t *) dst;
14321 if (af != AF_INET) {
14322 errno = ENOTSUP;
14323 return 0;
14324 }
14325 if (sscanf(src, "%lu.%lu.%lu.%lu", &a0, &a1, &a2, &a3) != 4) {
14326 return 0;
14327 }
14328 *db = a3;
14329 *(db + 1) = a2;
14330 *(db + 2) = a1;
14331 *(db + 3) = a0;
14332 return 1;
14333}
14334
14335#endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */
14336#ifdef MG_MODULE_LINES
14337#line 1 "common/platforms/simplelink/sl_mg_task.c"
14338#endif
14339#if MG_NET_IF == MG_NET_IF_SIMPLELINK && !defined(MG_SIMPLELINK_NO_OSI)
14340
14341/* Amalgamated: #include "mg_task.h" */
14342
14343#include <oslib/osi.h>
14344
14348struct mg_q_msg {
14350 void (*cb)(struct mg_mgr *mgr, void *arg);
14351 void *arg;
14352};
14354static void mg_task(void *arg);
14355
14357 if (osi_MsgQCreate(&s_mg_q, "MG", sizeof(struct mg_q_msg), 16) != OSI_OK) {
14358 return false;
14359 }
14360 if (osi_TaskCreate(mg_task, (const signed char *) "MG", stack_size,
14361 (void *) mg_init, priority, NULL) != OSI_OK) {
14362 return false;
14363 }
14364 return true;
14365}
14366
14367static void mg_task(void *arg) {
14368 struct mg_mgr mgr;
14370 mg_mgr_init(&mgr, NULL);
14371 mg_init(&mgr);
14372 while (1) {
14373 struct mg_q_msg msg;
14374 mg_mgr_poll(&mgr, 1);
14375 if (osi_MsgQRead(&s_mg_q, &msg, 1) != OSI_OK) continue;
14376 switch (msg.type) {
14377 case MG_Q_MSG_CB: {
14378 msg.cb(&mgr, msg.arg);
14379 }
14380 }
14381 }
14382}
14383
14384void mg_run_in_task(void (*cb)(struct mg_mgr *mgr, void *arg), void *cb_arg) {
14385 struct mg_q_msg msg = {MG_Q_MSG_CB, cb, cb_arg};
14387}
14388
14389#endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK && !defined(MG_SIMPLELINK_NO_OSI) \
14390 */
14391#ifdef MG_MODULE_LINES
14392#line 1 "common/platforms/simplelink/sl_net_if.h"
14393#endif
14394/*
14395 * Copyright (c) 2014-2018 Cesanta Software Limited
14396 * All rights reserved
14397 *
14398 * Licensed under the Apache License, Version 2.0 (the ""License"");
14399 * you may not use this file except in compliance with the License.
14400 * You may obtain a copy of the License at
14401 *
14402 * http://www.apache.org/licenses/LICENSE-2.0
14403 *
14404 * Unless required by applicable law or agreed to in writing, software
14405 * distributed under the License is distributed on an ""AS IS"" BASIS,
14406 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14407 * See the License for the specific language governing permissions and
14408 * limitations under the License.
14409 */
14410
14411#ifndef CS_COMMON_PLATFORMS_SIMPLELINK_SL_NET_IF_H_
14412#define CS_COMMON_PLATFORMS_SIMPLELINK_SL_NET_IF_H_
14413
14414/* Amalgamated: #include "mongoose/src/net_if.h" */
14415
14416#ifdef __cplusplus
14417extern "C" {
14418#endif /* __cplusplus */
14419
14420#ifndef MG_ENABLE_NET_IF_SIMPLELINK
14421#define MG_ENABLE_NET_IF_SIMPLELINK MG_NET_IF == MG_NET_IF_SIMPLELINK
14422#endif
14423
14425
14426#ifdef __cplusplus
14427}
14428#endif /* __cplusplus */
14429
14430#endif /* CS_COMMON_PLATFORMS_SIMPLELINK_SL_NET_IF_H_ */
14431#ifdef MG_MODULE_LINES
14432#line 1 "common/platforms/simplelink/sl_net_if.c"
14433#endif
14434/*
14435 * Copyright (c) 2014-2018 Cesanta Software Limited
14436 * All rights reserved
14437 *
14438 * Licensed under the Apache License, Version 2.0 (the ""License"");
14439 * you may not use this file except in compliance with the License.
14440 * You may obtain a copy of the License at
14441 *
14442 * http://www.apache.org/licenses/LICENSE-2.0
14443 *
14444 * Unless required by applicable law or agreed to in writing, software
14445 * distributed under the License is distributed on an ""AS IS"" BASIS,
14446 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14447 * See the License for the specific language governing permissions and
14448 * limitations under the License.
14449 */
14450
14451/* Amalgamated: #include "common/platforms/simplelink/sl_net_if.h" */
14452
14453#if MG_ENABLE_NET_IF_SIMPLELINK
14454
14455/* Amalgamated: #include "mongoose/src/internal.h" */
14456/* Amalgamated: #include "mongoose/src/util.h" */
14457
14458#define MG_TCP_RECV_BUFFER_SIZE 1024
14459#define MG_UDP_RECV_BUFFER_SIZE 1500
14460
14462 union socket_address *sa, int type,
14463 int proto);
14464
14465static void mg_set_non_blocking_mode(sock_t sock) {
14467#if SL_MAJOR_VERSION_NUM < 2
14468 opt.NonblockingEnabled = 1;
14469#else
14470 opt.NonBlockingEnabled = 1;
14471#endif
14473}
14474
14475static int mg_is_error(int n) {
14476 return (n < 0 && n != SL_ERROR_BSD_EALREADY && n != SL_ERROR_BSD_EAGAIN);
14477}
14478
14480 const union socket_address *sa) {
14481 int proto = 0;
14482#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
14483 if (nc->flags & MG_F_SSL) proto = SL_SEC_SOCKET;
14484#endif
14485 sock_t sock = sl_Socket(AF_INET, SOCK_STREAM, proto);
14486 if (sock < 0) {
14487 nc->err = sock;
14488 goto out;
14489 }
14490 mg_sock_set(nc, sock);
14491#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
14492 nc->err = sl_set_ssl_opts(sock, nc);
14493 if (nc->err != 0) goto out;
14494#endif
14495 nc->err = sl_Connect(sock, &sa->sa, sizeof(sa->sin));
14496out:
14497 DBG(("%p to %s:%d sock %d %d err %d", nc, inet_ntoa(sa->sin.sin_addr),
14498 ntohs(sa->sin.sin_port), nc->sock, proto, nc->err));
14499}
14500
14501static void mg_sl_if_connect_udp(struct mg_connection *nc) {
14502 sock_t sock = sl_Socket(AF_INET, SOCK_DGRAM, 0);
14503 if (sock < 0) {
14504 nc->err = sock;
14505 return;
14506 }
14507 mg_sock_set(nc, sock);
14508 nc->err = 0;
14509}
14510
14512 union socket_address *sa) {
14513 int proto = 0;
14514 if (nc->flags & MG_F_SSL) proto = SL_SEC_SOCKET;
14515 sock_t sock = mg_open_listening_socket(nc, sa, SOCK_STREAM, proto);
14516 if (sock < 0) return sock;
14517 mg_sock_set(nc, sock);
14518 return 0;
14519}
14520
14522 union socket_address *sa) {
14523 sock_t sock = mg_open_listening_socket(nc, sa, SOCK_DGRAM, 0);
14524 if (sock == INVALID_SOCKET) return (errno ? errno : 1);
14525 mg_sock_set(nc, sock);
14526 return 0;
14527}
14528
14529static int mg_sl_if_tcp_send(struct mg_connection *nc, const void *buf,
14530 size_t len) {
14531 int n = (int) sl_Send(nc->sock, buf, len, 0);
14532 if (n < 0 && !mg_is_error(n)) n = 0;
14533 return n;
14534}
14535
14536static int mg_sl_if_udp_send(struct mg_connection *nc, const void *buf,
14537 size_t len) {
14538 int n = sl_SendTo(nc->sock, buf, len, 0, &nc->sa.sa, sizeof(nc->sa.sin));
14539 if (n < 0 && !mg_is_error(n)) n = 0;
14540 return n;
14541}
14542
14543static int mg_sl_if_tcp_recv(struct mg_connection *nc, void *buf, size_t len) {
14544 int n = sl_Recv(nc->sock, buf, len, 0);
14545 if (n == 0) {
14546 /* Orderly shutdown of the socket, try flushing output. */
14548 } else if (n < 0 && !mg_is_error(n)) {
14549 n = 0;
14550 }
14551 return n;
14552}
14553
14554static int mg_sl_if_udp_recv(struct mg_connection *nc, void *buf, size_t len,
14555 union socket_address *sa, size_t *sa_len) {
14557 int n = sl_RecvFrom(nc->sock, buf, MG_UDP_RECV_BUFFER_SIZE, 0,
14558 (SlSockAddr_t *) sa, &sa_len_t);
14559 *sa_len = sa_len_t;
14560 if (n < 0 && !mg_is_error(n)) n = 0;
14561 return n;
14562}
14563
14564static int mg_sl_if_create_conn(struct mg_connection *nc) {
14565 (void) nc;
14566 return 1;
14567}
14568
14570 if (nc->sock == INVALID_SOCKET) return;
14571 /* For UDP, only close outgoing sockets or listeners. */
14572 if (!(nc->flags & MG_F_UDP) || nc->listener == NULL) {
14573 sl_Close(nc->sock);
14574 }
14575 nc->sock = INVALID_SOCKET;
14576}
14577
14578static int mg_accept_conn(struct mg_connection *lc) {
14579 struct mg_connection *nc;
14580 union socket_address sa;
14581 socklen_t sa_len = sizeof(sa);
14582 sock_t sock = sl_Accept(lc->sock, &sa.sa, &sa_len);
14583 if (sock < 0) {
14584 DBG(("%p: failed to accept: %d", lc, sock));
14585 return 0;
14586 }
14587 nc = mg_if_accept_new_conn(lc);
14588 if (nc == NULL) {
14589 sl_Close(sock);
14590 return 0;
14591 }
14592 DBG(("%p conn from %s:%d", nc, inet_ntoa(sa.sin.sin_addr),
14593 ntohs(sa.sin.sin_port)));
14594 mg_sock_set(nc, sock);
14596 return 1;
14597}
14598
14599/* 'sa' must be an initialized address to bind to */
14601 union socket_address *sa, int type,
14602 int proto) {
14603 int r;
14605 (sa->sa.sa_family == AF_INET) ? sizeof(sa->sin) : sizeof(sa->sin6);
14606 sock_t sock = sl_Socket(sa->sa.sa_family, type, proto);
14607 if (sock < 0) return sock;
14608#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
14609 if ((r = sl_set_ssl_opts(sock, nc)) < 0) goto clean;
14610#endif
14611 if ((r = sl_Bind(sock, &sa->sa, sa_len)) < 0) goto clean;
14612 if (type != SOCK_DGRAM) {
14613 if ((r = sl_Listen(sock, SOMAXCONN)) < 0) goto clean;
14614 }
14616clean:
14617 if (r < 0) {
14618 sl_Close(sock);
14619 sock = r;
14620 }
14621 return sock;
14622}
14623
14624#define _MG_F_FD_CAN_READ 1
14625#define _MG_F_FD_CAN_WRITE 1 << 1
14626#define _MG_F_FD_ERROR 1 << 2
14627
14628void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
14629 DBG(("%p fd=%d fd_flags=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock,
14630 fd_flags, nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
14631
14632 if (!mg_if_poll(nc, now)) return;
14633
14634 if (nc->flags & MG_F_CONNECTING) {
14635 if ((nc->flags & MG_F_UDP) || nc->err != SL_ERROR_BSD_EALREADY) {
14636 mg_if_connect_cb(nc, nc->err);
14637 } else {
14638 /* In SimpleLink, to get status of non-blocking connect() we need to wait
14639 * until socket is writable and repeat the call to sl_Connect again,
14640 * which will now return the real status. */
14642 nc->err = sl_Connect(nc->sock, &nc->sa.sa, sizeof(nc->sa.sin));
14643 DBG(("%p conn res=%d", nc, nc->err));
14644 if (nc->err == SL_ERROR_BSD_ESECSNOVERIFY ||
14645 /* TODO(rojer): Provide API to set the date for verification. */
14647#if SL_MAJOR_VERSION_NUM >= 2
14648 /* Per SWRU455, this error does not mean verification failed,
14649 * it only means that the cert used is not present in the trusted
14650 * root CA catalog. Which is perfectly fine. */
14651 ||
14653#endif
14654 ) {
14655 nc->err = 0;
14656 }
14657 mg_if_connect_cb(nc, nc->err);
14658 }
14659 }
14660 /* Ignore read/write in further processing, we've handled it. */
14662 }
14663
14665 if (nc->flags & MG_F_UDP) {
14667 } else {
14668 if (nc->flags & MG_F_LISTENING) {
14669 mg_accept_conn(nc);
14670 } else {
14672 }
14673 }
14674 }
14675
14678 }
14679
14680 DBG(("%p after fd=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock, nc->flags,
14681 (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
14682}
14683
14684/* Associate a socket to a connection. */
14687 nc->sock = sock;
14688 DBG(("%p %d", nc, sock));
14689}
14690
14691void mg_sl_if_init(struct mg_iface *iface) {
14692 (void) iface;
14693 DBG(("%p using sl_Select()", iface->mgr));
14694}
14695
14696void mg_sl_if_free(struct mg_iface *iface) {
14697 (void) iface;
14698}
14699
14701 (void) nc;
14702}
14703
14705 (void) nc;
14706}
14707
14709 struct mg_mgr *mgr = iface->mgr;
14710 double now = mg_time();
14711 double min_timer;
14712 struct mg_connection *nc, *tmp;
14713 struct SlTimeval_t tv;
14716 int num_fds, num_ev = 0, num_timers = 0;
14717
14721
14722 /*
14723 * Note: it is ok to have connections with sock == INVALID_SOCKET in the list,
14724 * e.g. timer-only "connections".
14725 */
14726 min_timer = 0;
14727 for (nc = mgr->active_connections, num_fds = 0; nc != NULL; nc = tmp) {
14728 tmp = nc->next;
14729
14730 if (nc->sock != INVALID_SOCKET) {
14731 num_fds++;
14732
14733 if (!(nc->flags & MG_F_WANT_WRITE) &&
14734 nc->recv_mbuf.len < nc->recv_mbuf_limit &&
14735 (!(nc->flags & MG_F_UDP) || nc->listener == NULL)) {
14737 if (max_fd == INVALID_SOCKET || nc->sock > max_fd) max_fd = nc->sock;
14738 }
14739
14740 if (((nc->flags & MG_F_CONNECTING) && !(nc->flags & MG_F_WANT_READ)) ||
14741 (nc->send_mbuf.len > 0 && !(nc->flags & MG_F_CONNECTING))) {
14744 if (max_fd == INVALID_SOCKET || nc->sock > max_fd) max_fd = nc->sock;
14745 }
14746 }
14747
14748 if (nc->ev_timer_time > 0) {
14749 if (num_timers == 0 || nc->ev_timer_time < min_timer) {
14751 }
14752 num_timers++;
14753 }
14754 }
14755
14756 /*
14757 * If there is a timer to be fired earlier than the requested timeout,
14758 * adjust the timeout.
14759 */
14760 if (num_timers > 0) {
14761 double timer_timeout_ms = (min_timer - mg_time()) * 1000 + 1 /* rounding */;
14764 }
14765 }
14766 if (timeout_ms < 0) timeout_ms = 0;
14767
14768 tv.tv_sec = timeout_ms / 1000;
14769 tv.tv_usec = (timeout_ms % 1000) * 1000;
14770
14771 if (num_fds > 0) {
14772 num_ev = sl_Select((int) max_fd + 1, &read_set, &write_set, &err_set, &tv);
14773 }
14774
14775 now = mg_time();
14776 DBG(("sl_Select @ %ld num_ev=%d of %d, timeout=%d", (long) now, num_ev,
14778
14779 for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
14780 int fd_flags = 0;
14781 if (nc->sock != INVALID_SOCKET) {
14782 if (num_ev > 0) {
14783 fd_flags =
14785 (!(nc->flags & MG_F_UDP) || nc->listener == NULL)
14787 : 0) |
14789 : 0) |
14791 }
14792 /* SimpleLink does not report UDP sockets as writable. */
14793 if (nc->flags & MG_F_UDP && nc->send_mbuf.len > 0) {
14795 }
14796 }
14797 tmp = nc->next;
14799 }
14800
14801 return now;
14802}
14803
14805 union socket_address *sa) {
14806 /* SimpleLink does not provide a way to get socket's peer address after
14807 * accept or connect. Address should have been preserved in the connection,
14808 * so we do our best here by using it. */
14809 if (remote) memcpy(sa, &nc->sa, sizeof(*sa));
14810}
14811
14812void sl_restart_cb(struct mg_mgr *mgr) {
14813 /*
14814 * SimpleLink has been restarted, meaning all sockets have been invalidated.
14815 * We try our best - we'll restart the listeners, but for outgoing
14816 * connections we have no option but to terminate.
14817 */
14818 struct mg_connection *nc;
14819 for (nc = mg_next(mgr, NULL); nc != NULL; nc = mg_next(mgr, nc)) {
14820 if (nc->sock == INVALID_SOCKET) continue; /* Could be a timer */
14821 if (nc->flags & MG_F_LISTENING) {
14822 DBG(("restarting %p %s:%d", nc, inet_ntoa(nc->sa.sin.sin_addr),
14823 ntohs(nc->sa.sin.sin_port)));
14824 int res = (nc->flags & MG_F_UDP ? mg_sl_if_listen_udp(nc, &nc->sa)
14825 : mg_sl_if_listen_tcp(nc, &nc->sa));
14826 if (res == 0) continue;
14827 /* Well, we tried and failed. Fall through to closing. */
14828 }
14829 nc->sock = INVALID_SOCKET;
14830 DBG(("terminating %p %s:%d", nc, inet_ntoa(nc->sa.sin.sin_addr),
14831 ntohs(nc->sa.sin.sin_port)));
14832 /* TODO(rojer): Outgoing UDP? */
14834 }
14835}
14836
14837/* clang-format off */
14838#define MG_SL_IFACE_VTABLE \
14839 { \
14840 mg_sl_if_init, \
14841 mg_sl_if_free, \
14842 mg_sl_if_add_conn, \
14843 mg_sl_if_remove_conn, \
14844 mg_sl_if_poll, \
14845 mg_sl_if_listen_tcp, \
14846 mg_sl_if_listen_udp, \
14847 mg_sl_if_connect_tcp, \
14848 mg_sl_if_connect_udp, \
14849 mg_sl_if_tcp_send, \
14850 mg_sl_if_udp_send, \
14851 mg_sl_if_tcp_recv, \
14852 mg_sl_if_udp_recv, \
14853 mg_sl_if_create_conn, \
14854 mg_sl_if_destroy_conn, \
14855 mg_sl_if_sock_set, \
14856 mg_sl_if_get_conn_addr, \
14857 }
14858/* clang-format on */
14859
14861#if MG_NET_IF == MG_NET_IF_SIMPLELINK
14863#endif
14864
14865#endif /* MG_ENABLE_NET_IF_SIMPLELINK */
14866#ifdef MG_MODULE_LINES
14867#line 1 "common/platforms/simplelink/sl_ssl_if.c"
14868#endif
14869/*
14870 * Copyright (c) 2014-2018 Cesanta Software Limited
14871 * All rights reserved
14872 *
14873 * Licensed under the Apache License, Version 2.0 (the ""License"");
14874 * you may not use this file except in compliance with the License.
14875 * You may obtain a copy of the License at
14876 *
14877 * http://www.apache.org/licenses/LICENSE-2.0
14878 *
14879 * Unless required by applicable law or agreed to in writing, software
14880 * distributed under the License is distributed on an ""AS IS"" BASIS,
14881 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14882 * See the License for the specific language governing permissions and
14883 * limitations under the License.
14884 */
14885
14886#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
14887
14888/* Amalgamated: #include "common/mg_mem.h" */
14889
14890#ifndef MG_SSL_IF_SIMPLELINK_SLFS_PREFIX
14891#define MG_SSL_IF_SIMPLELINK_SLFS_PREFIX "SL:"
14892#endif
14893
14894#define MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN \
14895 (sizeof(MG_SSL_IF_SIMPLELINK_SLFS_PREFIX) - 1)
14896
14897struct mg_ssl_if_ctx {
14898 char *ssl_cert;
14899 char *ssl_key;
14900 char *ssl_ca_cert;
14901 char *ssl_server_name;
14902};
14903
14904void mg_ssl_if_init() {
14905}
14906
14908 struct mg_connection *nc, const struct mg_ssl_if_conn_params *params,
14909 const char **err_msg) {
14910 struct mg_ssl_if_ctx *ctx =
14911 (struct mg_ssl_if_ctx *) MG_CALLOC(1, sizeof(*ctx));
14912 if (ctx == NULL) {
14913 MG_SET_PTRPTR(err_msg, "Out of memory");
14914 return MG_SSL_ERROR;
14915 }
14916 nc->ssl_if_data = ctx;
14917
14918 if (params->cert != NULL || params->key != NULL) {
14919 if (params->cert != NULL && params->key != NULL) {
14920 ctx->ssl_cert = strdup(params->cert);
14921 ctx->ssl_key = strdup(params->key);
14922 } else {
14923 MG_SET_PTRPTR(err_msg, "Both cert and key are required.");
14924 return MG_SSL_ERROR;
14925 }
14926 }
14927 if (params->ca_cert != NULL && strcmp(params->ca_cert, "*") != 0) {
14928 ctx->ssl_ca_cert = strdup(params->ca_cert);
14929 }
14930 /* TODO(rojer): cipher_suites. */
14931 if (params->server_name != NULL) {
14932 ctx->ssl_server_name = strdup(params->server_name);
14933 }
14934 return MG_SSL_OK;
14935}
14936
14938 struct mg_connection *lc) {
14939 /* SimpleLink does everything for us, nothing for us to do. */
14940 (void) nc;
14941 (void) lc;
14942 return MG_SSL_OK;
14943}
14944
14946 /* SimpleLink has already performed the handshake, nothing to do. */
14947 return MG_SSL_OK;
14948}
14949
14950int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t len) {
14951 /* SimpelLink handles TLS, so this is just a pass-through. */
14952 int n = nc->iface->vtable->tcp_recv(nc, buf, len);
14953 if (n == 0) nc->flags |= MG_F_WANT_READ;
14954 return n;
14955}
14956
14957int mg_ssl_if_write(struct mg_connection *nc, const void *buf, size_t len) {
14958 /* SimpelLink handles TLS, so this is just a pass-through. */
14959 return nc->iface->vtable->tcp_send(nc, buf, len);
14960}
14961
14963 /* Nothing to do */
14964 (void) nc;
14965}
14966
14967void mg_ssl_if_conn_free(struct mg_connection *nc) {
14968 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
14969 if (ctx == NULL) return;
14970 nc->ssl_if_data = NULL;
14971 MG_FREE(ctx->ssl_cert);
14972 MG_FREE(ctx->ssl_key);
14973 MG_FREE(ctx->ssl_ca_cert);
14974 MG_FREE(ctx->ssl_server_name);
14975 memset(ctx, 0, sizeof(*ctx));
14976 MG_FREE(ctx);
14977}
14978
14979bool pem_to_der(const char *pem_file, const char *der_file) {
14980 bool ret = false;
14981 FILE *pf = NULL, *df = NULL;
14982 bool writing = false;
14983 pf = fopen(pem_file, "r");
14984 if (pf == NULL) goto clean;
14987 df = fopen(der_file, "w");
14989 if (df == NULL) goto clean;
14990 while (1) {
14991 char pem_buf[70];
14992 char der_buf[48];
14993 if (!fgets(pem_buf, sizeof(pem_buf), pf)) break;
14994 if (writing) {
14995 if (strstr(pem_buf, "-----END ") != NULL) {
14996 ret = true;
14997 break;
14998 }
14999 int l = 0;
15000 while (!isspace((unsigned int) pem_buf[l])) l++;
15001 int der_len = 0;
15002 cs_base64_decode((const unsigned char *) pem_buf, sizeof(pem_buf),
15003 der_buf, &der_len);
15004 if (der_len <= 0) break;
15005 if (fwrite(der_buf, 1, der_len, df) != der_len) break;
15006 } else if (strstr(pem_buf, "-----BEGIN ") != NULL) {
15007 writing = true;
15008 }
15009 }
15010
15011clean:
15012 if (pf != NULL) fclose(pf);
15013 if (df != NULL) {
15014 fclose(df);
15015 if (!ret) remove(der_file);
15016 }
15017 return ret;
15018}
15019
15020#if MG_ENABLE_FILESYSTEM && defined(MG_FS_SLFS)
15021/* If the file's extension is .pem, convert it to DER format and put on SLFS. */
15022static char *sl_pem2der(const char *pem_file) {
15023 const char *pem_ext = strstr(pem_file, ".pem");
15024 if (pem_ext == NULL || *(pem_ext + 4) != '\0') {
15025 return strdup(pem_file);
15026 }
15027 char *der_file = NULL;
15028 /* DER file must be located on SLFS, add prefix. */
15030 (int) (pem_ext - pem_file), pem_file);
15031 if (der_file == NULL) return NULL;
15032 bool result = false;
15033 cs_stat_t st;
15034 if (mg_stat(der_file, &st) != 0) {
15035 result = pem_to_der(pem_file, der_file);
15036 LOG(LL_DEBUG, ("%s -> %s = %d", pem_file, der_file, result));
15037 } else {
15038 /* File exists, assume it's already been converted. */
15039 result = true;
15040 }
15041 if (result) {
15042 /* Strip the SL: prefix we added since NWP does not expect it. */
15044 l - 2 /* including \0 */);
15045 } else {
15047 der_file = NULL;
15048 }
15049 return der_file;
15050}
15051#else
15052static char *sl_pem2der(const char *pem_file) {
15053 return strdup(pem_file);
15054}
15055#endif
15056
15057int sl_set_ssl_opts(int sock, struct mg_connection *nc) {
15058 int err;
15059 const struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
15060 DBG(("%p ssl ctx: %p", nc, ctx));
15061
15062 if (ctx == NULL) return 0;
15063 DBG(("%p %s,%s,%s,%s", nc, (ctx->ssl_cert ? ctx->ssl_cert : "-"),
15064 (ctx->ssl_key ? ctx->ssl_cert : "-"),
15065 (ctx->ssl_ca_cert ? ctx->ssl_ca_cert : "-"),
15066 (ctx->ssl_server_name ? ctx->ssl_server_name : "-")));
15067 if (ctx->ssl_cert != NULL && ctx->ssl_key != NULL) {
15068 char *ssl_cert = sl_pem2der(ctx->ssl_cert), *ssl_key = NULL;
15069 if (ssl_cert != NULL) {
15070 err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
15072 strlen(ssl_cert));
15074 LOG(LL_DEBUG, ("CERTIFICATE_FILE_NAME %s -> %d", ssl_cert, err));
15075 ssl_key = sl_pem2der(ctx->ssl_key);
15076 if (ssl_key != NULL) {
15077 err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
15079 strlen(ssl_key));
15081 LOG(LL_DEBUG, ("PRIVATE_KEY_FILE_NAME %s -> %d", ssl_key, err));
15082 } else {
15083 err = -1;
15084 }
15085 } else {
15086 err = -1;
15087 }
15088 if (err != 0) return err;
15089 }
15090 if (ctx->ssl_ca_cert != NULL) {
15091 if (ctx->ssl_ca_cert[0] != '\0') {
15092 char *ssl_ca_cert = sl_pem2der(ctx->ssl_ca_cert);
15093 if (ssl_ca_cert != NULL) {
15094 err =
15097 LOG(LL_DEBUG, ("CA_FILE_NAME %s -> %d", ssl_ca_cert, err));
15098 } else {
15099 err = -1;
15100 }
15102 if (err != 0) return err;
15103 }
15104 }
15105 if (ctx->ssl_server_name != NULL) {
15106 err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
15108 ctx->ssl_server_name, strlen(ctx->ssl_server_name));
15109 DBG(("DOMAIN_NAME_VERIFICATION %s -> %d", ctx->ssl_server_name, err));
15110 /* Domain name verificationw as added in a NWP service pack, older
15111 * versions return SL_ERROR_BSD_ENOPROTOOPT. There isn't much we can do
15112 * about it,
15113 * so we ignore the error. */
15114 if (err != 0 && err != SL_ERROR_BSD_ENOPROTOOPT) return err;
15115 }
15116 return 0;
15117}
15118
15119#endif /* MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK */
15120#ifdef MG_MODULE_LINES
15121#line 1 "common/platforms/lwip/mg_lwip_net_if.h"
15122#endif
15123/*
15124 * Copyright (c) 2014-2018 Cesanta Software Limited
15125 * All rights reserved
15126 *
15127 * Licensed under the Apache License, Version 2.0 (the ""License"");
15128 * you may not use this file except in compliance with the License.
15129 * You may obtain a copy of the License at
15130 *
15131 * http://www.apache.org/licenses/LICENSE-2.0
15132 *
15133 * Unless required by applicable law or agreed to in writing, software
15134 * distributed under the License is distributed on an ""AS IS"" BASIS,
15135 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15136 * See the License for the specific language governing permissions and
15137 * limitations under the License.
15138 */
15139
15140#ifndef CS_COMMON_PLATFORMS_LWIP_MG_NET_IF_LWIP_H_
15141#define CS_COMMON_PLATFORMS_LWIP_MG_NET_IF_LWIP_H_
15142
15143#ifndef MG_ENABLE_NET_IF_LWIP_LOW_LEVEL
15144#define MG_ENABLE_NET_IF_LWIP_LOW_LEVEL MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL
15145#endif
15146
15147#if MG_ENABLE_NET_IF_LWIP_LOW_LEVEL
15148
15149#include <stdint.h>
15150
15151extern const struct mg_iface_vtable mg_lwip_iface_vtable;
15152
15156 union {
15157 struct tcp_pcb *tcp;
15158 struct udp_pcb *udp;
15161 size_t num_sent; /* Number of acknowledged bytes to be reported to the core */
15162 struct pbuf *rx_chain; /* Chain of incoming data segments. */
15163 size_t rx_offset; /* Offset within the first pbuf (if partially consumed) */
15164 /* Last SSL write size, for retries. */
15166 /* Whether MG_SIG_RECV is already pending for this connection */
15168 /* Whether the connection is about to close, just `rx_chain` needs to drain */
15170};
15171
15179
15180void mg_lwip_post_signal(enum mg_sig_type sig, struct mg_connection *nc);
15181
15182/* To be implemented by the platform. */
15184
15185#endif /* MG_ENABLE_NET_IF_LWIP_LOW_LEVEL */
15186
15187#endif /* CS_COMMON_PLATFORMS_LWIP_MG_NET_IF_LWIP_H_ */
15188#ifdef MG_MODULE_LINES
15189#line 1 "common/platforms/lwip/mg_lwip_net_if.c"
15190#endif
15191/*
15192 * Copyright (c) 2014-2018 Cesanta Software Limited
15193 * All rights reserved
15194 *
15195 * Licensed under the Apache License, Version 2.0 (the ""License"");
15196 * you may not use this file except in compliance with the License.
15197 * You may obtain a copy of the License at
15198 *
15199 * http://www.apache.org/licenses/LICENSE-2.0
15200 *
15201 * Unless required by applicable law or agreed to in writing, software
15202 * distributed under the License is distributed on an ""AS IS"" BASIS,
15203 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15204 * See the License for the specific language governing permissions and
15205 * limitations under the License.
15206 */
15207
15208#if MG_ENABLE_NET_IF_LWIP_LOW_LEVEL
15209
15210/* Amalgamated: #include "common/mg_mem.h" */
15211
15212#include <lwip/init.h>
15213#include <lwip/pbuf.h>
15214#include <lwip/tcp.h>
15215#include <lwip/tcpip.h>
15216#if ((LWIP_VERSION_MAJOR << 8) | LWIP_VERSION_MINOR) >= 0x0105
15217#include <lwip/priv/tcp_priv.h> /* For tcp_seg */
15218#else
15219#include <lwip/tcp_impl.h>
15220#endif
15221#include <lwip/udp.h>
15222
15223/* Amalgamated: #include "common/cs_dbg.h" */
15224
15225/*
15226 * Newest versions of LWIP have ip_2_ip4, older have ipX_2_ip,
15227 * even older have nothing.
15228 */
15229#ifndef ip_2_ip4
15230#ifdef ipX_2_ip
15231#define ip_2_ip4(addr) ipX_2_ip(addr)
15232#else
15233#define ip_2_ip4(addr) (addr)
15234#endif
15235#endif
15236
15237/*
15238 * Depending on whether Mongoose is compiled with ipv6 support, use right
15239 * lwip functions
15240 */
15241#if MG_ENABLE_IPV6
15242#define TCP_NEW tcp_new_ip6
15243#define TCP_BIND tcp_bind_ip6
15244#define UDP_BIND udp_bind_ip6
15245#define IPADDR_NTOA(x) ip6addr_ntoa((const ip6_addr_t *)(x))
15246#define SET_ADDR(dst, src) \
15247 memcpy((dst)->sin6.sin6_addr.s6_addr, (src)->ip6.addr, \
15248 sizeof((dst)->sin6.sin6_addr.s6_addr))
15249#else
15250#define TCP_NEW tcp_new
15251#define TCP_BIND tcp_bind
15252#define UDP_BIND udp_bind
15253#define IPADDR_NTOA ipaddr_ntoa
15254#define SET_ADDR(dst, src) (dst)->sin.sin_addr.s_addr = ip_2_ip4(src)->addr
15255#endif
15256
15257#if NO_SYS
15258#define tcpip_callback(fn, arg) (fn)(arg)
15259typedef void (*tcpip_callback_fn)(void *arg);
15260#endif
15261
15262void mg_lwip_if_init(struct mg_iface *iface);
15263void mg_lwip_if_free(struct mg_iface *iface);
15264void mg_lwip_if_add_conn(struct mg_connection *nc);
15265void mg_lwip_if_remove_conn(struct mg_connection *nc);
15266time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms);
15267
15268#if defined(RTOS_SDK) || defined(ESP_PLATFORM)
15269extern void mgos_lock();
15270extern void mgos_unlock();
15271#else
15272#define mgos_lock()
15273#define mgos_unlock()
15274#endif
15275
15276static void mg_lwip_recv_common(struct mg_connection *nc, struct pbuf *p);
15277
15278#if LWIP_TCP_KEEPALIVE
15280 int interval, int count) {
15281 if (nc->sock == INVALID_SOCKET || nc->flags & MG_F_UDP) {
15282 return;
15283 }
15284 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15285 struct tcp_pcb *tpcb = cs->pcb.tcp;
15286 if (idle > 0 && interval > 0 && count > 0) {
15287 tpcb->keep_idle = idle * 1000;
15288 tpcb->keep_intvl = interval * 1000;
15289 tpcb->keep_cnt = count;
15290 tpcb->so_options |= SOF_KEEPALIVE;
15291 } else {
15292 tpcb->so_options &= ~SOF_KEEPALIVE;
15293 }
15294}
15295#elif !defined(MG_NO_LWIP_TCP_KEEPALIVE)
15296#warning LWIP TCP keepalive is disabled. Please consider enabling it.
15297#endif /* LWIP_TCP_KEEPALIVE */
15298
15299static err_t mg_lwip_tcp_conn_cb(void *arg, struct tcp_pcb *tpcb, err_t err) {
15300 struct mg_connection *nc = (struct mg_connection *) arg;
15301 DBG(("%p connect to %s:%u = %d", nc, IPADDR_NTOA(ipX_2_ip(&tpcb->remote_ip)),
15302 tpcb->remote_port, err));
15303 if (nc == NULL) {
15304 tcp_abort(tpcb);
15305 return ERR_ARG;
15306 }
15307 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15308 cs->err = err;
15309#if LWIP_TCP_KEEPALIVE
15310 if (err == 0) mg_lwip_set_keepalive_params(nc, 60, 10, 6);
15311#endif
15313 return ERR_OK;
15314}
15315
15316static void mg_lwip_tcp_error_cb(void *arg, err_t err) {
15317 struct mg_connection *nc = (struct mg_connection *) arg;
15318 DBG(("%p conn error %d", nc, err));
15319 if (nc == NULL || (nc->flags & MG_F_CLOSE_IMMEDIATELY)) return;
15320 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15321 cs->pcb.tcp = NULL; /* Has already been deallocated */
15322 if (nc->flags & MG_F_CONNECTING) {
15323 cs->err = err;
15325 } else {
15327 }
15328}
15329
15330static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb,
15331 struct pbuf *p, err_t err) {
15332 struct mg_connection *nc = (struct mg_connection *) arg;
15333 struct mg_lwip_conn_state *cs =
15334 (nc ? (struct mg_lwip_conn_state *) nc->sock : NULL);
15335 DBG(("%p %p %p %p %u %d", nc, cs, tpcb, p, (p != NULL ? p->tot_len : 0),
15336 err));
15337 if (p == NULL) {
15338 if (nc != NULL && !(nc->flags & MG_F_CLOSE_IMMEDIATELY)) {
15339 if (cs->rx_chain != NULL) {
15340 /*
15341 * rx_chain still contains non-consumed data, don't close the
15342 * connection
15343 */
15344 cs->draining_rx_chain = 1;
15345 } else {
15347 }
15348 } else {
15349 /* Tombstoned connection, do nothing. */
15350 }
15351 return ERR_OK;
15352 } else if (nc == NULL) {
15353 tcp_abort(tpcb);
15354 return ERR_ARG;
15355 }
15356 /*
15357 * If we get a chain of more than one segment at once, we need to bump
15358 * refcount on the subsequent bufs to make them independent.
15359 */
15360 if (p->next != NULL) {
15361 struct pbuf *q = p->next;
15362 for (; q != NULL; q = q->next) pbuf_ref(q);
15363 }
15364 mgos_lock();
15365 if (cs->rx_chain == NULL) {
15366 cs->rx_offset = 0;
15367 } else if (pbuf_clen(cs->rx_chain) >= 4) {
15368 /* ESP SDK has a limited pool of 5 pbufs. We must not hog them all or RX
15369 * will be completely blocked. We already have at least 4 in the chain,
15370 * this one is the last, so we have to make a copy and release this one. */
15371 struct pbuf *np = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
15372 if (np != NULL) {
15373 pbuf_copy(np, p);
15374 pbuf_free(p);
15375 p = np;
15376 }
15377 }
15378 mg_lwip_recv_common(nc, p);
15379 mgos_unlock();
15380 (void) err;
15381 return ERR_OK;
15382}
15383
15384static err_t mg_lwip_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb,
15385 u16_t num_sent) {
15386 struct mg_connection *nc = (struct mg_connection *) arg;
15387 DBG(("%p %p %u %p %p", nc, tpcb, num_sent, tpcb->unsent, tpcb->unacked));
15388 if (nc == NULL) return ERR_OK;
15389 if ((nc->flags & MG_F_SEND_AND_CLOSE) && !(nc->flags & MG_F_WANT_WRITE) &&
15390 nc->send_mbuf.len == 0 && tpcb->unsent == NULL && tpcb->unacked == NULL) {
15392 }
15393 if (nc->send_mbuf.len > 0 || (nc->flags & MG_F_WANT_WRITE)) {
15395 }
15396 (void) num_sent;
15397 return ERR_OK;
15398}
15399
15402 const union socket_address *sa;
15403};
15404
15405static void mg_lwip_if_connect_tcp_tcpip(void *arg) {
15406 struct mg_lwip_if_connect_tcp_ctx *ctx =
15407 (struct mg_lwip_if_connect_tcp_ctx *) arg;
15408 struct mg_connection *nc = ctx->nc;
15409 const union socket_address *sa = ctx->sa;
15410
15411 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15412 struct tcp_pcb *tpcb = TCP_NEW();
15413 cs->pcb.tcp = tpcb;
15414 ip_addr_t *ip = (ip_addr_t *) &sa->sin.sin_addr.s_addr;
15415 u16_t port = ntohs(sa->sin.sin_port);
15416 tcp_arg(tpcb, nc);
15419 tcp_recv(tpcb, mg_lwip_tcp_recv_cb);
15420 cs->err = TCP_BIND(tpcb, IP_ADDR_ANY, 0 /* any port */);
15421 DBG(("%p tcp_bind = %d", nc, cs->err));
15422 if (cs->err != ERR_OK) {
15424 return;
15425 }
15426 cs->err = tcp_connect(tpcb, ip, port, mg_lwip_tcp_conn_cb);
15427 DBG(("%p tcp_connect %p = %d", nc, tpcb, cs->err));
15428 if (cs->err != ERR_OK) {
15430 return;
15431 }
15432}
15433
15435 const union socket_address *sa) {
15436 struct mg_lwip_if_connect_tcp_ctx ctx = {.nc = nc, .sa = sa};
15438}
15439
15440/*
15441 * Lwip included in the SDKs for nRF5x chips has different type for the
15442 * callback of `udp_recv()`
15443 */
15444#if ((LWIP_VERSION_MAJOR << 8) | LWIP_VERSION_MINOR) >= 0x0105
15445static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p,
15446 const ip_addr_t *addr, u16_t port)
15447#else
15448static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p,
15449 ip_addr_t *addr, u16_t port)
15450#endif
15451{
15452 struct mg_connection *nc = (struct mg_connection *) arg;
15453 DBG(("%p %s:%u %p %u %u", nc, IPADDR_NTOA(addr), port, p, p->ref, p->len));
15454 /* Put address in a separate pbuf and tack it onto the packet. */
15455 struct pbuf *sap =
15456 pbuf_alloc(PBUF_RAW, sizeof(union socket_address), PBUF_RAM);
15457 if (sap == NULL) {
15458 pbuf_free(p);
15459 return;
15460 }
15461 union socket_address *sa = (union socket_address *) sap->payload;
15462#if ((LWIP_VERSION_MAJOR << 8) | LWIP_VERSION_MINOR) >= 0x0105
15463 sa->sin.sin_addr.s_addr = ip_2_ip4(addr)->addr;
15464#else
15465 sa->sin.sin_addr.s_addr = addr->addr;
15466#endif
15467 sa->sin.sin_port = htons(port);
15468 /* Logic in the recv handler requires that there be exactly one data pbuf. */
15469 p = pbuf_coalesce(p, PBUF_RAW);
15470 pbuf_chain(sap, p);
15471 mgos_lock();
15473 mgos_unlock();
15474 (void) pcb;
15475}
15476
15477static void mg_lwip_recv_common(struct mg_connection *nc, struct pbuf *p) {
15478 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15479 if (cs->rx_chain == NULL) {
15480 cs->rx_chain = p;
15481 } else {
15482 pbuf_chain(cs->rx_chain, p);
15483 }
15484 if (!cs->recv_pending) {
15485 cs->recv_pending = 1;
15487 }
15488}
15489
15490static int mg_lwip_if_udp_recv(struct mg_connection *nc, void *buf, size_t len,
15491 union socket_address *sa, size_t *sa_len) {
15492 /*
15493 * For UDP, RX chain consists of interleaved address and packet bufs:
15494 * Address pbuf followed by exactly one data pbuf (recv_cb took care of that).
15495 */
15496 int res = 0;
15497 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15498 if (nc->sock == INVALID_SOCKET) return -1;
15499 mgos_lock();
15500 if (cs->rx_chain != NULL) {
15501 struct pbuf *ap = cs->rx_chain;
15502 struct pbuf *dp = ap->next;
15503 cs->rx_chain = pbuf_dechain(dp);
15504 res = MIN(dp->len, len);
15505 pbuf_copy_partial(dp, buf, res, 0);
15506 pbuf_free(dp);
15507 pbuf_copy_partial(ap, sa, MIN(*sa_len, ap->len), 0);
15508 pbuf_free(ap);
15509 }
15510 mgos_unlock();
15511 return res;
15512}
15513
15514static void mg_lwip_if_connect_udp_tcpip(void *arg) {
15515 struct mg_connection *nc = (struct mg_connection *) arg;
15516 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15517 struct udp_pcb *upcb = udp_new();
15518 cs->err = UDP_BIND(upcb, IP_ADDR_ANY, 0 /* any port */);
15519 DBG(("%p udp_bind %p = %d", nc, upcb, cs->err));
15520 if (cs->err == ERR_OK) {
15521 udp_recv(upcb, mg_lwip_udp_recv_cb, nc);
15522 cs->pcb.udp = upcb;
15523 } else {
15524 udp_remove(upcb);
15525 }
15527}
15528
15532
15533static void tcp_close_tcpip(void *arg) {
15534 tcp_close((struct tcp_pcb *) arg);
15535}
15536
15538 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15539 if (cs->pcb.tcp == NULL) return;
15540 union socket_address sa;
15541 struct tcp_pcb *tpcb = cs->pcb.tcp;
15542 SET_ADDR(&sa, &tpcb->remote_ip);
15543 sa.sin.sin_port = htons(tpcb->remote_port);
15544 mg_if_accept_tcp_cb(nc, &sa, sizeof(sa.sin));
15545}
15546
15547static err_t mg_lwip_accept_cb(void *arg, struct tcp_pcb *newtpcb, err_t err) {
15548 struct mg_connection *lc = (struct mg_connection *) arg, *nc;
15549 struct mg_lwip_conn_state *lcs, *cs;
15550 struct tcp_pcb_listen *lpcb;
15551 LOG(LL_DEBUG,
15552 ("%p conn %p from %s:%u", lc, newtpcb,
15553 IPADDR_NTOA(ipX_2_ip(&newtpcb->remote_ip)), newtpcb->remote_port));
15554 if (lc == NULL) {
15556 return ERR_ABRT;
15557 }
15558 lcs = (struct mg_lwip_conn_state *) lc->sock;
15559 lpcb = (struct tcp_pcb_listen *) lcs->pcb.tcp;
15560#if TCP_LISTEN_BACKLOG
15562#endif
15563 nc = mg_if_accept_new_conn(lc);
15564 if (nc == NULL) {
15566 return ERR_ABRT;
15567 }
15568 cs = (struct mg_lwip_conn_state *) nc->sock;
15569 cs->lc = lc;
15570 cs->pcb.tcp = newtpcb;
15571 /* We need to set up callbacks before returning because data may start
15572 * arriving immediately. */
15573 tcp_arg(newtpcb, nc);
15576 tcp_recv(newtpcb, mg_lwip_tcp_recv_cb);
15577#if LWIP_TCP_KEEPALIVE
15578 mg_lwip_set_keepalive_params(nc, 60, 10, 6);
15579#endif
15581 (void) err;
15582 (void) lpcb;
15583 return ERR_OK;
15584}
15585
15591
15592static void mg_lwip_if_listen_tcp_tcpip(void *arg) {
15593 struct mg_lwip_if_listen_ctx *ctx = (struct mg_lwip_if_listen_ctx *) arg;
15594 struct mg_connection *nc = ctx->nc;
15595 union socket_address *sa = ctx->sa;
15596 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15597 struct tcp_pcb *tpcb = TCP_NEW();
15598 ip_addr_t *ip = (ip_addr_t *) &sa->sin.sin_addr.s_addr;
15599 u16_t port = ntohs(sa->sin.sin_port);
15600 cs->err = TCP_BIND(tpcb, ip, port);
15601 DBG(("%p tcp_bind(%s:%u) = %d", nc, IPADDR_NTOA(ip), port, cs->err));
15602 if (cs->err != ERR_OK) {
15603 tcp_close(tpcb);
15604 ctx->ret = -1;
15605 return;
15606 }
15607 tcp_arg(tpcb, nc);
15608 tpcb = tcp_listen(tpcb);
15609 cs->pcb.tcp = tpcb;
15611 ctx->ret = 0;
15612}
15613
15615 struct mg_lwip_if_listen_ctx ctx = {.nc = nc, .sa = sa};
15617 return ctx.ret;
15618}
15619
15620static void mg_lwip_if_listen_udp_tcpip(void *arg) {
15621 struct mg_lwip_if_listen_ctx *ctx = (struct mg_lwip_if_listen_ctx *) arg;
15622 struct mg_connection *nc = ctx->nc;
15623 union socket_address *sa = ctx->sa;
15624 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15625 struct udp_pcb *upcb = udp_new();
15626 ip_addr_t *ip = (ip_addr_t *) &sa->sin.sin_addr.s_addr;
15627 u16_t port = ntohs(sa->sin.sin_port);
15628 cs->err = UDP_BIND(upcb, ip, port);
15629 DBG(("%p udb_bind(%s:%u) = %d", nc, IPADDR_NTOA(ip), port, cs->err));
15630 if (cs->err != ERR_OK) {
15631 udp_remove(upcb);
15632 ctx->ret = -1;
15633 } else {
15634 udp_recv(upcb, mg_lwip_udp_recv_cb, nc);
15635 cs->pcb.udp = upcb;
15636 ctx->ret = 0;
15637 }
15638}
15639
15641 struct mg_lwip_if_listen_ctx ctx = {.nc = nc, .sa = sa};
15643 return ctx.ret;
15644}
15645
15648 const void *data;
15650 int ret;
15651};
15652
15653static void tcp_output_tcpip(void *arg) {
15654 tcp_output((struct tcp_pcb *) arg);
15655}
15656
15657static void mg_lwip_tcp_write_tcpip(void *arg) {
15658 struct mg_lwip_tcp_write_ctx *ctx = (struct mg_lwip_tcp_write_ctx *) arg;
15659 struct mg_connection *nc = ctx->nc;
15660 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15661 struct tcp_pcb *tpcb = cs->pcb.tcp;
15662 size_t len = MIN(tpcb->mss, MIN(ctx->len, tpcb->snd_buf));
15663 size_t unsent, unacked;
15664 if (len == 0) {
15665 DBG(("%p no buf avail %u %u %p %p", tpcb, tpcb->snd_buf, tpcb->snd_queuelen,
15666 tpcb->unsent, tpcb->unacked));
15668 ctx->ret = 0;
15669 return;
15670 }
15671 unsent = (tpcb->unsent != NULL ? tpcb->unsent->len : 0);
15672 unacked = (tpcb->unacked != NULL ? tpcb->unacked->len : 0);
15673/*
15674 * On ESP8266 we only allow one TCP segment in flight at any given time.
15675 * This may increase latency and reduce efficiency of tcp windowing,
15676 * but memory is scarce and precious on that platform so we do this to
15677 * reduce footprint.
15678 */
15679#if CS_PLATFORM == CS_P_ESP8266
15680 if (unacked > 0) {
15681 ctx->ret = 0;
15682 return;
15683 }
15684 len = MIN(len, (TCP_MSS - unsent));
15685#endif
15686 cs->err = tcp_write(tpcb, ctx->data, len, TCP_WRITE_FLAG_COPY);
15687 unsent = (tpcb->unsent != NULL ? tpcb->unsent->len : 0);
15688 unacked = (tpcb->unacked != NULL ? tpcb->unacked->len : 0);
15689 DBG(("%p tcp_write %u = %d, %u %u", tpcb, len, cs->err, unsent, unacked));
15690 if (cs->err != ERR_OK) {
15691 /*
15692 * We ignore ERR_MEM because memory will be freed up when the data is sent
15693 * and we'll retry.
15694 */
15695 ctx->ret = (cs->err == ERR_MEM ? 0 : -1);
15696 return;
15697 }
15698 ctx->ret = len;
15699 (void) unsent;
15700 (void) unacked;
15701}
15702
15703int mg_lwip_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len) {
15704 struct mg_lwip_tcp_write_ctx ctx = {.nc = nc, .data = buf, .len = len};
15705 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15706 if (nc->sock == INVALID_SOCKET) return -1;
15707 struct tcp_pcb *tpcb = cs->pcb.tcp;
15708 if (tpcb == NULL) return -1;
15709 if (tpcb->snd_buf <= 0) return 0;
15711 return ctx.ret;
15712}
15713
15715 struct udp_pcb *upcb;
15716 struct pbuf *p;
15719 int ret;
15720};
15721
15722static void udp_sendto_tcpip(void *arg) {
15723 struct udp_sendto_ctx *ctx = (struct udp_sendto_ctx *) arg;
15724 ctx->ret = udp_sendto(ctx->upcb, ctx->p, ctx->ip, ctx->port);
15725}
15726
15727static int mg_lwip_if_udp_send(struct mg_connection *nc, const void *data,
15728 size_t len) {
15729 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15730 if (nc->sock == INVALID_SOCKET || cs->pcb.udp == NULL) return -1;
15731 struct udp_pcb *upcb = cs->pcb.udp;
15732 struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
15733#if defined(LWIP_IPV4) && LWIP_IPV4 && defined(LWIP_IPV6) && LWIP_IPV6
15734 ip_addr_t ip = {.u_addr.ip4.addr = nc->sa.sin.sin_addr.s_addr, .type = 0};
15735#else
15736 ip_addr_t ip = {.addr = nc->sa.sin.sin_addr.s_addr};
15737#endif
15738 u16_t port = ntohs(nc->sa.sin.sin_port);
15739 if (p == NULL) return 0;
15740 memcpy(p->payload, data, len);
15741 struct udp_sendto_ctx ctx = {.upcb = upcb, .p = p, .ip = &ip, .port = port};
15743 cs->err = ctx.ret;
15744 pbuf_free(p);
15745 return (cs->err == ERR_OK ? (int) len : -2);
15746}
15747
15749 struct mg_lwip_conn_state *cs) {
15750 int can_send = 0;
15751 if (nc->send_mbuf.len > 0 || (nc->flags & MG_F_WANT_WRITE)) {
15752 /* We have stuff to send, but can we? */
15753 if (nc->flags & MG_F_UDP) {
15754 /* UDP is always ready for sending. */
15755 can_send = (cs->pcb.udp != NULL);
15756 } else {
15757 can_send = (cs->pcb.tcp != NULL && cs->pcb.tcp->snd_buf > 0);
15758/* See comment above. */
15759#if CS_PLATFORM == CS_P_ESP8266
15760 if (cs->pcb.tcp->unacked != NULL) can_send = 0;
15761#endif
15762 }
15763 }
15764 return can_send;
15765}
15766
15768 struct tcp_pcb *tpcb;
15769 size_t len;
15770};
15771
15772void tcp_recved_tcpip(void *arg) {
15773 struct tcp_recved_ctx *ctx = (struct tcp_recved_ctx *) arg;
15774 if (ctx->tpcb != NULL) tcp_recved(ctx->tpcb, ctx->len);
15775}
15776
15777static int mg_lwip_if_tcp_recv(struct mg_connection *nc, void *buf,
15778 size_t len) {
15779 int res = 0;
15780 char *bufp = buf;
15781 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15782 if (nc->sock == INVALID_SOCKET) return -1;
15783 mgos_lock();
15784 while (cs->rx_chain != NULL && len > 0) {
15785 struct pbuf *seg = cs->rx_chain;
15786 size_t seg_len = (seg->len - cs->rx_offset);
15787 size_t copy_len = MIN(len, seg_len);
15788
15789 pbuf_copy_partial(seg, bufp, copy_len, cs->rx_offset);
15790 len -= copy_len;
15791 res += copy_len;
15792 bufp += copy_len;
15793 cs->rx_offset += copy_len;
15794 if (cs->rx_offset == cs->rx_chain->len) {
15795 cs->rx_chain = pbuf_dechain(cs->rx_chain);
15796 pbuf_free(seg);
15797 cs->rx_offset = 0;
15798 }
15799 }
15800 mgos_unlock();
15801 if (res > 0) {
15802 struct tcp_recved_ctx ctx = {.tpcb = cs->pcb.tcp, .len = res};
15804 }
15805 return res;
15806}
15807
15809 struct mg_lwip_conn_state *cs =
15810 (struct mg_lwip_conn_state *) MG_CALLOC(1, sizeof(*cs));
15811 if (cs == NULL) return 0;
15812 cs->nc = nc;
15813 nc->sock = (intptr_t) cs;
15814 return 1;
15815}
15816
15817static void udp_remove_tcpip(void *arg) {
15818 udp_remove((struct udp_pcb *) arg);
15819}
15820
15822 if (nc->sock == INVALID_SOCKET) return;
15823 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15824 if (!(nc->flags & MG_F_UDP)) {
15825 struct tcp_pcb *tpcb = cs->pcb.tcp;
15826 if (tpcb != NULL) {
15827 tcp_arg(tpcb, NULL);
15828 DBG(("%p tcp_close %p", nc, tpcb));
15829 tcp_arg(tpcb, NULL);
15831 }
15832 while (cs->rx_chain != NULL) {
15833 struct pbuf *seg = cs->rx_chain;
15834 cs->rx_chain = pbuf_dechain(cs->rx_chain);
15835 pbuf_free(seg);
15836 }
15837 memset(cs, 0, sizeof(*cs));
15838 MG_FREE(cs);
15839 } else if (nc->listener == NULL) {
15840 /* Only close outgoing UDP pcb or listeners. */
15841 struct udp_pcb *upcb = cs->pcb.udp;
15842 if (upcb != NULL) {
15843 DBG(("%p udp_remove %p", nc, upcb));
15845 }
15846 memset(cs, 0, sizeof(*cs));
15847 MG_FREE(cs);
15848 }
15849 nc->sock = INVALID_SOCKET;
15850}
15851
15853 union socket_address *sa) {
15854 memset(sa, 0, sizeof(*sa));
15855 if (nc == NULL || nc->sock == INVALID_SOCKET) return;
15856 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15857 if (nc->flags & MG_F_UDP) {
15858 struct udp_pcb *upcb = cs->pcb.udp;
15859 if (remote) {
15860 memcpy(sa, &nc->sa, sizeof(*sa));
15861 } else if (upcb != NULL) {
15862 sa->sin.sin_port = htons(upcb->local_port);
15863 SET_ADDR(sa, &upcb->local_ip);
15864 }
15865 } else {
15866 struct tcp_pcb *tpcb = cs->pcb.tcp;
15867 if (remote) {
15868 memcpy(sa, &nc->sa, sizeof(*sa));
15869 } else if (tpcb != NULL) {
15870 sa->sin.sin_port = htons(tpcb->local_port);
15871 SET_ADDR(sa, &tpcb->local_ip);
15872 }
15873 }
15874}
15875
15877 nc->sock = sock;
15878}
15879
15880/* clang-format off */
15881#define MG_LWIP_IFACE_VTABLE \
15882 { \
15883 mg_lwip_if_init, \
15884 mg_lwip_if_free, \
15885 mg_lwip_if_add_conn, \
15886 mg_lwip_if_remove_conn, \
15887 mg_lwip_if_poll, \
15888 mg_lwip_if_listen_tcp, \
15889 mg_lwip_if_listen_udp, \
15890 mg_lwip_if_connect_tcp, \
15891 mg_lwip_if_connect_udp, \
15892 mg_lwip_if_tcp_send, \
15893 mg_lwip_if_udp_send, \
15894 mg_lwip_if_tcp_recv, \
15895 mg_lwip_if_udp_recv, \
15896 mg_lwip_if_create_conn, \
15897 mg_lwip_if_destroy_conn, \
15898 mg_lwip_if_sock_set, \
15899 mg_lwip_if_get_conn_addr, \
15900 }
15901/* clang-format on */
15902
15904#if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL
15906#endif
15907
15908#endif /* MG_ENABLE_NET_IF_LWIP_LOW_LEVEL */
15909#ifdef MG_MODULE_LINES
15910#line 1 "common/platforms/lwip/mg_lwip_ev_mgr.c"
15911#endif
15912/*
15913 * Copyright (c) 2014-2018 Cesanta Software Limited
15914 * All rights reserved
15915 *
15916 * Licensed under the Apache License, Version 2.0 (the ""License"");
15917 * you may not use this file except in compliance with the License.
15918 * You may obtain a copy of the License at
15919 *
15920 * http://www.apache.org/licenses/LICENSE-2.0
15921 *
15922 * Unless required by applicable law or agreed to in writing, software
15923 * distributed under the License is distributed on an ""AS IS"" BASIS,
15924 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15925 * See the License for the specific language governing permissions and
15926 * limitations under the License.
15927 */
15928
15929#if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL
15930
15931#ifndef MG_SIG_QUEUE_LEN
15932#define MG_SIG_QUEUE_LEN 32
15933#endif
15934
15936 int sig;
15938};
15939
15945
15947 struct mg_ev_mgr_lwip_data *md =
15948 (struct mg_ev_mgr_lwip_data *) nc->iface->data;
15949 mgos_lock();
15950 if (md->sig_queue_len >= MG_SIG_QUEUE_LEN) {
15951 mgos_unlock();
15952 return;
15953 }
15954 int end_index = (md->start_index + md->sig_queue_len) % MG_SIG_QUEUE_LEN;
15955 md->sig_queue[end_index].sig = sig;
15956 md->sig_queue[end_index].nc = nc;
15957 md->sig_queue_len++;
15959 mgos_unlock();
15960}
15961
15963 struct mg_ev_mgr_lwip_data *md =
15964 (struct mg_ev_mgr_lwip_data *) mgr->ifaces[MG_MAIN_IFACE]->data;
15965 while (md->sig_queue_len > 0) {
15966 mgos_lock();
15967 int i = md->start_index;
15968 int sig = md->sig_queue[i].sig;
15969 struct mg_connection *nc = md->sig_queue[i].nc;
15970 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15971 md->start_index = (i + 1) % MG_SIG_QUEUE_LEN;
15972 md->sig_queue_len--;
15973 mgos_unlock();
15974 if (nc->iface == NULL || nc->mgr == NULL) continue;
15975 switch (sig) {
15976 case MG_SIG_CONNECT_RESULT: {
15978 break;
15979 }
15980 case MG_SIG_CLOSE_CONN: {
15982 break;
15983 }
15984 case MG_SIG_RECV: {
15985 cs->recv_pending = 0;
15988 break;
15989 }
15990 case MG_SIG_TOMBSTONE: {
15991 break;
15992 }
15993 case MG_SIG_ACCEPT: {
15995 break;
15996 }
15997 }
15998 }
15999}
16000
16001void mg_lwip_if_init(struct mg_iface *iface) {
16002 LOG(LL_INFO, ("Mongoose %s, LwIP %u.%u.%u", MG_VERSION, LWIP_VERSION_MAJOR,
16004 iface->data = MG_CALLOC(1, sizeof(struct mg_ev_mgr_lwip_data));
16005}
16006
16007void mg_lwip_if_free(struct mg_iface *iface) {
16008 MG_FREE(iface->data);
16009 iface->data = NULL;
16010}
16011
16013 (void) nc;
16014}
16015
16017 struct mg_ev_mgr_lwip_data *md =
16018 (struct mg_ev_mgr_lwip_data *) nc->iface->data;
16019 /* Walk the queue and null-out further signals for this conn. */
16020 for (int i = 0; i < MG_SIG_QUEUE_LEN; i++) {
16021 if (md->sig_queue[i].nc == nc) {
16022 md->sig_queue[i].sig = MG_SIG_TOMBSTONE;
16023 }
16024 }
16025}
16026
16028 struct mg_mgr *mgr = iface->mgr;
16029 int n = 0;
16030 double now = mg_time();
16031 struct mg_connection *nc, *tmp;
16032 double min_timer = 0;
16033 int num_timers = 0;
16034#if 0
16035 DBG(("begin poll @%u", (unsigned int) (now * 1000)));
16036#endif
16038 for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
16039 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
16040 tmp = nc->next;
16041 n++;
16042 if (!mg_if_poll(nc, now)) continue;
16043 if (nc->sock != INVALID_SOCKET &&
16044 !(nc->flags & (MG_F_UDP | MG_F_LISTENING)) && cs->pcb.tcp != NULL &&
16045 cs->pcb.tcp->unsent != NULL) {
16047 }
16048 if (nc->ev_timer_time > 0) {
16049 if (num_timers == 0 || nc->ev_timer_time < min_timer) {
16051 }
16052 num_timers++;
16053 }
16054
16055 if (nc->sock != INVALID_SOCKET) {
16056 if (mg_lwip_if_can_send(nc, cs)) {
16059 }
16060 if (cs->rx_chain != NULL) {
16062 } else if (cs->draining_rx_chain) {
16063 /*
16064 * If the connection is about to close, and rx_chain is finally empty,
16065 * send the MG_SIG_CLOSE_CONN signal
16066 */
16068 }
16069 }
16070 }
16071#if 0
16072 DBG(("end poll @%u, %d conns, %d timers (min %u), next in %d ms",
16073 (unsigned int) (now * 1000), n, num_timers,
16074 (unsigned int) (min_timer * 1000), timeout_ms));
16075#endif
16076 (void) timeout_ms;
16077 return now;
16078}
16079
16080#endif /* MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL */
16081#ifdef MG_MODULE_LINES
16082#line 1 "common/platforms/wince/wince_libc.c"
16083#endif
16084/*
16085 * Copyright (c) 2014-2018 Cesanta Software Limited
16086 * All rights reserved
16087 *
16088 * Licensed under the Apache License, Version 2.0 (the ""License"");
16089 * you may not use this file except in compliance with the License.
16090 * You may obtain a copy of the License at
16091 *
16092 * http://www.apache.org/licenses/LICENSE-2.0
16093 *
16094 * Unless required by applicable law or agreed to in writing, software
16095 * distributed under the License is distributed on an ""AS IS"" BASIS,
16096 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16097 * See the License for the specific language governing permissions and
16098 * limitations under the License.
16099 */
16100
16101#ifdef WINCE
16102
16103const char *strerror(int err) {
16104 /*
16105 * TODO(alashkin): there is no strerror on WinCE;
16106 * look for similar wce_xxxx function
16107 */
16108 static char buf[10];
16109 snprintf(buf, sizeof(buf), "%d", err);
16110 return buf;
16111}
16112
16113int open(const char *filename, int oflag, int pmode) {
16114 /*
16115 * TODO(alashkin): mg_open function is not used in mongoose
16116 * but exists in documentation as utility function
16117 * Shall we delete it at all or implement for WinCE as well?
16118 */
16119 DebugBreak();
16120 return 0; /* for compiler */
16121}
16122
16123int _wstati64(const wchar_t *path, cs_stat_t *st) {
16124 DWORD fa = GetFileAttributesW(path);
16125 if (fa == INVALID_FILE_ATTRIBUTES) {
16126 return -1;
16127 }
16128 memset(st, 0, sizeof(*st));
16129 if ((fa & FILE_ATTRIBUTE_DIRECTORY) == 0) {
16130 HANDLE h;
16132 st->st_mode |= _S_IFREG;
16135 if (h == INVALID_HANDLE_VALUE) {
16136 return -1;
16137 }
16138 st->st_size = GetFileSize(h, NULL);
16139 GetFileTime(h, NULL, NULL, &ftime);
16140 st->st_mtime = (uint32_t)((((uint64_t) ftime.dwLowDateTime +
16141 ((uint64_t) ftime.dwHighDateTime << 32)) /
16142 10000000.0) -
16143 11644473600);
16144 CloseHandle(h);
16145 } else {
16146 st->st_mode |= _S_IFDIR;
16147 }
16148 return 0;
16149}
16150
16151/* Windows CE doesn't have neither gmtime nor strftime */
16152static void mg_gmt_time_string(char *buf, size_t buf_len, time_t *t) {
16153 FILETIME ft;
16155 if (t != NULL) {
16156 uint64_t filetime = (*t + 11644473600) * 10000000;
16157 ft.dwLowDateTime = filetime & 0xFFFFFFFF;
16158 ft.dwHighDateTime = (filetime & 0xFFFFFFFF00000000) >> 32;
16160 } else {
16162 }
16163 /* There is no PRIu16 in WinCE SDK */
16164 snprintf(buf, buf_len, "%d.%d.%d %d:%d:%d GMT", (int) systime.wYear,
16165 (int) systime.wMonth, (int) systime.wDay, (int) systime.wHour,
16166 (int) systime.wMinute, (int) systime.wSecond);
16167}
16168
16169#endif
16170#ifdef MG_MODULE_LINES
16171#line 1 "common/platforms/pic32/pic32_net_if.h"
16172#endif
16173/*
16174 * Copyright (c) 2014-2018 Cesanta Software Limited
16175 * All rights reserved
16176 *
16177 * Licensed under the Apache License, Version 2.0 (the ""License"");
16178 * you may not use this file except in compliance with the License.
16179 * You may obtain a copy of the License at
16180 *
16181 * http://www.apache.org/licenses/LICENSE-2.0
16182 *
16183 * Unless required by applicable law or agreed to in writing, software
16184 * distributed under the License is distributed on an ""AS IS"" BASIS,
16185 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16186 * See the License for the specific language governing permissions and
16187 * limitations under the License.
16188 */
16189
16190#ifndef CS_COMMON_PLATFORMS_PIC32_NET_IF_H_
16191#define CS_COMMON_PLATFORMS_PIC32_NET_IF_H_
16192
16193/* Amalgamated: #include "mongoose/src/net_if.h" */
16194
16195#ifdef __cplusplus
16196extern "C" {
16197#endif /* __cplusplus */
16198
16199#ifndef MG_ENABLE_NET_IF_PIC32
16200#define MG_ENABLE_NET_IF_PIC32 MG_NET_IF == MG_NET_IF_PIC32
16201#endif
16202
16203extern const struct mg_iface_vtable mg_pic32_iface_vtable;
16204
16205#ifdef __cplusplus
16206}
16207#endif /* __cplusplus */
16208
16209#endif /* CS_COMMON_PLATFORMS_PIC32_NET_IF_H_ */
16210#ifdef MG_MODULE_LINES
16211#line 1 "common/platforms/pic32/pic32_net_if.c"
16212#endif
16213/*
16214 * Copyright (c) 2014-2018 Cesanta Software Limited
16215 * All rights reserved
16216 *
16217 * Licensed under the Apache License, Version 2.0 (the ""License"");
16218 * you may not use this file except in compliance with the License.
16219 * You may obtain a copy of the License at
16220 *
16221 * http://www.apache.org/licenses/LICENSE-2.0
16222 *
16223 * Unless required by applicable law or agreed to in writing, software
16224 * distributed under the License is distributed on an ""AS IS"" BASIS,
16225 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16226 * See the License for the specific language governing permissions and
16227 * limitations under the License.
16228 */
16229
16230#if MG_ENABLE_NET_IF_PIC32
16231
16233 (void) nc;
16234 return 1;
16235}
16236
16237void mg_pic32_if_recved(struct mg_connection *nc, size_t len) {
16238 (void) nc;
16239 (void) len;
16240}
16241
16243 (void) nc;
16244}
16245
16246void mg_pic32_if_init(struct mg_iface *iface) {
16247 (void) iface;
16248 (void) mg_get_errno(); /* Shutup compiler */
16249}
16250
16251void mg_pic32_if_free(struct mg_iface *iface) {
16252 (void) iface;
16253}
16254
16256 (void) nc;
16257}
16258
16260 if (nc->sock == INVALID_SOCKET) return;
16261 /* For UDP, only close outgoing sockets or listeners. */
16262 if (!(nc->flags & MG_F_UDP)) {
16263 /* Close TCP */
16265 } else if (nc->listener == NULL) {
16266 /* Only close outgoing UDP or listeners. */
16268 }
16269
16270 nc->sock = INVALID_SOCKET;
16271}
16272
16275 sa->sin.sin_family == AF_INET ? IP_ADDRESS_TYPE_IPV4
16277 ntohs(sa->sin.sin_port),
16278 sa->sin.sin_addr.s_addr == 0 ? 0 : (IP_MULTI_ADDRESS *) &sa->sin);
16279 if (nc->sock == INVALID_SOCKET) {
16280 return -1;
16281 }
16282 return 0;
16283}
16284
16285void mg_pic32_if_udp_send(struct mg_connection *nc, const void *buf,
16286 size_t len) {
16287 mbuf_append(&nc->send_mbuf, buf, len);
16288}
16289
16290void mg_pic32_if_tcp_send(struct mg_connection *nc, const void *buf,
16291 size_t len) {
16292 mbuf_append(&nc->send_mbuf, buf, len);
16293}
16294
16297 sa->sin.sin_family == AF_INET ? IP_ADDRESS_TYPE_IPV4
16299 ntohs(sa->sin.sin_port),
16300 sa->sin.sin_addr.s_addr == 0 ? 0 : (IP_MULTI_ADDRESS *) &sa->sin);
16301 memcpy(&nc->sa, sa, sizeof(*sa));
16302 if (nc->sock == INVALID_SOCKET) {
16303 return -1;
16304 }
16305 return 0;
16306}
16307
16308static int mg_accept_conn(struct mg_connection *lc) {
16309 struct mg_connection *nc;
16311 union socket_address sa;
16312
16313 nc = mg_if_accept_new_conn(lc);
16314
16315 if (nc == NULL) {
16316 return 0;
16317 }
16318
16319 nc->sock = lc->sock;
16320 nc->flags &= ~MG_F_LISTENING;
16321
16322 if (!TCPIP_TCP_SocketInfoGet((TCP_SOCKET) nc->sock, &si)) {
16323 return 0;
16324 }
16325
16326 if (si.addressType == IP_ADDRESS_TYPE_IPV4) {
16327 sa.sin.sin_family = AF_INET;
16328 sa.sin.sin_port = htons(si.remotePort);
16329 sa.sin.sin_addr.s_addr = si.remoteIPaddress.v4Add.Val;
16330 } else {
16331 /* TODO(alashkin): do something with _potential_ IPv6 */
16332 memset(&sa, 0, sizeof(sa));
16333 }
16334
16335 mg_if_accept_tcp_cb(nc, (union socket_address *) &sa, sizeof(sa));
16336
16337 return mg_pic32_if_listen_tcp(lc, &lc->sa) >= 0;
16338}
16339
16340char *inet_ntoa(struct in_addr in) {
16341 static char addr[17];
16342 snprintf(addr, sizeof(addr), "%d.%d.%d.%d", (int) in.S_un.S_un_b.s_b1,
16343 (int) in.S_un.S_un_b.s_b2, (int) in.S_un.S_un_b.s_b3,
16344 (int) in.S_un.S_un_b.s_b4);
16345 return addr;
16346}
16347
16348static void mg_handle_send(struct mg_connection *nc) {
16349 uint16_t bytes_written = 0;
16350 if (nc->flags & MG_F_UDP) {
16352 (UDP_SOCKET) nc->sock,
16353 nc->sa.sin.sin_family == AF_INET ? IP_ADDRESS_TYPE_IPV4
16355 ntohs(nc->sa.sin.sin_port), (IP_MULTI_ADDRESS *) &nc->sa.sin)) {
16357 return;
16358 }
16359 bytes_written = TCPIP_UDP_TxPutIsReady((UDP_SOCKET) nc->sock, 0);
16360 if (bytes_written >= nc->send_mbuf.len) {
16362 (uint8_t *) nc->send_mbuf.buf,
16363 nc->send_mbuf.len) != nc->send_mbuf.len) {
16365 bytes_written = 0;
16366 }
16367 }
16368 } else {
16369 bytes_written = TCPIP_TCP_FifoTxFreeGet((TCP_SOCKET) nc->sock);
16370 if (bytes_written != 0) {
16371 if (bytes_written > nc->send_mbuf.len) {
16372 bytes_written = nc->send_mbuf.len;
16373 }
16375 (uint8_t *) nc->send_mbuf.buf,
16376 bytes_written) != bytes_written) {
16378 bytes_written = 0;
16379 }
16380 }
16381 }
16382
16383 mg_if_sent_cb(nc, bytes_written);
16384}
16385
16386static void mg_handle_recv(struct mg_connection *nc) {
16387 uint16_t bytes_read = 0;
16388 uint8_t *buf = NULL;
16389 if (nc->flags & MG_F_UDP) {
16390 bytes_read = TCPIP_UDP_GetIsReady((UDP_SOCKET) nc->sock);
16391 if (bytes_read != 0 &&
16392 (nc->recv_mbuf_limit == -1 ||
16393 nc->recv_mbuf.len + bytes_read < nc->recv_mbuf_limit)) {
16394 buf = (uint8_t *) MG_MALLOC(bytes_read);
16395 if (TCPIP_UDP_ArrayGet((UDP_SOCKET) nc->sock, buf, bytes_read) !=
16396 bytes_read) {
16398 bytes_read = 0;
16399 MG_FREE(buf);
16400 }
16401 }
16402 } else {
16403 bytes_read = TCPIP_TCP_GetIsReady((TCP_SOCKET) nc->sock);
16404 if (bytes_read != 0) {
16405 if (nc->recv_mbuf_limit != -1 &&
16406 nc->recv_mbuf_limit - nc->recv_mbuf.len > bytes_read) {
16407 bytes_read = nc->recv_mbuf_limit - nc->recv_mbuf.len;
16408 }
16409 buf = (uint8_t *) MG_MALLOC(bytes_read);
16410 if (TCPIP_TCP_ArrayGet((TCP_SOCKET) nc->sock, buf, bytes_read) !=
16411 bytes_read) {
16413 MG_FREE(buf);
16414 bytes_read = 0;
16415 }
16416 }
16417 }
16418
16419 if (bytes_read != 0) {
16420 mg_if_recv_tcp_cb(nc, buf, bytes_read, 1 /* own */);
16421 }
16422}
16423
16425 struct mg_mgr *mgr = iface->mgr;
16426 double now = mg_time();
16427 struct mg_connection *nc, *tmp;
16428
16429 for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
16430 tmp = nc->next;
16431
16432 if (nc->flags & MG_F_CONNECTING) {
16433 /* processing connections */
16434 if (nc->flags & MG_F_UDP ||
16436 mg_if_connect_cb(nc, 0);
16437 }
16438 } else if (nc->flags & MG_F_LISTENING) {
16440 /* accept new connections */
16441 mg_accept_conn(nc);
16442 }
16443 } else {
16444 if (nc->send_mbuf.len != 0) {
16445 mg_handle_send(nc);
16446 }
16447
16448 if (nc->recv_mbuf_limit == -1 ||
16449 nc->recv_mbuf.len < nc->recv_mbuf_limit) {
16450 mg_handle_recv(nc);
16451 }
16452 }
16453 }
16454
16455 for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
16456 tmp = nc->next;
16457 if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) ||
16458 (nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE))) {
16459 mg_close_conn(nc);
16460 }
16461 }
16462
16463 return now;
16464}
16465
16467 nc->sock = sock;
16468}
16469
16471 union socket_address *sa) {
16472 /* TODO(alaskin): not implemented yet */
16473}
16474
16476 const union socket_address *sa) {
16478 sa->sin.sin_family == AF_INET ? IP_ADDRESS_TYPE_IPV4
16480 ntohs(sa->sin.sin_port), (IP_MULTI_ADDRESS *) &sa->sin);
16481 nc->err = (nc->sock == INVALID_SOCKET) ? -1 : 0;
16482}
16483
16486 nc->err = (nc->sock == INVALID_SOCKET) ? -1 : 0;
16487}
16488
16489/* clang-format off */
16490#define MG_PIC32_IFACE_VTABLE \
16491 { \
16492 mg_pic32_if_init, \
16493 mg_pic32_if_free, \
16494 mg_pic32_if_add_conn, \
16495 mg_pic32_if_remove_conn, \
16496 mg_pic32_if_poll, \
16497 mg_pic32_if_listen_tcp, \
16498 mg_pic32_if_listen_udp, \
16499 mg_pic32_if_connect_tcp, \
16500 mg_pic32_if_connect_udp, \
16501 mg_pic32_if_tcp_send, \
16502 mg_pic32_if_udp_send, \
16503 mg_pic32_if_recved, \
16504 mg_pic32_if_create_conn, \
16505 mg_pic32_if_destroy_conn, \
16506 mg_pic32_if_sock_set, \
16507 mg_pic32_if_get_conn_addr, \
16508 }
16509/* clang-format on */
16510
16512#if MG_NET_IF == MG_NET_IF_PIC32
16514#endif
16515
16516#endif /* MG_ENABLE_NET_IF_PIC32 */
16517#ifdef MG_MODULE_LINES
16518#line 1 "common/platforms/windows/windows_direct.c"
16519#endif
16520/*
16521 * Copyright (c) 2014-2018 Cesanta Software Limited
16522 * All rights reserved
16523 *
16524 * Licensed under the Apache License, Version 2.0 (the ""License"");
16525 * you may not use this file except in compliance with the License.
16526 * You may obtain a copy of the License at
16527 *
16528 * http://www.apache.org/licenses/LICENSE-2.0
16529 *
16530 * Unless required by applicable law or agreed to in writing, software
16531 * distributed under the License is distributed on an ""AS IS"" BASIS,
16532 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16533 * See the License for the specific language governing permissions and
16534 * limitations under the License.
16535 */
16536
16537#ifdef _WIN32
16538
16539int rmdir(const char *dirname) {
16540 return _rmdir(dirname);
16541}
16542
16543unsigned int sleep(unsigned int seconds) {
16544 Sleep(seconds * 1000);
16545 return 0;
16546}
16547
16548#endif /* _WIN32 */
#define LONG
Definition crc32c.cxx:230
unsigned int DWORD
Definition mcstd.h:51
int mg_start_thread(mg_thread_func_t f, void *p)
int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, int is_form_url_encoded)
int(* mg_event_handler_t)(struct mg_event *event)
Definition mongoose4.h:70
int mg_mgr_poll(struct mg_mgr *m, int timeout_ms)
struct mg_str message
Definition mongoose6.h:2068
void mg_mqtt_ping(struct mg_connection *nc)
void mg_set_protocol_mqtt(struct mg_connection *nc)
void * user_data
Definition mongoose6.h:1396
void mg_mgr_free(struct mg_mgr *m)
const char * hexdump_file
Definition mongoose6.h:1232
int mg_resolve_from_hosts_file(const char *host, union socket_address *usa)
void cs_base64_update(struct cs_base64_ctx *ctx, const char *str, size_t len)
void cs_to_hex(char *to, const unsigned char *p, size_t len) WEAK
#define WEBSOCKET_DONT_FIN
Definition mongoose6.h:2365
#define MG_MK_STR(str_literal)
Definition mongoose6.h:2006
void mg_send_dns_query(struct mg_connection *nc, const char *name, int query_type)
#define WEBSOCKET_OP_PING
Definition mongoose6.h:2350
char * cs_md5(char buf[33],...)
void mg_mqtt_disconnect(struct mg_connection *nc)
#define MG_MQTT_HAS_USER_NAME
Definition mongoose6.h:2944
#define MG_MQTT_CMD_PUBREC
Definition mongoose6.h:2904
void mg_mqtt_publish(struct mg_connection *nc, const char *topic, uint16_t message_id, int flags, const void *data, size_t len)
void mg_if_get_conn_addr(struct mg_connection *nc, int remote, union socket_address *sa)
#define MG_MQTT_CMD_UNSUBACK
Definition mongoose6.h:2910
void * user_data
Definition mongoose6.h:1265
struct mg_str header_names[MG_MAX_HTTP_HEADERS]
Definition mongoose6.h:2090
int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap) WEAK
struct mg_str payload
Definition mongoose6.h:2878
#define MG_MAX_HTTP_HEADERS
Definition mongoose6.h:2031
int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) WEAK
#define MG_MAX_HTTP_SEND_MBUF
Definition mongoose6.h:2047
#define MG_MAX_DNS_ANSWERS
Definition mongoose6.h:3169
#define MG_EV_WEBSOCKET_FRAME
Definition mongoose6.h:2121
int mg_stat(const char *path, cs_stat_t *st)
struct mg_connection * mg_connect_http(struct mg_mgr *mgr, mg_event_handler_t event_handler, const char *url, const char *extra_headers, const char *post_data)
#define MG_EV_WEBSOCKET_HANDSHAKE_DONE
Definition mongoose6.h:2120
int mg_resolve_async_opt(struct mg_mgr *mgr, const char *name, int query, mg_resolve_callback_t cb, void *data, struct mg_resolve_async_opts opts)
mg_event_handler_t handler
Definition mongoose6.h:1264
struct mg_connection * active_connections
Definition mongoose6.h:1231
void mg_mqtt_connack(struct mg_connection *nc, uint8_t return_code)
cs_log_level
Definition mongoose6.h:741
#define MG_MQTT_CMD_PUBACK
Definition mongoose6.h:2903
int mg_dns_encode_record(struct mbuf *io, struct mg_dns_resource_record *rr, const char *name, size_t nlen, const void *rdata, size_t rlen)
void mg_mqtt_pong(struct mg_connection *nc)
struct mg_connection ** dns_conn
Definition mongoose6.h:3426
int mg_is_big_endian(void)
#define MG_F_CLOSE_IMMEDIATELY
Definition mongoose6.h:1289
size_t mbuf_insert(struct mbuf *a, size_t off, const void *buf, size_t) WEAK
size_t mg_parse_multipart(const char *buf, size_t buf_len, char *var_name, size_t var_name_len, char *file_name, size_t file_name_len, const char **chunk, size_t *chunk_len)
#define MG_SOCK_STRINGIFY_PORT
Definition mongoose6.h:1905
void mbuf_remove(struct mbuf *mb, size_t n) WEAK
void mg_mgr_init(struct mg_mgr *m, void *user_data)
int mg_dns_insert_header(struct mbuf *io, size_t pos, struct mg_dns_message *msg)
void mg_send_head(struct mg_connection *n, int status_code, int64_t content_length, const char *extra_headers)
void mg_mqtt_pubcomp(struct mg_connection *nc, uint16_t message_id)
void(* proto_data_destructor)(void *proto_data)
Definition mongoose6.h:1263
struct mg_connection * mg_next(struct mg_mgr *s, struct mg_connection *conn)
int mg_resolve_async(struct mg_mgr *mgr, const char *name, int query, mg_resolve_callback_t cb, void *data)
#define MG_EV_RECV
Definition mongoose6.h:1222
uint32_t state[5]
Definition mongoose6.h:899
void mg_if_accept_tcp_cb(struct mg_connection *nc, union socket_address *sa, size_t sa_len)
int mg_normalize_uri_path(const struct mg_str *in, struct mg_str *out)
#define WEBSOCKET_OP_CLOSE
Definition mongoose6.h:2349
const char * c_strnstr(const char *s, const char *find, size_t slen) WEAK
int mg_vprintf(struct mg_connection *nc, const char *fmt, va_list ap)
const char * mg_set_ssl(struct mg_connection *nc, const char *cert, const char *ca_cert)
void mg_broadcast(struct mg_mgr *, mg_event_handler_t func, void *, size_t)
#define MG_DNS_AAAA_RECORD
Definition mongoose6.h:3165
void mg_send_response_line(struct mg_connection *c, int status_code, const char *extra_headers)
#define MG_MQTT_CMD_CONNACK
Definition mongoose6.h:2901
void mg_send_mqtt_handshake(struct mg_connection *nc, const char *client_id)
#define MG_VPRINTF_BUFFER_SIZE
Definition mongoose6.h:1179
struct mg_str header_values[MG_MAX_HTTP_HEADERS]
Definition mongoose6.h:2091
void mbuf_free(struct mbuf *mbuf) WEAK
union socket_address sa
Definition mongoose6.h:1253
#define MG_EV_WEBSOCKET_CONTROL_FRAME
Definition mongoose6.h:2122
void mg_serve_http(struct mg_connection *nc, struct http_message *hm, struct mg_serve_http_opts opts)
#define MG_F_WANT_READ
Definition mongoose6.h:1283
#define MG_MAX_CGI_ENVIR_VARS
Definition mongoose6.h:2059
void * user_data
Definition mongoose6.h:984
#define MG_SOCK_STRINGIFY_REMOTE
Definition mongoose6.h:1906
int mg_open(const char *path, int flag, int mode)
double mg_set_timer(struct mg_connection *c, double timestamp)
int mg_conn_addr_to_str(struct mg_connection *nc, char *buf, size_t len, int flags)
#define MG_MQTT_GET_QOS(flags)
Definition mongoose6.h:2936
#define MG_EV_CONNECT
Definition mongoose6.h:1221
int mg_parse_http(const char *s, int n, struct http_message *hm, int is_req)
size_t mg_match_prefix_n(const struct mg_str, const struct mg_str) WEAK
#define MG_EV_SSI_CALL
Definition mongoose6.h:2117
mg_resolve_err
Definition mongoose6.h:3409
#define MG_SEND_FUNC(s, b, l, f)
Definition mongoose6.h:1187
size_t len
Definition mongoose6.h:835
void * proto_data
Definition mongoose6.h:1262
#define MG_MAX_PATH
Definition mongoose6.h:2042
void mbuf_resize(struct mbuf *a, size_t new_size) WEAK
size_t len
Definition mongoose6.h:1207
void mg_if_recv_tcp_cb(struct mg_connection *nc, void *buf, int len)
void mg_printf_html_escape(struct mg_connection *nc, const char *fmt,...)
#define MG_F_LISTENING
Definition mongoose6.h:1278
unsigned char buffer[64]
Definition mongoose6.h:901
cs_base64_putc_t b64_putc
Definition mongoose6.h:981
void mg_if_sent_cb(struct mg_connection *nc, int num_sent)
#define MG_MQTT_HAS_WILL
Definition mongoose6.h:2941
#define MG_DNS_CNAME_RECORD
Definition mongoose6.h:3164
struct mg_connection * mg_if_accept_new_conn(struct mg_connection *lc)
#define MG_CGI_ENVIRONMENT_SIZE
Definition mongoose6.h:2055
int mg_casecmp(const char *s1, const char *s2) WEAK
void mg_send(struct mg_connection *nc, const void *buf, int len)
int mg_socketpair(sock_t[2], int sock_type)
#define WEBSOCKET_OP_PONG
Definition mongoose6.h:2351
#define MG_MQTT_CMD_PUBREL
Definition mongoose6.h:2905
struct mg_connection * next
Definition mongoose6.h:1247
void mg_send_http_chunk(struct mg_connection *nc, const char *buf, size_t len)
#define MG_MQTT_CMD_PINGREQ
Definition mongoose6.h:2911
#define MG_EV_MQTT_CONNACK_SERVER_UNAVAILABLE
Definition mongoose6.h:2953
#define MG_ENV_EXPORT_TO_CGI
Definition mongoose6.h:2063
void mg_hexdump_connection(struct mg_connection *nc, const char *path, const void *buf, int num_bytes, int ev)
struct mbuf send_mbuf
Definition mongoose6.h:1256
#define MG_F_WEBSOCKET_NO_DEFRAG
Definition mongoose6.h:1290
#define MG_DNS_A_RECORD
Definition mongoose6.h:3163
#define ARRAY_SIZE(array)
Definition mongoose6.h:119
struct mbuf recv_mbuf
Definition mongoose6.h:1255
unsigned char flags
Definition mongoose6.h:2101
void mg_if_connect_cb(struct mg_connection *nc, int err)
int mg_http_create_digest_auth_header(char *buf, size_t buf_len, const char *method, const char *uri, const char *auth_domain, const char *user, const char *passwd)
#define MG_EV_MQTT_CONNECT
Definition mongoose6.h:2917
#define MG_EV_POLL
Definition mongoose6.h:1219
unsigned int flags
Definition mongoose6.h:1437
void mg_sock_set(struct mg_connection *nc, sock_t sock)
#define MG_MQTT_QOS(qos)
Definition mongoose6.h:2935
#define MG_F_UDP
Definition mongoose6.h:1279
void mg_send_websocket_handshake2(struct mg_connection *nc, const char *path, const char *host, const char *protocol, const char *extra_headers)
void cs_base64_finish(struct cs_base64_ctx *ctx)
sock_t ctl[2]
Definition mongoose6.h:1234
double mg_time(void)
double ev_timer_time
Definition mongoose6.h:1260
void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path, mg_event_handler_t handler)
void mg_sock_to_str(sock_t sock, char *buf, size_t len, int flags)
#define MG_MQTT_CMD_PUBCOMP
Definition mongoose6.h:2906
void mg_mqtt_puback(struct mg_connection *nc, uint16_t message_id)
uint16_t flags
Definition mongoose6.h:3192
void mg_printf_websocket_frame(struct mg_connection *nc, int op_and_flags, const char *fmt,...)
void * SSL_CTX
Definition mongoose6.h:1175
#define MG_MQTT_EVENT_BASE
Definition mongoose6.h:2916
#define MG_MQTT_CMD_PUBLISH
Definition mongoose6.h:2902
#define MBUF_SIZE_MULTIPLIER
Definition mongoose6.h:829
struct mg_dns_resource_record questions[MG_MAX_DNS_QUESTIONS]
Definition mongoose6.h:3196
#define MG_EV_HTTP_CHUNK
Definition mongoose6.h:2116
void cs_log_set_level(enum cs_log_level level)
struct sockaddr sin6
Definition mongoose6.h:1200
#define MG_SOCK_STRINGIFY_IP
Definition mongoose6.h:1904
uint32_t count[2]
Definition mongoose6.h:900
size_t c_strnlen(const char *s, size_t maxlen) WEAK
size_t mg_match_prefix(const char *, int, const char *) WEAK
#define MG_MQTT_CMD_PINGRESP
Definition mongoose6.h:2912
#define MG_EV_TIMER
Definition mongoose6.h:1225
#define MG_MQTT_CMD_CONNECT
Definition mongoose6.h:2900
void cs_hmac_sha1(const unsigned char *key, size_t keylen, const unsigned char *data, size_t datalen, unsigned char out[20])
void mg_set_protocol_http_websocket(struct mg_connection *nc)
void mg_send_websocket_framev(struct mg_connection *nc, int op_and_flags, const struct mg_str *strings, int num_strings)
void cs_fprint_base64(FILE *f, const unsigned char *src, int src_len)
int mg_hexdump(const void *buf, int len, char *dst, int dst_len)
#define MG_DNS_MESSAGE
Definition mongoose6.h:3171
int mg_vcasecmp(const struct mg_str *str1, const char *str2) WEAK
#define MG_WEBSOCKET_PING_INTERVAL_SECONDS
Definition mongoose6.h:2051
#define MG_EV_SEND
Definition mongoose6.h:1223
unsigned long flags
Definition mongoose6.h:1276
int mg_base64_decode(const unsigned char *s, int len, char *dst)
struct mg_connection * mg_connect_ws(struct mg_mgr *mgr, mg_event_handler_t event_handler, const char *url, const char *protocol, const char *extra_headers)
struct mg_connection * listener
Definition mongoose6.h:1248
struct mg_connection * prev
Definition mongoose6.h:1247
#define MG_VERSION
Definition mongoose6.h:26
#define MG_MQTT_HAS_PASSWORD
Definition mongoose6.h:2943
void mg_mqtt_pubrec(struct mg_connection *nc, uint16_t message_id)
void * user_data
Definition mongoose6.h:1236
time_t last_io_time
Definition mongoose6.h:1259
void mg_set_close_on_exec(sock_t sock)
size_t recv_mbuf_limit
Definition mongoose6.h:1254
double cs_time(void) WEAK
void(* cs_base64_putc_t)(char, void *)
Definition mongoose6.h:977
struct mg_connection * mg_connect_ws_opt(struct mg_mgr *mgr, mg_event_handler_t ev_handler, struct mg_connect_opts opts, const char *url, const char *protocol, const char *extra_headers)
#define MG_F_DELETE_CHUNK
Definition mongoose6.h:1291
struct mg_str body
Definition mongoose6.h:2094
int mg_resolve(const char *domain_name, char *ip_addr_buf, size_t buf_len)
#define MG_EV_HTTP_REPLY
Definition mongoose6.h:2115
void mg_set_protocol_dns(struct mg_connection *nc)
const char * mg_skip(const char *s, const char *end, const char *delims, struct mg_str *v)
void mg_mqtt_suback(struct mg_connection *nc, uint8_t *qoss, size_t qoss_len, uint16_t message_id)
struct sockaddr sa
Definition mongoose6.h:1195
#define MG_MAX_HTTP_REQUEST_SIZE
Definition mongoose6.h:2035
#define MG_MQTT_CMD_UNSUBSCRIBE
Definition mongoose6.h:2909
struct mg_mgr * mgr
Definition mongoose6.h:1249
int mg_parse_dns(const char *buf, int len, struct mg_dns_message *msg)
int c_snprintf(char *buf, size_t buf_size, const char *fmt,...) WEAK
char * buf
Definition mongoose6.h:834
void mg_mqtt_unsuback(struct mg_connection *nc, uint16_t message_id)
void cs_base64_init(struct cs_base64_ctx *ctx, cs_base64_putc_t b64_putc, void *user_data)
struct mg_dns_resource_record * mg_dns_next_record(struct mg_dns_message *msg, int query, struct mg_dns_resource_record *prev)
#define MG_F_RESOLVING
Definition mongoose6.h:1280
void mbuf_init(struct mbuf *mbuf, size_t initial_size) WEAK
struct mg_str rdata
Definition mongoose6.h:3186
void cs_log_printf(const char *fmt,...)
void mg_send_mqtt_handshake_opt(struct mg_connection *nc, const char *client_id, struct mg_send_mqtt_handshake_opts)
size_t mbuf_append(struct mbuf *a, const void *buf, size_t len) WEAK
#define MG_F_SSL_HANDSHAKE_DONE
Definition mongoose6.h:1282
int mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len, int flags)
void mg_base64_encode(const unsigned char *src, int src_len, char *dst)
void mg_send_websocket_frame(struct mg_connection *nc, int op_and_flags, const void *data, size_t data_len)
#define MG_EV_MQTT_PUBLISH
Definition mongoose6.h:2919
void(* mg_resolve_callback_t)(struct mg_dns_message *dns_message, void *user_data, enum mg_resolve_err)
Definition mongoose6.h:3416
#define MG_F_IS_WEBSOCKET
Definition mongoose6.h:1285
#define MG_RECV_FUNC(s, b, l, f)
Definition mongoose6.h:1186
void cs_sha1_final(unsigned char digest[20], cs_sha1_ctx *context)
int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf, size_t buf_size)
struct mg_str mg_mk_str(const char *s) WEAK
void cs_base64_encode(const unsigned char *src, int src_len, char *dst)
int mg_get_http_var(const struct mg_str *buf, const char *name, char *dst, size_t dst_len)
void mg_send_websocket_handshake(struct mg_connection *nc, const char *uri, const char *extra_headers)
void mg_printf_http_chunk(struct mg_connection *nc, const char *fmt,...)
#define MG_EV_MQTT_SUBSCRIBE
Definition mongoose6.h:2924
const char * mg_next_comma_list_entry(const char *, struct mg_str *, struct mg_str *) WEAK
#define MG_EV_CLOSE
Definition mongoose6.h:1224
size_t mg_dns_uncompress_name(struct mg_dns_message *msg, struct mg_str *name, char *dst, int dst_len)
struct mg_connection * mg_connect_http_opt(struct mg_mgr *mgr, mg_event_handler_t ev_handler, struct mg_connect_opts opts, const char *url, const char *extra_headers, const char *post_data)
void mbuf_trim(struct mbuf *mbuf) WEAK
#define MG_MQTT_CMD_DISCONNECT
Definition mongoose6.h:2913
FILE * mg_fopen(const char *path, const char *mode)
struct mg_str * mg_get_http_header(struct http_message *hm, const char *name)
void cs_sha1_update(cs_sha1_ctx *context, const unsigned char *data, uint32_t len)
#define MG_MQTT_CMD_SUBSCRIBE
Definition mongoose6.h:2907
#define MG_MQTT_CMD_SUBACK
Definition mongoose6.h:2908
unsigned char chunk[3]
Definition mongoose6.h:982
int mg_vcmp(const struct mg_str *str1, const char *str2) WEAK
int mg_parse_uri(const struct mg_str uri, struct mg_str *scheme, struct mg_str *user_info, struct mg_str *host, unsigned int *port, struct mg_str *path, struct mg_str *query, struct mg_str *fragment)
#define MG_F_WANT_WRITE
Definition mongoose6.h:1284
size_t size
Definition mongoose6.h:836
int mg_check_ip_acl(const char *acl, uint32_t remote_ip)
struct mg_dns_resource_record answers[MG_MAX_DNS_ANSWERS]
Definition mongoose6.h:3197
#define MG_F_CONNECTING
Definition mongoose6.h:1281
mg_event_handler_t proto_handler
Definition mongoose6.h:1261
MG_INTERNAL void mg_close_conn(struct mg_connection *conn)
void * SSL
Definition mongoose6.h:1174
struct mg_str pkt
Definition mongoose6.h:3191
const char * p
Definition mongoose6.h:1206
void cs_sha1_init(cs_sha1_ctx *context)
int mg_ncasecmp(const char *s1, const char *s2, size_t len) WEAK
int mg_dns_parse_record_data(struct mg_dns_message *msg, struct mg_dns_resource_record *rr, void *data, size_t data_len)
#define MG_EV_ACCEPT
Definition mongoose6.h:1220
#define MG_EV_MQTT_CONNACK_ACCEPTED
Definition mongoose6.h:2950
void mg_mqtt_unsubscribe(struct mg_connection *nc, char **topics, size_t topics_len, uint16_t message_id)
#define MG_EV_WEBSOCKET_HANDSHAKE_REQUEST
Definition mongoose6.h:2119
struct sockaddr_in sin
Definition mongoose6.h:1196
int mg_printf(struct mg_connection *conn, const char *fmt,...)
void mg_mqtt_subscribe(struct mg_connection *nc, const struct mg_mqtt_topic_expression *topics, size_t topics_len, uint16_t message_id)
void mg_mqtt_pubrel(struct mg_connection *nc, uint16_t message_id)
void cs_log_set_file(FILE *file)
#define WEBSOCKET_OP_CONTINUE
Definition mongoose6.h:2346
int mg_mqtt_next_subscribe_topic(struct mg_mqtt_message *msg, struct mg_str *topic, uint8_t *qos, int pos)
#define MG_F_SEND_AND_CLOSE
Definition mongoose6.h:1288
uint16_t transaction_id
Definition mongoose6.h:3193
#define MG_EV_HTTP_REQUEST
Definition mongoose6.h:2114
@ MG_RESOLVE_TIMEOUT
Definition mongoose6.h:3413
@ MG_RESOLVE_EXCEEDED_RETRY_COUNT
Definition mongoose6.h:3412
@ MG_RESOLVE_OK
Definition mongoose6.h:3410
@ MG_RESOLVE_NO_ANSWERS
Definition mongoose6.h:3411
@ MG_DNS_INVALID_RECORD
Definition mongoose6.h:3174
@ MG_DNS_ANSWER
Definition mongoose6.h:3176
@ MG_DNS_QUESTION
Definition mongoose6.h:3175
#define FD_SETSIZE
Definition msystem.h:199
static std::string q(const char *s)
void ** info
Definition fesimdaq.cxx:41
HNDLE hKey
DWORD n[4]
Definition mana.cxx:247
void * data
Definition mana.cxx:268
INT type
Definition mana.cxx:269
BOOL create
Definition mchart.cxx:39
char addr[128]
Definition mcnaf.cxx:104
double count
Definition mdump.cxx:33
KEY key
Definition mdump.cxx:34
INT i
Definition mdump.cxx:32
INT bl
Definition mdump.cxx:29
char response[10000]
Definition melog.cxx:90
#define closesocket(s)
Definition melog.cxx:29
static int offset
Definition mgd.cxx:1500
#define TRUE
Definition midas.h:182
#define end
#define message(type, str)
#define read(n, a, f)
#define sleep(ms)
#define write(n, a, f, d)
#define mask(slot)
Definition midas_macro.h:54
#define begin
#define name(x)
Definition midas_macro.h:24
#define set(var, value)
static std::string remove(const std::string s, char c)
Definition mjsonrpc.cxx:253
static FILE * fp
#define mg_mkdir(x, y)
#define SOMAXCONN
#define HEXTOI(x)
const char * mime_type
static void do_ssi_exec(struct mg_connection *conn, char *tag)
#define INVALID_SOCKET
size_t ext_len
const char * extension
#define INT64_FMT
static const char * month_names[]
#define TCP_NEW
#define MG_COPY_COMMON_CONNECTION_OPTIONS(dst, src)
int mg_pic32_if_listen_udp(struct mg_connection *nc, union socket_address *sa)
#define LOG(l, x)
void mg_pic32_if_udp_send(struct mg_connection *nc, const void *buf, size_t len)
void mg_socket_if_sock_set(struct mg_connection *nc, sock_t sock)
#define IPADDR_NTOA
int cs_dirent_dummy
#define MD5STEP(f, w, x, y, z, data, s)
int _kill(int pid, int sig)
void cs_md5_final(unsigned char digest[16], cs_md5_ctx *ctx)
void mg_lwip_if_connect_udp(struct mg_connection *nc)
struct mg_connection * mg_bind(struct mg_mgr *srv, const char *address, MG_CB(mg_event_handler_t event_handler, void *user_data))
#define NUM_DIGITS
static OsiMsgQ_t s_mg_q
int mg_pic32_if_listen_tcp(struct mg_connection *nc, union socket_address *sa)
int _getpid()
static int mg_accept_conn(struct mg_connection *lc)
#define MG_MALLOC
static int mg_sl_if_listen_tcp(struct mg_connection *nc, union socket_address *sa)
void mg_socket_if_connect_udp(struct mg_connection *nc)
void mg_sl_if_sock_set(struct mg_connection *nc, sock_t sock)
static sock_t mg_open_listening_socket(union socket_address *sa, int type, int proto)
struct mg_str mg_strdup_nul(const struct mg_str s) WEAK
void cs_sha1_transform(uint32_t state[5], const unsigned char buffer[64])
int mg_strcmp(const struct mg_str str1, const struct mg_str str2) WEAK
MG_INTERNAL void mg_remove_conn(struct mg_connection *c)
void sl_restart_cb(struct mg_mgr *mgr)
void cs_md5_init(cs_md5_ctx *ctx)
struct mg_connection * mg_add_sock_opt(struct mg_mgr *s, sock_t sock, MG_CB(mg_event_handler_t callback, void *user_data), struct mg_add_sock_opts opts)
static int mg_sl_if_udp_recv(struct mg_connection *nc, void *buf, size_t len, union socket_address *sa, size_t *sa_len)
const struct mg_iface_vtable * mg_ifaces[]
double cs_timegm(const struct tm *tm)
static void mg_lwip_if_connect_tcp_tcpip(void *arg)
MG_INTERNAL struct mg_connection * mg_create_connection_base(struct mg_mgr *mgr, mg_event_handler_t callback, struct mg_add_sock_opts opts)
static int mg_socket_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len)
cs_log_level
@ LL_INFO
@ LL_DEBUG
@ LL_ERROR
@ LL_NONE
@ _LL_MAX
@ LL_WARN
@ LL_VERBOSE_DEBUG
@ _LL_MIN
#define MG_UDP_IO_SIZE
#define MG_LWIP_IFACE_VTABLE
#define R1(v, w, x, y, z, i)
static int mg_do_recv(struct mg_connection *nc)
MG_INTERNAL struct mg_connection * mg_create_connection(struct mg_mgr *mgr, mg_event_handler_t callback, struct mg_add_sock_opts opts)
void mg_lwip_if_destroy_conn(struct mg_connection *nc)
static int mg_socket_if_udp_recv(struct mg_connection *nc, void *buf, size_t len, union socket_address *sa, size_t *sa_len)
void mg_pic32_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len)
time_t mg_pic32_if_poll(struct mg_iface *iface, int timeout_ms)
static void mg_null_if_add_conn(struct mg_connection *c)
int mg_null_if_tcp_recv(struct mg_connection *c, void *buf, size_t len)
void mg_lwip_if_add_conn(struct mg_connection *nc)
static void mg_lwip_tcp_error_cb(void *arg, err_t err)
void mg_mbuf_append_base64_putc(char ch, void *user_data)
#define _MG_CALLBACK_MODIFIABLE_FLAGS_MASK
void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass, struct mbuf *buf)
static unsigned char from_b64(unsigned char ch)
static void tcp_output_tcpip(void *arg)
bool mg_start_task(int priority, int stack_size, mg_init_cb mg_init)
#define DBG(x)
mg_sig_type
@ MG_SIG_CLOSE_CONN
@ MG_SIG_RECV
@ MG_SIG_TOMBSTONE
@ MG_SIG_ACCEPT
@ MG_SIG_CONNECT_RESULT
#define MBUF_REALLOC
#define _MG_F_FD_ERROR
double mg_mgr_min_timer(const struct mg_mgr *mgr)
static int c_itoa(char *buf, size_t buf_size, int64_t num, int base, int flags, int field_width)
static void mg_lwip_if_connect_udp_tcpip(void *arg)
static void mg_null_if_get_conn_addr(struct mg_connection *c, int remote, union socket_address *sa)
int mg_str_starts_with(struct mg_str s, struct mg_str prefix) WEAK
#define MG_UDP_RECV_BUFFER_SIZE
static int parse_net(const char *spec, uint32_t *net, uint32_t *mask)
struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val, struct mg_str *eq_val) WEAK
#define MIN(a, b)
#define F1(x, y, z)
#define ip_2_ip4(addr)
int mg_lwip_if_create_conn(struct mg_connection *nc)
time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms)
void mg_pic32_if_recved(struct mg_connection *nc, size_t len)
static void mg_null_if_free(struct mg_iface *iface)
void mg_pic32_if_add_conn(struct mg_connection *nc)
void mg_lwip_handle_accept(struct mg_connection *nc)
struct mg_str mg_url_encode(const struct mg_str src)
static int mg_sl_if_create_conn(struct mg_connection *nc)
int mg_asprintf(char **buf, size_t size, const char *fmt,...) WEAK
int _isatty(int fd)
MG_INTERNAL size_t recv_avail_size(struct mg_connection *conn, size_t max)
static void mg_sl_if_connect_tcp(struct mg_connection *nc, const union socket_address *sa)
void mg_lwip_if_get_conn_addr(struct mg_connection *nc, int remote, union socket_address *sa)
void _not_implemented(const char *what)
size_t mbuf_append_and_free(struct mbuf *a, void *buf, size_t len) WEAK
int mg_num_ifaces
static err_t mg_lwip_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb, u16_t num_sent)
void mg_lwip_if_free(struct mg_iface *iface)
struct mg_str mg_url_encode_opt(const struct mg_str src, const struct mg_str safe, unsigned int flags)
int mg_strncmp(const struct mg_str, const struct mg_str, size_t n) WEAK
mg_q_msg_type
@ MG_Q_MSG_CB
int mg_if_poll(struct mg_connection *nc, double now)
static err_t mg_lwip_accept_cb(void *arg, struct tcp_pcb *newtpcb, err_t err)
static int mg_lwip_if_can_send(struct mg_connection *nc, struct mg_lwip_conn_state *cs)
void mg_socket_if_add_conn(struct mg_connection *nc)
void mg_sl_if_add_conn(struct mg_connection *nc)
void mg_sl_if_remove_conn(struct mg_connection *nc)
static void mg_handle_recv(struct mg_connection *nc)
static err_t mg_lwip_tcp_conn_cb(void *arg, struct tcp_pcb *tpcb, err_t err)
static int mg_lwip_if_udp_send(struct mg_connection *nc, const void *data, size_t len)
void mg_lwip_if_remove_conn(struct mg_connection *nc)
void mg_socket_if_get_conn_addr(struct mg_connection *nc, int remote, union socket_address *sa)
static time_t mg_null_if_poll(struct mg_iface *iface, int timeout_ms)
void mg_mgr_init_opt(struct mg_mgr *m, void *user_data, struct mg_mgr_init_opts opts)
static void cs_md5_transform(uint32_t buf[4], uint32_t const in[16])
static void udp_sendto_tcpip(void *arg)
void mg_socket_if_init(struct mg_iface *iface)
struct mg_connection * mg_connect(struct mg_mgr *mgr, const char *address, MG_CB(mg_event_handler_t callback, void *user_data))
#define MG_CALLOC
#define F4(x, y, z)
static void cs_base64_emit_chunk(struct cs_base64_ctx *ctx)
#define MG_PIC32_IFACE_VTABLE
#define _MG_ALLOWED_CONNECT_FLAGS_MASK
static int mg_recv_tcp(struct mg_connection *nc, char *buf, size_t len)
enum cs_log_level cs_log_level WEAK
void mg_pic32_if_init(struct mg_iface *iface)
static void mg_null_if_init(struct mg_iface *iface)
static void mg_null_if_destroy_conn(struct mg_connection *c)
struct mg_str mg_strdup(const struct mg_str s) WEAK
#define TCP_BIND
static int mg_null_if_create_conn(struct mg_connection *c)
void mg_set_non_blocking_mode(sock_t sock)
void mbuf_clear(struct mbuf *mb) WEAK
#define MG_MAX_HOST_LEN
static void mg_null_if_sock_set(struct mg_connection *c, sock_t sock)
void mg_socket_if_connect_tcp(struct mg_connection *nc, const union socket_address *sa)
static int isbyte(int n)
#define UDP_BIND
void mg_socket_if_remove_conn(struct mg_connection *nc)
#define R2(v, w, x, y, z, i)
void mg_pic32_if_connect_udp(struct mg_connection *nc)
void mg_lwip_if_init(struct mg_iface *iface)
const struct mg_iface_vtable mg_default_iface_vtable
void mg_pic32_if_free(struct mg_iface *iface)
static void mg_lwip_recv_common(struct mg_connection *nc, struct pbuf *p)
void mg_if_can_recv_cb(struct mg_connection *nc)
#define CS_LOG_PREFIX_LEN
static int mg_lwip_if_udp_recv(struct mg_connection *nc, void *buf, size_t len, union socket_address *sa, size_t *sa_len)
static int mg_socket_if_udp_send(struct mg_connection *nc, const void *buf, size_t len)
static void mg_sock_get_addr(sock_t sock, int remote, union socket_address *sa)
MG_INTERNAL int mg_parse_address(const char *str, union socket_address *sa, int *proto, char *host, size_t host_len)
static int mg_sl_if_listen_udp(struct mg_connection *nc, union socket_address *sa)
void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr)
void mg_mbuf_append_base64(struct mbuf *mbuf, const void *data, size_t len)
#define _MG_F_FD_CAN_READ
static void byteReverse(unsigned char *buf, unsigned longs)
#define MG_SL_IFACE_VTABLE
static void mg_null_if_connect_udp(struct mg_connection *c)
#define R0(v, w, x, y, z, i)
static void mg_sl_if_connect_udp(struct mg_connection *nc)
MG_INTERNAL int mg_get_errno(void)
static int mg_sl_if_tcp_recv(struct mg_connection *nc, void *buf, size_t len)
#define NUM_UPPERCASES
#define F3(x, y, z)
static void parse_uri_component(const char **p, const char *end, const char *seps, struct mg_str *res)
#define MG_SET_PTRPTR(_ptr, _v)
int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len)
static void tcp_close_tcpip(void *arg)
const struct mg_iface_vtable mg_simplelink_iface_vtable
static int mg_null_if_listen_tcp(struct mg_connection *c, union socket_address *sa)
int mg_assemble_uri(const struct mg_str *scheme, const struct mg_str *user_info, const struct mg_str *host, unsigned int port, const struct mg_str *path, const struct mg_str *query, const struct mg_str *fragment, int normalize_path, struct mg_str *uri)
void mg_pic32_if_destroy_conn(struct mg_connection *nc)
#define NUM_LETTERS
void mg_lwip_if_sock_set(struct mg_connection *nc, sock_t sock)
struct mg_iface * mg_if_create_iface(const struct mg_iface_vtable *vtable, struct mg_mgr *mgr)
static int mg_socket_if_listen_udp(struct mg_connection *nc, union socket_address *sa)
static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
struct mg_connection * mg_bind_opt(struct mg_mgr *mgr, const char *address, MG_CB(mg_event_handler_t callback, void *user_data), struct mg_bind_opts opts)
const char * mg_strstr(const struct mg_str haystack, const struct mg_str needle) WEAK
void mg_lwip_post_signal(enum mg_sig_type sig, struct mg_connection *nc)
static void cs_base64_emit_code(struct cs_base64_ctx *ctx, int v)
const struct mg_iface_vtable mg_pic32_iface_vtable
#define CONSOLE_UART
static int mg_socket_if_tcp_recv(struct mg_connection *nc, void *buf, size_t len)
static void mg_lwip_tcp_write_tcpip(void *arg)
#define MBUF_FREE
char * inet_ntoa(struct in_addr n)
void mg_forward(struct mg_connection *from, struct mg_connection *to)
#define intptr_t
void cs_from_hex(char *to, const char *p, size_t len) WEAK
const struct mg_iface_vtable mg_null_iface_vtable
struct mg_str mg_strstrip(struct mg_str s) WEAK
static int mg_null_if_tcp_send(struct mg_connection *c, const void *buf, size_t len)
static int str_util_lowercase(const char *s)
static int mg_lwip_if_tcp_recv(struct mg_connection *nc, void *buf, size_t len)
static int mg_null_if_udp_send(struct mg_connection *c, const void *buf, size_t len)
#define MG_TCP_IO_SIZE
static void mg_task(void *arg)
void mg_sl_if_get_conn_addr(struct mg_connection *nc, int remote, union socket_address *sa)
void mg_sl_if_destroy_conn(struct mg_connection *nc)
const char * mg_strchr(const struct mg_str s, int c) WEAK
static void mg_lwip_if_listen_tcp_tcpip(void *arg)
void mbuf_move(struct mbuf *from, struct mbuf *to) WEAK
void _exit(int status)
int mg_null_if_udp_recv(struct mg_connection *c, void *buf, size_t len, union socket_address *sa, size_t *sa_len)
int mg_pic32_if_create_conn(struct mg_connection *nc)
#define blk(i)
void mg_pic32_if_get_conn_addr(struct mg_connection *nc, int remote, union socket_address *sa)
static int fourbit(int ch)
#define C_SNPRINTF_FLAG_ZERO
#define MG_REALLOC
struct mg_str mg_mk_str_n(const char *s, size_t len) WEAK
#define BASE64_ENCODE_BODY
void mg_pic32_if_sock_set(struct mg_connection *nc, sock_t sock)
#define R3(v, w, x, y, z, i)
int mg_lwip_if_listen_tcp(struct mg_connection *nc, union socket_address *sa)
#define MG_SOCKET_IFACE_VTABLE
#define MG_INTERNAL
int mg_socket_if_listen_tcp(struct mg_connection *nc, union socket_address *sa)
void mg_sl_if_init(struct mg_iface *iface)
static void mg_null_if_remove_conn(struct mg_connection *c)
const struct mg_iface_vtable mg_socket_iface_vtable
const char * inet_ntop(int af, const void *src, char *dst, socklen_t size)
int gettimeofday(struct timeval *tp, void *tzp)
void cs_md5_update(cs_md5_ctx *ctx, const unsigned char *buf, size_t len)
struct mg_iface * mg_find_iface(struct mg_mgr *mgr, const struct mg_iface_vtable *vtable, struct mg_iface *from)
static void mg_handle_send(struct mg_connection *nc)
void cs_log_set_file_level(const char *file_level)
#define SET_ADDR(dst, src)
static void udp_remove_tcpip(void *arg)
static void mg_lwip_if_listen_udp_tcpip(void *arg)
void mg_sl_if_free(struct mg_iface *iface)
MG_INTERNAL void mg_add_conn(struct mg_mgr *mgr, struct mg_connection *c)
int inet_pton(int af, const char *src, void *dst)
int mg_lwip_if_listen_udp(struct mg_connection *nc, union socket_address *sa)
#define _MG_F_FD_CAN_WRITE
static int mg_sl_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len)
#define MG_FREE
MG_INTERNAL struct mg_connection * mg_do_connect(struct mg_connection *nc, int proto, union socket_address *sa)
void mg_socket_if_free(struct mg_iface *iface)
void mg_if_can_send_cb(struct mg_connection *nc)
#define MG_SIG_QUEUE_LEN
static int mg_sl_if_udp_send(struct mg_connection *nc, const void *buf, size_t len)
static void mg_null_if_connect_tcp(struct mg_connection *c, const union socket_address *sa)
#define F2(x, y, z)
void mg_pic32_if_connect_tcp(struct mg_connection *nc, const union socket_address *sa)
static struct mg_str mg_strdup_common(const struct mg_str s, int nul_terminate)
void mg_lwip_mgr_schedule_poll(struct mg_mgr *mgr)
#define mgos_lock()
void mg_strfree(struct mg_str *s) WEAK
static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
#define mgos_unlock()
void mg_add_to_set(sock_t sock, fd_set *set, sock_t *max_fd)
const struct mg_iface_vtable mg_lwip_iface_vtable
void fprint_str(FILE *fp, const char *str)
struct mg_connection * mg_connect_opt(struct mg_mgr *mgr, const char *address, MG_CB(mg_event_handler_t callback, void *user_data), struct mg_connect_opts opts)
int mg_lwip_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len)
void mg_destroy_conn(struct mg_connection *conn, int destroy_if)
void mg_lwip_if_connect_tcp(struct mg_connection *nc, const union socket_address *sa)
time_t mg_sl_if_poll(struct mg_iface *iface, int timeout_ms)
int mg_socket_if_create_conn(struct mg_connection *nc)
int cs_log_print_prefix(enum cs_log_level level, const char *fname, int line)
static int mg_is_error(void)
#define rol(value, bits)
static uint32_t blk0(union char64long16 *block, int i)
MG_INTERNAL void mg_call(struct mg_connection *nc, mg_event_handler_t ev_handler, void *user_data, int ev, void *ev_data)
static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len)
#define C_SNPRINTF_APPEND_CHAR(ch)
void mg_socket_if_destroy_conn(struct mg_connection *nc)
void mg_run_in_task(void(*cb)(struct mg_mgr *mgr, void *arg), void *cb_arg)
static int mg_null_if_listen_udp(struct mg_connection *c, union socket_address *sa)
void mg_pic32_if_remove_conn(struct mg_connection *nc)
#define R4(v, w, x, y, z, i)
#define MG_NULL_IFACE_VTABLE
void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now)
time_t mg_socket_if_poll(struct mg_iface *iface, int timeout_ms)
#define MAX(a, b)
struct mg_connection * mg_add_sock(struct mg_mgr *s, sock_t sock, MG_CB(mg_event_handler_t callback, void *user_data))
MG_INTERNAL void mg_timer(struct mg_connection *c, double now)
void tcp_recved_tcpip(void *arg)
void mg_set_nameserver(struct mg_mgr *mgr, const char *nameserver)
#define MG_NULL_STR
#define MBUF_SIZE_MAX_HEADROOM
#define MG_AUTH_FLAG_IS_GLOBAL_PASS_FILE
#define DO_NOT_WARN_UNUSED
void mg_http_send_error(struct mg_connection *nc, int code, const char *reason)
#define LIST_INIT(head)
int mg_get_http_basic_auth(struct http_message *hm, char *user, size_t user_len, char *pass, size_t pass_len)
int mg_parse_http_basic_auth(struct mg_str *hdr, char *user, size_t user_len, char *pass, size_t pass_len)
#define MG_UD_ARG(ud)
#define MG_AUTH_FLAG_IS_DIRECTORY
void mg_hash_sha1_v(size_t num_msgs, const uint8_t *msgs[], const size_t *msg_lens, uint8_t *digest)
void mg_send_websocket_handshake3v(struct mg_connection *nc, const struct mg_str path, const struct mg_str host, const struct mg_str protocol, const struct mg_str extra_headers, const struct mg_str user, const struct mg_str pass)
#define MG_ENABLE_HTTP_WEBDAV
#define MG_MK_STR_N(str_literal, len)
#define LIST_REMOVE(elm, field)
#define MG_EV_SSI_CALL_CTX
#define MG_CB(cb, ud)
void mg_http_send_digest_auth_request(struct mg_connection *c, const char *domain)
#define MG_F_SSL
#define PRINTF_LIKE(f, a)
#define MG_AUTH_FLAG_ALLOW_MISSING_FILE
#define LIST_FIRST(head)
#define MG_F_RECV_AND_CLOSE
void mg_http_send_redirect(struct mg_connection *nc, int status_code, const struct mg_str location, const struct mg_str extra_headers)
int mg_check_digest_auth(struct mg_str method, struct mg_str uri, struct mg_str username, struct mg_str cnonce, struct mg_str response, struct mg_str qop, struct mg_str nc, struct mg_str nonce, struct mg_str auth_domain, FILE *fp)
#define MG_MAIN_IFACE
int mg_mqtt_match_topic_expression(struct mg_str exp, struct mg_str topic)
int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain, FILE *fp)
int mg_http_parse_header2(struct mg_str *hdr, const char *var_name, char **buf, size_t buf_size)
void mg_hash_md5_v(size_t num_msgs, const uint8_t *msgs[], const size_t *msg_lens, uint8_t *digest)
#define MG_LWIP
int mg_dns_encode_name(struct mbuf *io, const char *name, size_t len)
#define MG_ENABLE_HTTP_STREAMING_MULTIPART
int mg_mqtt_vmatch_topic_expression(const char *exp, struct mg_str topic)
#define LIST_NEXT(elm, field)
void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path, const char *host, const char *protocol, const char *extra_headers, const char *user, const char *pass)
#define LIST_INSERT_HEAD(head, elm, field)
int mg_dns_copy_questions(struct mbuf *io, struct mg_dns_message *msg)
#define MG_F_ENABLE_BROADCAST
int mg_http_is_authorized(struct http_message *hm, struct mg_str path, const char *domain, const char *passwords_file, int flags)
void mg_register_http_endpoint_opt(struct mg_connection *nc, const char *uri_path, mg_event_handler_t handler, struct mg_http_endpoint_opts opts)
mg_q_msg_type
#define MG_CTL_MSG_MESSAGE_SIZE
#define MG_SIG_QUEUE_LEN
struct mg_str mg_url_encode_opt(const struct mg_str src, const struct mg_str safe, unsigned int flags)
const char * mg_strchr(const struct mg_str s, int c)
struct mg_str mg_mk_str_n(const char *s, size_t len)
#define MG_URL_ENCODE_F_UPPERCASE_HEX
#define MG_URL_ENCODE_F_SPACE_AS_PLUS
static size_t mg_http_parse_chunk(char *buf, size_t len, char **chunk_data, size_t *chunk_len)
mg_http_multipart_stream_state
@ MPS_WAITING_FOR_CHUNK
@ MPS_FINISHED
@ MPS_FINALIZE
@ MPS_GOT_BOUNDARY
@ MPS_WAITING_FOR_BOUNDARY
@ MPS_BEGIN
MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm)
static void mg_send_directory_listing(struct mg_connection *nc, const char *dir, struct http_message *hm, struct mg_serve_http_opts *opts)
MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm, const struct mg_serve_http_opts *opts, char **local_path, struct mg_str *remainder)
static void mg_http_free_proto_data_cgi(struct mg_http_proto_data_cgi *d)
static void mqtt_handler(struct mg_connection *nc, int ev, void *ev_data)
const char * mime_type
#define MG_MALLOC
Definition mongoose6.cxx:14
static int mg_resolve2(const char *host, struct in_addr *ina)
static void mg_handle_cgi(struct mg_connection *nc, const char *prog, const struct mg_str *path_info, const struct http_message *hm, const struct mg_serve_http_opts *opts)
static struct mg_http_proto_data * mg_http_get_proto_data(struct mg_connection *c)
static void mg_send_file_data(struct mg_connection *nc, FILE *fp)
static void mg_resolve_async_eh(struct mg_connection *nc, int ev, void *data)
FILE * cs_log_file
static const struct @23 mg_static_builtin_mime_types[]
#define MIME_ENTRY(_ext, _type)
size_t ext_len
static int mg_create_itermediate_directories(const char *path)
MG_INTERNAL void mg_send_http_file(struct mg_connection *nc, char *path, const struct mg_str *path_info, struct http_message *hm, struct mg_serve_http_opts *opts)
static void dns_handler(struct mg_connection *nc, int ev, void *ev_data)
const char * extension
static void mg_http_construct_etag(char *buf, size_t buf_len, const cs_stat_t *st)
static void mg_http_conn_destructor(void *proto_data)
static int mg_dns_tid
MG_INTERNAL time_t mg_parse_date_string(const char *datetime)
static void resolve_cb(struct mg_dns_message *msg, void *data, enum mg_resolve_err e)
static mg_event_handler_t mg_http_get_endpoint_handler(struct mg_connection *nc, struct mg_str *uri_path)
static int mg_is_ws_first_fragment(unsigned char flags)
static int mg_remove_directory(const struct mg_serve_http_opts *opts, const char *dir)
static int mg_check_nonce(const char *nonce)
static void mg_scan_directory(struct mg_connection *nc, const char *dir, const struct mg_serve_http_opts *opts, void(*func)(struct mg_connection *, const char *, cs_stat_t *))
static void mg_print_dir_entry(struct mg_connection *nc, const char *file_name, cs_stat_t *stp)
struct mg_connection * mg_connect_http_base(struct mg_mgr *mgr, mg_event_handler_t ev_handler, struct mg_connect_opts opts, const char *schema, const char *schema_ssl, const char *url, const char **path, char **addr)
static int left(const struct frozen *f)
static void mg_handle_put(struct mg_connection *nc, const char *path, struct http_message *hm)
static const char * mg_http_parse_headers(const char *s, const char *end, int len, struct http_message *req)
static void mg_escape(const char *src, char *dst, size_t dst_len)
static void mg_send_ssi_file(struct mg_connection *, const char *, FILE *, int, const struct mg_serve_http_opts *)
MG_INTERNAL int mg_is_not_modified(struct http_message *hm, cs_stat_t *st)
static int mg_get_month_index(const char *s)
static uint32_t mg_ws_random_mask(void)
static void mg_http_free_proto_data_file(struct mg_http_proto_data_file *d)
static int mg_get_ip_address_of_nameserver(char *name, size_t name_len)
static int mg_is_dav_request(const struct mg_str *s)
static unsigned char * mg_parse_dns_resource_record(unsigned char *data, unsigned char *end, struct mg_dns_resource_record *rr, int reply)
static void mg_mgr_handle_ctl_sock(struct mg_mgr *mgr)
static char * mg_addenv(struct mg_cgi_env_block *block, const char *fmt,...)
static void mg_ws_mask_frame(struct mbuf *mbuf, struct ws_mask_ctx *ctx)
static void mg_prepare_cgi_environment(struct mg_connection *nc, const char *prog, const struct mg_str *path_info, const struct http_message *hm, const struct mg_serve_http_opts *opts, struct mg_cgi_env_block *blk)
static void mg_handle_incoming_websocket_frame(struct mg_connection *nc, struct websocket_message *wsm)
static int mg_is_file_hidden(const char *path, const struct mg_serve_http_opts *opts, int exclude_specials)
static void mg_handle_ssi_request(struct mg_connection *nc, const char *path, const struct mg_serve_http_opts *opts)
static int mg_http_get_request_len(const char *s, int buf_len)
MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc, struct http_message *hm, char *buf, size_t blen)
static void mg_addenv2(struct mg_cgi_env_block *blk, const char *name)
static void mg_send_ws_header(struct mg_connection *nc, int op, size_t len, struct ws_mask_ctx *ctx)
static int mg_http_parse_range_header(const struct mg_str *header, int64_t *a, int64_t *b)
static void mg_print_props(struct mg_connection *nc, const char *name, cs_stat_t *stp)
static pid_t mg_start_process(const char *interp, const char *cmd, const char *env, const char *envp[], const char *dir, sock_t sock)
static int mg_is_ws_fragment(unsigned char flags)
MG_INTERNAL void mg_find_index_file(const char *path, const char *list, char **index_file, cs_stat_t *stp)
static int mg_deliver_websocket_data(struct mg_connection *nc)
static void mg_http_free_proto_data_endpoints(struct mg_http_endpoint **ep)
static void mg_cgi_ev_handler(struct mg_connection *cgi_nc, int ev, void *ev_data)
static size_t mg_get_line_len(const char *buf, size_t buf_len)
static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev, struct http_message *hm)
static void mg_handle_mkcol(struct mg_connection *nc, const char *path, struct http_message *hm)
static void mg_http_transfer_file_data(struct mg_connection *nc)
static void mg_mkmd5resp(const char *method, size_t method_len, const char *uri, size_t uri_len, const char *ha1, size_t ha1_len, const char *nonce, size_t nonce_len, const char *nc, size_t nc_len, const char *cnonce, size_t cnonce_len, const char *qop, size_t qop_len, char *resp)
mg_http_proto_data_type
@ DATA_FILE
@ DATA_NONE
@ DATA_PUT
void mg_http_handler(struct mg_connection *nc, int ev, void *ev_data)
static int mg_http_send_port_based_redirect(struct mg_connection *c, struct http_message *hm, const struct mg_serve_http_opts *opts)
static void mg_handle_delete(struct mg_connection *nc, const struct mg_serve_http_opts *opts, const char *path)
static void mg_handle_move(struct mg_connection *c, const struct mg_serve_http_opts *opts, const char *path, struct http_message *hm)
static void mg_handle_propfind(struct mg_connection *nc, const char *path, cs_stat_t *stp, struct http_message *hm, struct mg_serve_http_opts *opts)
static void mg_gmt_time_string(char *buf, size_t buf_len, time_t *t)
static void mg_http_send_options(struct mg_connection *nc)
#define MG_DEFAULT_NAMESERVER
static void mg_ws_handshake(struct mg_connection *nc, const struct mg_str *key)
static int mg_is_creation_request(const struct http_message *hm)
static int mg_num_leap_years(int year)
static struct mg_str mg_get_mime_type(const char *path, const char *dflt, const struct mg_serve_http_opts *opts)
static void mg_send_mqtt_short_command(struct mg_connection *nc, uint8_t cmd, uint16_t message_id)
struct callback_addr callback
Definition mserver.cxx:22
timeval tv
Definition msysmon.cxx:1095
#define gmtime
Definition msystem.h:266
#define localtime
Definition msystem.h:265
MUTEX_T * tm
Definition odbedit.cxx:39
INT j
Definition odbhist.cxx:40
double value[100]
Definition odbhist.cxx:42
INT k
Definition odbhist.cxx:40
char str[256]
Definition odbhist.cxx:33
char file_name[256]
Definition odbhist.cxx:41
DWORD status
Definition odbhist.cxx:39
char var_name[256]
Definition odbhist.cxx:41
TH1X EXPRT * h1_book(const char *name, const char *title, int bins, double min, double max)
Definition rmidas.h:24
unsigned char in[64]
uint32_t bits[2]
uint32_t buf[4]
char message[MG_CTL_MSG_MESSAGE_SIZE]
mg_event_handler_t callback
const char * vars[MG_MAX_CGI_ENVIR_VARS]
struct mg_connection * nc
char buf[MG_CGI_ENVIRONMENT_SIZE]
struct mg_iface * iface
struct mg_context * ctx
uint16_t transaction_id
uint16_t num_questions
uint16_t num_answers
uint16_t num_authority_prs
uint16_t num_other_prs
struct mg_ev_mgr_lwip_signal sig_queue[MG_SIG_QUEUE_LEN]
struct mg_connection * nc
mg_event_handler_t handler
struct mg_http_endpoint * next
enum mg_http_multipart_stream_state state
struct mg_connection * cgi_nc
enum mg_http_proto_data_type type
struct mg_http_proto_data_chuncked chunk
struct mg_http_endpoint * endpoints
struct mg_http_proto_data_cgi cgi
mg_event_handler_t endpoint_handler
time_t(* poll)(struct mg_iface *iface, int timeout_ms)
void(* destroy_conn)(struct mg_connection *nc)
int(* listen_tcp)(struct mg_connection *nc, union socket_address *sa)
void(* remove_conn)(struct mg_connection *nc)
void(* connect_tcp)(struct mg_connection *nc, const union socket_address *sa)
void(* free)(struct mg_iface *iface)
void(* init)(struct mg_iface *iface)
void(* get_conn_addr)(struct mg_connection *nc, int remote, union socket_address *sa)
void(* connect_udp)(struct mg_connection *nc)
int(* udp_send)(struct mg_connection *nc, const void *buf, size_t len)
int(* create_conn)(struct mg_connection *nc)
int(* listen_udp)(struct mg_connection *nc, union socket_address *sa)
void(* sock_set)(struct mg_connection *nc, sock_t sock)
int(* udp_recv)(struct mg_connection *nc, void *buf, size_t len, union socket_address *sa, size_t *sa_len)
int(* tcp_send)(struct mg_connection *nc, const void *buf, size_t len)
int(* tcp_recv)(struct mg_connection *nc, void *buf, size_t len)
void(* add_conn)(struct mg_connection *nc)
struct mg_mgr * mgr
const struct mg_iface_vtable * vtable
void * data
struct mg_connection * lc
union mg_lwip_conn_state::@24 pcb
struct pbuf * rx_chain
struct udp_pcb * udp
struct mg_connection * nc
struct tcp_pcb * tcp
const union socket_address * sa
struct mg_connection * nc
struct mg_connection * nc
union socket_address * sa
struct mg_connection * nc
int num_ifaces
struct mg_iface ** ifaces
int num_calls
const char * nameserver
enum mg_q_msg_type type
void(* cb)(struct mg_mgr *mgr, void *arg)
enum mg_resolve_err err
mg_resolve_callback_t callback
struct tcp_pcb * tpcb
struct pbuf * p
struct udp_pcb * upcb
size_t len
uint32_t mask
double d
Definition system.cxx:1311
char c
Definition system.cxx:1310
@ DIR
Definition test_init.cxx:7
static double comma(double a, double b)
Definition tinyexpr.c:248
static double e(void)
Definition tinyexpr.c:136
static te_expr * base(state *s)
Definition tinyexpr.c:357
static double pi(void)
Definition tinyexpr.c:135
static te_expr * list(state *s)
Definition tinyexpr.c:567
unsigned char c[64]
uint32_t l[16]
struct sockaddr_in sin