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