]> gitweb.ps.run Git - chirp/blob - ext/mongoose.h
bc5f9459948977c94484d7efca9b62ebbb575e41
[chirp] / ext / mongoose.h
1 // Copyright (c) 2004-2013 Sergey Lyubka
2 // Copyright (c) 2013-2022 Cesanta Software Limited
3 // All rights reserved
4 //
5 // This software is dual-licensed: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License version 2 as
7 // published by the Free Software Foundation. For the terms of this
8 // license, see http://www.gnu.org/licenses/
9 //
10 // You are free to use this software under the terms of the GNU General
11 // Public License, but WITHOUT ANY WARRANTY; without even the implied
12 // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 // See the GNU General Public License for more details.
14 //
15 // Alternatively, you can license this software under a commercial
16 // license, as set out in https://www.mongoose.ws/licensing/
17 //
18 // SPDX-License-Identifier: GPL-2.0-only or commercial
19
20 #ifndef MONGOOSE_H
21 #define MONGOOSE_H
22
23 #define MG_VERSION "7.11"
24
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28
29
30 #define MG_ARCH_CUSTOM 0       // User creates its own mongoose_custom.h
31 #define MG_ARCH_UNIX 1         // Linux, BSD, Mac, ...
32 #define MG_ARCH_WIN32 2        // Windows
33 #define MG_ARCH_ESP32 3        // ESP32
34 #define MG_ARCH_ESP8266 4      // ESP8266
35 #define MG_ARCH_FREERTOS 5     // FreeRTOS
36 #define MG_ARCH_AZURERTOS 6    // MS Azure RTOS
37 #define MG_ARCH_ZEPHYR 7       // Zephyr RTOS
38 #define MG_ARCH_NEWLIB 8       // Bare metal ARM
39 #define MG_ARCH_CMSIS_RTOS1 9  // CMSIS-RTOS API v1 (Keil RTX)
40 #define MG_ARCH_TIRTOS 10      // Texas Semi TI-RTOS
41 #define MG_ARCH_RP2040 11      // Raspberry Pi RP2040
42 #define MG_ARCH_ARMCC 12       // Keil MDK-Core with Configuration Wizard
43 #define MG_ARCH_CMSIS_RTOS2 13 // CMSIS-RTOS API v2 (Keil RTX5, FreeRTOS)
44 #define MG_ARCH_RTTHREAD 14    // RT-Thread RTOS
45
46 #if !defined(MG_ARCH)
47 #if defined(__unix__) || defined(__APPLE__)
48 #define MG_ARCH MG_ARCH_UNIX
49 #elif defined(_WIN32)
50 #define MG_ARCH MG_ARCH_WIN32
51 #elif defined(ICACHE_FLASH) || defined(ICACHE_RAM_ATTR)
52 #define MG_ARCH MG_ARCH_ESP8266
53 #elif defined(__ZEPHYR__)
54 #define MG_ARCH MG_ARCH_ZEPHYR
55 #elif defined(ESP_PLATFORM)
56 #define MG_ARCH MG_ARCH_ESP32
57 #elif defined(FREERTOS_IP_H)
58 #define MG_ARCH MG_ARCH_FREERTOS
59 #define MG_ENABLE_FREERTOS_TCP 1
60 #elif defined(AZURE_RTOS_THREADX)
61 #define MG_ARCH MG_ARCH_AZURERTOS
62 #elif defined(PICO_TARGET_NAME)
63 #define MG_ARCH MG_ARCH_RP2040
64 #elif defined(__ARMCC_VERSION)
65 #define MG_ARCH MG_ARCH_ARMCC
66 #elif defined(__RTTHREAD__)
67 #define MG_ARCH MG_ARCH_RTTHREAD
68 #endif
69 #endif  // !defined(MG_ARCH)
70
71 // if the user did not specify an MG_ARCH, or specified a custom one, OR
72 // we guessed a known IDE, pull the customized config (Configuration Wizard)
73 #if !defined(MG_ARCH) || (MG_ARCH == MG_ARCH_CUSTOM) || MG_ARCH == MG_ARCH_ARMCC
74 #include "mongoose_custom.h"  // keep this include
75 #endif
76
77 #if !defined(MG_ARCH)
78 #error "MG_ARCH is not specified and we couldn't guess it. Set -D MG_ARCH=..."
79 #endif
80
81 // http://esr.ibiblio.org/?p=5095
82 #define MG_BIG_ENDIAN (*(uint16_t *) "\0\xff" < 0x100)
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98 #if MG_ARCH == MG_ARCH_AZURERTOS
99
100 #include <stdarg.h>
101 #include <stdbool.h>
102 #include <stdint.h>
103 #include <stdio.h>
104 #include <time.h>
105
106 #include <fx_api.h>
107 #include <tx_api.h>
108
109 #include <nx_api.h>
110 #include <nx_bsd.h>
111 #include <nx_port.h>
112 #include <tx_port.h>
113
114 #define PATH_MAX FX_MAXIMUM_PATH
115 #define MG_DIRSEP '\\'
116
117 #define socklen_t int
118 #define closesocket(x) soc_close(x)
119
120 #undef FOPEN_MAX
121
122 #endif
123
124
125 #if MG_ARCH == MG_ARCH_ESP32
126
127 #include <ctype.h>
128 #include <dirent.h>
129 #include <errno.h>
130 #include <fcntl.h>
131 #include <limits.h>
132 #include <netdb.h>
133 #include <stdarg.h>
134 #include <stddef.h>
135 #include <stdio.h>
136 #include <stdlib.h>
137 #include <string.h>
138 #include <sys/stat.h>
139 #include <sys/types.h>
140 #include <time.h>
141
142 #include <esp_timer.h>
143
144 #define MG_PATH_MAX 128
145
146 #endif
147
148
149 #if MG_ARCH == MG_ARCH_ESP8266
150
151 #include <ctype.h>
152 #include <dirent.h>
153 #include <errno.h>
154 #include <fcntl.h>
155 #include <limits.h>
156 #include <netdb.h>
157 #include <stdarg.h>
158 #include <stdbool.h>
159 #include <stddef.h>
160 #include <stdio.h>
161 #include <stdlib.h>
162 #include <string.h>
163 #include <sys/stat.h>
164 #include <sys/time.h>
165 #include <sys/types.h>
166 #include <time.h>
167
168 #include <esp_system.h>
169
170 #define MG_PATH_MAX 128
171
172 #endif
173
174
175 #if MG_ARCH == MG_ARCH_FREERTOS
176
177 #include <ctype.h>
178 #if !defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP
179 #include <errno.h>
180 #endif
181 #include <stdarg.h>
182 #include <stdbool.h>
183 #include <stddef.h>
184 #include <stdint.h>
185 #include <stdio.h>
186 #include <stdlib.h> // rand(), strtol(), atoi()
187 #include <string.h>
188 #if defined(__ARMCC_VERSION)
189 #define mode_t size_t
190 #include <time.h>
191 #else
192 #include <sys/stat.h>
193 #endif
194
195 #include <FreeRTOS.h>
196 #include <task.h>
197
198 #ifndef MG_IO_SIZE
199 #define MG_IO_SIZE 512
200 #endif
201
202 #define calloc(a, b) mg_calloc(a, b)
203 #define free(a) vPortFree(a)
204 #define malloc(a) pvPortMalloc(a)
205 #define strdup(s) ((char *) mg_strdup(mg_str(s)).ptr)
206
207 // Re-route calloc/free to the FreeRTOS's functions, don't use stdlib
208 static inline void *mg_calloc(size_t cnt, size_t size) {
209   void *p = pvPortMalloc(cnt * size);
210   if (p != NULL) memset(p, 0, size * cnt);
211   return p;
212 }
213
214 #define mkdir(a, b) mg_mkdir(a, b)
215 static inline int mg_mkdir(const char *path, mode_t mode) {
216   (void) path, (void) mode;
217   return -1;
218 }
219
220 #endif  // MG_ARCH == MG_ARCH_FREERTOS
221
222
223 #if MG_ARCH == MG_ARCH_NEWLIB
224 #define _POSIX_TIMERS
225
226 #include <ctype.h>
227 #include <errno.h>
228 #include <stdarg.h>
229 #include <stdbool.h>
230 #include <stdio.h>
231 #include <stdlib.h>
232 #include <string.h>
233 #include <sys/stat.h>
234 #include <sys/time.h>
235 #include <sys/types.h>
236 #include <time.h>
237 #include <unistd.h>
238
239 #define MG_PATH_MAX 100
240 #define MG_ENABLE_SOCKET 0
241 #define MG_ENABLE_DIRLIST 0
242
243 #endif
244
245
246 #if MG_ARCH == MG_ARCH_RP2040
247 #include <errno.h>
248 #include <stdarg.h>
249 #include <stdbool.h>
250 #include <stdint.h>
251 #include <stdio.h>
252 #include <stdlib.h>
253 #include <string.h>
254 #include <time.h>
255
256 #include <pico/stdlib.h>
257 int mkdir(const char *, mode_t);
258 #endif
259 \r
260 \r
261 #if MG_ARCH == MG_ARCH_RTTHREAD\r
262 \r
263 #include <rtthread.h>\r
264 #include <ctype.h>\r
265 #include <errno.h>\r
266 #include <fcntl.h>\r
267 #include <sys/socket.h>\r
268 #include <sys/select.h>\r
269 #include <stdarg.h>\r
270 #include <stdbool.h>\r
271 #include <stdint.h>\r
272 #include <stdio.h>\r
273 #include <stdlib.h>\r
274 #include <string.h>\r
275 #include <sys/types.h>\r
276 #include <time.h>\r
277 \r
278 #ifndef MG_IO_SIZE\r
279 #define MG_IO_SIZE 1460\r
280 #endif\r
281 \r
282 #endif // MG_ARCH == MG_ARCH_RTTHREAD\r
283
284
285 #if MG_ARCH == MG_ARCH_ARMCC || MG_ARCH == MG_ARCH_CMSIS_RTOS1 || \
286     MG_ARCH == MG_ARCH_CMSIS_RTOS2
287
288 #include <ctype.h>
289 #include <errno.h>
290 #include <stdarg.h>
291 #include <stdbool.h>
292 #include <stddef.h>
293 #include <stdint.h>
294 #include <stdio.h>
295 #include <stdlib.h>
296 #include <string.h>
297 #include <time.h>
298 #if MG_ARCH == MG_ARCH_CMSIS_RTOS1
299 #include "cmsis_os.h"  // keep this include
300 // https://developer.arm.com/documentation/ka003821/latest
301 extern uint32_t rt_time_get(void);
302 #elif MG_ARCH == MG_ARCH_CMSIS_RTOS2
303 #include "cmsis_os2.h"  // keep this include
304 #endif
305
306 #define strdup(s) ((char *) mg_strdup(mg_str(s)).ptr)
307
308 #if defined(__ARMCC_VERSION)
309 #define mode_t size_t
310 #define mkdir(a, b) mg_mkdir(a, b)
311 static inline int mg_mkdir(const char *path, mode_t mode) {
312   (void) path, (void) mode;
313   return -1;
314 }
315 #endif
316
317 #if (MG_ARCH == MG_ARCH_CMSIS_RTOS1 || MG_ARCH == MG_ARCH_CMSIS_RTOS2) &&     \
318     !defined MG_ENABLE_RL && (!defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP) && \
319     (!defined(MG_ENABLE_TCPIP) || !MG_ENABLE_TCPIP)
320 #define MG_ENABLE_RL 1
321 #endif
322
323 #endif
324
325
326 #if MG_ARCH == MG_ARCH_TIRTOS
327
328 #include <stdlib.h>
329 #include <ctype.h>
330 #include <stdarg.h>
331 #include <stdbool.h>
332 #include <stdint.h>
333 #include <stdio.h>
334 #include <string.h>
335 #include <time.h>
336
337 #include <serrno.h>
338 #include <sys/socket.h>
339
340 #include <ti/sysbios/knl/Clock.h>
341
342 #endif
343
344
345 #if MG_ARCH == MG_ARCH_UNIX
346
347 #define _DARWIN_UNLIMITED_SELECT 1  // No limit on file descriptors
348
349 #if defined(__APPLE__)
350 #include <mach/mach_time.h>
351 #endif
352
353 #if !defined(MG_ENABLE_EPOLL) && defined(__linux__)
354 #define MG_ENABLE_EPOLL 1
355 #elif !defined(MG_ENABLE_POLL)
356 #define MG_ENABLE_POLL 1
357 #endif
358
359 #include <arpa/inet.h>
360 #include <ctype.h>
361 #include <dirent.h>
362 #include <errno.h>
363 #include <fcntl.h>
364 #include <inttypes.h>
365 #include <limits.h>
366 #include <netdb.h>
367 #include <netinet/in.h>
368 #include <netinet/tcp.h>
369 #include <signal.h>
370 #include <stdarg.h>
371 #include <stdbool.h>
372 #include <stddef.h>
373 #include <stdint.h>
374 #include <stdio.h>
375 #include <stdlib.h>
376 #include <string.h>
377
378 #if defined(MG_ENABLE_EPOLL) && MG_ENABLE_EPOLL
379 #include <sys/epoll.h>
380 #elif defined(MG_ENABLE_POLL) && MG_ENABLE_POLL
381 #include <poll.h>
382 #else
383 #include <sys/select.h>
384 #endif
385
386 #include <sys/socket.h>
387 #include <sys/stat.h>
388 #include <sys/time.h>
389 #include <sys/types.h>
390 #include <time.h>
391 #include <unistd.h>
392
393 #ifndef MG_ENABLE_DIRLIST
394 #define MG_ENABLE_DIRLIST 1
395 #endif
396
397 #ifndef MG_PATH_MAX
398 #define MG_PATH_MAX FILENAME_MAX
399 #endif
400
401 #endif
402
403
404 #if MG_ARCH == MG_ARCH_WIN32
405
406 #ifndef WIN32_LEAN_AND_MEAN
407 #define WIN32_LEAN_AND_MEAN
408 #endif
409
410 #ifndef _CRT_SECURE_NO_WARNINGS
411 #define _CRT_SECURE_NO_WARNINGS
412 #endif
413
414 #ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
415 #define _WINSOCK_DEPRECATED_NO_WARNINGS
416 #endif
417
418 #include <ctype.h>
419 #include <direct.h>
420 #include <errno.h>
421 #include <fcntl.h>
422 #include <limits.h>
423 #include <signal.h>
424 #include <stdarg.h>
425 #include <stddef.h>
426 #include <stdio.h>
427 #include <stdlib.h>
428 #include <string.h>
429 #include <sys/stat.h>
430 #include <sys/types.h>
431 #include <time.h>
432
433 #if defined(_MSC_VER) && _MSC_VER < 1700
434 #define __func__ ""
435 typedef __int64 int64_t;
436 typedef unsigned __int64 uint64_t;
437 typedef unsigned char uint8_t;
438 typedef char int8_t;
439 typedef unsigned short uint16_t;
440 typedef short int16_t;
441 typedef unsigned int uint32_t;
442 typedef int int32_t;
443 typedef enum { false = 0, true = 1 } bool;
444 #else
445 #include <stdbool.h>
446 #include <stdint.h>
447 #include <ws2tcpip.h>
448 #endif
449
450 #include <process.h>
451 #include <winerror.h>
452 #include <winsock2.h>
453
454 // Protect from calls like std::snprintf in app code
455 // See https://github.com/cesanta/mongoose/issues/1047
456 #ifndef __cplusplus
457 #define snprintf _snprintf
458 #define vsnprintf _vsnprintf
459 #ifndef strdup  // For MSVC with _DEBUG, see #1359
460 #define strdup(x) _strdup(x)
461 #endif
462 #endif
463
464 #define MG_INVALID_SOCKET INVALID_SOCKET
465 #define MG_SOCKET_TYPE SOCKET
466 typedef unsigned long nfds_t;
467 #if defined(_MSC_VER)
468 #pragma comment(lib, "ws2_32.lib")
469 #ifndef alloca
470 #define alloca(a) _alloca(a)
471 #endif
472 #endif
473 #define poll(a, b, c) WSAPoll((a), (b), (c))
474 #define closesocket(x) closesocket(x)
475
476 typedef int socklen_t;
477 #define MG_DIRSEP '\\'
478
479 #ifndef MG_PATH_MAX
480 #define MG_PATH_MAX FILENAME_MAX
481 #endif
482
483 #ifndef SO_EXCLUSIVEADDRUSE
484 #define SO_EXCLUSIVEADDRUSE ((int) (~SO_REUSEADDR))
485 #endif
486
487 #define MG_SOCK_ERR(errcode) ((errcode) < 0 ? WSAGetLastError() : 0)
488
489 #define MG_SOCK_PENDING(errcode)                                            \
490   (((errcode) < 0) &&                                                       \
491    (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEINPROGRESS || \
492     WSAGetLastError() == WSAEWOULDBLOCK))
493
494 #define MG_SOCK_RESET(errcode) \
495   (((errcode) < 0) && (WSAGetLastError() == WSAECONNRESET))
496
497 #define realpath(a, b) _fullpath((b), (a), MG_PATH_MAX)
498 #define sleep(x) Sleep((x) *1000)
499 #define mkdir(a, b) _mkdir(a)
500
501 #ifndef S_ISDIR
502 #define S_ISDIR(x) (((x) &_S_IFMT) == _S_IFDIR)
503 #endif
504
505 #ifndef MG_ENABLE_DIRLIST
506 #define MG_ENABLE_DIRLIST 1
507 #endif
508
509 #ifndef SIGPIPE
510 #define SIGPIPE 0
511 #endif
512
513 #endif
514
515
516 #if MG_ARCH == MG_ARCH_ZEPHYR
517
518 #include <zephyr/kernel.h>
519
520 #include <ctype.h>
521 #include <errno.h>
522 #include <fcntl.h>
523 #include <zephyr/net/socket.h>
524 #include <stdarg.h>
525 #include <stdbool.h>
526 #include <stdint.h>
527 #include <stdio.h>
528 #include <stdlib.h>
529 #include <string.h>
530 #include <sys/types.h>
531 #include <time.h>
532
533 #define MG_PUTCHAR(x) printk("%c", x)
534 #ifndef strdup
535 #define strdup(s) ((char *) mg_strdup(mg_str(s)).ptr)
536 #endif
537 #define strerror(x) zsock_gai_strerror(x)
538 #define FD_CLOEXEC 0
539 #define F_SETFD 0
540 #define MG_ENABLE_SSI 0
541
542 int rand(void);
543 int sscanf(const char *, const char *, ...);
544
545 #endif
546
547
548 #if defined(MG_ENABLE_FREERTOS_TCP) && MG_ENABLE_FREERTOS_TCP
549
550 #include <limits.h>
551 #include <list.h>
552
553 #include <FreeRTOS_IP.h>
554 #include <FreeRTOS_Sockets.h>
555 #include <FreeRTOS_errno_TCP.h>  // contents to be moved and file removed, some day
556
557 #define MG_SOCKET_TYPE Socket_t
558 #define MG_INVALID_SOCKET FREERTOS_INVALID_SOCKET
559
560 // Why FreeRTOS-TCP did not implement a clean BSD API, but its own thing
561 // with FreeRTOS_ prefix, is beyond me
562 #define IPPROTO_TCP FREERTOS_IPPROTO_TCP
563 #define IPPROTO_UDP FREERTOS_IPPROTO_UDP
564 #define AF_INET FREERTOS_AF_INET
565 #define SOCK_STREAM FREERTOS_SOCK_STREAM
566 #define SOCK_DGRAM FREERTOS_SOCK_DGRAM
567 #define SO_BROADCAST 0
568 #define SO_ERROR 0
569 #define SOL_SOCKET 0
570 #define SO_REUSEADDR 0
571
572 #define MG_SOCK_ERR(errcode) ((errcode) < 0 ? (errcode) : 0)
573
574 #define MG_SOCK_PENDING(errcode)                 \
575   ((errcode) == -pdFREERTOS_ERRNO_EWOULDBLOCK || \
576    (errcode) == -pdFREERTOS_ERRNO_EISCONN ||     \
577    (errcode) == -pdFREERTOS_ERRNO_EINPROGRESS || \
578    (errcode) == -pdFREERTOS_ERRNO_EAGAIN)
579
580 #define MG_SOCK_RESET(errcode) ((errcode) == -pdFREERTOS_ERRNO_ENOTCONN)
581
582 // actually only if optional timeout is enabled
583 #define MG_SOCK_INTR(fd) (fd == NULL)
584
585 #define sockaddr_in freertos_sockaddr
586 #define sockaddr freertos_sockaddr
587 #define accept(a, b, c) FreeRTOS_accept((a), (b), (c))
588 #define connect(a, b, c) FreeRTOS_connect((a), (b), (c))
589 #define bind(a, b, c) FreeRTOS_bind((a), (b), (c))
590 #define listen(a, b) FreeRTOS_listen((a), (b))
591 #define socket(a, b, c) FreeRTOS_socket((a), (b), (c))
592 #define send(a, b, c, d) FreeRTOS_send((a), (b), (c), (d))
593 #define recv(a, b, c, d) FreeRTOS_recv((a), (b), (c), (d))
594 #define setsockopt(a, b, c, d, e) FreeRTOS_setsockopt((a), (b), (c), (d), (e))
595 #define sendto(a, b, c, d, e, f) FreeRTOS_sendto((a), (b), (c), (d), (e), (f))
596 #define recvfrom(a, b, c, d, e, f) \
597   FreeRTOS_recvfrom((a), (b), (c), (d), (e), (f))
598 #define closesocket(x) FreeRTOS_closesocket(x)
599 #define gethostbyname(x) FreeRTOS_gethostbyname(x)
600 #define getsockname(a, b, c) mg_getsockname((a), (b), (c))
601 #define getpeername(a, b, c) mg_getpeername((a), (b), (c))
602
603 static inline int mg_getsockname(MG_SOCKET_TYPE fd, void *buf, socklen_t *len) {
604   (void) fd, (void) buf, (void) len;
605   return -1;
606 }
607
608 static inline int mg_getpeername(MG_SOCKET_TYPE fd, void *buf, socklen_t *len) {
609   (void) fd, (void) buf, (void) len;
610   return 0;
611 }
612 #endif
613
614
615 #if defined(MG_ENABLE_LWIP) && MG_ENABLE_LWIP
616
617 #if defined(__GNUC__) && !defined(__ARMCC_VERSION)
618 #include <sys/stat.h>
619 #endif
620
621 struct timeval;
622
623 #include <lwip/sockets.h>
624
625 #if !LWIP_TIMEVAL_PRIVATE
626 #if defined(__GNUC__) && !defined(__ARMCC_VERSION) // armclang sets both
627 #include <sys/time.h>
628 #else
629 struct timeval {
630   time_t tv_sec;
631   long tv_usec;
632 };
633 #endif
634 #endif
635
636 #if LWIP_SOCKET != 1
637 // Sockets support disabled in LWIP by default
638 #error Set LWIP_SOCKET variable to 1 (in lwipopts.h)
639 #endif
640 #endif
641
642
643 #if defined(MG_ENABLE_RL) && MG_ENABLE_RL
644 #include <rl_net.h>
645
646 #define closesocket(x) closesocket(x)
647
648 #define TCP_NODELAY SO_KEEPALIVE
649
650 #define MG_SOCK_ERR(errcode) ((errcode) < 0 ? (errcode) : 0)
651
652 #define MG_SOCK_PENDING(errcode)                                \
653   ((errcode) == BSD_EWOULDBLOCK || (errcode) == BSD_EALREADY || \
654    (errcode) == BSD_EINPROGRESS)
655
656 #define MG_SOCK_RESET(errcode) \
657   ((errcode) == BSD_ECONNABORTED || (errcode) == BSD_ECONNRESET)
658
659 // In blocking mode, which is enabled by default, accept() waits for a
660 // connection request. In non blocking mode, you must call accept()
661 // again if the error code BSD_EWOULDBLOCK is returned.
662 #define MG_SOCK_INTR(fd) (fd == BSD_EWOULDBLOCK)
663
664 #define socklen_t int
665 #endif
666
667
668 #ifndef MG_ENABLE_LOG
669 #define MG_ENABLE_LOG 1
670 #endif
671
672 #ifndef MG_ENABLE_TCPIP
673 #define MG_ENABLE_TCPIP 0  // Mongoose built-in network stack
674 #endif
675
676 #ifndef MG_ENABLE_LWIP
677 #define MG_ENABLE_LWIP 0  // lWIP network stack
678 #endif
679
680 #ifndef MG_ENABLE_FREERTOS_TCP
681 #define MG_ENABLE_FREERTOS_TCP 0  // Amazon FreeRTOS-TCP network stack
682 #endif
683
684 #ifndef MG_ENABLE_RL
685 #define MG_ENABLE_RL 0  // ARM MDK network stack
686 #endif
687
688 #ifndef MG_ENABLE_SOCKET
689 #define MG_ENABLE_SOCKET !MG_ENABLE_TCPIP
690 #endif
691
692 #ifndef MG_ENABLE_POLL
693 #define MG_ENABLE_POLL 0
694 #endif
695
696 #ifndef MG_ENABLE_EPOLL
697 #define MG_ENABLE_EPOLL 0
698 #endif
699
700 #ifndef MG_ENABLE_FATFS
701 #define MG_ENABLE_FATFS 0
702 #endif
703
704 #ifndef MG_ENABLE_SSI
705 #define MG_ENABLE_SSI 0
706 #endif
707
708 #ifndef MG_ENABLE_IPV6
709 #define MG_ENABLE_IPV6 0
710 #endif
711
712 #ifndef MG_ENABLE_MD5
713 #define MG_ENABLE_MD5 1
714 #endif
715
716 // Set MG_ENABLE_WINSOCK=0 for Win32 builds with external IP stack (like LWIP)
717 #ifndef MG_ENABLE_WINSOCK
718 #define MG_ENABLE_WINSOCK 1
719 #endif
720
721 #ifndef MG_ENABLE_DIRLIST
722 #define MG_ENABLE_DIRLIST 0
723 #endif
724
725 #ifndef MG_ENABLE_CUSTOM_RANDOM
726 #define MG_ENABLE_CUSTOM_RANDOM 0
727 #endif
728
729 #ifndef MG_ENABLE_CUSTOM_MILLIS
730 #define MG_ENABLE_CUSTOM_MILLIS 0
731 #endif
732
733 #ifndef MG_ENABLE_PACKED_FS
734 #define MG_ENABLE_PACKED_FS 0
735 #endif
736
737 #ifndef MG_ENABLE_ASSERT
738 #define MG_ENABLE_ASSERT 0
739 #endif
740
741 #ifndef MG_IO_SIZE
742 #define MG_IO_SIZE 2048  // Granularity of the send/recv IO buffer growth
743 #endif
744
745 #ifndef MG_MAX_RECV_SIZE
746 #define MG_MAX_RECV_SIZE (3UL * 1024UL * 1024UL)  // Maximum recv IO buffer size
747 #endif
748
749 #ifndef MG_DATA_SIZE
750 #define MG_DATA_SIZE 32  // struct mg_connection :: data size
751 #endif
752
753 #ifndef MG_MAX_HTTP_HEADERS
754 #define MG_MAX_HTTP_HEADERS 30
755 #endif
756
757 #ifndef MG_HTTP_INDEX
758 #define MG_HTTP_INDEX "index.html"
759 #endif
760
761 #ifndef MG_PATH_MAX
762 #ifdef PATH_MAX
763 #define MG_PATH_MAX PATH_MAX
764 #else
765 #define MG_PATH_MAX 128
766 #endif
767 #endif
768
769 #ifndef MG_SOCK_LISTEN_BACKLOG_SIZE
770 #define MG_SOCK_LISTEN_BACKLOG_SIZE 3
771 #endif
772
773 #ifndef MG_DIRSEP
774 #define MG_DIRSEP '/'
775 #endif
776
777 #ifndef MG_ENABLE_FILE
778 #if defined(FOPEN_MAX)
779 #define MG_ENABLE_FILE 1
780 #else
781 #define MG_ENABLE_FILE 0
782 #endif
783 #endif
784
785 #ifndef MG_INVALID_SOCKET
786 #define MG_INVALID_SOCKET (-1)
787 #endif
788
789 #ifndef MG_SOCKET_TYPE
790 #define MG_SOCKET_TYPE int
791 #endif
792
793 #ifndef MG_SOCKET_ERRNO
794 #define MG_SOCKET_ERRNO errno
795 #endif
796
797 #if MG_ENABLE_EPOLL
798 #define MG_EPOLL_ADD(c)                                                    \
799   do {                                                                     \
800     struct epoll_event ev = {EPOLLIN | EPOLLERR | EPOLLHUP, {c}};          \
801     epoll_ctl(c->mgr->epoll_fd, EPOLL_CTL_ADD, (int) (size_t) c->fd, &ev); \
802   } while (0)
803 #define MG_EPOLL_MOD(c, wr)                                                \
804   do {                                                                     \
805     struct epoll_event ev = {EPOLLIN | EPOLLERR | EPOLLHUP, {c}};          \
806     if (wr) ev.events |= EPOLLOUT;                                         \
807     epoll_ctl(c->mgr->epoll_fd, EPOLL_CTL_MOD, (int) (size_t) c->fd, &ev); \
808   } while (0)
809 #else
810 #define MG_EPOLL_ADD(c)
811 #define MG_EPOLL_MOD(c, wr)
812 #endif
813
814
815
816
817 struct mg_str {
818   const char *ptr;  // Pointer to string data
819   size_t len;       // String len
820 };
821
822 #define MG_NULL_STR \
823   { NULL, 0 }
824
825 #define MG_C_STR(a) \
826   { (a), sizeof(a) - 1 }
827
828 // Using macro to avoid shadowing C++ struct constructor, see #1298
829 #define mg_str(s) mg_str_s(s)
830
831 struct mg_str mg_str(const char *s);
832 struct mg_str mg_str_n(const char *s, size_t n);
833 int mg_lower(const char *s);
834 int mg_ncasecmp(const char *s1, const char *s2, size_t len);
835 int mg_casecmp(const char *s1, const char *s2);
836 int mg_vcmp(const struct mg_str *s1, const char *s2);
837 int mg_vcasecmp(const struct mg_str *str1, const char *str2);
838 int mg_strcmp(const struct mg_str str1, const struct mg_str str2);
839 struct mg_str mg_strstrip(struct mg_str s);
840 struct mg_str mg_strdup(const struct mg_str s);
841 const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle);
842 bool mg_match(struct mg_str str, struct mg_str pattern, struct mg_str *caps);
843 bool mg_globmatch(const char *pattern, size_t plen, const char *s, size_t n);
844 bool mg_commalist(struct mg_str *s, struct mg_str *k, struct mg_str *v);
845 bool mg_split(struct mg_str *s, struct mg_str *k, struct mg_str *v, char delim);
846 char *mg_hex(const void *buf, size_t len, char *dst);
847 void mg_unhex(const char *buf, size_t len, unsigned char *to);
848 unsigned long mg_unhexn(const char *s, size_t len);
849 bool mg_path_is_sane(const char *path);
850
851
852
853
854 // Single producer, single consumer non-blocking queue
855
856 struct mg_queue {
857   char *buf;
858   size_t size;
859   volatile size_t tail;
860   volatile size_t head;
861 };
862
863 void mg_queue_init(struct mg_queue *, char *, size_t);        // Init queue
864 size_t mg_queue_book(struct mg_queue *, char **buf, size_t);  // Reserve space
865 void mg_queue_add(struct mg_queue *, size_t);                 // Add new message
866 size_t mg_queue_next(struct mg_queue *, char **);  // Get oldest message
867 void mg_queue_del(struct mg_queue *, size_t);      // Delete oldest message
868
869
870
871
872 typedef void (*mg_pfn_t)(char, void *);                  // Output function
873 typedef size_t (*mg_pm_t)(mg_pfn_t, void *, va_list *);  // %M printer
874
875 size_t mg_vxprintf(void (*)(char, void *), void *, const char *fmt, va_list *);
876 size_t mg_xprintf(void (*fn)(char, void *), void *, const char *fmt, ...);
877
878
879
880
881
882
883 // Convenience wrappers around mg_xprintf
884 size_t mg_vsnprintf(char *buf, size_t len, const char *fmt, va_list *ap);
885 size_t mg_snprintf(char *, size_t, const char *fmt, ...);
886 char *mg_vmprintf(const char *fmt, va_list *ap);
887 char *mg_mprintf(const char *fmt, ...);
888 size_t mg_queue_vprintf(struct mg_queue *, const char *fmt, va_list *);
889 size_t mg_queue_printf(struct mg_queue *, const char *fmt, ...);
890
891 // %M print helper functions
892 size_t mg_print_base64(void (*out)(char, void *), void *arg, va_list *ap);
893 size_t mg_print_esc(void (*out)(char, void *), void *arg, va_list *ap);
894 size_t mg_print_hex(void (*out)(char, void *), void *arg, va_list *ap);
895 size_t mg_print_ip(void (*out)(char, void *), void *arg, va_list *ap);
896 size_t mg_print_ip_port(void (*out)(char, void *), void *arg, va_list *ap);
897 size_t mg_print_ip4(void (*out)(char, void *), void *arg, va_list *ap);
898 size_t mg_print_ip6(void (*out)(char, void *), void *arg, va_list *ap);
899 size_t mg_print_mac(void (*out)(char, void *), void *arg, va_list *ap);
900
901 // Various output functions
902 void mg_pfn_iobuf(char ch, void *param);  // param: struct mg_iobuf *
903 void mg_pfn_stdout(char c, void *param);  // param: ignored
904
905 // A helper macro for printing JSON: mg_snprintf(buf, len, "%m", MG_ESC("hi"))
906 #define MG_ESC(str) mg_print_esc, 0, (str)
907
908
909
910
911
912
913 enum { MG_LL_NONE, MG_LL_ERROR, MG_LL_INFO, MG_LL_DEBUG, MG_LL_VERBOSE };
914 void mg_log(const char *fmt, ...);
915 bool mg_log_prefix(int ll, const char *file, int line, const char *fname);
916 void mg_log_set(int log_level);
917 void mg_hexdump(const void *buf, size_t len);
918 void mg_log_set_fn(mg_pfn_t fn, void *param);
919
920 #if MG_ENABLE_LOG
921 #define MG_LOG(level, args)                                                \
922   do {                                                                     \
923     if (mg_log_prefix((level), __FILE__, __LINE__, __func__)) mg_log args; \
924   } while (0)
925 #else
926 #define MG_LOG(level, args) \
927   do {                      \
928     if (0) mg_log args;     \
929   } while (0)
930 #endif
931
932 #define MG_ERROR(args) MG_LOG(MG_LL_ERROR, args)
933 #define MG_INFO(args) MG_LOG(MG_LL_INFO, args)
934 #define MG_DEBUG(args) MG_LOG(MG_LL_DEBUG, args)
935 #define MG_VERBOSE(args) MG_LOG(MG_LL_VERBOSE, args)
936
937
938
939
940 struct mg_timer {
941   unsigned long id;         // Timer ID
942   uint64_t period_ms;       // Timer period in milliseconds
943   uint64_t expire;          // Expiration timestamp in milliseconds
944   unsigned flags;           // Possible flags values below
945 #define MG_TIMER_ONCE 0     // Call function once
946 #define MG_TIMER_REPEAT 1   // Call function periodically
947 #define MG_TIMER_RUN_NOW 2  // Call immediately when timer is set
948   void (*fn)(void *);       // Function to call
949   void *arg;                // Function argument
950   struct mg_timer *next;    // Linkage
951 };
952
953 void mg_timer_init(struct mg_timer **head, struct mg_timer *timer,
954                    uint64_t milliseconds, unsigned flags, void (*fn)(void *),
955                    void *arg);
956 void mg_timer_free(struct mg_timer **head, struct mg_timer *);
957 void mg_timer_poll(struct mg_timer **head, uint64_t new_ms);
958 bool mg_timer_expired(uint64_t *expiration, uint64_t period, uint64_t now);
959
960
961
962
963
964 enum { MG_FS_READ = 1, MG_FS_WRITE = 2, MG_FS_DIR = 4 };
965
966 // Filesystem API functions
967 // st() returns MG_FS_* flags and populates file size and modification time
968 // ls() calls fn() for every directory entry, allowing to list a directory
969 //
970 // NOTE: UNIX-style shorthand names for the API functions are deliberately
971 // chosen to avoid conflicts with some libraries that make macros for e.g.
972 // stat(), write(), read() calls.
973 struct mg_fs {
974   int (*st)(const char *path, size_t *size, time_t *mtime);  // stat file
975   void (*ls)(const char *path, void (*fn)(const char *, void *), void *);
976   void *(*op)(const char *path, int flags);             // Open file
977   void (*cl)(void *fd);                                 // Close file
978   size_t (*rd)(void *fd, void *buf, size_t len);        // Read file
979   size_t (*wr)(void *fd, const void *buf, size_t len);  // Write file
980   size_t (*sk)(void *fd, size_t offset);                // Set file position
981   bool (*mv)(const char *from, const char *to);         // Rename file
982   bool (*rm)(const char *path);                         // Delete file
983   bool (*mkd)(const char *path);                        // Create directory
984 };
985
986 extern struct mg_fs mg_fs_posix;   // POSIX open/close/read/write/seek
987 extern struct mg_fs mg_fs_packed;  // Packed FS, see examples/device-dashboard
988 extern struct mg_fs mg_fs_fat;     // FAT FS
989
990 // File descriptor
991 struct mg_fd {
992   void *fd;
993   struct mg_fs *fs;
994 };
995
996 struct mg_fd *mg_fs_open(struct mg_fs *fs, const char *path, int flags);
997 void mg_fs_close(struct mg_fd *fd);
998 char *mg_file_read(struct mg_fs *fs, const char *path, size_t *size);
999 bool mg_file_write(struct mg_fs *fs, const char *path, const void *, size_t);
1000 bool mg_file_printf(struct mg_fs *fs, const char *path, const char *fmt, ...);
1001
1002
1003
1004
1005
1006
1007
1008 #if MG_ENABLE_ASSERT
1009 #include <assert.h>
1010 #elif !defined(assert)
1011 #define assert(x)
1012 #endif
1013
1014 void mg_random(void *buf, size_t len);
1015 char *mg_random_str(char *buf, size_t len);
1016 uint16_t mg_ntohs(uint16_t net);
1017 uint32_t mg_ntohl(uint32_t net);
1018 uint32_t mg_crc32(uint32_t crc, const char *buf, size_t len);
1019 uint64_t mg_millis(void);
1020
1021 #define mg_htons(x) mg_ntohs(x)
1022 #define mg_htonl(x) mg_ntohl(x)
1023
1024 #define MG_U32(a, b, c, d)                                         \
1025   (((uint32_t) ((a) &255) << 24) | ((uint32_t) ((b) &255) << 16) | \
1026    ((uint32_t) ((c) &255) << 8) | (uint32_t) ((d) &255))
1027
1028 // For printing IPv4 addresses: printf("%d.%d.%d.%d\n", MG_IPADDR_PARTS(&ip))
1029 #define MG_U8P(ADDR) ((uint8_t *) (ADDR))
1030 #define MG_IPADDR_PARTS(ADDR) \
1031   MG_U8P(ADDR)[0], MG_U8P(ADDR)[1], MG_U8P(ADDR)[2], MG_U8P(ADDR)[3]
1032
1033 struct mg_addr;
1034 int mg_check_ip_acl(struct mg_str acl, struct mg_addr *remote_ip);
1035
1036 // Linked list management macros
1037 #define LIST_ADD_HEAD(type_, head_, elem_) \
1038   do {                                     \
1039     (elem_)->next = (*head_);              \
1040     *(head_) = (elem_);                    \
1041   } while (0)
1042
1043 #define LIST_ADD_TAIL(type_, head_, elem_) \
1044   do {                                     \
1045     type_ **h = head_;                     \
1046     while (*h != NULL) h = &(*h)->next;    \
1047     *h = (elem_);                          \
1048   } while (0)
1049
1050 #define LIST_DELETE(type_, head_, elem_)   \
1051   do {                                     \
1052     type_ **h = head_;                     \
1053     while (*h != (elem_)) h = &(*h)->next; \
1054     *h = (elem_)->next;                    \
1055   } while (0)
1056
1057
1058
1059 unsigned short mg_url_port(const char *url);
1060 int mg_url_is_ssl(const char *url);
1061 struct mg_str mg_url_host(const char *url);
1062 struct mg_str mg_url_user(const char *url);
1063 struct mg_str mg_url_pass(const char *url);
1064 const char *mg_url_uri(const char *url);
1065
1066
1067
1068
1069 struct mg_iobuf {
1070   unsigned char *buf;  // Pointer to stored data
1071   size_t size;         // Total size available
1072   size_t len;          // Current number of bytes
1073   size_t align;        // Alignment during allocation
1074 };
1075
1076 int mg_iobuf_init(struct mg_iobuf *, size_t, size_t);
1077 int mg_iobuf_resize(struct mg_iobuf *, size_t);
1078 void mg_iobuf_free(struct mg_iobuf *);
1079 size_t mg_iobuf_add(struct mg_iobuf *, size_t, const void *, size_t);
1080 size_t mg_iobuf_del(struct mg_iobuf *, size_t ofs, size_t len);
1081
1082 int mg_base64_update(unsigned char p, char *to, int len);
1083 int mg_base64_final(char *to, int len);
1084 int mg_base64_encode(const unsigned char *p, int n, char *to);
1085 int mg_base64_decode(const char *src, int n, char *dst);
1086
1087
1088
1089
1090 typedef struct {
1091   uint32_t buf[4];
1092   uint32_t bits[2];
1093   unsigned char in[64];
1094 } mg_md5_ctx;
1095
1096 void mg_md5_init(mg_md5_ctx *c);
1097 void mg_md5_update(mg_md5_ctx *c, const unsigned char *data, size_t len);
1098 void mg_md5_final(mg_md5_ctx *c, unsigned char[16]);
1099
1100
1101
1102
1103 typedef struct {
1104   uint32_t state[5];
1105   uint32_t count[2];
1106   unsigned char buffer[64];
1107 } mg_sha1_ctx;
1108
1109 void mg_sha1_init(mg_sha1_ctx *);
1110 void mg_sha1_update(mg_sha1_ctx *, const unsigned char *data, size_t len);
1111 void mg_sha1_final(unsigned char digest[20], mg_sha1_ctx *);
1112
1113
1114 struct mg_connection;
1115 typedef void (*mg_event_handler_t)(struct mg_connection *, int ev,
1116                                    void *ev_data, void *fn_data);
1117 void mg_call(struct mg_connection *c, int ev, void *ev_data);
1118 void mg_error(struct mg_connection *c, const char *fmt, ...);
1119
1120 enum {
1121   MG_EV_ERROR,       // Error                        char *error_message
1122   MG_EV_OPEN,        // Connection created           NULL
1123   MG_EV_POLL,        // mg_mgr_poll iteration        uint64_t *uptime_millis
1124   MG_EV_RESOLVE,     // Host name is resolved        NULL
1125   MG_EV_CONNECT,     // Connection established       NULL
1126   MG_EV_ACCEPT,      // Connection accepted          NULL
1127   MG_EV_TLS_HS,      // TLS handshake succeeded      NULL
1128   MG_EV_READ,        // Data received from socket    long *bytes_read
1129   MG_EV_WRITE,       // Data written to socket       long *bytes_written
1130   MG_EV_CLOSE,       // Connection closed            NULL
1131   MG_EV_HTTP_MSG,    // HTTP request/response        struct mg_http_message *
1132   MG_EV_HTTP_CHUNK,  // HTTP chunk (partial msg)     struct mg_http_message *
1133   MG_EV_WS_OPEN,     // Websocket handshake done     struct mg_http_message *
1134   MG_EV_WS_MSG,      // Websocket msg, text or bin   struct mg_ws_message *
1135   MG_EV_WS_CTL,      // Websocket control msg        struct mg_ws_message *
1136   MG_EV_MQTT_CMD,    // MQTT low-level command       struct mg_mqtt_message *
1137   MG_EV_MQTT_MSG,    // MQTT PUBLISH received        struct mg_mqtt_message *
1138   MG_EV_MQTT_OPEN,   // MQTT CONNACK received        int *connack_status_code
1139   MG_EV_SNTP_TIME,   // SNTP time received           uint64_t *epoch_millis
1140   MG_EV_USER         // Starting ID for user events
1141 };
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151 struct mg_dns {
1152   const char *url;          // DNS server URL
1153   struct mg_connection *c;  // DNS server connection
1154 };
1155
1156 struct mg_addr {
1157   uint8_t ip[16];  // Holds IPv4 or IPv6 address, in network byte order
1158   uint16_t port;   // TCP or UDP port in network byte order
1159   bool is_ip6;     // True when address is IPv6 address
1160 };
1161
1162 struct mg_mgr {
1163   struct mg_connection *conns;  // List of active connections
1164   struct mg_dns dns4;           // DNS for IPv4
1165   struct mg_dns dns6;           // DNS for IPv6
1166   int dnstimeout;               // DNS resolve timeout in milliseconds
1167   bool use_dns6;                // Use DNS6 server by default, see #1532
1168   unsigned long nextid;         // Next connection ID
1169   unsigned long timerid;        // Next timer ID
1170   void *userdata;               // Arbitrary user data pointer
1171   void *tls_ctx;                // TLS context shared by all TLS sessions
1172   uint16_t mqtt_id;             // MQTT IDs for pub/sub
1173   void *active_dns_requests;    // DNS requests in progress
1174   struct mg_timer *timers;      // Active timers
1175   int epoll_fd;                 // Used when MG_EPOLL_ENABLE=1
1176   void *priv;                   // Used by the MIP stack
1177   size_t extraconnsize;         // Used by the MIP stack
1178 #if MG_ENABLE_FREERTOS_TCP
1179   SocketSet_t ss;  // NOTE(lsm): referenced from socket struct
1180 #endif
1181 };
1182
1183 struct mg_connection {
1184   struct mg_connection *next;  // Linkage in struct mg_mgr :: connections
1185   struct mg_mgr *mgr;          // Our container
1186   struct mg_addr loc;          // Local address
1187   struct mg_addr rem;          // Remote address
1188   void *fd;                    // Connected socket, or LWIP data
1189   unsigned long id;            // Auto-incrementing unique connection ID
1190   struct mg_iobuf recv;        // Incoming data
1191   struct mg_iobuf send;        // Outgoing data
1192   mg_event_handler_t fn;       // User-specified event handler function
1193   void *fn_data;               // User-specified function parameter
1194   mg_event_handler_t pfn;      // Protocol-specific handler function
1195   void *pfn_data;              // Protocol-specific function parameter
1196   char data[MG_DATA_SIZE];     // Arbitrary connection data
1197   void *tls;                   // TLS specific data
1198   unsigned is_listening : 1;   // Listening connection
1199   unsigned is_client : 1;      // Outbound (client) connection
1200   unsigned is_accepted : 1;    // Accepted (server) connection
1201   unsigned is_resolving : 1;   // Non-blocking DNS resolution is in progress
1202   unsigned is_arplooking : 1;  // Non-blocking ARP resolution is in progress
1203   unsigned is_connecting : 1;  // Non-blocking connect is in progress
1204   unsigned is_tls : 1;         // TLS-enabled connection
1205   unsigned is_tls_hs : 1;      // TLS handshake is in progress
1206   unsigned is_udp : 1;         // UDP connection
1207   unsigned is_websocket : 1;   // WebSocket connection
1208   unsigned is_mqtt5 : 1;       // For MQTT connection, v5 indicator
1209   unsigned is_hexdumping : 1;  // Hexdump in/out traffic
1210   unsigned is_draining : 1;    // Send remaining data, then close and free
1211   unsigned is_closing : 1;     // Close and free the connection immediately
1212   unsigned is_full : 1;        // Stop reads, until cleared
1213   unsigned is_resp : 1;        // Response is still being generated
1214   unsigned is_readable : 1;    // Connection is ready to read
1215   unsigned is_writable : 1;    // Connection is ready to write
1216 };
1217
1218 void mg_mgr_poll(struct mg_mgr *, int ms);
1219 void mg_mgr_init(struct mg_mgr *);
1220 void mg_mgr_free(struct mg_mgr *);
1221
1222 struct mg_connection *mg_listen(struct mg_mgr *, const char *url,
1223                                 mg_event_handler_t fn, void *fn_data);
1224 struct mg_connection *mg_connect(struct mg_mgr *, const char *url,
1225                                  mg_event_handler_t fn, void *fn_data);
1226 struct mg_connection *mg_wrapfd(struct mg_mgr *mgr, int fd,
1227                                 mg_event_handler_t fn, void *fn_data);
1228 void mg_connect_resolved(struct mg_connection *);
1229 bool mg_send(struct mg_connection *, const void *, size_t);
1230 size_t mg_printf(struct mg_connection *, const char *fmt, ...);
1231 size_t mg_vprintf(struct mg_connection *, const char *fmt, va_list *ap);
1232 bool mg_aton(struct mg_str str, struct mg_addr *addr);
1233 int mg_mkpipe(struct mg_mgr *, mg_event_handler_t, void *, bool udp);
1234
1235 // These functions are used to integrate with custom network stacks
1236 struct mg_connection *mg_alloc_conn(struct mg_mgr *);
1237 void mg_close_conn(struct mg_connection *c);
1238 bool mg_open_listener(struct mg_connection *c, const char *url);
1239
1240 // Utility functions
1241 struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds,
1242                               unsigned flags, void (*fn)(void *), void *arg);
1243
1244 // Low-level IO primives used by TLS layer
1245 enum { MG_IO_ERR = -1, MG_IO_WAIT = -2, MG_IO_RESET = -3 };
1246 long mg_io_send(struct mg_connection *c, const void *buf, size_t len);
1247 long mg_io_recv(struct mg_connection *c, void *buf, size_t len);
1248
1249
1250
1251
1252
1253
1254
1255
1256 struct mg_http_header {
1257   struct mg_str name;   // Header name
1258   struct mg_str value;  // Header value
1259 };
1260
1261 struct mg_http_message {
1262   struct mg_str method, uri, query, proto;             // Request/response line
1263   struct mg_http_header headers[MG_MAX_HTTP_HEADERS];  // Headers
1264   struct mg_str body;                                  // Body
1265   struct mg_str head;                                  // Request + headers
1266   struct mg_str chunk;    // Chunk for chunked encoding,  or partial body
1267   struct mg_str message;  // Request + headers + body
1268 };
1269
1270 // Parameter for mg_http_serve_dir()
1271 struct mg_http_serve_opts {
1272   const char *root_dir;       // Web root directory, must be non-NULL
1273   const char *ssi_pattern;    // SSI file name pattern, e.g. #.shtml
1274   const char *extra_headers;  // Extra HTTP headers to add in responses
1275   const char *mime_types;     // Extra mime types, ext1=type1,ext2=type2,..
1276   const char *page404;        // Path to the 404 page, or NULL by default
1277   struct mg_fs *fs;           // Filesystem implementation. Use NULL for POSIX
1278 };
1279
1280 // Parameter for mg_http_next_multipart
1281 struct mg_http_part {
1282   struct mg_str name;      // Form field name
1283   struct mg_str filename;  // Filename for file uploads
1284   struct mg_str body;      // Part contents
1285 };
1286
1287 int mg_http_parse(const char *s, size_t len, struct mg_http_message *);
1288 int mg_http_get_request_len(const unsigned char *buf, size_t buf_len);
1289 void mg_http_printf_chunk(struct mg_connection *cnn, const char *fmt, ...);
1290 void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len);
1291 void mg_http_delete_chunk(struct mg_connection *c, struct mg_http_message *hm);
1292 struct mg_connection *mg_http_listen(struct mg_mgr *, const char *url,
1293                                      mg_event_handler_t fn, void *fn_data);
1294 struct mg_connection *mg_http_connect(struct mg_mgr *, const char *url,
1295                                       mg_event_handler_t fn, void *fn_data);
1296 void mg_http_serve_dir(struct mg_connection *, struct mg_http_message *hm,
1297                        const struct mg_http_serve_opts *);
1298 void mg_http_serve_file(struct mg_connection *, struct mg_http_message *hm,
1299                         const char *path, const struct mg_http_serve_opts *);
1300 void mg_http_reply(struct mg_connection *, int status_code, const char *headers,
1301                    const char *body_fmt, ...);
1302 struct mg_str *mg_http_get_header(struct mg_http_message *, const char *name);
1303 struct mg_str mg_http_var(struct mg_str buf, struct mg_str name);
1304 int mg_http_get_var(const struct mg_str *, const char *name, char *, size_t);
1305 int mg_url_decode(const char *s, size_t n, char *to, size_t to_len, int form);
1306 size_t mg_url_encode(const char *s, size_t n, char *buf, size_t len);
1307 void mg_http_creds(struct mg_http_message *, char *, size_t, char *, size_t);
1308 bool mg_http_match_uri(const struct mg_http_message *, const char *glob);
1309 long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
1310                     struct mg_fs *fs, const char *path, size_t max_size);
1311 void mg_http_bauth(struct mg_connection *, const char *user, const char *pass);
1312 struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v);
1313 size_t mg_http_next_multipart(struct mg_str, size_t, struct mg_http_part *);
1314 int mg_http_status(const struct mg_http_message *hm);
1315 void mg_hello(const char *url);
1316
1317
1318 void mg_http_serve_ssi(struct mg_connection *c, const char *root,
1319                        const char *fullpath);
1320
1321
1322 #define MG_TLS_NONE 0     // No TLS support
1323 #define MG_TLS_MBED 1     // mbedTLS
1324 #define MG_TLS_OPENSSL 2  // OpenSSL
1325 #define MG_TLS_BUILTIN 3  // Built-in
1326 #define MG_TLS_CUSTOM 4   // Custom implementation
1327
1328 #ifndef MG_TLS
1329 #define MG_TLS MG_TLS_NONE
1330 #endif
1331
1332
1333
1334
1335
1336 struct mg_tls_opts {
1337   struct mg_str client_ca;
1338   struct mg_str server_ca;
1339   struct mg_str server_cert;
1340   struct mg_str server_key;
1341   struct mg_str client_cert;
1342   struct mg_str client_key;
1343 };
1344
1345 void mg_tls_ctx_init(struct mg_mgr *, const struct mg_tls_opts *);
1346 void mg_tls_ctx_free(struct mg_mgr *);
1347 void mg_tls_init(struct mg_connection *, struct mg_str hostname);
1348 void mg_tls_free(struct mg_connection *);
1349 long mg_tls_send(struct mg_connection *, const void *buf, size_t len);
1350 long mg_tls_recv(struct mg_connection *, void *buf, size_t len);
1351 size_t mg_tls_pending(struct mg_connection *);
1352 void mg_tls_handshake(struct mg_connection *);
1353
1354
1355
1356
1357
1358
1359
1360 #if MG_TLS == MG_TLS_MBED
1361 #include <mbedtls/debug.h>
1362 #include <mbedtls/net_sockets.h>
1363 #include <mbedtls/ssl.h>
1364 #include <mbedtls/ssl_ticket.h>
1365
1366 struct mg_tls_ctx {
1367   mbedtls_x509_crt server_ca;     // Parsed CA certificate
1368   mbedtls_x509_crt client_ca;     // Parsed CA certificate
1369   mbedtls_x509_crt server_cert;   // Parsed server certificate
1370   mbedtls_pk_context server_key;  // Parsed server private key context
1371   mbedtls_x509_crt client_cert;   // Parsed client certificate
1372   mbedtls_pk_context client_key;  // Parsed client private key context
1373 #ifdef MBEDTLS_SSL_SESSION_TICKETS
1374   mbedtls_ssl_ticket_context ticket_ctx;  // Session tickets context
1375 #endif
1376 };
1377
1378 struct mg_tls {
1379   mbedtls_ssl_context ssl;  // SSL/TLS context
1380   mbedtls_ssl_config conf;  // SSL-TLS config
1381 };
1382 #endif
1383
1384
1385 #if MG_TLS == MG_TLS_OPENSSL
1386
1387 #include <openssl/err.h>
1388 #include <openssl/ssl.h>
1389
1390 struct mg_tls_ctx {
1391   X509 *server_cert;
1392   EVP_PKEY *server_key;
1393   STACK_OF(X509_INFO) *server_ca;
1394   X509 *client_cert;
1395   EVP_PKEY *client_key;
1396   STACK_OF(X509_INFO) *client_ca;
1397 };
1398
1399 struct mg_tls {
1400   SSL_CTX *ctx;
1401   SSL *ssl;
1402 };
1403 #endif
1404
1405
1406 #define WEBSOCKET_OP_CONTINUE 0
1407 #define WEBSOCKET_OP_TEXT 1
1408 #define WEBSOCKET_OP_BINARY 2
1409 #define WEBSOCKET_OP_CLOSE 8
1410 #define WEBSOCKET_OP_PING 9
1411 #define WEBSOCKET_OP_PONG 10
1412
1413
1414
1415 struct mg_ws_message {
1416   struct mg_str data;  // Websocket message data
1417   uint8_t flags;       // Websocket message flags
1418 };
1419
1420 struct mg_connection *mg_ws_connect(struct mg_mgr *, const char *url,
1421                                     mg_event_handler_t fn, void *fn_data,
1422                                     const char *fmt, ...);
1423 void mg_ws_upgrade(struct mg_connection *, struct mg_http_message *,
1424                    const char *fmt, ...);
1425 size_t mg_ws_send(struct mg_connection *, const void *buf, size_t len, int op);
1426 size_t mg_ws_wrap(struct mg_connection *, size_t len, int op);
1427 size_t mg_ws_printf(struct mg_connection *c, int op, const char *fmt, ...);
1428 size_t mg_ws_vprintf(struct mg_connection *c, int op, const char *fmt,
1429                      va_list *);
1430
1431
1432
1433
1434 struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, const char *url,
1435                                       mg_event_handler_t fn, void *fn_data);
1436 void mg_sntp_request(struct mg_connection *c);
1437 int64_t mg_sntp_parse(const unsigned char *buf, size_t len);
1438
1439
1440
1441
1442
1443 #define MQTT_CMD_CONNECT 1
1444 #define MQTT_CMD_CONNACK 2
1445 #define MQTT_CMD_PUBLISH 3
1446 #define MQTT_CMD_PUBACK 4
1447 #define MQTT_CMD_PUBREC 5
1448 #define MQTT_CMD_PUBREL 6
1449 #define MQTT_CMD_PUBCOMP 7
1450 #define MQTT_CMD_SUBSCRIBE 8
1451 #define MQTT_CMD_SUBACK 9
1452 #define MQTT_CMD_UNSUBSCRIBE 10
1453 #define MQTT_CMD_UNSUBACK 11
1454 #define MQTT_CMD_PINGREQ 12
1455 #define MQTT_CMD_PINGRESP 13
1456 #define MQTT_CMD_DISCONNECT 14
1457 #define MQTT_CMD_AUTH 15
1458
1459 #define MQTT_PROP_PAYLOAD_FORMAT_INDICATOR 0x01
1460 #define MQTT_PROP_MESSAGE_EXPIRY_INTERVAL 0x02
1461 #define MQTT_PROP_CONTENT_TYPE 0x03
1462 #define MQTT_PROP_RESPONSE_TOPIC 0x08
1463 #define MQTT_PROP_CORRELATION_DATA 0x09
1464 #define MQTT_PROP_SUBSCRIPTION_IDENTIFIER 0x0B
1465 #define MQTT_PROP_SESSION_EXPIRY_INTERVAL 0x11
1466 #define MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER 0x12
1467 #define MQTT_PROP_SERVER_KEEP_ALIVE 0x13
1468 #define MQTT_PROP_AUTHENTICATION_METHOD 0x15
1469 #define MQTT_PROP_AUTHENTICATION_DATA 0x16
1470 #define MQTT_PROP_REQUEST_PROBLEM_INFORMATION 0x17
1471 #define MQTT_PROP_WILL_DELAY_INTERVAL 0x18
1472 #define MQTT_PROP_REQUEST_RESPONSE_INFORMATION 0x19
1473 #define MQTT_PROP_RESPONSE_INFORMATION 0x1A
1474 #define MQTT_PROP_SERVER_REFERENCE 0x1C
1475 #define MQTT_PROP_REASON_STRING 0x1F
1476 #define MQTT_PROP_RECEIVE_MAXIMUM 0x21
1477 #define MQTT_PROP_TOPIC_ALIAS_MAXIMUM 0x22
1478 #define MQTT_PROP_TOPIC_ALIAS 0x23
1479 #define MQTT_PROP_MAXIMUM_QOS 0x24
1480 #define MQTT_PROP_RETAIN_AVAILABLE 0x25
1481 #define MQTT_PROP_USER_PROPERTY 0x26
1482 #define MQTT_PROP_MAXIMUM_PACKET_SIZE 0x27
1483 #define MQTT_PROP_WILDCARD_SUBSCRIPTION_AVAILABLE 0x28
1484 #define MQTT_PROP_SUBSCRIPTION_IDENTIFIER_AVAILABLE 0x29
1485 #define MQTT_PROP_SHARED_SUBSCRIPTION_AVAILABLE 0x2A
1486
1487 enum {
1488   MQTT_PROP_TYPE_BYTE,
1489   MQTT_PROP_TYPE_STRING,
1490   MQTT_PROP_TYPE_STRING_PAIR,
1491   MQTT_PROP_TYPE_BINARY_DATA,
1492   MQTT_PROP_TYPE_VARIABLE_INT,
1493   MQTT_PROP_TYPE_INT,
1494   MQTT_PROP_TYPE_SHORT
1495 };
1496
1497 enum { MQTT_OK, MQTT_INCOMPLETE, MQTT_MALFORMED };
1498
1499 struct mg_mqtt_prop {
1500   uint8_t id;         // Enumerated at MQTT5 Reference
1501   uint32_t iv;        // Integer value for 8-, 16-, 32-bit integers types
1502   struct mg_str key;  // Non-NULL only for user property type
1503   struct mg_str val;  // Non-NULL only for UTF-8 types and user properties
1504 };
1505
1506 struct mg_mqtt_opts {
1507   struct mg_str user;               // Username, can be empty
1508   struct mg_str pass;               // Password, can be empty
1509   struct mg_str client_id;          // Client ID
1510   struct mg_str topic;              // message/subscription topic
1511   struct mg_str message;            // message content
1512   uint8_t qos;                      // message quality of service
1513   uint8_t version;                  // Can be 4 (3.1.1), or 5. If 0, assume 4
1514   uint16_t keepalive;               // Keep-alive timer in seconds
1515   bool retain;                      // Retain flag
1516   bool clean;                       // Clean session flag
1517   struct mg_mqtt_prop *props;       // MQTT5 props array
1518   size_t num_props;                 // number of props
1519   struct mg_mqtt_prop *will_props;  // Valid only for CONNECT packet (MQTT5)
1520   size_t num_will_props;            // Number of will props
1521 };
1522
1523 struct mg_mqtt_message {
1524   struct mg_str topic;  // Parsed topic for PUBLISH
1525   struct mg_str data;   // Parsed message for PUBLISH
1526   struct mg_str dgram;  // Whole MQTT packet, including headers
1527   uint16_t id;          // For PUBACK, PUBREC, PUBREL, PUBCOMP, SUBACK, PUBLISH
1528   uint8_t cmd;          // MQTT command, one of MQTT_CMD_*
1529   uint8_t qos;          // Quality of service
1530   uint8_t ack;          // CONNACK return code, 0 = success
1531   size_t props_start;   // Offset to the start of the properties (MQTT5)
1532   size_t props_size;    // Length of the properties
1533 };
1534
1535 struct mg_connection *mg_mqtt_connect(struct mg_mgr *, const char *url,
1536                                       const struct mg_mqtt_opts *opts,
1537                                       mg_event_handler_t fn, void *fn_data);
1538 struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url,
1539                                      mg_event_handler_t fn, void *fn_data);
1540 void mg_mqtt_login(struct mg_connection *c, const struct mg_mqtt_opts *opts);
1541 void mg_mqtt_pub(struct mg_connection *c, const struct mg_mqtt_opts *opts);
1542 void mg_mqtt_sub(struct mg_connection *, const struct mg_mqtt_opts *opts);
1543 int mg_mqtt_parse(const uint8_t *, size_t, uint8_t, struct mg_mqtt_message *);
1544 void mg_mqtt_send_header(struct mg_connection *, uint8_t cmd, uint8_t flags,
1545                          uint32_t len);
1546 void mg_mqtt_ping(struct mg_connection *);
1547 void mg_mqtt_pong(struct mg_connection *);
1548 void mg_mqtt_disconnect(struct mg_connection *, const struct mg_mqtt_opts *);
1549 size_t mg_mqtt_next_prop(struct mg_mqtt_message *, struct mg_mqtt_prop *,
1550                          size_t ofs);
1551
1552
1553
1554
1555
1556 // Mongoose sends DNS queries that contain only one question:
1557 // either A (IPv4) or AAAA (IPv6) address lookup.
1558 // Therefore, we expect zero or one answer.
1559 // If `resolved` is true, then `addr` contains resolved IPv4 or IPV6 address.
1560 struct mg_dns_message {
1561   uint16_t txnid;       // Transaction ID
1562   bool resolved;        // Resolve successful, addr is set
1563   struct mg_addr addr;  // Resolved address
1564   char name[256];       // Host name
1565 };
1566
1567 struct mg_dns_header {
1568   uint16_t txnid;  // Transaction ID
1569   uint16_t flags;
1570   uint16_t num_questions;
1571   uint16_t num_answers;
1572   uint16_t num_authority_prs;
1573   uint16_t num_other_prs;
1574 };
1575
1576 // DNS resource record
1577 struct mg_dns_rr {
1578   uint16_t nlen;    // Name or pointer length
1579   uint16_t atype;   // Address type
1580   uint16_t aclass;  // Address class
1581   uint16_t alen;    // Address length
1582 };
1583
1584 void mg_resolve(struct mg_connection *, const char *url);
1585 void mg_resolve_cancel(struct mg_connection *);
1586 bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *);
1587 size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
1588                        bool is_question, struct mg_dns_rr *);
1589
1590
1591
1592
1593
1594 #ifndef MG_JSON_MAX_DEPTH
1595 #define MG_JSON_MAX_DEPTH 30
1596 #endif
1597
1598 // Error return values - negative. Successful returns are >= 0
1599 enum { MG_JSON_TOO_DEEP = -1, MG_JSON_INVALID = -2, MG_JSON_NOT_FOUND = -3 };
1600 int mg_json_get(struct mg_str json, const char *path, int *toklen);
1601
1602 bool mg_json_get_num(struct mg_str json, const char *path, double *v);
1603 bool mg_json_get_bool(struct mg_str json, const char *path, bool *v);
1604 long mg_json_get_long(struct mg_str json, const char *path, long dflt);
1605 char *mg_json_get_str(struct mg_str json, const char *path);
1606 char *mg_json_get_hex(struct mg_str json, const char *path, int *len);
1607 char *mg_json_get_b64(struct mg_str json, const char *path, int *len);
1608
1609 bool mg_json_unescape(struct mg_str str, char *buf, size_t len);
1610
1611
1612
1613
1614 // JSON-RPC request descriptor
1615 struct mg_rpc_req {
1616   struct mg_rpc **head;  // RPC handlers list head
1617   struct mg_rpc *rpc;    // RPC handler being called
1618   mg_pfn_t pfn;          // Response printing function
1619   void *pfn_data;        // Response printing function data
1620   void *req_data;        // Arbitrary request data
1621   struct mg_str frame;   // Request, e.g. {"id":1,"method":"add","params":[1,2]}
1622 };
1623
1624 // JSON-RPC method handler
1625 struct mg_rpc {
1626   struct mg_rpc *next;              // Next in list
1627   struct mg_str method;             // Method pattern
1628   void (*fn)(struct mg_rpc_req *);  // Handler function
1629   void *fn_data;                    // Handler function argument
1630 };
1631
1632 void mg_rpc_add(struct mg_rpc **head, struct mg_str method_pattern,
1633                 void (*handler)(struct mg_rpc_req *), void *handler_data);
1634 void mg_rpc_del(struct mg_rpc **head, void (*handler)(struct mg_rpc_req *));
1635 void mg_rpc_process(struct mg_rpc_req *);
1636
1637 // Helper functions to print result or error frame
1638 void mg_rpc_ok(struct mg_rpc_req *, const char *fmt, ...);
1639 void mg_rpc_vok(struct mg_rpc_req *, const char *fmt, va_list *ap);
1640 void mg_rpc_err(struct mg_rpc_req *, int code, const char *fmt, ...);
1641 void mg_rpc_verr(struct mg_rpc_req *, int code, const char *fmt, va_list *);
1642 void mg_rpc_list(struct mg_rpc_req *r);
1643
1644
1645
1646
1647
1648
1649 #if defined(MG_ENABLE_TCPIP) && MG_ENABLE_TCPIP
1650 struct mg_tcpip_if;  // Mongoose TCP/IP network interface
1651
1652 struct mg_tcpip_driver {
1653   bool (*init)(struct mg_tcpip_if *);                         // Init driver
1654   size_t (*tx)(const void *, size_t, struct mg_tcpip_if *);   // Transmit frame
1655   size_t (*rx)(void *buf, size_t len, struct mg_tcpip_if *);  // Receive frame
1656   bool (*up)(struct mg_tcpip_if *);                           // Up/down status
1657 };
1658
1659 // Network interface
1660 struct mg_tcpip_if {
1661   uint8_t mac[6];                  // MAC address. Must be set to a valid MAC
1662   uint32_t ip, mask, gw;           // IP address, mask, default gateway
1663   struct mg_str tx;                // Output (TX) buffer
1664   bool enable_dhcp_client;         // Enable DCHP client
1665   bool enable_dhcp_server;         // Enable DCHP server
1666   bool enable_crc32_check;         // Do a CRC check on RX frames and strip it
1667   bool enable_mac_check;           // Do a MAC check on RX frames
1668   struct mg_tcpip_driver *driver;  // Low level driver
1669   void *driver_data;               // Driver-specific data
1670   struct mg_mgr *mgr;              // Mongoose event manager
1671   struct mg_queue recv_queue;      // Receive queue
1672
1673   // Internal state, user can use it but should not change it
1674   uint8_t gwmac[6];             // Router's MAC
1675   uint64_t now;                 // Current time
1676   uint64_t timer_1000ms;        // 1000 ms timer: for DHCP and link state
1677   uint64_t lease_expire;        // Lease expiration time, in ms
1678   uint16_t eport;               // Next ephemeral port
1679   volatile uint32_t ndrop;      // Number of received, but dropped frames
1680   volatile uint32_t nrecv;      // Number of received frames
1681   volatile uint32_t nsent;      // Number of transmitted frames
1682   volatile uint32_t nerr;       // Number of driver errors
1683   uint8_t state;                // Current state
1684 #define MG_TCPIP_STATE_DOWN 0   // Interface is down
1685 #define MG_TCPIP_STATE_UP 1     // Interface is up
1686 #define MG_TCPIP_STATE_REQ 2    // Interface is up and has requested an IP
1687 #define MG_TCPIP_STATE_READY 3  // Interface is up and has an IP assigned
1688 };
1689
1690 void mg_tcpip_init(struct mg_mgr *, struct mg_tcpip_if *);
1691 void mg_tcpip_free(struct mg_tcpip_if *);
1692 void mg_tcpip_qwrite(void *buf, size_t len, struct mg_tcpip_if *ifp);
1693
1694 extern struct mg_tcpip_driver mg_tcpip_driver_stm32;
1695 extern struct mg_tcpip_driver mg_tcpip_driver_w5500;
1696 extern struct mg_tcpip_driver mg_tcpip_driver_tm4c;
1697 extern struct mg_tcpip_driver mg_tcpip_driver_stm32h;
1698 extern struct mg_tcpip_driver mg_tcpip_driver_imxrt;
1699 extern struct mg_tcpip_driver mg_tcpip_driver_same54;
1700
1701 // Drivers that require SPI, can use this SPI abstraction
1702 struct mg_tcpip_spi {
1703   void *spi;                        // Opaque SPI bus descriptor
1704   void (*begin)(void *);            // SPI begin: slave select low
1705   void (*end)(void *);              // SPI end: slave select high
1706   uint8_t (*txn)(void *, uint8_t);  // SPI transaction: write 1 byte, read reply
1707 };
1708 #endif
1709
1710
1711 struct mg_tcpip_driver_imxrt1020_data {
1712   // MDC clock divider. MDC clock is derived from IPS Bus clock (ipg_clk),
1713   // must not exceed 2.5MHz. Configuration for clock range 2.36~2.50 MHz
1714   //    ipg_clk       MSCR       mdc_cr VALUE
1715   //    -------------------------------------
1716   //                                -1  <-- tell driver to guess the value
1717   //    25 MHz        0x04           0
1718   //    33 MHz        0x06           1
1719   //    40 MHz        0x07           2
1720   //    50 MHz        0x09           3
1721   //    66 MHz        0x0D           4  <-- value for iMXRT1020-EVK at max freq.
1722   int mdc_cr;  // Valid values: -1, 0, 1, 2, 3, 4
1723 };
1724
1725
1726 #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && MG_ENABLE_DRIVER_SAME54
1727
1728 struct mg_tcpip_driver_same54_data {
1729     int mdc_cr;
1730 };
1731
1732 #endif
1733
1734
1735 struct mg_tcpip_driver_stm32_data {
1736   // MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz
1737   //    HCLK range    DIVIDER    mdc_cr VALUE
1738   //    -------------------------------------
1739   //                                -1  <-- tell driver to guess the value
1740   //    60-100 MHz    HCLK/42        0
1741   //    100-150 MHz   HCLK/62        1
1742   //    20-35 MHz     HCLK/16        2
1743   //    35-60 MHz     HCLK/26        3
1744   //    150-216 MHz   HCLK/102       4  <-- value for Nucleo-F* on max speed
1745   //    216-310 MHz   HCLK/124       5
1746   //    110, 111 Reserved
1747   int mdc_cr;  // Valid values: -1, 0, 1, 2, 3, 4, 5
1748 };
1749
1750
1751 struct mg_tcpip_driver_stm32h_data {
1752   // MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz
1753   //    HCLK range    DIVIDER    mdc_cr VALUE
1754   //    -------------------------------------
1755   //                                -1  <-- tell driver to guess the value
1756   //    60-100 MHz    HCLK/42        0
1757   //    100-150 MHz   HCLK/62        1
1758   //    20-35 MHz     HCLK/16        2
1759   //    35-60 MHz     HCLK/26        3
1760   //    150-250 MHz   HCLK/102       4  <-- value for Nucleo-H* on max speed driven by HSI
1761   //    250-300 MHz   HCLK/124       5  <-- value for Nucleo-H* on max speed driven by CSI
1762   //    110, 111 Reserved
1763   int mdc_cr;  // Valid values: -1, 0, 1, 2, 3, 4, 5
1764 };
1765
1766
1767 struct mg_tcpip_driver_tm4c_data {
1768   // MDC clock divider. MDC clock is derived from SYSCLK, must not exceed 2.5MHz
1769   //    SYSCLK range   DIVIDER   mdc_cr VALUE
1770   //    -------------------------------------
1771   //                                -1  <-- tell driver to guess the value
1772   //    60-100 MHz    SYSCLK/42      0
1773   //    100-150 MHz   SYSCLK/62      1  <-- value for EK-TM4C129* on max speed
1774   //    20-35 MHz     SYSCLK/16      2
1775   //    35-60 MHz     SYSCLK/26      3
1776   //    0x4-0xF Reserved
1777   int mdc_cr;  // Valid values: -1, 0, 1, 2, 3
1778 };
1779
1780
1781 #define CA_ISRG_ROOT_X2                                                \
1782   "-----BEGIN CERTIFICATE-----\n"                                      \
1783   "MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw\n" \
1784   "CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg\n" \
1785   "R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00\n" \
1786   "MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT\n" \
1787   "ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw\n" \
1788   "EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW\n" \
1789   "+1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9\n" \
1790   "ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T\n" \
1791   "AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI\n" \
1792   "zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW\n" \
1793   "tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1\n" \
1794   "/q4AaOeMSQ+2b1tbFfLn\n"                                             \
1795   "-----END CERTIFICATE-----\n"
1796
1797 #define CA_ISRG_ROOT_X1                                                \
1798   "-----BEGIN CERTIFICATE-----\n"                                      \
1799   "MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n" \
1800   "TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n" \
1801   "cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n" \
1802   "WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\n" \
1803   "ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\n" \
1804   "MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc\n" \
1805   "h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+\n" \
1806   "0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U\n" \
1807   "A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW\n" \
1808   "T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH\n" \
1809   "B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC\n" \
1810   "B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv\n" \
1811   "KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn\n" \
1812   "OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn\n" \
1813   "jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw\n" \
1814   "qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI\n" \
1815   "rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n" \
1816   "HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq\n" \
1817   "hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\n" \
1818   "ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ\n" \
1819   "3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK\n" \
1820   "NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5\n" \
1821   "ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur\n" \
1822   "TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC\n" \
1823   "jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc\n" \
1824   "oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq\n" \
1825   "4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA\n" \
1826   "mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d\n" \
1827   "emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n" \
1828   "-----END CERTIFICATE-----\n"
1829
1830 #define CA_GOOGLE_TRUST                                                \
1831   "-----BEGIN CERTIFICATE-----\n"                                      \
1832   "MIIBxTCCAWugAwIBAgINAfD3nVndblD3QnNxUDAKBggqhkjOPQQDAjBEMQswCQYD\n" \
1833   "VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzERMA8G\n" \
1834   "A1UEAxMIR1RTIExUU1IwHhcNMTgxMTAxMDAwMDQyWhcNNDIxMTAxMDAwMDQyWjBE\n" \
1835   "MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM\n" \
1836   "QzERMA8GA1UEAxMIR1RTIExUU1IwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATN\n" \
1837   "8YyO2u+yCQoZdwAkUNv5c3dokfULfrA6QJgFV2XMuENtQZIG5HUOS6jFn8f0ySlV\n" \
1838   "eORCxqFyjDJyRn86d+Iko0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUw\n" \
1839   "AwEB/zAdBgNVHQ4EFgQUPv7/zFLrvzQ+PfNA0OQlsV+4u1IwCgYIKoZIzj0EAwID\n" \
1840   "SAAwRQIhAPKuf/VtBHqGw3TUwUIq7TfaExp3bH7bjCBmVXJupT9FAiBr0SmCtsuk\n" \
1841   "miGgpajjf/gFigGM34F9021bCWs1MbL0SA==\n"                             \
1842   "-----END CERTIFICATE-----\n"
1843
1844 #define CA_GLOBALSIGN_EC                                               \
1845   "-----BEGIN CERTIFICATE-----\n"                                      \
1846   "MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk\n" \
1847   "MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH\n" \
1848   "bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX\n" \
1849   "DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD\n" \
1850   "QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu\n" \
1851   "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ\n" \
1852   "FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw\n" \
1853   "DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F\n" \
1854   "uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX\n" \
1855   "kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs\n" \
1856   "ewv4n4Q=\n"                                                         \
1857   "-----END CERTIFICATE-----\n"
1858
1859 #define CA_GLOBALSIGN_RSA                                              \
1860   "-----BEGIN CERTIFICATE-----\n"                                      \
1861   "MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\n" \
1862   "A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\n" \
1863   "b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\n" \
1864   "MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\n" \
1865   "YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\n" \
1866   "aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\n" \
1867   "jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\n" \
1868   "xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\n" \
1869   "1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\n" \
1870   "snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\n" \
1871   "U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\n" \
1872   "9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\n" \
1873   "BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\n" \
1874   "AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\n" \
1875   "yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\n" \
1876   "38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\n" \
1877   "AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\n" \
1878   "DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\n" \
1879   "HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\n"                             \
1880   "-----END CERTIFICATE-----\n"
1881
1882 #define CA_DIGICERT                                                    \
1883   "-----BEGIN CERTIFICATE-----\n"                                      \
1884   "MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n" \
1885   "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" \
1886   "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n" \
1887   "QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\n" \
1888   "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n" \
1889   "b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n" \
1890   "9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\n" \
1891   "CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\n" \
1892   "nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n" \
1893   "43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\n" \
1894   "T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\n" \
1895   "gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\n" \
1896   "BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\n" \
1897   "TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\n" \
1898   "DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\n" \
1899   "hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n" \
1900   "06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\n" \
1901   "PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\n" \
1902   "YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\n" \
1903   "CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n"                 \
1904   "-----END CERTIFICATE-----\n"
1905
1906 #define CA_AMAZON_4                                                    \
1907   "-----BEGIN CERTIFICATE-----\n"                                      \
1908   "MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5\n" \
1909   "MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g\n" \
1910   "Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG\n" \
1911   "A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg\n" \
1912   "Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi\n" \
1913   "9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk\n" \
1914   "M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB\n" \
1915   "/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB\n" \
1916   "MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw\n" \
1917   "CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW\n" \
1918   "1KyLa2tJElMzrdfkviT8tQp21KW8EA==\n"                                 \
1919   "-----END CERTIFICATE-----\n"
1920
1921 #define CA_AMAZON_3                                                    \
1922   "-----BEGIN CERTIFICATE-----\n"                                      \
1923   "MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5\n" \
1924   "MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g\n" \
1925   "Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG\n" \
1926   "A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg\n" \
1927   "Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl\n" \
1928   "ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j\n" \
1929   "QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr\n" \
1930   "ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr\n" \
1931   "BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM\n" \
1932   "YyRIHN8wfdVoOw==\n"                                                 \
1933   "-----END CERTIFICATE-----\n"
1934
1935 #define CA_ALL                                                     \
1936   CA_ISRG_ROOT_X1 CA_ISRG_ROOT_X2 CA_GOOGLE_TRUST CA_GLOBALSIGN_EC \
1937       CA_GLOBALSIGN_RSA CA_DIGICERT CA_AMAZON_4 CA_AMAZON_3
1938
1939 #ifdef __cplusplus
1940 }
1941 #endif
1942 #endif  // MONGOOSE_H