mongoose/mongoose.h

1650 lines
50 KiB
C
Raw Normal View History

2020-12-05 19:26:32 +08:00
// Copyright (c) 2004-2013 Sergey Lyubka
2022-02-23 02:13:06 +08:00
// Copyright (c) 2013-2022 Cesanta Software Limited
2020-12-05 19:26:32 +08:00
// 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
2021-10-20 17:04:49 +08:00
// license, see http://www.gnu.org/licenses/
2020-12-05 19:26:32 +08:00
//
// 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
2021-10-20 17:04:49 +08:00
// license, as set out in https://www.mongoose.ws/licensing/
2022-02-23 02:13:06 +08:00
//
// SPDX-License-Identifier: GPL-2.0-only or commercial
#ifndef MONGOOSE_H
#define MONGOOSE_H
2023-01-25 00:30:45 +08:00
#define MG_VERSION "7.9"
2020-12-05 19:26:32 +08:00
#ifdef __cplusplus
extern "C" {
#endif
2020-12-05 19:26:32 +08:00
#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_RTX 9 // Keil MDK RTX
#define MG_ARCH_TIRTOS 10 // Texas Semi TI-RTOS
#define MG_ARCH_RP2040 11 // Raspberry Pi RP2040
2020-12-05 19:26:32 +08:00
#if !defined(MG_ARCH)
2021-05-11 16:12:06 +08:00
#if defined(__unix__) || defined(__APPLE__)
2020-12-05 19:26:32 +08:00
#define MG_ARCH MG_ARCH_UNIX
#elif defined(_WIN32)
2020-12-05 19:26:32 +08:00
#define MG_ARCH MG_ARCH_WIN32
#elif defined(ICACHE_FLASH) || defined(ICACHE_RAM_ATTR)
#define MG_ARCH MG_ARCH_ESP8266
2022-10-21 22:39:45 +08:00
#elif defined(__ZEPHYR__)
#define MG_ARCH MG_ARCH_ZEPHYR
2020-12-27 09:29:42 +08:00
#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
2021-09-14 14:28:28 +08:00
#elif defined(AZURE_RTOS_THREADX)
#define MG_ARCH MG_ARCH_AZURERTOS
2022-07-04 06:00:15 +08:00
#elif defined(PICO_TARGET_NAME)
#define MG_ARCH MG_ARCH_RP2040
#endif
2022-11-03 20:59:55 +08:00
#endif // !defined(MG_ARCH)
#if !defined(MG_ARCH) || (MG_ARCH == MG_ARCH_CUSTOM)
#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
2022-09-28 19:42:20 +08:00
// http://esr.ibiblio.org/?p=5095
#define MG_BIG_ENDIAN (*(uint16_t *) "\0\xff" < 0x100)
2022-09-28 19:42:20 +08:00
2021-05-29 06:49:26 +08:00
2022-03-30 14:56:44 +08:00
2022-05-01 20:47:33 +08:00
2022-05-12 15:07:51 +08:00
2021-09-14 14:28:28 +08:00
#if MG_ARCH == MG_ARCH_AZURERTOS
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
2021-09-14 14:28:28 +08:00
#include <stdio.h>
#include <time.h>
2021-09-14 14:28:28 +08:00
#include <fx_api.h>
#include <tx_api.h>
2021-09-14 14:28:28 +08:00
#include <nx_api.h>
#include <nx_bsd.h>
#include <nx_port.h>
#include <tx_port.h>
2021-09-14 14:28:28 +08:00
#define PATH_MAX FX_MAXIMUM_PATH
#define MG_DIRSEP '\\'
#define socklen_t int
#define closesocket(x) soc_close(x)
#undef FOPEN_MAX
#endif
2020-12-05 19:26:32 +08:00
#if MG_ARCH == MG_ARCH_ESP32
#include <ctype.h>
2020-12-05 19:26:32 +08:00
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
2020-12-05 19:26:32 +08:00
#include <netdb.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
2022-05-16 18:54:26 +08:00
#include <esp_timer.h>
#define MG_PATH_MAX 128
#endif
2020-12-05 19:26:32 +08:00
#if MG_ARCH == MG_ARCH_ESP8266
#include <ctype.h>
2020-12-05 19:26:32 +08:00
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
2020-12-27 09:29:42 +08:00
#include <netdb.h>
#include <stdarg.h>
2020-12-05 19:26:32 +08:00
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
2020-12-05 19:26:32 +08:00
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <esp_system.h>
2021-10-31 02:34:53 +08:00
#define MG_PATH_MAX 128
#endif
#if MG_ARCH == MG_ARCH_FREERTOS
2021-05-29 06:49:26 +08:00
#include <ctype.h>
// #include <errno.h> // Cannot include errno - might conflict with lwip!
2021-05-29 06:49:26 +08:00
#include <stdarg.h>
#include <stdbool.h>
2022-08-15 06:46:33 +08:00
#include <stddef.h>
2021-05-29 06:49:26 +08:00
#include <stdint.h>
2021-09-29 17:13:02 +08:00
#include <stdio.h>
#include <stdlib.h> // rand(), strtol(), atoi()
2022-01-14 20:33:06 +08:00
#include <string.h>
#include <sys/stat.h>
2021-05-29 06:49:26 +08:00
#include <FreeRTOS.h>
#include <task.h>
#ifndef MG_IO_SIZE
#define MG_IO_SIZE 512
2021-08-11 14:56:46 +08:00
#endif
#define calloc(a, b) mg_calloc(a, b)
2021-05-29 06:49:26 +08:00
#define free(a) vPortFree(a)
#define malloc(a) pvPortMalloc(a)
2022-08-20 07:03:15 +08:00
#define strdup(s) ((char *) mg_strdup(mg_str(s)).ptr)
2020-12-05 19:26:32 +08:00
// 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);
2022-06-21 19:07:00 +08:00
if (p != NULL) memset(p, 0, size * cnt);
return p;
}
2021-05-19 07:00:32 +08:00
#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
2020-12-05 19:26:32 +08:00
2022-05-01 20:47:33 +08:00
#if MG_ARCH == MG_ARCH_NEWLIB
#define _POSIX_TIMERS
#include <ctype.h>
#include <errno.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#define MG_PATH_MAX 100
#define MG_ENABLE_SOCKET 0
#define MG_ENABLE_DIRLIST 0
#define MG_ENABLE_ATOMIC 1
2022-05-01 20:47:33 +08:00
#endif
2022-07-04 06:00:15 +08:00
#if MG_ARCH == MG_ARCH_RP2040
#include <errno.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
2022-07-04 18:10:08 +08:00
#include <pico/stdlib.h>
int mkdir(const char *, mode_t);
#define MG_ENABLE_ATOMIC 1
2022-07-04 06:00:15 +08:00
#endif
2022-05-12 15:07:51 +08:00
#if MG_ARCH == MG_ARCH_RTX
#include <ctype.h>
#include <errno.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#if !defined MG_ENABLE_RL && (!defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP)
#define MG_ENABLE_RL 1
2022-02-18 16:07:10 +08:00
#endif
#endif
2020-12-05 19:26:32 +08:00
2022-05-16 00:18:18 +08:00
#if MG_ARCH == MG_ARCH_TIRTOS
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <serrno.h>
2022-05-16 00:18:18 +08:00
#include <sys/socket.h>
2022-10-24 22:48:54 +08:00
#include <ti/sysbios/knl/Clock.h>
2022-05-16 00:18:18 +08:00
#endif
2020-12-05 19:26:32 +08:00
#if MG_ARCH == MG_ARCH_UNIX
2021-07-24 17:35:48 +08:00
#define _DARWIN_UNLIMITED_SELECT 1 // No limit on file descriptors
2022-07-02 00:28:06 +08:00
#if defined(__APPLE__)
#include <mach/mach_time.h>
#endif
2022-08-03 22:07:16 +08:00
#if !defined(MG_ENABLE_EPOLL) && defined(__linux__)
#define MG_ENABLE_EPOLL 1
#elif !defined(MG_ENABLE_POLL)
#define MG_ENABLE_POLL 1
#endif
2020-12-05 19:26:32 +08:00
#include <arpa/inet.h>
#include <ctype.h>
2020-12-05 19:26:32 +08:00
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
2020-12-05 19:26:32 +08:00
#include <netdb.h>
2022-01-24 10:20:45 +08:00
#include <netinet/in.h>
2020-12-05 19:26:32 +08:00
#include <netinet/tcp.h>
#include <signal.h>
#include <stdarg.h>
2020-12-05 19:26:32 +08:00
#include <stdbool.h>
#include <stddef.h>
2020-12-05 19:26:32 +08:00
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
2022-08-03 22:07:16 +08:00
#if defined(MG_ENABLE_EPOLL) && MG_ENABLE_EPOLL
#include <sys/epoll.h>
#elif defined(MG_ENABLE_POLL) && MG_ENABLE_POLL
#include <poll.h>
#else
2020-12-05 19:26:32 +08:00
#include <sys/select.h>
#endif
2022-08-03 22:07:16 +08:00
2020-12-05 19:26:32 +08:00
#include <sys/socket.h>
#include <sys/stat.h>
2020-12-05 19:26:32 +08:00
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
2020-12-05 19:26:32 +08:00
#include <unistd.h>
2022-02-14 19:32:01 +08:00
#ifndef MG_ENABLE_DIRLIST
#define MG_ENABLE_DIRLIST 1
#endif
#ifndef MG_PATH_MAX
#define MG_PATH_MAX FILENAME_MAX
#endif
#endif
2020-12-05 19:26:32 +08:00
#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 <ctype.h>
#include <direct.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
2020-12-05 19:26:32 +08:00
#if defined(_MSC_VER) && _MSC_VER < 1700
#define __func__ ""
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
typedef unsigned char uint8_t;
2021-01-25 18:08:15 +08:00
typedef char int8_t;
2020-12-05 19:26:32 +08:00
typedef unsigned short uint16_t;
2021-01-25 18:08:15 +08:00
typedef short int16_t;
2020-12-05 19:26:32 +08:00
typedef unsigned int uint32_t;
2021-01-25 18:08:15 +08:00
typedef int int32_t;
2021-01-26 20:16:58 +08:00
typedef enum { false = 0, true = 1 } bool;
2020-12-05 19:26:32 +08:00
#else
#include <stdbool.h>
#include <stdint.h>
2020-12-22 17:44:59 +08:00
#include <ws2tcpip.h>
2020-12-05 19:26:32 +08:00
#endif
#include <process.h>
#include <winerror.h>
2020-12-05 19:26:32 +08:00
#include <winsock2.h>
2020-12-24 05:20:48 +08:00
// Protect from calls like std::snprintf in app code
// See https://github.com/cesanta/mongoose/issues/1047
#ifndef __cplusplus
2020-12-05 19:26:32 +08:00
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#ifndef strdup // For MSVC with _DEBUG, see #1359
2020-12-05 19:26:32 +08:00
#define strdup(x) _strdup(x)
#endif
#endif
2022-11-05 18:07:31 +08:00
#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")
2022-10-31 18:40:34 +08:00
#ifndef alloca
2022-11-05 18:07:31 +08:00
#define alloca(a) _alloca(a)
#endif
2022-10-31 18:40:34 +08:00
#endif
2022-11-05 18:07:31 +08:00
#define poll(a, b, c) WSAPoll((a), (b), (c))
#define closesocket(x) closesocket(x)
2020-12-05 19:26:32 +08:00
typedef int socklen_t;
#define MG_DIRSEP '\\'
#ifndef MG_PATH_MAX
#define MG_PATH_MAX FILENAME_MAX
#endif
2023-02-01 20:25:30 +08:00
#ifndef SO_EXCLUSIVEADDRUSE
#define SO_EXCLUSIVEADDRUSE ((int) (~SO_REUSEADDR))
#endif
2021-07-24 17:35:48 +08:00
2023-02-01 20:25:30 +08:00
#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))
2021-12-23 02:04:36 +08:00
#define realpath(a, b) _fullpath((b), (a), MG_PATH_MAX)
#define sleep(x) Sleep(x)
#define mkdir(a, b) _mkdir(a)
2021-12-23 02:04:36 +08:00
2020-12-05 19:26:32 +08:00
#ifndef S_ISDIR
#define S_ISDIR(x) (((x) &_S_IFMT) == _S_IFDIR)
#endif
2022-02-14 19:32:01 +08:00
#ifndef MG_ENABLE_DIRLIST
#define MG_ENABLE_DIRLIST 1
#endif
#endif
2022-03-30 14:56:44 +08:00
#if MG_ARCH == MG_ARCH_ZEPHYR
#include <zephyr/kernel.h>
2022-03-30 14:56:44 +08:00
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <zephyr/net/socket.h>
2022-03-30 14:56:44 +08:00
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#define MG_PUTCHAR(x) printk("%c", x)
#ifndef strdup
#define strdup(s) ((char *) mg_strdup(mg_str(s)).ptr)
#endif
2022-03-30 14:56:44 +08:00
#define strerror(x) zsock_gai_strerror(x)
#define FD_CLOEXEC 0
#define F_SETFD 0
#define MG_ENABLE_SSI 0
2022-03-30 14:56:44 +08:00
int rand(void);
int sscanf(const char *, const char *, ...);
#endif
#if defined(MG_ENABLE_FREERTOS_TCP) && MG_ENABLE_FREERTOS_TCP
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <FreeRTOS.h>
#include <list.h>
#include <task.h>
#include <FreeRTOS_IP.h>
#include <FreeRTOS_Sockets.h>
#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 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__)
#include <sys/stat.h>
#include <sys/time.h>
#else
struct timeval {
time_t tv_sec;
long tv_usec;
};
#endif
#include <lwip/sockets.h>
#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 <rl_net.h>
#define MG_ENABLE_CUSTOM_MILLIS 1
#define closesocket(x) closesocket(x)
#define mkdir(a, b) (-1)
2023-02-01 20:25:30 +08:00
#define TCP_NODELAY SO_KEEPALIVE
2023-02-01 20:25:30 +08:00
#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)
#define MG_SOCK_INTR(fd) 0
#define socklen_t int
#endif
2022-06-19 16:04:22 +08:00
#ifndef MG_ENABLE_LOG
#define MG_ENABLE_LOG 1
#endif
#ifndef MG_ENABLE_TCPIP
#define MG_ENABLE_TCPIP 0 // Mongoose built-in network stack
#endif
#ifndef MG_ENABLE_ATOMIC
#define MG_ENABLE_ATOMIC 0 // Required by mg_queue
#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
2022-05-19 04:19:21 +08:00
#endif
#ifndef MG_ENABLE_POLL
#define MG_ENABLE_POLL 0
#endif
2022-08-03 22:07:16 +08:00
#ifndef MG_ENABLE_EPOLL
#define MG_ENABLE_EPOLL 0
#endif
2022-01-18 15:44:30 +08:00
#ifndef MG_ENABLE_FATFS
#define MG_ENABLE_FATFS 0
#endif
#ifndef MG_ENABLE_MBEDTLS
#define MG_ENABLE_MBEDTLS 0
#endif
#ifndef MG_ENABLE_OPENSSL
#define MG_ENABLE_OPENSSL 0
#endif
#ifndef MG_ENABLE_CUSTOM_TLS
#define MG_ENABLE_CUSTOM_TLS 0
#endif
#ifndef MG_ENABLE_SSI
2022-05-09 04:54:15 +08:00
#define MG_ENABLE_SSI 0
#endif
#ifndef MG_ENABLE_IPV6
#define MG_ENABLE_IPV6 0
#endif
#ifndef MG_ENABLE_MD5
2022-09-28 19:42:20 +08:00
#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
2022-02-14 19:32:01 +08:00
#define MG_ENABLE_DIRLIST 0
#endif
#ifndef MG_ENABLE_CUSTOM_RANDOM
#define MG_ENABLE_CUSTOM_RANDOM 0
#endif
2022-04-05 01:14:59 +08:00
#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_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 (3 * 1024 * 1024) // 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
2022-05-12 22:07:02 +08:00
#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
2022-11-05 18:07:31 +08:00
#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
2022-08-03 22:07:16 +08:00
#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
2022-01-11 01:30:51 +08:00
2020-12-05 19:26:32 +08:00
struct mg_str {
2021-09-15 14:43:48 +08:00
const char *ptr; // Pointer to string data
size_t len; // String len
};
2020-12-05 19:26:32 +08:00
#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)
2020-12-05 19:26:32 +08:00
struct mg_str mg_str(const char *s);
2020-12-07 11:47:37 +08:00
struct mg_str mg_str_n(const char *s, size_t n);
2020-12-05 19:26:32 +08:00
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);
2022-05-31 17:41:14 +08:00
bool mg_split(struct mg_str *s, struct mg_str *k, struct mg_str *v, char delim);
2022-02-10 19:56:55 +08:00
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);
int mg_check_ip_acl(struct mg_str acl, uint32_t remote_ip);
int64_t mg_to64(struct mg_str str);
2022-04-12 17:20:43 +08:00
uint64_t mg_tou64(struct mg_str str);
char *mg_remove_double_dots(char *s);
2022-07-28 17:18:17 +08:00
#if MG_ENABLE_ATOMIC
#include <stdatomic.h>
#elif !defined(_Atomic)
#define _Atomic
#endif
// Single producer, single consumer non-blocking queue
//
// Producer:
// void *buf;
// while (mg_queue_space(q, &buf) < len) WAIT(); // Wait for free space
// memcpy(buf, data, len); // Copy data to the queue
// mg_queue_add(q, len); // Advance q->head
//
// Consumer:
// void *buf;
// while ((len = mg_queue_next(q, &buf)) == MG_QUEUE_EMPTY) WAIT();
// mg_hexdump(buf, len); // Handle message
// mg_queue_del(q); // Delete message
//
struct mg_queue {
char *buf;
size_t len;
volatile _Atomic size_t tail;
volatile _Atomic size_t head;
};
#define MG_QUEUE_EMPTY ((size_t) ~0ul) // Next message size when queue is empty
void mg_queue_add(struct mg_queue *, size_t len); // Advance head
void mg_queue_del(struct mg_queue *); // Advance tail
size_t mg_queue_space(struct mg_queue *, char **); // Get free space
size_t mg_queue_next(struct mg_queue *, char **); // Get next message size
typedef void (*mg_pfn_t)(char, void *); // Output function
2022-07-27 07:46:05 +08:00
typedef size_t (*mg_pm_t)(mg_pfn_t, void *, va_list *); // %M printer
2022-06-28 07:45:52 +08:00
2022-08-14 03:34:20 +08:00
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
2022-06-28 07:45:52 +08:00
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, ...);
2022-08-13 22:37:55 +08:00
char *mg_vmprintf(const char *fmt, va_list *ap);
2022-06-28 07:45:52 +08:00
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, ...);
2022-08-13 22:37:55 +08:00
// %M print helper functions
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
2022-06-28 07:45:52 +08:00
2020-12-05 19:26:32 +08:00
enum { MG_LL_NONE, MG_LL_ERROR, MG_LL_INFO, MG_LL_DEBUG, MG_LL_VERBOSE };
2022-06-09 05:09:11 +08:00
void mg_log(const char *fmt, ...);
bool mg_log_prefix(int ll, const char *file, int line, const char *fname);
2022-08-01 18:19:32 +08:00
void mg_log_set(int log_level);
void mg_hexdump(const void *buf, size_t len);
2022-08-13 22:37:55 +08:00
void mg_log_set_fn(mg_pfn_t fn, void *param);
2022-01-24 10:20:45 +08:00
2022-06-19 16:04:22 +08:00
#if MG_ENABLE_LOG
#define MG_LOG(level, args) \
2020-12-05 19:26:32 +08:00
do { \
if (mg_log_prefix((level), __FILE__, __LINE__, __func__)) mg_log args; \
} while (0)
2022-06-19 16:04:22 +08:00
#else
#define MG_LOG(level, args) \
do { \
if (0) mg_log args; \
} while (0)
#endif
2022-01-24 10:20:45 +08:00
#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)
2021-12-22 05:50:18 +08:00
2020-12-05 19:26:32 +08:00
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
2022-05-15 21:29:34 +08:00
#define MG_TIMER_ONCE 0 // Call function once
#define MG_TIMER_REPEAT 1 // Call function periodically
2021-11-06 19:29:56 +08:00
#define MG_TIMER_RUN_NOW 2 // Call immediately when timer is set
2020-12-05 19:26:32 +08:00
void (*fn)(void *); // Function to call
2021-03-11 21:15:53 +08:00
void *arg; // Function argument
2022-05-15 21:29:34 +08:00
struct mg_timer *next; // Linkage
2020-12-05 19:26:32 +08:00
};
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
};
2022-01-19 17:25:01 +08:00
extern struct mg_fs mg_fs_posix; // POSIX open/close/read/write/seek
2022-05-25 20:28:25 +08:00
extern struct mg_fs mg_fs_packed; // Packed FS, see examples/device-dashboard
2022-01-19 17:25:01 +08:00
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, ...);
2021-12-22 02:16:12 +08:00
2023-01-31 22:56:46 +08:00
2021-07-30 20:19:20 +08:00
void mg_random(void *buf, size_t len);
char *mg_random_str(char *buf, size_t len);
2020-12-05 19:26:32 +08:00
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);
2020-12-05 19:26:32 +08:00
#define mg_htons(x) mg_ntohs(x)
#define mg_htonl(x) mg_ntohl(x)
#define MG_U32(a, b, c, d) \
2022-12-19 19:43:25 +08:00
(((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]
2021-04-09 23:55:12 +08:00
// Linked list management macros
2020-12-05 19:26:32 +08:00
#define LIST_ADD_HEAD(type_, head_, elem_) \
do { \
(elem_)->next = (*head_); \
*(head_) = (elem_); \
} while (0)
2020-12-05 19:26:32 +08:00
#define LIST_ADD_TAIL(type_, head_, elem_) \
do { \
type_ **h = head_; \
while (*h != NULL) h = &(*h)->next; \
*h = (elem_); \
} while (0)
2020-12-05 19:26:32 +08:00
#define LIST_DELETE(type_, head_, elem_) \
do { \
type_ **h = head_; \
while (*h != (elem_)) h = &(*h)->next; \
*h = (elem_)->next; \
} while (0)
2020-12-05 19:26:32 +08:00
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);
2022-07-02 00:28:06 +08:00
2020-12-05 19:26:32 +08:00
struct mg_iobuf {
2021-08-30 20:06:45 +08:00
unsigned char *buf; // Pointer to stored data
2021-08-28 15:08:54 +08:00
size_t size; // Total size available
size_t len; // Current number of bytes
2022-08-01 19:53:25 +08:00
size_t align; // Alignment during allocation
};
2022-08-01 19:53:25 +08:00
int mg_iobuf_init(struct mg_iobuf *, size_t, size_t);
2021-01-29 20:32:34 +08:00
int mg_iobuf_resize(struct mg_iobuf *, size_t);
2020-12-05 19:26:32 +08:00
void mg_iobuf_free(struct mg_iobuf *);
2022-08-01 19:53:25 +08:00
size_t mg_iobuf_add(struct mg_iobuf *, size_t, const void *, size_t);
2021-08-27 17:25:24 +08:00
size_t mg_iobuf_del(struct mg_iobuf *, size_t ofs, size_t len);
2020-12-05 19:26:32 +08:00
int mg_base64_update(unsigned char p, char *to, int len);
int mg_base64_final(char *to, int len);
int mg_base64_encode(const unsigned char *p, int n, char *to);
int mg_base64_decode(const char *src, int n, char *dst);
2020-12-05 19:26:32 +08:00
typedef struct {
uint32_t buf[4];
uint32_t bits[2];
unsigned char in[64];
} mg_md5_ctx;
2020-12-05 19:26:32 +08:00
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]);
2020-12-05 19:26:32 +08:00
typedef struct {
uint32_t state[5];
uint32_t count[2];
unsigned char buffer[64];
} mg_sha1_ctx;
2020-12-05 19:26:32 +08:00
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 *);
2020-12-05 19:26:32 +08:00
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
2022-09-10 00:09:18 +08:00
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
2022-09-20 18:34:22 +08:00
MG_EV_TLS_HS, // TLS handshake succeeded NULL
2022-09-10 00:09:18 +08:00
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_HTTP_CHUNK, // HTTP chunk (partial msg) 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
2022-09-10 00:09:18 +08:00
MG_EV_SNTP_TIME, // SNTP time received uint64_t *epoch_millis
2022-09-19 20:28:07 +08:00
MG_EV_USER // Starting ID for user events
};
2020-12-23 18:15:09 +08:00
2020-12-22 17:44:59 +08:00
struct mg_dns {
const char *url; // DNS server URL
struct mg_connection *c; // DNS server connection
};
2020-12-05 19:26:32 +08:00
struct mg_addr {
2020-12-21 00:55:33 +08:00
uint16_t port; // TCP or UDP port in network byte order
uint32_t ip; // IP address in network byte order
uint8_t ip6[16]; // IPv6 address
bool is_ip6; // True when address is IPv6 address
2020-12-05 19:26:32 +08:00
};
2020-12-22 17:44:59 +08:00
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
2022-04-23 03:44:53 +08:00
bool use_dns6; // Use DNS6 server by default, see #1532
2020-12-22 17:44:59 +08:00
unsigned long nextid; // Next connection ID
unsigned long timerid; // Next timer ID
2021-03-01 00:40:27 +08:00
void *userdata; // Arbitrary user data pointer
uint16_t mqtt_id; // MQTT IDs for pub/sub
void *active_dns_requests; // DNS requests in progress
struct mg_timer *timers; // Active timers
2022-08-03 22:07:16 +08:00
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
2020-12-22 17:44:59 +08:00
SocketSet_t ss; // NOTE(lsm): referenced from socket struct
#endif
};
2020-12-05 19:26:32 +08:00
struct mg_connection {
struct mg_connection *next; // Linkage in struct mg_mgr :: connections
struct mg_mgr *mgr; // Our container
2022-02-23 06:00:55 +08:00
struct mg_addr loc; // Local address
struct mg_addr rem; // Remote address
2020-12-05 19:26:32 +08:00
void *fd; // Connected socket, or LWIP data
2020-12-21 20:26:44 +08:00
unsigned long id; // Auto-incrementing unique connection ID
2020-12-05 19:26:32 +08:00
struct mg_iobuf recv; // Incoming data
struct mg_iobuf send; // Outgoing data
mg_event_handler_t fn; // User-specified event handler function
2021-03-11 21:15:53 +08:00
void *fn_data; // User-specified function parameter
2020-12-05 19:26:32 +08:00
mg_event_handler_t pfn; // Protocol-specific handler function
void *pfn_data; // Protocol-specific function parameter
char data[MG_DATA_SIZE]; // Arbitrary connection data
2020-12-05 19:26:32 +08:00
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
2021-03-11 21:15:53 +08:00
unsigned is_resolving : 1; // Non-blocking DNS resolution is in progress
2023-02-07 10:10:30 +08:00
unsigned is_arplooking : 1; // Non-blocking ARP resolution is in progress
2020-12-05 19:26:32 +08:00
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
2020-12-05 19:26:32 +08:00
unsigned is_hexdumping : 1; // Hexdump in/out traffic
2020-12-07 05:12:05 +08:00
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
2020-12-05 19:26:32 +08:00
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);
2022-04-22 21:42:07 +08:00
struct mg_connection *mg_wrapfd(struct mg_mgr *mgr, int fd,
mg_event_handler_t fn, void *fn_data);
2021-10-22 21:00:31 +08:00
void mg_connect_resolved(struct mg_connection *);
bool mg_send(struct mg_connection *, const void *, size_t);
2022-02-11 01:11:03 +08:00
size_t mg_printf(struct mg_connection *, const char *fmt, ...);
2022-09-23 15:59:02 +08:00
size_t mg_vprintf(struct mg_connection *, const char *fmt, va_list *ap);
2020-12-21 00:55:33 +08:00
bool mg_aton(struct mg_str str, struct mg_addr *addr);
int mg_mkpipe(struct mg_mgr *, mg_event_handler_t, void *, bool udp);
2022-02-23 05:14:29 +08:00
// These functions are used to integrate with custom network stacks
2022-02-23 18:51:01 +08:00
struct mg_connection *mg_alloc_conn(struct mg_mgr *);
2022-02-23 11:06:02 +08:00
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);
2022-02-23 05:14:29 +08:00
2022-09-09 18:11:53 +08:00
// 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);
2021-07-29 04:11:07 +08:00
2021-12-22 02:16:12 +08:00
2020-12-05 19:26:32 +08:00
struct mg_http_header {
2021-09-15 14:43:48 +08:00
struct mg_str name; // Header name
struct mg_str value; // Header value
};
2020-12-05 19:26:32 +08:00
struct mg_http_message {
2020-12-25 23:04:43 +08:00
struct mg_str method, uri, query, proto; // Request/response line
2020-12-05 19:26:32 +08:00
struct mg_http_header headers[MG_MAX_HTTP_HEADERS]; // Headers
2020-12-25 23:04:43 +08:00
struct mg_str body; // Body
struct mg_str head; // Request + headers
struct mg_str chunk; // Chunk for chunked encoding, or partial body
struct mg_str message; // Request + headers + body
2020-12-05 19:26:32 +08:00
};
// Parameter for mg_http_serve_dir()
struct mg_http_serve_opts {
2021-07-24 09:44:25 +08:00
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
2021-07-29 04:11:07 +08:00
const char *mime_types; // Extra mime types, ext1=type1,ext2=type2,..
2022-06-01 06:44:03 +08:00
const char *page404; // Path to the 404 page, or NULL by default
2021-07-29 04:11:07 +08:00
struct mg_fs *fs; // Filesystem implementation. Use NULL for POSIX
};
2021-03-15 21:20:53 +08:00
// 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
2021-03-17 15:43:29 +08:00
struct mg_str body; // Part contents
2021-03-15 21:20:53 +08:00
};
2020-12-05 19:26:32 +08:00
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);
2020-12-05 19:26:32 +08:00
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 *);
2021-07-29 04:11:07 +08:00
void mg_http_serve_file(struct mg_connection *, struct mg_http_message *hm,
const char *path, const struct mg_http_serve_opts *);
2020-12-18 06:45:22 +08:00
void mg_http_reply(struct mg_connection *, int status_code, const char *headers,
const char *body_fmt, ...);
2020-12-05 19:26:32 +08:00
struct mg_str *mg_http_get_header(struct mg_http_message *, const char *name);
2022-06-18 11:23:56 +08:00
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);
2020-12-05 19:26:32 +08:00
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);
2020-12-05 19:26:32 +08:00
bool mg_http_match_uri(const struct mg_http_message *, const char *glob);
2022-07-01 04:54:50 +08:00
long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm,
struct mg_fs *fs, const char *path, size_t max_size);
2020-12-05 19:26:32 +08:00
void mg_http_bauth(struct mg_connection *, const char *user, const char *pass);
2021-03-17 15:43:29 +08:00
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);
2022-10-28 22:35:40 +08:00
void mg_hello(const char *url);
2020-12-05 19:26:32 +08:00
void mg_http_serve_ssi(struct mg_connection *c, const char *root,
const char *fullpath);
2020-12-05 19:26:32 +08:00
2020-12-05 19:26:32 +08:00
struct mg_tls_opts {
2021-01-30 21:03:11 +08:00
const char *ca; // CA certificate file. For both listeners and clients
const char *crl; // Certificate Revocation List. For clients
2021-01-30 21:03:11 +08:00
const char *cert; // Certificate
const char *certkey; // Certificate key
const char *ciphers; // Cipher list
struct mg_str srvname; // If not empty, enables server name verification
struct mg_fs *fs; // FS API for reading certificate files
2020-12-05 19:26:32 +08:00
};
void mg_tls_init(struct mg_connection *, const struct mg_tls_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);
2022-04-12 16:38:25 +08:00
size_t mg_tls_pending(struct mg_connection *);
void mg_tls_handshake(struct mg_connection *);
2022-01-24 10:20:45 +08:00
#if MG_ENABLE_MBEDTLS
#include <mbedtls/debug.h>
#include <mbedtls/net_sockets.h>
#include <mbedtls/ssl.h>
struct mg_tls {
char *cafile; // CA certificate path
mbedtls_x509_crt ca; // Parsed CA certificate
mbedtls_x509_crt cert; // Parsed certificate
mbedtls_ssl_context ssl; // SSL/TLS context
mbedtls_ssl_config conf; // SSL-TLS config
mbedtls_pk_context pk; // Private key context
};
#endif
#if MG_ENABLE_OPENSSL
#include <openssl/err.h>
#include <openssl/ssl.h>
struct mg_tls {
SSL_CTX *ctx;
SSL *ssl;
};
#endif
2020-12-05 19:26:32 +08:00
#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
2020-12-05 19:26:32 +08:00
struct mg_ws_message {
2021-09-15 14:43:48 +08:00
struct mg_str data; // Websocket message data
uint8_t flags; // Websocket message flags
2020-12-05 19:26:32 +08:00
};
2020-12-05 19:26:32 +08:00
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);
2022-06-05 21:59:50 +08:00
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 *);
2020-12-05 19:26:32 +08:00
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);
2021-12-22 05:50:18 +08:00
int64_t mg_sntp_parse(const unsigned char *buf, size_t len);
2020-12-16 04:29:47 +08:00
#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
2022-06-28 18:31:13 +08:00
#define MQTT_CMD_AUTH 15
2020-12-16 04:29:47 +08:00
2022-07-02 02:15:38 +08:00
enum { MQTT_OK, MQTT_INCOMPLETE, MQTT_MALFORMED };
2020-12-05 19:26:32 +08:00
struct mg_mqtt_opts {
struct mg_str user; // Username, can be empty
struct mg_str pass; // Password, can be empty
2021-09-15 14:43:48 +08:00
struct mg_str client_id; // Client ID
struct mg_str will_topic; // Will topic
struct mg_str will_message; // Will message
uint8_t will_qos; // Will message quality of service
2022-06-28 18:31:13 +08:00
uint8_t version; // Can be 4 (3.1.1), or 5. If 0, assume 4.
uint16_t keepalive; // Keep-alive timer in seconds
2021-09-15 14:43:48 +08:00
bool will_retain; // Retain last will
bool clean; // Use clean session, 0 or 1
};
2020-12-05 19:26:32 +08:00
struct mg_mqtt_message {
2021-06-11 02:15:50 +08:00
struct mg_str topic; // Parsed topic
struct mg_str data; // Parsed message
struct mg_str dgram; // Whole MQTT datagram, including headers
2020-12-16 04:29:47 +08:00
uint16_t id; // Set 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
};
2020-12-05 19:26:32 +08:00
struct mg_connection *mg_mqtt_connect(struct mg_mgr *, const char *url,
const struct mg_mqtt_opts *opts,
2020-12-05 19:26:32 +08:00
mg_event_handler_t fn, void *fn_data);
2020-12-16 04:29:47 +08:00
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, struct mg_str topic,
struct mg_str data, int qos, bool retain);
void mg_mqtt_sub(struct mg_connection *, struct mg_str topic, int qos);
2022-06-28 18:31:13 +08:00
int mg_mqtt_parse(const uint8_t *, size_t, uint8_t, struct mg_mqtt_message *);
2020-12-16 04:29:47 +08:00
void mg_mqtt_send_header(struct mg_connection *, uint8_t cmd, uint8_t flags,
uint32_t len);
2021-03-07 20:21:59 +08:00
void mg_mqtt_ping(struct mg_connection *);
void mg_mqtt_pong(struct mg_connection *);
void mg_mqtt_disconnect(struct mg_connection *);
2020-12-22 17:44:59 +08:00
// 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.
2020-12-05 19:26:32 +08:00
struct mg_dns_message {
2020-12-22 17:44:59 +08:00
uint16_t txnid; // Transaction ID
bool resolved; // Resolve successful, addr is set
struct mg_addr addr; // Resolved address
char name[256]; // Host name
2020-12-05 19:26:32 +08:00
};
2020-12-28 13:25:29 +08:00
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
};
2022-01-07 23:00:10 +08:00
void mg_resolve(struct mg_connection *, const char *url);
2020-12-22 17:44:59 +08:00
void mg_resolve_cancel(struct mg_connection *);
2020-12-21 00:55:33 +08:00
bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *);
2020-12-28 13:25:29 +08:00
size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs,
bool is_question, struct mg_dns_rr *);
2022-05-19 04:19:21 +08:00
2022-06-12 00:29:45 +08:00
#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 };
2022-07-30 14:55:26 +08:00
int mg_json_get(struct mg_str json, const char *path, int *toklen);
2022-06-12 00:29:45 +08:00
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);
2022-07-01 03:03:02 +08:00
long mg_json_get_long(struct mg_str json, const char *path, long dflt);
2022-06-12 00:29:45 +08:00
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);
2022-06-12 00:29:45 +08:00
2022-07-28 17:18:17 +08:00
2022-07-27 07:46:05 +08:00
// JSON-RPC request descriptor
struct mg_rpc_req {
2022-08-01 05:51:59 +08:00
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]}
2022-07-27 07:46:05 +08:00
};
2022-08-01 05:51:59 +08:00
// 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,
2022-07-27 07:46:05 +08:00
void (*handler)(struct mg_rpc_req *), void *handler_data);
2022-08-01 05:51:59 +08:00
void mg_rpc_del(struct mg_rpc **head, void (*handler)(struct mg_rpc_req *));
2022-07-30 14:55:26 +08:00
void mg_rpc_process(struct mg_rpc_req *);
2022-07-27 07:46:05 +08:00
// 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);
2022-06-12 00:29:45 +08:00
struct mg_tcpip_if; // MIP network interface
2022-12-19 19:43:25 +08:00
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
2022-05-19 04:19:21 +08:00
};
2022-11-09 21:11:22 +08:00
// Receive queue - single producer, single consumer queue. Interrupt-based
// drivers copy received frames to the queue in interrupt context.
// mg_tcpip_poll() function runs in event loop context, reads from the queue
2022-11-09 21:11:22 +08:00
struct queue {
uint8_t *buf;
size_t len;
volatile size_t tail, head;
2022-05-19 04:19:21 +08:00
};
2022-11-09 21:11:22 +08:00
// 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 rx; // Output (TX) buffer
struct mg_str tx; // Input (RX) buffer
bool enable_dhcp_client; // Enable DCHP client
bool enable_dhcp_server; // Enable DCHP server
struct mg_tcpip_driver *driver; // Low level driver
void *driver_data; // Driver-specific data
struct mg_mgr *mgr; // Mongoose event manager
struct queue queue; // Set queue.len for interrupt based drivers
2022-11-09 21:11:22 +08:00
// Internal state, user can use it but should not change it
2023-02-07 10:10:30 +08:00
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
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 MIP_STATE_DOWN 0 // Interface is down
#define MIP_STATE_UP 1 // Interface is up
#define MIP_STATE_READY 2 // Interface is up and has IP
2022-11-09 21:11:22 +08:00
};
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);
size_t mg_tcpip_qread(void *buf, struct mg_tcpip_if *ifp);
// conveniency rx function for IRQ-driven drivers
size_t mg_tcpip_driver_rx(void *buf, size_t len, struct mg_tcpip_if *ifp);
2022-05-19 04:19:21 +08:00
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;
// 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
};
2022-06-09 19:39:48 +08:00
#if MG_ENABLE_TCPIP
2023-02-04 03:32:38 +08:00
#if !defined(MG_ENABLE_DRIVER_STM32H) && !defined(MG_ENABLE_DRIVER_TM4C)
#define MG_ENABLE_DRIVER_STM32 1
#else
2023-02-04 03:32:38 +08:00
#define MG_ENABLE_DRIVER_STM32 0
#endif
#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
// ipg_clk MSCR mdc_cr VALUE
// -------------------------------------
// -1 <-- tell driver to guess the value
// 25 MHz 0x04 0
// 33 MHz 0x06 1
// 40 MHz 0x07 2
// 50 MHz 0x09 3
// 66 MHz 0x0D 4 <-- value for iMXRT1020-EVK at max freq.
int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4
};
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 {
2023-02-04 03:32:38 +08:00
// 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