From 32559f15ea048538d22e0a51f637f27718baa4ca Mon Sep 17 00:00:00 2001 From: "Sergio R. Caprile" Date: Thu, 12 Oct 2023 10:56:38 -0300 Subject: [PATCH] fix Github editor line ending creativity --- mongoose.h | 3708 ++++++++++++++++++++++++++-------------------------- 1 file changed, 1854 insertions(+), 1854 deletions(-) diff --git a/mongoose.h b/mongoose.h index 09403e9f85..fc9eb7ac04 100644 --- a/mongoose.h +++ b/mongoose.h @@ -1,261 +1,261 @@ -// Copyright (c) 2004-2013 Sergey Lyubka -// Copyright (c) 2013-2022 Cesanta Software Limited -// All rights reserved -// -// This software is dual-licensed: you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. For the terms of this -// license, see http://www.gnu.org/licenses/ -// -// You are free to use this software under the terms of the GNU General -// Public License, but WITHOUT ANY WARRANTY; without even the implied -// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU General Public License for more details. -// -// Alternatively, you can license this software under a commercial -// license, as set out in https://www.mongoose.ws/licensing/ -// -// SPDX-License-Identifier: GPL-2.0-only or commercial - -#ifndef MONGOOSE_H -#define MONGOOSE_H - -#define MG_VERSION "7.12" - -#ifdef __cplusplus -extern "C" { -#endif - - -#define MG_ARCH_CUSTOM 0 // User creates its own mongoose_custom.h -#define MG_ARCH_UNIX 1 // Linux, BSD, Mac, ... -#define MG_ARCH_WIN32 2 // Windows -#define MG_ARCH_ESP32 3 // ESP32 -#define MG_ARCH_ESP8266 4 // ESP8266 -#define MG_ARCH_FREERTOS 5 // FreeRTOS -#define MG_ARCH_AZURERTOS 6 // MS Azure RTOS -#define MG_ARCH_ZEPHYR 7 // Zephyr RTOS -#define MG_ARCH_NEWLIB 8 // Bare metal ARM -#define MG_ARCH_CMSIS_RTOS1 9 // CMSIS-RTOS API v1 (Keil RTX) -#define MG_ARCH_TIRTOS 10 // Texas Semi TI-RTOS -#define MG_ARCH_RP2040 11 // Raspberry Pi RP2040 -#define MG_ARCH_ARMCC 12 // Keil MDK-Core with Configuration Wizard -#define MG_ARCH_CMSIS_RTOS2 13 // CMSIS-RTOS API v2 (Keil RTX5, FreeRTOS) -#define MG_ARCH_RTTHREAD 14 // RT-Thread RTOS - -#if !defined(MG_ARCH) -#if defined(__unix__) || defined(__APPLE__) -#define MG_ARCH MG_ARCH_UNIX -#elif defined(_WIN32) -#define MG_ARCH MG_ARCH_WIN32 -#elif defined(ICACHE_FLASH) || defined(ICACHE_RAM_ATTR) -#define MG_ARCH MG_ARCH_ESP8266 -#elif defined(__ZEPHYR__) -#define MG_ARCH MG_ARCH_ZEPHYR -#elif defined(ESP_PLATFORM) -#define MG_ARCH MG_ARCH_ESP32 -#elif defined(FREERTOS_IP_H) -#define MG_ARCH MG_ARCH_FREERTOS -#define MG_ENABLE_FREERTOS_TCP 1 -#elif defined(AZURE_RTOS_THREADX) -#define MG_ARCH MG_ARCH_AZURERTOS -#elif defined(PICO_TARGET_NAME) -#define MG_ARCH MG_ARCH_RP2040 -#elif defined(__ARMCC_VERSION) -#define MG_ARCH MG_ARCH_ARMCC -#elif defined(__RTTHREAD__) -#define MG_ARCH MG_ARCH_RTTHREAD -#endif -#endif // !defined(MG_ARCH) - -// if the user did not specify an MG_ARCH, or specified a custom one, OR -// we guessed a known IDE, pull the customized config (Configuration Wizard) -#if !defined(MG_ARCH) || (MG_ARCH == MG_ARCH_CUSTOM) || MG_ARCH == MG_ARCH_ARMCC -#include "mongoose_custom.h" // keep this include -#endif - -#if !defined(MG_ARCH) -#error "MG_ARCH is not specified and we couldn't guess it. Set -D MG_ARCH=..." -#endif - -// http://esr.ibiblio.org/?p=5095 -#define MG_BIG_ENDIAN (*(uint16_t *) "\0\xff" < 0x100) - - - - - - - - - - - - - - - -#if MG_ARCH == MG_ARCH_AZURERTOS - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#define PATH_MAX FX_MAXIMUM_PATH -#define MG_DIRSEP '\\' - -#define socklen_t int -#define closesocket(x) soc_close(x) - -#undef FOPEN_MAX - -#endif - - -#if MG_ARCH == MG_ARCH_ESP32 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define MG_PATH_MAX 128 - -#endif - - -#if MG_ARCH == MG_ARCH_ESP8266 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define MG_PATH_MAX 128 - -#endif - - -#if MG_ARCH == MG_ARCH_FREERTOS - -#include -#if !defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP -#include -#endif -#include -#include -#include -#include -#include -#include // rand(), strtol(), atoi() -#include -#if defined(__ARMCC_VERSION) -#define mode_t size_t -#include -#else -#include -#endif - -#include -#include - -#ifndef MG_IO_SIZE -#define MG_IO_SIZE 512 -#endif - -#define calloc(a, b) mg_calloc(a, b) -#define free(a) vPortFree(a) -#define malloc(a) pvPortMalloc(a) -#define strdup(s) ((char *) mg_strdup(mg_str(s)).ptr) - -// Re-route calloc/free to the FreeRTOS's functions, don't use stdlib -static inline void *mg_calloc(size_t cnt, size_t size) { - void *p = pvPortMalloc(cnt * size); - if (p != NULL) memset(p, 0, size * cnt); - return p; -} - -#define mkdir(a, b) mg_mkdir(a, b) -static inline int mg_mkdir(const char *path, mode_t mode) { - (void) path, (void) mode; - return -1; -} - -#endif // MG_ARCH == MG_ARCH_FREERTOS - - -#if MG_ARCH == MG_ARCH_NEWLIB -#define _POSIX_TIMERS - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MG_PATH_MAX 100 -#define MG_ENABLE_SOCKET 0 -#define MG_ENABLE_DIRLIST 0 - -#endif - - -#if MG_ARCH == MG_ARCH_RP2040 -#include -#include -#include -#include -#include -#include -#include -#include - -#include -int mkdir(const char *, mode_t); -#endif +// Copyright (c) 2004-2013 Sergey Lyubka +// Copyright (c) 2013-2022 Cesanta Software Limited +// All rights reserved +// +// This software is dual-licensed: you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. For the terms of this +// license, see http://www.gnu.org/licenses/ +// +// You are free to use this software under the terms of the GNU General +// Public License, but WITHOUT ANY WARRANTY; without even the implied +// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// Alternatively, you can license this software under a commercial +// license, as set out in https://www.mongoose.ws/licensing/ +// +// SPDX-License-Identifier: GPL-2.0-only or commercial + +#ifndef MONGOOSE_H +#define MONGOOSE_H + +#define MG_VERSION "7.12" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define MG_ARCH_CUSTOM 0 // User creates its own mongoose_custom.h +#define MG_ARCH_UNIX 1 // Linux, BSD, Mac, ... +#define MG_ARCH_WIN32 2 // Windows +#define MG_ARCH_ESP32 3 // ESP32 +#define MG_ARCH_ESP8266 4 // ESP8266 +#define MG_ARCH_FREERTOS 5 // FreeRTOS +#define MG_ARCH_AZURERTOS 6 // MS Azure RTOS +#define MG_ARCH_ZEPHYR 7 // Zephyr RTOS +#define MG_ARCH_NEWLIB 8 // Bare metal ARM +#define MG_ARCH_CMSIS_RTOS1 9 // CMSIS-RTOS API v1 (Keil RTX) +#define MG_ARCH_TIRTOS 10 // Texas Semi TI-RTOS +#define MG_ARCH_RP2040 11 // Raspberry Pi RP2040 +#define MG_ARCH_ARMCC 12 // Keil MDK-Core with Configuration Wizard +#define MG_ARCH_CMSIS_RTOS2 13 // CMSIS-RTOS API v2 (Keil RTX5, FreeRTOS) +#define MG_ARCH_RTTHREAD 14 // RT-Thread RTOS + +#if !defined(MG_ARCH) +#if defined(__unix__) || defined(__APPLE__) +#define MG_ARCH MG_ARCH_UNIX +#elif defined(_WIN32) +#define MG_ARCH MG_ARCH_WIN32 +#elif defined(ICACHE_FLASH) || defined(ICACHE_RAM_ATTR) +#define MG_ARCH MG_ARCH_ESP8266 +#elif defined(__ZEPHYR__) +#define MG_ARCH MG_ARCH_ZEPHYR +#elif defined(ESP_PLATFORM) +#define MG_ARCH MG_ARCH_ESP32 +#elif defined(FREERTOS_IP_H) +#define MG_ARCH MG_ARCH_FREERTOS +#define MG_ENABLE_FREERTOS_TCP 1 +#elif defined(AZURE_RTOS_THREADX) +#define MG_ARCH MG_ARCH_AZURERTOS +#elif defined(PICO_TARGET_NAME) +#define MG_ARCH MG_ARCH_RP2040 +#elif defined(__ARMCC_VERSION) +#define MG_ARCH MG_ARCH_ARMCC +#elif defined(__RTTHREAD__) +#define MG_ARCH MG_ARCH_RTTHREAD +#endif +#endif // !defined(MG_ARCH) + +// if the user did not specify an MG_ARCH, or specified a custom one, OR +// we guessed a known IDE, pull the customized config (Configuration Wizard) +#if !defined(MG_ARCH) || (MG_ARCH == MG_ARCH_CUSTOM) || MG_ARCH == MG_ARCH_ARMCC +#include "mongoose_custom.h" // keep this include +#endif + +#if !defined(MG_ARCH) +#error "MG_ARCH is not specified and we couldn't guess it. Set -D MG_ARCH=..." +#endif + +// http://esr.ibiblio.org/?p=5095 +#define MG_BIG_ENDIAN (*(uint16_t *) "\0\xff" < 0x100) + + + + + + + + + + + + + + + +#if MG_ARCH == MG_ARCH_AZURERTOS + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#define PATH_MAX FX_MAXIMUM_PATH +#define MG_DIRSEP '\\' + +#define socklen_t int +#define closesocket(x) soc_close(x) + +#undef FOPEN_MAX + +#endif + + +#if MG_ARCH == MG_ARCH_ESP32 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define MG_PATH_MAX 128 + +#endif + + +#if MG_ARCH == MG_ARCH_ESP8266 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define MG_PATH_MAX 128 + +#endif + + +#if MG_ARCH == MG_ARCH_FREERTOS + +#include +#if !defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP +#include +#endif +#include +#include +#include +#include +#include +#include // rand(), strtol(), atoi() +#include +#if defined(__ARMCC_VERSION) +#define mode_t size_t +#include +#else +#include +#endif + +#include +#include + +#ifndef MG_IO_SIZE +#define MG_IO_SIZE 512 +#endif + +#define calloc(a, b) mg_calloc(a, b) +#define free(a) vPortFree(a) +#define malloc(a) pvPortMalloc(a) +#define strdup(s) ((char *) mg_strdup(mg_str(s)).ptr) + +// Re-route calloc/free to the FreeRTOS's functions, don't use stdlib +static inline void *mg_calloc(size_t cnt, size_t size) { + void *p = pvPortMalloc(cnt * size); + if (p != NULL) memset(p, 0, size * cnt); + return p; +} + +#define mkdir(a, b) mg_mkdir(a, b) +static inline int mg_mkdir(const char *path, mode_t mode) { + (void) path, (void) mode; + return -1; +} + +#endif // MG_ARCH == MG_ARCH_FREERTOS + + +#if MG_ARCH == MG_ARCH_NEWLIB +#define _POSIX_TIMERS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MG_PATH_MAX 100 +#define MG_ENABLE_SOCKET 0 +#define MG_ENABLE_DIRLIST 0 + +#endif + + +#if MG_ARCH == MG_ARCH_RP2040 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +int mkdir(const char *, mode_t); +#endif #if MG_ARCH == MG_ARCH_RTTHREAD @@ -280,1599 +280,1599 @@ int mkdir(const char *, mode_t); #endif #endif // MG_ARCH == MG_ARCH_RTTHREAD - - -#if MG_ARCH == MG_ARCH_ARMCC || MG_ARCH == MG_ARCH_CMSIS_RTOS1 || \ - MG_ARCH == MG_ARCH_CMSIS_RTOS2 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if MG_ARCH == MG_ARCH_CMSIS_RTOS1 -#include "cmsis_os.h" // keep this include -// https://developer.arm.com/documentation/ka003821/latest -extern uint32_t rt_time_get(void); -#elif MG_ARCH == MG_ARCH_CMSIS_RTOS2 -#include "cmsis_os2.h" // keep this include -#endif - -#define strdup(s) ((char *) mg_strdup(mg_str(s)).ptr) - -#if defined(__ARMCC_VERSION) -#define mode_t size_t -#define mkdir(a, b) mg_mkdir(a, b) -static inline int mg_mkdir(const char *path, mode_t mode) { - (void) path, (void) mode; - return -1; -} -#endif - -#if (MG_ARCH == MG_ARCH_CMSIS_RTOS1 || MG_ARCH == MG_ARCH_CMSIS_RTOS2) && \ - !defined MG_ENABLE_RL && (!defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP) && \ - (!defined(MG_ENABLE_TCPIP) || !MG_ENABLE_TCPIP) -#define MG_ENABLE_RL 1 -#endif - -#endif - - -#if MG_ARCH == MG_ARCH_TIRTOS - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#endif - - -#if MG_ARCH == MG_ARCH_UNIX - -#define _DARWIN_UNLIMITED_SELECT 1 // No limit on file descriptors - -#if defined(__APPLE__) -#include -#endif - -#if !defined(MG_ENABLE_EPOLL) && defined(__linux__) -#define MG_ENABLE_EPOLL 1 -#elif !defined(MG_ENABLE_POLL) -#define MG_ENABLE_POLL 1 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(MG_ENABLE_EPOLL) && MG_ENABLE_EPOLL -#include -#elif defined(MG_ENABLE_POLL) && MG_ENABLE_POLL -#include -#else -#include -#endif - -#include -#include -#include -#include -#include -#include - -#ifndef MG_ENABLE_DIRLIST -#define MG_ENABLE_DIRLIST 1 -#endif - -#ifndef MG_PATH_MAX -#define MG_PATH_MAX FILENAME_MAX -#endif - -#endif - - -#if MG_ARCH == MG_ARCH_WIN32 - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif - -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif - -#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS -#define _WINSOCK_DEPRECATED_NO_WARNINGS -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(_MSC_VER) && _MSC_VER < 1700 -#define __func__ "" -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -typedef unsigned char uint8_t; -typedef char int8_t; -typedef unsigned short uint16_t; -typedef short int16_t; -typedef unsigned int uint32_t; -typedef int int32_t; -typedef enum { false = 0, true = 1 } bool; -#else -#include -#include -#include -#endif - -#include -#include -#include - -// Protect from calls like std::snprintf in app code -// See https://github.com/cesanta/mongoose/issues/1047 -#ifndef __cplusplus -#define snprintf _snprintf -#define vsnprintf _vsnprintf -#ifndef strdup // For MSVC with _DEBUG, see #1359 -#define strdup(x) _strdup(x) -#endif -#endif - -#define MG_INVALID_SOCKET INVALID_SOCKET -#define MG_SOCKET_TYPE SOCKET -typedef unsigned long nfds_t; -#if defined(_MSC_VER) -#pragma comment(lib, "ws2_32.lib") -#ifndef alloca -#define alloca(a) _alloca(a) -#endif -#endif -#define poll(a, b, c) WSAPoll((a), (b), (c)) -#define closesocket(x) closesocket(x) - -typedef int socklen_t; -#define MG_DIRSEP '\\' - -#ifndef MG_PATH_MAX -#define MG_PATH_MAX FILENAME_MAX -#endif - -#ifndef SO_EXCLUSIVEADDRUSE -#define SO_EXCLUSIVEADDRUSE ((int) (~SO_REUSEADDR)) -#endif - -#define MG_SOCK_ERR(errcode) ((errcode) < 0 ? WSAGetLastError() : 0) - -#define MG_SOCK_PENDING(errcode) \ - (((errcode) < 0) && \ - (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEINPROGRESS || \ - WSAGetLastError() == WSAEWOULDBLOCK)) - -#define MG_SOCK_RESET(errcode) \ - (((errcode) < 0) && (WSAGetLastError() == WSAECONNRESET)) - -#define realpath(a, b) _fullpath((b), (a), MG_PATH_MAX) -#define sleep(x) Sleep((x) *1000) -#define mkdir(a, b) _mkdir(a) - -#ifndef S_ISDIR -#define S_ISDIR(x) (((x) &_S_IFMT) == _S_IFDIR) -#endif - -#ifndef MG_ENABLE_DIRLIST -#define MG_ENABLE_DIRLIST 1 -#endif - -#ifndef SIGPIPE -#define SIGPIPE 0 -#endif - -#endif - - -#if MG_ARCH == MG_ARCH_ZEPHYR - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MG_PUTCHAR(x) printk("%c", x) -#ifndef strdup -#define strdup(s) ((char *) mg_strdup(mg_str(s)).ptr) -#endif -#define strerror(x) zsock_gai_strerror(x) -#define FD_CLOEXEC 0 -#define F_SETFD 0 -#define MG_ENABLE_SSI 0 - -int rand(void); -int sscanf(const char *, const char *, ...); - -#endif - - -#if defined(MG_ENABLE_FREERTOS_TCP) && MG_ENABLE_FREERTOS_TCP - -#include -#include - -#include -#include -#include // contents to be moved and file removed, some day - -#define MG_SOCKET_TYPE Socket_t -#define MG_INVALID_SOCKET FREERTOS_INVALID_SOCKET - -// Why FreeRTOS-TCP did not implement a clean BSD API, but its own thing -// with FreeRTOS_ prefix, is beyond me -#define IPPROTO_TCP FREERTOS_IPPROTO_TCP -#define IPPROTO_UDP FREERTOS_IPPROTO_UDP -#define AF_INET FREERTOS_AF_INET -#define SOCK_STREAM FREERTOS_SOCK_STREAM -#define SOCK_DGRAM FREERTOS_SOCK_DGRAM -#define SO_BROADCAST 0 -#define SO_ERROR 0 -#define SOL_SOCKET 0 -#define SO_REUSEADDR 0 - -#define MG_SOCK_ERR(errcode) ((errcode) < 0 ? (errcode) : 0) - -#define MG_SOCK_PENDING(errcode) \ - ((errcode) == -pdFREERTOS_ERRNO_EWOULDBLOCK || \ - (errcode) == -pdFREERTOS_ERRNO_EISCONN || \ - (errcode) == -pdFREERTOS_ERRNO_EINPROGRESS || \ - (errcode) == -pdFREERTOS_ERRNO_EAGAIN) - -#define MG_SOCK_RESET(errcode) ((errcode) == -pdFREERTOS_ERRNO_ENOTCONN) - -// actually only if optional timeout is enabled -#define MG_SOCK_INTR(fd) (fd == NULL) - -#define sockaddr_in freertos_sockaddr -#define sockaddr freertos_sockaddr -#define accept(a, b, c) FreeRTOS_accept((a), (b), (c)) -#define connect(a, b, c) FreeRTOS_connect((a), (b), (c)) -#define bind(a, b, c) FreeRTOS_bind((a), (b), (c)) -#define listen(a, b) FreeRTOS_listen((a), (b)) -#define socket(a, b, c) FreeRTOS_socket((a), (b), (c)) -#define send(a, b, c, d) FreeRTOS_send((a), (b), (c), (d)) -#define recv(a, b, c, d) FreeRTOS_recv((a), (b), (c), (d)) -#define setsockopt(a, b, c, d, e) FreeRTOS_setsockopt((a), (b), (c), (d), (e)) -#define sendto(a, b, c, d, e, f) FreeRTOS_sendto((a), (b), (c), (d), (e), (f)) -#define recvfrom(a, b, c, d, e, f) \ - FreeRTOS_recvfrom((a), (b), (c), (d), (e), (f)) -#define closesocket(x) FreeRTOS_closesocket(x) -#define gethostbyname(x) FreeRTOS_gethostbyname(x) -#define getsockname(a, b, c) mg_getsockname((a), (b), (c)) -#define getpeername(a, b, c) mg_getpeername((a), (b), (c)) - -static inline int mg_getsockname(MG_SOCKET_TYPE fd, void *buf, socklen_t *len) { - (void) fd, (void) buf, (void) len; - return -1; -} - -static inline int mg_getpeername(MG_SOCKET_TYPE fd, void *buf, socklen_t *len) { - (void) fd, (void) buf, (void) len; - return 0; -} -#endif - - -#if defined(MG_ENABLE_LWIP) && MG_ENABLE_LWIP - -#if defined(__GNUC__) && !defined(__ARMCC_VERSION) -#include -#endif - -struct timeval; - -#include - -#if !LWIP_TIMEVAL_PRIVATE -#if defined(__GNUC__) && !defined(__ARMCC_VERSION) // armclang sets both -#include -#else -struct timeval { - time_t tv_sec; - long tv_usec; -}; -#endif -#endif - -#if LWIP_SOCKET != 1 -// Sockets support disabled in LWIP by default -#error Set LWIP_SOCKET variable to 1 (in lwipopts.h) -#endif -#endif - - -#if defined(MG_ENABLE_RL) && MG_ENABLE_RL -#include - -#define closesocket(x) closesocket(x) - -#define TCP_NODELAY SO_KEEPALIVE - -#define MG_SOCK_ERR(errcode) ((errcode) < 0 ? (errcode) : 0) - -#define MG_SOCK_PENDING(errcode) \ - ((errcode) == BSD_EWOULDBLOCK || (errcode) == BSD_EALREADY || \ - (errcode) == BSD_EINPROGRESS) - -#define MG_SOCK_RESET(errcode) \ - ((errcode) == BSD_ECONNABORTED || (errcode) == BSD_ECONNRESET) - -// In blocking mode, which is enabled by default, accept() waits for a -// connection request. In non blocking mode, you must call accept() -// again if the error code BSD_EWOULDBLOCK is returned. -#define MG_SOCK_INTR(fd) (fd == BSD_EWOULDBLOCK) - -#define socklen_t int -#endif - - -#ifndef MG_ENABLE_LOG -#define MG_ENABLE_LOG 1 -#endif - -#ifndef MG_ENABLE_CUSTOM_LOG -#define MG_ENABLE_CUSTOM_LOG 0 // Let user define their own MG_LOG -#endif - -#ifndef MG_ENABLE_TCPIP -#define MG_ENABLE_TCPIP 0 // Mongoose built-in network stack -#endif - -#ifndef MG_ENABLE_LWIP -#define MG_ENABLE_LWIP 0 // lWIP network stack -#endif - -#ifndef MG_ENABLE_FREERTOS_TCP -#define MG_ENABLE_FREERTOS_TCP 0 // Amazon FreeRTOS-TCP network stack -#endif - -#ifndef MG_ENABLE_RL -#define MG_ENABLE_RL 0 // ARM MDK network stack -#endif - -#ifndef MG_ENABLE_SOCKET -#define MG_ENABLE_SOCKET !MG_ENABLE_TCPIP -#endif - -#ifndef MG_ENABLE_POLL -#define MG_ENABLE_POLL 0 -#endif - -#ifndef MG_ENABLE_EPOLL -#define MG_ENABLE_EPOLL 0 -#endif - -#ifndef MG_ENABLE_FATFS -#define MG_ENABLE_FATFS 0 -#endif - -#ifndef MG_ENABLE_SSI -#define MG_ENABLE_SSI 0 -#endif - -#ifndef MG_ENABLE_IPV6 -#define MG_ENABLE_IPV6 0 -#endif - -#ifndef MG_IPV6_V6ONLY -#define MG_IPV6_V6ONLY 0 // IPv6 socket binds only to V6, not V4 address -#endif - -#ifndef MG_ENABLE_MD5 -#define MG_ENABLE_MD5 1 -#endif - -// Set MG_ENABLE_WINSOCK=0 for Win32 builds with external IP stack (like LWIP) -#ifndef MG_ENABLE_WINSOCK -#define MG_ENABLE_WINSOCK 1 -#endif - -#ifndef MG_ENABLE_DIRLIST -#define MG_ENABLE_DIRLIST 0 -#endif - -#ifndef MG_ENABLE_CUSTOM_RANDOM -#define MG_ENABLE_CUSTOM_RANDOM 0 -#endif - -#ifndef MG_ENABLE_CUSTOM_MILLIS -#define MG_ENABLE_CUSTOM_MILLIS 0 -#endif - -#ifndef MG_ENABLE_PACKED_FS -#define MG_ENABLE_PACKED_FS 0 -#endif - -#ifndef MG_ENABLE_ASSERT -#define MG_ENABLE_ASSERT 0 -#endif - -#ifndef MG_IO_SIZE -#define MG_IO_SIZE 2048 // Granularity of the send/recv IO buffer growth -#endif - -#ifndef MG_MAX_RECV_SIZE -#define MG_MAX_RECV_SIZE (3UL * 1024UL * 1024UL) // Maximum recv IO buffer size -#endif - -#ifndef MG_DATA_SIZE -#define MG_DATA_SIZE 32 // struct mg_connection :: data size -#endif - -#ifndef MG_MAX_HTTP_HEADERS -#define MG_MAX_HTTP_HEADERS 30 -#endif - -#ifndef MG_HTTP_INDEX -#define MG_HTTP_INDEX "index.html" -#endif - -#ifndef MG_PATH_MAX -#ifdef PATH_MAX -#define MG_PATH_MAX PATH_MAX -#else -#define MG_PATH_MAX 128 -#endif -#endif - -#ifndef MG_SOCK_LISTEN_BACKLOG_SIZE -#define MG_SOCK_LISTEN_BACKLOG_SIZE 3 -#endif - -#ifndef MG_DIRSEP -#define MG_DIRSEP '/' -#endif - -#ifndef MG_ENABLE_FILE -#if defined(FOPEN_MAX) -#define MG_ENABLE_FILE 1 -#else -#define MG_ENABLE_FILE 0 -#endif -#endif - -#ifndef MG_INVALID_SOCKET -#define MG_INVALID_SOCKET (-1) -#endif - -#ifndef MG_SOCKET_TYPE -#define MG_SOCKET_TYPE int -#endif - -#ifndef MG_SOCKET_ERRNO -#define MG_SOCKET_ERRNO errno -#endif - -#if MG_ENABLE_EPOLL -#define MG_EPOLL_ADD(c) \ - do { \ - struct epoll_event ev = {EPOLLIN | EPOLLERR | EPOLLHUP, {c}}; \ - epoll_ctl(c->mgr->epoll_fd, EPOLL_CTL_ADD, (int) (size_t) c->fd, &ev); \ - } while (0) -#define MG_EPOLL_MOD(c, wr) \ - do { \ - struct epoll_event ev = {EPOLLIN | EPOLLERR | EPOLLHUP, {c}}; \ - if (wr) ev.events |= EPOLLOUT; \ - epoll_ctl(c->mgr->epoll_fd, EPOLL_CTL_MOD, (int) (size_t) c->fd, &ev); \ - } while (0) -#else -#define MG_EPOLL_ADD(c) -#define MG_EPOLL_MOD(c, wr) -#endif - - - - -struct mg_str { - const char *ptr; // Pointer to string data - size_t len; // String len -}; - -#define MG_NULL_STR \ - { NULL, 0 } - -#define MG_C_STR(a) \ - { (a), sizeof(a) - 1 } - -// Using macro to avoid shadowing C++ struct constructor, see #1298 -#define mg_str(s) mg_str_s(s) - -struct mg_str mg_str(const char *s); -struct mg_str mg_str_n(const char *s, size_t n); -int mg_lower(const char *s); -int mg_ncasecmp(const char *s1, const char *s2, size_t len); -int mg_casecmp(const char *s1, const char *s2); -int mg_vcmp(const struct mg_str *s1, const char *s2); -int mg_vcasecmp(const struct mg_str *str1, const char *str2); -int mg_strcmp(const struct mg_str str1, const struct mg_str str2); -struct mg_str mg_strstrip(struct mg_str s); -struct mg_str mg_strdup(const struct mg_str s); -const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle); -bool mg_match(struct mg_str str, struct mg_str pattern, struct mg_str *caps); -bool mg_globmatch(const char *pattern, size_t plen, const char *s, size_t n); -bool mg_commalist(struct mg_str *s, struct mg_str *k, struct mg_str *v); -bool mg_split(struct mg_str *s, struct mg_str *k, struct mg_str *v, char delim); -char *mg_hex(const void *buf, size_t len, char *dst); -void mg_unhex(const char *buf, size_t len, unsigned char *to); -unsigned long mg_unhexn(const char *s, size_t len); -bool mg_path_is_sane(const char *path); - - - - -// Single producer, single consumer non-blocking queue - -struct mg_queue { - char *buf; - size_t size; - volatile size_t tail; - volatile size_t head; -}; - -void mg_queue_init(struct mg_queue *, char *, size_t); // Init queue -size_t mg_queue_book(struct mg_queue *, char **buf, size_t); // Reserve space -void mg_queue_add(struct mg_queue *, size_t); // Add new message -size_t mg_queue_next(struct mg_queue *, char **); // Get oldest message -void mg_queue_del(struct mg_queue *, size_t); // Delete oldest message - - - - -typedef void (*mg_pfn_t)(char, void *); // Output function -typedef size_t (*mg_pm_t)(mg_pfn_t, void *, va_list *); // %M printer - -size_t mg_vxprintf(void (*)(char, void *), void *, const char *fmt, va_list *); -size_t mg_xprintf(void (*fn)(char, void *), void *, const char *fmt, ...); - - - - - - -// Convenience wrappers around mg_xprintf -size_t mg_vsnprintf(char *buf, size_t len, const char *fmt, va_list *ap); -size_t mg_snprintf(char *, size_t, const char *fmt, ...); -char *mg_vmprintf(const char *fmt, va_list *ap); -char *mg_mprintf(const char *fmt, ...); -size_t mg_queue_vprintf(struct mg_queue *, const char *fmt, va_list *); -size_t mg_queue_printf(struct mg_queue *, const char *fmt, ...); - -// %M print helper functions -size_t mg_print_base64(void (*out)(char, void *), void *arg, va_list *ap); -size_t mg_print_esc(void (*out)(char, void *), void *arg, va_list *ap); -size_t mg_print_hex(void (*out)(char, void *), void *arg, va_list *ap); -size_t mg_print_ip(void (*out)(char, void *), void *arg, va_list *ap); -size_t mg_print_ip_port(void (*out)(char, void *), void *arg, va_list *ap); -size_t mg_print_ip4(void (*out)(char, void *), void *arg, va_list *ap); -size_t mg_print_ip6(void (*out)(char, void *), void *arg, va_list *ap); -size_t mg_print_mac(void (*out)(char, void *), void *arg, va_list *ap); - -// Various output functions -void mg_pfn_iobuf(char ch, void *param); // param: struct mg_iobuf * -void mg_pfn_stdout(char c, void *param); // param: ignored - -// A helper macro for printing JSON: mg_snprintf(buf, len, "%m", MG_ESC("hi")) -#define MG_ESC(str) mg_print_esc, 0, (str) - - - - - - -enum { MG_LL_NONE, MG_LL_ERROR, MG_LL_INFO, MG_LL_DEBUG, MG_LL_VERBOSE }; -void mg_log(const char *fmt, ...); -bool mg_log_prefix(int ll, const char *file, int line, const char *fname); -void mg_log_set(int log_level); -void mg_hexdump(const void *buf, size_t len); -void mg_log_set_fn(mg_pfn_t fn, void *param); - -#if MG_ENABLE_LOG -#define MG_LOG(level, args) \ - do { \ - if (mg_log_prefix((level), __FILE__, __LINE__, __func__)) mg_log args; \ - } while (0) -#else -#define MG_LOG(level, args) \ - do { \ - if (0) mg_log args; \ - } while (0) -#endif - -#define MG_ERROR(args) MG_LOG(MG_LL_ERROR, args) -#define MG_INFO(args) MG_LOG(MG_LL_INFO, args) -#define MG_DEBUG(args) MG_LOG(MG_LL_DEBUG, args) -#define MG_VERBOSE(args) MG_LOG(MG_LL_VERBOSE, args) - - - - -struct mg_timer { - unsigned long id; // Timer ID - uint64_t period_ms; // Timer period in milliseconds - uint64_t expire; // Expiration timestamp in milliseconds - unsigned flags; // Possible flags values below -#define MG_TIMER_ONCE 0 // Call function once -#define MG_TIMER_REPEAT 1 // Call function periodically -#define MG_TIMER_RUN_NOW 2 // Call immediately when timer is set - void (*fn)(void *); // Function to call - void *arg; // Function argument - struct mg_timer *next; // Linkage -}; - -void mg_timer_init(struct mg_timer **head, struct mg_timer *timer, - uint64_t milliseconds, unsigned flags, void (*fn)(void *), - void *arg); -void mg_timer_free(struct mg_timer **head, struct mg_timer *); -void mg_timer_poll(struct mg_timer **head, uint64_t new_ms); -bool mg_timer_expired(uint64_t *expiration, uint64_t period, uint64_t now); - - - - - -enum { MG_FS_READ = 1, MG_FS_WRITE = 2, MG_FS_DIR = 4 }; - -// Filesystem API functions -// st() returns MG_FS_* flags and populates file size and modification time -// ls() calls fn() for every directory entry, allowing to list a directory -// -// NOTE: UNIX-style shorthand names for the API functions are deliberately -// chosen to avoid conflicts with some libraries that make macros for e.g. -// stat(), write(), read() calls. -struct mg_fs { - int (*st)(const char *path, size_t *size, time_t *mtime); // stat file - void (*ls)(const char *path, void (*fn)(const char *, void *), void *); - void *(*op)(const char *path, int flags); // Open file - void (*cl)(void *fd); // Close file - size_t (*rd)(void *fd, void *buf, size_t len); // Read file - size_t (*wr)(void *fd, const void *buf, size_t len); // Write file - size_t (*sk)(void *fd, size_t offset); // Set file position - bool (*mv)(const char *from, const char *to); // Rename file - bool (*rm)(const char *path); // Delete file - bool (*mkd)(const char *path); // Create directory -}; - -extern struct mg_fs mg_fs_posix; // POSIX open/close/read/write/seek -extern struct mg_fs mg_fs_packed; // Packed FS, see examples/device-dashboard -extern struct mg_fs mg_fs_fat; // FAT FS - -// File descriptor -struct mg_fd { - void *fd; - struct mg_fs *fs; -}; - -struct mg_fd *mg_fs_open(struct mg_fs *fs, const char *path, int flags); -void mg_fs_close(struct mg_fd *fd); -char *mg_file_read(struct mg_fs *fs, const char *path, size_t *size); -bool mg_file_write(struct mg_fs *fs, const char *path, const void *, size_t); -bool mg_file_printf(struct mg_fs *fs, const char *path, const char *fmt, ...); - -// Packed API -const char *mg_unpack(const char *path, size_t *size, time_t *mtime); -const char *mg_unlist(size_t no); // Get no'th packed filename -struct mg_str mg_unpacked(const char *path); // Packed file as mg_str - - - - - - - -#if MG_ENABLE_ASSERT -#include -#elif !defined(assert) -#define assert(x) -#endif - -void mg_bzero(volatile unsigned char *buf, size_t len); -void mg_random(void *buf, size_t len); -char *mg_random_str(char *buf, size_t len); -uint16_t mg_ntohs(uint16_t net); -uint32_t mg_ntohl(uint32_t net); -uint32_t mg_crc32(uint32_t crc, const char *buf, size_t len); -uint64_t mg_millis(void); // Return milliseconds since boot -uint64_t mg_now(void); // Return milliseconds since Epoch - -#define mg_htons(x) mg_ntohs(x) -#define mg_htonl(x) mg_ntohl(x) - -#define MG_U32(a, b, c, d) \ - (((uint32_t) ((a) &255) << 24) | ((uint32_t) ((b) &255) << 16) | \ - ((uint32_t) ((c) &255) << 8) | (uint32_t) ((d) &255)) - -// For printing IPv4 addresses: printf("%d.%d.%d.%d\n", MG_IPADDR_PARTS(&ip)) -#define MG_U8P(ADDR) ((uint8_t *) (ADDR)) -#define MG_IPADDR_PARTS(ADDR) \ - MG_U8P(ADDR)[0], MG_U8P(ADDR)[1], MG_U8P(ADDR)[2], MG_U8P(ADDR)[3] - -#define MG_REG(x) ((volatile uint32_t *) (x))[0] -#define MG_BIT(x) (((uint32_t) 1U) << (x)) -#define MG_SET_BITS(R, CLRMASK, SETMASK) (R) = ((R) & ~(CLRMASK)) | (SETMASK) - -#define MG_ROUND_UP(x, a) ((a) == 0 ? (x) : ((((x) + (a) -1) / (a)) * (a))) -#define MG_ROUND_DOWN(x, a) ((a) == 0 ? (x) : (((x) / (a)) * (a))) - -#ifdef __GNUC__ -#define MG_ARM_DISABLE_IRQ() asm volatile ("cpsid i" : : : "memory") -#define MG_ARM_ENABLE_IRQ() asm volatile ("cpsie i" : : : "memory") -#else -#define MG_ARM_DISABLE_IRQ() -#define MG_ARM_ENABLE_IRQ() -#endif - -struct mg_addr; -int mg_check_ip_acl(struct mg_str acl, struct mg_addr *remote_ip); - -// Linked list management macros -#define LIST_ADD_HEAD(type_, head_, elem_) \ - do { \ - (elem_)->next = (*head_); \ - *(head_) = (elem_); \ - } while (0) - -#define LIST_ADD_TAIL(type_, head_, elem_) \ - do { \ - type_ **h = head_; \ - while (*h != NULL) h = &(*h)->next; \ - *h = (elem_); \ - } while (0) - -#define LIST_DELETE(type_, head_, elem_) \ - do { \ - type_ **h = head_; \ - while (*h != (elem_)) h = &(*h)->next; \ - *h = (elem_)->next; \ - } while (0) - - - -unsigned short mg_url_port(const char *url); -int mg_url_is_ssl(const char *url); -struct mg_str mg_url_host(const char *url); -struct mg_str mg_url_user(const char *url); -struct mg_str mg_url_pass(const char *url); -const char *mg_url_uri(const char *url); - - - - -struct mg_iobuf { - unsigned char *buf; // Pointer to stored data - size_t size; // Total size available - size_t len; // Current number of bytes - size_t align; // Alignment during allocation -}; - -int mg_iobuf_init(struct mg_iobuf *, size_t, size_t); -int mg_iobuf_resize(struct mg_iobuf *, size_t); -void mg_iobuf_free(struct mg_iobuf *); -size_t mg_iobuf_add(struct mg_iobuf *, size_t, const void *, size_t); -size_t mg_iobuf_del(struct mg_iobuf *, size_t ofs, size_t len); - - -size_t mg_base64_update(unsigned char input_byte, char *buf, size_t len); -size_t mg_base64_final(char *buf, size_t len); -size_t mg_base64_encode(const unsigned char *p, size_t n, char *buf, size_t); -size_t mg_base64_decode(const char *src, size_t n, char *dst, size_t); - - - - -typedef struct { - uint32_t buf[4]; - uint32_t bits[2]; - unsigned char in[64]; -} mg_md5_ctx; - -void mg_md5_init(mg_md5_ctx *c); -void mg_md5_update(mg_md5_ctx *c, const unsigned char *data, size_t len); -void mg_md5_final(mg_md5_ctx *c, unsigned char[16]); - - - - -typedef struct { - uint32_t state[5]; - uint32_t count[2]; - unsigned char buffer[64]; -} mg_sha1_ctx; - -void mg_sha1_init(mg_sha1_ctx *); -void mg_sha1_update(mg_sha1_ctx *, const unsigned char *data, size_t len); -void mg_sha1_final(unsigned char digest[20], mg_sha1_ctx *); - - -struct mg_connection; -typedef void (*mg_event_handler_t)(struct mg_connection *, int ev, - void *ev_data, void *fn_data); -void mg_call(struct mg_connection *c, int ev, void *ev_data); -void mg_error(struct mg_connection *c, const char *fmt, ...); - -enum { - MG_EV_ERROR, // Error char *error_message - MG_EV_OPEN, // Connection created NULL - MG_EV_POLL, // mg_mgr_poll iteration uint64_t *uptime_millis - MG_EV_RESOLVE, // Host name is resolved NULL - MG_EV_CONNECT, // Connection established NULL - MG_EV_ACCEPT, // Connection accepted NULL - MG_EV_TLS_HS, // TLS handshake succeeded NULL - MG_EV_READ, // Data received from socket long *bytes_read - MG_EV_WRITE, // Data written to socket long *bytes_written - MG_EV_CLOSE, // Connection closed NULL - MG_EV_HTTP_MSG, // HTTP request/response struct mg_http_message * - MG_EV_WS_OPEN, // Websocket handshake done struct mg_http_message * - MG_EV_WS_MSG, // Websocket msg, text or bin struct mg_ws_message * - MG_EV_WS_CTL, // Websocket control msg struct mg_ws_message * - MG_EV_MQTT_CMD, // MQTT low-level command struct mg_mqtt_message * - MG_EV_MQTT_MSG, // MQTT PUBLISH received struct mg_mqtt_message * - MG_EV_MQTT_OPEN, // MQTT CONNACK received int *connack_status_code - MG_EV_SNTP_TIME, // SNTP time received uint64_t *epoch_millis - MG_EV_USER // Starting ID for user events -}; - - - - - - - - - -struct mg_dns { - const char *url; // DNS server URL - struct mg_connection *c; // DNS server connection -}; - -struct mg_addr { - uint8_t ip[16]; // Holds IPv4 or IPv6 address, in network byte order - uint16_t port; // TCP or UDP port in network byte order - uint8_t scope_id; // IPv6 scope ID - bool is_ip6; // True when address is IPv6 address -}; - -struct mg_mgr { - struct mg_connection *conns; // List of active connections - struct mg_dns dns4; // DNS for IPv4 - struct mg_dns dns6; // DNS for IPv6 - int dnstimeout; // DNS resolve timeout in milliseconds - bool use_dns6; // Use DNS6 server by default, see #1532 - unsigned long nextid; // Next connection ID - unsigned long timerid; // Next timer ID - void *userdata; // Arbitrary user data pointer - void *tls_ctx; // TLS context shared by all TLS sessions - uint16_t mqtt_id; // MQTT IDs for pub/sub - void *active_dns_requests; // DNS requests in progress - struct mg_timer *timers; // Active timers - int epoll_fd; // Used when MG_EPOLL_ENABLE=1 - void *priv; // Used by the MIP stack - size_t extraconnsize; // Used by the MIP stack -#if MG_ENABLE_FREERTOS_TCP - SocketSet_t ss; // NOTE(lsm): referenced from socket struct -#endif -}; - -struct mg_connection { - struct mg_connection *next; // Linkage in struct mg_mgr :: connections - struct mg_mgr *mgr; // Our container - struct mg_addr loc; // Local address - struct mg_addr rem; // Remote address - void *fd; // Connected socket, or LWIP data - unsigned long id; // Auto-incrementing unique connection ID - struct mg_iobuf recv; // Incoming data - struct mg_iobuf send; // Outgoing data - mg_event_handler_t fn; // User-specified event handler function - void *fn_data; // User-specified function parameter - mg_event_handler_t pfn; // Protocol-specific handler function - void *pfn_data; // Protocol-specific function parameter - char data[MG_DATA_SIZE]; // Arbitrary connection data - void *tls; // TLS specific data - unsigned is_listening : 1; // Listening connection - unsigned is_client : 1; // Outbound (client) connection - unsigned is_accepted : 1; // Accepted (server) connection - unsigned is_resolving : 1; // Non-blocking DNS resolution is in progress - unsigned is_arplooking : 1; // Non-blocking ARP resolution is in progress - unsigned is_connecting : 1; // Non-blocking connect is in progress - unsigned is_tls : 1; // TLS-enabled connection - unsigned is_tls_hs : 1; // TLS handshake is in progress - unsigned is_udp : 1; // UDP connection - unsigned is_websocket : 1; // WebSocket connection - unsigned is_mqtt5 : 1; // For MQTT connection, v5 indicator - unsigned is_hexdumping : 1; // Hexdump in/out traffic - unsigned is_draining : 1; // Send remaining data, then close and free - unsigned is_closing : 1; // Close and free the connection immediately - unsigned is_full : 1; // Stop reads, until cleared - unsigned is_resp : 1; // Response is still being generated - unsigned is_readable : 1; // Connection is ready to read - unsigned is_writable : 1; // Connection is ready to write -}; - -void mg_mgr_poll(struct mg_mgr *, int ms); -void mg_mgr_init(struct mg_mgr *); -void mg_mgr_free(struct mg_mgr *); - -struct mg_connection *mg_listen(struct mg_mgr *, const char *url, - mg_event_handler_t fn, void *fn_data); -struct mg_connection *mg_connect(struct mg_mgr *, const char *url, - mg_event_handler_t fn, void *fn_data); -struct mg_connection *mg_wrapfd(struct mg_mgr *mgr, int fd, - mg_event_handler_t fn, void *fn_data); -void mg_connect_resolved(struct mg_connection *); -bool mg_send(struct mg_connection *, const void *, size_t); -size_t mg_printf(struct mg_connection *, const char *fmt, ...); -size_t mg_vprintf(struct mg_connection *, const char *fmt, va_list *ap); -bool mg_aton(struct mg_str str, struct mg_addr *addr); - -// These functions are used to integrate with custom network stacks -struct mg_connection *mg_alloc_conn(struct mg_mgr *); -void mg_close_conn(struct mg_connection *c); -bool mg_open_listener(struct mg_connection *c, const char *url); - -// Utility functions -struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds, - unsigned flags, void (*fn)(void *), void *arg); - -// Low-level IO primives used by TLS layer -enum { MG_IO_ERR = -1, MG_IO_WAIT = -2, MG_IO_RESET = -3 }; -long mg_io_send(struct mg_connection *c, const void *buf, size_t len); -long mg_io_recv(struct mg_connection *c, void *buf, size_t len); - - - - - - - - -struct mg_http_header { - struct mg_str name; // Header name - struct mg_str value; // Header value -}; - -struct mg_http_message { - struct mg_str method, uri, query, proto; // Request/response line - struct mg_http_header headers[MG_MAX_HTTP_HEADERS]; // Headers - struct mg_str body; // Body - struct mg_str head; // Request + headers - struct mg_str message; // Request + headers + body -}; - -// Parameter for mg_http_serve_dir() -struct mg_http_serve_opts { - const char *root_dir; // Web root directory, must be non-NULL - const char *ssi_pattern; // SSI file name pattern, e.g. #.shtml - const char *extra_headers; // Extra HTTP headers to add in responses - const char *mime_types; // Extra mime types, ext1=type1,ext2=type2,.. - const char *page404; // Path to the 404 page, or NULL by default - struct mg_fs *fs; // Filesystem implementation. Use NULL for POSIX -}; - -// Parameter for mg_http_next_multipart -struct mg_http_part { - struct mg_str name; // Form field name - struct mg_str filename; // Filename for file uploads - struct mg_str body; // Part contents -}; - -int mg_http_parse(const char *s, size_t len, struct mg_http_message *); -int mg_http_get_request_len(const unsigned char *buf, size_t buf_len); -void mg_http_printf_chunk(struct mg_connection *cnn, const char *fmt, ...); -void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len); -void mg_http_delete_chunk(struct mg_connection *c, struct mg_http_message *hm); -struct mg_connection *mg_http_listen(struct mg_mgr *, const char *url, - mg_event_handler_t fn, void *fn_data); -struct mg_connection *mg_http_connect(struct mg_mgr *, const char *url, - mg_event_handler_t fn, void *fn_data); -void mg_http_serve_dir(struct mg_connection *, struct mg_http_message *hm, - const struct mg_http_serve_opts *); -void mg_http_serve_file(struct mg_connection *, struct mg_http_message *hm, - const char *path, const struct mg_http_serve_opts *); -void mg_http_reply(struct mg_connection *, int status_code, const char *headers, - const char *body_fmt, ...); -struct mg_str *mg_http_get_header(struct mg_http_message *, const char *name); -struct mg_str mg_http_var(struct mg_str buf, struct mg_str name); -int mg_http_get_var(const struct mg_str *, const char *name, char *, size_t); -int mg_url_decode(const char *s, size_t n, char *to, size_t to_len, int form); -size_t mg_url_encode(const char *s, size_t n, char *buf, size_t len); -void mg_http_creds(struct mg_http_message *, char *, size_t, char *, size_t); -bool mg_http_match_uri(const struct mg_http_message *, const char *glob); -long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm, - struct mg_fs *fs, const char *path, size_t max_size); -void mg_http_bauth(struct mg_connection *, const char *user, const char *pass); -struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v); -size_t mg_http_next_multipart(struct mg_str, size_t, struct mg_http_part *); -int mg_http_status(const struct mg_http_message *hm); -void mg_hello(const char *url); - - -void mg_http_serve_ssi(struct mg_connection *c, const char *root, - const char *fullpath); - - -#define MG_TLS_NONE 0 // No TLS support -#define MG_TLS_MBED 1 // mbedTLS -#define MG_TLS_OPENSSL 2 // OpenSSL -#define MG_TLS_BUILTIN 3 // Built-in -#define MG_TLS_CUSTOM 4 // Custom implementation - -#ifndef MG_TLS -#define MG_TLS MG_TLS_NONE -#endif - - - - - -struct mg_tls_opts { - struct mg_str ca; // PEM or DER - struct mg_str cert; // PEM or DER - struct mg_str key; // PEM or DER - struct mg_str name; // If not empty, enable host name verification -}; - -void mg_tls_init(struct mg_connection *, const struct mg_tls_opts *opts); -void mg_tls_free(struct mg_connection *); -long mg_tls_send(struct mg_connection *, const void *buf, size_t len); -long mg_tls_recv(struct mg_connection *, void *buf, size_t len); -size_t mg_tls_pending(struct mg_connection *); -void mg_tls_handshake(struct mg_connection *); - -// Private -void mg_tls_ctx_init(struct mg_mgr *); -void mg_tls_ctx_free(struct mg_mgr *); - - - - - - - -#if MG_TLS == MG_TLS_MBED -#include -#include -#include -#include - -struct mg_tls_ctx { - int dummy; -#ifdef MBEDTLS_SSL_SESSION_TICKETS - mbedtls_ssl_ticket_context tickets; -#endif -}; - -struct mg_tls { - mbedtls_x509_crt ca; // Parsed CA certificate - mbedtls_x509_crt cert; // Parsed certificate - mbedtls_pk_context pk; // Private key context - mbedtls_ssl_context ssl; // SSL/TLS context - mbedtls_ssl_config conf; // SSL-TLS config -#ifdef MBEDTLS_SSL_SESSION_TICKETS - mbedtls_ssl_ticket_context ticket; // Session tickets context -#endif -}; -#endif - - -#if MG_TLS == MG_TLS_OPENSSL - -#include -#include - -struct mg_tls { - SSL_CTX *ctx; - SSL *ssl; -}; -#endif - - -#define WEBSOCKET_OP_CONTINUE 0 -#define WEBSOCKET_OP_TEXT 1 -#define WEBSOCKET_OP_BINARY 2 -#define WEBSOCKET_OP_CLOSE 8 -#define WEBSOCKET_OP_PING 9 -#define WEBSOCKET_OP_PONG 10 - - - -struct mg_ws_message { - struct mg_str data; // Websocket message data - uint8_t flags; // Websocket message flags -}; - -struct mg_connection *mg_ws_connect(struct mg_mgr *, const char *url, - mg_event_handler_t fn, void *fn_data, - const char *fmt, ...); -void mg_ws_upgrade(struct mg_connection *, struct mg_http_message *, - const char *fmt, ...); -size_t mg_ws_send(struct mg_connection *, const void *buf, size_t len, int op); -size_t mg_ws_wrap(struct mg_connection *, size_t len, int op); -size_t mg_ws_printf(struct mg_connection *c, int op, const char *fmt, ...); -size_t mg_ws_vprintf(struct mg_connection *c, int op, const char *fmt, - va_list *); - - - - -struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, const char *url, - mg_event_handler_t fn, void *fn_data); -void mg_sntp_request(struct mg_connection *c); -int64_t mg_sntp_parse(const unsigned char *buf, size_t len); - - - - - -#define MQTT_CMD_CONNECT 1 -#define MQTT_CMD_CONNACK 2 -#define MQTT_CMD_PUBLISH 3 -#define MQTT_CMD_PUBACK 4 -#define MQTT_CMD_PUBREC 5 -#define MQTT_CMD_PUBREL 6 -#define MQTT_CMD_PUBCOMP 7 -#define MQTT_CMD_SUBSCRIBE 8 -#define MQTT_CMD_SUBACK 9 -#define MQTT_CMD_UNSUBSCRIBE 10 -#define MQTT_CMD_UNSUBACK 11 -#define MQTT_CMD_PINGREQ 12 -#define MQTT_CMD_PINGRESP 13 -#define MQTT_CMD_DISCONNECT 14 -#define MQTT_CMD_AUTH 15 - -#define MQTT_PROP_PAYLOAD_FORMAT_INDICATOR 0x01 -#define MQTT_PROP_MESSAGE_EXPIRY_INTERVAL 0x02 -#define MQTT_PROP_CONTENT_TYPE 0x03 -#define MQTT_PROP_RESPONSE_TOPIC 0x08 -#define MQTT_PROP_CORRELATION_DATA 0x09 -#define MQTT_PROP_SUBSCRIPTION_IDENTIFIER 0x0B -#define MQTT_PROP_SESSION_EXPIRY_INTERVAL 0x11 -#define MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER 0x12 -#define MQTT_PROP_SERVER_KEEP_ALIVE 0x13 -#define MQTT_PROP_AUTHENTICATION_METHOD 0x15 -#define MQTT_PROP_AUTHENTICATION_DATA 0x16 -#define MQTT_PROP_REQUEST_PROBLEM_INFORMATION 0x17 -#define MQTT_PROP_WILL_DELAY_INTERVAL 0x18 -#define MQTT_PROP_REQUEST_RESPONSE_INFORMATION 0x19 -#define MQTT_PROP_RESPONSE_INFORMATION 0x1A -#define MQTT_PROP_SERVER_REFERENCE 0x1C -#define MQTT_PROP_REASON_STRING 0x1F -#define MQTT_PROP_RECEIVE_MAXIMUM 0x21 -#define MQTT_PROP_TOPIC_ALIAS_MAXIMUM 0x22 -#define MQTT_PROP_TOPIC_ALIAS 0x23 -#define MQTT_PROP_MAXIMUM_QOS 0x24 -#define MQTT_PROP_RETAIN_AVAILABLE 0x25 -#define MQTT_PROP_USER_PROPERTY 0x26 -#define MQTT_PROP_MAXIMUM_PACKET_SIZE 0x27 -#define MQTT_PROP_WILDCARD_SUBSCRIPTION_AVAILABLE 0x28 -#define MQTT_PROP_SUBSCRIPTION_IDENTIFIER_AVAILABLE 0x29 -#define MQTT_PROP_SHARED_SUBSCRIPTION_AVAILABLE 0x2A - -enum { - MQTT_PROP_TYPE_BYTE, - MQTT_PROP_TYPE_STRING, - MQTT_PROP_TYPE_STRING_PAIR, - MQTT_PROP_TYPE_BINARY_DATA, - MQTT_PROP_TYPE_VARIABLE_INT, - MQTT_PROP_TYPE_INT, - MQTT_PROP_TYPE_SHORT -}; - -enum { MQTT_OK, MQTT_INCOMPLETE, MQTT_MALFORMED }; - -struct mg_mqtt_prop { - uint8_t id; // Enumerated at MQTT5 Reference - uint32_t iv; // Integer value for 8-, 16-, 32-bit integers types - struct mg_str key; // Non-NULL only for user property type - struct mg_str val; // Non-NULL only for UTF-8 types and user properties -}; - -struct mg_mqtt_opts { - struct mg_str user; // Username, can be empty - struct mg_str pass; // Password, can be empty - struct mg_str client_id; // Client ID - struct mg_str topic; // message/subscription topic - struct mg_str message; // message content - uint8_t qos; // message quality of service - uint8_t version; // Can be 4 (3.1.1), or 5. If 0, assume 4 - uint16_t keepalive; // Keep-alive timer in seconds - bool retain; // Retain flag - bool clean; // Clean session flag - struct mg_mqtt_prop *props; // MQTT5 props array - size_t num_props; // number of props - struct mg_mqtt_prop *will_props; // Valid only for CONNECT packet (MQTT5) - size_t num_will_props; // Number of will props -}; - -struct mg_mqtt_message { - struct mg_str topic; // Parsed topic for PUBLISH - struct mg_str data; // Parsed message for PUBLISH - struct mg_str dgram; // Whole MQTT packet, including headers - uint16_t id; // For PUBACK, PUBREC, PUBREL, PUBCOMP, SUBACK, PUBLISH - uint8_t cmd; // MQTT command, one of MQTT_CMD_* - uint8_t qos; // Quality of service - uint8_t ack; // CONNACK return code, 0 = success - size_t props_start; // Offset to the start of the properties (MQTT5) - size_t props_size; // Length of the properties -}; - -struct mg_connection *mg_mqtt_connect(struct mg_mgr *, const char *url, - const struct mg_mqtt_opts *opts, - mg_event_handler_t fn, void *fn_data); -struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url, - mg_event_handler_t fn, void *fn_data); -void mg_mqtt_login(struct mg_connection *c, const struct mg_mqtt_opts *opts); -void mg_mqtt_pub(struct mg_connection *c, const struct mg_mqtt_opts *opts); -void mg_mqtt_sub(struct mg_connection *, const struct mg_mqtt_opts *opts); -int mg_mqtt_parse(const uint8_t *, size_t, uint8_t, struct mg_mqtt_message *); -void mg_mqtt_send_header(struct mg_connection *, uint8_t cmd, uint8_t flags, - uint32_t len); -void mg_mqtt_ping(struct mg_connection *); -void mg_mqtt_pong(struct mg_connection *); -void mg_mqtt_disconnect(struct mg_connection *, const struct mg_mqtt_opts *); -size_t mg_mqtt_next_prop(struct mg_mqtt_message *, struct mg_mqtt_prop *, - size_t ofs); - - - - - -// Mongoose sends DNS queries that contain only one question: -// either A (IPv4) or AAAA (IPv6) address lookup. -// Therefore, we expect zero or one answer. -// If `resolved` is true, then `addr` contains resolved IPv4 or IPV6 address. -struct mg_dns_message { - uint16_t txnid; // Transaction ID - bool resolved; // Resolve successful, addr is set - struct mg_addr addr; // Resolved address - char name[256]; // Host name -}; - -struct mg_dns_header { - uint16_t txnid; // Transaction ID - uint16_t flags; - uint16_t num_questions; - uint16_t num_answers; - uint16_t num_authority_prs; - uint16_t num_other_prs; -}; - -// DNS resource record -struct mg_dns_rr { - uint16_t nlen; // Name or pointer length - uint16_t atype; // Address type - uint16_t aclass; // Address class - uint16_t alen; // Address length -}; - -void mg_resolve(struct mg_connection *, const char *url); -void mg_resolve_cancel(struct mg_connection *); -bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *); -size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs, - bool is_question, struct mg_dns_rr *); - - - - - -#ifndef MG_JSON_MAX_DEPTH -#define MG_JSON_MAX_DEPTH 30 -#endif - -// Error return values - negative. Successful returns are >= 0 -enum { MG_JSON_TOO_DEEP = -1, MG_JSON_INVALID = -2, MG_JSON_NOT_FOUND = -3 }; -int mg_json_get(struct mg_str json, const char *path, int *toklen); - -bool mg_json_get_num(struct mg_str json, const char *path, double *v); -bool mg_json_get_bool(struct mg_str json, const char *path, bool *v); -long mg_json_get_long(struct mg_str json, const char *path, long dflt); -char *mg_json_get_str(struct mg_str json, const char *path); -char *mg_json_get_hex(struct mg_str json, const char *path, int *len); -char *mg_json_get_b64(struct mg_str json, const char *path, int *len); - -bool mg_json_unescape(struct mg_str str, char *buf, size_t len); -size_t mg_json_next(struct mg_str obj, size_t ofs, struct mg_str *key, - struct mg_str *val); - - - - -// JSON-RPC request descriptor -struct mg_rpc_req { - struct mg_rpc **head; // RPC handlers list head - struct mg_rpc *rpc; // RPC handler being called - mg_pfn_t pfn; // Response printing function - void *pfn_data; // Response printing function data - void *req_data; // Arbitrary request data - struct mg_str frame; // Request, e.g. {"id":1,"method":"add","params":[1,2]} -}; - -// JSON-RPC method handler -struct mg_rpc { - struct mg_rpc *next; // Next in list - struct mg_str method; // Method pattern - void (*fn)(struct mg_rpc_req *); // Handler function - void *fn_data; // Handler function argument -}; - -void mg_rpc_add(struct mg_rpc **head, struct mg_str method_pattern, - void (*handler)(struct mg_rpc_req *), void *handler_data); -void mg_rpc_del(struct mg_rpc **head, void (*handler)(struct mg_rpc_req *)); -void mg_rpc_process(struct mg_rpc_req *); - -// Helper functions to print result or error frame -void mg_rpc_ok(struct mg_rpc_req *, const char *fmt, ...); -void mg_rpc_vok(struct mg_rpc_req *, const char *fmt, va_list *ap); -void mg_rpc_err(struct mg_rpc_req *, int code, const char *fmt, ...); -void mg_rpc_verr(struct mg_rpc_req *, int code, const char *fmt, va_list *); -void mg_rpc_list(struct mg_rpc_req *r); -// Copyright (c) 2023 Cesanta Software Limited -// All rights reserved - - - - - -#define MG_OTA_NONE 0 // No OTA support -#define MG_OTA_FLASH 1 // OTA via an internal flash -#define MG_OTA_CUSTOM 100 // Custom implementation - -#ifndef MG_OTA -#define MG_OTA MG_OTA_NONE -#endif - -// Firmware update API -bool mg_ota_begin(size_t new_firmware_size); // Start writing -bool mg_ota_write(const void *buf, size_t len); // Write chunk, aligned to 1k -bool mg_ota_end(void); // Stop writing - -enum { - MG_OTA_UNAVAILABLE = 0, // No OTA information is present - MG_OTA_FIRST_BOOT = 1, // Device booting the first time after the OTA - MG_OTA_UNCOMMITTED = 2, // Ditto, but marking us for the rollback - MG_OTA_COMMITTED = 3, // The firmware is good -}; -enum { MG_FIRMWARE_CURRENT = 0, MG_FIRMWARE_PREVIOUS = 1 }; - -int mg_ota_status(int firmware); // Return firmware status MG_OTA_* -uint32_t mg_ota_crc32(int firmware); // Return firmware checksum -uint32_t mg_ota_timestamp(int firmware); // Firmware timestamp, UNIX UTC epoch -size_t mg_ota_size(int firmware); // Firmware size - -bool mg_ota_commit(void); // Commit current firmware -bool mg_ota_rollback(void); // Rollback to the previous firmware -// Copyright (c) 2023 Cesanta Software Limited -// All rights reserved - - - - - -#define MG_DEVICE_NONE 0 // Dummy system -#define MG_DEVICE_STM32H5 1 // STM32 H5 -#define MG_DEVICE_STM32H7 2 // STM32 H7 -#define MG_DEVICE_CUSTOM 100 // Custom implementation - -#ifndef MG_DEVICE -#define MG_DEVICE MG_DEVICE_NONE -#endif - -// Flash information -void *mg_flash_start(void); // Return flash start address -size_t mg_flash_size(void); // Return flash size -size_t mg_flash_sector_size(void); // Return flash sector size -size_t mg_flash_write_align(void); // Return flash write align, minimum 4 -int mg_flash_bank(void); // 0: not dual bank, 1: bank1, 2: bank2 - -// Write, erase, swap bank -bool mg_flash_write(void *addr, const void *buf, size_t len); -bool mg_flash_erase(void *addr); // Must be at sector boundary -bool mg_flash_swap_bank(void); - -// Convenience functions to store data on a flash sector with wear levelling -// If `sector` is NULL, then the last sector of flash is used -bool mg_flash_load(void *sector, uint32_t key, void *buf, size_t len); -bool mg_flash_save(void *sector, uint32_t key, const void *buf, size_t len); - -void mg_device_reset(void); // Reboot device immediately - - - - - - -#if defined(MG_ENABLE_TCPIP) && MG_ENABLE_TCPIP -struct mg_tcpip_if; // Mongoose TCP/IP network interface - -struct mg_tcpip_driver { - bool (*init)(struct mg_tcpip_if *); // Init driver - size_t (*tx)(const void *, size_t, struct mg_tcpip_if *); // Transmit frame - size_t (*rx)(void *buf, size_t len, struct mg_tcpip_if *); // Receive frame - bool (*up)(struct mg_tcpip_if *); // Up/down status -}; - -// Network interface -struct mg_tcpip_if { - uint8_t mac[6]; // MAC address. Must be set to a valid MAC - uint32_t ip, mask, gw; // IP address, mask, default gateway - struct mg_str tx; // Output (TX) buffer - bool enable_dhcp_client; // Enable DCHP client - bool enable_dhcp_server; // Enable DCHP server - bool enable_crc32_check; // Do a CRC check on RX frames and strip it - bool enable_mac_check; // Do a MAC check on RX frames - struct mg_tcpip_driver *driver; // Low level driver - void *driver_data; // Driver-specific data - struct mg_mgr *mgr; // Mongoose event manager - struct mg_queue recv_queue; // Receive queue - uint16_t mtu; // Interface MTU -#define MG_TCPIP_MTU_DEFAULT 1500 - - // Internal state, user can use it but should not change it - uint8_t gwmac[6]; // Router's MAC - uint64_t now; // Current time - uint64_t timer_1000ms; // 1000 ms timer: for DHCP and link state - uint64_t lease_expire; // Lease expiration time, in ms - uint16_t eport; // Next ephemeral port - volatile uint32_t ndrop; // Number of received, but dropped frames - volatile uint32_t nrecv; // Number of received frames - volatile uint32_t nsent; // Number of transmitted frames - volatile uint32_t nerr; // Number of driver errors - uint8_t state; // Current state -#define MG_TCPIP_STATE_DOWN 0 // Interface is down -#define MG_TCPIP_STATE_UP 1 // Interface is up -#define MG_TCPIP_STATE_REQ 2 // Interface is up and has requested an IP -#define MG_TCPIP_STATE_READY 3 // Interface is up and has an IP assigned -}; - -void mg_tcpip_init(struct mg_mgr *, struct mg_tcpip_if *); -void mg_tcpip_free(struct mg_tcpip_if *); -void mg_tcpip_qwrite(void *buf, size_t len, struct mg_tcpip_if *ifp); - -extern struct mg_tcpip_driver mg_tcpip_driver_stm32; -extern struct mg_tcpip_driver mg_tcpip_driver_w5500; -extern struct mg_tcpip_driver mg_tcpip_driver_tm4c; -extern struct mg_tcpip_driver mg_tcpip_driver_stm32h; -extern struct mg_tcpip_driver mg_tcpip_driver_imxrt1020; -extern struct mg_tcpip_driver mg_tcpip_driver_same54; - -// Drivers that require SPI, can use this SPI abstraction -struct mg_tcpip_spi { - void *spi; // Opaque SPI bus descriptor - void (*begin)(void *); // SPI begin: slave select low - void (*end)(void *); // SPI end: slave select high - uint8_t (*txn)(void *, uint8_t); // SPI transaction: write 1 byte, read reply -}; -#endif - - -struct mg_tcpip_driver_imxrt1020_data { - // MDC clock divider. MDC clock is derived from IPS Bus clock (ipg_clk), - // must not exceed 2.5MHz. Configuration for clock range 2.36~2.50 MHz - // 37.5.1.8.2, Table 37-46 : f = ipg_clk / (2(mdc_cr + 1)) - // ipg_clk mdc_cr VALUE - // -------------------------- - // -1 <-- TODO() tell driver to guess the value - // 25 MHz 4 - // 33 MHz 6 - // 40 MHz 7 - // 50 MHz 9 - // 66 MHz 13 - int mdc_cr; // Valid values: -1 to 63 -}; - - -#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && MG_ENABLE_DRIVER_SAME54 - -struct mg_tcpip_driver_same54_data { - int mdc_cr; -}; - -#endif - - -struct mg_tcpip_driver_stm32_data { - // MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz - // HCLK range DIVIDER mdc_cr VALUE - // ------------------------------------- - // -1 <-- tell driver to guess the value - // 60-100 MHz HCLK/42 0 - // 100-150 MHz HCLK/62 1 - // 20-35 MHz HCLK/16 2 - // 35-60 MHz HCLK/26 3 - // 150-216 MHz HCLK/102 4 <-- value for Nucleo-F* on max speed - // 216-310 MHz HCLK/124 5 - // 110, 111 Reserved - int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5 -}; - - -struct mg_tcpip_driver_stm32h_data { - // MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz - // HCLK range DIVIDER mdc_cr VALUE - // ------------------------------------- - // -1 <-- tell driver to guess the value - // 60-100 MHz HCLK/42 0 - // 100-150 MHz HCLK/62 1 - // 20-35 MHz HCLK/16 2 - // 35-60 MHz HCLK/26 3 - // 150-250 MHz HCLK/102 4 <-- value for Nucleo-H* on max speed driven by HSI - // 250-300 MHz HCLK/124 5 <-- value for Nucleo-H* on max speed driven by CSI - // 110, 111 Reserved - int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5 -}; - - -struct mg_tcpip_driver_tm4c_data { - // MDC clock divider. MDC clock is derived from SYSCLK, must not exceed 2.5MHz - // SYSCLK range DIVIDER mdc_cr VALUE - // ------------------------------------- - // -1 <-- tell driver to guess the value - // 60-100 MHz SYSCLK/42 0 - // 100-150 MHz SYSCLK/62 1 <-- value for EK-TM4C129* on max speed - // 20-35 MHz SYSCLK/16 2 - // 35-60 MHz SYSCLK/26 3 - // 0x4-0xF Reserved - int mdc_cr; // Valid values: -1, 0, 1, 2, 3 -}; - -#ifdef __cplusplus -} -#endif -#endif // MONGOOSE_H + + +#if MG_ARCH == MG_ARCH_ARMCC || MG_ARCH == MG_ARCH_CMSIS_RTOS1 || \ + MG_ARCH == MG_ARCH_CMSIS_RTOS2 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if MG_ARCH == MG_ARCH_CMSIS_RTOS1 +#include "cmsis_os.h" // keep this include +// https://developer.arm.com/documentation/ka003821/latest +extern uint32_t rt_time_get(void); +#elif MG_ARCH == MG_ARCH_CMSIS_RTOS2 +#include "cmsis_os2.h" // keep this include +#endif + +#define strdup(s) ((char *) mg_strdup(mg_str(s)).ptr) + +#if defined(__ARMCC_VERSION) +#define mode_t size_t +#define mkdir(a, b) mg_mkdir(a, b) +static inline int mg_mkdir(const char *path, mode_t mode) { + (void) path, (void) mode; + return -1; +} +#endif + +#if (MG_ARCH == MG_ARCH_CMSIS_RTOS1 || MG_ARCH == MG_ARCH_CMSIS_RTOS2) && \ + !defined MG_ENABLE_RL && (!defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP) && \ + (!defined(MG_ENABLE_TCPIP) || !MG_ENABLE_TCPIP) +#define MG_ENABLE_RL 1 +#endif + +#endif + + +#if MG_ARCH == MG_ARCH_TIRTOS + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#endif + + +#if MG_ARCH == MG_ARCH_UNIX + +#define _DARWIN_UNLIMITED_SELECT 1 // No limit on file descriptors + +#if defined(__APPLE__) +#include +#endif + +#if !defined(MG_ENABLE_EPOLL) && defined(__linux__) +#define MG_ENABLE_EPOLL 1 +#elif !defined(MG_ENABLE_POLL) +#define MG_ENABLE_POLL 1 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(MG_ENABLE_EPOLL) && MG_ENABLE_EPOLL +#include +#elif defined(MG_ENABLE_POLL) && MG_ENABLE_POLL +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include + +#ifndef MG_ENABLE_DIRLIST +#define MG_ENABLE_DIRLIST 1 +#endif + +#ifndef MG_PATH_MAX +#define MG_PATH_MAX FILENAME_MAX +#endif + +#endif + + +#if MG_ARCH == MG_ARCH_WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS +#define _WINSOCK_DEPRECATED_NO_WARNINGS +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1700 +#define __func__ "" +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +typedef unsigned char uint8_t; +typedef char int8_t; +typedef unsigned short uint16_t; +typedef short int16_t; +typedef unsigned int uint32_t; +typedef int int32_t; +typedef enum { false = 0, true = 1 } bool; +#else +#include +#include +#include +#endif + +#include +#include +#include + +// Protect from calls like std::snprintf in app code +// See https://github.com/cesanta/mongoose/issues/1047 +#ifndef __cplusplus +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#ifndef strdup // For MSVC with _DEBUG, see #1359 +#define strdup(x) _strdup(x) +#endif +#endif + +#define MG_INVALID_SOCKET INVALID_SOCKET +#define MG_SOCKET_TYPE SOCKET +typedef unsigned long nfds_t; +#if defined(_MSC_VER) +#pragma comment(lib, "ws2_32.lib") +#ifndef alloca +#define alloca(a) _alloca(a) +#endif +#endif +#define poll(a, b, c) WSAPoll((a), (b), (c)) +#define closesocket(x) closesocket(x) + +typedef int socklen_t; +#define MG_DIRSEP '\\' + +#ifndef MG_PATH_MAX +#define MG_PATH_MAX FILENAME_MAX +#endif + +#ifndef SO_EXCLUSIVEADDRUSE +#define SO_EXCLUSIVEADDRUSE ((int) (~SO_REUSEADDR)) +#endif + +#define MG_SOCK_ERR(errcode) ((errcode) < 0 ? WSAGetLastError() : 0) + +#define MG_SOCK_PENDING(errcode) \ + (((errcode) < 0) && \ + (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEINPROGRESS || \ + WSAGetLastError() == WSAEWOULDBLOCK)) + +#define MG_SOCK_RESET(errcode) \ + (((errcode) < 0) && (WSAGetLastError() == WSAECONNRESET)) + +#define realpath(a, b) _fullpath((b), (a), MG_PATH_MAX) +#define sleep(x) Sleep((x) *1000) +#define mkdir(a, b) _mkdir(a) + +#ifndef S_ISDIR +#define S_ISDIR(x) (((x) &_S_IFMT) == _S_IFDIR) +#endif + +#ifndef MG_ENABLE_DIRLIST +#define MG_ENABLE_DIRLIST 1 +#endif + +#ifndef SIGPIPE +#define SIGPIPE 0 +#endif + +#endif + + +#if MG_ARCH == MG_ARCH_ZEPHYR + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MG_PUTCHAR(x) printk("%c", x) +#ifndef strdup +#define strdup(s) ((char *) mg_strdup(mg_str(s)).ptr) +#endif +#define strerror(x) zsock_gai_strerror(x) +#define FD_CLOEXEC 0 +#define F_SETFD 0 +#define MG_ENABLE_SSI 0 + +int rand(void); +int sscanf(const char *, const char *, ...); + +#endif + + +#if defined(MG_ENABLE_FREERTOS_TCP) && MG_ENABLE_FREERTOS_TCP + +#include +#include + +#include +#include +#include // contents to be moved and file removed, some day + +#define MG_SOCKET_TYPE Socket_t +#define MG_INVALID_SOCKET FREERTOS_INVALID_SOCKET + +// Why FreeRTOS-TCP did not implement a clean BSD API, but its own thing +// with FreeRTOS_ prefix, is beyond me +#define IPPROTO_TCP FREERTOS_IPPROTO_TCP +#define IPPROTO_UDP FREERTOS_IPPROTO_UDP +#define AF_INET FREERTOS_AF_INET +#define SOCK_STREAM FREERTOS_SOCK_STREAM +#define SOCK_DGRAM FREERTOS_SOCK_DGRAM +#define SO_BROADCAST 0 +#define SO_ERROR 0 +#define SOL_SOCKET 0 +#define SO_REUSEADDR 0 + +#define MG_SOCK_ERR(errcode) ((errcode) < 0 ? (errcode) : 0) + +#define MG_SOCK_PENDING(errcode) \ + ((errcode) == -pdFREERTOS_ERRNO_EWOULDBLOCK || \ + (errcode) == -pdFREERTOS_ERRNO_EISCONN || \ + (errcode) == -pdFREERTOS_ERRNO_EINPROGRESS || \ + (errcode) == -pdFREERTOS_ERRNO_EAGAIN) + +#define MG_SOCK_RESET(errcode) ((errcode) == -pdFREERTOS_ERRNO_ENOTCONN) + +// actually only if optional timeout is enabled +#define MG_SOCK_INTR(fd) (fd == NULL) + +#define sockaddr_in freertos_sockaddr +#define sockaddr freertos_sockaddr +#define accept(a, b, c) FreeRTOS_accept((a), (b), (c)) +#define connect(a, b, c) FreeRTOS_connect((a), (b), (c)) +#define bind(a, b, c) FreeRTOS_bind((a), (b), (c)) +#define listen(a, b) FreeRTOS_listen((a), (b)) +#define socket(a, b, c) FreeRTOS_socket((a), (b), (c)) +#define send(a, b, c, d) FreeRTOS_send((a), (b), (c), (d)) +#define recv(a, b, c, d) FreeRTOS_recv((a), (b), (c), (d)) +#define setsockopt(a, b, c, d, e) FreeRTOS_setsockopt((a), (b), (c), (d), (e)) +#define sendto(a, b, c, d, e, f) FreeRTOS_sendto((a), (b), (c), (d), (e), (f)) +#define recvfrom(a, b, c, d, e, f) \ + FreeRTOS_recvfrom((a), (b), (c), (d), (e), (f)) +#define closesocket(x) FreeRTOS_closesocket(x) +#define gethostbyname(x) FreeRTOS_gethostbyname(x) +#define getsockname(a, b, c) mg_getsockname((a), (b), (c)) +#define getpeername(a, b, c) mg_getpeername((a), (b), (c)) + +static inline int mg_getsockname(MG_SOCKET_TYPE fd, void *buf, socklen_t *len) { + (void) fd, (void) buf, (void) len; + return -1; +} + +static inline int mg_getpeername(MG_SOCKET_TYPE fd, void *buf, socklen_t *len) { + (void) fd, (void) buf, (void) len; + return 0; +} +#endif + + +#if defined(MG_ENABLE_LWIP) && MG_ENABLE_LWIP + +#if defined(__GNUC__) && !defined(__ARMCC_VERSION) +#include +#endif + +struct timeval; + +#include + +#if !LWIP_TIMEVAL_PRIVATE +#if defined(__GNUC__) && !defined(__ARMCC_VERSION) // armclang sets both +#include +#else +struct timeval { + time_t tv_sec; + long tv_usec; +}; +#endif +#endif + +#if LWIP_SOCKET != 1 +// Sockets support disabled in LWIP by default +#error Set LWIP_SOCKET variable to 1 (in lwipopts.h) +#endif +#endif + + +#if defined(MG_ENABLE_RL) && MG_ENABLE_RL +#include + +#define closesocket(x) closesocket(x) + +#define TCP_NODELAY SO_KEEPALIVE + +#define MG_SOCK_ERR(errcode) ((errcode) < 0 ? (errcode) : 0) + +#define MG_SOCK_PENDING(errcode) \ + ((errcode) == BSD_EWOULDBLOCK || (errcode) == BSD_EALREADY || \ + (errcode) == BSD_EINPROGRESS) + +#define MG_SOCK_RESET(errcode) \ + ((errcode) == BSD_ECONNABORTED || (errcode) == BSD_ECONNRESET) + +// In blocking mode, which is enabled by default, accept() waits for a +// connection request. In non blocking mode, you must call accept() +// again if the error code BSD_EWOULDBLOCK is returned. +#define MG_SOCK_INTR(fd) (fd == BSD_EWOULDBLOCK) + +#define socklen_t int +#endif + + +#ifndef MG_ENABLE_LOG +#define MG_ENABLE_LOG 1 +#endif + +#ifndef MG_ENABLE_CUSTOM_LOG +#define MG_ENABLE_CUSTOM_LOG 0 // Let user define their own MG_LOG +#endif + +#ifndef MG_ENABLE_TCPIP +#define MG_ENABLE_TCPIP 0 // Mongoose built-in network stack +#endif + +#ifndef MG_ENABLE_LWIP +#define MG_ENABLE_LWIP 0 // lWIP network stack +#endif + +#ifndef MG_ENABLE_FREERTOS_TCP +#define MG_ENABLE_FREERTOS_TCP 0 // Amazon FreeRTOS-TCP network stack +#endif + +#ifndef MG_ENABLE_RL +#define MG_ENABLE_RL 0 // ARM MDK network stack +#endif + +#ifndef MG_ENABLE_SOCKET +#define MG_ENABLE_SOCKET !MG_ENABLE_TCPIP +#endif + +#ifndef MG_ENABLE_POLL +#define MG_ENABLE_POLL 0 +#endif + +#ifndef MG_ENABLE_EPOLL +#define MG_ENABLE_EPOLL 0 +#endif + +#ifndef MG_ENABLE_FATFS +#define MG_ENABLE_FATFS 0 +#endif + +#ifndef MG_ENABLE_SSI +#define MG_ENABLE_SSI 0 +#endif + +#ifndef MG_ENABLE_IPV6 +#define MG_ENABLE_IPV6 0 +#endif + +#ifndef MG_IPV6_V6ONLY +#define MG_IPV6_V6ONLY 0 // IPv6 socket binds only to V6, not V4 address +#endif + +#ifndef MG_ENABLE_MD5 +#define MG_ENABLE_MD5 1 +#endif + +// Set MG_ENABLE_WINSOCK=0 for Win32 builds with external IP stack (like LWIP) +#ifndef MG_ENABLE_WINSOCK +#define MG_ENABLE_WINSOCK 1 +#endif + +#ifndef MG_ENABLE_DIRLIST +#define MG_ENABLE_DIRLIST 0 +#endif + +#ifndef MG_ENABLE_CUSTOM_RANDOM +#define MG_ENABLE_CUSTOM_RANDOM 0 +#endif + +#ifndef MG_ENABLE_CUSTOM_MILLIS +#define MG_ENABLE_CUSTOM_MILLIS 0 +#endif + +#ifndef MG_ENABLE_PACKED_FS +#define MG_ENABLE_PACKED_FS 0 +#endif + +#ifndef MG_ENABLE_ASSERT +#define MG_ENABLE_ASSERT 0 +#endif + +#ifndef MG_IO_SIZE +#define MG_IO_SIZE 2048 // Granularity of the send/recv IO buffer growth +#endif + +#ifndef MG_MAX_RECV_SIZE +#define MG_MAX_RECV_SIZE (3UL * 1024UL * 1024UL) // Maximum recv IO buffer size +#endif + +#ifndef MG_DATA_SIZE +#define MG_DATA_SIZE 32 // struct mg_connection :: data size +#endif + +#ifndef MG_MAX_HTTP_HEADERS +#define MG_MAX_HTTP_HEADERS 30 +#endif + +#ifndef MG_HTTP_INDEX +#define MG_HTTP_INDEX "index.html" +#endif + +#ifndef MG_PATH_MAX +#ifdef PATH_MAX +#define MG_PATH_MAX PATH_MAX +#else +#define MG_PATH_MAX 128 +#endif +#endif + +#ifndef MG_SOCK_LISTEN_BACKLOG_SIZE +#define MG_SOCK_LISTEN_BACKLOG_SIZE 3 +#endif + +#ifndef MG_DIRSEP +#define MG_DIRSEP '/' +#endif + +#ifndef MG_ENABLE_FILE +#if defined(FOPEN_MAX) +#define MG_ENABLE_FILE 1 +#else +#define MG_ENABLE_FILE 0 +#endif +#endif + +#ifndef MG_INVALID_SOCKET +#define MG_INVALID_SOCKET (-1) +#endif + +#ifndef MG_SOCKET_TYPE +#define MG_SOCKET_TYPE int +#endif + +#ifndef MG_SOCKET_ERRNO +#define MG_SOCKET_ERRNO errno +#endif + +#if MG_ENABLE_EPOLL +#define MG_EPOLL_ADD(c) \ + do { \ + struct epoll_event ev = {EPOLLIN | EPOLLERR | EPOLLHUP, {c}}; \ + epoll_ctl(c->mgr->epoll_fd, EPOLL_CTL_ADD, (int) (size_t) c->fd, &ev); \ + } while (0) +#define MG_EPOLL_MOD(c, wr) \ + do { \ + struct epoll_event ev = {EPOLLIN | EPOLLERR | EPOLLHUP, {c}}; \ + if (wr) ev.events |= EPOLLOUT; \ + epoll_ctl(c->mgr->epoll_fd, EPOLL_CTL_MOD, (int) (size_t) c->fd, &ev); \ + } while (0) +#else +#define MG_EPOLL_ADD(c) +#define MG_EPOLL_MOD(c, wr) +#endif + + + + +struct mg_str { + const char *ptr; // Pointer to string data + size_t len; // String len +}; + +#define MG_NULL_STR \ + { NULL, 0 } + +#define MG_C_STR(a) \ + { (a), sizeof(a) - 1 } + +// Using macro to avoid shadowing C++ struct constructor, see #1298 +#define mg_str(s) mg_str_s(s) + +struct mg_str mg_str(const char *s); +struct mg_str mg_str_n(const char *s, size_t n); +int mg_lower(const char *s); +int mg_ncasecmp(const char *s1, const char *s2, size_t len); +int mg_casecmp(const char *s1, const char *s2); +int mg_vcmp(const struct mg_str *s1, const char *s2); +int mg_vcasecmp(const struct mg_str *str1, const char *str2); +int mg_strcmp(const struct mg_str str1, const struct mg_str str2); +struct mg_str mg_strstrip(struct mg_str s); +struct mg_str mg_strdup(const struct mg_str s); +const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle); +bool mg_match(struct mg_str str, struct mg_str pattern, struct mg_str *caps); +bool mg_globmatch(const char *pattern, size_t plen, const char *s, size_t n); +bool mg_commalist(struct mg_str *s, struct mg_str *k, struct mg_str *v); +bool mg_split(struct mg_str *s, struct mg_str *k, struct mg_str *v, char delim); +char *mg_hex(const void *buf, size_t len, char *dst); +void mg_unhex(const char *buf, size_t len, unsigned char *to); +unsigned long mg_unhexn(const char *s, size_t len); +bool mg_path_is_sane(const char *path); + + + + +// Single producer, single consumer non-blocking queue + +struct mg_queue { + char *buf; + size_t size; + volatile size_t tail; + volatile size_t head; +}; + +void mg_queue_init(struct mg_queue *, char *, size_t); // Init queue +size_t mg_queue_book(struct mg_queue *, char **buf, size_t); // Reserve space +void mg_queue_add(struct mg_queue *, size_t); // Add new message +size_t mg_queue_next(struct mg_queue *, char **); // Get oldest message +void mg_queue_del(struct mg_queue *, size_t); // Delete oldest message + + + + +typedef void (*mg_pfn_t)(char, void *); // Output function +typedef size_t (*mg_pm_t)(mg_pfn_t, void *, va_list *); // %M printer + +size_t mg_vxprintf(void (*)(char, void *), void *, const char *fmt, va_list *); +size_t mg_xprintf(void (*fn)(char, void *), void *, const char *fmt, ...); + + + + + + +// Convenience wrappers around mg_xprintf +size_t mg_vsnprintf(char *buf, size_t len, const char *fmt, va_list *ap); +size_t mg_snprintf(char *, size_t, const char *fmt, ...); +char *mg_vmprintf(const char *fmt, va_list *ap); +char *mg_mprintf(const char *fmt, ...); +size_t mg_queue_vprintf(struct mg_queue *, const char *fmt, va_list *); +size_t mg_queue_printf(struct mg_queue *, const char *fmt, ...); + +// %M print helper functions +size_t mg_print_base64(void (*out)(char, void *), void *arg, va_list *ap); +size_t mg_print_esc(void (*out)(char, void *), void *arg, va_list *ap); +size_t mg_print_hex(void (*out)(char, void *), void *arg, va_list *ap); +size_t mg_print_ip(void (*out)(char, void *), void *arg, va_list *ap); +size_t mg_print_ip_port(void (*out)(char, void *), void *arg, va_list *ap); +size_t mg_print_ip4(void (*out)(char, void *), void *arg, va_list *ap); +size_t mg_print_ip6(void (*out)(char, void *), void *arg, va_list *ap); +size_t mg_print_mac(void (*out)(char, void *), void *arg, va_list *ap); + +// Various output functions +void mg_pfn_iobuf(char ch, void *param); // param: struct mg_iobuf * +void mg_pfn_stdout(char c, void *param); // param: ignored + +// A helper macro for printing JSON: mg_snprintf(buf, len, "%m", MG_ESC("hi")) +#define MG_ESC(str) mg_print_esc, 0, (str) + + + + + + +enum { MG_LL_NONE, MG_LL_ERROR, MG_LL_INFO, MG_LL_DEBUG, MG_LL_VERBOSE }; +void mg_log(const char *fmt, ...); +bool mg_log_prefix(int ll, const char *file, int line, const char *fname); +void mg_log_set(int log_level); +void mg_hexdump(const void *buf, size_t len); +void mg_log_set_fn(mg_pfn_t fn, void *param); + +#if MG_ENABLE_LOG +#define MG_LOG(level, args) \ + do { \ + if (mg_log_prefix((level), __FILE__, __LINE__, __func__)) mg_log args; \ + } while (0) +#else +#define MG_LOG(level, args) \ + do { \ + if (0) mg_log args; \ + } while (0) +#endif + +#define MG_ERROR(args) MG_LOG(MG_LL_ERROR, args) +#define MG_INFO(args) MG_LOG(MG_LL_INFO, args) +#define MG_DEBUG(args) MG_LOG(MG_LL_DEBUG, args) +#define MG_VERBOSE(args) MG_LOG(MG_LL_VERBOSE, args) + + + + +struct mg_timer { + unsigned long id; // Timer ID + uint64_t period_ms; // Timer period in milliseconds + uint64_t expire; // Expiration timestamp in milliseconds + unsigned flags; // Possible flags values below +#define MG_TIMER_ONCE 0 // Call function once +#define MG_TIMER_REPEAT 1 // Call function periodically +#define MG_TIMER_RUN_NOW 2 // Call immediately when timer is set + void (*fn)(void *); // Function to call + void *arg; // Function argument + struct mg_timer *next; // Linkage +}; + +void mg_timer_init(struct mg_timer **head, struct mg_timer *timer, + uint64_t milliseconds, unsigned flags, void (*fn)(void *), + void *arg); +void mg_timer_free(struct mg_timer **head, struct mg_timer *); +void mg_timer_poll(struct mg_timer **head, uint64_t new_ms); +bool mg_timer_expired(uint64_t *expiration, uint64_t period, uint64_t now); + + + + + +enum { MG_FS_READ = 1, MG_FS_WRITE = 2, MG_FS_DIR = 4 }; + +// Filesystem API functions +// st() returns MG_FS_* flags and populates file size and modification time +// ls() calls fn() for every directory entry, allowing to list a directory +// +// NOTE: UNIX-style shorthand names for the API functions are deliberately +// chosen to avoid conflicts with some libraries that make macros for e.g. +// stat(), write(), read() calls. +struct mg_fs { + int (*st)(const char *path, size_t *size, time_t *mtime); // stat file + void (*ls)(const char *path, void (*fn)(const char *, void *), void *); + void *(*op)(const char *path, int flags); // Open file + void (*cl)(void *fd); // Close file + size_t (*rd)(void *fd, void *buf, size_t len); // Read file + size_t (*wr)(void *fd, const void *buf, size_t len); // Write file + size_t (*sk)(void *fd, size_t offset); // Set file position + bool (*mv)(const char *from, const char *to); // Rename file + bool (*rm)(const char *path); // Delete file + bool (*mkd)(const char *path); // Create directory +}; + +extern struct mg_fs mg_fs_posix; // POSIX open/close/read/write/seek +extern struct mg_fs mg_fs_packed; // Packed FS, see examples/device-dashboard +extern struct mg_fs mg_fs_fat; // FAT FS + +// File descriptor +struct mg_fd { + void *fd; + struct mg_fs *fs; +}; + +struct mg_fd *mg_fs_open(struct mg_fs *fs, const char *path, int flags); +void mg_fs_close(struct mg_fd *fd); +char *mg_file_read(struct mg_fs *fs, const char *path, size_t *size); +bool mg_file_write(struct mg_fs *fs, const char *path, const void *, size_t); +bool mg_file_printf(struct mg_fs *fs, const char *path, const char *fmt, ...); + +// Packed API +const char *mg_unpack(const char *path, size_t *size, time_t *mtime); +const char *mg_unlist(size_t no); // Get no'th packed filename +struct mg_str mg_unpacked(const char *path); // Packed file as mg_str + + + + + + + +#if MG_ENABLE_ASSERT +#include +#elif !defined(assert) +#define assert(x) +#endif + +void mg_bzero(volatile unsigned char *buf, size_t len); +void mg_random(void *buf, size_t len); +char *mg_random_str(char *buf, size_t len); +uint16_t mg_ntohs(uint16_t net); +uint32_t mg_ntohl(uint32_t net); +uint32_t mg_crc32(uint32_t crc, const char *buf, size_t len); +uint64_t mg_millis(void); // Return milliseconds since boot +uint64_t mg_now(void); // Return milliseconds since Epoch + +#define mg_htons(x) mg_ntohs(x) +#define mg_htonl(x) mg_ntohl(x) + +#define MG_U32(a, b, c, d) \ + (((uint32_t) ((a) &255) << 24) | ((uint32_t) ((b) &255) << 16) | \ + ((uint32_t) ((c) &255) << 8) | (uint32_t) ((d) &255)) + +// For printing IPv4 addresses: printf("%d.%d.%d.%d\n", MG_IPADDR_PARTS(&ip)) +#define MG_U8P(ADDR) ((uint8_t *) (ADDR)) +#define MG_IPADDR_PARTS(ADDR) \ + MG_U8P(ADDR)[0], MG_U8P(ADDR)[1], MG_U8P(ADDR)[2], MG_U8P(ADDR)[3] + +#define MG_REG(x) ((volatile uint32_t *) (x))[0] +#define MG_BIT(x) (((uint32_t) 1U) << (x)) +#define MG_SET_BITS(R, CLRMASK, SETMASK) (R) = ((R) & ~(CLRMASK)) | (SETMASK) + +#define MG_ROUND_UP(x, a) ((a) == 0 ? (x) : ((((x) + (a) -1) / (a)) * (a))) +#define MG_ROUND_DOWN(x, a) ((a) == 0 ? (x) : (((x) / (a)) * (a))) + +#ifdef __GNUC__ +#define MG_ARM_DISABLE_IRQ() asm volatile ("cpsid i" : : : "memory") +#define MG_ARM_ENABLE_IRQ() asm volatile ("cpsie i" : : : "memory") +#else +#define MG_ARM_DISABLE_IRQ() +#define MG_ARM_ENABLE_IRQ() +#endif + +struct mg_addr; +int mg_check_ip_acl(struct mg_str acl, struct mg_addr *remote_ip); + +// Linked list management macros +#define LIST_ADD_HEAD(type_, head_, elem_) \ + do { \ + (elem_)->next = (*head_); \ + *(head_) = (elem_); \ + } while (0) + +#define LIST_ADD_TAIL(type_, head_, elem_) \ + do { \ + type_ **h = head_; \ + while (*h != NULL) h = &(*h)->next; \ + *h = (elem_); \ + } while (0) + +#define LIST_DELETE(type_, head_, elem_) \ + do { \ + type_ **h = head_; \ + while (*h != (elem_)) h = &(*h)->next; \ + *h = (elem_)->next; \ + } while (0) + + + +unsigned short mg_url_port(const char *url); +int mg_url_is_ssl(const char *url); +struct mg_str mg_url_host(const char *url); +struct mg_str mg_url_user(const char *url); +struct mg_str mg_url_pass(const char *url); +const char *mg_url_uri(const char *url); + + + + +struct mg_iobuf { + unsigned char *buf; // Pointer to stored data + size_t size; // Total size available + size_t len; // Current number of bytes + size_t align; // Alignment during allocation +}; + +int mg_iobuf_init(struct mg_iobuf *, size_t, size_t); +int mg_iobuf_resize(struct mg_iobuf *, size_t); +void mg_iobuf_free(struct mg_iobuf *); +size_t mg_iobuf_add(struct mg_iobuf *, size_t, const void *, size_t); +size_t mg_iobuf_del(struct mg_iobuf *, size_t ofs, size_t len); + + +size_t mg_base64_update(unsigned char input_byte, char *buf, size_t len); +size_t mg_base64_final(char *buf, size_t len); +size_t mg_base64_encode(const unsigned char *p, size_t n, char *buf, size_t); +size_t mg_base64_decode(const char *src, size_t n, char *dst, size_t); + + + + +typedef struct { + uint32_t buf[4]; + uint32_t bits[2]; + unsigned char in[64]; +} mg_md5_ctx; + +void mg_md5_init(mg_md5_ctx *c); +void mg_md5_update(mg_md5_ctx *c, const unsigned char *data, size_t len); +void mg_md5_final(mg_md5_ctx *c, unsigned char[16]); + + + + +typedef struct { + uint32_t state[5]; + uint32_t count[2]; + unsigned char buffer[64]; +} mg_sha1_ctx; + +void mg_sha1_init(mg_sha1_ctx *); +void mg_sha1_update(mg_sha1_ctx *, const unsigned char *data, size_t len); +void mg_sha1_final(unsigned char digest[20], mg_sha1_ctx *); + + +struct mg_connection; +typedef void (*mg_event_handler_t)(struct mg_connection *, int ev, + void *ev_data, void *fn_data); +void mg_call(struct mg_connection *c, int ev, void *ev_data); +void mg_error(struct mg_connection *c, const char *fmt, ...); + +enum { + MG_EV_ERROR, // Error char *error_message + MG_EV_OPEN, // Connection created NULL + MG_EV_POLL, // mg_mgr_poll iteration uint64_t *uptime_millis + MG_EV_RESOLVE, // Host name is resolved NULL + MG_EV_CONNECT, // Connection established NULL + MG_EV_ACCEPT, // Connection accepted NULL + MG_EV_TLS_HS, // TLS handshake succeeded NULL + MG_EV_READ, // Data received from socket long *bytes_read + MG_EV_WRITE, // Data written to socket long *bytes_written + MG_EV_CLOSE, // Connection closed NULL + MG_EV_HTTP_MSG, // HTTP request/response struct mg_http_message * + MG_EV_WS_OPEN, // Websocket handshake done struct mg_http_message * + MG_EV_WS_MSG, // Websocket msg, text or bin struct mg_ws_message * + MG_EV_WS_CTL, // Websocket control msg struct mg_ws_message * + MG_EV_MQTT_CMD, // MQTT low-level command struct mg_mqtt_message * + MG_EV_MQTT_MSG, // MQTT PUBLISH received struct mg_mqtt_message * + MG_EV_MQTT_OPEN, // MQTT CONNACK received int *connack_status_code + MG_EV_SNTP_TIME, // SNTP time received uint64_t *epoch_millis + MG_EV_USER // Starting ID for user events +}; + + + + + + + + + +struct mg_dns { + const char *url; // DNS server URL + struct mg_connection *c; // DNS server connection +}; + +struct mg_addr { + uint8_t ip[16]; // Holds IPv4 or IPv6 address, in network byte order + uint16_t port; // TCP or UDP port in network byte order + uint8_t scope_id; // IPv6 scope ID + bool is_ip6; // True when address is IPv6 address +}; + +struct mg_mgr { + struct mg_connection *conns; // List of active connections + struct mg_dns dns4; // DNS for IPv4 + struct mg_dns dns6; // DNS for IPv6 + int dnstimeout; // DNS resolve timeout in milliseconds + bool use_dns6; // Use DNS6 server by default, see #1532 + unsigned long nextid; // Next connection ID + unsigned long timerid; // Next timer ID + void *userdata; // Arbitrary user data pointer + void *tls_ctx; // TLS context shared by all TLS sessions + uint16_t mqtt_id; // MQTT IDs for pub/sub + void *active_dns_requests; // DNS requests in progress + struct mg_timer *timers; // Active timers + int epoll_fd; // Used when MG_EPOLL_ENABLE=1 + void *priv; // Used by the MIP stack + size_t extraconnsize; // Used by the MIP stack +#if MG_ENABLE_FREERTOS_TCP + SocketSet_t ss; // NOTE(lsm): referenced from socket struct +#endif +}; + +struct mg_connection { + struct mg_connection *next; // Linkage in struct mg_mgr :: connections + struct mg_mgr *mgr; // Our container + struct mg_addr loc; // Local address + struct mg_addr rem; // Remote address + void *fd; // Connected socket, or LWIP data + unsigned long id; // Auto-incrementing unique connection ID + struct mg_iobuf recv; // Incoming data + struct mg_iobuf send; // Outgoing data + mg_event_handler_t fn; // User-specified event handler function + void *fn_data; // User-specified function parameter + mg_event_handler_t pfn; // Protocol-specific handler function + void *pfn_data; // Protocol-specific function parameter + char data[MG_DATA_SIZE]; // Arbitrary connection data + void *tls; // TLS specific data + unsigned is_listening : 1; // Listening connection + unsigned is_client : 1; // Outbound (client) connection + unsigned is_accepted : 1; // Accepted (server) connection + unsigned is_resolving : 1; // Non-blocking DNS resolution is in progress + unsigned is_arplooking : 1; // Non-blocking ARP resolution is in progress + unsigned is_connecting : 1; // Non-blocking connect is in progress + unsigned is_tls : 1; // TLS-enabled connection + unsigned is_tls_hs : 1; // TLS handshake is in progress + unsigned is_udp : 1; // UDP connection + unsigned is_websocket : 1; // WebSocket connection + unsigned is_mqtt5 : 1; // For MQTT connection, v5 indicator + unsigned is_hexdumping : 1; // Hexdump in/out traffic + unsigned is_draining : 1; // Send remaining data, then close and free + unsigned is_closing : 1; // Close and free the connection immediately + unsigned is_full : 1; // Stop reads, until cleared + unsigned is_resp : 1; // Response is still being generated + unsigned is_readable : 1; // Connection is ready to read + unsigned is_writable : 1; // Connection is ready to write +}; + +void mg_mgr_poll(struct mg_mgr *, int ms); +void mg_mgr_init(struct mg_mgr *); +void mg_mgr_free(struct mg_mgr *); + +struct mg_connection *mg_listen(struct mg_mgr *, const char *url, + mg_event_handler_t fn, void *fn_data); +struct mg_connection *mg_connect(struct mg_mgr *, const char *url, + mg_event_handler_t fn, void *fn_data); +struct mg_connection *mg_wrapfd(struct mg_mgr *mgr, int fd, + mg_event_handler_t fn, void *fn_data); +void mg_connect_resolved(struct mg_connection *); +bool mg_send(struct mg_connection *, const void *, size_t); +size_t mg_printf(struct mg_connection *, const char *fmt, ...); +size_t mg_vprintf(struct mg_connection *, const char *fmt, va_list *ap); +bool mg_aton(struct mg_str str, struct mg_addr *addr); + +// These functions are used to integrate with custom network stacks +struct mg_connection *mg_alloc_conn(struct mg_mgr *); +void mg_close_conn(struct mg_connection *c); +bool mg_open_listener(struct mg_connection *c, const char *url); + +// Utility functions +struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds, + unsigned flags, void (*fn)(void *), void *arg); + +// Low-level IO primives used by TLS layer +enum { MG_IO_ERR = -1, MG_IO_WAIT = -2, MG_IO_RESET = -3 }; +long mg_io_send(struct mg_connection *c, const void *buf, size_t len); +long mg_io_recv(struct mg_connection *c, void *buf, size_t len); + + + + + + + + +struct mg_http_header { + struct mg_str name; // Header name + struct mg_str value; // Header value +}; + +struct mg_http_message { + struct mg_str method, uri, query, proto; // Request/response line + struct mg_http_header headers[MG_MAX_HTTP_HEADERS]; // Headers + struct mg_str body; // Body + struct mg_str head; // Request + headers + struct mg_str message; // Request + headers + body +}; + +// Parameter for mg_http_serve_dir() +struct mg_http_serve_opts { + const char *root_dir; // Web root directory, must be non-NULL + const char *ssi_pattern; // SSI file name pattern, e.g. #.shtml + const char *extra_headers; // Extra HTTP headers to add in responses + const char *mime_types; // Extra mime types, ext1=type1,ext2=type2,.. + const char *page404; // Path to the 404 page, or NULL by default + struct mg_fs *fs; // Filesystem implementation. Use NULL for POSIX +}; + +// Parameter for mg_http_next_multipart +struct mg_http_part { + struct mg_str name; // Form field name + struct mg_str filename; // Filename for file uploads + struct mg_str body; // Part contents +}; + +int mg_http_parse(const char *s, size_t len, struct mg_http_message *); +int mg_http_get_request_len(const unsigned char *buf, size_t buf_len); +void mg_http_printf_chunk(struct mg_connection *cnn, const char *fmt, ...); +void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len); +void mg_http_delete_chunk(struct mg_connection *c, struct mg_http_message *hm); +struct mg_connection *mg_http_listen(struct mg_mgr *, const char *url, + mg_event_handler_t fn, void *fn_data); +struct mg_connection *mg_http_connect(struct mg_mgr *, const char *url, + mg_event_handler_t fn, void *fn_data); +void mg_http_serve_dir(struct mg_connection *, struct mg_http_message *hm, + const struct mg_http_serve_opts *); +void mg_http_serve_file(struct mg_connection *, struct mg_http_message *hm, + const char *path, const struct mg_http_serve_opts *); +void mg_http_reply(struct mg_connection *, int status_code, const char *headers, + const char *body_fmt, ...); +struct mg_str *mg_http_get_header(struct mg_http_message *, const char *name); +struct mg_str mg_http_var(struct mg_str buf, struct mg_str name); +int mg_http_get_var(const struct mg_str *, const char *name, char *, size_t); +int mg_url_decode(const char *s, size_t n, char *to, size_t to_len, int form); +size_t mg_url_encode(const char *s, size_t n, char *buf, size_t len); +void mg_http_creds(struct mg_http_message *, char *, size_t, char *, size_t); +bool mg_http_match_uri(const struct mg_http_message *, const char *glob); +long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm, + struct mg_fs *fs, const char *path, size_t max_size); +void mg_http_bauth(struct mg_connection *, const char *user, const char *pass); +struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v); +size_t mg_http_next_multipart(struct mg_str, size_t, struct mg_http_part *); +int mg_http_status(const struct mg_http_message *hm); +void mg_hello(const char *url); + + +void mg_http_serve_ssi(struct mg_connection *c, const char *root, + const char *fullpath); + + +#define MG_TLS_NONE 0 // No TLS support +#define MG_TLS_MBED 1 // mbedTLS +#define MG_TLS_OPENSSL 2 // OpenSSL +#define MG_TLS_BUILTIN 3 // Built-in +#define MG_TLS_CUSTOM 4 // Custom implementation + +#ifndef MG_TLS +#define MG_TLS MG_TLS_NONE +#endif + + + + + +struct mg_tls_opts { + struct mg_str ca; // PEM or DER + struct mg_str cert; // PEM or DER + struct mg_str key; // PEM or DER + struct mg_str name; // If not empty, enable host name verification +}; + +void mg_tls_init(struct mg_connection *, const struct mg_tls_opts *opts); +void mg_tls_free(struct mg_connection *); +long mg_tls_send(struct mg_connection *, const void *buf, size_t len); +long mg_tls_recv(struct mg_connection *, void *buf, size_t len); +size_t mg_tls_pending(struct mg_connection *); +void mg_tls_handshake(struct mg_connection *); + +// Private +void mg_tls_ctx_init(struct mg_mgr *); +void mg_tls_ctx_free(struct mg_mgr *); + + + + + + + +#if MG_TLS == MG_TLS_MBED +#include +#include +#include +#include + +struct mg_tls_ctx { + int dummy; +#ifdef MBEDTLS_SSL_SESSION_TICKETS + mbedtls_ssl_ticket_context tickets; +#endif +}; + +struct mg_tls { + mbedtls_x509_crt ca; // Parsed CA certificate + mbedtls_x509_crt cert; // Parsed certificate + mbedtls_pk_context pk; // Private key context + mbedtls_ssl_context ssl; // SSL/TLS context + mbedtls_ssl_config conf; // SSL-TLS config +#ifdef MBEDTLS_SSL_SESSION_TICKETS + mbedtls_ssl_ticket_context ticket; // Session tickets context +#endif +}; +#endif + + +#if MG_TLS == MG_TLS_OPENSSL + +#include +#include + +struct mg_tls { + SSL_CTX *ctx; + SSL *ssl; +}; +#endif + + +#define WEBSOCKET_OP_CONTINUE 0 +#define WEBSOCKET_OP_TEXT 1 +#define WEBSOCKET_OP_BINARY 2 +#define WEBSOCKET_OP_CLOSE 8 +#define WEBSOCKET_OP_PING 9 +#define WEBSOCKET_OP_PONG 10 + + + +struct mg_ws_message { + struct mg_str data; // Websocket message data + uint8_t flags; // Websocket message flags +}; + +struct mg_connection *mg_ws_connect(struct mg_mgr *, const char *url, + mg_event_handler_t fn, void *fn_data, + const char *fmt, ...); +void mg_ws_upgrade(struct mg_connection *, struct mg_http_message *, + const char *fmt, ...); +size_t mg_ws_send(struct mg_connection *, const void *buf, size_t len, int op); +size_t mg_ws_wrap(struct mg_connection *, size_t len, int op); +size_t mg_ws_printf(struct mg_connection *c, int op, const char *fmt, ...); +size_t mg_ws_vprintf(struct mg_connection *c, int op, const char *fmt, + va_list *); + + + + +struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, const char *url, + mg_event_handler_t fn, void *fn_data); +void mg_sntp_request(struct mg_connection *c); +int64_t mg_sntp_parse(const unsigned char *buf, size_t len); + + + + + +#define MQTT_CMD_CONNECT 1 +#define MQTT_CMD_CONNACK 2 +#define MQTT_CMD_PUBLISH 3 +#define MQTT_CMD_PUBACK 4 +#define MQTT_CMD_PUBREC 5 +#define MQTT_CMD_PUBREL 6 +#define MQTT_CMD_PUBCOMP 7 +#define MQTT_CMD_SUBSCRIBE 8 +#define MQTT_CMD_SUBACK 9 +#define MQTT_CMD_UNSUBSCRIBE 10 +#define MQTT_CMD_UNSUBACK 11 +#define MQTT_CMD_PINGREQ 12 +#define MQTT_CMD_PINGRESP 13 +#define MQTT_CMD_DISCONNECT 14 +#define MQTT_CMD_AUTH 15 + +#define MQTT_PROP_PAYLOAD_FORMAT_INDICATOR 0x01 +#define MQTT_PROP_MESSAGE_EXPIRY_INTERVAL 0x02 +#define MQTT_PROP_CONTENT_TYPE 0x03 +#define MQTT_PROP_RESPONSE_TOPIC 0x08 +#define MQTT_PROP_CORRELATION_DATA 0x09 +#define MQTT_PROP_SUBSCRIPTION_IDENTIFIER 0x0B +#define MQTT_PROP_SESSION_EXPIRY_INTERVAL 0x11 +#define MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER 0x12 +#define MQTT_PROP_SERVER_KEEP_ALIVE 0x13 +#define MQTT_PROP_AUTHENTICATION_METHOD 0x15 +#define MQTT_PROP_AUTHENTICATION_DATA 0x16 +#define MQTT_PROP_REQUEST_PROBLEM_INFORMATION 0x17 +#define MQTT_PROP_WILL_DELAY_INTERVAL 0x18 +#define MQTT_PROP_REQUEST_RESPONSE_INFORMATION 0x19 +#define MQTT_PROP_RESPONSE_INFORMATION 0x1A +#define MQTT_PROP_SERVER_REFERENCE 0x1C +#define MQTT_PROP_REASON_STRING 0x1F +#define MQTT_PROP_RECEIVE_MAXIMUM 0x21 +#define MQTT_PROP_TOPIC_ALIAS_MAXIMUM 0x22 +#define MQTT_PROP_TOPIC_ALIAS 0x23 +#define MQTT_PROP_MAXIMUM_QOS 0x24 +#define MQTT_PROP_RETAIN_AVAILABLE 0x25 +#define MQTT_PROP_USER_PROPERTY 0x26 +#define MQTT_PROP_MAXIMUM_PACKET_SIZE 0x27 +#define MQTT_PROP_WILDCARD_SUBSCRIPTION_AVAILABLE 0x28 +#define MQTT_PROP_SUBSCRIPTION_IDENTIFIER_AVAILABLE 0x29 +#define MQTT_PROP_SHARED_SUBSCRIPTION_AVAILABLE 0x2A + +enum { + MQTT_PROP_TYPE_BYTE, + MQTT_PROP_TYPE_STRING, + MQTT_PROP_TYPE_STRING_PAIR, + MQTT_PROP_TYPE_BINARY_DATA, + MQTT_PROP_TYPE_VARIABLE_INT, + MQTT_PROP_TYPE_INT, + MQTT_PROP_TYPE_SHORT +}; + +enum { MQTT_OK, MQTT_INCOMPLETE, MQTT_MALFORMED }; + +struct mg_mqtt_prop { + uint8_t id; // Enumerated at MQTT5 Reference + uint32_t iv; // Integer value for 8-, 16-, 32-bit integers types + struct mg_str key; // Non-NULL only for user property type + struct mg_str val; // Non-NULL only for UTF-8 types and user properties +}; + +struct mg_mqtt_opts { + struct mg_str user; // Username, can be empty + struct mg_str pass; // Password, can be empty + struct mg_str client_id; // Client ID + struct mg_str topic; // message/subscription topic + struct mg_str message; // message content + uint8_t qos; // message quality of service + uint8_t version; // Can be 4 (3.1.1), or 5. If 0, assume 4 + uint16_t keepalive; // Keep-alive timer in seconds + bool retain; // Retain flag + bool clean; // Clean session flag + struct mg_mqtt_prop *props; // MQTT5 props array + size_t num_props; // number of props + struct mg_mqtt_prop *will_props; // Valid only for CONNECT packet (MQTT5) + size_t num_will_props; // Number of will props +}; + +struct mg_mqtt_message { + struct mg_str topic; // Parsed topic for PUBLISH + struct mg_str data; // Parsed message for PUBLISH + struct mg_str dgram; // Whole MQTT packet, including headers + uint16_t id; // For PUBACK, PUBREC, PUBREL, PUBCOMP, SUBACK, PUBLISH + uint8_t cmd; // MQTT command, one of MQTT_CMD_* + uint8_t qos; // Quality of service + uint8_t ack; // CONNACK return code, 0 = success + size_t props_start; // Offset to the start of the properties (MQTT5) + size_t props_size; // Length of the properties +}; + +struct mg_connection *mg_mqtt_connect(struct mg_mgr *, const char *url, + const struct mg_mqtt_opts *opts, + mg_event_handler_t fn, void *fn_data); +struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url, + mg_event_handler_t fn, void *fn_data); +void mg_mqtt_login(struct mg_connection *c, const struct mg_mqtt_opts *opts); +void mg_mqtt_pub(struct mg_connection *c, const struct mg_mqtt_opts *opts); +void mg_mqtt_sub(struct mg_connection *, const struct mg_mqtt_opts *opts); +int mg_mqtt_parse(const uint8_t *, size_t, uint8_t, struct mg_mqtt_message *); +void mg_mqtt_send_header(struct mg_connection *, uint8_t cmd, uint8_t flags, + uint32_t len); +void mg_mqtt_ping(struct mg_connection *); +void mg_mqtt_pong(struct mg_connection *); +void mg_mqtt_disconnect(struct mg_connection *, const struct mg_mqtt_opts *); +size_t mg_mqtt_next_prop(struct mg_mqtt_message *, struct mg_mqtt_prop *, + size_t ofs); + + + + + +// Mongoose sends DNS queries that contain only one question: +// either A (IPv4) or AAAA (IPv6) address lookup. +// Therefore, we expect zero or one answer. +// If `resolved` is true, then `addr` contains resolved IPv4 or IPV6 address. +struct mg_dns_message { + uint16_t txnid; // Transaction ID + bool resolved; // Resolve successful, addr is set + struct mg_addr addr; // Resolved address + char name[256]; // Host name +}; + +struct mg_dns_header { + uint16_t txnid; // Transaction ID + uint16_t flags; + uint16_t num_questions; + uint16_t num_answers; + uint16_t num_authority_prs; + uint16_t num_other_prs; +}; + +// DNS resource record +struct mg_dns_rr { + uint16_t nlen; // Name or pointer length + uint16_t atype; // Address type + uint16_t aclass; // Address class + uint16_t alen; // Address length +}; + +void mg_resolve(struct mg_connection *, const char *url); +void mg_resolve_cancel(struct mg_connection *); +bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *); +size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs, + bool is_question, struct mg_dns_rr *); + + + + + +#ifndef MG_JSON_MAX_DEPTH +#define MG_JSON_MAX_DEPTH 30 +#endif + +// Error return values - negative. Successful returns are >= 0 +enum { MG_JSON_TOO_DEEP = -1, MG_JSON_INVALID = -2, MG_JSON_NOT_FOUND = -3 }; +int mg_json_get(struct mg_str json, const char *path, int *toklen); + +bool mg_json_get_num(struct mg_str json, const char *path, double *v); +bool mg_json_get_bool(struct mg_str json, const char *path, bool *v); +long mg_json_get_long(struct mg_str json, const char *path, long dflt); +char *mg_json_get_str(struct mg_str json, const char *path); +char *mg_json_get_hex(struct mg_str json, const char *path, int *len); +char *mg_json_get_b64(struct mg_str json, const char *path, int *len); + +bool mg_json_unescape(struct mg_str str, char *buf, size_t len); +size_t mg_json_next(struct mg_str obj, size_t ofs, struct mg_str *key, + struct mg_str *val); + + + + +// JSON-RPC request descriptor +struct mg_rpc_req { + struct mg_rpc **head; // RPC handlers list head + struct mg_rpc *rpc; // RPC handler being called + mg_pfn_t pfn; // Response printing function + void *pfn_data; // Response printing function data + void *req_data; // Arbitrary request data + struct mg_str frame; // Request, e.g. {"id":1,"method":"add","params":[1,2]} +}; + +// JSON-RPC method handler +struct mg_rpc { + struct mg_rpc *next; // Next in list + struct mg_str method; // Method pattern + void (*fn)(struct mg_rpc_req *); // Handler function + void *fn_data; // Handler function argument +}; + +void mg_rpc_add(struct mg_rpc **head, struct mg_str method_pattern, + void (*handler)(struct mg_rpc_req *), void *handler_data); +void mg_rpc_del(struct mg_rpc **head, void (*handler)(struct mg_rpc_req *)); +void mg_rpc_process(struct mg_rpc_req *); + +// Helper functions to print result or error frame +void mg_rpc_ok(struct mg_rpc_req *, const char *fmt, ...); +void mg_rpc_vok(struct mg_rpc_req *, const char *fmt, va_list *ap); +void mg_rpc_err(struct mg_rpc_req *, int code, const char *fmt, ...); +void mg_rpc_verr(struct mg_rpc_req *, int code, const char *fmt, va_list *); +void mg_rpc_list(struct mg_rpc_req *r); +// Copyright (c) 2023 Cesanta Software Limited +// All rights reserved + + + + + +#define MG_OTA_NONE 0 // No OTA support +#define MG_OTA_FLASH 1 // OTA via an internal flash +#define MG_OTA_CUSTOM 100 // Custom implementation + +#ifndef MG_OTA +#define MG_OTA MG_OTA_NONE +#endif + +// Firmware update API +bool mg_ota_begin(size_t new_firmware_size); // Start writing +bool mg_ota_write(const void *buf, size_t len); // Write chunk, aligned to 1k +bool mg_ota_end(void); // Stop writing + +enum { + MG_OTA_UNAVAILABLE = 0, // No OTA information is present + MG_OTA_FIRST_BOOT = 1, // Device booting the first time after the OTA + MG_OTA_UNCOMMITTED = 2, // Ditto, but marking us for the rollback + MG_OTA_COMMITTED = 3, // The firmware is good +}; +enum { MG_FIRMWARE_CURRENT = 0, MG_FIRMWARE_PREVIOUS = 1 }; + +int mg_ota_status(int firmware); // Return firmware status MG_OTA_* +uint32_t mg_ota_crc32(int firmware); // Return firmware checksum +uint32_t mg_ota_timestamp(int firmware); // Firmware timestamp, UNIX UTC epoch +size_t mg_ota_size(int firmware); // Firmware size + +bool mg_ota_commit(void); // Commit current firmware +bool mg_ota_rollback(void); // Rollback to the previous firmware +// Copyright (c) 2023 Cesanta Software Limited +// All rights reserved + + + + + +#define MG_DEVICE_NONE 0 // Dummy system +#define MG_DEVICE_STM32H5 1 // STM32 H5 +#define MG_DEVICE_STM32H7 2 // STM32 H7 +#define MG_DEVICE_CUSTOM 100 // Custom implementation + +#ifndef MG_DEVICE +#define MG_DEVICE MG_DEVICE_NONE +#endif + +// Flash information +void *mg_flash_start(void); // Return flash start address +size_t mg_flash_size(void); // Return flash size +size_t mg_flash_sector_size(void); // Return flash sector size +size_t mg_flash_write_align(void); // Return flash write align, minimum 4 +int mg_flash_bank(void); // 0: not dual bank, 1: bank1, 2: bank2 + +// Write, erase, swap bank +bool mg_flash_write(void *addr, const void *buf, size_t len); +bool mg_flash_erase(void *addr); // Must be at sector boundary +bool mg_flash_swap_bank(void); + +// Convenience functions to store data on a flash sector with wear levelling +// If `sector` is NULL, then the last sector of flash is used +bool mg_flash_load(void *sector, uint32_t key, void *buf, size_t len); +bool mg_flash_save(void *sector, uint32_t key, const void *buf, size_t len); + +void mg_device_reset(void); // Reboot device immediately + + + + + + +#if defined(MG_ENABLE_TCPIP) && MG_ENABLE_TCPIP +struct mg_tcpip_if; // Mongoose TCP/IP network interface + +struct mg_tcpip_driver { + bool (*init)(struct mg_tcpip_if *); // Init driver + size_t (*tx)(const void *, size_t, struct mg_tcpip_if *); // Transmit frame + size_t (*rx)(void *buf, size_t len, struct mg_tcpip_if *); // Receive frame + bool (*up)(struct mg_tcpip_if *); // Up/down status +}; + +// Network interface +struct mg_tcpip_if { + uint8_t mac[6]; // MAC address. Must be set to a valid MAC + uint32_t ip, mask, gw; // IP address, mask, default gateway + struct mg_str tx; // Output (TX) buffer + bool enable_dhcp_client; // Enable DCHP client + bool enable_dhcp_server; // Enable DCHP server + bool enable_crc32_check; // Do a CRC check on RX frames and strip it + bool enable_mac_check; // Do a MAC check on RX frames + struct mg_tcpip_driver *driver; // Low level driver + void *driver_data; // Driver-specific data + struct mg_mgr *mgr; // Mongoose event manager + struct mg_queue recv_queue; // Receive queue + uint16_t mtu; // Interface MTU +#define MG_TCPIP_MTU_DEFAULT 1500 + + // Internal state, user can use it but should not change it + uint8_t gwmac[6]; // Router's MAC + uint64_t now; // Current time + uint64_t timer_1000ms; // 1000 ms timer: for DHCP and link state + uint64_t lease_expire; // Lease expiration time, in ms + uint16_t eport; // Next ephemeral port + volatile uint32_t ndrop; // Number of received, but dropped frames + volatile uint32_t nrecv; // Number of received frames + volatile uint32_t nsent; // Number of transmitted frames + volatile uint32_t nerr; // Number of driver errors + uint8_t state; // Current state +#define MG_TCPIP_STATE_DOWN 0 // Interface is down +#define MG_TCPIP_STATE_UP 1 // Interface is up +#define MG_TCPIP_STATE_REQ 2 // Interface is up and has requested an IP +#define MG_TCPIP_STATE_READY 3 // Interface is up and has an IP assigned +}; + +void mg_tcpip_init(struct mg_mgr *, struct mg_tcpip_if *); +void mg_tcpip_free(struct mg_tcpip_if *); +void mg_tcpip_qwrite(void *buf, size_t len, struct mg_tcpip_if *ifp); + +extern struct mg_tcpip_driver mg_tcpip_driver_stm32; +extern struct mg_tcpip_driver mg_tcpip_driver_w5500; +extern struct mg_tcpip_driver mg_tcpip_driver_tm4c; +extern struct mg_tcpip_driver mg_tcpip_driver_stm32h; +extern struct mg_tcpip_driver mg_tcpip_driver_imxrt1020; +extern struct mg_tcpip_driver mg_tcpip_driver_same54; + +// Drivers that require SPI, can use this SPI abstraction +struct mg_tcpip_spi { + void *spi; // Opaque SPI bus descriptor + void (*begin)(void *); // SPI begin: slave select low + void (*end)(void *); // SPI end: slave select high + uint8_t (*txn)(void *, uint8_t); // SPI transaction: write 1 byte, read reply +}; +#endif + + +struct mg_tcpip_driver_imxrt1020_data { + // MDC clock divider. MDC clock is derived from IPS Bus clock (ipg_clk), + // must not exceed 2.5MHz. Configuration for clock range 2.36~2.50 MHz + // 37.5.1.8.2, Table 37-46 : f = ipg_clk / (2(mdc_cr + 1)) + // ipg_clk mdc_cr VALUE + // -------------------------- + // -1 <-- TODO() tell driver to guess the value + // 25 MHz 4 + // 33 MHz 6 + // 40 MHz 7 + // 50 MHz 9 + // 66 MHz 13 + int mdc_cr; // Valid values: -1 to 63 +}; + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && MG_ENABLE_DRIVER_SAME54 + +struct mg_tcpip_driver_same54_data { + int mdc_cr; +}; + +#endif + + +struct mg_tcpip_driver_stm32_data { + // MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz + // HCLK range DIVIDER mdc_cr VALUE + // ------------------------------------- + // -1 <-- tell driver to guess the value + // 60-100 MHz HCLK/42 0 + // 100-150 MHz HCLK/62 1 + // 20-35 MHz HCLK/16 2 + // 35-60 MHz HCLK/26 3 + // 150-216 MHz HCLK/102 4 <-- value for Nucleo-F* on max speed + // 216-310 MHz HCLK/124 5 + // 110, 111 Reserved + int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5 +}; + + +struct mg_tcpip_driver_stm32h_data { + // MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz + // HCLK range DIVIDER mdc_cr VALUE + // ------------------------------------- + // -1 <-- tell driver to guess the value + // 60-100 MHz HCLK/42 0 + // 100-150 MHz HCLK/62 1 + // 20-35 MHz HCLK/16 2 + // 35-60 MHz HCLK/26 3 + // 150-250 MHz HCLK/102 4 <-- value for Nucleo-H* on max speed driven by HSI + // 250-300 MHz HCLK/124 5 <-- value for Nucleo-H* on max speed driven by CSI + // 110, 111 Reserved + int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5 +}; + + +struct mg_tcpip_driver_tm4c_data { + // MDC clock divider. MDC clock is derived from SYSCLK, must not exceed 2.5MHz + // SYSCLK range DIVIDER mdc_cr VALUE + // ------------------------------------- + // -1 <-- tell driver to guess the value + // 60-100 MHz SYSCLK/42 0 + // 100-150 MHz SYSCLK/62 1 <-- value for EK-TM4C129* on max speed + // 20-35 MHz SYSCLK/16 2 + // 35-60 MHz SYSCLK/26 3 + // 0x4-0xF Reserved + int mdc_cr; // Valid values: -1, 0, 1, 2, 3 +}; + +#ifdef __cplusplus +} +#endif +#endif // MONGOOSE_H