diff options
Diffstat (limited to 'src/mongoose.h')
| -rw-r--r-- | src/mongoose.h | 1117 |
1 files changed, 1117 insertions, 0 deletions
diff --git a/src/mongoose.h b/src/mongoose.h new file mode 100644 index 0000000..90a8a1f --- /dev/null +++ b/src/mongoose.h @@ -0,0 +1,1117 @@ +// Copyright (c) 2004-2013 Sergey Lyubka +// Copyright (c) 2013-2021 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/ + +#ifndef MONGOOSE_H +#define MONGOOSE_H + +#define MG_VERSION "7.5" + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifndef MG_ENABLE_SOCKET +#define MG_ENABLE_SOCKET 1 +#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 +#define MG_ENABLE_SSI 1 +#endif + +#ifndef MG_ENABLE_IPV6 +#define MG_ENABLE_IPV6 0 +#endif + +#ifndef MG_ENABLE_LOG +#define MG_ENABLE_LOG 1 +#endif + +#ifndef MG_ENABLE_MD5 +#define MG_ENABLE_MD5 0 +#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_PACKED_FS +#define MG_ENABLE_PACKED_FS 0 +#endif + +// Granularity of the send/recv IO buffer growth +#ifndef MG_IO_SIZE +#define MG_IO_SIZE 2048 +#endif + +// Maximum size of the recv IO buffer +#ifndef MG_MAX_RECV_BUF_SIZE +#define MG_MAX_RECV_BUF_SIZE (3 * 1024 * 1024) +#endif + +#ifndef MG_MAX_HTTP_HEADERS +#define MG_MAX_HTTP_HEADERS 40 +#endif + +#ifndef MG_HTTP_INDEX +#define MG_HTTP_INDEX "index.html" +#endif + +#ifndef MG_PATH_MAX +#define MG_PATH_MAX PATH_MAX +#endif + +#ifndef MG_SOCK_LISTEN_BACKLOG_SIZE +#define MG_SOCK_LISTEN_BACKLOG_SIZE 128 +#endif + + +#define MG_ARCH_CUSTOM 0 +#define MG_ARCH_UNIX 1 +#define MG_ARCH_WIN32 2 +#define MG_ARCH_ESP32 3 +#define MG_ARCH_ESP8266 4 +#define MG_ARCH_FREERTOS_TCP 5 +#define MG_ARCH_FREERTOS_LWIP 6 +#define MG_ARCH_AZURERTOS 7 + +#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(ESP_PLATFORM) +#define MG_ARCH MG_ARCH_ESP32 +#elif defined(FREERTOS_IP_H) +#define MG_ARCH MG_ARCH_FREERTOS_TCP +#elif defined(AZURE_RTOS_THREADX) +#define MG_ARCH MG_ARCH_AZURERTOS +#endif + +#if !defined(MG_ARCH) +#error "MG_ARCH is not specified and we couldn't guess it." +#endif +#endif // !defined(MG_ARCH) + +#if !defined(PRINTF_LIKE) +#if defined(__GNUC__) || defined(__clang__) || defined(__TI_COMPILER_VERSION__) +#define PRINTF_LIKE(f, a) __attribute__((format(printf, f, a))) +#else +#define PRINTF_LIKE(f, a) +#endif +#endif + +#if MG_ARCH == MG_ARCH_CUSTOM +#include <mongoose_custom.h> +#endif + + + + + + + + + +#if MG_ARCH == MG_ARCH_AZURERTOS + +#include <stdarg.h> +#include <stdint.h> +#include <stdbool.h> +#include <time.h> +#include <stdio.h> + +#include <tx_api.h> +#include <fx_api.h> + +#include <tx_port.h> +#include <nx_port.h> +#include <nx_api.h> +#include <nx_bsd.h> + +#ifdef __REDLIB__ +#define va_copy(d,s)__builtin_va_copy(d,s) +#endif + +#define PATH_MAX FX_MAXIMUM_PATH +#define MG_DIRSEP '\\' + +#define socklen_t int +#define closesocket(x) soc_close(x) +#define gmtime_r(a, b) gmtime(a) +#define MG_INT64_FMT "%lld" + +static __inline struct tm *localtime_r(time_t *t, struct tm *tm) { + (void) tm; + return localtime(t); +} + +#undef FOPEN_MAX + +#endif + + +#if MG_ARCH == MG_ARCH_ESP32 + +#include <ctype.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#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> + +#undef MG_PATH_MAX +#undef MG_ENABLE_DIRLIST + +#define MG_DIRSEP '/' +#define MG_INT64_FMT "%lld" +#define MG_PATH_MAX 128 +#define MG_ENABLE_DIRLIST 1 + +#endif + + +#if MG_ARCH == MG_ARCH_ESP8266 + +#include <ctype.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <netdb.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stddef.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 <esp_system.h> + +#undef MG_PATH_MAX +#undef MG_ENABLE_DIRLIST + +#define MG_DIRSEP '/' +#define MG_INT64_FMT "%lld" +#define MG_PATH_MAX 128 +#define MG_ENABLE_DIRLIST 1 + +#endif + + +#if MG_ARCH == MG_ARCH_FREERTOS_LWIP + +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <string.h> +#include <stdio.h> + +#if defined(__GNUC__) +#include <sys/stat.h> +#include <sys/time.h> +#else +typedef long suseconds_t; +struct timeval { + time_t tv_sec; + suseconds_t tv_usec; +}; +#endif + +#include <FreeRTOS.h> +#include <task.h> + +#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 + +#if LWIP_POSIX_SOCKETS_IO_NAMES != 0 +// LWIP_POSIX_SOCKETS_IO_NAMES must be disabled in posix-compatible OS +// enviroment (freertos mimics to one) otherwise names like `read` and `write` +// conflict +#error LWIP_POSIX_SOCKETS_IO_NAMES must be set to 0 (in lwipopts.h) for FreeRTOS +#endif + +#define MG_INT64_FMT "%lld" +#define MG_DIRSEP '/' + +// Re-route calloc/free to the FreeRTOS's functions, don't use stdlib +static inline void *mg_calloc(int cnt, size_t size) { + void *p = pvPortMalloc(cnt * size); + if (p != NULL) memset(p, 0, size); + return p; +} +#define calloc(a, b) mg_calloc((a), (b)) +#define free(a) vPortFree(a) +#define malloc(a) pvPortMalloc(a) + +#define gmtime_r(a, b) gmtime(a) + +#endif // MG_ARCH == MG_ARCH_FREERTOS_LWIP + + +#if MG_ARCH == MG_ARCH_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 <FreeRTOS_IP.h> +#include <FreeRTOS_Sockets.h> +#include <task.h> + +#define MG_INT64_FMT "%lld" +#define MG_DIRSEP '/' + +// 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) (-1) + +// Re-route calloc/free to the FreeRTOS's functions, don't use stdlib +static inline void *mg_calloc(int cnt, size_t size) { + void *p = pvPortMalloc(cnt * size); + if (p != NULL) memset(p, 0, size); + return p; +} +#define calloc(a, b) mg_calloc((a), (b)) +#define free(a) vPortFree(a) +#define malloc(a) pvPortMalloc(a) + +#define gmtime_r(a, b) gmtime(a) + +#if !defined(__GNUC__) +// copied from GCC on ARM; for some reason useconds are signed +typedef long suseconds_t; +struct timeval { + time_t tv_sec; + suseconds_t tv_usec; +}; +#endif + +#ifndef EINPROGRESS +#define EINPROGRESS pdFREERTOS_ERRNO_EINPROGRESS +#endif +#ifndef EWOULDBLOCK +#define EWOULDBLOCK pdFREERTOS_ERRNO_EWOULDBLOCK +#endif +#ifndef EAGAIN +#define EAGAIN pdFREERTOS_ERRNO_EAGAIN +#endif +#ifndef EINTR +#define EINTR pdFREERTOS_ERRNO_EINTR +#endif + +#endif // MG_ARCH == MG_ARCH_FREERTOS_TCP + + +#if MG_ARCH == MG_ARCH_UNIX + +#define _DARWIN_UNLIMITED_SELECT 1 // No limit on file descriptors + +#include <arpa/inet.h> +#include <ctype.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <limits.h> +#include <netdb.h> +#include <netinet/tcp.h> +#include <signal.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> + +#define MG_DIRSEP '/' +#define MG_INT64_FMT "%" PRId64 +#undef MG_ENABLE_DIRLIST +#define MG_ENABLE_DIRLIST 1 + +#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 <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.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> + +#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 <stdbool.h> +#include <stdint.h> +#include <ws2tcpip.h> +#endif + +#include <winsock2.h> + +// 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 + +typedef unsigned suseconds_t; +typedef int socklen_t; +#define MG_DIRSEP '\\' +#ifndef PATH_MAX +#define PATH_MAX MAX_PATH +#endif +#ifndef EINPROGRESS +#define EINPROGRESS WSAEINPROGRESS +#endif +#ifndef EWOULDBLOCK +#define EWOULDBLOCK WSAEWOULDBLOCK +#endif + +#ifndef va_copy +#ifdef __va_copy +#define va_copy __va_copy +#else +#define va_copy(x, y) (x) = (y) +#endif +#endif +#ifndef S_ISDIR +#define S_ISDIR(x) (((x) &_S_IFMT) == _S_IFDIR) +#endif + +#define MG_INT64_FMT "%I64d" + +#undef MG_ENABLE_DIRLIST +#define MG_ENABLE_DIRLIST 1 + +// https://lgtm.com/rules/2154840805/ -gmtime, localtime, ctime and asctime +static __inline struct tm *gmtime_r(time_t *t, struct tm *tm) { + (void) tm; + return gmtime(t); +} + +static __inline struct tm *localtime_r(time_t *t, struct tm *tm) { + (void) tm; + return localtime(t); +} + +#endif + + +#include <ctype.h> +#include <string.h> + +struct mg_str { + const char *ptr; // Pointer to string data + size_t len; // String len +}; + +#define MG_NULL_STR \ + { NULL, 0 } + +// 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); + + + + + +#if MG_ENABLE_LOG +#define LOG(level, args) \ + do { \ + if (mg_log_prefix((level), __FILE__, __LINE__, __func__)) mg_log args; \ + } while (0) +enum { LL_NONE, LL_ERROR, LL_INFO, LL_DEBUG, LL_VERBOSE_DEBUG }; +bool mg_log_prefix(int ll, const char *file, int line, const char *fname); +void mg_log(const char *fmt, ...) PRINTF_LIKE(1, 2); +void mg_log_set(const char *spec); +void mg_log_set_callback(void (*fn)(const void *, size_t, void *), void *param); +#else +#define LOG(level, args) (void) 0 +#define mg_log_set(x) (void) (x) +#endif + + +struct mg_timer { + unsigned long period_ms; // Timer period in milliseconds + unsigned long expire; // Expiration timestamp in milliseconds + unsigned flags; // Possible flags values below +#define MG_TIMER_REPEAT 1 // Call function periodically, otherwise run once +#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 in g_timers list +}; + +extern struct mg_timer *g_timers; // Global list of timers + +void mg_timer_init(struct mg_timer *, unsigned long ms, unsigned, + void (*fn)(void *), void *); +void mg_timer_free(struct mg_timer *); +void mg_timer_poll(unsigned long current_time_ms); + + + + + +char *mg_file_read(const char *path, size_t *size); +bool mg_file_write(const char *path, const void *buf, size_t len); +bool mg_file_printf(const char *path, const char *fmt, ...); +void mg_random(void *buf, size_t len); +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); +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); +char *mg_hexdump(const void *buf, size_t len); +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_asprintf(char **buf, size_t size, const char *fmt, ...); +int mg_vasprintf(char **buf, size_t size, const char *fmt, va_list ap); +int64_t mg_to64(struct mg_str str); +int mg_check_ip_acl(struct mg_str acl, uint32_t remote_ip); +double mg_time(void); +unsigned long mg_millis(void); +void mg_usleep(unsigned long usecs); + +#define mg_htons(x) mg_ntohs(x) +#define mg_htonl(x) mg_ntohl(x) + +#ifndef EXTERN_C +#ifdef __cplusplus +#define EXTERN_C extern "C" +#else +#define EXTERN_C +#endif +#endif + +// Expands to a string representation of its argument: e.g. +// MG_STRINGIFY_LITERAL(5) expands to "5" +#if !defined(_MSC_VER) || _MSC_VER >= 1900 +#define MG_STRINGIFY_LITERAL(...) #__VA_ARGS__ +#else +#define MG_STRINGIFY_LITERAL(x) #x +#endif +// Expands to a string representation of its argument, which can be a macro: +// #define FOO 123 +// MG_STRINGIFY_MACRO(FOO) // Expands to 123 +#define MG_STRINGIFY_MACRO(x) MG_STRINGIFY_LITERAL(x) + +// 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) + + + + +enum { MG_FS_READ = 1, MG_FS_WRITE = 2, MG_FS_DIR = 4 }; + +// Filesystem API functions +// stat() returns MG_FS_* flags and populates file size and modification time +// list() calls fn() for every directory entry, allowing to list a directory +struct mg_fs { + int (*stat)(const char *path, size_t *size, time_t *mtime); + void (*list)(const char *path, void (*fn)(const char *, void *), void *); + struct mg_fd *(*open)(const char *path, int flags); // Open file + void (*close)(struct mg_fd *fd); // Close file + size_t (*read)(void *fd, void *buf, size_t len); // Read file + size_t (*write)(void *fd, const void *buf, size_t len); // Write file + size_t (*seek)(void *fd, size_t offset); // Set file position +}; + +// File descriptor +struct mg_fd { + void *fd; + struct mg_fs *fs; +}; + +extern struct mg_fs mg_fs_posix; // POSIX open/close/read/write/seek +extern struct mg_fs mg_fs_packed; // Packed FS, see examples/complete + + + +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); + + +#include <stddef.h> + +struct mg_iobuf { + unsigned char *buf; // Pointer to stored data + size_t size; // Total size available + size_t len; // Current number of bytes +}; + +int mg_iobuf_init(struct mg_iobuf *, 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); +size_t mg_iobuf_del(struct mg_iobuf *, size_t ofs, size_t len); + +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); + + + + +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 *); +void mg_hmac_sha1(const unsigned char *key, size_t key_len, + const unsigned char *text, size_t text_len, + unsigned char out[20]); + + +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 unsigned long *millis + MG_EV_RESOLVE, // Host name is resolved NULL + MG_EV_CONNECT, // Connection established NULL + MG_EV_ACCEPT, // Connection accepted NULL + MG_EV_READ, // Data received from socket struct mg_str * + 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 + MG_EV_SNTP_TIME, // SNTP time received struct timeval * + 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 { + 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 +}; + +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 + unsigned long nextid; // Next connection ID + void *userdata; // Arbitrary user data pointer +#if MG_ARCH == MG_ARCH_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 peer; // Remote address. For listeners, local 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 label[50]; // Arbitrary label + 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_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_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_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); +void mg_connect_resolved(struct mg_connection *); +bool mg_send(struct mg_connection *, const void *, size_t); +int mg_printf(struct mg_connection *, const char *fmt, ...); +int mg_vprintf(struct mg_connection *, const char *fmt, va_list ap); +char *mg_straddr(struct mg_connection *, char *, size_t); +bool mg_aton(struct mg_str str, struct mg_addr *addr); +char *mg_ntoa(const struct mg_addr *addr, char *buf, size_t len); + +struct mg_connection *mg_mkpipe(struct mg_mgr *, mg_event_handler_t, void *); +void mg_mgr_wakeup(struct mg_connection *pipe); + + + + + + + +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 chunk; // Chunk for chunked encoding, or partial body + 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,.. + 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, + struct mg_http_serve_opts *opts); +void mg_http_serve_file(struct mg_connection *, struct mg_http_message *hm, + const char *path, struct mg_http_serve_opts *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); +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); +int mg_http_upload(struct mg_connection *, struct mg_http_message *hm, + const char *dir); +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 *); + + +void mg_http_serve_ssi(struct mg_connection *c, const char *root, + const char *fullpath); + + + + + + +struct mg_tls_opts { + const char *ca; // CA certificate file. For both listeners and clients + const char *crl; // Certificate Revocation List. For clients + 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 +}; + +void mg_tls_init(struct mg_connection *, 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); +void mg_tls_handshake(struct mg_connection *); + + +#if MG_ENABLE_MBEDTLS + + + + +#include <mbedtls/debug.h> +#include <mbedtls/ssl.h> + +#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000 +#define RNG , rng_get, NULL +#else +#define RNG +#endif + +// Different versions have those in different files, so declare here +EXTERN_C int mbedtls_net_recv(void *, unsigned char *, size_t); +EXTERN_C int mbedtls_net_send(void *, const unsigned char *, size_t); + +struct mg_tls { + char *cafile; // CA certificate path + mbedtls_x509_crt ca; // Parsed CA certificate + mbedtls_x509_crl crl; // Parsed Certificate Revocation List + 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 + + +#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 char *buf, size_t len, int op); +size_t mg_ws_wrap(struct mg_connection *, size_t len, int op); + + + + +struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, const char *url, + mg_event_handler_t fn, void *fn_data); +void mg_sntp_send(struct mg_connection *c, unsigned long utc); +int mg_sntp_parse(const unsigned char *buf, size_t len, struct timeval *tv); + + + + + +#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 + +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 will_topic; // Will topic + struct mg_str will_message; // Will message + uint8_t qos; // Quality of service + bool will_retain; // Retain last will + bool clean; // Use clean session, 0 or 1 + uint16_t keepalive; // Keep-alive timer in seconds +}; + +struct mg_mqtt_message { + struct mg_str topic; // Parsed topic + struct mg_str data; // Parsed message + struct mg_str dgram; // Whole MQTT datagram, including headers + 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 +}; + +struct mg_connection *mg_mqtt_connect(struct mg_mgr *, const char *url, + 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, 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); +int mg_mqtt_parse(const uint8_t *buf, size_t len, struct mg_mqtt_message *m); +void mg_mqtt_send_header(struct mg_connection *, uint8_t cmd, uint8_t flags, + uint32_t len); +size_t mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic, + uint8_t *qos, size_t pos); +size_t mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic, + size_t pos); +void mg_mqtt_ping(struct mg_connection *); +void mg_mqtt_pong(struct mg_connection *); +void mg_mqtt_disconnect(struct mg_connection *); + + + + + +// 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 *, struct mg_str *, int); +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 *); +size_t mg_dns_decode_name(const uint8_t *, size_t, size_t, char *, size_t); + +#ifdef __cplusplus +} +#endif +#endif // MONGOOSE_H |
