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
26extern "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
208static 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)
215static 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>
257int mkdir(const char *, mode_t);
258#endif
259
260
261#if MG_ARCH == MG_ARCH_RTTHREAD
262
263#include <rtthread.h>
264#include <ctype.h>
265#include <errno.h>
266#include <fcntl.h>
267#include <sys/socket.h>
268#include <sys/select.h>
269#include <stdarg.h>
270#include <stdbool.h>
271#include <stdint.h>
272#include <stdio.h>
273#include <stdlib.h>
274#include <string.h>
275#include <sys/types.h>
276#include <time.h>
277
278#ifndef MG_IO_SIZE
279#define MG_IO_SIZE 1460
280#endif
281
282#endif // MG_ARCH == MG_ARCH_RTTHREAD
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
301extern 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)
311static 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__ ""
435typedef __int64 int64_t;
436typedef unsigned __int64 uint64_t;
437typedef unsigned char uint8_t;
438typedef char int8_t;
439typedef unsigned short uint16_t;
440typedef short int16_t;
441typedef unsigned int uint32_t;
442typedef int int32_t;
443typedef 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
466typedef 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
476typedef 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
542int rand(void);
543int 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
603static 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
608static 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
621struct 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
629struct 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_MBEDTLS
705#define MG_ENABLE_MBEDTLS 0
706#endif
707
708#ifndef MG_ENABLE_OPENSSL
709#define MG_ENABLE_OPENSSL 0
710#endif
711
712#ifndef MG_ENABLE_CUSTOM_TLS
713#define MG_ENABLE_CUSTOM_TLS 0
714#endif
715
716#ifndef MG_ENABLE_SSI
717#define MG_ENABLE_SSI 0
718#endif
719
720#ifndef MG_ENABLE_IPV6
721#define MG_ENABLE_IPV6 0
722#endif
723
724#ifndef MG_ENABLE_MD5
725#define MG_ENABLE_MD5 1
726#endif
727
728// Set MG_ENABLE_WINSOCK=0 for Win32 builds with external IP stack (like LWIP)
729#ifndef MG_ENABLE_WINSOCK
730#define MG_ENABLE_WINSOCK 1
731#endif
732
733#ifndef MG_ENABLE_DIRLIST
734#define MG_ENABLE_DIRLIST 0
735#endif
736
737#ifndef MG_ENABLE_CUSTOM_RANDOM
738#define MG_ENABLE_CUSTOM_RANDOM 0
739#endif
740
741#ifndef MG_ENABLE_CUSTOM_MILLIS
742#define MG_ENABLE_CUSTOM_MILLIS 0
743#endif
744
745#ifndef MG_ENABLE_PACKED_FS
746#define MG_ENABLE_PACKED_FS 0
747#endif
748
749#ifndef MG_ENABLE_ASSERT
750#define MG_ENABLE_ASSERT 0
751#endif
752
753#ifndef MG_IO_SIZE
754#define MG_IO_SIZE 2048 // Granularity of the send/recv IO buffer growth
755#endif
756
757#ifndef MG_MAX_RECV_SIZE
758#define MG_MAX_RECV_SIZE (3 * 1024 * 1024) // Maximum recv IO buffer size
759#endif
760
761#ifndef MG_DATA_SIZE
762#define MG_DATA_SIZE 32 // struct mg_connection :: data size
763#endif
764
765#ifndef MG_MAX_HTTP_HEADERS
766#define MG_MAX_HTTP_HEADERS 30
767#endif
768
769#ifndef MG_HTTP_INDEX
770#define MG_HTTP_INDEX "index.html"
771#endif
772
773#ifndef MG_PATH_MAX
774#ifdef PATH_MAX
775#define MG_PATH_MAX PATH_MAX
776#else
777#define MG_PATH_MAX 128
778#endif
779#endif
780
781#ifndef MG_SOCK_LISTEN_BACKLOG_SIZE
782#define MG_SOCK_LISTEN_BACKLOG_SIZE 3
783#endif
784
785#ifndef MG_DIRSEP
786#define MG_DIRSEP '/'
787#endif
788
789#ifndef MG_ENABLE_FILE
790#if defined(FOPEN_MAX)
791#define MG_ENABLE_FILE 1
792#else
793#define MG_ENABLE_FILE 0
794#endif
795#endif
796
797#ifndef MG_INVALID_SOCKET
798#define MG_INVALID_SOCKET (-1)
799#endif
800
801#ifndef MG_SOCKET_TYPE
802#define MG_SOCKET_TYPE int
803#endif
804
805#ifndef MG_SOCKET_ERRNO
806#define MG_SOCKET_ERRNO errno
807#endif
808
809#if MG_ENABLE_EPOLL
810#define MG_EPOLL_ADD(c) \
811 do { \
812 struct epoll_event ev = {EPOLLIN | EPOLLERR | EPOLLHUP, {c}}; \
813 epoll_ctl(c->mgr->epoll_fd, EPOLL_CTL_ADD, (int) (size_t) c->fd, &ev); \
814 } while (0)
815#define MG_EPOLL_MOD(c, wr) \
816 do { \
817 struct epoll_event ev = {EPOLLIN | EPOLLERR | EPOLLHUP, {c}}; \
818 if (wr) ev.events |= EPOLLOUT; \
819 epoll_ctl(c->mgr->epoll_fd, EPOLL_CTL_MOD, (int) (size_t) c->fd, &ev); \
820 } while (0)
821#else
822#define MG_EPOLL_ADD(c)
823#define MG_EPOLL_MOD(c, wr)
824#endif
825
826
827
828
829struct mg_str {
830 const char *ptr; // Pointer to string data
831 size_t len; // String len
832};
833
834#define MG_NULL_STR \
835 { NULL, 0 }
836
837#define MG_C_STR(a) \
838 { (a), sizeof(a) - 1 }
839
840// Using macro to avoid shadowing C++ struct constructor, see #1298
841#define mg_str(s) mg_str_s(s)
842
843struct mg_str mg_str(const char *s);
844struct mg_str mg_str_n(const char *s, size_t n);
845int mg_lower(const char *s);
846int mg_ncasecmp(const char *s1, const char *s2, size_t len);
847int mg_casecmp(const char *s1, const char *s2);
848int mg_vcmp(const struct mg_str *s1, const char *s2);
849int mg_vcasecmp(const struct mg_str *str1, const char *str2);
850int mg_strcmp(const struct mg_str str1, const struct mg_str str2);
851struct mg_str mg_strstrip(struct mg_str s);
852struct mg_str mg_strdup(const struct mg_str s);
853const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle);
854bool mg_match(struct mg_str str, struct mg_str pattern, struct mg_str *caps);
855bool mg_globmatch(const char *pattern, size_t plen, const char *s, size_t n);
856bool mg_commalist(struct mg_str *s, struct mg_str *k, struct mg_str *v);
857bool mg_split(struct mg_str *s, struct mg_str *k, struct mg_str *v, char delim);
858char *mg_hex(const void *buf, size_t len, char *dst);
859void mg_unhex(const char *buf, size_t len, unsigned char *to);
860unsigned long mg_unhexn(const char *s, size_t len);
861int mg_check_ip_acl(struct mg_str acl, uint32_t remote_ip);
862char *mg_remove_double_dots(char *s);
863
864
865
866
867// Single producer, single consumer non-blocking queue
868
869struct mg_queue {
870 char *buf;
871 size_t size;
872 volatile size_t tail;
873 volatile size_t head;
874};
875
876void mg_queue_init(struct mg_queue *, char *, size_t); // Init queue
877size_t mg_queue_book(struct mg_queue *, char **buf, size_t); // Reserve space
878void mg_queue_add(struct mg_queue *, size_t); // Add new message
879size_t mg_queue_next(struct mg_queue *, char **); // Get oldest message
880void mg_queue_del(struct mg_queue *, size_t); // Delete oldest message
881
882
883
884
885typedef void (*mg_pfn_t)(char, void *); // Output function
886typedef size_t (*mg_pm_t)(mg_pfn_t, void *, va_list *); // %M printer
887
888size_t mg_vxprintf(void (*)(char, void *), void *, const char *fmt, va_list *);
889size_t mg_xprintf(void (*fn)(char, void *), void *, const char *fmt, ...);
890
891
892
893
894
895
896// Convenience wrappers around mg_xprintf
897size_t mg_vsnprintf(char *buf, size_t len, const char *fmt, va_list *ap);
898size_t mg_snprintf(char *, size_t, const char *fmt, ...);
899char *mg_vmprintf(const char *fmt, va_list *ap);
900char *mg_mprintf(const char *fmt, ...);
901size_t mg_queue_vprintf(struct mg_queue *, const char *fmt, va_list *);
902size_t mg_queue_printf(struct mg_queue *, const char *fmt, ...);
903
904// %M print helper functions
905size_t mg_print_base64(void (*out)(char, void *), void *arg, va_list *ap);
906size_t mg_print_esc(void (*out)(char, void *), void *arg, va_list *ap);
907size_t mg_print_hex(void (*out)(char, void *), void *arg, va_list *ap);
908size_t mg_print_ip(void (*out)(char, void *), void *arg, va_list *ap);
909size_t mg_print_ip_port(void (*out)(char, void *), void *arg, va_list *ap);
910size_t mg_print_ip4(void (*out)(char, void *), void *arg, va_list *ap);
911size_t mg_print_ip6(void (*out)(char, void *), void *arg, va_list *ap);
912size_t mg_print_mac(void (*out)(char, void *), void *arg, va_list *ap);
913
914// Various output functions
915void mg_pfn_iobuf(char ch, void *param); // param: struct mg_iobuf *
916void mg_pfn_stdout(char c, void *param); // param: ignored
917
918// A helper macro for printing JSON: mg_snprintf(buf, len, "%m", MG_ESC("hi"))
919#define MG_ESC(str) mg_print_esc, 0, (str)
920
921
922
923
924
925
926enum { MG_LL_NONE, MG_LL_ERROR, MG_LL_INFO, MG_LL_DEBUG, MG_LL_VERBOSE };
927void mg_log(const char *fmt, ...);
928bool mg_log_prefix(int ll, const char *file, int line, const char *fname);
929void mg_log_set(int log_level);
930void mg_hexdump(const void *buf, size_t len);
931void mg_log_set_fn(mg_pfn_t fn, void *param);
932
933#if MG_ENABLE_LOG
934#define MG_LOG(level, args) \
935 do { \
936 if (mg_log_prefix((level), __FILE__, __LINE__, __func__)) mg_log args; \
937 } while (0)
938#else
939#define MG_LOG(level, args) \
940 do { \
941 if (0) mg_log args; \
942 } while (0)
943#endif
944
945#define MG_ERROR(args) MG_LOG(MG_LL_ERROR, args)
946#define MG_INFO(args) MG_LOG(MG_LL_INFO, args)
947#define MG_DEBUG(args) MG_LOG(MG_LL_DEBUG, args)
948#define MG_VERBOSE(args) MG_LOG(MG_LL_VERBOSE, args)
949
950
951
952
953struct mg_timer {
954 unsigned long id; // Timer ID
955 uint64_t period_ms; // Timer period in milliseconds
956 uint64_t expire; // Expiration timestamp in milliseconds
957 unsigned flags; // Possible flags values below
958#define MG_TIMER_ONCE 0 // Call function once
959#define MG_TIMER_REPEAT 1 // Call function periodically
960#define MG_TIMER_RUN_NOW 2 // Call immediately when timer is set
961 void (*fn)(void *); // Function to call
962 void *arg; // Function argument
963 struct mg_timer *next; // Linkage
964};
965
966void mg_timer_init(struct mg_timer **head, struct mg_timer *timer,
967 uint64_t milliseconds, unsigned flags, void (*fn)(void *),
968 void *arg);
969void mg_timer_free(struct mg_timer **head, struct mg_timer *);
970void mg_timer_poll(struct mg_timer **head, uint64_t new_ms);
971bool mg_timer_expired(uint64_t *expiration, uint64_t period, uint64_t now);
972
973
974
975
976
977enum { MG_FS_READ = 1, MG_FS_WRITE = 2, MG_FS_DIR = 4 };
978
979// Filesystem API functions
980// st() returns MG_FS_* flags and populates file size and modification time
981// ls() calls fn() for every directory entry, allowing to list a directory
982//
983// NOTE: UNIX-style shorthand names for the API functions are deliberately
984// chosen to avoid conflicts with some libraries that make macros for e.g.
985// stat(), write(), read() calls.
986struct mg_fs {
987 int (*st)(const char *path, size_t *size, time_t *mtime); // stat file
988 void (*ls)(const char *path, void (*fn)(const char *, void *), void *);
989 void *(*op)(const char *path, int flags); // Open file
990 void (*cl)(void *fd); // Close file
991 size_t (*rd)(void *fd, void *buf, size_t len); // Read file
992 size_t (*wr)(void *fd, const void *buf, size_t len); // Write file
993 size_t (*sk)(void *fd, size_t offset); // Set file position
994 bool (*mv)(const char *from, const char *to); // Rename file
995 bool (*rm)(const char *path); // Delete file
996 bool (*mkd)(const char *path); // Create directory
997};
998
999extern struct mg_fs mg_fs_posix; // POSIX open/close/read/write/seek
1000extern struct mg_fs mg_fs_packed; // Packed FS, see examples/device-dashboard
1001extern struct mg_fs mg_fs_fat; // FAT FS
1002
1003// File descriptor
1004struct mg_fd {
1005 void *fd;
1006 struct mg_fs *fs;
1007};
1008
1009struct mg_fd *mg_fs_open(struct mg_fs *fs, const char *path, int flags);
1010void mg_fs_close(struct mg_fd *fd);
1011char *mg_file_read(struct mg_fs *fs, const char *path, size_t *size);
1012bool mg_file_write(struct mg_fs *fs, const char *path, const void *, size_t);
1013bool mg_file_printf(struct mg_fs *fs, const char *path, const char *fmt, ...);
1014
1015
1016
1017
1018
1019
1020
1021#if MG_ENABLE_ASSERT
1022#include <assert.h>
1023#elif !defined(assert)
1024#define assert(x)
1025#endif
1026
1027void mg_random(void *buf, size_t len);
1028char *mg_random_str(char *buf, size_t len);
1029uint16_t mg_ntohs(uint16_t net);
1030uint32_t mg_ntohl(uint32_t net);
1031uint32_t mg_crc32(uint32_t crc, const char *buf, size_t len);
1032uint64_t mg_millis(void);
1033
1034#define mg_htons(x) mg_ntohs(x)
1035#define mg_htonl(x) mg_ntohl(x)
1036
1037#define MG_U32(a, b, c, d) \
1038 (((uint32_t) ((a) &255) << 24) | ((uint32_t) ((b) &255) << 16) | \
1039 ((uint32_t) ((c) &255) << 8) | (uint32_t) ((d) &255))
1040
1041// For printing IPv4 addresses: printf("%d.%d.%d.%d\n", MG_IPADDR_PARTS(&ip))
1042#define MG_U8P(ADDR) ((uint8_t *) (ADDR))
1043#define MG_IPADDR_PARTS(ADDR) \
1044 MG_U8P(ADDR)[0], MG_U8P(ADDR)[1], MG_U8P(ADDR)[2], MG_U8P(ADDR)[3]
1045
1046// Linked list management macros
1047#define LIST_ADD_HEAD(type_, head_, elem_) \
1048 do { \
1049 (elem_)->next = (*head_); \
1050 *(head_) = (elem_); \
1051 } while (0)
1052
1053#define LIST_ADD_TAIL(type_, head_, elem_) \
1054 do { \
1055 type_ **h = head_; \
1056 while (*h != NULL) h = &(*h)->next; \
1057 *h = (elem_); \
1058 } while (0)
1059
1060#define LIST_DELETE(type_, head_, elem_) \
1061 do { \
1062 type_ **h = head_; \
1063 while (*h != (elem_)) h = &(*h)->next; \
1064 *h = (elem_)->next; \
1065 } while (0)
1066
1067
1068
1069unsigned short mg_url_port(const char *url);
1070int mg_url_is_ssl(const char *url);
1071struct mg_str mg_url_host(const char *url);
1072struct mg_str mg_url_user(const char *url);
1073struct mg_str mg_url_pass(const char *url);
1074const char *mg_url_uri(const char *url);
1075
1076
1077
1078
1079struct mg_iobuf {
1080 unsigned char *buf; // Pointer to stored data
1081 size_t size; // Total size available
1082 size_t len; // Current number of bytes
1083 size_t align; // Alignment during allocation
1084};
1085
1086int mg_iobuf_init(struct mg_iobuf *, size_t, size_t);
1087int mg_iobuf_resize(struct mg_iobuf *, size_t);
1088void mg_iobuf_free(struct mg_iobuf *);
1089size_t mg_iobuf_add(struct mg_iobuf *, size_t, const void *, size_t);
1090size_t mg_iobuf_del(struct mg_iobuf *, size_t ofs, size_t len);
1091
1092int mg_base64_update(unsigned char p, char *to, int len);
1093int mg_base64_final(char *to, int len);
1094int mg_base64_encode(const unsigned char *p, int n, char *to);
1095int mg_base64_decode(const char *src, int n, char *dst);
1096
1097
1098
1099
1100typedef struct {
1101 uint32_t buf[4];
1102 uint32_t bits[2];
1103 unsigned char in[64];
1104} mg_md5_ctx;
1105
1106void mg_md5_init(mg_md5_ctx *c);
1107void mg_md5_update(mg_md5_ctx *c, const unsigned char *data, size_t len);
1108void mg_md5_final(mg_md5_ctx *c, unsigned char[16]);
1109
1110
1111
1112
1113typedef struct {
1114 uint32_t state[5];
1115 uint32_t count[2];
1116 unsigned char buffer[64];
1117} mg_sha1_ctx;
1118
1119void mg_sha1_init(mg_sha1_ctx *);
1120void mg_sha1_update(mg_sha1_ctx *, const unsigned char *data, size_t len);
1121void mg_sha1_final(unsigned char digest[20], mg_sha1_ctx *);
1122
1123
1124struct mg_connection;
1125typedef void (*mg_event_handler_t)(struct mg_connection *, int ev,
1126 void *ev_data, void *fn_data);
1127void mg_call(struct mg_connection *c, int ev, void *ev_data);
1128void mg_error(struct mg_connection *c, const char *fmt, ...);
1129
1130enum {
1131 MG_EV_ERROR, // Error char *error_message
1132 MG_EV_OPEN, // Connection created NULL
1133 MG_EV_POLL, // mg_mgr_poll iteration uint64_t *uptime_millis
1134 MG_EV_RESOLVE, // Host name is resolved NULL
1135 MG_EV_CONNECT, // Connection established NULL
1136 MG_EV_ACCEPT, // Connection accepted NULL
1137 MG_EV_TLS_HS, // TLS handshake succeeded NULL
1138 MG_EV_READ, // Data received from socket long *bytes_read
1139 MG_EV_WRITE, // Data written to socket long *bytes_written
1140 MG_EV_CLOSE, // Connection closed NULL
1141 MG_EV_HTTP_MSG, // HTTP request/response struct mg_http_message *
1142 MG_EV_HTTP_CHUNK, // HTTP chunk (partial msg) struct mg_http_message *
1143 MG_EV_WS_OPEN, // Websocket handshake done struct mg_http_message *
1144 MG_EV_WS_MSG, // Websocket msg, text or bin struct mg_ws_message *
1145 MG_EV_WS_CTL, // Websocket control msg struct mg_ws_message *
1146 MG_EV_MQTT_CMD, // MQTT low-level command struct mg_mqtt_message *
1147 MG_EV_MQTT_MSG, // MQTT PUBLISH received struct mg_mqtt_message *
1148 MG_EV_MQTT_OPEN, // MQTT CONNACK received int *connack_status_code
1149 MG_EV_SNTP_TIME, // SNTP time received uint64_t *epoch_millis
1150 MG_EV_USER // Starting ID for user events
1151};
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161struct mg_dns {
1162 const char *url; // DNS server URL
1163 struct mg_connection *c; // DNS server connection
1164};
1165
1166struct mg_addr {
1167 uint8_t ip[16]; // Holds IPv4 or IPv6 address, in network byte order
1168 uint16_t port; // TCP or UDP port in network byte order
1169 bool is_ip6; // True when address is IPv6 address
1170};
1171
1172struct mg_mgr {
1173 struct mg_connection *conns; // List of active connections
1174 struct mg_dns dns4; // DNS for IPv4
1175 struct mg_dns dns6; // DNS for IPv6
1176 int dnstimeout; // DNS resolve timeout in milliseconds
1177 bool use_dns6; // Use DNS6 server by default, see #1532
1178 unsigned long nextid; // Next connection ID
1179 unsigned long timerid; // Next timer ID
1180 void *userdata; // Arbitrary user data pointer
1181 void *tls_ctx; // TLS context shared by all TLS sessions
1182 uint16_t mqtt_id; // MQTT IDs for pub/sub
1183 void *active_dns_requests; // DNS requests in progress
1184 struct mg_timer *timers; // Active timers
1185 int epoll_fd; // Used when MG_EPOLL_ENABLE=1
1186 void *priv; // Used by the MIP stack
1187 size_t extraconnsize; // Used by the MIP stack
1188#if MG_ENABLE_FREERTOS_TCP
1189 SocketSet_t ss; // NOTE(lsm): referenced from socket struct
1190#endif
1191};
1192
1193struct mg_connection {
1194 struct mg_connection *next; // Linkage in struct mg_mgr :: connections
1195 struct mg_mgr *mgr; // Our container
1196 struct mg_addr loc; // Local address
1197 struct mg_addr rem; // Remote address
1198 void *fd; // Connected socket, or LWIP data
1199 unsigned long id; // Auto-incrementing unique connection ID
1200 struct mg_iobuf recv; // Incoming data
1201 struct mg_iobuf send; // Outgoing data
1202 mg_event_handler_t fn; // User-specified event handler function
1203 void *fn_data; // User-specified function parameter
1204 mg_event_handler_t pfn; // Protocol-specific handler function
1205 void *pfn_data; // Protocol-specific function parameter
1206 char data[MG_DATA_SIZE]; // Arbitrary connection data
1207 void *tls; // TLS specific data
1208 unsigned is_listening : 1; // Listening connection
1209 unsigned is_client : 1; // Outbound (client) connection
1210 unsigned is_accepted : 1; // Accepted (server) connection
1211 unsigned is_resolving : 1; // Non-blocking DNS resolution is in progress
1212 unsigned is_arplooking : 1; // Non-blocking ARP resolution is in progress
1213 unsigned is_connecting : 1; // Non-blocking connect is in progress
1214 unsigned is_tls : 1; // TLS-enabled connection
1215 unsigned is_tls_hs : 1; // TLS handshake is in progress
1216 unsigned is_udp : 1; // UDP connection
1217 unsigned is_websocket : 1; // WebSocket connection
1218 unsigned is_mqtt5 : 1; // For MQTT connection, v5 indicator
1219 unsigned is_hexdumping : 1; // Hexdump in/out traffic
1220 unsigned is_draining : 1; // Send remaining data, then close and free
1221 unsigned is_closing : 1; // Close and free the connection immediately
1222 unsigned is_full : 1; // Stop reads, until cleared
1223 unsigned is_resp : 1; // Response is still being generated
1224 unsigned is_readable : 1; // Connection is ready to read
1225 unsigned is_writable : 1; // Connection is ready to write
1226};
1227
1228void mg_mgr_poll(struct mg_mgr *, int ms);
1229void mg_mgr_init(struct mg_mgr *);
1230void mg_mgr_free(struct mg_mgr *);
1231
1232struct mg_connection *mg_listen(struct mg_mgr *, const char *url,
1233 mg_event_handler_t fn, void *fn_data);
1234struct mg_connection *mg_connect(struct mg_mgr *, const char *url,
1235 mg_event_handler_t fn, void *fn_data);
1236struct mg_connection *mg_wrapfd(struct mg_mgr *mgr, int fd,
1237 mg_event_handler_t fn, void *fn_data);
1238void mg_connect_resolved(struct mg_connection *);
1239bool mg_send(struct mg_connection *, const void *, size_t);
1240size_t mg_printf(struct mg_connection *, const char *fmt, ...);
1241size_t mg_vprintf(struct mg_connection *, const char *fmt, va_list *ap);
1242bool mg_aton(struct mg_str str, struct mg_addr *addr);
1243int mg_mkpipe(struct mg_mgr *, mg_event_handler_t, void *, bool udp);
1244
1245// These functions are used to integrate with custom network stacks
1246struct mg_connection *mg_alloc_conn(struct mg_mgr *);
1247void mg_close_conn(struct mg_connection *c);
1248bool mg_open_listener(struct mg_connection *c, const char *url);
1249
1250// Utility functions
1251struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds,
1252 unsigned flags, void (*fn)(void *), void *arg);
1253
1254// Low-level IO primives used by TLS layer
1255enum { MG_IO_ERR = -1, MG_IO_WAIT = -2, MG_IO_RESET = -3 };
1256long mg_io_send(struct mg_connection *c, const void *buf, size_t len);
1257long mg_io_recv(struct mg_connection *c, void *buf, size_t len);
1258
1259
1260
1261
1262
1263
1264
1265
1266struct mg_http_header {
1267 struct mg_str name; // Header name
1268 struct mg_str value; // Header value
1269};
1270
1271struct mg_http_message {
1272 struct mg_str method, uri, query, proto; // Request/response line
1273 struct mg_http_header headers[MG_MAX_HTTP_HEADERS]; // Headers
1274 struct mg_str body; // Body
1275 struct mg_str head; // Request + headers
1276 struct mg_str chunk; // Chunk for chunked encoding, or partial body
1277 struct mg_str message; // Request + headers + body
1278};
1279
1280// Parameter for mg_http_serve_dir()
1281struct mg_http_serve_opts {
1282 const char *root_dir; // Web root directory, must be non-NULL
1283 const char *ssi_pattern; // SSI file name pattern, e.g. #.shtml
1284 const char *extra_headers; // Extra HTTP headers to add in responses
1285 const char *mime_types; // Extra mime types, ext1=type1,ext2=type2,..
1286 const char *page404; // Path to the 404 page, or NULL by default
1287 struct mg_fs *fs; // Filesystem implementation. Use NULL for POSIX
1288};
1289
1290// Parameter for mg_http_next_multipart
1291struct mg_http_part {
1292 struct mg_str name; // Form field name
1293 struct mg_str filename; // Filename for file uploads
1294 struct mg_str body; // Part contents
1295};
1296
1297int mg_http_parse(const char *s, size_t len, struct mg_http_message *);
1298int mg_http_get_request_len(const unsigned char *buf, size_t buf_len);
1299void mg_http_printf_chunk(struct mg_connection *cnn, const char *fmt, ...);
1300void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len);
1301void mg_http_delete_chunk(struct mg_connection *c, struct mg_http_message *hm);
1302struct mg_connection *mg_http_listen(struct mg_mgr *, const char *url,
1303 mg_event_handler_t fn, void *fn_data);
1304struct mg_connection *mg_http_connect(struct mg_mgr *, const char *url,
1305 mg_event_handler_t fn, void *fn_data);
1306void mg_http_serve_dir(struct mg_connection *, struct mg_http_message *hm,
1307 const struct mg_http_serve_opts *);
1308void mg_http_serve_file(struct mg_connection *, struct mg_http_message *hm,
1309 const char *path, const struct mg_http_serve_opts *);
1310void mg_http_reply(struct mg_connection *, int status_code, const char *headers,
1311 const char *body_fmt, ...);
1312struct mg_str *mg_http_get_header(struct mg_http_message *, const char *name);
1313struct mg_str mg_http_var(struct mg_str buf, struct mg_str name);
1314int mg_http_get_var(const struct mg_str *, const char *name, char *, size_t);
1315int mg_url_decode(const char *s, size_t n, char *to, size_t to_len, int form);
1316size_t mg_url_encode(const char *s, size_t n, char *buf, size_t len);
1317void mg_http_creds(struct mg_http_message *, char *, size_t, char *, size_t);
1318bool mg_http_match_uri(const struct mg_http_message *, const char *glob);
1319long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
1320 struct mg_fs *fs, const char *path, size_t max_size);
1321void mg_http_bauth(struct mg_connection *, const char *user, const char *pass);
1322struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v);
1323size_t mg_http_next_multipart(struct mg_str, size_t, struct mg_http_part *);
1324int mg_http_status(const struct mg_http_message *hm);
1325void mg_hello(const char *url);
1326
1327
1328void mg_http_serve_ssi(struct mg_connection *c, const char *root,
1329 const char *fullpath);
1330
1331
1332
1333
1334
1335
1336struct mg_tls_opts {
1337 const char *ca; // CA certificate file. For both listeners and clients
1338 const char *crl; // Certificate Revocation List. For clients
1339 const char *cert; // Certificate
1340 const char *certkey; // Certificate key
1341 const char *ciphers; // Cipher list
1342 struct mg_str srvname; // If not empty, enables server name verification
1343 struct mg_fs *fs; // FS API for reading certificate files
1344};
1345
1346void mg_tls_init(struct mg_connection *, const struct mg_tls_opts *);
1347void mg_tls_free(struct mg_connection *);
1348long mg_tls_send(struct mg_connection *, const void *buf, size_t len);
1349long mg_tls_recv(struct mg_connection *, void *buf, size_t len);
1350size_t mg_tls_pending(struct mg_connection *);
1351void mg_tls_handshake(struct mg_connection *);
1352
1353
1354
1355
1356
1357
1358
1359#if MG_ENABLE_MBEDTLS
1360#include <mbedtls/debug.h>
1361#include <mbedtls/net_sockets.h>
1362#include <mbedtls/ssl.h>
1363
1364struct mg_tls {
1365 char *cafile; // CA certificate path
1366 mbedtls_x509_crt ca; // Parsed CA certificate
1367 mbedtls_x509_crt cert; // Parsed certificate
1368 mbedtls_ssl_context ssl; // SSL/TLS context
1369 mbedtls_ssl_config conf; // SSL-TLS config
1370 mbedtls_pk_context pk; // Private key context
1371};
1372#endif
1373
1374
1375#if MG_ENABLE_OPENSSL
1376
1377#include <openssl/err.h>
1378#include <openssl/ssl.h>
1379
1380struct mg_tls {
1381 SSL_CTX *ctx;
1382 SSL *ssl;
1383};
1384#endif
1385
1386
1387#define WEBSOCKET_OP_CONTINUE 0
1388#define WEBSOCKET_OP_TEXT 1
1389#define WEBSOCKET_OP_BINARY 2
1390#define WEBSOCKET_OP_CLOSE 8
1391#define WEBSOCKET_OP_PING 9
1392#define WEBSOCKET_OP_PONG 10
1393
1394
1395
1396struct mg_ws_message {
1397 struct mg_str data; // Websocket message data
1398 uint8_t flags; // Websocket message flags
1399};
1400
1401struct mg_connection *mg_ws_connect(struct mg_mgr *, const char *url,
1402 mg_event_handler_t fn, void *fn_data,
1403 const char *fmt, ...);
1404void mg_ws_upgrade(struct mg_connection *, struct mg_http_message *,
1405 const char *fmt, ...);
1406size_t mg_ws_send(struct mg_connection *, const void *buf, size_t len, int op);
1407size_t mg_ws_wrap(struct mg_connection *, size_t len, int op);
1408size_t mg_ws_printf(struct mg_connection *c, int op, const char *fmt, ...);
1409size_t mg_ws_vprintf(struct mg_connection *c, int op, const char *fmt,
1410 va_list *);
1411
1412
1413
1414
1415struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, const char *url,
1416 mg_event_handler_t fn, void *fn_data);
1417void mg_sntp_request(struct mg_connection *c);
1418int64_t mg_sntp_parse(const unsigned char *buf, size_t len);
1419
1420
1421
1422
1423
1424#define MQTT_CMD_CONNECT 1
1425#define MQTT_CMD_CONNACK 2
1426#define MQTT_CMD_PUBLISH 3
1427#define MQTT_CMD_PUBACK 4
1428#define MQTT_CMD_PUBREC 5
1429#define MQTT_CMD_PUBREL 6
1430#define MQTT_CMD_PUBCOMP 7
1431#define MQTT_CMD_SUBSCRIBE 8
1432#define MQTT_CMD_SUBACK 9
1433#define MQTT_CMD_UNSUBSCRIBE 10
1434#define MQTT_CMD_UNSUBACK 11
1435#define MQTT_CMD_PINGREQ 12
1436#define MQTT_CMD_PINGRESP 13
1437#define MQTT_CMD_DISCONNECT 14
1438#define MQTT_CMD_AUTH 15
1439
1440#define MQTT_PROP_PAYLOAD_FORMAT_INDICATOR 0x01
1441#define MQTT_PROP_MESSAGE_EXPIRY_INTERVAL 0x02
1442#define MQTT_PROP_CONTENT_TYPE 0x03
1443#define MQTT_PROP_RESPONSE_TOPIC 0x08
1444#define MQTT_PROP_CORRELATION_DATA 0x09
1445#define MQTT_PROP_SUBSCRIPTION_IDENTIFIER 0x0B
1446#define MQTT_PROP_SESSION_EXPIRY_INTERVAL 0x11
1447#define MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER 0x12
1448#define MQTT_PROP_SERVER_KEEP_ALIVE 0x13
1449#define MQTT_PROP_AUTHENTICATION_METHOD 0x15
1450#define MQTT_PROP_AUTHENTICATION_DATA 0x16
1451#define MQTT_PROP_REQUEST_PROBLEM_INFORMATION 0x17
1452#define MQTT_PROP_WILL_DELAY_INTERVAL 0x18
1453#define MQTT_PROP_REQUEST_RESPONSE_INFORMATION 0x19
1454#define MQTT_PROP_RESPONSE_INFORMATION 0x1A
1455#define MQTT_PROP_SERVER_REFERENCE 0x1C
1456#define MQTT_PROP_REASON_STRING 0x1F
1457#define MQTT_PROP_RECEIVE_MAXIMUM 0x21
1458#define MQTT_PROP_TOPIC_ALIAS_MAXIMUM 0x22
1459#define MQTT_PROP_TOPIC_ALIAS 0x23
1460#define MQTT_PROP_MAXIMUM_QOS 0x24
1461#define MQTT_PROP_RETAIN_AVAILABLE 0x25
1462#define MQTT_PROP_USER_PROPERTY 0x26
1463#define MQTT_PROP_MAXIMUM_PACKET_SIZE 0x27
1464#define MQTT_PROP_WILDCARD_SUBSCRIPTION_AVAILABLE 0x28
1465#define MQTT_PROP_SUBSCRIPTION_IDENTIFIER_AVAILABLE 0x29
1466#define MQTT_PROP_SHARED_SUBSCRIPTION_AVAILABLE 0x2A
1467
1468enum {
1469 MQTT_PROP_TYPE_BYTE,
1470 MQTT_PROP_TYPE_STRING,
1471 MQTT_PROP_TYPE_STRING_PAIR,
1472 MQTT_PROP_TYPE_BINARY_DATA,
1473 MQTT_PROP_TYPE_VARIABLE_INT,
1474 MQTT_PROP_TYPE_INT,
1475 MQTT_PROP_TYPE_SHORT
1476};
1477
1478enum { MQTT_OK, MQTT_INCOMPLETE, MQTT_MALFORMED };
1479
1480struct mg_mqtt_prop {
1481 uint8_t id; // Enumerated at MQTT5 Reference
1482 uint32_t iv; // Integer value for 8-, 16-, 32-bit integers types
1483 struct mg_str key; // Non-NULL only for user property type
1484 struct mg_str val; // Non-NULL only for UTF-8 types and user properties
1485};
1486
1487struct mg_mqtt_opts {
1488 struct mg_str user; // Username, can be empty
1489 struct mg_str pass; // Password, can be empty
1490 struct mg_str client_id; // Client ID
1491 struct mg_str topic; // message/subscription topic
1492 struct mg_str message; // message content
1493 uint8_t qos; // message quality of service
1494 uint8_t version; // Can be 4 (3.1.1), or 5. If 0, assume 4
1495 uint16_t keepalive; // Keep-alive timer in seconds
1496 bool retain; // Retain flag
1497 bool clean; // Clean session flag
1498 struct mg_mqtt_prop *props; // MQTT5 props array
1499 size_t num_props; // number of props
1500 struct mg_mqtt_prop *will_props; // Valid only for CONNECT packet (MQTT5)
1501 size_t num_will_props; // Number of will props
1502};
1503
1504struct mg_mqtt_message {
1505 struct mg_str topic; // Parsed topic for PUBLISH
1506 struct mg_str data; // Parsed message for PUBLISH
1507 struct mg_str dgram; // Whole MQTT packet, including headers
1508 uint16_t id; // For PUBACK, PUBREC, PUBREL, PUBCOMP, SUBACK, PUBLISH
1509 uint8_t cmd; // MQTT command, one of MQTT_CMD_*
1510 uint8_t qos; // Quality of service
1511 uint8_t ack; // CONNACK return code, 0 = success
1512 size_t props_start; // Offset to the start of the properties (MQTT5)
1513 size_t props_size; // Length of the properties
1514};
1515
1516struct mg_connection *mg_mqtt_connect(struct mg_mgr *, const char *url,
1517 const struct mg_mqtt_opts *opts,
1518 mg_event_handler_t fn, void *fn_data);
1519struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url,
1520 mg_event_handler_t fn, void *fn_data);
1521void mg_mqtt_login(struct mg_connection *c, const struct mg_mqtt_opts *opts);
1522void mg_mqtt_pub(struct mg_connection *c, const struct mg_mqtt_opts *opts);
1523void mg_mqtt_sub(struct mg_connection *, const struct mg_mqtt_opts *opts);
1524int mg_mqtt_parse(const uint8_t *, size_t, uint8_t, struct mg_mqtt_message *);
1525void mg_mqtt_send_header(struct mg_connection *, uint8_t cmd, uint8_t flags,
1526 uint32_t len);
1527void mg_mqtt_ping(struct mg_connection *);
1528void mg_mqtt_pong(struct mg_connection *);
1529void mg_mqtt_disconnect(struct mg_connection *, const struct mg_mqtt_opts *);
1530size_t mg_mqtt_next_prop(struct mg_mqtt_message *, struct mg_mqtt_prop *,
1531 size_t ofs);
1532
1533
1534
1535
1536
1537// Mongoose sends DNS queries that contain only one question:
1538// either A (IPv4) or AAAA (IPv6) address lookup.
1539// Therefore, we expect zero or one answer.
1540// If `resolved` is true, then `addr` contains resolved IPv4 or IPV6 address.
1541struct mg_dns_message {
1542 uint16_t txnid; // Transaction ID
1543 bool resolved; // Resolve successful, addr is set
1544 struct mg_addr addr; // Resolved address
1545 char name[256]; // Host name
1546};
1547
1548struct mg_dns_header {
1549 uint16_t txnid; // Transaction ID
1550 uint16_t flags;
1551 uint16_t num_questions;
1552 uint16_t num_answers;
1553 uint16_t num_authority_prs;
1554 uint16_t num_other_prs;
1555};
1556
1557// DNS resource record
1558struct mg_dns_rr {
1559 uint16_t nlen; // Name or pointer length
1560 uint16_t atype; // Address type
1561 uint16_t aclass; // Address class
1562 uint16_t alen; // Address length
1563};
1564
1565void mg_resolve(struct mg_connection *, const char *url);
1566void mg_resolve_cancel(struct mg_connection *);
1567bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *);
1568size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
1569 bool is_question, struct mg_dns_rr *);
1570
1571
1572
1573
1574
1575#ifndef MG_JSON_MAX_DEPTH
1576#define MG_JSON_MAX_DEPTH 30
1577#endif
1578
1579// Error return values - negative. Successful returns are >= 0
1580enum { MG_JSON_TOO_DEEP = -1, MG_JSON_INVALID = -2, MG_JSON_NOT_FOUND = -3 };
1581int mg_json_get(struct mg_str json, const char *path, int *toklen);
1582
1583bool mg_json_get_num(struct mg_str json, const char *path, double *v);
1584bool mg_json_get_bool(struct mg_str json, const char *path, bool *v);
1585long mg_json_get_long(struct mg_str json, const char *path, long dflt);
1586char *mg_json_get_str(struct mg_str json, const char *path);
1587char *mg_json_get_hex(struct mg_str json, const char *path, int *len);
1588char *mg_json_get_b64(struct mg_str json, const char *path, int *len);
1589
1590bool mg_json_unescape(struct mg_str str, char *buf, size_t len);
1591
1592
1593
1594
1595// JSON-RPC request descriptor
1596struct mg_rpc_req {
1597 struct mg_rpc **head; // RPC handlers list head
1598 struct mg_rpc *rpc; // RPC handler being called
1599 mg_pfn_t pfn; // Response printing function
1600 void *pfn_data; // Response printing function data
1601 void *req_data; // Arbitrary request data
1602 struct mg_str frame; // Request, e.g. {"id":1,"method":"add","params":[1,2]}
1603};
1604
1605// JSON-RPC method handler
1606struct mg_rpc {
1607 struct mg_rpc *next; // Next in list
1608 struct mg_str method; // Method pattern
1609 void (*fn)(struct mg_rpc_req *); // Handler function
1610 void *fn_data; // Handler function argument
1611};
1612
1613void mg_rpc_add(struct mg_rpc **head, struct mg_str method_pattern,
1614 void (*handler)(struct mg_rpc_req *), void *handler_data);
1615void mg_rpc_del(struct mg_rpc **head, void (*handler)(struct mg_rpc_req *));
1616void mg_rpc_process(struct mg_rpc_req *);
1617
1618// Helper functions to print result or error frame
1619void mg_rpc_ok(struct mg_rpc_req *, const char *fmt, ...);
1620void mg_rpc_vok(struct mg_rpc_req *, const char *fmt, va_list *ap);
1621void mg_rpc_err(struct mg_rpc_req *, int code, const char *fmt, ...);
1622void mg_rpc_verr(struct mg_rpc_req *, int code, const char *fmt, va_list *);
1623void mg_rpc_list(struct mg_rpc_req *r);
1624
1625
1626#if MG_ENABLE_TCPIP
1627
1628
1629
1630
1631struct mg_tcpip_if; // MIP network interface
1632
1633struct mg_tcpip_driver {
1634 bool (*init)(struct mg_tcpip_if *); // Init driver
1635 size_t (*tx)(const void *, size_t, struct mg_tcpip_if *); // Transmit frame
1636 size_t (*rx)(void *buf, size_t len, struct mg_tcpip_if *); // Receive frame
1637 bool (*up)(struct mg_tcpip_if *); // Up/down status
1638};
1639
1640// Network interface
1641struct mg_tcpip_if {
1642 uint8_t mac[6]; // MAC address. Must be set to a valid MAC
1643 uint32_t ip, mask, gw; // IP address, mask, default gateway
1644 struct mg_str tx; // Output (TX) buffer
1645 bool enable_dhcp_client; // Enable DCHP client
1646 bool enable_dhcp_server; // Enable DCHP server
1647 bool enable_crc32_check; // Do a CRC check on rx frames and strip it
1648 bool enable_mac_check; // Do a MAC check on rx frames
1649 struct mg_tcpip_driver *driver; // Low level driver
1650 void *driver_data; // Driver-specific data
1651 struct mg_mgr *mgr; // Mongoose event manager
1652 struct mg_queue recv_queue; // Receive queue
1653
1654 // Internal state, user can use it but should not change it
1655 uint8_t gwmac[6]; // Router's MAC
1656 uint64_t now; // Current time
1657 uint64_t timer_1000ms; // 1000 ms timer: for DHCP and link state
1658 uint64_t lease_expire; // Lease expiration time, in ms
1659 uint16_t eport; // Next ephemeral port
1660 volatile uint32_t ndrop; // Number of received, but dropped frames
1661 volatile uint32_t nrecv; // Number of received frames
1662 volatile uint32_t nsent; // Number of transmitted frames
1663 volatile uint32_t nerr; // Number of driver errors
1664 uint8_t state; // Current state
1665#define MG_TCPIP_STATE_DOWN 0 // Interface is down
1666#define MG_TCPIP_STATE_UP 1 // Interface is up
1667#define MG_TCPIP_STATE_REQ 2 // Interface is up and has requested an IP
1668#define MG_TCPIP_STATE_READY 3 // Interface is up and has an IP assigned
1669};
1670
1671void mg_tcpip_init(struct mg_mgr *, struct mg_tcpip_if *);
1672void mg_tcpip_free(struct mg_tcpip_if *);
1673void mg_tcpip_qwrite(void *buf, size_t len, struct mg_tcpip_if *ifp);
1674
1675extern struct mg_tcpip_driver mg_tcpip_driver_stm32;
1676extern struct mg_tcpip_driver mg_tcpip_driver_w5500;
1677extern struct mg_tcpip_driver mg_tcpip_driver_tm4c;
1678extern struct mg_tcpip_driver mg_tcpip_driver_stm32h;
1679extern struct mg_tcpip_driver mg_tcpip_driver_imxrt;
1680
1681// Drivers that require SPI, can use this SPI abstraction
1682struct mg_tcpip_spi {
1683 void *spi; // Opaque SPI bus descriptor
1684 void (*begin)(void *); // SPI begin: slave select low
1685 void (*end)(void *); // SPI end: slave select high
1686 uint8_t (*txn)(void *, uint8_t); // SPI transaction: write 1 byte, read reply
1687};
1688
1689#if !defined(MG_ENABLE_DRIVER_STM32H) && !defined(MG_ENABLE_DRIVER_TM4C)
1690#define MG_ENABLE_DRIVER_STM32 1
1691#else
1692#define MG_ENABLE_DRIVER_STM32 0
1693#endif
1694#endif
1695
1696
1697struct mg_tcpip_driver_imxrt1020_data {
1698 // MDC clock divider. MDC clock is derived from IPS Bus clock (ipg_clk),
1699 // must not exceed 2.5MHz. Configuration for clock range 2.36~2.50 MHz
1700 // ipg_clk MSCR mdc_cr VALUE
1701 // -------------------------------------
1702 // -1 <-- tell driver to guess the value
1703 // 25 MHz 0x04 0
1704 // 33 MHz 0x06 1
1705 // 40 MHz 0x07 2
1706 // 50 MHz 0x09 3
1707 // 66 MHz 0x0D 4 <-- value for iMXRT1020-EVK at max freq.
1708 int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4
1709};
1710
1711
1712struct mg_tcpip_driver_stm32_data {
1713 // MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz
1714 // HCLK range DIVIDER mdc_cr VALUE
1715 // -------------------------------------
1716 // -1 <-- tell driver to guess the value
1717 // 60-100 MHz HCLK/42 0
1718 // 100-150 MHz HCLK/62 1
1719 // 20-35 MHz HCLK/16 2
1720 // 35-60 MHz HCLK/26 3
1721 // 150-216 MHz HCLK/102 4 <-- value for Nucleo-F* on max speed
1722 // 216-310 MHz HCLK/124 5
1723 // 110, 111 Reserved
1724 int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5
1725};
1726
1727
1728struct mg_tcpip_driver_stm32h_data {
1729 // MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz
1730 // HCLK range DIVIDER mdc_cr VALUE
1731 // -------------------------------------
1732 // -1 <-- tell driver to guess the value
1733 // 60-100 MHz HCLK/42 0
1734 // 100-150 MHz HCLK/62 1
1735 // 20-35 MHz HCLK/16 2
1736 // 35-60 MHz HCLK/26 3
1737 // 150-250 MHz HCLK/102 4 <-- value for Nucleo-H* on max speed driven by HSI
1738 // 250-300 MHz HCLK/124 5 <-- value for Nucleo-H* on max speed driven by CSI
1739 // 110, 111 Reserved
1740 int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5
1741};
1742
1743
1744struct mg_tcpip_driver_tm4c_data {
1745 // MDC clock divider. MDC clock is derived from SYSCLK, must not exceed 2.5MHz
1746 // SYSCLK range DIVIDER mdc_cr VALUE
1747 // -------------------------------------
1748 // -1 <-- tell driver to guess the value
1749 // 60-100 MHz SYSCLK/42 0
1750 // 100-150 MHz SYSCLK/62 1 <-- value for EK-TM4C129* on max speed
1751 // 20-35 MHz SYSCLK/16 2
1752 // 35-60 MHz SYSCLK/26 3
1753 // 0x4-0xF Reserved
1754 int mdc_cr; // Valid values: -1, 0, 1, 2, 3
1755};
1756
1757#ifdef __cplusplus
1758}
1759#endif
1760#endif // MONGOOSE_H
1761