From patchwork Sat Jun 15 19:11:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Glembotzki X-Patchwork-Id: 1948206 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=YiMTKhmI; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=nR0zlwa/; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::33e; helo=mail-wm1-x33e.google.com; envelope-from=swupdate+bncbdy5juxlviebb4osw6zqmgqe4swcxxi@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-wm1-x33e.google.com (mail-wm1-x33e.google.com [IPv6:2a00:1450:4864:20::33e]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W1mFS6xP8z23v2 for ; Sun, 16 Jun 2024 05:20:28 +1000 (AEST) Received: by mail-wm1-x33e.google.com with SMTP id 5b1f17b1804b1-42183fdd668sf19999495e9.2 for ; Sat, 15 Jun 2024 12:20:28 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718479220; cv=pass; d=google.com; s=arc-20160816; b=yAM72z1uDknUoj/VbDQotgTZk721xytrZgGjW/EL76mxKtyY2IbBDVpzwRR7fVP6mP R7qzhpGE0W2m2/x3yiYrpHLiS+tn7zLH0KHd20j8G6dnVk5frti9ni5ebkDwDeAv30nn j5gw/rIYboZViilkLsuNHJSkq+EiMNR1Pg26DVnpYcFZVrz9H+lcKM+LYQ+FcrEmHexU IMlxgRvE9GzIt69U1PUvASXzzSVBnooBqkJjWVJdfDhwJkTkW+DE6vNWqUZSRS0zHYlC KowK/gMWdx7HyRe5Pn7oW2K99RZMEUGlEJLxeVNvnzu3Qh1/CxCFAOXwTSNzR5yLzrxC cvng== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:dkim-signature :dkim-signature; bh=vOXamt+6Z+yoFmdQa+HnmQdoPpjUybLz8giUsCcqjlI=; fh=LC4YUyKRXHQn1YORf9EX34w4LtGzDZAicbsUbn7hTYM=; b=qdGWgud0K2PkB7du+OL6F8vNv1Xz91Mf2O+GNHLcMzE31a8RiPli/dk5fdzQmbcuYb /ODWbQyKznFKohRq/qE9eiymD6i2DBVdmBmeU29NaCg6J+CQj69p0bn1URulbcnLnoVM IrRBpf9pFiOOh64/dWeXwsk/rV7FN/SgSZIap6OiJss5D4l/ODLuzgq/gpsmIFy3JMmV XgI61RK/HrrDEN5eMubvJ6SZeRLQqwqLNJPtyVAChA8QbCIPiQZtXuZmh8tVl8FM/Sy9 uXvzvKicJDc7iNjAhjFmhtTsdF6TeiyO90bLpO5kj7+WURwrAYjYV7kIC8nSWNI+DvYk 8EYA==; darn=patchwork.ozlabs.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=axT6WPhT; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::62e as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1718479220; x=1719084020; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:sender:from:to:cc:subject:date:message-id :reply-to; bh=vOXamt+6Z+yoFmdQa+HnmQdoPpjUybLz8giUsCcqjlI=; b=YiMTKhmICDwKMCmxXSHgg+u3KUuvzclLVZK5Nez/R1QlyP1SWtVu3X5F/3ttAThBXh Px3UaoaT4hKH7WF6V8hPCBZziKda3XKUZP9M6H1hJFCtkAznxUUkxL82amhJ8ByHXdwz VxLJmtT3dPEXRYzGpgDcyRap3XATqxeXCc+tTfMwr6nqcAJa36NhbV5Yz2td1skLae+T YepPjQWYSgW1H8iaKZMz4wQaJwDqQrEtO0QOHxySQ233MyqLwN9A3GsVdTqdqG29IlFZ w9byrIbLcAE6f6nh34riUC4AGvYnosMd9fFQVJ7Pi+nVvWoSzBbcbzbUNQuxBHgS3Ic8 GFHg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718479220; x=1719084020; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=vOXamt+6Z+yoFmdQa+HnmQdoPpjUybLz8giUsCcqjlI=; b=nR0zlwa/rDkUuFkytodvqSDlxgygFs7bNom9IAnemRxXo7tuY5cy2Cv6dvVAKMTxv0 H2S7yDYJs1w8S+VIHgIyVIYuvEWEJU+C890evwIojYXKNCG/UL+jtV8L+EANfx37s9TG HWpxmYcgYR4lIoSJZdZWhnOQ9SsmFHL9TDm3vNX3SoSOq6W8pG3qUQW/iGKSJdQbemfm hOwLa7nYWMuq1GpC9gnhfr5/Sf+DJHQ45bVni1b0iUrhRr2hnFj9LiOm6aMZZyVnNIpS DO0KSxNQ6hiMXdv8Ji/pmpICCpeSCv77SKwCYN+jESgGEKVs0aDBS5AOwl+KBIBjnHoF YgMQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718479220; x=1719084020; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :x-beenthere:x-gm-message-state:sender:from:to:cc:subject:date :message-id:reply-to; bh=vOXamt+6Z+yoFmdQa+HnmQdoPpjUybLz8giUsCcqjlI=; b=h5oPLAwgOB7uWmeT46YRh5pjPXs+vgM0yhT94wDtpG+sgN9Rfo2RY5QEmlkldFHOQc fR53iVh6UEw46aUUYadp6QUcVWgOWGepF8q3YRrBKIQLQar4BfjiqTPw/TRmyobaIBkK z64JyPxtK9SI9w7hhlX0C8zg1MDRiF6rArYAEuj9D64TRCNkzOmroyHNMqIJLxFDG86H SZPKoAmSNuduQDFdHkrq96tAframU9a1ikniY45Q2eSs6NKL69zL4OwBlwlckl1tMyFC 1DnVi5fVqiu+gr0Rw/8MjJ8BmxL/jyqudUc/wur2m3K7pZfS6MvLsabEMs74ljuGq0Bb aohA== Sender: swupdate@googlegroups.com X-Forwarded-Encrypted: i=2; AJvYcCWXy6fXyLSVYcvthK2SLTKmgQrNVt44cwH9Tqq8sdl3jhYVg+pEgQufW3ddKxufQqbYsyvFfr2XWeQQ38pFnfEHykaDplZzZCb/lUxWbQ== X-Gm-Message-State: AOJu0YziyZhsfK7wu2CixZAO7fSuXuQhRACVNdwpi0w8IeBvpV3EAbka WbE7qYbTpAVMeYaF5huBha8JEISM9TWhYU0gSMJ9g+ZCaQztsRxj X-Google-Smtp-Source: AGHT+IExaHp6MLcAUvjP8lrFyf+eJi29kpwgDJl/Rej/KKzCeK8u7EewJ6BeSQOmKv5xP6Hgcw6oDQ== X-Received: by 2002:a05:600c:4e8b:b0:421:b16c:5bf5 with SMTP id 5b1f17b1804b1-4230481a6f4mr51039265e9.2.1718479218632; Sat, 15 Jun 2024 12:20:18 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a05:600c:4f83:b0:421:7e41:1870 with SMTP id 5b1f17b1804b1-422b6dc5d7dls12836345e9.0.-pod-prod-03-eu; Sat, 15 Jun 2024 12:20:16 -0700 (PDT) X-Received: by 2002:a05:600c:46ce:b0:422:5c5d:1b89 with SMTP id 5b1f17b1804b1-423047cc7c2mr53324665e9.0.1718479215012; Sat, 15 Jun 2024 12:20:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1718479214; cv=none; d=google.com; s=arc-20160816; b=U1WJsOrvWLWoTFqvDZfJmtdm7erR9d+PEL9QmgkGQJV7HpJ6PxISXQqffwNkqGMPSt u4/SrKYNmW+0H3vkGnCkI3QpfStbkh5P7JlQFTbNzpHXRXXbyGOU+O9QZTrbrodp9EIj 8ehbOAs95lCpobdnex16DxnAghY9KTsM2OeWevc+OfyS7bEBhaOAErVTT913fgc9QhnH JOcM01ZsceDd8jsapQhyXTB5OmIB/9vZBh64+a9Chb+DlB3fbin4IIX9Y6zhd2g6OUOn 4U9rxb3V3xGb8DnxQ2vxlBHSwmopo9+4mCUtyQ4UER0SUC519RCMXkUwxlLq1ixfJ1C0 +O7w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=jvG0uvNyncFa4cG1ZnDXb7XyqDFDHWWsKBb2I3oRu8s=; fh=zydHuzCQWrku2OPQyZfraJZFcOpEXLQ/YBcu3QNiBd0=; b=AJQ+pKg3k5w8W+OAZrNPJ4w+tInEtDAfcG++7aMJtl+B2Kh+5xqOd6CAfuKexwv0wK 6Y9RIGnoUtQ2SqMYz76GsWD+kR97mzaETT0SG6KLh1hh5fCPMpRBoYfj+0wVshC7VosR /6psWBdVnSYmF+7bzfrU7c9Gbch39Yp+nUWiyuzt93viRqDyymPeJguv7ltfjOdFfUbe jlpDss3CU+al32Q/4gykv3ylB1KqV7g6Yx/ddnNSl/jXeS74/cz6v/BeMxsRqpkvSG9p 42YIOsWCW3L9CC4Pxyb47lWmlydjaIwNyupJiPtb0CMopCiz1rR3uX4EWa4xVzZbkeT1 E4Zg==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=axT6WPhT; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::62e as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-ej1-x62e.google.com (mail-ej1-x62e.google.com. [2a00:1450:4864:20::62e]) by gmr-mx.google.com with ESMTPS id 5b1f17b1804b1-422855708b8si572635e9.1.2024.06.15.12.20.14 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 15 Jun 2024 12:20:14 -0700 (PDT) Received-SPF: pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::62e as permitted sender) client-ip=2a00:1450:4864:20::62e; Received: by mail-ej1-x62e.google.com with SMTP id a640c23a62f3a-a6f13dddf7eso403885966b.0 for ; Sat, 15 Jun 2024 12:20:14 -0700 (PDT) X-Received: by 2002:a17:906:e18:b0:a6f:2ea0:b013 with SMTP id a640c23a62f3a-a6f60d41895mr400514266b.43.1718479211877; Sat, 15 Jun 2024 12:20:11 -0700 (PDT) Received: from PC-2635.irisgmbh.local ([2a02:8108:96c0:76fc::80bb]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a6f56db61e0sm327283766b.49.2024.06.15.12.20.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 12:20:09 -0700 (PDT) From: Michael Glembotzki To: swupdate@googlegroups.com Cc: Michael Glembotzki Subject: [swupdate] [PATCH 01/21] mongoose: Update to version 7.14 Date: Sat, 15 Jun 2024 21:11:14 +0200 Message-ID: <20240615191941.40301-2-Michael.Glembotzki@iris-sensing.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> References: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> MIME-Version: 1.0 X-Original-Sender: m.glembo@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=axT6WPhT; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::62e as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , mongoose rev-id: 6bb40e6ec96f95bfd36a816b430ea2726fac9d05 Signed-off-by: Michael Glembotzki --- mongoose/mongoose.c | 21614 +++++++++++++++++++++++++++++++----------- mongoose/mongoose.h | 2003 +++- 2 files changed, 17594 insertions(+), 6023 deletions(-) +#include +#include + +#ifndef MG_IO_SIZE +#define MG_IO_SIZE 1460 +#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 @@ -252,11 +277,35 @@ int mkdir(const char *, mode_t); #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) mg_mprintf("%s", s) + +#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 !defined MG_ENABLE_RL && (!defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP) +#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 +#ifndef MG_SOCK_LISTEN_BACKLOG_SIZE +#define MG_SOCK_LISTEN_BACKLOG_SIZE 3 +#endif #endif #endif @@ -403,7 +452,6 @@ typedef enum { false = 0, true = 1 } bool; #define MG_INVALID_SOCKET INVALID_SOCKET #define MG_SOCKET_TYPE SOCKET typedef unsigned long nfds_t; -#define MG_SOCKET_ERRNO WSAGetLastError() #if defined(_MSC_VER) #pragma comment(lib, "ws2_32.lib") #ifndef alloca @@ -411,9 +459,6 @@ typedef unsigned long nfds_t; #endif #endif #define poll(a, b, c) WSAPoll((a), (b), (c)) -#ifndef SO_EXCLUSIVEADDRUSE -#define SO_EXCLUSIVEADDRUSE ((int) (~SO_REUSEADDR)) -#endif #define closesocket(x) closesocket(x) typedef int socklen_t; @@ -423,16 +468,24 @@ typedef int socklen_t; #define MG_PATH_MAX FILENAME_MAX #endif -#ifndef EINPROGRESS -#define EINPROGRESS WSAEINPROGRESS -#endif -#ifndef EWOULDBLOCK -#define EWOULDBLOCK WSAEWOULDBLOCK +#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) +#define sleep(x) Sleep((x) *1000) #define mkdir(a, b) _mkdir(a) +#define timegm(x) _mkgmtime(x) #ifndef S_ISDIR #define S_ISDIR(x) (((x) &_S_IFMT) == _S_IFDIR) @@ -442,6 +495,10 @@ typedef int socklen_t; #define MG_ENABLE_DIRLIST 1 #endif +#ifndef SIGPIPE +#define SIGPIPE 0 +#endif + #endif @@ -451,8 +508,9 @@ typedef int socklen_t; #include #include -#include #include +#include +#include #include #include #include @@ -464,11 +522,18 @@ typedef int socklen_t; #define MG_PUTCHAR(x) printk("%c", x) #ifndef strdup -#define strdup(s) ((char *) mg_strdup(mg_str(s)).ptr) +#define strdup(s) ((char *) mg_strdup(mg_str(s)).buf) #endif #define strerror(x) zsock_gai_strerror(x) + +#ifndef FD_CLOEXEC #define FD_CLOEXEC 0 +#endif + +#ifndef F_SETFD #define F_SETFD 0 +#endif + #define MG_ENABLE_SSI 0 int rand(void); @@ -479,24 +544,12 @@ int sscanf(const char *, const char *, ...); #if defined(MG_ENABLE_FREERTOS_TCP) && MG_ENABLE_FREERTOS_TCP -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include - -#include #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 @@ -512,6 +565,20 @@ int sscanf(const char *, const char *, ...); #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)) @@ -543,8 +610,17 @@ static inline int mg_getpeername(MG_SOCKET_TYPE fd, void *buf, socklen_t *len) { #if defined(MG_ENABLE_LWIP) && MG_ENABLE_LWIP -#if defined(__GNUC__) + +#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 { @@ -552,8 +628,7 @@ struct timeval { long tv_usec; }; #endif - -#include +#endif #if LWIP_SOCKET != 1 // Sockets support disabled in LWIP by default @@ -565,16 +640,25 @@ struct timeval { #if defined(MG_ENABLE_RL) && MG_ENABLE_RL #include -#define MG_ENABLE_CUSTOM_MILLIS 1 #define closesocket(x) closesocket(x) -#define mkdir(a, b) (-1) -#define EWOULDBLOCK BSD_EWOULDBLOCK -#define EAGAIN BSD_EWOULDBLOCK -#define EINPROGRESS BSD_EWOULDBLOCK -#define EINTR BSD_EWOULDBLOCK -#define ECONNRESET BSD_ECONNRESET -#define EPIPE BSD_ECONNRESET + #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 @@ -582,8 +666,12 @@ struct timeval { #define MG_ENABLE_LOG 1 #endif -#ifndef MG_ENABLE_MIP -#define MG_ENABLE_MIP 0 // Mongoose built-in network stack +#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 @@ -599,7 +687,7 @@ struct timeval { #endif #ifndef MG_ENABLE_SOCKET -#define MG_ENABLE_SOCKET !MG_ENABLE_MIP +#define MG_ENABLE_SOCKET !MG_ENABLE_TCPIP #endif #ifndef MG_ENABLE_POLL @@ -614,18 +702,6 @@ struct timeval { #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 #define MG_ENABLE_SSI 0 #endif @@ -634,6 +710,10 @@ struct timeval { #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 @@ -659,12 +739,16 @@ struct timeval { #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 (3 * 1024 * 1024) // Maximum recv IO buffer size +#define MG_MAX_RECV_SIZE (3UL * 1024UL * 1024UL) // Maximum recv IO buffer size #endif #ifndef MG_DATA_SIZE @@ -688,18 +772,18 @@ struct timeval { #endif #ifndef MG_SOCK_LISTEN_BACKLOG_SIZE -#define MG_SOCK_LISTEN_BACKLOG_SIZE 3 +#define MG_SOCK_LISTEN_BACKLOG_SIZE 128 #endif #ifndef MG_DIRSEP #define MG_DIRSEP '/' #endif -#ifndef MG_ENABLE_FILE +#ifndef MG_ENABLE_POSIX_FS #if defined(FOPEN_MAX) -#define MG_ENABLE_FILE 1 +#define MG_ENABLE_POSIX_FS 1 #else -#define MG_ENABLE_FILE 0 +#define MG_ENABLE_POSIX_FS 0 #endif #endif @@ -732,60 +816,112 @@ struct timeval { #define MG_EPOLL_MOD(c, wr) #endif +#ifndef MG_ENABLE_PROFILE +#define MG_ENABLE_PROFILE 0 +#endif +#ifndef MG_ENABLE_TCPIP_DRIVER_INIT // mg_mgr_init() will also initialize +#define MG_ENABLE_TCPIP_DRIVER_INIT 1 // enabled built-in driver for +#endif // Mongoose built-in network stack +#ifndef MG_TCPIP_IP // e.g. MG_IPV4(192, 168, 0, 223) +#define MG_TCPIP_IP MG_IPV4(0, 0, 0, 0) // Default is 0.0.0.0 (DHCP) +#endif -struct mg_str { - const char *ptr; // Pointer to string data - size_t len; // String len -}; +#ifndef MG_TCPIP_MASK +#define MG_TCPIP_MASK MG_IPV4(0, 0, 0, 0) // Default is 0.0.0.0 (DHCP) +#endif + +#ifndef MG_TCPIP_GW +#define MG_TCPIP_GW MG_IPV4(0, 0, 0, 0) // Default is 0.0.0.0 (DHCP) +#endif + +#ifndef MG_SET_MAC_ADDRESS +#define MG_SET_MAC_ADDRESS(mac) +#endif -#define MG_NULL_STR \ - { NULL, 0 } +#ifndef MG_ENABLE_TCPIP_PRINT_DEBUG_STATS +#define MG_ENABLE_TCPIP_PRINT_DEBUG_STATS 0 +#endif -#define MG_C_STR(a) \ - { (a), sizeof(a) - 1 } + + + +// Describes an arbitrary chunk of memory +struct mg_str { + char *buf; // String data + size_t len; // String length +}; // 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); +int mg_strcasecmp(const struct mg_str str1, const struct mg_str str2); 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); -int mg_check_ip_acl(struct mg_str acl, uint32_t remote_ip); -int64_t mg_to64(struct mg_str str); -uint64_t mg_tou64(struct mg_str str); -char *mg_remove_double_dots(char *s); +bool mg_span(struct mg_str s, struct mg_str *a, struct mg_str *b, char delim); + +bool mg_str_to_num(struct mg_str, int base, void *val, size_t val_len); + +// 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 *); // Custom putchar + + +typedef void (*mg_pfn_t)(char, void *); // Output function typedef size_t (*mg_pm_t)(mg_pfn_t, void *, va_list *); // %M printer -void mg_pfn_iobuf(char ch, void *param); // iobuf 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) @@ -793,16 +929,23 @@ char *mg_mprintf(const char *fmt, ...); enum { MG_LL_NONE, MG_LL_ERROR, MG_LL_INFO, MG_LL_DEBUG, MG_LL_VERBOSE }; +extern int mg_log_level; // Current log level, one of MG_LL_* + 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_log_prefix(int ll, const char *file, int line, const char *fname); +// bool mg_log2(int ll, const char *file, int line, const char *fmt, ...); void mg_hexdump(const void *buf, size_t len); void mg_log_set_fn(mg_pfn_t fn, void *param); +#define mg_log_set(level_) mg_log_level = (level_) + #if MG_ENABLE_LOG -#define MG_LOG(level, args) \ - do { \ - if (mg_log_prefix((level), __FILE__, __LINE__, __func__)) mg_log args; \ +#define MG_LOG(level, args) \ + do { \ + if ((level) <= mg_log_level) { \ + mg_log_prefix((level), __FILE__, __LINE__, __func__); \ + mg_log args; \ + } \ } while (0) #else #define MG_LOG(level, args) \ @@ -854,7 +997,9 @@ enum { MG_FS_READ = 1, MG_FS_WRITE = 2, MG_FS_DIR = 4 }; // 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 (*ls)(const char *path, void (*fn)(const char *, void *), + void *); // List directory entries: call fn(file_name, fn_data) + // for each directory entry 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 @@ -877,28 +1022,84 @@ struct mg_fd { 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_fs_ls(struct mg_fs *fs, const char *path, char *buf, size_t len); +struct mg_str mg_file_read(struct mg_fs *fs, const char *path); 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); +uint64_t mg_millis(void); // Return milliseconds since boot +uint64_t mg_now(void); // Return milliseconds since Epoch +bool mg_path_is_sane(const struct mg_str path); #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)) +#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)) + +#define MG_IPV4(a, b, c, d) mg_htonl(MG_U32(a, b, c, d)) + +// 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))) + +#if defined(__GNUC__) +#define MG_ARM_DISABLE_IRQ() asm volatile("cpsid i" : : : "memory") +#define MG_ARM_ENABLE_IRQ() asm volatile("cpsie i" : : : "memory") +#elif defined(__CCRH__) +#define MG_RH850_DISABLE_IRQ() __DI() +#define MG_RH850_ENABLE_IRQ() __EI() +#else +#define MG_ARM_DISABLE_IRQ() +#define MG_ARM_ENABLE_IRQ() +#endif + +#if defined(__CC_ARM) +#define MG_DSB() __dsb(0xf) +#elif defined(__ARMCC_VERSION) +#define MG_DSB() __builtin_arm_dsb(0xf) +#elif defined(__GNUC__) && defined(__arm__) && defined(__thumb__) +#define MG_DSB() asm("DSB 0xf") +#elif defined(__ICCARM__) +#define MG_DSB() __iar_builtin_DSB() +#else +#define MG_DSB() +#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_) \ @@ -946,10 +1147,11 @@ 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); -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); + +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); @@ -976,35 +1178,793 @@ typedef struct { 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 *); +// https://github.com/B-Con/crypto-algorithms +// Author: Brad Conte (brad AT bradconte.com) +// Disclaimer: This code is presented "as is" without any guarantees. +// Details: Defines the API for the corresponding SHA1 implementation. +// Copyright: public domain + + + + + +typedef struct { + uint32_t state[8]; + uint64_t bits; + uint32_t len; + unsigned char buffer[64]; +} mg_sha256_ctx; + +void mg_sha256_init(mg_sha256_ctx *); +void mg_sha256_update(mg_sha256_ctx *, const unsigned char *data, size_t len); +void mg_sha256_final(unsigned char digest[32], mg_sha256_ctx *); +void mg_hmac_sha256(uint8_t dst[32], uint8_t *key, size_t keysz, uint8_t *data, + size_t datasz); +#ifndef TLS_X15519_H +#define TLS_X15519_H + + + +#define X25519_BYTES 32 +extern const uint8_t X25519_BASE_POINT[X25519_BYTES]; + +int mg_tls_x25519(uint8_t out[X25519_BYTES], const uint8_t scalar[X25519_BYTES], + const uint8_t x1[X25519_BYTES], int clamp); + + +#endif /* TLS_X15519_H */ +/****************************************************************************** + * + * THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL + * + * This is a simple and straightforward implementation of AES-GCM authenticated + * encryption. The focus of this work was correctness & accuracy. It is written + * in straight 'C' without any particular focus upon optimization or speed. It + * should be endian (memory byte order) neutral since the few places that care + * are handled explicitly. + * + * This implementation of AES-GCM was created by Steven M. Gibson of GRC.com. + * + * It is intended for general purpose use, but was written in support of GRC's + * reference implementation of the SQRL (Secure Quick Reliable Login) client. + * + * See: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf + * http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/ \ + * gcm/gcm-revised-spec.pdf + * + * NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE + * REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK. + * + *******************************************************************************/ +#ifndef TLS_AES128_H +#define TLS_AES128_H + +typedef unsigned char uchar; // add some convienent shorter types +typedef unsigned int uint; + +/****************************************************************************** + * AES_CONTEXT : cipher context / holds inter-call data + ******************************************************************************/ +typedef struct { + int mode; // 1 for Encryption, 0 for Decryption + int rounds; // keysize-based rounds count + uint32_t *rk; // pointer to current round key + uint32_t buf[68]; // key expansion buffer +} aes_context; + + +#define GCM_AUTH_FAILURE 0x55555555 // authentication failure + +/****************************************************************************** + * GCM_CONTEXT : MUST be called once before ANY use of this library + ******************************************************************************/ +int mg_gcm_initialize(void); + +// +// aes-gcm.h +// MKo +// +// Created by Markus Kosmal on 20/11/14. +// +// +int mg_aes_gcm_encrypt(unsigned char *output, const unsigned char *input, + size_t input_length, const unsigned char *key, + const size_t key_len, const unsigned char *iv, + const size_t iv_len, unsigned char *aead, + size_t aead_len, unsigned char *tag, + const size_t tag_len); + +int mg_aes_gcm_decrypt(unsigned char *output, const unsigned char *input, + size_t input_length, const unsigned char *key, + const size_t key_len, const unsigned char *iv, + const size_t iv_len); + +#endif /* TLS_AES128_H */ + +// End of aes128 PD + + + +#define MG_UECC_SUPPORTS_secp256r1 1 +/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */ + +#ifndef _UECC_H_ +#define _UECC_H_ + +/* Platform selection options. +If MG_UECC_PLATFORM is not defined, the code will try to guess it based on +compiler macros. Possible values for MG_UECC_PLATFORM are defined below: */ +#define mg_uecc_arch_other 0 +#define mg_uecc_x86 1 +#define mg_uecc_x86_64 2 +#define mg_uecc_arm 3 +#define mg_uecc_arm_thumb 4 +#define mg_uecc_arm_thumb2 5 +#define mg_uecc_arm64 6 +#define mg_uecc_avr 7 + +/* If desired, you can define MG_UECC_WORD_SIZE as appropriate for your platform +(1, 4, or 8 bytes). If MG_UECC_WORD_SIZE is not explicitly defined then it will +be automatically set based on your platform. */ + +/* Optimization level; trade speed for code size. + Larger values produce code that is faster but larger. + Currently supported values are 0 - 4; 0 is unusably slow for most + applications. Optimization level 4 currently only has an effect ARM platforms + where more than one curve is enabled. */ +#ifndef MG_UECC_OPTIMIZATION_LEVEL +#define MG_UECC_OPTIMIZATION_LEVEL 2 +#endif + +/* MG_UECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a +specific function to be used for (scalar) squaring instead of the generic +multiplication function. This can make things faster somewhat faster, but +increases the code size. */ +#ifndef MG_UECC_SQUARE_FUNC +#define MG_UECC_SQUARE_FUNC 0 +#endif + +/* MG_UECC_VLI_NATIVE_LITTLE_ENDIAN - If enabled (defined as nonzero), this will +switch to native little-endian format for *all* arrays passed in and out of the +public API. This includes public and private keys, shared secrets, signatures +and message hashes. Using this switch reduces the amount of call stack memory +used by uECC, since less intermediate translations are required. Note that this +will *only* work on native little-endian processors and it will treat the +uint8_t arrays passed into the public API as word arrays, therefore requiring +the provided byte arrays to be word aligned on architectures that do not support +unaligned accesses. IMPORTANT: Keys and signatures generated with +MG_UECC_VLI_NATIVE_LITTLE_ENDIAN=1 are incompatible with keys and signatures +generated with MG_UECC_VLI_NATIVE_LITTLE_ENDIAN=0; all parties must use the same +endianness. */ +#ifndef MG_UECC_VLI_NATIVE_LITTLE_ENDIAN +#define MG_UECC_VLI_NATIVE_LITTLE_ENDIAN 0 +#endif + +/* Curve support selection. Set to 0 to remove that curve. */ +#ifndef MG_UECC_SUPPORTS_secp160r1 +#define MG_UECC_SUPPORTS_secp160r1 0 +#endif +#ifndef MG_UECC_SUPPORTS_secp192r1 +#define MG_UECC_SUPPORTS_secp192r1 0 +#endif +#ifndef MG_UECC_SUPPORTS_secp224r1 +#define MG_UECC_SUPPORTS_secp224r1 0 +#endif +#ifndef MG_UECC_SUPPORTS_secp256r1 +#define MG_UECC_SUPPORTS_secp256r1 1 +#endif +#ifndef MG_UECC_SUPPORTS_secp256k1 +#define MG_UECC_SUPPORTS_secp256k1 0 +#endif + +/* Specifies whether compressed point format is supported. + Set to 0 to disable point compression/decompression functions. */ +#ifndef MG_UECC_SUPPORT_COMPRESSED_POINT +#define MG_UECC_SUPPORT_COMPRESSED_POINT 1 +#endif + +struct MG_UECC_Curve_t; +typedef const struct MG_UECC_Curve_t *MG_UECC_Curve; + +#ifdef __cplusplus +extern "C" { +#endif + +#if MG_UECC_SUPPORTS_secp160r1 +MG_UECC_Curve mg_uecc_secp160r1(void); +#endif +#if MG_UECC_SUPPORTS_secp192r1 +MG_UECC_Curve mg_uecc_secp192r1(void); +#endif +#if MG_UECC_SUPPORTS_secp224r1 +MG_UECC_Curve mg_uecc_secp224r1(void); +#endif +#if MG_UECC_SUPPORTS_secp256r1 +MG_UECC_Curve mg_uecc_secp256r1(void); +#endif +#if MG_UECC_SUPPORTS_secp256k1 +MG_UECC_Curve mg_uecc_secp256k1(void); +#endif + +/* MG_UECC_RNG_Function type +The RNG function should fill 'size' random bytes into 'dest'. It should return 1 +if 'dest' was filled with random data, or 0 if the random data could not be +generated. The filled-in values should be either truly random, or from a +cryptographically-secure PRNG. + +A correctly functioning RNG function must be set (using mg_uecc_set_rng()) +before calling mg_uecc_make_key() or mg_uecc_sign(). + +Setting a correctly functioning RNG function improves the resistance to +side-channel attacks for mg_uecc_shared_secret() and +mg_uecc_sign_deterministic(). + +A correct RNG function is set by default when building for Windows, Linux, or OS +X. If you are building on another POSIX-compliant system that supports +/dev/random or /dev/urandom, you can define MG_UECC_POSIX to use the predefined +RNG. For embedded platforms there is no predefined RNG function; you must +provide your own. +*/ +typedef int (*MG_UECC_RNG_Function)(uint8_t *dest, unsigned size); + +/* mg_uecc_set_rng() function. +Set the function that will be used to generate random bytes. The RNG function +should return 1 if the random data was generated, or 0 if the random data could +not be generated. + +On platforms where there is no predefined RNG function (eg embedded platforms), +this must be called before mg_uecc_make_key() or mg_uecc_sign() are used. + +Inputs: + rng_function - The function that will be used to generate random bytes. +*/ +void mg_uecc_set_rng(MG_UECC_RNG_Function rng_function); + +/* mg_uecc_get_rng() function. + +Returns the function that will be used to generate random bytes. +*/ +MG_UECC_RNG_Function mg_uecc_get_rng(void); + +/* mg_uecc_curve_private_key_size() function. + +Returns the size of a private key for the curve in bytes. +*/ +int mg_uecc_curve_private_key_size(MG_UECC_Curve curve); + +/* mg_uecc_curve_public_key_size() function. + +Returns the size of a public key for the curve in bytes. +*/ +int mg_uecc_curve_public_key_size(MG_UECC_Curve curve); + +/* mg_uecc_make_key() function. +Create a public/private key pair. + +Outputs: + public_key - Will be filled in with the public key. Must be at least 2 * +the curve size (in bytes) long. For example, if the curve is secp256r1, +public_key must be 64 bytes long. private_key - Will be filled in with the +private key. Must be as long as the curve order; this is typically the same as +the curve size, except for secp160r1. For example, if the curve is secp256r1, +private_key must be 32 bytes long. + + For secp160r1, private_key must be 21 bytes long! Note that +the first byte will almost always be 0 (there is about a 1 in 2^80 chance of it +being non-zero). + +Returns 1 if the key pair was generated successfully, 0 if an error occurred. +*/ +int mg_uecc_make_key(uint8_t *public_key, uint8_t *private_key, + MG_UECC_Curve curve); + +/* mg_uecc_shared_secret() function. +Compute a shared secret given your secret key and someone else's public key. If +the public key is not from a trusted source and has not been previously +verified, you should verify it first using mg_uecc_valid_public_key(). Note: It +is recommended that you hash the result of mg_uecc_shared_secret() before using +it for symmetric encryption or HMAC. + +Inputs: + public_key - The public key of the remote party. + private_key - Your private key. + +Outputs: + secret - Will be filled in with the shared secret value. Must be the same +size as the curve size; for example, if the curve is secp256r1, secret must be +32 bytes long. + +Returns 1 if the shared secret was generated successfully, 0 if an error +occurred. +*/ +int mg_uecc_shared_secret(const uint8_t *public_key, const uint8_t *private_key, + uint8_t *secret, MG_UECC_Curve curve); + +#if MG_UECC_SUPPORT_COMPRESSED_POINT +/* mg_uecc_compress() function. +Compress a public key. + +Inputs: + public_key - The public key to compress. + +Outputs: + compressed - Will be filled in with the compressed public key. Must be at +least (curve size + 1) bytes long; for example, if the curve is secp256r1, + compressed must be 33 bytes long. +*/ +void mg_uecc_compress(const uint8_t *public_key, uint8_t *compressed, + MG_UECC_Curve curve); + +/* mg_uecc_decompress() function. +Decompress a compressed public key. + +Inputs: + compressed - The compressed public key. + +Outputs: + public_key - Will be filled in with the decompressed public key. +*/ +void mg_uecc_decompress(const uint8_t *compressed, uint8_t *public_key, + MG_UECC_Curve curve); +#endif /* MG_UECC_SUPPORT_COMPRESSED_POINT */ + +/* mg_uecc_valid_public_key() function. +Check to see if a public key is valid. + +Note that you are not required to check for a valid public key before using any +other uECC functions. However, you may wish to avoid spending CPU time computing +a shared secret or verifying a signature using an invalid public key. + +Inputs: + public_key - The public key to check. + +Returns 1 if the public key is valid, 0 if it is invalid. +*/ +int mg_uecc_valid_public_key(const uint8_t *public_key, MG_UECC_Curve curve); + +/* mg_uecc_compute_public_key() function. +Compute the corresponding public key for a private key. + +Inputs: + private_key - The private key to compute the public key for + +Outputs: + public_key - Will be filled in with the corresponding public key + +Returns 1 if the key was computed successfully, 0 if an error occurred. +*/ +int mg_uecc_compute_public_key(const uint8_t *private_key, uint8_t *public_key, + MG_UECC_Curve curve); + +/* mg_uecc_sign() function. +Generate an ECDSA signature for a given hash value. + +Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and +pass it in to this function along with your private key. + +Inputs: + private_key - Your private key. + message_hash - The hash of the message to sign. + hash_size - The size of message_hash in bytes. + +Outputs: + signature - Will be filled in with the signature value. Must be at least 2 * +curve size long. For example, if the curve is secp256r1, signature must be 64 +bytes long. + +Returns 1 if the signature generated successfully, 0 if an error occurred. +*/ +int mg_uecc_sign(const uint8_t *private_key, const uint8_t *message_hash, + unsigned hash_size, uint8_t *signature, MG_UECC_Curve curve); + +/* MG_UECC_HashContext structure. +This is used to pass in an arbitrary hash function to +mg_uecc_sign_deterministic(). The structure will be used for multiple hash +computations; each time a new hash is computed, init_hash() will be called, +followed by one or more calls to update_hash(), and finally a call to +finish_hash() to produce the resulting hash. + +The intention is that you will create a structure that includes +MG_UECC_HashContext followed by any hash-specific data. For example: + +typedef struct SHA256_HashContext { + MG_UECC_HashContext uECC; + SHA256_CTX ctx; +} SHA256_HashContext; + +void init_SHA256(MG_UECC_HashContext *base) { + SHA256_HashContext *context = (SHA256_HashContext *)base; + SHA256_Init(&context->ctx); +} + +void update_SHA256(MG_UECC_HashContext *base, + const uint8_t *message, + unsigned message_size) { + SHA256_HashContext *context = (SHA256_HashContext *)base; + SHA256_Update(&context->ctx, message, message_size); +} + +void finish_SHA256(MG_UECC_HashContext *base, uint8_t *hash_result) { + SHA256_HashContext *context = (SHA256_HashContext *)base; + SHA256_Final(hash_result, &context->ctx); +} + +... when signing ... +{ + uint8_t tmp[32 + 32 + 64]; + SHA256_HashContext ctx = {{&init_SHA256, &update_SHA256, &finish_SHA256, 64, +32, tmp}}; mg_uecc_sign_deterministic(key, message_hash, &ctx.uECC, signature); +} +*/ +typedef struct MG_UECC_HashContext { + void (*init_hash)(const struct MG_UECC_HashContext *context); + void (*update_hash)(const struct MG_UECC_HashContext *context, + const uint8_t *message, unsigned message_size); + void (*finish_hash)(const struct MG_UECC_HashContext *context, + uint8_t *hash_result); + unsigned + block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */ + unsigned + result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */ + uint8_t *tmp; /* Must point to a buffer of at least (2 * result_size + + block_size) bytes. */ +} MG_UECC_HashContext; + +/* mg_uecc_sign_deterministic() function. +Generate an ECDSA signature for a given hash value, using a deterministic +algorithm (see RFC 6979). You do not need to set the RNG using mg_uecc_set_rng() +before calling this function; however, if the RNG is defined it will improve +resistance to side-channel attacks. + +Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and +pass it to this function along with your private key and a hash context. Note +that the message_hash does not need to be computed with the same hash function +used by hash_context. + +Inputs: + private_key - Your private key. + message_hash - The hash of the message to sign. + hash_size - The size of message_hash in bytes. + hash_context - A hash context to use. + +Outputs: + signature - Will be filled in with the signature value. + +Returns 1 if the signature generated successfully, 0 if an error occurred. +*/ +int mg_uecc_sign_deterministic(const uint8_t *private_key, + const uint8_t *message_hash, unsigned hash_size, + const MG_UECC_HashContext *hash_context, + uint8_t *signature, MG_UECC_Curve curve); + +/* mg_uecc_verify() function. +Verify an ECDSA signature. + +Usage: Compute the hash of the signed data using the same hash as the signer and +pass it to this function along with the signer's public key and the signature +values (r and s). + +Inputs: + public_key - The signer's public key. + message_hash - The hash of the signed data. + hash_size - The size of message_hash in bytes. + signature - The signature value. + +Returns 1 if the signature is valid, 0 if it is invalid. +*/ +int mg_uecc_verify(const uint8_t *public_key, const uint8_t *message_hash, + unsigned hash_size, const uint8_t *signature, + MG_UECC_Curve curve); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* _UECC_H_ */ + +/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ + +#ifndef _UECC_VLI_H_ +#define _UECC_VLI_H_ + +// +// + +/* Functions for raw large-integer manipulation. These are only available + if uECC.c is compiled with MG_UECC_ENABLE_VLI_API defined to 1. */ +#ifndef MG_UECC_ENABLE_VLI_API +#define MG_UECC_ENABLE_VLI_API 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if MG_UECC_ENABLE_VLI_API + +void mg_uecc_vli_clear(mg_uecc_word_t *vli, wordcount_t num_words); + +/* Constant-time comparison to zero - secure way to compare long integers */ +/* Returns 1 if vli == 0, 0 otherwise. */ +mg_uecc_word_t mg_uecc_vli_isZero(const mg_uecc_word_t *vli, + wordcount_t num_words); + +/* Returns nonzero if bit 'bit' of vli is set. */ +mg_uecc_word_t mg_uecc_vli_testBit(const mg_uecc_word_t *vli, bitcount_t bit); + +/* Counts the number of bits required to represent vli. */ +bitcount_t mg_uecc_vli_numBits(const mg_uecc_word_t *vli, + const wordcount_t max_words); + +/* Sets dest = src. */ +void mg_uecc_vli_set(mg_uecc_word_t *dest, const mg_uecc_word_t *src, + wordcount_t num_words); + +/* Constant-time comparison function - secure way to compare long integers */ +/* Returns one if left == right, zero otherwise */ +mg_uecc_word_t mg_uecc_vli_equal(const mg_uecc_word_t *left, + const mg_uecc_word_t *right, + wordcount_t num_words); + +/* Constant-time comparison function - secure way to compare long integers */ +/* Returns sign of left - right, in constant time. */ +cmpresult_t mg_uecc_vli_cmp(const mg_uecc_word_t *left, + const mg_uecc_word_t *right, wordcount_t num_words); + +/* Computes vli = vli >> 1. */ +void mg_uecc_vli_rshift1(mg_uecc_word_t *vli, wordcount_t num_words); + +/* Computes result = left + right, returning carry. Can modify in place. */ +mg_uecc_word_t mg_uecc_vli_add(mg_uecc_word_t *result, + const mg_uecc_word_t *left, + const mg_uecc_word_t *right, + wordcount_t num_words); + +/* Computes result = left - right, returning borrow. Can modify in place. */ +mg_uecc_word_t mg_uecc_vli_sub(mg_uecc_word_t *result, + const mg_uecc_word_t *left, + const mg_uecc_word_t *right, + wordcount_t num_words); + +/* Computes result = left * right. Result must be 2 * num_words long. */ +void mg_uecc_vli_mult(mg_uecc_word_t *result, const mg_uecc_word_t *left, + const mg_uecc_word_t *right, wordcount_t num_words); + +/* Computes result = left^2. Result must be 2 * num_words long. */ +void mg_uecc_vli_square(mg_uecc_word_t *result, const mg_uecc_word_t *left, + wordcount_t num_words); + +/* Computes result = (left + right) % mod. + Assumes that left < mod and right < mod, and that result does not overlap + mod. */ +void mg_uecc_vli_modAdd(mg_uecc_word_t *result, const mg_uecc_word_t *left, + const mg_uecc_word_t *right, const mg_uecc_word_t *mod, + wordcount_t num_words); + +/* Computes result = (left - right) % mod. + Assumes that left < mod and right < mod, and that result does not overlap + mod. */ +void mg_uecc_vli_modSub(mg_uecc_word_t *result, const mg_uecc_word_t *left, + const mg_uecc_word_t *right, const mg_uecc_word_t *mod, + wordcount_t num_words); + +/* Computes result = product % mod, where product is 2N words long. + Currently only designed to work for mod == curve->p or curve_n. */ +void mg_uecc_vli_mmod(mg_uecc_word_t *result, mg_uecc_word_t *product, + const mg_uecc_word_t *mod, wordcount_t num_words); + +/* Calculates result = product (mod curve->p), where product is up to + 2 * curve->num_words long. */ +void mg_uecc_vli_mmod_fast(mg_uecc_word_t *result, mg_uecc_word_t *product, + MG_UECC_Curve curve); + +/* Computes result = (left * right) % mod. + Currently only designed to work for mod == curve->p or curve_n. */ +void mg_uecc_vli_modMult(mg_uecc_word_t *result, const mg_uecc_word_t *left, + const mg_uecc_word_t *right, const mg_uecc_word_t *mod, + wordcount_t num_words); + +/* Computes result = (left * right) % curve->p. */ +void mg_uecc_vli_modMult_fast(mg_uecc_word_t *result, + const mg_uecc_word_t *left, + const mg_uecc_word_t *right, MG_UECC_Curve curve); + +/* Computes result = left^2 % mod. + Currently only designed to work for mod == curve->p or curve_n. */ +void mg_uecc_vli_modSquare(mg_uecc_word_t *result, const mg_uecc_word_t *left, + const mg_uecc_word_t *mod, wordcount_t num_words); + +/* Computes result = left^2 % curve->p. */ +void mg_uecc_vli_modSquare_fast(mg_uecc_word_t *result, + const mg_uecc_word_t *left, + MG_UECC_Curve curve); + +/* Computes result = (1 / input) % mod.*/ +void mg_uecc_vli_modInv(mg_uecc_word_t *result, const mg_uecc_word_t *input, + const mg_uecc_word_t *mod, wordcount_t num_words); + +#if MG_UECC_SUPPORT_COMPRESSED_POINT +/* Calculates a = sqrt(a) (mod curve->p) */ +void mg_uecc_vli_mod_sqrt(mg_uecc_word_t *a, MG_UECC_Curve curve); +#endif + +/* Converts an integer in uECC native format to big-endian bytes. */ +void mg_uecc_vli_nativeToBytes(uint8_t *bytes, int num_bytes, + const mg_uecc_word_t *native); +/* Converts big-endian bytes to an integer in uECC native format. */ +void mg_uecc_vli_bytesToNative(mg_uecc_word_t *native, const uint8_t *bytes, + int num_bytes); + +unsigned mg_uecc_curve_num_words(MG_UECC_Curve curve); +unsigned mg_uecc_curve_num_bytes(MG_UECC_Curve curve); +unsigned mg_uecc_curve_num_bits(MG_UECC_Curve curve); +unsigned mg_uecc_curve_num_n_words(MG_UECC_Curve curve); +unsigned mg_uecc_curve_num_n_bytes(MG_UECC_Curve curve); +unsigned mg_uecc_curve_num_n_bits(MG_UECC_Curve curve); + +const mg_uecc_word_t *mg_uecc_curve_p(MG_UECC_Curve curve); +const mg_uecc_word_t *mg_uecc_curve_n(MG_UECC_Curve curve); +const mg_uecc_word_t *mg_uecc_curve_G(MG_UECC_Curve curve); +const mg_uecc_word_t *mg_uecc_curve_b(MG_UECC_Curve curve); + +int mg_uecc_valid_point(const mg_uecc_word_t *point, MG_UECC_Curve curve); + +/* Multiplies a point by a scalar. Points are represented by the X coordinate + followed by the Y coordinate in the same array, both coordinates are + curve->num_words long. Note that scalar must be curve->num_n_words long (NOT + curve->num_words). */ +void mg_uecc_point_mult(mg_uecc_word_t *result, const mg_uecc_word_t *point, + const mg_uecc_word_t *scalar, MG_UECC_Curve curve); + +/* Generates a random integer in the range 0 < random < top. + Both random and top have num_words words. */ +int mg_uecc_generate_random_int(mg_uecc_word_t *random, + const mg_uecc_word_t *top, + wordcount_t num_words); + +#endif /* MG_UECC_ENABLE_VLI_API */ + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* _UECC_VLI_H_ */ + +/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ + +#ifndef _UECC_TYPES_H_ +#define _UECC_TYPES_H_ + +#ifndef MG_UECC_PLATFORM +#if defined(__AVR__) && __AVR__ +#define MG_UECC_PLATFORM mg_uecc_avr +#elif defined(__thumb2__) || \ + defined(_M_ARMT) /* I think MSVC only supports Thumb-2 targets */ +#define MG_UECC_PLATFORM mg_uecc_arm_thumb2 +#elif defined(__thumb__) +#define MG_UECC_PLATFORM mg_uecc_arm_thumb +#elif defined(__arm__) || defined(_M_ARM) +#define MG_UECC_PLATFORM mg_uecc_arm +#elif defined(__aarch64__) +#define MG_UECC_PLATFORM mg_uecc_arm64 +#elif defined(__i386__) || defined(_M_IX86) || defined(_X86_) || \ + defined(__I86__) +#define MG_UECC_PLATFORM mg_uecc_x86 +#elif defined(__amd64__) || defined(_M_X64) +#define MG_UECC_PLATFORM mg_uecc_x86_64 +#else +#define MG_UECC_PLATFORM mg_uecc_arch_other +#endif +#endif + +#ifndef MG_UECC_ARM_USE_UMAAL +#if (MG_UECC_PLATFORM == mg_uecc_arm) && (__ARM_ARCH >= 6) +#define MG_UECC_ARM_USE_UMAAL 1 +#elif (MG_UECC_PLATFORM == mg_uecc_arm_thumb2) && (__ARM_ARCH >= 6) && \ + (!defined(__ARM_ARCH_7M__) || !__ARM_ARCH_7M__) +#define MG_UECC_ARM_USE_UMAAL 1 +#else +#define MG_UECC_ARM_USE_UMAAL 0 +#endif +#endif + +#ifndef MG_UECC_WORD_SIZE +#if MG_UECC_PLATFORM == mg_uecc_avr +#define MG_UECC_WORD_SIZE 1 +#elif (MG_UECC_PLATFORM == mg_uecc_x86_64 || MG_UECC_PLATFORM == mg_uecc_arm64) +#define MG_UECC_WORD_SIZE 8 +#else +#define MG_UECC_WORD_SIZE 4 +#endif +#endif + +#if (MG_UECC_WORD_SIZE != 1) && (MG_UECC_WORD_SIZE != 4) && \ + (MG_UECC_WORD_SIZE != 8) +#error "Unsupported value for MG_UECC_WORD_SIZE" +#endif + +#if ((MG_UECC_PLATFORM == mg_uecc_avr) && (MG_UECC_WORD_SIZE != 1)) +#pragma message("MG_UECC_WORD_SIZE must be 1 for AVR") +#undef MG_UECC_WORD_SIZE +#define MG_UECC_WORD_SIZE 1 +#endif + +#if ((MG_UECC_PLATFORM == mg_uecc_arm || \ + MG_UECC_PLATFORM == mg_uecc_arm_thumb || \ + MG_UECC_PLATFORM == mg_uecc_arm_thumb2) && \ + (MG_UECC_WORD_SIZE != 4)) +#pragma message("MG_UECC_WORD_SIZE must be 4 for ARM") +#undef MG_UECC_WORD_SIZE +#define MG_UECC_WORD_SIZE 4 +#endif + +typedef int8_t wordcount_t; +typedef int16_t bitcount_t; +typedef int8_t cmpresult_t; + +#if (MG_UECC_WORD_SIZE == 1) + +typedef uint8_t mg_uecc_word_t; +typedef uint16_t mg_uecc_dword_t; + +#define HIGH_BIT_SET 0x80 +#define MG_UECC_WORD_BITS 8 +#define MG_UECC_WORD_BITS_SHIFT 3 +#define MG_UECC_WORD_BITS_MASK 0x07 + +#elif (MG_UECC_WORD_SIZE == 4) + +typedef uint32_t mg_uecc_word_t; +typedef uint64_t mg_uecc_dword_t; + +#define HIGH_BIT_SET 0x80000000 +#define MG_UECC_WORD_BITS 32 +#define MG_UECC_WORD_BITS_SHIFT 5 +#define MG_UECC_WORD_BITS_MASK 0x01F + +#elif (MG_UECC_WORD_SIZE == 8) + +typedef uint64_t mg_uecc_word_t; + +#define HIGH_BIT_SET 0x8000000000000000U +#define MG_UECC_WORD_BITS 64 +#define MG_UECC_WORD_BITS_SHIFT 6 +#define MG_UECC_WORD_BITS_MASK 0x03F + +#endif /* MG_UECC_WORD_SIZE */ + +#endif /* _UECC_TYPES_H_ */ +// End of uecc BSD-2 struct mg_connection; typedef void (*mg_event_handler_t)(struct mg_connection *, int ev, - void *ev_data, void *fn_data); + void *ev_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_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 uint64_t *epoch_millis - MG_EV_USER // Starting ID for user events + 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_HDRS, // HTTP headers struct mg_http_message * + MG_EV_HTTP_MSG, // Full 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_WAKEUP, // mg_wakeup() data received struct mg_str *data + MG_EV_USER // Starting ID for user events }; @@ -1021,10 +1981,10 @@ struct mg_dns { }; 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 + 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 { @@ -1036,12 +1996,14 @@ struct mg_mgr { 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 + MG_SOCKET_TYPE pipe; // Socketpair end for mg_wakeup() #if MG_ENABLE_FREERTOS_TCP SocketSet_t ss; // NOTE(lsm): referenced from socket struct #endif @@ -1056,6 +2018,8 @@ struct mg_connection { unsigned long id; // Auto-incrementing unique connection ID struct mg_iobuf recv; // Incoming data struct mg_iobuf send; // Outgoing data + struct mg_iobuf prof; // Profile data enabled by MG_ENABLE_PROFILE + struct mg_iobuf rtls; // TLS only. Incoming encrypted 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 @@ -1066,6 +2030,7 @@ struct mg_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 @@ -1096,20 +2061,18 @@ 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); -int mg_mkpipe(struct mg_mgr *, mg_event_handler_t, void *, bool udp); // 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 +bool mg_wakeup(struct mg_mgr *, unsigned long id, const void *buf, size_t len); +bool mg_wakeup_init(struct mg_mgr *); 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); - @@ -1127,7 +2090,6 @@ struct mg_http_message { 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 }; @@ -1169,9 +2131,8 @@ 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); + struct mg_fs *fs, const char *dir, 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 *); @@ -1183,60 +2144,84 @@ 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_WOLFSSL 5 // WolfSSL (based on 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 { - 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 - struct mg_fs *fs; // FS API for reading certificate files + 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 + int skip_verification; // Skip certificate and host name verification }; -void mg_tls_init(struct mg_connection *, const struct mg_tls_opts *); +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 *); + +// 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); -#if MG_ENABLE_MBEDTLS + +#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 { - char *cafile; // CA certificate path 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 - mbedtls_pk_context pk; // Private key context +#ifdef MBEDTLS_SSL_SESSION_TICKETS + mbedtls_ssl_ticket_context ticket; // Session tickets context +#endif }; #endif -#if MG_ENABLE_OPENSSL +#if MG_TLS == MG_TLS_OPENSSL || MG_TLS == MG_TLS_WOLFSSL -#ifdef CONFIG_SSL_IMPL_WOLFSSL -#include -#include -#else #include #include -#endif struct mg_tls { + BIO_METHOD *bm; SSL_CTX *ctx; SSL *ssl; }; @@ -1296,29 +2281,81 @@ int64_t mg_sntp_parse(const unsigned char *buf, size_t len); #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 will_topic; // Will topic - struct mg_str will_message; // Will message - uint8_t will_qos; // Will 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 will_retain; // Retain last will - bool clean; // Use clean session, 0 or 1 + 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 + uint16_t retransmit_id; // For PUBLISH, init to 0 + 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 - 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_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, @@ -1327,15 +2364,16 @@ struct mg_connection *mg_mqtt_connect(struct mg_mgr *, const char *url, 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); +uint16_t 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 *); +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); @@ -1387,6 +2425,7 @@ size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs, 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); +struct mg_str mg_json_get_tok(struct mg_str json, const char *path); 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); @@ -1394,6 +2433,10 @@ 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); + @@ -1426,96 +2469,342 @@ 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 -struct mip_if; // MIP network interface +#define MG_OTA_NONE 0 // No OTA support +#define MG_OTA_FLASH 1 // OTA via an internal flash +#define MG_OTA_ESP32 2 // ESP32 OTA implementation +#define MG_OTA_CUSTOM 100 // Custom implementation -struct mip_driver { - bool (*init)(struct mip_if *); // Initialise driver - size_t (*tx)(const void *, size_t, struct mip_if *); // Transmit frame - size_t (*rx)(void *buf, size_t len, struct mip_if *); // Receive frame (poll) - bool (*up)(struct mip_if *); // Up/down status -}; +#ifndef MG_OTA +#define MG_OTA MG_OTA_NONE +#endif + +#if defined(__GNUC__) && !defined(__APPLE__) +#define MG_IRAM __attribute__((section(".iram"))) +#else +#define MG_IRAM +#endif -// Receive queue - single producer, single consumer queue. Interrupt-based -// drivers copy received frames to the queue in interrupt context. mip_poll() -// function runs in event loop context, reads from the queue -struct queue { - uint8_t *buf; - size_t len; - volatile size_t tail, head; +// 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 +MG_IRAM void mg_ota_boot(void); // Bootloader function +// Copyright (c) 2023 Cesanta Software Limited +// All rights reserved -#define MIP_ARP_ENTRIES 5 // Number of ARP cache entries. Maximum 21 -#define MIP_ARP_CS (2 + 12 * MIP_ARP_ENTRIES) // ARP cache size + + + + +#define MG_DEVICE_NONE 0 // Dummy system + +#define MG_DEVICE_STM32H5 1 // STM32 H5 +#define MG_DEVICE_STM32H7 2 // STM32 H7 +#define MG_DEVICE_CH32V307 100 // WCH CH32V307 +#define MG_DEVICE_U2A 200 // Renesas U2A16, U2A8, U2A6 +#define MG_DEVICE_RT1020 300 // IMXRT1020 +#define MG_DEVICE_RT1060 301 // IMXRT1060 +#define MG_DEVICE_CUSTOM 1000 // 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 *sector); +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 mip_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 mip_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 +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_get_gateway; // DCHP server sets client as gateway + 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 - uint64_t now; // Current time - uint64_t timer_1000ms; // 1000 ms timer: for DHCP and link state - uint64_t lease_expire; // Lease expiration time - uint8_t arp_cache[MIP_ARP_CS]; // Each entry is 12 bytes - uint16_t eport; // Next ephemeral port - uint16_t dropped; // Number of dropped frames - 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 + 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 mip_init(struct mg_mgr *, struct mip_if *); -void mip_free(struct mip_if *); -void mip_qwrite(void *buf, size_t len, struct mip_if *ifp); -size_t mip_qread(void *buf, struct mip_if *ifp); -// conveniency rx function for IRQ-driven drivers -size_t mip_driver_rx(void *buf, size_t len, struct mip_if *ifp); - -extern struct mip_driver mip_driver_stm32; -extern struct mip_driver mip_driver_w5500; -extern struct mip_driver mip_driver_tm4c; +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_stm32f; +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_imxrt; +extern struct mg_tcpip_driver mg_tcpip_driver_same54; +extern struct mg_tcpip_driver mg_tcpip_driver_cmsis; +extern struct mg_tcpip_driver mg_tcpip_driver_ra; +extern struct mg_tcpip_driver mg_tcpip_driver_xmc; +extern struct mg_tcpip_driver mg_tcpip_driver_xmc7; // Drivers that require SPI, can use this SPI abstraction -struct mip_spi { +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 -#ifdef MIP_QPROFILE -enum { - QP_IRQTRIGGERED = 0, // payload is number of interrupts so far - QP_FRAMEPUSHED, // available space in the frame queue - QP_FRAMEPOPPED, // available space in the frame queue - QP_FRAMEDONE, // available space in the frame queue - QP_FRAMEDROPPED, // number of dropped frames - QP_QUEUEOVF // profiling queue is full, payload is number of frame drops + + +// Macros to record timestamped events that happens with a connection. +// They are saved into a c->prof IO buffer, each event is a name and a 32-bit +// timestamp in milliseconds since connection init time. +// +// Test (run in two separate terminals): +// make -C examples/http-server/ CFLAGS_EXTRA=-DMG_ENABLE_PROFILE=1 +// curl localhost:8000 +// Output: +// 1ea1f1e7 2 net.c:150:mg_close_conn 3 profile: +// 1ea1f1e8 2 net.c:150:mg_close_conn 1ea1f1e6 init +// 1ea1f1e8 2 net.c:150:mg_close_conn 0 EV_OPEN +// 1ea1f1e8 2 net.c:150:mg_close_conn 0 EV_ACCEPT +// 1ea1f1e8 2 net.c:150:mg_close_conn 0 EV_READ +// 1ea1f1e8 2 net.c:150:mg_close_conn 0 EV_HTTP_MSG +// 1ea1f1e8 2 net.c:150:mg_close_conn 0 EV_WRITE +// 1ea1f1e8 2 net.c:150:mg_close_conn 1 EV_CLOSE +// +// Usage: +// Enable profiling by setting MG_ENABLE_PROFILE=1 +// Invoke MG_PROF_ADD(c, "MY_EVENT_1") in the places you'd like to measure + +#if MG_ENABLE_PROFILE +struct mg_profitem { + const char *name; // Event name + uint32_t timestamp; // Milliseconds since connection creation (MG_EV_OPEN) }; -void qp_mark(unsigned int type, int len); -void qp_log(void); // timestamp, type, payload -void qp_init(void); +#define MG_PROFILE_ALLOC_GRANULARITY 256 // Can save 32 items wih to realloc + +// Adding a profile item to the c->prof. Must be as fast as possible. +// Reallocation of the c->prof iobuf is not desirable here, that's why we +// pre-allocate c->prof with MG_PROFILE_ALLOC_GRANULARITY. +// This macro just inits and copies 8 bytes, and calls mg_millis(), +// which should be fast enough. +#define MG_PROF_ADD(c, name_) \ + do { \ + struct mg_iobuf *io = &c->prof; \ + uint32_t inittime = ((struct mg_profitem *) io->buf)->timestamp; \ + struct mg_profitem item = {name_, (uint32_t) mg_millis() - inittime}; \ + mg_iobuf_add(io, io->len, &item, sizeof(item)); \ + } while (0) + +// Initialising profile for a new connection. Not time sensitive +#define MG_PROF_INIT(c) \ + do { \ + struct mg_profitem first = {"init", (uint32_t) mg_millis()}; \ + mg_iobuf_init(&(c)->prof, 0, MG_PROFILE_ALLOC_GRANULARITY); \ + mg_iobuf_add(&c->prof, c->prof.len, &first, sizeof(first)); \ + } while (0) + +#define MG_PROF_FREE(c) mg_iobuf_free(&(c)->prof) + +// Dumping the profile. Not time sensitive +#define MG_PROF_DUMP(c) \ + do { \ + struct mg_iobuf *io = &c->prof; \ + struct mg_profitem *p = (struct mg_profitem *) io->buf; \ + struct mg_profitem *e = &p[io->len / sizeof(*p)]; \ + MG_INFO(("%lu profile:", c->id)); \ + while (p < e) { \ + MG_INFO(("%5lx %s", (unsigned long) p->timestamp, p->name)); \ + p++; \ + } \ + } while (0) + #else -#define qp_mark(a, b) +#define MG_PROF_INIT(c) +#define MG_PROF_FREE(c) +#define MG_PROF_ADD(c, name) +#define MG_PROF_DUMP(c) +#endif + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_CMSIS) && MG_ENABLE_DRIVER_CMSIS + +#include "Driver_ETH_MAC.h" // keep this include +#include "Driver_ETH_PHY.h" // keep this include + +#endif + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_IMXRT) && MG_ENABLE_DRIVER_IMXRT + +struct mg_tcpip_driver_imxrt_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 + + uint8_t phy_addr; // PHY address +}; + +#ifndef MG_TCPIP_PHY_ADDR +#define MG_TCPIP_PHY_ADDR 2 +#endif + +#ifndef MG_DRIVER_MDC_CR +#define MG_DRIVER_MDC_CR 24 +#endif + +#define MG_TCPIP_DRIVER_INIT(mgr) \ + do { \ + static struct mg_tcpip_driver_imxrt_data driver_data_; \ + static struct mg_tcpip_if mif_; \ + driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \ + driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \ + mif_.ip = MG_TCPIP_IP; \ + mif_.mask = MG_TCPIP_MASK; \ + mif_.gw = MG_TCPIP_GW; \ + mif_.driver = &mg_tcpip_driver_imxrt; \ + mif_.driver_data = &driver_data_; \ + MG_SET_MAC_ADDRESS(mif_.mac); \ + mg_tcpip_init(mgr, &mif_); \ + MG_INFO(("Driver: imxrt, MAC: %M", mg_print_mac, mif_.mac)); \ + } while (0) + #endif -struct mip_driver_stm32_data { + + +struct mg_phy { + uint16_t (*read_reg)(uint8_t addr, uint8_t reg); + void (*write_reg)(uint8_t addr, uint8_t reg, uint16_t value); +}; + +// PHY configuration settings, bitmask +enum { + MG_PHY_LEDS_ACTIVE_HIGH = + (1 << 0), // Set if PHY LEDs are connected to ground + MG_PHY_CLOCKS_MAC = + (1 << 1) // Set when PHY clocks MAC. Otherwise, MAC clocks PHY +}; + +enum { MG_PHY_SPEED_10M, MG_PHY_SPEED_100M, MG_PHY_SPEED_1000M }; + +void mg_phy_init(struct mg_phy *, uint8_t addr, uint8_t config); +bool mg_phy_up(struct mg_phy *, uint8_t addr, bool *full_duplex, + uint8_t *speed); + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_RA) && MG_ENABLE_DRIVER_RA + +struct mg_tcpip_driver_ra_data { + // MDC clock "divider". MDC clock is software generated, + uint32_t clock; // core clock frequency in Hz + uint16_t irqno; // IRQn, R_ICU->IELSR[irqno] + uint8_t phy_addr; // PHY address +}; + +#endif + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && MG_ENABLE_DRIVER_SAME54 + +struct mg_tcpip_driver_same54_data { + int mdc_cr; +}; + +#ifndef MG_DRIVER_MDC_CR +#define MG_DRIVER_MDC_CR 5 +#endif + +#endif + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_STM32F) && \ + MG_ENABLE_DRIVER_STM32F + +struct mg_tcpip_driver_stm32f_data { // MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz // HCLK range DIVIDER mdc_cr VALUE // ------------------------------------- @@ -1528,10 +2817,88 @@ struct mip_driver_stm32_data { // 216-310 MHz HCLK/124 5 // 110, 111 Reserved int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5 + + uint8_t phy_addr; // PHY address +}; + +#ifndef MG_TCPIP_PHY_ADDR +#define MG_TCPIP_PHY_ADDR 0 +#endif + +#ifndef MG_DRIVER_MDC_CR +#define MG_DRIVER_MDC_CR 4 +#endif + +#define MG_TCPIP_DRIVER_INIT(mgr) \ + do { \ + static struct mg_tcpip_driver_stm32f_data driver_data_; \ + static struct mg_tcpip_if mif_; \ + driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \ + driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \ + mif_.ip = MG_TCPIP_IP; \ + mif_.mask = MG_TCPIP_MASK; \ + mif_.gw = MG_TCPIP_GW; \ + mif_.driver = &mg_tcpip_driver_stm32f; \ + mif_.driver_data = &driver_data_; \ + MG_SET_MAC_ADDRESS(mif_.mac); \ + mg_tcpip_init(mgr, &mif_); \ + MG_INFO(("Driver: stm32f, MAC: %M", mg_print_mac, mif_.mac)); \ + } while (0) + +#endif + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_STM32H) && \ + MG_ENABLE_DRIVER_STM32H + +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 max speed HSI + // 250-300 MHz HCLK/124 5 <-- value for Nucleo-H* on CSI + // 110, 111 Reserved + int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5 + + uint8_t phy_addr; // PHY address + uint8_t phy_conf; // PHY config }; +#ifndef MG_TCPIP_PHY_ADDR +#define MG_TCPIP_PHY_ADDR 0 +#endif + +#ifndef MG_DRIVER_MDC_CR +#define MG_DRIVER_MDC_CR 4 +#endif + +#define MG_TCPIP_DRIVER_INIT(mgr) \ + do { \ + static struct mg_tcpip_driver_stm32h_data driver_data_; \ + static struct mg_tcpip_if mif_; \ + driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \ + driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \ + mif_.ip = MG_TCPIP_IP; \ + mif_.mask = MG_TCPIP_MASK; \ + mif_.gw = MG_TCPIP_GW; \ + mif_.driver = &mg_tcpip_driver_stm32h; \ + mif_.driver_data = &driver_data_; \ + MG_SET_MAC_ADDRESS(mif_.mac); \ + mg_tcpip_init(mgr, &mif_); \ + MG_INFO(("Driver: stm32h, MAC: %M", mg_print_mac, mif_.mac)); \ + } while (0) + +#endif + -struct mip_driver_tm4c_data { +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_TM4C) && MG_ENABLE_DRIVER_TM4C + +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 // ------------------------------------- @@ -1544,6 +2911,102 @@ struct mip_driver_tm4c_data { int mdc_cr; // Valid values: -1, 0, 1, 2, 3 }; +#ifndef MG_DRIVER_MDC_CR +#define MG_DRIVER_MDC_CR 1 +#endif + +#endif + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_W5500) && MG_ENABLE_DRIVER_W5500 + +#undef MG_ENABLE_TCPIP_DRIVER_INIT +#define MG_ENABLE_TCPIP_DRIVER_INIT 0 + +#endif + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC7) && MG_ENABLE_DRIVER_XMC7 + +struct mg_tcpip_driver_xmc7_data { + int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5 + uint8_t phy_addr; +}; + +#ifndef MG_TCPIP_PHY_ADDR +#define MG_TCPIP_PHY_ADDR 0 +#endif + +#ifndef MG_DRIVER_MDC_CR +#define MG_DRIVER_MDC_CR 3 +#endif + +#define MG_TCPIP_DRIVER_INIT(mgr) \ + do { \ + static struct mg_tcpip_driver_xmc7_data driver_data_; \ + static struct mg_tcpip_if mif_; \ + driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \ + driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \ + mif_.ip = MG_TCPIP_IP; \ + mif_.mask = MG_TCPIP_MASK; \ + mif_.gw = MG_TCPIP_GW; \ + mif_.driver = &mg_tcpip_driver_xmc7; \ + mif_.driver_data = &driver_data_; \ + MG_SET_MAC_ADDRESS(mif_.mac); \ + mg_tcpip_init(mgr, &mif_); \ + MG_INFO(("Driver: xmc7, MAC: %M", mg_print_mac, mif_.mac)); \ + } while (0) + +#endif + + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC) && MG_ENABLE_DRIVER_XMC + +struct mg_tcpip_driver_xmc_data { + // 13.2.8.1 Station Management Functions + // MDC clock divider (). MDC clock is derived from ETH MAC clock + // It must not exceed 2.5MHz + // ETH Clock range DIVIDER mdc_cr VALUE + // -------------------------------------------- + // -1 <-- tell driver to guess the value + // 60-100 MHz ETH Clock/42 0 + // 100-150 MHz ETH Clock/62 1 + // 20-35 MHz ETH Clock/16 2 + // 35-60 MHz ETH Clock/26 3 + // 150-250 MHz ETH Clock/102 4 + // 250-300 MHz ETH Clock/124 5 + // 110, 111 Reserved + int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5 + uint8_t phy_addr; +}; + +#ifndef MG_TCPIP_PHY_ADDR +#define MG_TCPIP_PHY_ADDR 0 +#endif + +#ifndef MG_DRIVER_MDC_CR +#define MG_DRIVER_MDC_CR 4 +#endif + +#define MG_TCPIP_DRIVER_INIT(mgr) \ + do { \ + static struct mg_tcpip_driver_xmc_data driver_data_; \ + static struct mg_tcpip_if mif_; \ + driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \ + driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \ + mif_.ip = MG_TCPIP_IP; \ + mif_.mask = MG_TCPIP_MASK; \ + mif_.gw = MG_TCPIP_GW; \ + mif_.driver = &mg_tcpip_driver_xmc; \ + mif_.driver_data = &driver_data_; \ + MG_SET_MAC_ADDRESS(mif_.mac); \ + mg_tcpip_init(mgr, &mif_); \ + MG_INFO(("Driver: xmc, MAC: %M", mg_print_mac, mif_.mac)); \ + } while (0) + +#endif + #ifdef __cplusplus } #endif diff --git a/mongoose/mongoose.c b/mongoose/mongoose.c index 83d8fe18..3fc0e14a 100644 --- a/mongoose/mongoose.c +++ b/mongoose/mongoose.c @@ -1,5 +1,5 @@ // Copyright (c) 2004-2013 Sergey Lyubka -// Copyright (c) 2013-2022 Cesanta Software Limited +// Copyright (c) 2013-2024 Cesanta Software Limited // All rights reserved // // This software is dual-licensed: you can redistribute it and/or modify @@ -15,7 +15,7 @@ // 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 +// SPDX-License-Identifier: GPL-2.0-only or commercial #include "mongoose.h" @@ -24,8 +24,7 @@ #endif - -static int mg_b64idx(int c) { +static int mg_base64_encode_single(int c) { if (c < 26) { return c + 'A'; } else if (c < 52) { @@ -37,7 +36,7 @@ static int mg_b64idx(int c) { } } -static int mg_b64rev(int c) { +static int mg_base64_decode_single(int c) { if (c >= 'A' && c <= 'Z') { return c - 'A'; } else if (c >= 'a' && c <= 'z') { @@ -55,24 +54,24 @@ static int mg_b64rev(int c) { } } -int mg_base64_update(unsigned char ch, char *to, int n) { - int rem = (n & 3) % 3; +size_t mg_base64_update(unsigned char ch, char *to, size_t n) { + unsigned long rem = (n & 3) % 3; if (rem == 0) { - to[n] = (char) mg_b64idx(ch >> 2); + to[n] = (char) mg_base64_encode_single(ch >> 2); to[++n] = (char) ((ch & 3) << 4); } else if (rem == 1) { - to[n] = (char) mg_b64idx(to[n] | (ch >> 4)); + to[n] = (char) mg_base64_encode_single(to[n] | (ch >> 4)); to[++n] = (char) ((ch & 15) << 2); } else { - to[n] = (char) mg_b64idx(to[n] | (ch >> 6)); - to[++n] = (char) mg_b64idx(ch & 63); + to[n] = (char) mg_base64_encode_single(to[n] | (ch >> 6)); + to[++n] = (char) mg_base64_encode_single(ch & 63); n++; } return n; } -int mg_base64_final(char *to, int n) { - int saved = n; +size_t mg_base64_final(char *to, size_t n) { + size_t saved = n; // printf("---[%.*s]\n", n, to); if (n & 3) n = mg_base64_update(0, to, n); if ((saved & 3) == 2) n--; @@ -82,20 +81,27 @@ int mg_base64_final(char *to, int n) { return n; } -int mg_base64_encode(const unsigned char *p, int n, char *to) { - int i, len = 0; +size_t mg_base64_encode(const unsigned char *p, size_t n, char *to, size_t dl) { + size_t i, len = 0; + if (dl > 0) to[0] = '\0'; + if (dl < ((n / 3) + (n % 3 ? 1 : 0)) * 4 + 1) return 0; for (i = 0; i < n; i++) len = mg_base64_update(p[i], to, len); len = mg_base64_final(to, len); return len; } -int mg_base64_decode(const char *src, int n, char *dst) { +size_t mg_base64_decode(const char *src, size_t n, char *dst, size_t dl) { const char *end = src == NULL ? NULL : src + n; // Cannot add to NULL - int len = 0; + size_t len = 0; + if (dl < n / 4 * 3 + 1) goto fail; while (src != NULL && src + 3 < end) { - int a = mg_b64rev(src[0]), b = mg_b64rev(src[1]), c = mg_b64rev(src[2]), - d = mg_b64rev(src[3]); - if (a == 64 || a < 0 || b == 64 || b < 0 || c < 0 || d < 0) return 0; + int a = mg_base64_decode_single(src[0]), + b = mg_base64_decode_single(src[1]), + c = mg_base64_decode_single(src[2]), + d = mg_base64_decode_single(src[3]); + if (a == 64 || a < 0 || b == 64 || b < 0 || c < 0 || d < 0) { + goto fail; + } dst[len++] = (char) ((a << 2) | (b >> 4)); if (src[2] != '=') { dst[len++] = (char) ((b << 4) | (c >> 2)); @@ -105,1942 +111,2915 @@ int mg_base64_decode(const char *src, int n, char *dst) { } dst[len] = '\0'; return len; +fail: + if (dl > 0) dst[0] = '\0'; + return 0; } #ifdef MG_ENABLE_LINES -#line 1 "src/dns.c" +#line 1 "src/device_ch32v307.c" #endif +#if MG_DEVICE == MG_DEVICE_CH32V307 +// RM: https://www.wch-ic.com/downloads/CH32FV2x_V3xRM_PDF.html +#define FLASH_BASE 0x40022000 +#define FLASH_ACTLR (FLASH_BASE + 0) +#define FLASH_KEYR (FLASH_BASE + 4) +#define FLASH_OBKEYR (FLASH_BASE + 8) +#define FLASH_STATR (FLASH_BASE + 12) +#define FLASH_CTLR (FLASH_BASE + 16) +#define FLASH_ADDR (FLASH_BASE + 20) +#define FLASH_OBR (FLASH_BASE + 28) +#define FLASH_WPR (FLASH_BASE + 32) - - -struct dns_data { - struct dns_data *next; - struct mg_connection *c; - uint64_t expire; - uint16_t txnid; -}; - -static void mg_sendnsreq(struct mg_connection *, struct mg_str *, int, - struct mg_dns *, bool); - -static void mg_dns_free(struct mg_connection *c, struct dns_data *d) { - LIST_DELETE(struct dns_data, - (struct dns_data **) &c->mgr->active_dns_requests, d); - free(d); +void *mg_flash_start(void) { + return (void *) 0x08000000; } - -void mg_resolve_cancel(struct mg_connection *c) { - struct dns_data *tmp, *d = (struct dns_data *) c->mgr->active_dns_requests; - for (; d != NULL; d = tmp) { - tmp = d->next; - if (d->c == c) mg_dns_free(c, d); +size_t mg_flash_size(void) { + return 480 * 1024; // First 320k is 0-wait +} +size_t mg_flash_sector_size(void) { + return 4096; +} +size_t mg_flash_write_align(void) { + return 4; +} +int mg_flash_bank(void) { + return 0; +} +void mg_device_reset(void) { + *((volatile uint32_t *) 0xbeef0000) |= 1U << 7; // NVIC_SystemReset() +} +static void flash_unlock(void) { + static bool unlocked; + if (unlocked == false) { + MG_REG(FLASH_KEYR) = 0x45670123; + MG_REG(FLASH_KEYR) = 0xcdef89ab; + unlocked = true; } } +static void flash_wait(void) { + while (MG_REG(FLASH_STATR) & MG_BIT(0)) (void) 0; +} -static size_t mg_dns_parse_name_depth(const uint8_t *s, size_t len, size_t ofs, - char *to, size_t tolen, size_t j, - int depth) { - size_t i = 0; - if (tolen > 0 && depth == 0) to[0] = '\0'; - if (depth > 5) return 0; - // MG_INFO(("ofs %lx %x %x", (unsigned long) ofs, s[ofs], s[ofs + 1])); - while (ofs + i + 1 < len) { - size_t n = s[ofs + i]; - if (n == 0) { - i++; - break; - } - if (n & 0xc0) { - size_t ptr = (((n & 0x3f) << 8) | s[ofs + i + 1]); // 12 is hdr len - // MG_INFO(("PTR %lx", (unsigned long) ptr)); - if (ptr + 1 < len && (s[ptr] & 0xc0) == 0 && - mg_dns_parse_name_depth(s, len, ptr, to, tolen, j, depth + 1) == 0) - return 0; - i += 2; - break; - } - if (ofs + i + n + 1 >= len) return 0; - if (j > 0) { - if (j < tolen) to[j] = '.'; - j++; - } - if (j + n < tolen) memcpy(&to[j], &s[ofs + i + 1], n); - j += n; - i += n + 1; - if (j < tolen) to[j] = '\0'; // Zero-terminate this chunk - // MG_INFO(("--> [%s]", to)); - } - if (tolen > 0) to[tolen - 1] = '\0'; // Make sure make sure it is nul-term - return i; +bool mg_flash_erase(void *addr) { + //MG_INFO(("%p", addr)); + flash_unlock(); + flash_wait(); + MG_REG(FLASH_ADDR) = (uint32_t) addr; + MG_REG(FLASH_CTLR) |= MG_BIT(1) | MG_BIT(6); // PER | STRT; + flash_wait(); + return true; } -static size_t mg_dns_parse_name(const uint8_t *s, size_t n, size_t ofs, - char *dst, size_t dstlen) { - return mg_dns_parse_name_depth(s, n, ofs, dst, dstlen, 0, 0); +static bool is_page_boundary(const void *addr) { + uint32_t val = (uint32_t) addr; + return (val & (mg_flash_sector_size() - 1)) == 0; } -size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs, - bool is_question, struct mg_dns_rr *rr) { - const uint8_t *s = buf + ofs, *e = &buf[len]; +bool mg_flash_write(void *addr, const void *buf, size_t len) { + //MG_INFO(("%p %p %lu", addr, buf, len)); + //mg_hexdump(buf, len); + flash_unlock(); + const uint16_t *src = (uint16_t *) buf, *end = &src[len / 2]; + uint16_t *dst = (uint16_t *) addr; + MG_REG(FLASH_CTLR) |= MG_BIT(0); // Set PG + //MG_INFO(("CTLR: %#lx", MG_REG(FLASH_CTLR))); + while (src < end) { + if (is_page_boundary(dst)) mg_flash_erase(dst); + *dst++ = *src++; + flash_wait(); + } + MG_REG(FLASH_CTLR) &= ~MG_BIT(0); // Clear PG + return true; +} +#endif - memset(rr, 0, sizeof(*rr)); - if (len < sizeof(struct mg_dns_header)) return 0; // Too small - if (len > 512) return 0; // Too large, we don't expect that - if (s >= e) return 0; // Overflow +#ifdef MG_ENABLE_LINES +#line 1 "src/device_dummy.c" +#endif - if ((rr->nlen = (uint16_t) mg_dns_parse_name(buf, len, ofs, NULL, 0)) == 0) - return 0; - s += rr->nlen + 4; - if (s > e) return 0; - rr->atype = (uint16_t) (((uint16_t) s[-4] << 8) | s[-3]); - rr->aclass = (uint16_t) (((uint16_t) s[-2] << 8) | s[-1]); - if (is_question) return (size_t) (rr->nlen + 4); - s += 6; - if (s > e) return 0; - rr->alen = (uint16_t) (((uint16_t) s[-2] << 8) | s[-1]); - if (s + rr->alen > e) return 0; - return (size_t) (rr->nlen + rr->alen + 10); +#if MG_DEVICE == MG_DEVICE_NONE +void *mg_flash_start(void) { + return NULL; +} +size_t mg_flash_size(void) { + return 0; +} +size_t mg_flash_sector_size(void) { + return 0; +} +size_t mg_flash_write_align(void) { + return 0; +} +int mg_flash_bank(void) { + return 0; +} +bool mg_flash_erase(void *location) { + (void) location; + return false; +} +bool mg_flash_swap_bank(void) { + return true; +} +bool mg_flash_write(void *addr, const void *buf, size_t len) { + (void) addr, (void) buf, (void) len; + return false; +} +void mg_device_reset(void) { } +#endif -bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *dm) { - const struct mg_dns_header *h = (struct mg_dns_header *) buf; - struct mg_dns_rr rr; - size_t i, n, ofs = sizeof(*h); - memset(dm, 0, sizeof(*dm)); +#ifdef MG_ENABLE_LINES +#line 1 "src/device_flash.c" +#endif - if (len < sizeof(*h)) return 0; // Too small, headers dont fit - if (mg_ntohs(h->num_questions) > 1) return 0; // Sanity - if (mg_ntohs(h->num_answers) > 10) return 0; // Sanity - dm->txnid = mg_ntohs(h->txnid); - for (i = 0; i < mg_ntohs(h->num_questions); i++) { - if ((n = mg_dns_parse_rr(buf, len, ofs, true, &rr)) == 0) return false; - // MG_INFO(("Q %lu %lu %hu/%hu", ofs, n, rr.atype, rr.aclass)); - ofs += n; +#if MG_DEVICE == MG_DEVICE_STM32H7 || MG_DEVICE == MG_DEVICE_STM32H5 || \ + MG_DEVICE == MG_DEVICE_RT1020 || MG_DEVICE == MG_DEVICE_RT1060 +// Flash can be written only if it is erased. Erased flash is 0xff (all bits 1) +// Writes must be mg_flash_write_align() - aligned. Thus if we want to save an +// object, we pad it at the end for alignment. +// +// Objects in the flash sector are stored sequentially: +// | 32-bit size | 32-bit KEY | ..data.. | ..pad.. | 32-bit size | ...... +// +// In order to get to the next object, read its size, then align up. + +// Traverse the list of saved objects +size_t mg_flash_next(char *p, char *end, uint32_t *key, size_t *size) { + size_t aligned_size = 0, align = mg_flash_write_align(), left = end - p; + uint32_t *p32 = (uint32_t *) p, min_size = sizeof(uint32_t) * 2; + if (p32[0] != 0xffffffff && left > MG_ROUND_UP(min_size, align)) { + if (size) *size = (size_t) p32[0]; + if (key) *key = p32[1]; + aligned_size = MG_ROUND_UP(p32[0] + sizeof(uint32_t) * 2, align); + if (left < aligned_size) aligned_size = 0; // Out of bounds, fail } - for (i = 0; i < mg_ntohs(h->num_answers); i++) { - if ((n = mg_dns_parse_rr(buf, len, ofs, false, &rr)) == 0) return false; - // MG_INFO(("A -- %lu %lu %hu/%hu %s", ofs, n, rr.atype, rr.aclass, - // dm->name)); - mg_dns_parse_name(buf, len, ofs, dm->name, sizeof(dm->name)); - ofs += n; - - if (rr.alen == 4 && rr.atype == 1 && rr.aclass == 1) { - dm->addr.is_ip6 = false; - memcpy(&dm->addr.ip, &buf[ofs - 4], 4); - dm->resolved = true; - break; // Return success - } else if (rr.alen == 16 && rr.atype == 28 && rr.aclass == 1) { - dm->addr.is_ip6 = true; - memcpy(&dm->addr.ip6, &buf[ofs - 16], 16); - dm->resolved = true; - break; // Return success + return aligned_size; +} + +// Return the last sector of Bank 2 +static char *flash_last_sector(void) { + size_t ss = mg_flash_sector_size(), size = mg_flash_size(); + char *base = (char *) mg_flash_start(), *last = base + size - ss; + if (mg_flash_bank() == 2) last -= size / 2; + return last; +} + +// Find a saved object with a given key +bool mg_flash_load(void *sector, uint32_t key, void *buf, size_t len) { + char *base = (char *) mg_flash_start(), *s = (char *) sector, *res = NULL; + size_t ss = mg_flash_sector_size(), ofs = 0, n, sz; + bool ok = false; + if (s == NULL) s = flash_last_sector(); + if (s < base || s >= base + mg_flash_size()) { + MG_ERROR(("%p is outsize of flash", sector)); + } else if (((s - base) % ss) != 0) { + MG_ERROR(("%p is not a sector boundary", sector)); + } else { + uint32_t k, scanned = 0; + while ((n = mg_flash_next(s + ofs, s + ss, &k, &sz)) > 0) { + // MG_DEBUG((" > obj %lu, ofs %lu, key %x/%x", scanned, ofs, k, key)); + // mg_hexdump(s + ofs, n); + if (k == key && sz == len) { + res = s + ofs + sizeof(uint32_t) * 2; + memcpy(buf, res, len); // Copy object + ok = true; // Keep scanning for the newer versions of it + } + ofs += n, scanned++; } + MG_DEBUG(("Scanned %u objects, key %x is @ %p", scanned, key, res)); } - return true; + return ok; } -static void dns_cb(struct mg_connection *c, int ev, void *ev_data, - void *fn_data) { - struct dns_data *d, *tmp; - if (ev == MG_EV_POLL) { - uint64_t now = *(uint64_t *) ev_data; - for (d = (struct dns_data *) c->mgr->active_dns_requests; d != NULL; - d = tmp) { - tmp = d->next; - // MG_DEBUG ("%lu %lu dns poll", d->expire, now)); - if (now > d->expire) mg_error(d->c, "DNS timeout"); +// For all saved objects in the sector, delete old versions of objects +static void mg_flash_sector_cleanup(char *sector) { + // Buffer all saved objects into an IO buffer (backed by RAM) + // erase sector, and re-save them. + struct mg_iobuf io = {0, 0, 0, 2048}; + size_t ss = mg_flash_sector_size(); + size_t n, size, size2, ofs = 0, hs = sizeof(uint32_t) * 2; + uint32_t key; + // Traverse all objects + MG_DEBUG(("Cleaning up sector %p", sector)); + while ((n = mg_flash_next(sector + ofs, sector + ss, &key, &size)) > 0) { + // Delete an old copy of this object in the cache + for (size_t o = 0; o < io.len; o += size2 + hs) { + uint32_t k = *(uint32_t *) (io.buf + o + sizeof(uint32_t)); + size2 = *(uint32_t *) (io.buf + o); + if (k == key) { + mg_iobuf_del(&io, o, size2 + hs); + break; + } } - } else if (ev == MG_EV_READ) { - struct mg_dns_message dm; - int resolved = 0; - if (mg_dns_parse(c->recv.buf, c->recv.len, &dm) == false) { - MG_ERROR(("Unexpected DNS response:")); - mg_hexdump(c->recv.buf, c->recv.len); - } else { - // MG_VERBOSE(("%s %d", dm.name, dm.resolved)); - for (d = (struct dns_data *) c->mgr->active_dns_requests; d != NULL; - d = tmp) { - tmp = d->next; - // MG_INFO(("d %p %hu %hu", d, d->txnid, dm.txnid)); - if (dm.txnid != d->txnid) continue; - if (d->c->is_resolving) { - if (dm.resolved) { - dm.addr.port = d->c->rem.port; // Save port - d->c->rem = dm.addr; // Copy resolved address - MG_DEBUG( - ("%lu %s is %I", d->c->id, dm.name, d->c->rem.is_ip6 ? 16 : 4, - d->c->rem.is_ip6 ? &d->c->rem.ip6 : (void *) &d->c->rem.ip)); - mg_connect_resolved(d->c); -#if MG_ENABLE_IPV6 - } else if (dm.addr.is_ip6 == false && dm.name[0] != '\0' && - c->mgr->use_dns6 == false) { - struct mg_str x = mg_str(dm.name); - mg_sendnsreq(d->c, &x, c->mgr->dnstimeout, &c->mgr->dns6, true); -#endif - } else { - mg_error(d->c, "%s DNS lookup failed", dm.name); + // And add the new copy + mg_iobuf_add(&io, io.len, sector + ofs, size + hs); + ofs += n; + } + // All objects are cached in RAM now + if (mg_flash_erase(sector)) { // Erase sector. If successful, + for (ofs = 0; ofs < io.len; ofs += size + hs) { // Traverse cached objects + size = *(uint32_t *) (io.buf + ofs); + key = *(uint32_t *) (io.buf + ofs + sizeof(uint32_t)); + mg_flash_save(sector, key, io.buf + ofs + hs, size); // Save to flash + } + } + mg_iobuf_free(&io); +} + +// Save an object with a given key - append to the end of an object list +bool mg_flash_save(void *sector, uint32_t key, const void *buf, size_t len) { + char *base = (char *) mg_flash_start(), *s = (char *) sector; + size_t ss = mg_flash_sector_size(), ofs = 0, n; + bool ok = false; + if (s == NULL) s = flash_last_sector(); + if (s < base || s >= base + mg_flash_size()) { + MG_ERROR(("%p is outsize of flash", sector)); + } else if (((s - base) % ss) != 0) { + MG_ERROR(("%p is not a sector boundary", sector)); + } else { + char ab[mg_flash_write_align()]; // Aligned write block + uint32_t hdr[2] = {(uint32_t) len, key}; + size_t needed = sizeof(hdr) + len; + size_t needed_aligned = MG_ROUND_UP(needed, sizeof(ab)); + while ((n = mg_flash_next(s + ofs, s + ss, NULL, NULL)) > 0) ofs += n; + + // If there is not enough space left, cleanup sector and re-eval ofs + if (ofs + needed_aligned >= ss) { + mg_flash_sector_cleanup(s); + ofs = 0; + while ((n = mg_flash_next(s + ofs, s + ss, NULL, NULL)) > 0) ofs += n; + } + + if (ofs + needed_aligned <= ss) { + // Enough space to save this object + if (sizeof(ab) < sizeof(hdr)) { + // Flash write granularity is 32 bit or less, write with no buffering + ok = mg_flash_write(s + ofs, hdr, sizeof(hdr)); + if (ok) mg_flash_write(s + ofs + sizeof(hdr), buf, len); + } else { + // Flash granularity is sizeof(hdr) or more. We need to save in + // 3 chunks: initial block, bulk, rest. This is because we have + // two memory chunks to write: hdr and buf, on aligned boundaries. + n = sizeof(ab) - sizeof(hdr); // Initial chunk that we write + if (n > len) n = len; // is + memset(ab, 0xff, sizeof(ab)); // initialized to all-one + memcpy(ab, hdr, sizeof(hdr)); // contains the header (key + size) + memcpy(ab + sizeof(hdr), buf, n); // and an initial part of buf + MG_INFO(("saving initial block of %lu", sizeof(ab))); + ok = mg_flash_write(s + ofs, ab, sizeof(ab)); + if (ok && len > n) { + size_t n2 = MG_ROUND_DOWN(len - n, sizeof(ab)); + if (n2 > 0) { + MG_INFO(("saving bulk, %lu", n2)); + ok = mg_flash_write(s + ofs + sizeof(ab), (char *) buf + n, n2); + } + if (ok && len > n) { + size_t n3 = len - n - n2; + if (n3 > sizeof(ab)) n3 = sizeof(ab); + memset(ab, 0xff, sizeof(ab)); + memcpy(ab, (char *) buf + n + n2, n3); + MG_INFO(("saving rest, %lu", n3)); + ok = mg_flash_write(s + ofs + sizeof(ab) + n2, ab, sizeof(ab)); } - } else { - MG_ERROR(("%lu already resolved", d->c->id)); } - mg_dns_free(c, d); - resolved = 1; } - } - if (!resolved) MG_ERROR(("stray DNS reply")); - c->recv.len = 0; - } else if (ev == MG_EV_CLOSE) { - for (d = (struct dns_data *) c->mgr->active_dns_requests; d != NULL; - d = tmp) { - tmp = d->next; - mg_error(d->c, "DNS error"); - mg_dns_free(c, d); + MG_DEBUG(("Saved %lu/%lu bytes @ %p, key %x: %d", len, needed_aligned, + s + ofs, key, ok)); + MG_DEBUG(("Sector space left: %lu bytes", ss - ofs - needed_aligned)); + } else { + MG_ERROR(("Sector is full")); } } - (void) fn_data; + return ok; +} +#else +bool mg_flash_save(void *sector, uint32_t key, const void *buf, size_t len) { + (void) sector, (void) key, (void) buf, (void) len; + return false; +} +bool mg_flash_load(void *sector, uint32_t key, void *buf, size_t len) { + (void) sector, (void) key, (void) buf, (void) len; + return false; } +#endif -static bool mg_dns_send(struct mg_connection *c, const struct mg_str *name, - uint16_t txnid, bool ipv6) { - struct { - struct mg_dns_header header; - uint8_t data[256]; - } pkt; - size_t i, n; - memset(&pkt, 0, sizeof(pkt)); - pkt.header.txnid = mg_htons(txnid); - pkt.header.flags = mg_htons(0x100); - pkt.header.num_questions = mg_htons(1); - for (i = n = 0; i < sizeof(pkt.data) - 5; i++) { - if (name->ptr[i] == '.' || i >= name->len) { - pkt.data[n] = (uint8_t) (i - n); - memcpy(&pkt.data[n + 1], name->ptr + n, i - n); - n = i + 1; - } - if (i >= name->len) break; +#ifdef MG_ENABLE_LINES +#line 1 "src/device_imxrt.c" +#endif + + + +#if MG_DEVICE == MG_DEVICE_RT1020 || MG_DEVICE == MG_DEVICE_RT1060 + +struct mg_flexspi_lut_seq { + uint8_t seqNum; + uint8_t seqId; + uint16_t reserved; +}; + +struct mg_flexspi_mem_config { + uint32_t tag; + uint32_t version; + uint32_t reserved0; + uint8_t readSampleClkSrc; + uint8_t csHoldTime; + uint8_t csSetupTime; + uint8_t columnAddressWidth; + uint8_t deviceModeCfgEnable; + uint8_t deviceModeType; + uint16_t waitTimeCfgCommands; + struct mg_flexspi_lut_seq deviceModeSeq; + uint32_t deviceModeArg; + uint8_t configCmdEnable; + uint8_t configModeType[3]; + struct mg_flexspi_lut_seq configCmdSeqs[3]; + uint32_t reserved1; + uint32_t configCmdArgs[3]; + uint32_t reserved2; + uint32_t controllerMiscOption; + uint8_t deviceType; + uint8_t sflashPadType; + uint8_t serialClkFreq; + uint8_t lutCustomSeqEnable; + uint32_t reserved3[2]; + uint32_t sflashA1Size; + uint32_t sflashA2Size; + uint32_t sflashB1Size; + uint32_t sflashB2Size; + uint32_t csPadSettingOverride; + uint32_t sclkPadSettingOverride; + uint32_t dataPadSettingOverride; + uint32_t dqsPadSettingOverride; + uint32_t timeoutInMs; + uint32_t commandInterval; + uint16_t dataValidTime[2]; + uint16_t busyOffset; + uint16_t busyBitPolarity; + uint32_t lookupTable[64]; + struct mg_flexspi_lut_seq lutCustomSeq[12]; + uint32_t reserved4[4]; +}; + +struct mg_flexspi_nor_config { + struct mg_flexspi_mem_config memConfig; + uint32_t pageSize; + uint32_t sectorSize; + uint8_t ipcmdSerialClkFreq; + uint8_t isUniformBlockSize; + uint8_t reserved0[2]; + uint8_t serialNorType; + uint8_t needExitNoCmdMode; + uint8_t halfClkForNonReadCmd; + uint8_t needRestoreNoCmdMode; + uint32_t blockSize; + uint32_t reserve2[11]; +}; + +/* FLEXSPI memory config block related defintions */ +#define MG_FLEXSPI_CFG_BLK_TAG (0x42464346UL) // ascii "FCFB" Big Endian +#define MG_FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0 + +#define MG_FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1) \ + (MG_FLEXSPI_LUT_OPERAND0(op0) | MG_FLEXSPI_LUT_NUM_PADS0(pad0) | MG_FLEXSPI_LUT_OPCODE0(cmd0) | \ + MG_FLEXSPI_LUT_OPERAND1(op1) | MG_FLEXSPI_LUT_NUM_PADS1(pad1) | MG_FLEXSPI_LUT_OPCODE1(cmd1)) + +#define MG_CMD_SDR 0x01 +#define MG_CMD_DDR 0x21 +#define MG_DUMMY_SDR 0x0C +#define MG_DUMMY_DDR 0x2C +#define MG_RADDR_SDR 0x02 +#define MG_RADDR_DDR 0x22 +#define MG_READ_SDR 0x09 +#define MG_READ_DDR 0x29 +#define MG_WRITE_SDR 0x08 +#define MG_WRITE_DDR 0x28 +#define MG_STOP 0 + +#define MG_FLEXSPI_1PAD 0 +#define MG_FLEXSPI_2PAD 1 +#define MG_FLEXSPI_4PAD 2 +#define MG_FLEXSPI_8PAD 3 + +#define MG_FLEXSPI_QSPI_LUT \ + { \ + [0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_SDR, MG_FLEXSPI_1PAD, 0xEB, MG_RADDR_SDR, MG_FLEXSPI_4PAD, \ + 0x18), \ + [1] = MG_FLEXSPI_LUT_SEQ(MG_DUMMY_SDR, MG_FLEXSPI_4PAD, 0x06, MG_READ_SDR, MG_FLEXSPI_4PAD, \ + 0x04), \ + [4 * 1 + 0] = \ + MG_FLEXSPI_LUT_SEQ(MG_CMD_SDR, MG_FLEXSPI_1PAD, 0x05, MG_READ_SDR, MG_FLEXSPI_1PAD, 0x04), \ + [4 * 3 + 0] = \ + MG_FLEXSPI_LUT_SEQ(MG_CMD_SDR, MG_FLEXSPI_1PAD, 0x06, MG_STOP, MG_FLEXSPI_1PAD, 0x0), \ + [4 * 5 + 0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_SDR, MG_FLEXSPI_1PAD, 0x20, MG_RADDR_SDR, \ + MG_FLEXSPI_1PAD, 0x18), \ + [4 * 8 + 0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_SDR, MG_FLEXSPI_1PAD, 0xD8, MG_RADDR_SDR, \ + MG_FLEXSPI_1PAD, 0x18), \ + [4 * 9 + 0] = MG_FLEXSPI_LUT_SEQ(MG_CMD_SDR, MG_FLEXSPI_1PAD, 0x02, MG_RADDR_SDR, \ + MG_FLEXSPI_1PAD, 0x18), \ + [4 * 9 + 1] = \ + MG_FLEXSPI_LUT_SEQ(MG_WRITE_SDR, MG_FLEXSPI_1PAD, 0x04, MG_STOP, MG_FLEXSPI_1PAD, 0x0), \ + [4 * 11 + 0] = \ + MG_FLEXSPI_LUT_SEQ(MG_CMD_SDR, MG_FLEXSPI_1PAD, 0x60, MG_STOP, MG_FLEXSPI_1PAD, 0x0), \ } - memcpy(&pkt.data[n], "\x00\x00\x01\x00\x01", 5); // A query - n += 5; - if (ipv6) pkt.data[n - 3] = 0x1c; // AAAA query - // memcpy(&pkt.data[n], "\xc0\x0c\x00\x1c\x00\x01", 6); // AAAA query - // n += 6; - return mg_send(c, &pkt, sizeof(pkt.header) + n); + +#define MG_FLEXSPI_LUT_OPERAND0(x) (((uint32_t) (((uint32_t) (x)))) & 0xFFU) +#define MG_FLEXSPI_LUT_NUM_PADS0(x) (((uint32_t) (((uint32_t) (x)) << 8U)) & 0x300U) +#define MG_FLEXSPI_LUT_OPCODE0(x) (((uint32_t) (((uint32_t) (x)) << 10U)) & 0xFC00U) +#define MG_FLEXSPI_LUT_OPERAND1(x) (((uint32_t) (((uint32_t) (x)) << 16U)) & 0xFF0000U) +#define MG_FLEXSPI_LUT_NUM_PADS1(x) (((uint32_t) (((uint32_t) (x)) << 24U)) & 0x3000000U) +#define MG_FLEXSPI_LUT_OPCODE1(x) (((uint32_t) (((uint32_t) (x)) << 26U)) & 0xFC000000U) + +#define FLEXSPI_NOR_INSTANCE 0 + +#if MG_DEVICE == MG_DEVICE_RT1020 +struct mg_flexspi_nor_driver_interface { + uint32_t version; + int (*init)(uint32_t instance, struct mg_flexspi_nor_config *config); + int (*program)(uint32_t instance, struct mg_flexspi_nor_config *config, uint32_t dst_addr, + const uint32_t *src); + uint32_t reserved; + int (*erase)(uint32_t instance, struct mg_flexspi_nor_config *config, uint32_t start, + uint32_t lengthInBytes); + uint32_t reserved2; + int (*update_lut)(uint32_t instance, uint32_t seqIndex, const uint32_t *lutBase, + uint32_t seqNumber); + int (*xfer)(uint32_t instance, char *xfer); + void (*clear_cache)(uint32_t instance); +}; +#elif MG_DEVICE == MG_DEVICE_RT1060 +struct mg_flexspi_nor_driver_interface { + uint32_t version; + int (*init)(uint32_t instance, struct mg_flexspi_nor_config *config); + int (*program)(uint32_t instance, struct mg_flexspi_nor_config *config, uint32_t dst_addr, + const uint32_t *src); + int (*erase_all)(uint32_t instance, struct mg_flexspi_nor_config *config); + int (*erase)(uint32_t instance, struct mg_flexspi_nor_config *config, uint32_t start, + uint32_t lengthInBytes); + int (*read)(uint32_t instance, struct mg_flexspi_nor_config *config, uint32_t *dst, uint32_t addr, + uint32_t lengthInBytes); + void (*clear_cache)(uint32_t instance); + int (*xfer)(uint32_t instance, char *xfer); + int (*update_lut)(uint32_t instance, uint32_t seqIndex, const uint32_t *lutBase, + uint32_t seqNumber); + int (*get_config)(uint32_t instance, struct mg_flexspi_nor_config *config, uint32_t *option); +}; +#endif + +#define flexspi_nor (*((struct mg_flexspi_nor_driver_interface**) \ + (*(uint32_t*)0x0020001c + 16))) + +static bool s_flash_irq_disabled; + +MG_IRAM void *mg_flash_start(void) { + return (void *) 0x60000000; +} +MG_IRAM size_t mg_flash_size(void) { + return 8 * 1024 * 1024; +} +MG_IRAM size_t mg_flash_sector_size(void) { + return 4 * 1024; // 4k +} +MG_IRAM size_t mg_flash_write_align(void) { + return 256; +} +MG_IRAM int mg_flash_bank(void) { + return 0; } -static void mg_sendnsreq(struct mg_connection *c, struct mg_str *name, int ms, - struct mg_dns *dnsc, bool ipv6) { - struct dns_data *d = NULL; - if (dnsc->url == NULL) { - mg_error(c, "DNS server URL is NULL. Call mg_mgr_init()"); - } else if (dnsc->c == NULL) { - dnsc->c = mg_connect(c->mgr, dnsc->url, NULL, NULL); - if (dnsc->c != NULL) { - dnsc->c->pfn = dns_cb; - // dnsc->c->is_hexdumping = 1; - } +MG_IRAM static bool flash_page_start(volatile uint32_t *dst) { + char *base = (char *) mg_flash_start(), *end = base + mg_flash_size(); + volatile char *p = (char *) dst; + return p >= base && p < end && ((p - base) % mg_flash_sector_size()) == 0; +} + +// Note: the get_config function below works both for RT1020 and 1060 +#if MG_DEVICE == MG_DEVICE_RT1020 +MG_IRAM static int flexspi_nor_get_config(struct mg_flexspi_nor_config *config) { + struct mg_flexspi_nor_config default_config = { + .memConfig = {.tag = MG_FLEXSPI_CFG_BLK_TAG, + .version = MG_FLEXSPI_CFG_BLK_VERSION, + .readSampleClkSrc = 1, // ReadSampleClk_LoopbackFromDqsPad + .csHoldTime = 3, + .csSetupTime = 3, + .controllerMiscOption = MG_BIT(4), + .deviceType = 1, // serial NOR + .sflashPadType = 4, + .serialClkFreq = 7, // 133MHz + .sflashA1Size = 8 * 1024 * 1024, + .lookupTable = MG_FLEXSPI_QSPI_LUT}, + .pageSize = 256, + .sectorSize = 4 * 1024, + .ipcmdSerialClkFreq = 1, + .blockSize = 64 * 1024, + .isUniformBlockSize = false}; + + *config = default_config; + return 0; +} +#else +MG_IRAM static int flexspi_nor_get_config(struct mg_flexspi_nor_config *config) { + uint32_t options[] = {0xc0000000, 0x00}; + + MG_ARM_DISABLE_IRQ(); + uint32_t status = + flexspi_nor->get_config(FLEXSPI_NOR_INSTANCE, config, options); + if (!s_flash_irq_disabled) { + MG_ARM_ENABLE_IRQ(); } - if (dnsc->c == NULL) { - mg_error(c, "resolver"); - } else if ((d = (struct dns_data *) calloc(1, sizeof(*d))) == NULL) { - mg_error(c, "resolve OOM"); - } else { - struct dns_data *reqs = (struct dns_data *) c->mgr->active_dns_requests; - d->txnid = reqs ? (uint16_t) (reqs->txnid + 1) : 1; - d->next = (struct dns_data *) c->mgr->active_dns_requests; - c->mgr->active_dns_requests = d; - d->expire = mg_millis() + (uint64_t) ms; - d->c = c; - c->is_resolving = 1; - MG_VERBOSE(("%lu resolving %.*s @ %s, txnid %hu", c->id, (int) name->len, - name->ptr, &dnsc->url, d->txnid)); - if (!mg_dns_send(dnsc->c, name, d->txnid, ipv6)) { - mg_error(dnsc->c, "DNS send"); - } + if (status) { + MG_ERROR(("Failed to extract flash configuration: status %u", status)); } + return status; } +#endif -void mg_resolve(struct mg_connection *c, const char *url) { - struct mg_str host = mg_url_host(url); - c->rem.port = mg_htons(mg_url_port(url)); - if (mg_aton(host, &c->rem)) { - // host is an IP address, do not fire name resolution - mg_connect_resolved(c); - } else { - // host is not an IP, send DNS resolution request - struct mg_dns *dns = c->mgr->use_dns6 ? &c->mgr->dns6 : &c->mgr->dns4; - mg_sendnsreq(c, &host, c->mgr->dnstimeout, dns, c->mgr->use_dns6); +MG_IRAM bool mg_flash_erase(void *addr) { + struct mg_flexspi_nor_config config; + if (flexspi_nor_get_config(&config) != 0) { + return false; + } + if (flash_page_start(addr) == false) { + MG_ERROR(("%p is not on a sector boundary", addr)); + return false; + } + + void *dst = (void *)((char *) addr - (char *) mg_flash_start()); + + // Note: Interrupts must be disabled before any call to the ROM API on RT1020 + // and 1060 + MG_ARM_DISABLE_IRQ(); + bool ok = (flexspi_nor->erase(FLEXSPI_NOR_INSTANCE, &config, (uint32_t) dst, + mg_flash_sector_size()) == 0); + if (!s_flash_irq_disabled) { + MG_ARM_ENABLE_IRQ(); // Reenable them after the call } + MG_DEBUG(("Sector starting at %p erasure: %s", addr, ok ? "ok" : "fail")); + return ok; } -#ifdef MG_ENABLE_LINES -#line 1 "src/event.c" -#endif +MG_IRAM bool mg_flash_swap_bank(void) { + return true; +} + +static inline void spin(volatile uint32_t count) { + while (count--) (void) 0; +} + +static inline void flash_wait(void) { + while ((*((volatile uint32_t *)(0x402A8000 + 0xE0)) & MG_BIT(1)) == 0) + spin(1); +} +MG_IRAM static void *flash_code_location(void) { + return (void *) ((char *) mg_flash_start() + 0x2000); +} +MG_IRAM bool mg_flash_write(void *addr, const void *buf, size_t len) { + struct mg_flexspi_nor_config config; + if (flexspi_nor_get_config(&config) != 0) { + return false; + } + if ((len % mg_flash_write_align()) != 0) { + MG_ERROR(("%lu is not aligned to %lu", len, mg_flash_write_align())); + return false; + } + if ((char *) addr < (char *) mg_flash_start()) { + MG_ERROR(("Invalid flash write address: %p", addr)); + return false; + } + uint32_t *dst = (uint32_t *) addr; + uint32_t *src = (uint32_t *) buf; + uint32_t *end = (uint32_t *) ((char *) buf + len); + bool ok = true; + + // Note: If we overwrite the flash irq section of the image, we must also + // make sure interrupts are disabled and are not reenabled until we write + // this sector with another irq table. + if ((char *) addr == (char *) flash_code_location()) { + s_flash_irq_disabled = true; + MG_ARM_DISABLE_IRQ(); + } -void mg_call(struct mg_connection *c, int ev, void *ev_data) { - // Run user-defined handler first, in order to give it an ability - // to intercept processing (e.g. clean input buffer) before the - // protocol handler kicks in - if (c->fn != NULL) c->fn(c, ev, ev_data, c->fn_data); - if (c->pfn != NULL) c->pfn(c, ev, ev_data, c->pfn_data); + while (ok && src < end) { + if (flash_page_start(dst) && mg_flash_erase(dst) == false) { + break; + } + uint32_t status; + uint32_t dst_ofs = (uint32_t) dst - (uint32_t) mg_flash_start(); + if ((char *) buf >= (char *) mg_flash_start()) { + // If we copy from FLASH to FLASH, then we first need to copy the source + // to RAM + size_t tmp_buf_size = mg_flash_write_align() / sizeof(uint32_t); + uint32_t tmp[tmp_buf_size]; + + for (size_t i = 0; i < tmp_buf_size; i++) { + flash_wait(); + tmp[i] = src[i]; + } + MG_ARM_DISABLE_IRQ(); + status = flexspi_nor->program(FLEXSPI_NOR_INSTANCE, &config, + (uint32_t) dst_ofs, tmp); + } else { + MG_ARM_DISABLE_IRQ(); + status = flexspi_nor->program(FLEXSPI_NOR_INSTANCE, &config, + (uint32_t) dst_ofs, src); + } + if (!s_flash_irq_disabled) { + MG_ARM_ENABLE_IRQ(); + } + src = (uint32_t *) ((char *) src + mg_flash_write_align()); + dst = (uint32_t *) ((char *) dst + mg_flash_write_align()); + if (status != 0) { + ok = false; + } + } + MG_DEBUG(("Flash write %lu bytes @ %p: %s.", len, dst, ok ? "ok" : "fail")); + return ok; } -void mg_error(struct mg_connection *c, const char *fmt, ...) { - char buf[64]; - va_list ap; - va_start(ap, fmt); - mg_vsnprintf(buf, sizeof(buf), fmt, &ap); - va_end(ap); - MG_ERROR(("%lu %p %s", c->id, c->fd, buf)); - c->is_closing = 1; // Set is_closing before sending MG_EV_CALL - mg_call(c, MG_EV_ERROR, buf); // Let user handler to override it +MG_IRAM void mg_device_reset(void) { + MG_DEBUG(("Resetting device...")); + *(volatile unsigned long *) 0xe000ed0c = 0x5fa0004; } +#endif + #ifdef MG_ENABLE_LINES -#line 1 "src/fmt.c" +#line 1 "src/device_stm32h5.c" #endif +#if MG_DEVICE == MG_DEVICE_STM32H5 -static void mg_pfn_iobuf_private(char ch, void *param, bool expand) { - struct mg_iobuf *io = (struct mg_iobuf *) param; - if (expand && io->len + 2 > io->size) mg_iobuf_resize(io, io->len + 2); - if (io->len + 2 <= io->size) { - io->buf[io->len++] = (uint8_t) ch; - io->buf[io->len] = 0; - } else if (io->len < io->size) { - io->buf[io->len++] = 0; // Guarantee to 0-terminate - } -} +#define FLASH_BASE 0x40022000 // Base address of the flash controller +#define FLASH_KEYR (FLASH_BASE + 0x4) // See RM0481 7.11 +#define FLASH_OPTKEYR (FLASH_BASE + 0xc) +#define FLASH_OPTCR (FLASH_BASE + 0x1c) +#define FLASH_NSSR (FLASH_BASE + 0x20) +#define FLASH_NSCR (FLASH_BASE + 0x28) +#define FLASH_NSCCR (FLASH_BASE + 0x30) +#define FLASH_OPTSR_CUR (FLASH_BASE + 0x50) +#define FLASH_OPTSR_PRG (FLASH_BASE + 0x54) -static void mg_putchar_iobuf_static(char ch, void *param) { - mg_pfn_iobuf_private(ch, param, false); +void *mg_flash_start(void) { + return (void *) 0x08000000; } - -void mg_pfn_iobuf(char ch, void *param) { - mg_pfn_iobuf_private(ch, param, true); +size_t mg_flash_size(void) { + return 2 * 1024 * 1024; // 2Mb } - -size_t mg_vsnprintf(char *buf, size_t len, const char *fmt, va_list *ap) { - struct mg_iobuf io = {(uint8_t *) buf, len, 0, 0}; - size_t n = mg_vxprintf(mg_putchar_iobuf_static, &io, fmt, ap); - if (n < len) buf[n] = '\0'; - return n; +size_t mg_flash_sector_size(void) { + return 8 * 1024; // 8k } - -size_t mg_snprintf(char *buf, size_t len, const char *fmt, ...) { - va_list ap; - size_t n; - va_start(ap, fmt); - n = mg_vsnprintf(buf, len, fmt, &ap); - va_end(ap); - return n; +size_t mg_flash_write_align(void) { + return 16; // 128 bit } - -char *mg_vmprintf(const char *fmt, va_list *ap) { - struct mg_iobuf io = {0, 0, 0, 256}; - mg_vxprintf(mg_pfn_iobuf, &io, fmt, ap); - return (char *) io.buf; +int mg_flash_bank(void) { + return MG_REG(FLASH_OPTCR) & MG_BIT(31) ? 2 : 1; } -char *mg_mprintf(const char *fmt, ...) { - char *s; - va_list ap; - va_start(ap, fmt); - s = mg_vmprintf(fmt, &ap); - va_end(ap); - return s; +static void flash_unlock(void) { + static bool unlocked = false; + if (unlocked == false) { + MG_REG(FLASH_KEYR) = 0x45670123; + MG_REG(FLASH_KEYR) = 0Xcdef89ab; + MG_REG(FLASH_OPTKEYR) = 0x08192a3b; + MG_REG(FLASH_OPTKEYR) = 0x4c5d6e7f; + unlocked = true; + } } -size_t mg_xprintf(void (*out)(char, void *), void *ptr, const char *fmt, ...) { - size_t len = 0; - va_list ap; - va_start(ap, fmt); - len = mg_vxprintf(out, ptr, fmt, &ap); - va_end(ap); - return len; +static int flash_page_start(volatile uint32_t *dst) { + char *base = (char *) mg_flash_start(), *end = base + mg_flash_size(); + volatile char *p = (char *) dst; + return p >= base && p < end && ((p - base) % mg_flash_sector_size()) == 0; } -static bool is_digit(int c) { - return c >= '0' && c <= '9'; +static bool flash_is_err(void) { + return MG_REG(FLASH_NSSR) & ((MG_BIT(8) - 1) << 17); // RM0481 7.11.9 } -static int addexp(char *buf, int e, int sign) { - int n = 0; - buf[n++] = 'e'; - buf[n++] = (char) sign; - if (e > 400) return 0; - if (e < 10) buf[n++] = '0'; - if (e >= 100) buf[n++] = (char) (e / 100 + '0'), e -= 100 * (e / 100); - if (e >= 10) buf[n++] = (char) (e / 10 + '0'), e -= 10 * (e / 10); - buf[n++] = (char) (e + '0'); - return n; +static void flash_wait(void) { + while ((MG_REG(FLASH_NSSR) & MG_BIT(0)) && + (MG_REG(FLASH_NSSR) & MG_BIT(16)) == 0) { + (void) 0; + } } -static int xisinf(double x) { - union { - double f; - uint64_t u; - } ieee754 = {x}; - return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 && - ((unsigned) ieee754.u == 0); +static void flash_clear_err(void) { + flash_wait(); // Wait until ready + MG_REG(FLASH_NSCCR) = ((MG_BIT(9) - 1) << 16U); // Clear all errors } -static int xisnan(double x) { - union { - double f; - uint64_t u; - } ieee754 = {x}; - return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) + - ((unsigned) ieee754.u != 0) > - 0x7ff00000; +static bool flash_bank_is_swapped(void) { + return MG_REG(FLASH_OPTCR) & MG_BIT(31); // RM0481 7.11.8 } -static size_t mg_dtoa(char *dst, size_t dstlen, double d, int width) { - char buf[40]; - int i, s = 0, n = 0, e = 0; - double t, mul, saved; - if (d == 0.0) return mg_snprintf(dst, dstlen, "%s", "0"); - if (xisinf(d)) return mg_snprintf(dst, dstlen, "%s", d > 0 ? "inf" : "-inf"); - if (xisnan(d)) return mg_snprintf(dst, dstlen, "%s", "nan"); - if (d < 0.0) d = -d, buf[s++] = '-'; - - // Round - saved = d; - mul = 1.0; - while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0; - while (d <= 1.0 && d / mul <= 1.0) mul /= 10.0; - for (i = 0, t = mul * 5; i < width; i++) t /= 10.0; - d += t; - // Calculate exponent, and 'mul' for scientific representation - mul = 1.0; - while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0, e++; - while (d < 1.0 && d / mul < 1.0) mul /= 10.0, e--; - // printf(" --> %g %d %g %g\n", saved, e, t, mul); - - if (e >= width) { - n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width); - // printf(" --> %.*g %d [%.*s]\n", 10, d / t, e, n, buf); - n += addexp(buf + s + n, e, '+'); - return mg_snprintf(dst, dstlen, "%.*s", n, buf); - } else if (e <= -width) { - n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width); - // printf(" --> %.*g %d [%.*s]\n", 10, d / mul, e, n, buf); - n += addexp(buf + s + n, -e, '-'); - return mg_snprintf(dst, dstlen, "%.*s", n, buf); +bool mg_flash_erase(void *location) { + bool ok = false; + if (flash_page_start(location) == false) { + MG_ERROR(("%p is not on a sector boundary")); } else { - for (i = 0, t = mul; t >= 1.0 && s + n < (int) sizeof(buf); i++) { - int ch = (int) (d / t); - if (n > 0 || ch > 0) buf[s + n++] = (char) (ch + '0'); - d -= ch * t; - t /= 10.0; - } - // printf(" --> [%g] -> %g %g (%d) [%.*s]\n", saved, d, t, n, s + n, buf); - if (n == 0) buf[s++] = '0'; - while (t >= 1.0 && n + s < (int) sizeof(buf)) buf[n++] = '0', t /= 10.0; - if (s + n < (int) sizeof(buf)) buf[n + s++] = '.'; - // printf(" 1--> [%g] -> [%.*s]\n", saved, s + n, buf); - for (i = 0, t = 0.1; s + n < (int) sizeof(buf) && n < width; i++) { - int ch = (int) (d / t); - buf[s + n++] = (char) (ch + '0'); - d -= ch * t; - t /= 10.0; + uintptr_t diff = (char *) location - (char *) mg_flash_start(); + uint32_t sector = diff / mg_flash_sector_size(); + uint32_t saved_cr = MG_REG(FLASH_NSCR); // Save CR value + flash_unlock(); + flash_clear_err(); + MG_REG(FLASH_NSCR) = 0; + if ((sector < 128 && flash_bank_is_swapped()) || + (sector > 127 && !flash_bank_is_swapped())) { + MG_REG(FLASH_NSCR) |= MG_BIT(31); // Set FLASH_CR_BKSEL } + if (sector > 127) sector -= 128; + MG_REG(FLASH_NSCR) |= MG_BIT(2) | (sector << 6); // Erase | sector_num + MG_REG(FLASH_NSCR) |= MG_BIT(5); // Start erasing + flash_wait(); + ok = !flash_is_err(); + MG_DEBUG(("Erase sector %lu @ %p: %s. CR %#lx SR %#lx", sector, location, + ok ? "ok" : "fail", MG_REG(FLASH_NSCR), MG_REG(FLASH_NSSR))); + // mg_hexdump(location, 32); + MG_REG(FLASH_NSCR) = saved_cr; // Restore saved CR } - while (n > 0 && buf[s + n - 1] == '0') n--; // Trim trailing zeros - if (n > 0 && buf[s + n - 1] == '.') n--; // Trim trailing dot - n += s; - if (n >= (int) sizeof(buf)) n = (int) sizeof(buf) - 1; - buf[n] = '\0'; - return mg_snprintf(dst, dstlen, "%s", buf); + return ok; } -static size_t mg_lld(char *buf, int64_t val, bool is_signed, bool is_hex) { - const char *letters = "0123456789abcdef"; - uint64_t v = (uint64_t) val; - size_t s = 0, n, i; - if (is_signed && val < 0) buf[s++] = '-', v = (uint64_t) (-val); - // This loop prints a number in reverse order. I guess this is because we - // write numbers from right to left: least significant digit comes last. - // Maybe because we use Arabic numbers, and Arabs write RTL? - if (is_hex) { - for (n = 0; v; v >>= 4) buf[s + n++] = letters[v & 15]; - } else { - for (n = 0; v; v /= 10) buf[s + n++] = letters[v % 10]; +bool mg_flash_swap_bank(void) { + uint32_t desired = flash_bank_is_swapped() ? 0 : MG_BIT(31); + flash_unlock(); + flash_clear_err(); + // printf("OPTSR_PRG 1 %#lx\n", FLASH->OPTSR_PRG); + MG_SET_BITS(MG_REG(FLASH_OPTSR_PRG), MG_BIT(31), desired); + // printf("OPTSR_PRG 2 %#lx\n", FLASH->OPTSR_PRG); + MG_REG(FLASH_OPTCR) |= MG_BIT(1); // OPTSTART + while ((MG_REG(FLASH_OPTSR_CUR) & MG_BIT(31)) != desired) (void) 0; + return true; +} + +bool mg_flash_write(void *addr, const void *buf, size_t len) { + if ((len % mg_flash_write_align()) != 0) { + MG_ERROR(("%lu is not aligned to %lu", len, mg_flash_write_align())); + return false; } - // Reverse a string - for (i = 0; i < n / 2; i++) { - char t = buf[s + i]; - buf[s + i] = buf[s + n - i - 1], buf[s + n - i - 1] = t; + uint32_t *dst = (uint32_t *) addr; + uint32_t *src = (uint32_t *) buf; + uint32_t *end = (uint32_t *) ((char *) buf + len); + bool ok = true; + flash_unlock(); + flash_clear_err(); + MG_ARM_DISABLE_IRQ(); + // MG_DEBUG(("Starting flash write %lu bytes @ %p", len, addr)); + MG_REG(FLASH_NSCR) = MG_BIT(1); // Set programming flag + while (ok && src < end) { + if (flash_page_start(dst) && mg_flash_erase(dst) == false) break; + *(volatile uint32_t *) dst++ = *src++; + flash_wait(); + if (flash_is_err()) ok = false; } - if (val == 0) buf[n++] = '0'; // Handle special case - return n + s; + MG_ARM_ENABLE_IRQ(); + MG_DEBUG(("Flash write %lu bytes @ %p: %s. CR %#lx SR %#lx", len, dst, + flash_is_err() ? "fail" : "ok", MG_REG(FLASH_NSCR), + MG_REG(FLASH_NSSR))); + MG_REG(FLASH_NSCR) = 0; // Clear flags + return ok; } -static size_t scpy(void (*out)(char, void *), void *ptr, char *buf, - size_t len) { - size_t i = 0; - while (i < len && buf[i] != '\0') out(buf[i++], ptr); - return i; +void mg_device_reset(void) { + // SCB->AIRCR = ((0x5fa << SCB_AIRCR_VECTKEY_Pos)|SCB_AIRCR_SYSRESETREQ_Msk); + *(volatile unsigned long *) 0xe000ed0c = 0x5fa0004; } +#endif -static char mg_esc(int c, bool esc) { - const char *p, *esc1 = "\b\f\n\r\t\\\"", *esc2 = "bfnrt\\\""; - for (p = esc ? esc1 : esc2; *p != '\0'; p++) { - if (*p == c) return esc ? esc2[p - esc1] : esc1[p - esc2]; +#ifdef MG_ENABLE_LINES +#line 1 "src/device_stm32h7.c" +#endif + + + +#if MG_DEVICE == MG_DEVICE_STM32H7 + +#define FLASH_BASE1 0x52002000 // Base address for bank1 +#define FLASH_BASE2 0x52002100 // Base address for bank2 +#define FLASH_KEYR 0x04 // See RM0433 4.9.2 +#define FLASH_OPTKEYR 0x08 +#define FLASH_OPTCR 0x18 +#define FLASH_SR 0x10 +#define FLASH_CR 0x0c +#define FLASH_CCR 0x14 +#define FLASH_OPTSR_CUR 0x1c +#define FLASH_OPTSR_PRG 0x20 +#define FLASH_SIZE_REG 0x1ff1e880 + +MG_IRAM void *mg_flash_start(void) { + return (void *) 0x08000000; +} +MG_IRAM size_t mg_flash_size(void) { + return MG_REG(FLASH_SIZE_REG) * 1024; +} +MG_IRAM size_t mg_flash_sector_size(void) { + return 128 * 1024; // 128k +} +MG_IRAM size_t mg_flash_write_align(void) { + return 32; // 256 bit +} +MG_IRAM int mg_flash_bank(void) { + if (mg_flash_size() < 2 * 1024 * 1024) return 0; // No dual bank support + return MG_REG(FLASH_BASE1 + FLASH_OPTCR) & MG_BIT(31) ? 2 : 1; +} + +MG_IRAM static void flash_unlock(void) { + static bool unlocked = false; + if (unlocked == false) { + MG_REG(FLASH_BASE1 + FLASH_KEYR) = 0x45670123; + MG_REG(FLASH_BASE1 + FLASH_KEYR) = 0xcdef89ab; + if (mg_flash_bank() > 0) { + MG_REG(FLASH_BASE2 + FLASH_KEYR) = 0x45670123; + MG_REG(FLASH_BASE2 + FLASH_KEYR) = 0xcdef89ab; + } + MG_REG(FLASH_BASE1 + FLASH_OPTKEYR) = 0x08192a3b; // opt reg is "shared" + MG_REG(FLASH_BASE1 + FLASH_OPTKEYR) = 0x4c5d6e7f; // thus unlock once + unlocked = true; } - return 0; } -static char mg_escape(int c) { - return mg_esc(c, true); +MG_IRAM static bool flash_page_start(volatile uint32_t *dst) { + char *base = (char *) mg_flash_start(), *end = base + mg_flash_size(); + volatile char *p = (char *) dst; + return p >= base && p < end && ((p - base) % mg_flash_sector_size()) == 0; } -static size_t qcpy(void (*out)(char, void *), void *ptr, char *buf, - size_t len) { - size_t i = 0, extra = 0; - for (i = 0; i < len && buf[i] != '\0'; i++) { - char c = mg_escape(buf[i]); - if (c) { - out('\\', ptr), out(c, ptr), extra++; - } else { - out(buf[i], ptr); - } - } - return i + extra; +MG_IRAM static bool flash_is_err(uint32_t bank) { + return MG_REG(bank + FLASH_SR) & ((MG_BIT(11) - 1) << 17); // RM0433 4.9.5 } -static size_t Qcpy(void (*out)(char, void *), void *ptr, char *buf, - size_t len) { - size_t n = 2; - out('"', ptr); - n += qcpy(out, ptr, buf, len); - out('"', ptr); - return n; +MG_IRAM static void flash_wait(uint32_t bank) { + while (MG_REG(bank + FLASH_SR) & (MG_BIT(0) | MG_BIT(2))) (void) 0; } -static size_t bcpy(void (*out)(char, void *), void *ptr, uint8_t *buf, - size_t len) { - size_t i, n = 0; - const char *t = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - out('"', ptr), n++; - for (i = 0; i < len; i += 3) { - uint8_t c1 = buf[i], c2 = i + 1 < len ? buf[i + 1] : 0, - c3 = i + 2 < len ? buf[i + 2] : 0; - char tmp[4] = {t[c1 >> 2], t[(c1 & 3) << 4 | (c2 >> 4)], '=', '='}; - if (i + 1 < len) tmp[2] = t[(c2 & 15) << 2 | (c3 >> 6)]; - if (i + 2 < len) tmp[3] = t[c3 & 63]; - n += scpy(out, ptr, tmp, sizeof(tmp)); - } - out('"', ptr), n++; - return n; +MG_IRAM static void flash_clear_err(uint32_t bank) { + flash_wait(bank); // Wait until ready + MG_REG(bank + FLASH_CCR) = ((MG_BIT(11) - 1) << 16U); // Clear all errors } -size_t mg_vxprintf(void (*out)(char, void *), void *param, const char *fmt, - va_list *ap) { - size_t i = 0, n = 0; - while (fmt[i] != '\0') { - if (fmt[i] == '%') { - size_t j, k, x = 0, is_long = 0, w = 0 /* width */, pr = ~0U /* prec */; - char pad = ' ', minus = 0, c = fmt[++i]; - if (c == '#') x++, c = fmt[++i]; - if (c == '-') minus++, c = fmt[++i]; - if (c == '0') pad = '0', c = fmt[++i]; - while (is_digit(c)) w *= 10, w += (size_t) (c - '0'), c = fmt[++i]; - if (c == '.') { - c = fmt[++i]; - if (c == '*') { - pr = (size_t) va_arg(*ap, int); - c = fmt[++i]; - } else { - pr = 0; - while (is_digit(c)) pr *= 10, pr += (size_t) (c - '0'), c = fmt[++i]; - } - } - while (c == 'h') c = fmt[++i]; // Treat h and hh as int - if (c == 'l') { - is_long++, c = fmt[++i]; - if (c == 'l') is_long++, c = fmt[++i]; - } - if (c == 'p') x = 1, is_long = 1; - if (c == 'd' || c == 'u' || c == 'x' || c == 'X' || c == 'p' || - c == 'g' || c == 'f') { - bool s = (c == 'd'), h = (c == 'x' || c == 'X' || c == 'p'); - char tmp[40]; - size_t xl = x ? 2 : 0; - if (c == 'g' || c == 'f') { - double v = va_arg(*ap, double); - if (pr == ~0U) pr = 6; - k = mg_dtoa(tmp, sizeof(tmp), v, (int) pr); - } else if (is_long == 2) { - int64_t v = va_arg(*ap, int64_t); - k = mg_lld(tmp, v, s, h); - } else if (is_long == 1) { - long v = va_arg(*ap, long); - k = mg_lld(tmp, s ? (int64_t) v : (int64_t) (unsigned long) v, s, h); - } else { - int v = va_arg(*ap, int); - k = mg_lld(tmp, s ? (int64_t) v : (int64_t) (unsigned) v, s, h); - } - for (j = 0; j < xl && w > 0; j++) w--; - for (j = 0; pad == ' ' && !minus && k < w && j + k < w; j++) - n += scpy(out, param, &pad, 1); - n += scpy(out, param, (char *) "0x", xl); - for (j = 0; pad == '0' && k < w && j + k < w; j++) - n += scpy(out, param, &pad, 1); - n += scpy(out, param, tmp, k); - for (j = 0; pad == ' ' && minus && k < w && j + k < w; j++) - n += scpy(out, param, &pad, 1); - } else if (c == 'M') { - mg_pm_t f = va_arg(*ap, mg_pm_t); - n += f(out, param, ap); - } else if (c == 'c') { - int ch = va_arg(*ap, int); - out((char) ch, param); - n++; - } else if (c == 'H') { - // Print hex-encoded double-quoted string - size_t bl = (size_t) va_arg(*ap, int); - uint8_t *p = va_arg(*ap, uint8_t *), dquote = '"'; - const char *hex = "0123456789abcdef"; - n += scpy(out, param, (char *) &dquote, 1); - for (j = 0; j < bl; j++) { - n += scpy(out, param, (char *) &hex[(p[j] >> 4) & 15], 1); - n += scpy(out, param, (char *) &hex[p[j] & 15], 1); - } - n += scpy(out, param, (char *) &dquote, 1); - } else if (c == 'I') { - // Print IPv4 or IPv6 address - size_t len = (size_t) va_arg(*ap, int); // Length 16 means IPv6 address - uint8_t *buf = va_arg(*ap, uint8_t *); // Pointer to the IP address - if (len == 6) { - uint16_t *p = (uint16_t *) buf; - n += mg_xprintf(out, param, "%x:%x:%x:%x:%x:%x:%x:%x", mg_htons(p[0]), - mg_htons(p[1]), mg_htons(p[2]), mg_htons(p[3]), - mg_htons(p[4]), mg_htons(p[5]), mg_htons(p[6]), - mg_htons(p[7])); - } else { - n += mg_xprintf(out, param, "%d.%d.%d.%d", (int) buf[0], (int) buf[1], - (int) buf[2], (int) buf[3]); - } - } else if (c == 'A') { - // Print hardware addresses (currently Ethernet MAC) - uint8_t *buf = va_arg(*ap, uint8_t *); // Pointer to the hw address - n += mg_xprintf(out, param, "%02x:%02x:%02x:%02x:%02x:%02x", - (int) buf[0], (int) buf[1], (int) buf[2], (int) buf[3], - (int) buf[4], (int) buf[5]); - } else if (c == 'V') { - // Print base64-encoded double-quoted string - size_t len = (size_t) va_arg(*ap, int); - uint8_t *buf = va_arg(*ap, uint8_t *); - n += bcpy(out, param, buf, len); - } else if (c == 's' || c == 'Q' || c == 'q') { - char *p = va_arg(*ap, char *); - size_t (*f)(void (*)(char, void *), void *, char *, size_t) = scpy; - if (c == 'Q') f = Qcpy; - if (c == 'q') f = qcpy; - if (pr == ~0U) pr = p == NULL ? 0 : strlen(p); - for (j = 0; !minus && pr < w && j + pr < w; j++) - n += f(out, param, &pad, 1); - n += f(out, param, p, pr); - for (j = 0; minus && pr < w && j + pr < w; j++) - n += f(out, param, &pad, 1); - } else if (c == '%') { - out('%', param); - n++; - } else { - out('%', param); - out(c, param); - n += 2; - } - i++; - } else { - out(fmt[i], param), n++, i++; - } - } - return n; +MG_IRAM static bool flash_bank_is_swapped(uint32_t bank) { + return MG_REG(bank + FLASH_OPTCR) & MG_BIT(31); // RM0433 4.9.7 } -#ifdef MG_ENABLE_LINES -#line 1 "src/fs.c" -#endif - - - -struct mg_fd *mg_fs_open(struct mg_fs *fs, const char *path, int flags) { - struct mg_fd *fd = (struct mg_fd *) calloc(1, sizeof(*fd)); - if (fd != NULL) { - fd->fd = fs->op(path, flags); - fd->fs = fs; - if (fd->fd == NULL) { - free(fd); - fd = NULL; - } - } - return fd; +// Figure out flash bank based on the address +MG_IRAM static uint32_t flash_bank(void *addr) { + size_t ofs = (char *) addr - (char *) mg_flash_start(); + if (mg_flash_bank() == 0) return FLASH_BASE1; + return ofs < mg_flash_size() / 2 ? FLASH_BASE1 : FLASH_BASE2; } -void mg_fs_close(struct mg_fd *fd) { - if (fd != NULL) { - fd->fs->cl(fd->fd); - free(fd); +MG_IRAM bool mg_flash_erase(void *addr) { + bool ok = false; + if (flash_page_start(addr) == false) { + MG_ERROR(("%p is not on a sector boundary", addr)); + } else { + uintptr_t diff = (char *) addr - (char *) mg_flash_start(); + uint32_t sector = diff / mg_flash_sector_size(); + uint32_t bank = flash_bank(addr); + uint32_t saved_cr = MG_REG(bank + FLASH_CR); // Save CR value + + flash_unlock(); + if (sector > 7) sector -= 8; + + flash_clear_err(bank); + MG_REG(bank + FLASH_CR) = MG_BIT(5); // 32-bit write parallelism + MG_REG(bank + FLASH_CR) |= (sector & 7U) << 8U; // Sector to erase + MG_REG(bank + FLASH_CR) |= MG_BIT(2); // Sector erase bit + MG_REG(bank + FLASH_CR) |= MG_BIT(7); // Start erasing + ok = !flash_is_err(bank); + MG_DEBUG(("Erase sector %lu @ %p %s. CR %#lx SR %#lx", sector, addr, + ok ? "ok" : "fail", MG_REG(bank + FLASH_CR), + MG_REG(bank + FLASH_SR))); + MG_REG(bank + FLASH_CR) = saved_cr; // Restore CR } + return ok; } -char *mg_file_read(struct mg_fs *fs, const char *path, size_t *sizep) { - struct mg_fd *fd; - char *data = NULL; - size_t size = 0; - fs->st(path, &size, NULL); - if ((fd = mg_fs_open(fs, path, MG_FS_READ)) != NULL) { - data = (char *) calloc(1, size + 1); - if (data != NULL) { - if (fs->rd(fd->fd, data, size) != size) { - free(data); - data = NULL; - } else { - data[size] = '\0'; - if (sizep != NULL) *sizep = size; - } - } - mg_fs_close(fd); - } - return data; +MG_IRAM bool mg_flash_swap_bank(void) { + if (mg_flash_bank() == 0) return true; + uint32_t bank = FLASH_BASE1; + uint32_t desired = flash_bank_is_swapped(bank) ? 0 : MG_BIT(31); + flash_unlock(); + flash_clear_err(bank); + // printf("OPTSR_PRG 1 %#lx\n", FLASH->OPTSR_PRG); + MG_SET_BITS(MG_REG(bank + FLASH_OPTSR_PRG), MG_BIT(31), desired); + // printf("OPTSR_PRG 2 %#lx\n", FLASH->OPTSR_PRG); + MG_REG(bank + FLASH_OPTCR) |= MG_BIT(1); // OPTSTART + while ((MG_REG(bank + FLASH_OPTSR_CUR) & MG_BIT(31)) != desired) (void) 0; + return true; } -bool mg_file_write(struct mg_fs *fs, const char *path, const void *buf, - size_t len) { - bool result = false; - struct mg_fd *fd; - char tmp[MG_PATH_MAX]; - mg_snprintf(tmp, sizeof(tmp), "%s..%d", path, rand()); - if ((fd = mg_fs_open(fs, tmp, MG_FS_WRITE)) != NULL) { - result = fs->wr(fd->fd, buf, len) == len; - mg_fs_close(fd); - if (result) { - fs->rm(path); - fs->mv(tmp, path); - } else { - fs->rm(tmp); - } +MG_IRAM bool mg_flash_write(void *addr, const void *buf, size_t len) { + if ((len % mg_flash_write_align()) != 0) { + MG_ERROR(("%lu is not aligned to %lu", len, mg_flash_write_align())); + return false; } - return result; + uint32_t bank = flash_bank(addr); + uint32_t *dst = (uint32_t *) addr; + uint32_t *src = (uint32_t *) buf; + uint32_t *end = (uint32_t *) ((char *) buf + len); + bool ok = true; + flash_unlock(); + flash_clear_err(bank); + MG_REG(bank + FLASH_CR) = MG_BIT(1); // Set programming flag + MG_REG(bank + FLASH_CR) |= MG_BIT(5); // 32-bit write parallelism + MG_DEBUG(("Writing flash @ %p, %lu bytes", addr, len)); + MG_ARM_DISABLE_IRQ(); + while (ok && src < end) { + if (flash_page_start(dst) && mg_flash_erase(dst) == false) break; + *(volatile uint32_t *) dst++ = *src++; + flash_wait(bank); + if (flash_is_err(bank)) ok = false; + } + MG_ARM_ENABLE_IRQ(); + MG_DEBUG(("Flash write %lu bytes @ %p: %s. CR %#lx SR %#lx", len, dst, + ok ? "ok" : "fail", MG_REG(bank + FLASH_CR), + MG_REG(bank + FLASH_SR))); + MG_REG(bank + FLASH_CR) &= ~MG_BIT(1); // Clear programming flag + return ok; } -bool mg_file_printf(struct mg_fs *fs, const char *path, const char *fmt, ...) { - va_list ap; - char *data; - bool result = false; - va_start(ap, fmt); - data = mg_vmprintf(fmt, &ap); - va_end(ap); - result = mg_file_write(fs, path, data, strlen(data)); - free(data); - return result; +MG_IRAM void mg_device_reset(void) { + // SCB->AIRCR = ((0x5fa << SCB_AIRCR_VECTKEY_Pos)|SCB_AIRCR_SYSRESETREQ_Msk); + *(volatile unsigned long *) 0xe000ed0c = 0x5fa0004; } +#endif #ifdef MG_ENABLE_LINES -#line 1 "src/fs_fat.c" +#line 1 "src/dns.c" #endif -#if MG_ENABLE_FATFS -#include -static int mg_days_from_epoch(int y, int m, int d) { - y -= m <= 2; - int era = y / 400; - int yoe = y - era * 400; - int doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1; - int doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; - return era * 146097 + doe - 719468; -} -static time_t mg_timegm(const struct tm *t) { - int year = t->tm_year + 1900; - int month = t->tm_mon; // 0-11 - if (month > 11) { - year += month / 12; - month %= 12; - } else if (month < 0) { - int years_diff = (11 - month) / 12; - year -= years_diff; - month += 12 * years_diff; - } - int x = mg_days_from_epoch(year, month + 1, t->tm_mday); - return 60 * (60 * (24L * x + t->tm_hour) + t->tm_min) + t->tm_sec; -} -static time_t ff_time_to_epoch(uint16_t fdate, uint16_t ftime) { - struct tm tm; - memset(&tm, 0, sizeof(struct tm)); - tm.tm_sec = (ftime << 1) & 0x3e; - tm.tm_min = ((ftime >> 5) & 0x3f); - tm.tm_hour = ((ftime >> 11) & 0x1f); - tm.tm_mday = (fdate & 0x1f); - tm.tm_mon = ((fdate >> 5) & 0x0f) - 1; - tm.tm_year = ((fdate >> 9) & 0x7f) + 80; - return mg_timegm(&tm); -} -static int ff_stat(const char *path, size_t *size, time_t *mtime) { - FILINFO fi; - if (path[0] == '\0') { - if (size) *size = 0; - if (mtime) *mtime = 0; - return MG_FS_DIR; - } else if (f_stat(path, &fi) == 0) { - if (size) *size = (size_t) fi.fsize; - if (mtime) *mtime = ff_time_to_epoch(fi.fdate, fi.ftime); - return MG_FS_READ | MG_FS_WRITE | ((fi.fattrib & AM_DIR) ? MG_FS_DIR : 0); - } else { - return 0; - } -} -static void ff_list(const char *dir, void (*fn)(const char *, void *), - void *userdata) { - DIR d; - FILINFO fi; - if (f_opendir(&d, dir) == FR_OK) { - while (f_readdir(&d, &fi) == FR_OK && fi.fname[0] != '\0') { - if (!strcmp(fi.fname, ".") || !strcmp(fi.fname, "..")) continue; - fn(fi.fname, userdata); - } - f_closedir(&d); - } -} +struct dns_data { + struct dns_data *next; + struct mg_connection *c; + uint64_t expire; + uint16_t txnid; +}; -static void *ff_open(const char *path, int flags) { - FIL f; - unsigned char mode = FA_READ; - if (flags & MG_FS_WRITE) mode |= FA_WRITE | FA_OPEN_ALWAYS | FA_OPEN_APPEND; - if (f_open(&f, path, mode) == 0) { - FIL *fp = calloc(1, sizeof(*fp)); - memcpy(fp, &f, sizeof(*fp)); - return fp; - } else { - return NULL; - } +static void mg_sendnsreq(struct mg_connection *, struct mg_str *, int, + struct mg_dns *, bool); + +static void mg_dns_free(struct dns_data **head, struct dns_data *d) { + LIST_DELETE(struct dns_data, head, d); + free(d); } -static void ff_close(void *fp) { - if (fp != NULL) { - f_close((FIL *) fp); - free(fp); +void mg_resolve_cancel(struct mg_connection *c) { + struct dns_data *tmp, *d; + struct dns_data **head = (struct dns_data **) &c->mgr->active_dns_requests; + for (d = *head; d != NULL; d = tmp) { + tmp = d->next; + if (d->c == c) mg_dns_free(head, d); } } -static size_t ff_read(void *fp, void *buf, size_t len) { - UINT n = 0, misalign = ((size_t) buf) & 3; - if (misalign) { - char aligned[4]; - f_read((FIL *) fp, aligned, len > misalign ? misalign : len, &n); - memcpy(buf, aligned, n); - } else { - f_read((FIL *) fp, buf, len, &n); +static size_t mg_dns_parse_name_depth(const uint8_t *s, size_t len, size_t ofs, + char *to, size_t tolen, size_t j, + int depth) { + size_t i = 0; + if (tolen > 0 && depth == 0) to[0] = '\0'; + if (depth > 5) return 0; + // MG_INFO(("ofs %lx %x %x", (unsigned long) ofs, s[ofs], s[ofs + 1])); + while (ofs + i + 1 < len) { + size_t n = s[ofs + i]; + if (n == 0) { + i++; + break; + } + if (n & 0xc0) { + size_t ptr = (((n & 0x3f) << 8) | s[ofs + i + 1]); // 12 is hdr len + // MG_INFO(("PTR %lx", (unsigned long) ptr)); + if (ptr + 1 < len && (s[ptr] & 0xc0) == 0 && + mg_dns_parse_name_depth(s, len, ptr, to, tolen, j, depth + 1) == 0) + return 0; + i += 2; + break; + } + if (ofs + i + n + 1 >= len) return 0; + if (j > 0) { + if (j < tolen) to[j] = '.'; + j++; + } + if (j + n < tolen) memcpy(&to[j], &s[ofs + i + 1], n); + j += n; + i += n + 1; + if (j < tolen) to[j] = '\0'; // Zero-terminate this chunk + // MG_INFO(("--> [%s]", to)); } - return n; + if (tolen > 0) to[tolen - 1] = '\0'; // Make sure make sure it is nul-term + return i; } -static size_t ff_write(void *fp, const void *buf, size_t len) { - UINT n = 0; - return f_write((FIL *) fp, (char *) buf, len, &n) == FR_OK ? n : 0; +static size_t mg_dns_parse_name(const uint8_t *s, size_t n, size_t ofs, + char *dst, size_t dstlen) { + return mg_dns_parse_name_depth(s, n, ofs, dst, dstlen, 0, 0); } -static size_t ff_seek(void *fp, size_t offset) { - f_lseek((FIL *) fp, offset); - return offset; +size_t mg_dns_parse_rr(const uint8_t *buf, size_t len, size_t ofs, + bool is_question, struct mg_dns_rr *rr) { + const uint8_t *s = buf + ofs, *e = &buf[len]; + + memset(rr, 0, sizeof(*rr)); + if (len < sizeof(struct mg_dns_header)) return 0; // Too small + if (len > 512) return 0; // Too large, we don't expect that + if (s >= e) return 0; // Overflow + + if ((rr->nlen = (uint16_t) mg_dns_parse_name(buf, len, ofs, NULL, 0)) == 0) + return 0; + s += rr->nlen + 4; + if (s > e) return 0; + rr->atype = (uint16_t) (((uint16_t) s[-4] << 8) | s[-3]); + rr->aclass = (uint16_t) (((uint16_t) s[-2] << 8) | s[-1]); + if (is_question) return (size_t) (rr->nlen + 4); + + s += 6; + if (s > e) return 0; + rr->alen = (uint16_t) (((uint16_t) s[-2] << 8) | s[-1]); + if (s + rr->alen > e) return 0; + return (size_t) (rr->nlen + rr->alen + 10); } -static bool ff_rename(const char *from, const char *to) { - return f_rename(from, to) == FR_OK; +bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *dm) { + const struct mg_dns_header *h = (struct mg_dns_header *) buf; + struct mg_dns_rr rr; + size_t i, n, num_answers, ofs = sizeof(*h); + memset(dm, 0, sizeof(*dm)); + + if (len < sizeof(*h)) return 0; // Too small, headers dont fit + if (mg_ntohs(h->num_questions) > 1) return 0; // Sanity + num_answers = mg_ntohs(h->num_answers); + if (num_answers > 10) { + MG_DEBUG(("Got %u answers, ignoring beyond 10th one", num_answers)); + num_answers = 10; // Sanity cap + } + dm->txnid = mg_ntohs(h->txnid); + + for (i = 0; i < mg_ntohs(h->num_questions); i++) { + if ((n = mg_dns_parse_rr(buf, len, ofs, true, &rr)) == 0) return false; + // MG_INFO(("Q %lu %lu %hu/%hu", ofs, n, rr.atype, rr.aclass)); + ofs += n; + } + for (i = 0; i < num_answers; i++) { + if ((n = mg_dns_parse_rr(buf, len, ofs, false, &rr)) == 0) return false; + // MG_INFO(("A -- %lu %lu %hu/%hu %s", ofs, n, rr.atype, rr.aclass, + // dm->name)); + mg_dns_parse_name(buf, len, ofs, dm->name, sizeof(dm->name)); + ofs += n; + + if (rr.alen == 4 && rr.atype == 1 && rr.aclass == 1) { + dm->addr.is_ip6 = false; + memcpy(&dm->addr.ip, &buf[ofs - 4], 4); + dm->resolved = true; + break; // Return success + } else if (rr.alen == 16 && rr.atype == 28 && rr.aclass == 1) { + dm->addr.is_ip6 = true; + memcpy(&dm->addr.ip, &buf[ofs - 16], 16); + dm->resolved = true; + break; // Return success + } + } + return true; } -static bool ff_remove(const char *path) { - return f_unlink(path) == FR_OK; +static void dns_cb(struct mg_connection *c, int ev, void *ev_data) { + struct dns_data *d, *tmp; + struct dns_data **head = (struct dns_data **) &c->mgr->active_dns_requests; + if (ev == MG_EV_POLL) { + uint64_t now = *(uint64_t *) ev_data; + for (d = *head; d != NULL; d = tmp) { + tmp = d->next; + // MG_DEBUG ("%lu %lu dns poll", d->expire, now)); + if (now > d->expire) mg_error(d->c, "DNS timeout"); + } + } else if (ev == MG_EV_READ) { + struct mg_dns_message dm; + int resolved = 0; + if (mg_dns_parse(c->recv.buf, c->recv.len, &dm) == false) { + MG_ERROR(("Unexpected DNS response:")); + mg_hexdump(c->recv.buf, c->recv.len); + } else { + // MG_VERBOSE(("%s %d", dm.name, dm.resolved)); + for (d = *head; d != NULL; d = tmp) { + tmp = d->next; + // MG_INFO(("d %p %hu %hu", d, d->txnid, dm.txnid)); + if (dm.txnid != d->txnid) continue; + if (d->c->is_resolving) { + if (dm.resolved) { + dm.addr.port = d->c->rem.port; // Save port + d->c->rem = dm.addr; // Copy resolved address + MG_DEBUG( + ("%lu %s is %M", d->c->id, dm.name, mg_print_ip, &d->c->rem)); + mg_connect_resolved(d->c); +#if MG_ENABLE_IPV6 + } else if (dm.addr.is_ip6 == false && dm.name[0] != '\0' && + c->mgr->use_dns6 == false) { + struct mg_str x = mg_str(dm.name); + mg_sendnsreq(d->c, &x, c->mgr->dnstimeout, &c->mgr->dns6, true); +#endif + } else { + mg_error(d->c, "%s DNS lookup failed", dm.name); + } + } else { + MG_ERROR(("%lu already resolved", d->c->id)); + } + mg_dns_free(head, d); + resolved = 1; + } + } + if (!resolved) MG_ERROR(("stray DNS reply")); + c->recv.len = 0; + } else if (ev == MG_EV_CLOSE) { + for (d = *head; d != NULL; d = tmp) { + tmp = d->next; + mg_error(d->c, "DNS error"); + mg_dns_free(head, d); + } + } } -static bool ff_mkdir(const char *path) { - return f_mkdir(path) == FR_OK; +static bool mg_dns_send(struct mg_connection *c, const struct mg_str *name, + uint16_t txnid, bool ipv6) { + struct { + struct mg_dns_header header; + uint8_t data[256]; + } pkt; + size_t i, n; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.txnid = mg_htons(txnid); + pkt.header.flags = mg_htons(0x100); + pkt.header.num_questions = mg_htons(1); + for (i = n = 0; i < sizeof(pkt.data) - 5; i++) { + if (name->buf[i] == '.' || i >= name->len) { + pkt.data[n] = (uint8_t) (i - n); + memcpy(&pkt.data[n + 1], name->buf + n, i - n); + n = i + 1; + } + if (i >= name->len) break; + } + memcpy(&pkt.data[n], "\x00\x00\x01\x00\x01", 5); // A query + n += 5; + if (ipv6) pkt.data[n - 3] = 0x1c; // AAAA query + // memcpy(&pkt.data[n], "\xc0\x0c\x00\x1c\x00\x01", 6); // AAAA query + // n += 6; + return mg_send(c, &pkt, sizeof(pkt.header) + n); } -struct mg_fs mg_fs_fat = {ff_stat, ff_list, ff_open, ff_close, ff_read, - ff_write, ff_seek, ff_rename, ff_remove, ff_mkdir}; -#endif +static void mg_sendnsreq(struct mg_connection *c, struct mg_str *name, int ms, + struct mg_dns *dnsc, bool ipv6) { + struct dns_data *d = NULL; + if (dnsc->url == NULL) { + mg_error(c, "DNS server URL is NULL. Call mg_mgr_init()"); + } else if (dnsc->c == NULL) { + dnsc->c = mg_connect(c->mgr, dnsc->url, NULL, NULL); + if (dnsc->c != NULL) { + dnsc->c->pfn = dns_cb; + // dnsc->c->is_hexdumping = 1; + } + } + if (dnsc->c == NULL) { + mg_error(c, "resolver"); + } else if ((d = (struct dns_data *) calloc(1, sizeof(*d))) == NULL) { + mg_error(c, "resolve OOM"); + } else { + struct dns_data *reqs = (struct dns_data *) c->mgr->active_dns_requests; + d->txnid = reqs ? (uint16_t) (reqs->txnid + 1) : 1; + d->next = (struct dns_data *) c->mgr->active_dns_requests; + c->mgr->active_dns_requests = d; + d->expire = mg_millis() + (uint64_t) ms; + d->c = c; + c->is_resolving = 1; + MG_VERBOSE(("%lu resolving %.*s @ %s, txnid %hu", c->id, (int) name->len, + name->buf, dnsc->url, d->txnid)); + if (!mg_dns_send(dnsc->c, name, d->txnid, ipv6)) { + mg_error(dnsc->c, "DNS send"); + } + } +} + +void mg_resolve(struct mg_connection *c, const char *url) { + struct mg_str host = mg_url_host(url); + c->rem.port = mg_htons(mg_url_port(url)); + if (mg_aton(host, &c->rem)) { + // host is an IP address, do not fire name resolution + mg_connect_resolved(c); + } else { + // host is not an IP, send DNS resolution request + struct mg_dns *dns = c->mgr->use_dns6 ? &c->mgr->dns6 : &c->mgr->dns4; + mg_sendnsreq(c, &host, c->mgr->dnstimeout, dns, c->mgr->use_dns6); + } +} #ifdef MG_ENABLE_LINES -#line 1 "src/fs_packed.c" +#line 1 "src/event.c" #endif -struct packed_file { - const char *data; - size_t size; - size_t pos; -}; -const char *mg_unpack(const char *path, size_t *size, time_t *mtime); -const char *mg_unlist(size_t no); -#if MG_ENABLE_PACKED_FS -#else -const char *mg_unpack(const char *path, size_t *size, time_t *mtime) { - (void) path, (void) size, (void) mtime; - return NULL; -} -const char *mg_unlist(size_t no) { - (void) no; - return NULL; -} +void mg_call(struct mg_connection *c, int ev, void *ev_data) { +#if MG_ENABLE_PROFILE + const char *names[] = { + "EV_ERROR", "EV_OPEN", "EV_POLL", "EV_RESOLVE", + "EV_CONNECT", "EV_ACCEPT", "EV_TLS_HS", "EV_READ", + "EV_WRITE", "EV_CLOSE", "EV_HTTP_MSG", "EV_HTTP_CHUNK", + "EV_WS_OPEN", "EV_WS_MSG", "EV_WS_CTL", "EV_MQTT_CMD", + "EV_MQTT_MSG", "EV_MQTT_OPEN", "EV_SNTP_TIME", "EV_USER"}; + if (ev != MG_EV_POLL && ev < (int) (sizeof(names) / sizeof(names[0]))) { + MG_PROF_ADD(c, names[ev]); + } #endif - -static int is_dir_prefix(const char *prefix, size_t n, const char *path) { - // MG_INFO(("[%.*s] [%s] %c", (int) n, prefix, path, path[n])); - return n < strlen(path) && strncmp(prefix, path, n) == 0 && - (n == 0 || path[n] == '/' || path[n - 1] == '/'); + // Fire protocol handler first, user handler second. See #2559 + if (c->pfn != NULL) c->pfn(c, ev, ev_data); + if (c->fn != NULL) c->fn(c, ev, ev_data); } -static int packed_stat(const char *path, size_t *size, time_t *mtime) { - const char *p; - size_t i, n = strlen(path); - if (mg_unpack(path, size, mtime)) return MG_FS_READ; // Regular file - // Scan all files. If `path` is a dir prefix for any of them, it's a dir - for (i = 0; (p = mg_unlist(i)) != NULL; i++) { - if (is_dir_prefix(path, n, p)) return MG_FS_DIR; - } - return 0; -} - -static void packed_list(const char *dir, void (*fn)(const char *, void *), - void *userdata) { - char buf[MG_PATH_MAX], tmp[sizeof(buf)]; - const char *path, *begin, *end; - size_t i, n = strlen(dir); - tmp[0] = '\0'; // Previously listed entry - for (i = 0; (path = mg_unlist(i)) != NULL; i++) { - if (!is_dir_prefix(dir, n, path)) continue; - begin = &path[n + 1]; - end = strchr(begin, '/'); - if (end == NULL) end = begin + strlen(begin); - mg_snprintf(buf, sizeof(buf), "%.*s", (int) (end - begin), begin); - buf[sizeof(buf) - 1] = '\0'; - // If this entry has been already listed, skip - // NOTE: we're assuming that file list is sorted alphabetically - if (strcmp(buf, tmp) == 0) continue; - fn(buf, userdata); // Not yet listed, call user function - strcpy(tmp, buf); // And save this entry as listed - } -} - -static void *packed_open(const char *path, int flags) { - size_t size = 0; - const char *data = mg_unpack(path, &size, NULL); - struct packed_file *fp = NULL; - if (data == NULL) return NULL; - if (flags & MG_FS_WRITE) return NULL; - fp = (struct packed_file *) calloc(1, sizeof(*fp)); - fp->size = size; - fp->data = data; - return (void *) fp; +void mg_error(struct mg_connection *c, const char *fmt, ...) { + char buf[64]; + va_list ap; + va_start(ap, fmt); + mg_vsnprintf(buf, sizeof(buf), fmt, &ap); + va_end(ap); + MG_ERROR(("%lu %ld %s", c->id, c->fd, buf)); + c->is_closing = 1; // Set is_closing before sending MG_EV_CALL + mg_call(c, MG_EV_ERROR, buf); // Let user handler override it } -static void packed_close(void *fp) { - if (fp != NULL) free(fp); -} +#ifdef MG_ENABLE_LINES +#line 1 "src/fmt.c" +#endif -static size_t packed_read(void *fd, void *buf, size_t len) { - struct packed_file *fp = (struct packed_file *) fd; - if (fp->pos + len > fp->size) len = fp->size - fp->pos; - memcpy(buf, &fp->data[fp->pos], len); - fp->pos += len; - return len; -} -static size_t packed_write(void *fd, const void *buf, size_t len) { - (void) fd, (void) buf, (void) len; - return 0; -} -static size_t packed_seek(void *fd, size_t offset) { - struct packed_file *fp = (struct packed_file *) fd; - fp->pos = offset; - if (fp->pos > fp->size) fp->pos = fp->size; - return fp->pos; -} -static bool packed_rename(const char *from, const char *to) { - (void) from, (void) to; - return false; +static bool is_digit(int c) { + return c >= '0' && c <= '9'; } -static bool packed_remove(const char *path) { - (void) path; - return false; +static int addexp(char *buf, int e, int sign) { + int n = 0; + buf[n++] = 'e'; + buf[n++] = (char) sign; + if (e > 400) return 0; + if (e < 10) buf[n++] = '0'; + if (e >= 100) buf[n++] = (char) (e / 100 + '0'), e -= 100 * (e / 100); + if (e >= 10) buf[n++] = (char) (e / 10 + '0'), e -= 10 * (e / 10); + buf[n++] = (char) (e + '0'); + return n; } -static bool packed_mkdir(const char *path) { - (void) path; - return false; +static int xisinf(double x) { + union { + double f; + uint64_t u; + } ieee754 = {x}; + return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 && + ((unsigned) ieee754.u == 0); } -struct mg_fs mg_fs_packed = { - packed_stat, packed_list, packed_open, packed_close, packed_read, - packed_write, packed_seek, packed_rename, packed_remove, packed_mkdir}; - -#ifdef MG_ENABLE_LINES -#line 1 "src/fs_posix.c" -#endif - - -#if MG_ENABLE_FILE - -#ifndef MG_STAT_STRUCT -#define MG_STAT_STRUCT stat -#endif - -#ifndef MG_STAT_FUNC -#define MG_STAT_FUNC stat -#endif - -static int p_stat(const char *path, size_t *size, time_t *mtime) { -#if !defined(S_ISDIR) - MG_ERROR(("stat() API is not supported. %p %p %p", path, size, mtime)); - return 0; -#else -#if MG_ARCH == MG_ARCH_WIN32 - struct _stati64 st; - wchar_t tmp[MG_PATH_MAX]; - MultiByteToWideChar(CP_UTF8, 0, path, -1, tmp, sizeof(tmp) / sizeof(tmp[0])); - if (_wstati64(tmp, &st) != 0) return 0; -#else - struct MG_STAT_STRUCT st; - if (MG_STAT_FUNC(path, &st) != 0) return 0; -#endif - if (size) *size = (size_t) st.st_size; - if (mtime) *mtime = st.st_mtime; - return MG_FS_READ | MG_FS_WRITE | (S_ISDIR(st.st_mode) ? MG_FS_DIR : 0); -#endif +static int xisnan(double x) { + union { + double f; + uint64_t u; + } ieee754 = {x}; + return ((unsigned) (ieee754.u >> 32) & 0x7fffffff) + + ((unsigned) ieee754.u != 0) > + 0x7ff00000; } -#if MG_ARCH == MG_ARCH_WIN32 -struct dirent { - char d_name[MAX_PATH]; -}; - -typedef struct win32_dir { - HANDLE handle; - WIN32_FIND_DATAW info; - struct dirent result; -} DIR; +static size_t mg_dtoa(char *dst, size_t dstlen, double d, int width, bool tz) { + char buf[40]; + int i, s = 0, n = 0, e = 0; + double t, mul, saved; + if (d == 0.0) return mg_snprintf(dst, dstlen, "%s", "0"); + if (xisinf(d)) return mg_snprintf(dst, dstlen, "%s", d > 0 ? "inf" : "-inf"); + if (xisnan(d)) return mg_snprintf(dst, dstlen, "%s", "nan"); + if (d < 0.0) d = -d, buf[s++] = '-'; -int gettimeofday(struct timeval *tv, void *tz) { - FILETIME ft; - unsigned __int64 tmpres = 0; + // Round + saved = d; + mul = 1.0; + while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0; + while (d <= 1.0 && d / mul <= 1.0) mul /= 10.0; + for (i = 0, t = mul * 5; i < width; i++) t /= 10.0; + d += t; + // Calculate exponent, and 'mul' for scientific representation + mul = 1.0; + while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0, e++; + while (d < 1.0 && d / mul < 1.0) mul /= 10.0, e--; + // printf(" --> %g %d %g %g\n", saved, e, t, mul); - if (tv != NULL) { - GetSystemTimeAsFileTime(&ft); - tmpres |= ft.dwHighDateTime; - tmpres <<= 32; - tmpres |= ft.dwLowDateTime; - tmpres /= 10; // convert into microseconds - tmpres -= (int64_t) 11644473600000000; - tv->tv_sec = (long) (tmpres / 1000000UL); - tv->tv_usec = (long) (tmpres % 1000000UL); + if (e >= width && width > 1) { + n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz); + // printf(" --> %.*g %d [%.*s]\n", 10, d / t, e, n, buf); + n += addexp(buf + s + n, e, '+'); + return mg_snprintf(dst, dstlen, "%.*s", n, buf); + } else if (e <= -width && width > 1) { + n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz); + // printf(" --> %.*g %d [%.*s]\n", 10, d / mul, e, n, buf); + n += addexp(buf + s + n, -e, '-'); + return mg_snprintf(dst, dstlen, "%.*s", n, buf); + } else { + for (i = 0, t = mul; t >= 1.0 && s + n < (int) sizeof(buf); i++) { + int ch = (int) (d / t); + if (n > 0 || ch > 0) buf[s + n++] = (char) (ch + '0'); + d -= ch * t; + t /= 10.0; + } + // printf(" --> [%g] -> %g %g (%d) [%.*s]\n", saved, d, t, n, s + n, buf); + if (n == 0) buf[s++] = '0'; + while (t >= 1.0 && n + s < (int) sizeof(buf)) buf[n++] = '0', t /= 10.0; + if (s + n < (int) sizeof(buf)) buf[n + s++] = '.'; + // printf(" 1--> [%g] -> [%.*s]\n", saved, s + n, buf); + for (i = 0, t = 0.1; s + n < (int) sizeof(buf) && n < width; i++) { + int ch = (int) (d / t); + buf[s + n++] = (char) (ch + '0'); + d -= ch * t; + t /= 10.0; + } } - (void) tz; - return 0; + while (tz && n > 0 && buf[s + n - 1] == '0') n--; // Trim trailing zeroes + if (n > 0 && buf[s + n - 1] == '.') n--; // Trim trailing dot + n += s; + if (n >= (int) sizeof(buf)) n = (int) sizeof(buf) - 1; + buf[n] = '\0'; + return mg_snprintf(dst, dstlen, "%s", buf); } -static int to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len) { - int ret; - char buf[MAX_PATH * 2], buf2[MAX_PATH * 2], *p; - strncpy(buf, path, sizeof(buf)); - buf[sizeof(buf) - 1] = '\0'; - // Trim trailing slashes. Leave backslash for paths like "X:\" - p = buf + strlen(buf) - 1; - while (p > buf && p[-1] != ':' && (p[0] == '\\' || p[0] == '/')) *p-- = '\0'; - memset(wbuf, 0, wbuf_len * sizeof(wchar_t)); - ret = MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len); - // Convert back to Unicode. If doubly-converted string does not match the - // original, something is fishy, reject. - WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2), - NULL, NULL); - if (strcmp(buf, buf2) != 0) { - wbuf[0] = L'\0'; - ret = 0; +static size_t mg_lld(char *buf, int64_t val, bool is_signed, bool is_hex) { + const char *letters = "0123456789abcdef"; + uint64_t v = (uint64_t) val; + size_t s = 0, n, i; + if (is_signed && val < 0) buf[s++] = '-', v = (uint64_t) (-val); + // This loop prints a number in reverse order. I guess this is because we + // write numbers from right to left: least significant digit comes last. + // Maybe because we use Arabic numbers, and Arabs write RTL? + if (is_hex) { + for (n = 0; v; v >>= 4) buf[s + n++] = letters[v & 15]; + } else { + for (n = 0; v; v /= 10) buf[s + n++] = letters[v % 10]; } - return ret; + // Reverse a string + for (i = 0; i < n / 2; i++) { + char t = buf[s + i]; + buf[s + i] = buf[s + n - i - 1], buf[s + n - i - 1] = t; + } + if (val == 0) buf[n++] = '0'; // Handle special case + return n + s; } -DIR *opendir(const char *name) { - DIR *d = NULL; - wchar_t wpath[MAX_PATH]; - DWORD attrs; +static size_t scpy(void (*out)(char, void *), void *ptr, char *buf, + size_t len) { + size_t i = 0; + while (i < len && buf[i] != '\0') out(buf[i++], ptr); + return i; +} - if (name == NULL) { - SetLastError(ERROR_BAD_ARGUMENTS); - } else if ((d = (DIR *) calloc(1, sizeof(*d))) == NULL) { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - } else { - to_wchar(name, wpath, sizeof(wpath) / sizeof(wpath[0])); - attrs = GetFileAttributesW(wpath); - if (attrs != 0Xffffffff && (attrs & FILE_ATTRIBUTE_DIRECTORY)) { - (void) wcscat(wpath, L"\\*"); - d->handle = FindFirstFileW(wpath, &d->info); - d->result.d_name[0] = '\0'; +size_t mg_xprintf(void (*out)(char, void *), void *ptr, const char *fmt, ...) { + size_t len = 0; + va_list ap; + va_start(ap, fmt); + len = mg_vxprintf(out, ptr, fmt, &ap); + va_end(ap); + return len; +} + +size_t mg_vxprintf(void (*out)(char, void *), void *param, const char *fmt, + va_list *ap) { + size_t i = 0, n = 0; + while (fmt[i] != '\0') { + if (fmt[i] == '%') { + size_t j, k, x = 0, is_long = 0, w = 0 /* width */, pr = ~0U /* prec */; + char pad = ' ', minus = 0, c = fmt[++i]; + if (c == '#') x++, c = fmt[++i]; + if (c == '-') minus++, c = fmt[++i]; + if (c == '0') pad = '0', c = fmt[++i]; + while (is_digit(c)) w *= 10, w += (size_t) (c - '0'), c = fmt[++i]; + if (c == '.') { + c = fmt[++i]; + if (c == '*') { + pr = (size_t) va_arg(*ap, int); + c = fmt[++i]; + } else { + pr = 0; + while (is_digit(c)) pr *= 10, pr += (size_t) (c - '0'), c = fmt[++i]; + } + } + while (c == 'h') c = fmt[++i]; // Treat h and hh as int + if (c == 'l') { + is_long++, c = fmt[++i]; + if (c == 'l') is_long++, c = fmt[++i]; + } + if (c == 'p') x = 1, is_long = 1; + if (c == 'd' || c == 'u' || c == 'x' || c == 'X' || c == 'p' || + c == 'g' || c == 'f') { + bool s = (c == 'd'), h = (c == 'x' || c == 'X' || c == 'p'); + char tmp[40]; + size_t xl = x ? 2 : 0; + if (c == 'g' || c == 'f') { + double v = va_arg(*ap, double); + if (pr == ~0U) pr = 6; + k = mg_dtoa(tmp, sizeof(tmp), v, (int) pr, c == 'g'); + } else if (is_long == 2) { + int64_t v = va_arg(*ap, int64_t); + k = mg_lld(tmp, v, s, h); + } else if (is_long == 1) { + long v = va_arg(*ap, long); + k = mg_lld(tmp, s ? (int64_t) v : (int64_t) (unsigned long) v, s, h); + } else { + int v = va_arg(*ap, int); + k = mg_lld(tmp, s ? (int64_t) v : (int64_t) (unsigned) v, s, h); + } + for (j = 0; j < xl && w > 0; j++) w--; + for (j = 0; pad == ' ' && !minus && k < w && j + k < w; j++) + n += scpy(out, param, &pad, 1); + n += scpy(out, param, (char *) "0x", xl); + for (j = 0; pad == '0' && k < w && j + k < w; j++) + n += scpy(out, param, &pad, 1); + n += scpy(out, param, tmp, k); + for (j = 0; pad == ' ' && minus && k < w && j + k < w; j++) + n += scpy(out, param, &pad, 1); + } else if (c == 'm' || c == 'M') { + mg_pm_t f = va_arg(*ap, mg_pm_t); + if (c == 'm') out('"', param); + n += f(out, param, ap); + if (c == 'm') n += 2, out('"', param); + } else if (c == 'c') { + int ch = va_arg(*ap, int); + out((char) ch, param); + n++; + } else if (c == 's') { + char *p = va_arg(*ap, char *); + if (pr == ~0U) pr = p == NULL ? 0 : strlen(p); + for (j = 0; !minus && pr < w && j + pr < w; j++) + n += scpy(out, param, &pad, 1); + n += scpy(out, param, p, pr); + for (j = 0; minus && pr < w && j + pr < w; j++) + n += scpy(out, param, &pad, 1); + } else if (c == '%') { + out('%', param); + n++; + } else { + out('%', param); + out(c, param); + n += 2; + } + i++; } else { - free(d); - d = NULL; + out(fmt[i], param), n++, i++; } } - return d; + return n; } -int closedir(DIR *d) { - int result = 0; - if (d != NULL) { - if (d->handle != INVALID_HANDLE_VALUE) - result = FindClose(d->handle) ? 0 : -1; - free(d); - } else { - result = -1; - SetLastError(ERROR_BAD_ARGUMENTS); +#ifdef MG_ENABLE_LINES +#line 1 "src/fs.c" +#endif + + + + +struct mg_fd *mg_fs_open(struct mg_fs *fs, const char *path, int flags) { + struct mg_fd *fd = (struct mg_fd *) calloc(1, sizeof(*fd)); + if (fd != NULL) { + fd->fd = fs->op(path, flags); + fd->fs = fs; + if (fd->fd == NULL) { + free(fd); + fd = NULL; + } } - return result; + return fd; } -struct dirent *readdir(DIR *d) { - struct dirent *result = NULL; - if (d != NULL) { - memset(&d->result, 0, sizeof(d->result)); - if (d->handle != INVALID_HANDLE_VALUE) { - result = &d->result; - WideCharToMultiByte(CP_UTF8, 0, d->info.cFileName, -1, result->d_name, - sizeof(result->d_name), NULL, NULL); - if (!FindNextFileW(d->handle, &d->info)) { - FindClose(d->handle); - d->handle = INVALID_HANDLE_VALUE; - } - } else { - SetLastError(ERROR_FILE_NOT_FOUND); - } - } else { - SetLastError(ERROR_BAD_ARGUMENTS); +void mg_fs_close(struct mg_fd *fd) { + if (fd != NULL) { + fd->fs->cl(fd->fd); + free(fd); } - return result; } -#endif -static void p_list(const char *dir, void (*fn)(const char *, void *), - void *userdata) { -#if MG_ENABLE_DIRLIST - struct dirent *dp; - DIR *dirp; - if ((dirp = (opendir(dir))) == NULL) return; - while ((dp = readdir(dirp)) != NULL) { - if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue; - fn(dp->d_name, userdata); +struct mg_str mg_file_read(struct mg_fs *fs, const char *path) { + struct mg_str result = {NULL, 0}; + void *fp; + fs->st(path, &result.len, NULL); + if ((fp = fs->op(path, MG_FS_READ)) != NULL) { + result.buf = (char *) calloc(1, result.len + 1); + if (result.buf != NULL && + fs->rd(fp, (void *) result.buf, result.len) != result.len) { + free((void *) result.buf); + result.buf = NULL; + } + fs->cl(fp); } - closedir(dirp); -#else - (void) dir, (void) fn, (void) userdata; -#endif + if (result.buf == NULL) result.len = 0; + return result; } -static void *p_open(const char *path, int flags) { - const char *mode = flags == MG_FS_READ ? "rb" : "a+b"; -#if MG_ARCH == MG_ARCH_WIN32 - wchar_t b1[MG_PATH_MAX], b2[10]; - MultiByteToWideChar(CP_UTF8, 0, path, -1, b1, sizeof(b1) / sizeof(b1[0])); - MultiByteToWideChar(CP_UTF8, 0, mode, -1, b2, sizeof(b2) / sizeof(b2[0])); - return (void *) _wfopen(b1, b2); -#else - return (void *) fopen(path, mode); -#endif +bool mg_file_write(struct mg_fs *fs, const char *path, const void *buf, + size_t len) { + bool result = false; + struct mg_fd *fd; + char tmp[MG_PATH_MAX]; + mg_snprintf(tmp, sizeof(tmp), "%s..%d", path, rand()); + if ((fd = mg_fs_open(fs, tmp, MG_FS_WRITE)) != NULL) { + result = fs->wr(fd->fd, buf, len) == len; + mg_fs_close(fd); + if (result) { + fs->rm(path); + fs->mv(tmp, path); + } else { + fs->rm(tmp); + } + } + return result; } -static void p_close(void *fp) { - fclose((FILE *) fp); +bool mg_file_printf(struct mg_fs *fs, const char *path, const char *fmt, ...) { + va_list ap; + char *data; + bool result = false; + va_start(ap, fmt); + data = mg_vmprintf(fmt, &ap); + va_end(ap); + result = mg_file_write(fs, path, data, strlen(data)); + free(data); + return result; } -static size_t p_read(void *fp, void *buf, size_t len) { - return fread(buf, 1, len, (FILE *) fp); +// This helper function allows to scan a filesystem in a sequential way, +// without using callback function: +// char buf[100] = ""; +// while (mg_fs_ls(&mg_fs_posix, "./", buf, sizeof(buf))) { +// ... +static void mg_fs_ls_fn(const char *filename, void *param) { + struct mg_str *s = (struct mg_str *) param; + if (s->buf[0] == '\0') { + mg_snprintf((char *) s->buf, s->len, "%s", filename); + } else if (strcmp(s->buf, filename) == 0) { + ((char *) s->buf)[0] = '\0'; // Fetch next file + } } -static size_t p_write(void *fp, const void *buf, size_t len) { - return fwrite(buf, 1, len, (FILE *) fp); +bool mg_fs_ls(struct mg_fs *fs, const char *path, char *buf, size_t len) { + struct mg_str s = {buf, len}; + fs->ls(path, mg_fs_ls_fn, &s); + return buf[0] != '\0'; } -static size_t p_seek(void *fp, size_t offset) { -#if (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64) || \ - (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || \ - (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600) - if (fseeko((FILE *) fp, (off_t) offset, SEEK_SET) != 0) (void) 0; -#else - if (fseek((FILE *) fp, (long) offset, SEEK_SET) != 0) (void) 0; +#ifdef MG_ENABLE_LINES +#line 1 "src/fs_fat.c" #endif - return (size_t) ftell((FILE *) fp); -} -static bool p_rename(const char *from, const char *to) { - return rename(from, to) == 0; -} -static bool p_remove(const char *path) { - return remove(path) == 0; -} -static bool p_mkdir(const char *path) { - return mkdir(path, 0775) == 0; -} +#if MG_ENABLE_FATFS +#include -#else +static int mg_days_from_epoch(int y, int m, int d) { + y -= m <= 2; + int era = y / 400; + int yoe = y - era * 400; + int doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1; + int doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; + return era * 146097 + doe - 719468; +} -static int p_stat(const char *path, size_t *size, time_t *mtime) { - (void) path, (void) size, (void) mtime; - return 0; +static time_t mg_timegm(const struct tm *t) { + int year = t->tm_year + 1900; + int month = t->tm_mon; // 0-11 + if (month > 11) { + year += month / 12; + month %= 12; + } else if (month < 0) { + int years_diff = (11 - month) / 12; + year -= years_diff; + month += 12 * years_diff; + } + int x = mg_days_from_epoch(year, month + 1, t->tm_mday); + return 60 * (60 * (24L * x + t->tm_hour) + t->tm_min) + t->tm_sec; } -static void p_list(const char *path, void (*fn)(const char *, void *), - void *userdata) { - (void) path, (void) fn, (void) userdata; -} -static void *p_open(const char *path, int flags) { - (void) path, (void) flags; - return NULL; -} -static void p_close(void *fp) { - (void) fp; -} -static size_t p_read(void *fd, void *buf, size_t len) { - (void) fd, (void) buf, (void) len; - return 0; -} -static size_t p_write(void *fd, const void *buf, size_t len) { - (void) fd, (void) buf, (void) len; - return 0; -} -static size_t p_seek(void *fd, size_t offset) { - (void) fd, (void) offset; - return (size_t) ~0; -} -static bool p_rename(const char *from, const char *to) { - (void) from, (void) to; - return false; -} -static bool p_remove(const char *path) { - (void) path; - return false; -} -static bool p_mkdir(const char *path) { - (void) path; - return false; -} -#endif - -struct mg_fs mg_fs_posix = {p_stat, p_list, p_open, p_close, p_read, - p_write, p_seek, p_rename, p_remove, p_mkdir}; - -#ifdef MG_ENABLE_LINES -#line 1 "src/http.c" -#endif - - - - - - - - - - - - -// Chunk deletion marker is the MSB in the "processed" counter -#define MG_DMARK ((size_t) 1 << (sizeof(size_t) * 8 - 1)) - -// Multipart POST example: -// --xyz -// Content-Disposition: form-data; name="val" -// -// abcdef -// --xyz -// Content-Disposition: form-data; name="foo"; filename="a.txt" -// Content-Type: text/plain -// -// hello world -// -// --xyz-- -size_t mg_http_next_multipart(struct mg_str body, size_t ofs, - struct mg_http_part *part) { - struct mg_str cd = mg_str_n("Content-Disposition", 19); - const char *s = body.ptr; - size_t b = ofs, h1, h2, b1, b2, max = body.len; - - // Init part params - if (part != NULL) part->name = part->filename = part->body = mg_str_n(0, 0); - - // Skip boundary - while (b + 2 < max && s[b] != '\r' && s[b + 1] != '\n') b++; - if (b <= ofs || b + 2 >= max) return 0; - // MG_INFO(("B: %zu %zu [%.*s]", ofs, b - ofs, (int) (b - ofs), s)); - - // Skip headers - h1 = h2 = b + 2; - for (;;) { - while (h2 + 2 < max && s[h2] != '\r' && s[h2 + 1] != '\n') h2++; - if (h2 == h1) break; - if (h2 + 2 >= max) return 0; - // MG_INFO(("Header: [%.*s]", (int) (h2 - h1), &s[h1])); - if (part != NULL && h1 + cd.len + 2 < h2 && s[h1 + cd.len] == ':' && - mg_ncasecmp(&s[h1], cd.ptr, cd.len) == 0) { - struct mg_str v = mg_str_n(&s[h1 + cd.len + 2], h2 - (h1 + cd.len + 2)); - part->name = mg_http_get_header_var(v, mg_str_n("name", 4)); - part->filename = mg_http_get_header_var(v, mg_str_n("filename", 8)); - } - h1 = h2 = h2 + 2; - } - b1 = b2 = h2 + 2; - while (b2 + 2 + (b - ofs) + 2 < max && !(s[b2] == '\r' && s[b2 + 1] == '\n' && - memcmp(&s[b2 + 2], s, b - ofs) == 0)) - b2++; - if (b2 + 2 >= max) return 0; - if (part != NULL) part->body = mg_str_n(&s[b1], b2 - b1); - // MG_INFO(("Body: [%.*s]", (int) (b2 - b1), &s[b1])); - return b2 + 2; +static time_t ff_time_to_epoch(uint16_t fdate, uint16_t ftime) { + struct tm tm; + memset(&tm, 0, sizeof(struct tm)); + tm.tm_sec = (ftime << 1) & 0x3e; + tm.tm_min = ((ftime >> 5) & 0x3f); + tm.tm_hour = ((ftime >> 11) & 0x1f); + tm.tm_mday = (fdate & 0x1f); + tm.tm_mon = ((fdate >> 5) & 0x0f) - 1; + tm.tm_year = ((fdate >> 9) & 0x7f) + 80; + return mg_timegm(&tm); } -void mg_http_bauth(struct mg_connection *c, const char *user, - const char *pass) { - struct mg_str u = mg_str(user), p = mg_str(pass); - size_t need = c->send.len + 36 + (u.len + p.len) * 2; - if (c->send.size < need) mg_iobuf_resize(&c->send, need); - if (c->send.size >= need) { - int i, n = 0; - char *buf = (char *) &c->send.buf[c->send.len]; - memcpy(buf, "Authorization: Basic ", 21); // DON'T use mg_send! - for (i = 0; i < (int) u.len; i++) { - n = mg_base64_update(((unsigned char *) u.ptr)[i], buf + 21, n); - } - if (p.len > 0) { - n = mg_base64_update(':', buf + 21, n); - for (i = 0; i < (int) p.len; i++) { - n = mg_base64_update(((unsigned char *) p.ptr)[i], buf + 21, n); - } - } - n = mg_base64_final(buf + 21, n); - c->send.len += 21 + (size_t) n + 2; - memcpy(&c->send.buf[c->send.len - 2], "\r\n", 2); +static int ff_stat(const char *path, size_t *size, time_t *mtime) { + FILINFO fi; + if (path[0] == '\0') { + if (size) *size = 0; + if (mtime) *mtime = 0; + return MG_FS_DIR; + } else if (f_stat(path, &fi) == 0) { + if (size) *size = (size_t) fi.fsize; + if (mtime) *mtime = ff_time_to_epoch(fi.fdate, fi.ftime); + return MG_FS_READ | MG_FS_WRITE | ((fi.fattrib & AM_DIR) ? MG_FS_DIR : 0); } else { - MG_ERROR(("%lu oom %d->%d ", c->id, (int) c->send.size, (int) need)); + return 0; } } -struct mg_str mg_http_var(struct mg_str buf, struct mg_str name) { - struct mg_str k, v, result = mg_str_n(NULL, 0); - while (mg_split(&buf, &k, &v, '&')) { - if (name.len == k.len && mg_ncasecmp(name.ptr, k.ptr, k.len) == 0) { - result = v; - break; +static void ff_list(const char *dir, void (*fn)(const char *, void *), + void *userdata) { + DIR d; + FILINFO fi; + if (f_opendir(&d, dir) == FR_OK) { + while (f_readdir(&d, &fi) == FR_OK && fi.fname[0] != '\0') { + if (!strcmp(fi.fname, ".") || !strcmp(fi.fname, "..")) continue; + fn(fi.fname, userdata); } + f_closedir(&d); } - return result; } -int mg_http_get_var(const struct mg_str *buf, const char *name, char *dst, - size_t dst_len) { - int len; - if (dst == NULL || dst_len == 0) { - len = -2; // Bad destination - } else if (buf->ptr == NULL || name == NULL || buf->len == 0) { - len = -1; // Bad source - dst[0] = '\0'; - } else { - struct mg_str v = mg_http_var(*buf, mg_str(name)); - if (v.ptr == NULL) { - len = -4; // Name does not exist - } else { - len = mg_url_decode(v.ptr, v.len, dst, dst_len, 1); - if (len < 0) len = -3; // Failed to decode +static void *ff_open(const char *path, int flags) { + FIL f; + unsigned char mode = FA_READ; + if (flags & MG_FS_WRITE) mode |= FA_WRITE | FA_OPEN_ALWAYS | FA_OPEN_APPEND; + if (f_open(&f, path, mode) == 0) { + FIL *fp; + if ((fp = calloc(1, sizeof(*fp))) != NULL) { + memcpy(fp, &f, sizeof(*fp)); + return fp; } } - return len; + return NULL; } -static bool isx(int c) { - return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || - (c >= 'A' && c <= 'F'); +static void ff_close(void *fp) { + if (fp != NULL) { + f_close((FIL *) fp); + free(fp); + } } -int mg_url_decode(const char *src, size_t src_len, char *dst, size_t dst_len, - int is_form_url_encoded) { - size_t i, j; - for (i = j = 0; i < src_len && j + 1 < dst_len; i++, j++) { - if (src[i] == '%') { - // Use `i + 2 < src_len`, not `i < src_len - 2`, note small src_len - if (i + 2 < src_len && isx(src[i + 1]) && isx(src[i + 2])) { - mg_unhex(src + i + 1, 2, (uint8_t *) &dst[j]); - i += 2; - } else { - return -1; - } - } else if (is_form_url_encoded && src[i] == '+') { - dst[j] = ' '; - } else { - dst[j] = src[i]; - } +static size_t ff_read(void *fp, void *buf, size_t len) { + UINT n = 0, misalign = ((size_t) buf) & 3; + if (misalign) { + char aligned[4]; + f_read((FIL *) fp, aligned, len > misalign ? misalign : len, &n); + memcpy(buf, aligned, n); + } else { + f_read((FIL *) fp, buf, len, &n); } - if (j < dst_len) dst[j] = '\0'; // Null-terminate the destination - return i >= src_len && j < dst_len ? (int) j : -1; + return n; } -static bool isok(uint8_t c) { return c == '\n' || c == '\r' || c >= ' '; } - -int mg_http_get_request_len(const unsigned char *buf, size_t buf_len) { - size_t i; - for (i = 0; i < buf_len; i++) { - if (!isok(buf[i])) return -1; - if ((i > 0 && buf[i] == '\n' && buf[i - 1] == '\n') || - (i > 3 && buf[i] == '\n' && buf[i - 1] == '\r' && buf[i - 2] == '\n')) - return (int) i + 1; - } - return 0; +static size_t ff_write(void *fp, const void *buf, size_t len) { + UINT n = 0; + return f_write((FIL *) fp, (char *) buf, len, &n) == FR_OK ? n : 0; } -static const char *skip(const char *s, const char *e, const char *d, - struct mg_str *v) { - v->ptr = s; - while (s < e && *s != '\n' && strchr(d, *s) == NULL) s++; - v->len = (size_t) (s - v->ptr); - while (s < e && strchr(d, *s) != NULL) s++; - return s; +static size_t ff_seek(void *fp, size_t offset) { + f_lseek((FIL *) fp, offset); + return offset; } -struct mg_str *mg_http_get_header(struct mg_http_message *h, const char *name) { - size_t i, n = strlen(name), max = sizeof(h->headers) / sizeof(h->headers[0]); - for (i = 0; i < max && h->headers[i].name.len > 0; i++) { - struct mg_str *k = &h->headers[i].name, *v = &h->headers[i].value; - if (n == k->len && mg_ncasecmp(k->ptr, name, n) == 0) return v; - } - return NULL; +static bool ff_rename(const char *from, const char *to) { + return f_rename(from, to) == FR_OK; } -static void mg_http_parse_headers(const char *s, const char *end, - struct mg_http_header *h, int max_headers) { - int i; - for (i = 0; i < max_headers; i++) { - struct mg_str k, v, tmp; - const char *he = skip(s, end, "\n", &tmp); - s = skip(s, he, ": \r\n", &k); - s = skip(s, he, "\r\n", &v); - if (k.len == tmp.len) continue; - while (v.len > 0 && v.ptr[v.len - 1] == ' ') v.len--; // Trim spaces - if (k.len == 0) break; - // MG_INFO(("--HH [%.*s] [%.*s] [%.*s]", (int) tmp.len - 1, tmp.ptr, - //(int) k.len, k.ptr, (int) v.len, v.ptr)); - h[i].name = k; - h[i].value = v; - } +static bool ff_remove(const char *path) { + return f_unlink(path) == FR_OK; } -int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) { - int is_response, req_len = mg_http_get_request_len((unsigned char *) s, len); - const char *end = s == NULL ? NULL : s + req_len, *qs; // Cannot add to NULL - struct mg_str *cl; +static bool ff_mkdir(const char *path) { + return f_mkdir(path) == FR_OK; +} - memset(hm, 0, sizeof(*hm)); - if (req_len <= 0) return req_len; +struct mg_fs mg_fs_fat = {ff_stat, ff_list, ff_open, ff_close, ff_read, + ff_write, ff_seek, ff_rename, ff_remove, ff_mkdir}; +#endif - hm->message.ptr = hm->head.ptr = s; - hm->body.ptr = end; - hm->head.len = (size_t) req_len; - hm->chunk.ptr = end; - hm->message.len = hm->body.len = (size_t) ~0; // Set body length to infinite +#ifdef MG_ENABLE_LINES +#line 1 "src/fs_packed.c" +#endif - // Parse request line - s = skip(s, end, " ", &hm->method); - s = skip(s, end, " ", &hm->uri); - s = skip(s, end, "\r\n", &hm->proto); - // Sanity check. Allow protocol/reason to be empty - if (hm->method.len == 0 || hm->uri.len == 0) return -1; - // If URI contains '?' character, setup query string - if ((qs = (const char *) memchr(hm->uri.ptr, '?', hm->uri.len)) != NULL) { - hm->query.ptr = qs + 1; - hm->query.len = (size_t) (&hm->uri.ptr[hm->uri.len] - (qs + 1)); - hm->uri.len = (size_t) (qs - hm->uri.ptr); - } - mg_http_parse_headers(s, end, hm->headers, - sizeof(hm->headers) / sizeof(hm->headers[0])); - if ((cl = mg_http_get_header(hm, "Content-Length")) != NULL) { - hm->body.len = (size_t) mg_to64(*cl); - hm->message.len = (size_t) req_len + hm->body.len; - } +struct packed_file { + const char *data; + size_t size; + size_t pos; +}; - // mg_http_parse() is used to parse both HTTP requests and HTTP - // responses. If HTTP response does not have Content-Length set, then - // body is read until socket is closed, i.e. body.len is infinite (~0). - // - // For HTTP requests though, according to - // http://tools.ietf.org/html/rfc7231#section-8.1.3, - // only POST and PUT methods have defined body semantics. - // Therefore, if Content-Length is not specified and methods are - // not one of PUT or POST, set body length to 0. - // - // So, if it is HTTP request, and Content-Length is not set, - // and method is not (PUT or POST) then reset body length to zero. - is_response = mg_ncasecmp(hm->method.ptr, "HTTP/", 5) == 0; - if (hm->body.len == (size_t) ~0 && !is_response && - mg_vcasecmp(&hm->method, "PUT") != 0 && - mg_vcasecmp(&hm->method, "POST") != 0) { - hm->body.len = 0; - hm->message.len = (size_t) req_len; - } +#if MG_ENABLE_PACKED_FS +#else +const char *mg_unpack(const char *path, size_t *size, time_t *mtime) { + *size = 0, *mtime = 0; + (void) path; + return NULL; +} +const char *mg_unlist(size_t no) { + (void) no; + return NULL; +} +#endif - // The 204 (No content) responses also have 0 body length - if (hm->body.len == (size_t) ~0 && is_response && - mg_vcasecmp(&hm->uri, "204") == 0) { - hm->body.len = 0; - hm->message.len = (size_t) req_len; - } +struct mg_str mg_unpacked(const char *path) { + size_t len = 0; + const char *buf = mg_unpack(path, &len, NULL); + return mg_str_n(buf, len); +} - return req_len; +static int is_dir_prefix(const char *prefix, size_t n, const char *path) { + // MG_INFO(("[%.*s] [%s] %c", (int) n, prefix, path, path[n])); + return n < strlen(path) && strncmp(prefix, path, n) == 0 && + (n == 0 || path[n] == '/' || path[n - 1] == '/'); } -static void mg_http_vprintf_chunk(struct mg_connection *c, const char *fmt, - va_list *ap) { - size_t len = c->send.len; - mg_send(c, " \r\n", 10); - mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap); - if (c->send.len >= len + 10) { - mg_snprintf((char *) c->send.buf + len, 9, "%08lx", c->send.len - len - 10); - c->send.buf[len + 8] = '\r'; - if (c->send.len == len + 10) c->is_resp = 0; // Last chunk, reset marker +static int packed_stat(const char *path, size_t *size, time_t *mtime) { + const char *p; + size_t i, n = strlen(path); + if (mg_unpack(path, size, mtime)) return MG_FS_READ; // Regular file + // Scan all files. If `path` is a dir prefix for any of them, it's a dir + for (i = 0; (p = mg_unlist(i)) != NULL; i++) { + if (is_dir_prefix(path, n, p)) return MG_FS_DIR; } - mg_send(c, "\r\n", 2); + return 0; } -void mg_http_printf_chunk(struct mg_connection *c, const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - mg_http_vprintf_chunk(c, fmt, &ap); - va_end(ap); +static void packed_list(const char *dir, void (*fn)(const char *, void *), + void *userdata) { + char buf[MG_PATH_MAX], tmp[sizeof(buf)]; + const char *path, *begin, *end; + size_t i, n = strlen(dir); + tmp[0] = '\0'; // Previously listed entry + for (i = 0; (path = mg_unlist(i)) != NULL; i++) { + if (!is_dir_prefix(dir, n, path)) continue; + begin = &path[n + 1]; + end = strchr(begin, '/'); + if (end == NULL) end = begin + strlen(begin); + mg_snprintf(buf, sizeof(buf), "%.*s", (int) (end - begin), begin); + buf[sizeof(buf) - 1] = '\0'; + // If this entry has been already listed, skip + // NOTE: we're assuming that file list is sorted alphabetically + if (strcmp(buf, tmp) == 0) continue; + fn(buf, userdata); // Not yet listed, call user function + strcpy(tmp, buf); // And save this entry as listed + } } -void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len) { - mg_printf(c, "%lx\r\n", (unsigned long) len); - mg_send(c, buf, len); - mg_send(c, "\r\n", 2); - if (len == 0) c->is_resp = 0; +static void *packed_open(const char *path, int flags) { + size_t size = 0; + const char *data = mg_unpack(path, &size, NULL); + struct packed_file *fp = NULL; + if (data == NULL) return NULL; + if (flags & MG_FS_WRITE) return NULL; + if ((fp = (struct packed_file *) calloc(1, sizeof(*fp))) != NULL) { + fp->size = size; + fp->data = data; + } + return (void *) fp; } -// clang-format off -static const char *mg_http_status_code_str(int status_code) { - switch (status_code) { - case 100: return "Continue"; - case 201: return "Created"; - case 202: return "Accepted"; - case 204: return "No Content"; - case 206: return "Partial Content"; - case 301: return "Moved Permanently"; - case 302: return "Found"; - case 304: return "Not Modified"; - case 400: return "Bad Request"; - case 401: return "Unauthorized"; - case 403: return "Forbidden"; - case 404: return "Not Found"; - case 418: return "I'm a teapot"; - case 500: return "Internal Server Error"; - case 501: return "Not Implemented"; - default: return "OK"; - } +static void packed_close(void *fp) { + if (fp != NULL) free(fp); } -// clang-format on -void mg_http_reply(struct mg_connection *c, int code, const char *headers, - const char *fmt, ...) { - va_list ap; - size_t len; - mg_printf(c, "HTTP/1.1 %d %s\r\n%sContent-Length: \r\n\r\n", code, - mg_http_status_code_str(code), headers == NULL ? "" : headers); - len = c->send.len; - va_start(ap, fmt); - mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, &ap); - va_end(ap); - if (c->send.len > 15) { - mg_snprintf((char *) &c->send.buf[len - 14], 11, "%010lu", - (unsigned long) (c->send.len - len)); - c->is_resp = 0; - c->send.buf[len - 4] = '\r'; // Change ending 0 to space - } - c->is_resp = 0; +static size_t packed_read(void *fd, void *buf, size_t len) { + struct packed_file *fp = (struct packed_file *) fd; + if (fp->pos + len > fp->size) len = fp->size - fp->pos; + memcpy(buf, &fp->data[fp->pos], len); + fp->pos += len; + return len; } -static void http_cb(struct mg_connection *, int, void *, void *); -static void restore_http_cb(struct mg_connection *c) { - mg_fs_close((struct mg_fd *) c->pfn_data); - c->pfn_data = NULL; - c->pfn = http_cb; - c->is_resp = 0; +static size_t packed_write(void *fd, const void *buf, size_t len) { + (void) fd, (void) buf, (void) len; + return 0; } -char *mg_http_etag(char *buf, size_t len, size_t size, time_t mtime); -char *mg_http_etag(char *buf, size_t len, size_t size, time_t mtime) { - mg_snprintf(buf, len, "\"%lld.%lld\"", (int64_t) mtime, (int64_t) size); - return buf; +static size_t packed_seek(void *fd, size_t offset) { + struct packed_file *fp = (struct packed_file *) fd; + fp->pos = offset; + if (fp->pos > fp->size) fp->pos = fp->size; + return fp->pos; } -static void static_cb(struct mg_connection *c, int ev, void *ev_data, - void *fn_data) { - if (ev == MG_EV_WRITE || ev == MG_EV_POLL) { - struct mg_fd *fd = (struct mg_fd *) fn_data; - // Read to send IO buffer directly, avoid extra on-stack buffer - size_t n, max = MG_IO_SIZE, space; - size_t *cl = (size_t *) &c->data[(sizeof(c->data) - sizeof(size_t)) / - sizeof(size_t) * sizeof(size_t)]; - if (c->send.size < max) mg_iobuf_resize(&c->send, max); - if (c->send.len >= c->send.size) return; // Rate limit - if ((space = c->send.size - c->send.len) > *cl) space = *cl; - n = fd->fs->rd(fd->fd, c->send.buf + c->send.len, space); - c->send.len += n; - *cl -= n; - if (n == 0) restore_http_cb(c); - } else if (ev == MG_EV_CLOSE) { - restore_http_cb(c); - } - (void) ev_data; +static bool packed_rename(const char *from, const char *to) { + (void) from, (void) to; + return false; } -// Known mime types. Keep it outside guess_content_type() function, since -// some environments don't like it defined there. -// clang-format off -static struct mg_str s_known_types[] = { - MG_C_STR("html"), MG_C_STR("text/html; charset=utf-8"), - MG_C_STR("htm"), MG_C_STR("text/html; charset=utf-8"), - MG_C_STR("css"), MG_C_STR("text/css; charset=utf-8"), - MG_C_STR("js"), MG_C_STR("text/javascript; charset=utf-8"), - MG_C_STR("gif"), MG_C_STR("image/gif"), - MG_C_STR("png"), MG_C_STR("image/png"), - MG_C_STR("jpg"), MG_C_STR("image/jpeg"), - MG_C_STR("jpeg"), MG_C_STR("image/jpeg"), - MG_C_STR("woff"), MG_C_STR("font/woff"), - MG_C_STR("ttf"), MG_C_STR("font/ttf"), - MG_C_STR("svg"), MG_C_STR("image/svg+xml"), - MG_C_STR("txt"), MG_C_STR("text/plain; charset=utf-8"), - MG_C_STR("avi"), MG_C_STR("video/x-msvideo"), - MG_C_STR("csv"), MG_C_STR("text/csv"), - MG_C_STR("doc"), MG_C_STR("application/msword"), - MG_C_STR("exe"), MG_C_STR("application/octet-stream"), - MG_C_STR("gz"), MG_C_STR("application/gzip"), - MG_C_STR("ico"), MG_C_STR("image/x-icon"), - MG_C_STR("json"), MG_C_STR("application/json"), - MG_C_STR("mov"), MG_C_STR("video/quicktime"), - MG_C_STR("mp3"), MG_C_STR("audio/mpeg"), - MG_C_STR("mp4"), MG_C_STR("video/mp4"), - MG_C_STR("mpeg"), MG_C_STR("video/mpeg"), - MG_C_STR("pdf"), MG_C_STR("application/pdf"), - MG_C_STR("shtml"), MG_C_STR("text/html; charset=utf-8"), - MG_C_STR("tgz"), MG_C_STR("application/tar-gz"), - MG_C_STR("wav"), MG_C_STR("audio/wav"), - MG_C_STR("webp"), MG_C_STR("image/webp"), - MG_C_STR("zip"), MG_C_STR("application/zip"), - MG_C_STR("3gp"), MG_C_STR("video/3gpp"), - {0, 0}, -}; -// clang-format on +static bool packed_remove(const char *path) { + (void) path; + return false; +} -static struct mg_str guess_content_type(struct mg_str path, const char *extra) { - struct mg_str k, v, s = mg_str(extra); - size_t i = 0; +static bool packed_mkdir(const char *path) { + (void) path; + return false; +} - // Shrink path to its extension only - while (i < path.len && path.ptr[path.len - i - 1] != '.') i++; - path.ptr += path.len - i; - path.len = i; +struct mg_fs mg_fs_packed = { + packed_stat, packed_list, packed_open, packed_close, packed_read, + packed_write, packed_seek, packed_rename, packed_remove, packed_mkdir}; - // Process user-provided mime type overrides, if any - while (mg_commalist(&s, &k, &v)) { - if (mg_strcmp(path, k) == 0) return v; - } +#ifdef MG_ENABLE_LINES +#line 1 "src/fs_posix.c" +#endif - // Process built-in mime types - for (i = 0; s_known_types[i].ptr != NULL; i += 2) { - if (mg_strcmp(path, s_known_types[i]) == 0) return s_known_types[i + 1]; - } - return mg_str("text/plain; charset=utf-8"); -} +#if MG_ENABLE_POSIX_FS -static int getrange(struct mg_str *s, int64_t *a, int64_t *b) { - size_t i, numparsed = 0; - // MG_INFO(("%.*s", (int) s->len, s->ptr)); - for (i = 0; i + 6 < s->len; i++) { - if (memcmp(&s->ptr[i], "bytes=", 6) == 0) { - struct mg_str p = mg_str_n(s->ptr + i + 6, s->len - i - 6); - if (p.len > 0 && p.ptr[0] >= '0' && p.ptr[0] <= '9') numparsed++; - *a = mg_to64(p); - // MG_INFO(("PPP [%.*s] %d", (int) p.len, p.ptr, numparsed)); - while (p.len && p.ptr[0] >= '0' && p.ptr[0] <= '9') p.ptr++, p.len--; - if (p.len && p.ptr[0] == '-') p.ptr++, p.len--; - *b = mg_to64(p); - if (p.len > 0 && p.ptr[0] >= '0' && p.ptr[0] <= '9') numparsed++; - // MG_INFO(("PPP [%.*s] %d", (int) p.len, p.ptr, numparsed)); - break; - } - } - return (int) numparsed; -} +#ifndef MG_STAT_STRUCT +#define MG_STAT_STRUCT stat +#endif -void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm, - const char *path, - const struct mg_http_serve_opts *opts) { - char etag[64], tmp[MG_PATH_MAX]; - struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs; - struct mg_fd *fd = path == NULL ? NULL : mg_fs_open(fs, path, MG_FS_READ); - size_t size = 0; - time_t mtime = 0; - struct mg_str *inm = NULL; - struct mg_str mime = guess_content_type(mg_str(path), opts->mime_types); - bool gzip = false; +#ifndef MG_STAT_FUNC +#define MG_STAT_FUNC stat +#endif - // If file does not exist, we try to open file PATH.gz - and if such - // pre-compressed .gz file exists, serve it with the Content-Encoding: gzip - // Note - we ignore Accept-Encoding, cause we don't have a choice - if (fd == NULL) { - MG_DEBUG(("NULL [%s]", path)); - mg_snprintf(tmp, sizeof(tmp), "%s.gz", path); - if ((fd = mg_fs_open(fs, tmp, MG_FS_READ)) != NULL) { - gzip = true; - path = tmp; - } else if (opts->page404 != NULL) { - // No precompressed file, serve 404 - fd = mg_fs_open(fs, opts->page404, MG_FS_READ); - mime = guess_content_type(mg_str(path), opts->mime_types); - path = opts->page404; +static int p_stat(const char *path, size_t *size, time_t *mtime) { +#if !defined(S_ISDIR) + MG_ERROR(("stat() API is not supported. %p %p %p", path, size, mtime)); + return 0; +#else +#if MG_ARCH == MG_ARCH_WIN32 + struct _stati64 st; + wchar_t tmp[MG_PATH_MAX]; + MultiByteToWideChar(CP_UTF8, 0, path, -1, tmp, sizeof(tmp) / sizeof(tmp[0])); + if (_wstati64(tmp, &st) != 0) return 0; + // If path is a symlink, windows reports 0 in st.st_size. + // Get a real file size by opening it and jumping to the end + if (st.st_size == 0 && (st.st_mode & _S_IFREG)) { + FILE *fp = _wfopen(tmp, L"rb"); + if (fp != NULL) { + fseek(fp, 0, SEEK_END); + if (ftell(fp) > 0) st.st_size = ftell(fp); // Use _ftelli64 on win10+ + fclose(fp); } } +#else + struct MG_STAT_STRUCT st; + if (MG_STAT_FUNC(path, &st) != 0) return 0; +#endif + if (size) *size = (size_t) st.st_size; + if (mtime) *mtime = st.st_mtime; + return MG_FS_READ | MG_FS_WRITE | (S_ISDIR(st.st_mode) ? MG_FS_DIR : 0); +#endif +} - if (fd == NULL || fs->st(path, &size, &mtime) == 0) { - mg_http_reply(c, 404, opts->extra_headers, "Not found\n"); - mg_fs_close(fd); - // NOTE: mg_http_etag() call should go first! - } else if (mg_http_etag(etag, sizeof(etag), size, mtime) != NULL && - (inm = mg_http_get_header(hm, "If-None-Match")) != NULL && - mg_vcasecmp(inm, etag) == 0) { - mg_fs_close(fd); - mg_http_reply(c, 304, opts->extra_headers, ""); - } else { - int n, status = 200; - char range[100]; - int64_t r1 = 0, r2 = 0, cl = (int64_t) size; +#if MG_ARCH == MG_ARCH_WIN32 +struct dirent { + char d_name[MAX_PATH]; +}; - // Handle Range header - struct mg_str *rh = mg_http_get_header(hm, "Range"); - range[0] = '\0'; - if (rh != NULL && (n = getrange(rh, &r1, &r2)) > 0 && r1 >= 0 && r2 >= 0) { - // If range is specified like "400-", set second limit to content len - if (n == 1) r2 = cl - 1; - if (r1 > r2 || r2 >= cl) { - status = 416; - cl = 0; - mg_snprintf(range, sizeof(range), "Content-Range: bytes */%lld\r\n", - (int64_t) size); - } else { - status = 206; - cl = r2 - r1 + 1; - mg_snprintf(range, sizeof(range), - "Content-Range: bytes %lld-%lld/%lld\r\n", r1, r1 + cl - 1, - (int64_t) size); - fs->sk(fd->fd, (size_t) r1); - } - } - mg_printf(c, - "HTTP/1.1 %d %s\r\n" - "Content-Type: %.*s\r\n" - "Etag: %s\r\n" - "Content-Length: %llu\r\n" - "%s%s%s\r\n", - status, mg_http_status_code_str(status), (int) mime.len, mime.ptr, - etag, cl, gzip ? "Content-Encoding: gzip\r\n" : "", range, - opts->extra_headers ? opts->extra_headers : ""); - if (mg_vcasecmp(&hm->method, "HEAD") == 0) { - c->is_draining = 1; - c->is_resp = 0; - mg_fs_close(fd); - } else { - // Track to-be-sent content length at the end of c->data, aligned - size_t *clp = (size_t *) &c->data[(sizeof(c->data) - sizeof(size_t)) / - sizeof(size_t) * sizeof(size_t)]; - c->pfn = static_cb; - c->pfn_data = fd; - *clp = (size_t) cl; - } +typedef struct win32_dir { + HANDLE handle; + WIN32_FIND_DATAW info; + struct dirent result; +} DIR; + +#if 0 +int gettimeofday(struct timeval *tv, void *tz) { + FILETIME ft; + unsigned __int64 tmpres = 0; + + if (tv != NULL) { + GetSystemTimeAsFileTime(&ft); + tmpres |= ft.dwHighDateTime; + tmpres <<= 32; + tmpres |= ft.dwLowDateTime; + tmpres /= 10; // convert into microseconds + tmpres -= (int64_t) 11644473600000000; + tv->tv_sec = (long) (tmpres / 1000000UL); + tv->tv_usec = (long) (tmpres % 1000000UL); } + (void) tz; + return 0; } +#endif -struct printdirentrydata { - struct mg_connection *c; - struct mg_http_message *hm; - const struct mg_http_serve_opts *opts; - const char *dir; -}; +static int to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len) { + int ret; + char buf[MAX_PATH * 2], buf2[MAX_PATH * 2], *p; + strncpy(buf, path, sizeof(buf)); + buf[sizeof(buf) - 1] = '\0'; + // Trim trailing slashes. Leave backslash for paths like "X:\" + p = buf + strlen(buf) - 1; + while (p > buf && p[-1] != ':' && (p[0] == '\\' || p[0] == '/')) *p-- = '\0'; + memset(wbuf, 0, wbuf_len * sizeof(wchar_t)); + ret = MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len); + // Convert back to Unicode. If doubly-converted string does not match the + // original, something is fishy, reject. + WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2), + NULL, NULL); + if (strcmp(buf, buf2) != 0) { + wbuf[0] = L'\0'; + ret = 0; + } + return ret; +} -static void printdirentry(const char *name, void *userdata) { - struct printdirentrydata *d = (struct printdirentrydata *) userdata; - struct mg_fs *fs = d->opts->fs == NULL ? &mg_fs_posix : d->opts->fs; - size_t size = 0; - time_t t = 0; - char path[MG_PATH_MAX], sz[40], mod[40]; - int flags, n = 0; +DIR *opendir(const char *name) { + DIR *d = NULL; + wchar_t wpath[MAX_PATH]; + DWORD attrs; - // MG_DEBUG(("[%s] [%s]", d->dir, name)); - if (mg_snprintf(path, sizeof(path), "%s%c%s", d->dir, '/', name) > - sizeof(path)) { - MG_ERROR(("%s truncated", name)); - } else if ((flags = fs->st(path, &size, &t)) == 0) { - MG_ERROR(("%lu stat(%s): %d", d->c->id, path, errno)); + if (name == NULL) { + SetLastError(ERROR_BAD_ARGUMENTS); + } else if ((d = (DIR *) calloc(1, sizeof(*d))) == NULL) { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); } else { - const char *slash = flags & MG_FS_DIR ? "/" : ""; - if (flags & MG_FS_DIR) { - mg_snprintf(sz, sizeof(sz), "%s", "[DIR]"); + to_wchar(name, wpath, sizeof(wpath) / sizeof(wpath[0])); + attrs = GetFileAttributesW(wpath); + if (attrs != 0Xffffffff && (attrs & FILE_ATTRIBUTE_DIRECTORY)) { + (void) wcscat(wpath, L"\\*"); + d->handle = FindFirstFileW(wpath, &d->info); + d->result.d_name[0] = '\0'; } else { - mg_snprintf(sz, sizeof(sz), "%lld", (uint64_t) size); + free(d); + d = NULL; } -#if defined(MG_HTTP_DIRLIST_TIME) - char time_str[30]; - struct tm *time_info = localtime(&t); - strftime(time_str, sizeof time_str, "%Y/%m/%d %H:%M:%S", time_info); - mg_snprintf(mod, sizeof(mod), "%s", time_str); -#elif defined(MG_HTTP_DIRLIST_TIME_UTC) - char time_str[30]; - struct tm *time_info = gmtime(&t); - strftime(time_str, sizeof time_str, "%Y/%m/%d %H:%M:%S", time_info); - mg_snprintf(mod, sizeof(mod), "%s", time_str); -#else - mg_snprintf(mod, sizeof(mod), "%ld", (unsigned long) t); -#endif - n = (int) mg_url_encode(name, strlen(name), path, sizeof(path)); - mg_printf(d->c, - " %s%s" - "%s%s\n", - n, path, slash, name, slash, (unsigned long) t, mod, - flags & MG_FS_DIR ? (int64_t) -1 : (int64_t) size, sz); } + return d; } -static void listdir(struct mg_connection *c, struct mg_http_message *hm, - const struct mg_http_serve_opts *opts, char *dir) { - const char *sort_js_code = - ""; - struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs; - struct printdirentrydata d = {c, hm, opts, dir}; - char tmp[10], buf[MG_PATH_MAX]; - size_t off, n; - int len = mg_url_decode(hm->uri.ptr, hm->uri.len, buf, sizeof(buf), 0); - struct mg_str uri = len > 0 ? mg_str_n(buf, (size_t) len) : hm->uri; - - mg_printf(c, - "HTTP/1.1 200 OK\r\n" - "Content-Type: text/html; charset=utf-8\r\n" - "%s" - "Content-Length: \r\n\r\n", - opts->extra_headers == NULL ? "" : opts->extra_headers); - off = c->send.len; // Start of body - mg_printf(c, - "Index of %.*s%s%s" - "" - "

Index of %.*s

" - "" - "" - "" - "" - "\n", - (int) uri.len, uri.ptr, sort_js_code, sort_js_code2, (int) uri.len, - uri.ptr); - mg_printf(c, "%s", - " " - "\n"); - - fs->ls(dir, printdirentry, &d); - mg_printf(c, - "" - "
Name" - "ModifiedSize

..[DIR]

Mongoose v.%s
\n", - MG_VERSION); - n = mg_snprintf(tmp, sizeof(tmp), "%lu", (unsigned long) (c->send.len - off)); - if (n > sizeof(tmp)) n = 0; - memcpy(c->send.buf + off - 12, tmp, n); // Set content length - c->is_resp = 0; // Mark response end +int closedir(DIR *d) { + int result = 0; + if (d != NULL) { + if (d->handle != INVALID_HANDLE_VALUE) + result = FindClose(d->handle) ? 0 : -1; + free(d); + } else { + result = -1; + SetLastError(ERROR_BAD_ARGUMENTS); + } + return result; } -// Resolve requested file into `path` and return its fs->st() result -static int uri_to_path2(struct mg_connection *c, struct mg_http_message *hm, - struct mg_fs *fs, struct mg_str url, struct mg_str dir, - char *path, size_t path_size) { - int flags, tmp; - // Append URI to the root_dir, and sanitize it - size_t n = mg_snprintf(path, path_size, "%.*s", (int) dir.len, dir.ptr); - if (n > path_size) n = path_size; - path[path_size - 1] = '\0'; - if (n + 2 < path_size) path[n++] = '/', path[n] = '\0'; - mg_url_decode(hm->uri.ptr + url.len, hm->uri.len - url.len, path + n, - path_size - n, 0); - path[path_size - 1] = '\0'; // Double-check - mg_remove_double_dots(path); - n = strlen(path); - while (n > 1 && path[n - 1] == '/') path[--n] = 0; // Trim trailing slashes - flags = mg_vcmp(&hm->uri, "/") == 0 ? MG_FS_DIR : fs->st(path, NULL, NULL); - MG_VERBOSE(("%lu %.*s -> %s %d", c->id, (int) hm->uri.len, hm->uri.ptr, path, - flags)); - if (flags == 0) { - // Do nothing - let's caller decide - } else if ((flags & MG_FS_DIR) && hm->uri.len > 0 && - hm->uri.ptr[hm->uri.len - 1] != '/') { - mg_printf(c, - "HTTP/1.1 301 Moved\r\n" - "Location: %.*s/\r\n" - "Content-Length: 0\r\n" +struct dirent *readdir(DIR *d) { + struct dirent *result = NULL; + if (d != NULL) { + memset(&d->result, 0, sizeof(d->result)); + if (d->handle != INVALID_HANDLE_VALUE) { + result = &d->result; + WideCharToMultiByte(CP_UTF8, 0, d->info.cFileName, -1, result->d_name, + sizeof(result->d_name), NULL, NULL); + if (!FindNextFileW(d->handle, &d->info)) { + FindClose(d->handle); + d->handle = INVALID_HANDLE_VALUE; + } + } else { + SetLastError(ERROR_FILE_NOT_FOUND); + } + } else { + SetLastError(ERROR_BAD_ARGUMENTS); + } + return result; +} +#endif + +static void p_list(const char *dir, void (*fn)(const char *, void *), + void *userdata) { +#if MG_ENABLE_DIRLIST + struct dirent *dp; + DIR *dirp; + if ((dirp = (opendir(dir))) == NULL) return; + while ((dp = readdir(dirp)) != NULL) { + if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue; + fn(dp->d_name, userdata); + } + closedir(dirp); +#else + (void) dir, (void) fn, (void) userdata; +#endif +} + +static void *p_open(const char *path, int flags) { +#if MG_ARCH == MG_ARCH_WIN32 + const char *mode = flags == MG_FS_READ ? "rb" : "a+b"; + wchar_t b1[MG_PATH_MAX], b2[10]; + MultiByteToWideChar(CP_UTF8, 0, path, -1, b1, sizeof(b1) / sizeof(b1[0])); + MultiByteToWideChar(CP_UTF8, 0, mode, -1, b2, sizeof(b2) / sizeof(b2[0])); + return (void *) _wfopen(b1, b2); +#else + const char *mode = flags == MG_FS_READ ? "rbe" : "a+be"; // e for CLOEXEC + return (void *) fopen(path, mode); +#endif +} + +static void p_close(void *fp) { + fclose((FILE *) fp); +} + +static size_t p_read(void *fp, void *buf, size_t len) { + return fread(buf, 1, len, (FILE *) fp); +} + +static size_t p_write(void *fp, const void *buf, size_t len) { + return fwrite(buf, 1, len, (FILE *) fp); +} + +static size_t p_seek(void *fp, size_t offset) { +#if (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64) || \ + (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || \ + (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600) + if (fseeko((FILE *) fp, (off_t) offset, SEEK_SET) != 0) (void) 0; +#else + if (fseek((FILE *) fp, (long) offset, SEEK_SET) != 0) (void) 0; +#endif + return (size_t) ftell((FILE *) fp); +} + +static bool p_rename(const char *from, const char *to) { + return rename(from, to) == 0; +} + +static bool p_remove(const char *path) { + return remove(path) == 0; +} + +static bool p_mkdir(const char *path) { + return mkdir(path, 0775) == 0; +} + +#else + +static int p_stat(const char *path, size_t *size, time_t *mtime) { + (void) path, (void) size, (void) mtime; + return 0; +} +static void p_list(const char *path, void (*fn)(const char *, void *), + void *userdata) { + (void) path, (void) fn, (void) userdata; +} +static void *p_open(const char *path, int flags) { + (void) path, (void) flags; + return NULL; +} +static void p_close(void *fp) { + (void) fp; +} +static size_t p_read(void *fd, void *buf, size_t len) { + (void) fd, (void) buf, (void) len; + return 0; +} +static size_t p_write(void *fd, const void *buf, size_t len) { + (void) fd, (void) buf, (void) len; + return 0; +} +static size_t p_seek(void *fd, size_t offset) { + (void) fd, (void) offset; + return (size_t) ~0; +} +static bool p_rename(const char *from, const char *to) { + (void) from, (void) to; + return false; +} +static bool p_remove(const char *path) { + (void) path; + return false; +} +static bool p_mkdir(const char *path) { + (void) path; + return false; +} +#endif + +struct mg_fs mg_fs_posix = {p_stat, p_list, p_open, p_close, p_read, + p_write, p_seek, p_rename, p_remove, p_mkdir}; + +#ifdef MG_ENABLE_LINES +#line 1 "src/http.c" +#endif + + + + + + + + + + + + + +static int mg_ncasecmp(const char *s1, const char *s2, size_t len) { + int diff = 0; + if (len > 0) do { + int c = *s1++, d = *s2++; + if (c >= 'A' && c <= 'Z') c += 'a' - 'A'; + if (d >= 'A' && d <= 'Z') d += 'a' - 'A'; + diff = c - d; + } while (diff == 0 && s1[-1] != '\0' && --len > 0); + return diff; +} + +bool mg_to_size_t(struct mg_str str, size_t *val); +bool mg_to_size_t(struct mg_str str, size_t *val) { + size_t i = 0, max = (size_t) -1, max2 = max / 10, result = 0, ndigits = 0; + while (i < str.len && (str.buf[i] == ' ' || str.buf[i] == '\t')) i++; + if (i < str.len && str.buf[i] == '-') return false; + while (i < str.len && str.buf[i] >= '0' && str.buf[i] <= '9') { + size_t digit = (size_t) (str.buf[i] - '0'); + if (result > max2) return false; // Overflow + result *= 10; + if (result > max - digit) return false; // Overflow + result += digit; + i++, ndigits++; + } + while (i < str.len && (str.buf[i] == ' ' || str.buf[i] == '\t')) i++; + if (ndigits == 0) return false; // #2322: Content-Length = 1 * DIGIT + if (i != str.len) return false; // Ditto + *val = (size_t) result; + return true; +} + +// Chunk deletion marker is the MSB in the "processed" counter +#define MG_DMARK ((size_t) 1 << (sizeof(size_t) * 8 - 1)) + +// Multipart POST example: +// --xyz +// Content-Disposition: form-data; name="val" +// +// abcdef +// --xyz +// Content-Disposition: form-data; name="foo"; filename="a.txt" +// Content-Type: text/plain +// +// hello world +// +// --xyz-- +size_t mg_http_next_multipart(struct mg_str body, size_t ofs, + struct mg_http_part *part) { + struct mg_str cd = mg_str_n("Content-Disposition", 19); + const char *s = body.buf; + size_t b = ofs, h1, h2, b1, b2, max = body.len; + + // Init part params + if (part != NULL) part->name = part->filename = part->body = mg_str_n(0, 0); + + // Skip boundary + while (b + 2 < max && s[b] != '\r' && s[b + 1] != '\n') b++; + if (b <= ofs || b + 2 >= max) return 0; + // MG_INFO(("B: %zu %zu [%.*s]", ofs, b - ofs, (int) (b - ofs), s)); + + // Skip headers + h1 = h2 = b + 2; + for (;;) { + while (h2 + 2 < max && s[h2] != '\r' && s[h2 + 1] != '\n') h2++; + if (h2 == h1) break; + if (h2 + 2 >= max) return 0; + // MG_INFO(("Header: [%.*s]", (int) (h2 - h1), &s[h1])); + if (part != NULL && h1 + cd.len + 2 < h2 && s[h1 + cd.len] == ':' && + mg_ncasecmp(&s[h1], cd.buf, cd.len) == 0) { + struct mg_str v = mg_str_n(&s[h1 + cd.len + 2], h2 - (h1 + cd.len + 2)); + part->name = mg_http_get_header_var(v, mg_str_n("name", 4)); + part->filename = mg_http_get_header_var(v, mg_str_n("filename", 8)); + } + h1 = h2 = h2 + 2; + } + b1 = b2 = h2 + 2; + while (b2 + 2 + (b - ofs) + 2 < max && !(s[b2] == '\r' && s[b2 + 1] == '\n' && + memcmp(&s[b2 + 2], s, b - ofs) == 0)) + b2++; + + if (b2 + 2 >= max) return 0; + if (part != NULL) part->body = mg_str_n(&s[b1], b2 - b1); + // MG_INFO(("Body: [%.*s]", (int) (b2 - b1), &s[b1])); + return b2 + 2; +} + +void mg_http_bauth(struct mg_connection *c, const char *user, + const char *pass) { + struct mg_str u = mg_str(user), p = mg_str(pass); + size_t need = c->send.len + 36 + (u.len + p.len) * 2; + if (c->send.size < need) mg_iobuf_resize(&c->send, need); + if (c->send.size >= need) { + size_t i, n = 0; + char *buf = (char *) &c->send.buf[c->send.len]; + memcpy(buf, "Authorization: Basic ", 21); // DON'T use mg_send! + for (i = 0; i < u.len; i++) { + n = mg_base64_update(((unsigned char *) u.buf)[i], buf + 21, n); + } + if (p.len > 0) { + n = mg_base64_update(':', buf + 21, n); + for (i = 0; i < p.len; i++) { + n = mg_base64_update(((unsigned char *) p.buf)[i], buf + 21, n); + } + } + n = mg_base64_final(buf + 21, n); + c->send.len += 21 + (size_t) n + 2; + memcpy(&c->send.buf[c->send.len - 2], "\r\n", 2); + } else { + MG_ERROR(("%lu oom %d->%d ", c->id, (int) c->send.size, (int) need)); + } +} + +struct mg_str mg_http_var(struct mg_str buf, struct mg_str name) { + struct mg_str entry, k, v, result = mg_str_n(NULL, 0); + while (mg_span(buf, &entry, &buf, '&')) { + if (mg_span(entry, &k, &v, '=') && name.len == k.len && + mg_ncasecmp(name.buf, k.buf, k.len) == 0) { + result = v; + break; + } + } + return result; +} + +int mg_http_get_var(const struct mg_str *buf, const char *name, char *dst, + size_t dst_len) { + int len; + if (dst != NULL && dst_len > 0) { + dst[0] = '\0'; // If destination buffer is valid, always nul-terminate it + } + if (dst == NULL || dst_len == 0) { + len = -2; // Bad destination + } else if (buf->buf == NULL || name == NULL || buf->len == 0) { + len = -1; // Bad source + } else { + struct mg_str v = mg_http_var(*buf, mg_str(name)); + if (v.buf == NULL) { + len = -4; // Name does not exist + } else { + len = mg_url_decode(v.buf, v.len, dst, dst_len, 1); + if (len < 0) len = -3; // Failed to decode + } + } + return len; +} + +static bool isx(int c) { + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'F'); +} + +int mg_url_decode(const char *src, size_t src_len, char *dst, size_t dst_len, + int is_form_url_encoded) { + size_t i, j; + for (i = j = 0; i < src_len && j + 1 < dst_len; i++, j++) { + if (src[i] == '%') { + // Use `i + 2 < src_len`, not `i < src_len - 2`, note small src_len + if (i + 2 < src_len && isx(src[i + 1]) && isx(src[i + 2])) { + mg_str_to_num(mg_str_n(src + i + 1, 2), 16, &dst[j], sizeof(uint8_t)); + i += 2; + } else { + return -1; + } + } else if (is_form_url_encoded && src[i] == '+') { + dst[j] = ' '; + } else { + dst[j] = src[i]; + } + } + if (j < dst_len) dst[j] = '\0'; // Null-terminate the destination + return i >= src_len && j < dst_len ? (int) j : -1; +} + +static bool isok(uint8_t c) { + return c == '\n' || c == '\r' || c >= ' '; +} + +int mg_http_get_request_len(const unsigned char *buf, size_t buf_len) { + size_t i; + for (i = 0; i < buf_len; i++) { + if (!isok(buf[i])) return -1; + if ((i > 0 && buf[i] == '\n' && buf[i - 1] == '\n') || + (i > 3 && buf[i] == '\n' && buf[i - 1] == '\r' && buf[i - 2] == '\n')) + return (int) i + 1; + } + return 0; +} +struct mg_str *mg_http_get_header(struct mg_http_message *h, const char *name) { + size_t i, n = strlen(name), max = sizeof(h->headers) / sizeof(h->headers[0]); + for (i = 0; i < max && h->headers[i].name.len > 0; i++) { + struct mg_str *k = &h->headers[i].name, *v = &h->headers[i].value; + if (n == k->len && mg_ncasecmp(k->buf, name, n) == 0) return v; + } + return NULL; +} + +// Is it a valid utf-8 continuation byte +static bool vcb(uint8_t c) { + return (c & 0xc0) == 0x80; +} + +// Get character length (valid utf-8). Used to parse method, URI, headers +static size_t clen(const char *s, const char *end) { + const unsigned char *u = (unsigned char *) s, c = *u; + long n = (long) (end - s); + if (c > ' ' && c < '~') return 1; // Usual ascii printed char + if ((c & 0xe0) == 0xc0 && n > 1 && vcb(u[1])) return 2; // 2-byte UTF8 + if ((c & 0xf0) == 0xe0 && n > 2 && vcb(u[1]) && vcb(u[2])) return 3; + if ((c & 0xf8) == 0xf0 && n > 3 && vcb(u[1]) && vcb(u[2]) && vcb(u[3])) + return 4; + return 0; +} + +// Skip until the newline. Return advanced `s`, or NULL on error +static const char *skiptorn(const char *s, const char *end, struct mg_str *v) { + v->buf = (char *) s; + while (s < end && s[0] != '\n' && s[0] != '\r') s++, v->len++; // To newline + if (s >= end || (s[0] == '\r' && s[1] != '\n')) return NULL; // Stray \r + if (s < end && s[0] == '\r') s++; // Skip \r + if (s >= end || *s++ != '\n') return NULL; // Skip \n + return s; +} + +static bool mg_http_parse_headers(const char *s, const char *end, + struct mg_http_header *h, size_t max_hdrs) { + size_t i, n; + for (i = 0; i < max_hdrs; i++) { + struct mg_str k = {NULL, 0}, v = {NULL, 0}; + if (s >= end) return false; + if (s[0] == '\n' || (s[0] == '\r' && s[1] == '\n')) break; + k.buf = (char *) s; + while (s < end && s[0] != ':' && (n = clen(s, end)) > 0) s += n, k.len += n; + if (k.len == 0) return false; // Empty name + if (s >= end || clen(s, end) == 0) return false; // Invalid UTF-8 + if (*s++ != ':') return false; // Invalid, not followed by : + // if (clen(s, end) == 0) return false; // Invalid UTF-8 + while (s < end && s[0] == ' ') s++; // Skip spaces + if ((s = skiptorn(s, end, &v)) == NULL) return false; + while (v.len > 0 && v.buf[v.len - 1] == ' ') v.len--; // Trim spaces + // MG_INFO(("--HH [%.*s] [%.*s]", (int) k.len, k.buf, (int) v.len, v.buf)); + h[i].name = k, h[i].value = v; // Success. Assign values + } + return true; +} + +int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) { + int is_response, req_len = mg_http_get_request_len((unsigned char *) s, len); + const char *end = s == NULL ? NULL : s + req_len, *qs; // Cannot add to NULL + const struct mg_str *cl; + size_t n; + + memset(hm, 0, sizeof(*hm)); + if (req_len <= 0) return req_len; + + hm->message.buf = hm->head.buf = (char *) s; + hm->body.buf = (char *) end; + hm->head.len = (size_t) req_len; + hm->message.len = hm->body.len = (size_t) -1; // Set body length to infinite + + // Parse request line + hm->method.buf = (char *) s; + while (s < end && (n = clen(s, end)) > 0) s += n, hm->method.len += n; + while (s < end && s[0] == ' ') s++; // Skip spaces + hm->uri.buf = (char *) s; + while (s < end && (n = clen(s, end)) > 0) s += n, hm->uri.len += n; + while (s < end && s[0] == ' ') s++; // Skip spaces + if ((s = skiptorn(s, end, &hm->proto)) == NULL) return false; + + // If URI contains '?' character, setup query string + if ((qs = (const char *) memchr(hm->uri.buf, '?', hm->uri.len)) != NULL) { + hm->query.buf = (char *) qs + 1; + hm->query.len = (size_t) (&hm->uri.buf[hm->uri.len] - (qs + 1)); + hm->uri.len = (size_t) (qs - hm->uri.buf); + } + + // Sanity check. Allow protocol/reason to be empty + // Do this check after hm->method.len and hm->uri.len are finalised + if (hm->method.len == 0 || hm->uri.len == 0) return -1; + + if (!mg_http_parse_headers(s, end, hm->headers, + sizeof(hm->headers) / sizeof(hm->headers[0]))) + return -1; // error when parsing + if ((cl = mg_http_get_header(hm, "Content-Length")) != NULL) { + if (mg_to_size_t(*cl, &hm->body.len) == false) return -1; + hm->message.len = (size_t) req_len + hm->body.len; + } + + // mg_http_parse() is used to parse both HTTP requests and HTTP + // responses. If HTTP response does not have Content-Length set, then + // body is read until socket is closed, i.e. body.len is infinite (~0). + // + // For HTTP requests though, according to + // http://tools.ietf.org/html/rfc7231#section-8.1.3, + // only POST and PUT methods have defined body semantics. + // Therefore, if Content-Length is not specified and methods are + // not one of PUT or POST, set body length to 0. + // + // So, if it is HTTP request, and Content-Length is not set, + // and method is not (PUT or POST) then reset body length to zero. + is_response = mg_ncasecmp(hm->method.buf, "HTTP/", 5) == 0; + if (hm->body.len == (size_t) ~0 && !is_response && + mg_strcasecmp(hm->method, mg_str("PUT")) != 0 && + mg_strcasecmp(hm->method, mg_str("POST")) != 0) { + hm->body.len = 0; + hm->message.len = (size_t) req_len; + } + + // The 204 (No content) responses also have 0 body length + if (hm->body.len == (size_t) ~0 && is_response && + mg_strcasecmp(hm->uri, mg_str("204")) == 0) { + hm->body.len = 0; + hm->message.len = (size_t) req_len; + } + if (hm->message.len < (size_t) req_len) return -1; // Overflow protection + + return req_len; +} + +static void mg_http_vprintf_chunk(struct mg_connection *c, const char *fmt, + va_list *ap) { + size_t len = c->send.len; + mg_send(c, " \r\n", 10); + mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap); + if (c->send.len >= len + 10) { + mg_snprintf((char *) c->send.buf + len, 9, "%08lx", c->send.len - len - 10); + c->send.buf[len + 8] = '\r'; + if (c->send.len == len + 10) c->is_resp = 0; // Last chunk, reset marker + } + mg_send(c, "\r\n", 2); +} + +void mg_http_printf_chunk(struct mg_connection *c, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + mg_http_vprintf_chunk(c, fmt, &ap); + va_end(ap); +} + +void mg_http_write_chunk(struct mg_connection *c, const char *buf, size_t len) { + mg_printf(c, "%lx\r\n", (unsigned long) len); + mg_send(c, buf, len); + mg_send(c, "\r\n", 2); + if (len == 0) c->is_resp = 0; +} + +// clang-format off +static const char *mg_http_status_code_str(int status_code) { + switch (status_code) { + case 100: return "Continue"; + case 101: return "Switching Protocols"; + case 102: return "Processing"; + case 200: return "OK"; + case 201: return "Created"; + case 202: return "Accepted"; + case 203: return "Non-authoritative Information"; + case 204: return "No Content"; + case 205: return "Reset Content"; + case 206: return "Partial Content"; + case 207: return "Multi-Status"; + case 208: return "Already Reported"; + case 226: return "IM Used"; + case 300: return "Multiple Choices"; + case 301: return "Moved Permanently"; + case 302: return "Found"; + case 303: return "See Other"; + case 304: return "Not Modified"; + case 305: return "Use Proxy"; + case 307: return "Temporary Redirect"; + case 308: return "Permanent Redirect"; + case 400: return "Bad Request"; + case 401: return "Unauthorized"; + case 402: return "Payment Required"; + case 403: return "Forbidden"; + case 404: return "Not Found"; + case 405: return "Method Not Allowed"; + case 406: return "Not Acceptable"; + case 407: return "Proxy Authentication Required"; + case 408: return "Request Timeout"; + case 409: return "Conflict"; + case 410: return "Gone"; + case 411: return "Length Required"; + case 412: return "Precondition Failed"; + case 413: return "Payload Too Large"; + case 414: return "Request-URI Too Long"; + case 415: return "Unsupported Media Type"; + case 416: return "Requested Range Not Satisfiable"; + case 417: return "Expectation Failed"; + case 418: return "I'm a teapot"; + case 421: return "Misdirected Request"; + case 422: return "Unprocessable Entity"; + case 423: return "Locked"; + case 424: return "Failed Dependency"; + case 426: return "Upgrade Required"; + case 428: return "Precondition Required"; + case 429: return "Too Many Requests"; + case 431: return "Request Header Fields Too Large"; + case 444: return "Connection Closed Without Response"; + case 451: return "Unavailable For Legal Reasons"; + case 499: return "Client Closed Request"; + case 500: return "Internal Server Error"; + case 501: return "Not Implemented"; + case 502: return "Bad Gateway"; + case 503: return "Service Unavailable"; + case 504: return "Gateway Timeout"; + case 505: return "HTTP Version Not Supported"; + case 506: return "Variant Also Negotiates"; + case 507: return "Insufficient Storage"; + case 508: return "Loop Detected"; + case 510: return "Not Extended"; + case 511: return "Network Authentication Required"; + case 599: return "Network Connect Timeout Error"; + default: return ""; + } +} +// clang-format on + +void mg_http_reply(struct mg_connection *c, int code, const char *headers, + const char *fmt, ...) { + va_list ap; + size_t len; + mg_printf(c, "HTTP/1.1 %d %s\r\n%sContent-Length: \r\n\r\n", code, + mg_http_status_code_str(code), headers == NULL ? "" : headers); + len = c->send.len; + va_start(ap, fmt); + mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, &ap); + va_end(ap); + if (c->send.len > 16) { + size_t n = mg_snprintf((char *) &c->send.buf[len - 15], 11, "%-10lu", + (unsigned long) (c->send.len - len)); + c->send.buf[len - 15 + n] = ' '; // Change ending 0 to space + } + c->is_resp = 0; +} + +static void http_cb(struct mg_connection *, int, void *); +static void restore_http_cb(struct mg_connection *c) { + mg_fs_close((struct mg_fd *) c->pfn_data); + c->pfn_data = NULL; + c->pfn = http_cb; + c->is_resp = 0; +} + +char *mg_http_etag(char *buf, size_t len, size_t size, time_t mtime); +char *mg_http_etag(char *buf, size_t len, size_t size, time_t mtime) { + mg_snprintf(buf, len, "\"%lld.%lld\"", (int64_t) mtime, (int64_t) size); + return buf; +} + +static void static_cb(struct mg_connection *c, int ev, void *ev_data) { + if (ev == MG_EV_WRITE || ev == MG_EV_POLL) { + struct mg_fd *fd = (struct mg_fd *) c->pfn_data; + // Read to send IO buffer directly, avoid extra on-stack buffer + size_t n, max = MG_IO_SIZE, space; + size_t *cl = (size_t *) &c->data[(sizeof(c->data) - sizeof(size_t)) / + sizeof(size_t) * sizeof(size_t)]; + if (c->send.size < max) mg_iobuf_resize(&c->send, max); + if (c->send.len >= c->send.size) return; // Rate limit + if ((space = c->send.size - c->send.len) > *cl) space = *cl; + n = fd->fs->rd(fd->fd, c->send.buf + c->send.len, space); + c->send.len += n; + *cl -= n; + if (n == 0) restore_http_cb(c); + } else if (ev == MG_EV_CLOSE) { + restore_http_cb(c); + } + (void) ev_data; +} + +// Known mime types. Keep it outside guess_content_type() function, since +// some environments don't like it defined there. +// clang-format off +#define MG_C_STR(a) { (char *) (a), sizeof(a) - 1 } +static struct mg_str s_known_types[] = { + MG_C_STR("html"), MG_C_STR("text/html; charset=utf-8"), + MG_C_STR("htm"), MG_C_STR("text/html; charset=utf-8"), + MG_C_STR("css"), MG_C_STR("text/css; charset=utf-8"), + MG_C_STR("js"), MG_C_STR("text/javascript; charset=utf-8"), + MG_C_STR("gif"), MG_C_STR("image/gif"), + MG_C_STR("png"), MG_C_STR("image/png"), + MG_C_STR("jpg"), MG_C_STR("image/jpeg"), + MG_C_STR("jpeg"), MG_C_STR("image/jpeg"), + MG_C_STR("woff"), MG_C_STR("font/woff"), + MG_C_STR("ttf"), MG_C_STR("font/ttf"), + MG_C_STR("svg"), MG_C_STR("image/svg+xml"), + MG_C_STR("txt"), MG_C_STR("text/plain; charset=utf-8"), + MG_C_STR("avi"), MG_C_STR("video/x-msvideo"), + MG_C_STR("csv"), MG_C_STR("text/csv"), + MG_C_STR("doc"), MG_C_STR("application/msword"), + MG_C_STR("exe"), MG_C_STR("application/octet-stream"), + MG_C_STR("gz"), MG_C_STR("application/gzip"), + MG_C_STR("ico"), MG_C_STR("image/x-icon"), + MG_C_STR("json"), MG_C_STR("application/json"), + MG_C_STR("mov"), MG_C_STR("video/quicktime"), + MG_C_STR("mp3"), MG_C_STR("audio/mpeg"), + MG_C_STR("mp4"), MG_C_STR("video/mp4"), + MG_C_STR("mpeg"), MG_C_STR("video/mpeg"), + MG_C_STR("pdf"), MG_C_STR("application/pdf"), + MG_C_STR("shtml"), MG_C_STR("text/html; charset=utf-8"), + MG_C_STR("tgz"), MG_C_STR("application/tar-gz"), + MG_C_STR("wav"), MG_C_STR("audio/wav"), + MG_C_STR("webp"), MG_C_STR("image/webp"), + MG_C_STR("zip"), MG_C_STR("application/zip"), + MG_C_STR("3gp"), MG_C_STR("video/3gpp"), + {0, 0}, +}; +// clang-format on + +static struct mg_str guess_content_type(struct mg_str path, const char *extra) { + struct mg_str entry, k, v, s = mg_str(extra); + size_t i = 0; + + // Shrink path to its extension only + while (i < path.len && path.buf[path.len - i - 1] != '.') i++; + path.buf += path.len - i; + path.len = i; + + // Process user-provided mime type overrides, if any + while (mg_span(s, &entry, &s, ',')) { + if (mg_span(entry, &k, &v, '=') && mg_strcmp(path, k) == 0) return v; + } + + // Process built-in mime types + for (i = 0; s_known_types[i].buf != NULL; i += 2) { + if (mg_strcmp(path, s_known_types[i]) == 0) return s_known_types[i + 1]; + } + + return mg_str("text/plain; charset=utf-8"); +} + +static int getrange(struct mg_str *s, size_t *a, size_t *b) { + size_t i, numparsed = 0; + for (i = 0; i + 6 < s->len; i++) { + struct mg_str k, v = mg_str_n(s->buf + i + 6, s->len - i - 6); + if (memcmp(&s->buf[i], "bytes=", 6) != 0) continue; + if (mg_span(v, &k, &v, '-')) { + if (mg_to_size_t(k, a)) numparsed++; + if (v.len > 0 && mg_to_size_t(v, b)) numparsed++; + } else { + if (mg_to_size_t(v, a)) numparsed++; + } + break; + } + return (int) numparsed; +} + +void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm, + const char *path, + const struct mg_http_serve_opts *opts) { + char etag[64], tmp[MG_PATH_MAX]; + struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs; + struct mg_fd *fd = NULL; + size_t size = 0; + time_t mtime = 0; + struct mg_str *inm = NULL; + struct mg_str mime = guess_content_type(mg_str(path), opts->mime_types); + bool gzip = false; + + if (path != NULL) { + // If a browser sends us "Accept-Encoding: gzip", try to open .gz first + struct mg_str *ae = mg_http_get_header(hm, "Accept-Encoding"); + if (ae != NULL) { + char *ae_ = mg_mprintf("%.*s", ae->len, ae->buf); + if (ae_ != NULL && strstr(ae_, "gzip") != NULL) { + mg_snprintf(tmp, sizeof(tmp), "%s.gz", path); + fd = mg_fs_open(fs, tmp, MG_FS_READ); + if (fd != NULL) gzip = true, path = tmp; + } + free(ae_); + } + // No luck opening .gz? Open what we've told to open + if (fd == NULL) fd = mg_fs_open(fs, path, MG_FS_READ); + } + + // Failed to open, and page404 is configured? Open it, then + if (fd == NULL && opts->page404 != NULL) { + fd = mg_fs_open(fs, opts->page404, MG_FS_READ); + path = opts->page404; + mime = guess_content_type(mg_str(path), opts->mime_types); + } + + if (fd == NULL || fs->st(path, &size, &mtime) == 0) { + mg_http_reply(c, 404, opts->extra_headers, "Not found\n"); + mg_fs_close(fd); + // NOTE: mg_http_etag() call should go first! + } else if (mg_http_etag(etag, sizeof(etag), size, mtime) != NULL && + (inm = mg_http_get_header(hm, "If-None-Match")) != NULL && + mg_strcasecmp(*inm, mg_str(etag)) == 0) { + mg_fs_close(fd); + mg_http_reply(c, 304, opts->extra_headers, ""); + } else { + int n, status = 200; + char range[100]; + size_t r1 = 0, r2 = 0, cl = size; + + // Handle Range header + struct mg_str *rh = mg_http_get_header(hm, "Range"); + range[0] = '\0'; + if (rh != NULL && (n = getrange(rh, &r1, &r2)) > 0) { + // If range is specified like "400-", set second limit to content len + if (n == 1) r2 = cl - 1; + if (r1 > r2 || r2 >= cl) { + status = 416; + cl = 0; + mg_snprintf(range, sizeof(range), "Content-Range: bytes */%lld\r\n", + (int64_t) size); + } else { + status = 206; + cl = r2 - r1 + 1; + mg_snprintf(range, sizeof(range), + "Content-Range: bytes %llu-%llu/%llu\r\n", (uint64_t) r1, + (uint64_t) (r1 + cl - 1), (uint64_t) size); + fs->sk(fd->fd, r1); + } + } + mg_printf(c, + "HTTP/1.1 %d %s\r\n" + "Content-Type: %.*s\r\n" + "Etag: %s\r\n" + "Content-Length: %llu\r\n" + "%s%s%s\r\n", + status, mg_http_status_code_str(status), (int) mime.len, mime.buf, + etag, (uint64_t) cl, gzip ? "Content-Encoding: gzip\r\n" : "", + range, opts->extra_headers ? opts->extra_headers : ""); + if (mg_strcasecmp(hm->method, mg_str("HEAD")) == 0) { + c->is_draining = 1; + c->is_resp = 0; + mg_fs_close(fd); + } else { + // Track to-be-sent content length at the end of c->data, aligned + size_t *clp = (size_t *) &c->data[(sizeof(c->data) - sizeof(size_t)) / + sizeof(size_t) * sizeof(size_t)]; + c->pfn = static_cb; + c->pfn_data = fd; + *clp = cl; + } + } +} + +struct printdirentrydata { + struct mg_connection *c; + struct mg_http_message *hm; + const struct mg_http_serve_opts *opts; + const char *dir; +}; + +#if MG_ENABLE_DIRLIST +static void printdirentry(const char *name, void *userdata) { + struct printdirentrydata *d = (struct printdirentrydata *) userdata; + struct mg_fs *fs = d->opts->fs == NULL ? &mg_fs_posix : d->opts->fs; + size_t size = 0; + time_t t = 0; + char path[MG_PATH_MAX], sz[40], mod[40]; + int flags, n = 0; + + // MG_DEBUG(("[%s] [%s]", d->dir, name)); + if (mg_snprintf(path, sizeof(path), "%s%c%s", d->dir, '/', name) > + sizeof(path)) { + MG_ERROR(("%s truncated", name)); + } else if ((flags = fs->st(path, &size, &t)) == 0) { + MG_ERROR(("%lu stat(%s): %d", d->c->id, path, errno)); + } else { + const char *slash = flags & MG_FS_DIR ? "/" : ""; + if (flags & MG_FS_DIR) { + mg_snprintf(sz, sizeof(sz), "%s", "[DIR]"); + } else { + mg_snprintf(sz, sizeof(sz), "%lld", (uint64_t) size); + } +#if defined(MG_HTTP_DIRLIST_TIME_FMT) + { + char time_str[40]; + struct tm *time_info = localtime(&t); + strftime(time_str, sizeof time_str, "%Y/%m/%d %H:%M:%S", time_info); + mg_snprintf(mod, sizeof(mod), "%s", time_str); + } +#else + mg_snprintf(mod, sizeof(mod), "%lu", (unsigned long) t); +#endif + n = (int) mg_url_encode(name, strlen(name), path, sizeof(path)); + mg_printf(d->c, + " %s%s" + "%s%s\n", + n, path, slash, name, slash, (unsigned long) t, mod, + flags & MG_FS_DIR ? (int64_t) -1 : (int64_t) size, sz); + } +} + +static void listdir(struct mg_connection *c, struct mg_http_message *hm, + const struct mg_http_serve_opts *opts, char *dir) { + const char *sort_js_code = + ""; + struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs; + struct printdirentrydata d = {c, hm, opts, dir}; + char tmp[10], buf[MG_PATH_MAX]; + size_t off, n; + int len = mg_url_decode(hm->uri.buf, hm->uri.len, buf, sizeof(buf), 0); + struct mg_str uri = len > 0 ? mg_str_n(buf, (size_t) len) : hm->uri; + + mg_printf(c, + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html; charset=utf-8\r\n" + "%s" + "Content-Length: \r\n\r\n", + opts->extra_headers == NULL ? "" : opts->extra_headers); + off = c->send.len; // Start of body + mg_printf(c, + "Index of %.*s%s%s" + "" + "

Index of %.*s

" + "" + "" + "" + "" + "\n", + (int) uri.len, uri.buf, sort_js_code, sort_js_code2, (int) uri.len, + uri.buf); + mg_printf(c, "%s", + " " + "\n"); + + fs->ls(dir, printdirentry, &d); + mg_printf(c, + "" + "
Name" + "ModifiedSize

..[DIR]

Mongoose v.%s
\n", + MG_VERSION); + n = mg_snprintf(tmp, sizeof(tmp), "%lu", (unsigned long) (c->send.len - off)); + if (n > sizeof(tmp)) n = 0; + memcpy(c->send.buf + off - 12, tmp, n); // Set content length + c->is_resp = 0; // Mark response end +} +#endif + +// Resolve requested file into `path` and return its fs->st() result +static int uri_to_path2(struct mg_connection *c, struct mg_http_message *hm, + struct mg_fs *fs, struct mg_str url, struct mg_str dir, + char *path, size_t path_size) { + int flags, tmp; + // Append URI to the root_dir, and sanitize it + size_t n = mg_snprintf(path, path_size, "%.*s", (int) dir.len, dir.buf); + if (n + 2 >= path_size) { + mg_http_reply(c, 400, "", "Exceeded path size"); + return -1; + } + path[path_size - 1] = '\0'; + // Terminate root dir with slash + if (n > 0 && path[n - 1] != '/') path[n++] = '/', path[n] = '\0'; + if (url.len < hm->uri.len) { + mg_url_decode(hm->uri.buf + url.len, hm->uri.len - url.len, path + n, + path_size - n, 0); + } + path[path_size - 1] = '\0'; // Double-check + if (!mg_path_is_sane(mg_str_n(path, path_size))) { + mg_http_reply(c, 400, "", "Invalid path"); + return -1; + } + n = strlen(path); + while (n > 1 && path[n - 1] == '/') path[--n] = 0; // Trim trailing slashes + flags = mg_strcmp(hm->uri, mg_str("/")) == 0 ? MG_FS_DIR + : fs->st(path, NULL, NULL); + MG_VERBOSE(("%lu %.*s -> %s %d", c->id, (int) hm->uri.len, hm->uri.buf, path, + flags)); + if (flags == 0) { + // Do nothing - let's caller decide + } else if ((flags & MG_FS_DIR) && hm->uri.len > 0 && + hm->uri.buf[hm->uri.len - 1] != '/') { + mg_printf(c, + "HTTP/1.1 301 Moved\r\n" + "Location: %.*s/\r\n" + "Content-Length: 0\r\n" "\r\n", - (int) hm->uri.len, hm->uri.ptr); + (int) hm->uri.len, hm->uri.buf); c->is_resp = 0; flags = -1; } else if (flags & MG_FS_DIR) { @@ -2057,3318 +3036,11754 @@ static int uri_to_path2(struct mg_connection *c, struct mg_http_message *hm, path[n + 1 + strlen(MG_HTTP_INDEX)] = '\0'; // Remove appended .gz in index file name } else { - path[n] = '\0'; // Remove appended index file name + path[n] = '\0'; // Remove appended index file name + } + } + return flags; +} + +static int uri_to_path(struct mg_connection *c, struct mg_http_message *hm, + const struct mg_http_serve_opts *opts, char *path, + size_t path_size) { + struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs; + struct mg_str k, v, part, s = mg_str(opts->root_dir), u = {NULL, 0}, p = u; + while (mg_span(s, &part, &s, ',')) { + if (!mg_span(part, &k, &v, '=')) k = part, v = mg_str_n(NULL, 0); + if (v.len == 0) v = k, k = mg_str("/"), u = k, p = v; + if (hm->uri.len < k.len) continue; + if (mg_strcmp(k, mg_str_n(hm->uri.buf, k.len)) != 0) continue; + u = k, p = v; + } + return uri_to_path2(c, hm, fs, u, p, path, path_size); +} + +void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm, + const struct mg_http_serve_opts *opts) { + char path[MG_PATH_MAX]; + const char *sp = opts->ssi_pattern; + int flags = uri_to_path(c, hm, opts, path, sizeof(path)); + if (flags < 0) { + // Do nothing: the response has already been sent by uri_to_path() + } else if (flags & MG_FS_DIR) { +#if MG_ENABLE_DIRLIST + listdir(c, hm, opts, path); +#else + mg_http_reply(c, 403, "", "Forbidden\n"); +#endif + } else if (flags && sp != NULL && mg_match(mg_str(path), mg_str(sp), NULL)) { + mg_http_serve_ssi(c, opts->root_dir, path); + } else { + mg_http_serve_file(c, hm, path, opts); + } +} + +static bool mg_is_url_safe(int c) { + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || c == '.' || c == '_' || c == '-' || c == '~'; +} + +size_t mg_url_encode(const char *s, size_t sl, char *buf, size_t len) { + size_t i, n = 0; + for (i = 0; i < sl; i++) { + int c = *(unsigned char *) &s[i]; + if (n + 4 >= len) return 0; + if (mg_is_url_safe(c)) { + buf[n++] = s[i]; + } else { + mg_snprintf(&buf[n], 4, "%%%M", mg_print_hex, 1, &s[i]); + n += 3; + } + } + if (len > 0 && n < len - 1) buf[n] = '\0'; // Null-terminate the destination + if (len > 0) buf[len - 1] = '\0'; // Always. + return n; +} + +void mg_http_creds(struct mg_http_message *hm, char *user, size_t userlen, + char *pass, size_t passlen) { + struct mg_str *v = mg_http_get_header(hm, "Authorization"); + user[0] = pass[0] = '\0'; + if (v != NULL && v->len > 6 && memcmp(v->buf, "Basic ", 6) == 0) { + char buf[256]; + size_t n = mg_base64_decode(v->buf + 6, v->len - 6, buf, sizeof(buf)); + const char *p = (const char *) memchr(buf, ':', n > 0 ? n : 0); + if (p != NULL) { + mg_snprintf(user, userlen, "%.*s", p - buf, buf); + mg_snprintf(pass, passlen, "%.*s", n - (size_t) (p - buf) - 1, p + 1); + } + } else if (v != NULL && v->len > 7 && memcmp(v->buf, "Bearer ", 7) == 0) { + mg_snprintf(pass, passlen, "%.*s", (int) v->len - 7, v->buf + 7); + } else if ((v = mg_http_get_header(hm, "Cookie")) != NULL) { + struct mg_str t = mg_http_get_header_var(*v, mg_str_n("access_token", 12)); + if (t.len > 0) mg_snprintf(pass, passlen, "%.*s", (int) t.len, t.buf); + } else { + mg_http_get_var(&hm->query, "access_token", pass, passlen); + } +} + +static struct mg_str stripquotes(struct mg_str s) { + return s.len > 1 && s.buf[0] == '"' && s.buf[s.len - 1] == '"' + ? mg_str_n(s.buf + 1, s.len - 2) + : s; +} + +struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v) { + size_t i; + for (i = 0; v.len > 0 && i + v.len + 2 < s.len; i++) { + if (s.buf[i + v.len] == '=' && memcmp(&s.buf[i], v.buf, v.len) == 0) { + const char *p = &s.buf[i + v.len + 1], *b = p, *x = &s.buf[s.len]; + int q = p < x && *p == '"' ? 1 : 0; + while (p < x && + (q ? p == b || *p != '"' : *p != ';' && *p != ' ' && *p != ',')) + p++; + // MG_INFO(("[%.*s] [%.*s] [%.*s]", (int) s.len, s.buf, (int) v.len, + // v.buf, (int) (p - b), b)); + return stripquotes(mg_str_n(b, (size_t) (p - b + q))); + } + } + return mg_str_n(NULL, 0); +} + +long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm, + struct mg_fs *fs, const char *dir, size_t max_size) { + char buf[20] = "0", file[MG_PATH_MAX], path[MG_PATH_MAX]; + long res = 0, offset; + mg_http_get_var(&hm->query, "offset", buf, sizeof(buf)); + mg_http_get_var(&hm->query, "file", file, sizeof(file)); + offset = strtol(buf, NULL, 0); + mg_snprintf(path, sizeof(path), "%s%c%s", dir, MG_DIRSEP, file); + if (hm->body.len == 0) { + mg_http_reply(c, 200, "", "%ld", res); // Nothing to write + } else if (file[0] == '\0') { + mg_http_reply(c, 400, "", "file required"); + res = -1; + } else if (mg_path_is_sane(mg_str(file)) == false) { + mg_http_reply(c, 400, "", "%s: invalid file", file); + res = -2; + } else if (offset < 0) { + mg_http_reply(c, 400, "", "offset required"); + res = -3; + } else if ((size_t) offset + hm->body.len > max_size) { + mg_http_reply(c, 400, "", "%s: over max size of %lu", path, + (unsigned long) max_size); + res = -4; + } else { + struct mg_fd *fd; + size_t current_size = 0; + MG_DEBUG(("%s -> %lu bytes @ %ld", path, hm->body.len, offset)); + if (offset == 0) fs->rm(path); // If offset if 0, truncate file + fs->st(path, ¤t_size, NULL); + if (offset > 0 && current_size != (size_t) offset) { + mg_http_reply(c, 400, "", "%s: offset mismatch", path); + res = -5; + } else if ((fd = mg_fs_open(fs, path, MG_FS_WRITE)) == NULL) { + mg_http_reply(c, 400, "", "open(%s): %d", path, errno); + res = -6; + } else { + res = offset + (long) fs->wr(fd->fd, hm->body.buf, hm->body.len); + mg_fs_close(fd); + mg_http_reply(c, 200, "", "%ld", res); + } + } + return res; +} + +int mg_http_status(const struct mg_http_message *hm) { + return atoi(hm->uri.buf); +} + +static bool is_hex_digit(int c) { + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'F'); +} + +static int skip_chunk(const char *buf, int len, int *pl, int *dl) { + int i = 0, n = 0; + if (len < 3) return 0; + while (i < len && is_hex_digit(buf[i])) i++; + if (i == 0) return -1; // Error, no length specified + if (i > (int) sizeof(int) * 2) return -1; // Chunk length is too big + if (len < i + 1 || buf[i] != '\r' || buf[i + 1] != '\n') return -1; // Error + if (mg_str_to_num(mg_str_n(buf, (size_t) i), 16, &n, sizeof(int)) == false) + return -1; // Decode chunk length, overflow + if (n < 0) return -1; // Error. TODO(): some checks now redundant + if (n > len - i - 4) return 0; // Chunk not yet fully buffered + if (buf[i + n + 2] != '\r' || buf[i + n + 3] != '\n') return -1; // Error + *pl = i + 2, *dl = n; + return i + 2 + n + 2; +} + +static void http_cb(struct mg_connection *c, int ev, void *ev_data) { + if (ev == MG_EV_READ || ev == MG_EV_CLOSE) { + struct mg_http_message hm; + size_t ofs = 0; // Parsing offset + while (c->is_resp == 0 && ofs < c->recv.len) { + const char *buf = (char *) c->recv.buf + ofs; + int n = mg_http_parse(buf, c->recv.len - ofs, &hm); + struct mg_str *te; // Transfer - encoding header + bool is_chunked = false; + if (n < 0) { + // We don't use mg_error() here, to avoid closing pipelined requests + // prematurely, see #2592 + MG_ERROR(("HTTP parse, %lu bytes", c->recv.len)); + c->is_draining = 1; + mg_hexdump(buf, c->recv.len - ofs > 16 ? 16 : c->recv.len - ofs); + c->recv.len = 0; + return; + } + if (n == 0) break; // Request is not buffered yet + mg_call(c, MG_EV_HTTP_HDRS, &hm); // Got all HTTP headers + if (ev == MG_EV_CLOSE) { // If client did not set Content-Length + hm.message.len = c->recv.len - ofs; // and closes now, deliver MSG + hm.body.len = hm.message.len - (size_t) (hm.body.buf - hm.message.buf); + } + if ((te = mg_http_get_header(&hm, "Transfer-Encoding")) != NULL) { + if (mg_strcasecmp(*te, mg_str("chunked")) == 0) { + is_chunked = true; + } else { + mg_error(c, "Invalid Transfer-Encoding"); // See #2460 + return; + } + } else if (mg_http_get_header(&hm, "Content-length") == NULL) { + // #2593: HTTP packets must contain either Transfer-Encoding or + // Content-length + bool is_response = mg_ncasecmp(hm.method.buf, "HTTP/", 5) == 0; + bool require_content_len = false; + if (!is_response && (mg_strcasecmp(hm.method, mg_str("POST")) == 0 || + mg_strcasecmp(hm.method, mg_str("PUT")) == 0)) { + // POST and PUT should include an entity body. Therefore, they should + // contain a Content-length header. Other requests can also contain a + // body, but their content has no defined semantics (RFC 7231) + require_content_len = true; + } else if (is_response) { + // HTTP spec 7.2 Entity body: All other responses must include a body + // or Content-Length header field defined with a value of 0. + int status = mg_http_status(&hm); + require_content_len = status >= 200 && status != 204 && status != 304; + } + if (require_content_len) { + mg_http_reply(c, 411, "", ""); + MG_ERROR(("%s", "Content length missing from request")); + } + } + + if (is_chunked) { + // For chunked data, strip off prefixes and suffixes from chunks + // and relocate them right after the headers, then report a message + char *s = (char *) c->recv.buf + ofs + n; + int o = 0, pl, dl, cl, len = (int) (c->recv.len - ofs - (size_t) n); + + // Find zero-length chunk (the end of the body) + while ((cl = skip_chunk(s + o, len - o, &pl, &dl)) > 0 && dl) o += cl; + if (cl == 0) break; // No zero-len chunk, buffer more data + if (cl < 0) { + mg_error(c, "Invalid chunk"); + break; + } + + // Zero chunk found. Second pass: strip + relocate + o = 0, hm.body.len = 0, hm.message.len = (size_t) n; + while ((cl = skip_chunk(s + o, len - o, &pl, &dl)) > 0) { + memmove(s + hm.body.len, s + o + pl, (size_t) dl); + o += cl, hm.body.len += (size_t) dl, hm.message.len += (size_t) dl; + if (dl == 0) break; + } + ofs += (size_t) (n + o); + } else { // Normal, non-chunked data + size_t len = c->recv.len - ofs - (size_t) n; + if (hm.body.len > len) break; // Buffer more data + ofs += (size_t) n + hm.body.len; + } + + if (c->is_accepted) c->is_resp = 1; // Start generating response + mg_call(c, MG_EV_HTTP_MSG, &hm); // User handler can clear is_resp + } + if (ofs > 0) mg_iobuf_del(&c->recv, 0, ofs); // Delete processed data + } + (void) ev_data; +} + +static void mg_hfn(struct mg_connection *c, int ev, void *ev_data) { + if (ev == MG_EV_HTTP_MSG) { + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + if (mg_match(hm->uri, mg_str("/quit"), NULL)) { + mg_http_reply(c, 200, "", "ok\n"); + c->is_draining = 1; + c->data[0] = 'X'; + } else if (mg_match(hm->uri, mg_str("/debug"), NULL)) { + int level = (int) mg_json_get_long(hm->body, "$.level", MG_LL_DEBUG); + mg_log_set(level); + mg_http_reply(c, 200, "", "Debug level set to %d\n", level); + } else { + mg_http_reply(c, 200, "", "hi\n"); + } + } else if (ev == MG_EV_CLOSE) { + if (c->data[0] == 'X') *(bool *) c->fn_data = true; + } +} + +void mg_hello(const char *url) { + struct mg_mgr mgr; + bool done = false; + mg_mgr_init(&mgr); + if (mg_http_listen(&mgr, url, mg_hfn, &done) == NULL) done = true; + while (done == false) mg_mgr_poll(&mgr, 100); + mg_mgr_free(&mgr); +} + +struct mg_connection *mg_http_connect(struct mg_mgr *mgr, const char *url, + mg_event_handler_t fn, void *fn_data) { + struct mg_connection *c = mg_connect(mgr, url, fn, fn_data); + if (c != NULL) c->pfn = http_cb; + return c; +} + +struct mg_connection *mg_http_listen(struct mg_mgr *mgr, const char *url, + mg_event_handler_t fn, void *fn_data) { + struct mg_connection *c = mg_listen(mgr, url, fn, fn_data); + if (c != NULL) c->pfn = http_cb; + return c; +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/iobuf.c" +#endif + + + + + +static size_t roundup(size_t size, size_t align) { + return align == 0 ? size : (size + align - 1) / align * align; +} + +int mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) { + int ok = 1; + new_size = roundup(new_size, io->align); + if (new_size == 0) { + mg_bzero(io->buf, io->size); + free(io->buf); + io->buf = NULL; + io->len = io->size = 0; + } else if (new_size != io->size) { + // NOTE(lsm): do not use realloc here. Use calloc/free only, to ease the + // porting to some obscure platforms like FreeRTOS + void *p = calloc(1, new_size); + if (p != NULL) { + size_t len = new_size < io->len ? new_size : io->len; + if (len > 0 && io->buf != NULL) memmove(p, io->buf, len); + mg_bzero(io->buf, io->size); + free(io->buf); + io->buf = (unsigned char *) p; + io->size = new_size; + } else { + ok = 0; + MG_ERROR(("%lld->%lld", (uint64_t) io->size, (uint64_t) new_size)); + } + } + return ok; +} + +int mg_iobuf_init(struct mg_iobuf *io, size_t size, size_t align) { + io->buf = NULL; + io->align = align; + io->size = io->len = 0; + return mg_iobuf_resize(io, size); +} + +size_t mg_iobuf_add(struct mg_iobuf *io, size_t ofs, const void *buf, + size_t len) { + size_t new_size = roundup(io->len + len, io->align); + mg_iobuf_resize(io, new_size); // Attempt to resize + if (new_size != io->size) len = 0; // Resize failure, append nothing + if (ofs < io->len) memmove(io->buf + ofs + len, io->buf + ofs, io->len - ofs); + if (buf != NULL) memmove(io->buf + ofs, buf, len); + if (ofs > io->len) io->len += ofs - io->len; + io->len += len; + return len; +} + +size_t mg_iobuf_del(struct mg_iobuf *io, size_t ofs, size_t len) { + if (ofs > io->len) ofs = io->len; + if (ofs + len > io->len) len = io->len - ofs; + if (io->buf) memmove(io->buf + ofs, io->buf + ofs + len, io->len - ofs - len); + if (io->buf) mg_bzero(io->buf + io->len - len, len); + io->len -= len; + return len; +} + +void mg_iobuf_free(struct mg_iobuf *io) { + mg_iobuf_resize(io, 0); +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/json.c" +#endif + + + + +static const char *escapeseq(int esc) { + return esc ? "\b\f\n\r\t\\\"" : "bfnrt\\\""; +} + +static char json_esc(int c, int esc) { + const char *p, *esc1 = escapeseq(esc), *esc2 = escapeseq(!esc); + for (p = esc1; *p != '\0'; p++) { + if (*p == c) return esc2[p - esc1]; + } + return 0; +} + +static int mg_pass_string(const char *s, int len) { + int i; + for (i = 0; i < len; i++) { + if (s[i] == '\\' && i + 1 < len && json_esc(s[i + 1], 1)) { + i++; + } else if (s[i] == '\0') { + return MG_JSON_INVALID; + } else if (s[i] == '"') { + return i; + } + } + return MG_JSON_INVALID; +} + +static double mg_atod(const char *p, int len, int *numlen) { + double d = 0.0; + int i = 0, sign = 1; + + // Sign + if (i < len && *p == '-') { + sign = -1, i++; + } else if (i < len && *p == '+') { + i++; + } + + // Decimal + for (; i < len && p[i] >= '0' && p[i] <= '9'; i++) { + d *= 10.0; + d += p[i] - '0'; + } + d *= sign; + + // Fractional + if (i < len && p[i] == '.') { + double frac = 0.0, base = 0.1; + i++; + for (; i < len && p[i] >= '0' && p[i] <= '9'; i++) { + frac += base * (p[i] - '0'); + base /= 10.0; + } + d += frac * sign; + } + + // Exponential + if (i < len && (p[i] == 'e' || p[i] == 'E')) { + int j, exp = 0, minus = 0; + i++; + if (i < len && p[i] == '-') minus = 1, i++; + if (i < len && p[i] == '+') i++; + while (i < len && p[i] >= '0' && p[i] <= '9' && exp < 308) + exp = exp * 10 + (p[i++] - '0'); + if (minus) exp = -exp; + for (j = 0; j < exp; j++) d *= 10.0; + for (j = 0; j < -exp; j++) d /= 10.0; + } + + if (numlen != NULL) *numlen = i; + return d; +} + +// Iterate over object or array elements +size_t mg_json_next(struct mg_str obj, size_t ofs, struct mg_str *key, + struct mg_str *val) { + if (ofs >= obj.len) { + ofs = 0; // Out of boundaries, stop scanning + } else if (obj.len < 2 || (*obj.buf != '{' && *obj.buf != '[')) { + ofs = 0; // Not an array or object, stop + } else { + struct mg_str sub = mg_str_n(obj.buf + ofs, obj.len - ofs); + if (ofs == 0) ofs++, sub.buf++, sub.len--; + if (*obj.buf == '[') { // Iterate over an array + int n = 0, o = mg_json_get(sub, "$", &n); + if (n < 0 || o < 0 || (size_t) (o + n) > sub.len) { + ofs = 0; // Error parsing key, stop scanning + } else { + if (key) *key = mg_str_n(NULL, 0); + if (val) *val = mg_str_n(sub.buf + o, (size_t) n); + ofs = (size_t) (&sub.buf[o + n] - obj.buf); + } + } else { // Iterate over an object + int n = 0, o = mg_json_get(sub, "$", &n); + if (n < 0 || o < 0 || (size_t) (o + n) > sub.len) { + ofs = 0; // Error parsing key, stop scanning + } else { + if (key) *key = mg_str_n(sub.buf + o, (size_t) n); + sub.buf += o + n, sub.len -= (size_t) (o + n); + while (sub.len > 0 && *sub.buf != ':') sub.len--, sub.buf++; + if (sub.len > 0 && *sub.buf == ':') sub.len--, sub.buf++; + n = 0, o = mg_json_get(sub, "$", &n); + if (n < 0 || o < 0 || (size_t) (o + n) > sub.len) { + ofs = 0; // Error parsing value, stop scanning + } else { + if (val) *val = mg_str_n(sub.buf + o, (size_t) n); + ofs = (size_t) (&sub.buf[o + n] - obj.buf); + } + } + } + // MG_INFO(("SUB ofs %u %.*s", ofs, sub.len, sub.buf)); + while (ofs && ofs < obj.len && + (obj.buf[ofs] == ' ' || obj.buf[ofs] == '\t' || + obj.buf[ofs] == '\n' || obj.buf[ofs] == '\r')) { + ofs++; + } + if (ofs && ofs < obj.len && obj.buf[ofs] == ',') ofs++; + if (ofs > obj.len) ofs = 0; + } + return ofs; +} + +int mg_json_get(struct mg_str json, const char *path, int *toklen) { + const char *s = json.buf; + int len = (int) json.len; + enum { S_VALUE, S_KEY, S_COLON, S_COMMA_OR_EOO } expecting = S_VALUE; + unsigned char nesting[MG_JSON_MAX_DEPTH]; + int i = 0; // Current offset in `s` + int j = 0; // Offset in `s` we're looking for (return value) + int depth = 0; // Current depth (nesting level) + int ed = 0; // Expected depth + int pos = 1; // Current position in `path` + int ci = -1, ei = -1; // Current and expected index in array + + if (toklen) *toklen = 0; + if (path[0] != '$') return MG_JSON_INVALID; + +#define MG_CHECKRET(x) \ + do { \ + if (depth == ed && path[pos] == '\0' && ci == ei) { \ + if (toklen) *toklen = i - j + 1; \ + return j; \ + } \ + } while (0) + +// In the ascii table, the distance between `[` and `]` is 2. +// Ditto for `{` and `}`. Hence +2 in the code below. +#define MG_EOO(x) \ + do { \ + if (depth == ed && ci != ei) return MG_JSON_NOT_FOUND; \ + if (c != nesting[depth - 1] + 2) return MG_JSON_INVALID; \ + depth--; \ + MG_CHECKRET(x); \ + } while (0) + + for (i = 0; i < len; i++) { + unsigned char c = ((unsigned char *) s)[i]; + if (c == ' ' || c == '\t' || c == '\n' || c == '\r') continue; + switch (expecting) { + case S_VALUE: + // p("V %s [%.*s] %d %d %d %d\n", path, pos, path, depth, ed, ci, ei); + if (depth == ed) j = i; + if (c == '{') { + if (depth >= (int) sizeof(nesting)) return MG_JSON_TOO_DEEP; + if (depth == ed && path[pos] == '.' && ci == ei) { + // If we start the object, reset array indices + ed++, pos++, ci = ei = -1; + } + nesting[depth++] = c; + expecting = S_KEY; + break; + } else if (c == '[') { + if (depth >= (int) sizeof(nesting)) return MG_JSON_TOO_DEEP; + if (depth == ed && path[pos] == '[' && ei == ci) { + ed++, pos++, ci = 0; + for (ei = 0; path[pos] != ']' && path[pos] != '\0'; pos++) { + ei *= 10; + ei += path[pos] - '0'; + } + if (path[pos] != 0) pos++; + } + nesting[depth++] = c; + break; + } else if (c == ']' && depth > 0) { // Empty array + MG_EOO(']'); + } else if (c == 't' && i + 3 < len && memcmp(&s[i], "true", 4) == 0) { + i += 3; + } else if (c == 'n' && i + 3 < len && memcmp(&s[i], "null", 4) == 0) { + i += 3; + } else if (c == 'f' && i + 4 < len && memcmp(&s[i], "false", 5) == 0) { + i += 4; + } else if (c == '-' || ((c >= '0' && c <= '9'))) { + int numlen = 0; + mg_atod(&s[i], len - i, &numlen); + i += numlen - 1; + } else if (c == '"') { + int n = mg_pass_string(&s[i + 1], len - i - 1); + if (n < 0) return n; + i += n + 1; + } else { + return MG_JSON_INVALID; + } + MG_CHECKRET('V'); + if (depth == ed && ei >= 0) ci++; + expecting = S_COMMA_OR_EOO; + break; + + case S_KEY: + if (c == '"') { + int n = mg_pass_string(&s[i + 1], len - i - 1); + if (n < 0) return n; + if (i + 1 + n >= len) return MG_JSON_NOT_FOUND; + if (depth < ed) return MG_JSON_NOT_FOUND; + if (depth == ed && path[pos - 1] != '.') return MG_JSON_NOT_FOUND; + // printf("K %s [%.*s] [%.*s] %d %d %d %d %d\n", path, pos, path, n, + // &s[i + 1], n, depth, ed, ci, ei); + // NOTE(cpq): in the check sequence below is important. + // strncmp() must go first: it fails fast if the remaining length + // of the path is smaller than `n`. + if (depth == ed && path[pos - 1] == '.' && + strncmp(&s[i + 1], &path[pos], (size_t) n) == 0 && + (path[pos + n] == '\0' || path[pos + n] == '.' || + path[pos + n] == '[')) { + pos += n; + } + i += n + 1; + expecting = S_COLON; + } else if (c == '}') { // Empty object + MG_EOO('}'); + expecting = S_COMMA_OR_EOO; + if (depth == ed && ei >= 0) ci++; + } else { + return MG_JSON_INVALID; + } + break; + + case S_COLON: + if (c == ':') { + expecting = S_VALUE; + } else { + return MG_JSON_INVALID; + } + break; + + case S_COMMA_OR_EOO: + if (depth <= 0) { + return MG_JSON_INVALID; + } else if (c == ',') { + expecting = (nesting[depth - 1] == '{') ? S_KEY : S_VALUE; + } else if (c == ']' || c == '}') { + if (depth == ed && c == '}' && path[pos - 1] == '.') + return MG_JSON_NOT_FOUND; + if (depth == ed && c == ']' && path[pos - 1] == ',') + return MG_JSON_NOT_FOUND; + MG_EOO('O'); + if (depth == ed && ei >= 0) ci++; + } else { + return MG_JSON_INVALID; + } + break; + } + } + return MG_JSON_NOT_FOUND; +} + +struct mg_str mg_json_get_tok(struct mg_str json, const char *path) { + int len = 0, ofs = mg_json_get(json, path, &len); + return mg_str_n(ofs < 0 ? NULL : json.buf + ofs, + (size_t) (len < 0 ? 0 : len)); +} + +bool mg_json_get_num(struct mg_str json, const char *path, double *v) { + int n, toklen, found = 0; + if ((n = mg_json_get(json, path, &toklen)) >= 0 && + (json.buf[n] == '-' || (json.buf[n] >= '0' && json.buf[n] <= '9'))) { + if (v != NULL) *v = mg_atod(json.buf + n, toklen, NULL); + found = 1; + } + return found; +} + +bool mg_json_get_bool(struct mg_str json, const char *path, bool *v) { + int found = 0, off = mg_json_get(json, path, NULL); + if (off >= 0 && (json.buf[off] == 't' || json.buf[off] == 'f')) { + if (v != NULL) *v = json.buf[off] == 't'; + found = 1; + } + return found; +} + +bool mg_json_unescape(struct mg_str s, char *to, size_t n) { + size_t i, j; + for (i = 0, j = 0; i < s.len && j < n; i++, j++) { + if (s.buf[i] == '\\' && i + 5 < s.len && s.buf[i + 1] == 'u') { + // \uXXXX escape. We process simple one-byte chars \u00xx within ASCII + // range. More complex chars would require dragging in a UTF8 library, + // which is too much for us + if (mg_str_to_num(mg_str_n(s.buf + i + 2, 4), 16, &to[j], + sizeof(uint8_t)) == false) + return false; + i += 5; + } else if (s.buf[i] == '\\' && i + 1 < s.len) { + char c = json_esc(s.buf[i + 1], 0); + if (c == 0) return false; + to[j] = c; + i++; + } else { + to[j] = s.buf[i]; + } + } + if (j >= n) return false; + if (n > 0) to[j] = '\0'; + return true; +} + +char *mg_json_get_str(struct mg_str json, const char *path) { + char *result = NULL; + int len = 0, off = mg_json_get(json, path, &len); + if (off >= 0 && len > 1 && json.buf[off] == '"') { + if ((result = (char *) calloc(1, (size_t) len)) != NULL && + !mg_json_unescape(mg_str_n(json.buf + off + 1, (size_t) (len - 2)), + result, (size_t) len)) { + free(result); + result = NULL; + } + } + return result; +} + +char *mg_json_get_b64(struct mg_str json, const char *path, int *slen) { + char *result = NULL; + int len = 0, off = mg_json_get(json, path, &len); + if (off >= 0 && json.buf[off] == '"' && len > 1 && + (result = (char *) calloc(1, (size_t) len)) != NULL) { + size_t k = mg_base64_decode(json.buf + off + 1, (size_t) (len - 2), result, + (size_t) len); + if (slen != NULL) *slen = (int) k; + } + return result; +} + +char *mg_json_get_hex(struct mg_str json, const char *path, int *slen) { + char *result = NULL; + int len = 0, off = mg_json_get(json, path, &len); + if (off >= 0 && json.buf[off] == '"' && len > 1 && + (result = (char *) calloc(1, (size_t) len / 2)) != NULL) { + int i; + for (i = 0; i < len - 2; i += 2) { + mg_str_to_num(mg_str_n(json.buf + off + 1 + i, 2), 16, &result[i >> 1], + sizeof(uint8_t)); + } + result[len / 2 - 1] = '\0'; + if (slen != NULL) *slen = len / 2 - 1; + } + return result; +} + +long mg_json_get_long(struct mg_str json, const char *path, long dflt) { + double dv; + long result = dflt; + if (mg_json_get_num(json, path, &dv)) result = (long) dv; + return result; +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/log.c" +#endif + + + + + +int mg_log_level = MG_LL_INFO; +static mg_pfn_t s_log_func = mg_pfn_stdout; +static void *s_log_func_param = NULL; + +void mg_log_set_fn(mg_pfn_t fn, void *param) { + s_log_func = fn; + s_log_func_param = param; +} + +static void logc(unsigned char c) { + s_log_func((char) c, s_log_func_param); +} + +static void logs(const char *buf, size_t len) { + size_t i; + for (i = 0; i < len; i++) logc(((unsigned char *) buf)[i]); +} + +#if MG_ENABLE_CUSTOM_LOG +// Let user define their own mg_log_prefix() and mg_log() +#else +void mg_log_prefix(int level, const char *file, int line, const char *fname) { + const char *p = strrchr(file, '/'); + char buf[41]; + size_t n; + if (p == NULL) p = strrchr(file, '\\'); + n = mg_snprintf(buf, sizeof(buf), "%-6llx %d %s:%d:%s", mg_millis(), level, + p == NULL ? file : p + 1, line, fname); + if (n > sizeof(buf) - 2) n = sizeof(buf) - 2; + while (n < sizeof(buf)) buf[n++] = ' '; + logs(buf, n - 1); +} + +void mg_log(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + mg_vxprintf(s_log_func, s_log_func_param, fmt, &ap); + va_end(ap); + logs("\r\n", 2); +} +#endif + +static unsigned char nibble(unsigned c) { + return (unsigned char) (c < 10 ? c + '0' : c + 'W'); +} + +#define ISPRINT(x) ((x) >= ' ' && (x) <= '~') +void mg_hexdump(const void *buf, size_t len) { + const unsigned char *p = (const unsigned char *) buf; + unsigned char ascii[16], alen = 0; + size_t i; + for (i = 0; i < len; i++) { + if ((i % 16) == 0) { + // Print buffered ascii chars + if (i > 0) logs(" ", 2), logs((char *) ascii, 16), logc('\n'), alen = 0; + // Print hex address, then \t + logc(nibble((i >> 12) & 15)), logc(nibble((i >> 8) & 15)), + logc(nibble((i >> 4) & 15)), logc('0'), logs(" ", 3); + } + logc(nibble(p[i] >> 4)), logc(nibble(p[i] & 15)); // Two nibbles, e.g. c5 + logc(' '); // Space after hex number + ascii[alen++] = ISPRINT(p[i]) ? p[i] : '.'; // Add to the ascii buf + } + while (alen < 16) logs(" ", 3), ascii[alen++] = ' '; + logs(" ", 2), logs((char *) ascii, 16), logc('\n'); +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/md5.c" +#endif + + + +// This code implements the MD5 message-digest algorithm. +// The algorithm is due to Ron Rivest. This code was +// written by Colin Plumb in 1993, no copyright is claimed. +// This code is in the public domain; do with it what you wish. +// +// Equivalent code is available from RSA Data Security, Inc. +// This code has been tested against that, and is equivalent, +// except that you don't need to include two pages of legalese +// with every copy. +// +// To compute the message digest of a chunk of bytes, declare an +// MD5Context structure, pass it to MD5Init, call MD5Update as +// needed on buffers full of bytes, and then call MD5Final, which +// will fill a supplied 16-byte array with the digest. + +#if defined(MG_ENABLE_MD5) && MG_ENABLE_MD5 + +static void mg_byte_reverse(unsigned char *buf, unsigned longs) { + if (MG_BIG_ENDIAN) { + do { + uint32_t t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(uint32_t *) buf = t; + buf += 4; + } while (--longs); + } else { + (void) buf, (void) longs; // Little endian. Do nothing + } +} + +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +#define MD5STEP(f, w, x, y, z, data, s) \ + (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x) + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void mg_md5_init(mg_md5_ctx *ctx) { + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +static void mg_md5_transform(uint32_t buf[4], uint32_t const in[16]) { + uint32_t a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +void mg_md5_update(mg_md5_ctx *ctx, const unsigned char *buf, size_t len) { + uint32_t t; + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) ctx->bits[1]++; + ctx->bits[1] += (uint32_t) len >> 29; + + t = (t >> 3) & 0x3f; + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + mg_byte_reverse(ctx->in, 16); + mg_md5_transform(ctx->buf, (uint32_t *) ctx->in); + buf += t; + len -= t; + } + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + mg_byte_reverse(ctx->in, 16); + mg_md5_transform(ctx->buf, (uint32_t *) ctx->in); + buf += 64; + len -= 64; + } + + memcpy(ctx->in, buf, len); +} + +void mg_md5_final(mg_md5_ctx *ctx, unsigned char digest[16]) { + unsigned count; + unsigned char *p; + uint32_t *a; + + count = (ctx->bits[0] >> 3) & 0x3F; + + p = ctx->in + count; + *p++ = 0x80; + count = 64 - 1 - count; + if (count < 8) { + memset(p, 0, count); + mg_byte_reverse(ctx->in, 16); + mg_md5_transform(ctx->buf, (uint32_t *) ctx->in); + memset(ctx->in, 0, 56); + } else { + memset(p, 0, count - 8); + } + mg_byte_reverse(ctx->in, 14); + + a = (uint32_t *) ctx->in; + a[14] = ctx->bits[0]; + a[15] = ctx->bits[1]; + + mg_md5_transform(ctx->buf, (uint32_t *) ctx->in); + mg_byte_reverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset((char *) ctx, 0, sizeof(*ctx)); +} +#endif + +#ifdef MG_ENABLE_LINES +#line 1 "src/mqtt.c" +#endif + + + + + + + + +#define MQTT_CLEAN_SESSION 0x02 +#define MQTT_HAS_WILL 0x04 +#define MQTT_WILL_RETAIN 0x20 +#define MQTT_HAS_PASSWORD 0x40 +#define MQTT_HAS_USER_NAME 0x80 + +struct mg_mqtt_pmap { + uint8_t id; + uint8_t type; +}; + +static const struct mg_mqtt_pmap s_prop_map[] = { + {MQTT_PROP_PAYLOAD_FORMAT_INDICATOR, MQTT_PROP_TYPE_BYTE}, + {MQTT_PROP_MESSAGE_EXPIRY_INTERVAL, MQTT_PROP_TYPE_INT}, + {MQTT_PROP_CONTENT_TYPE, MQTT_PROP_TYPE_STRING}, + {MQTT_PROP_RESPONSE_TOPIC, MQTT_PROP_TYPE_STRING}, + {MQTT_PROP_CORRELATION_DATA, MQTT_PROP_TYPE_BINARY_DATA}, + {MQTT_PROP_SUBSCRIPTION_IDENTIFIER, MQTT_PROP_TYPE_VARIABLE_INT}, + {MQTT_PROP_SESSION_EXPIRY_INTERVAL, MQTT_PROP_TYPE_INT}, + {MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER, MQTT_PROP_TYPE_STRING}, + {MQTT_PROP_SERVER_KEEP_ALIVE, MQTT_PROP_TYPE_SHORT}, + {MQTT_PROP_AUTHENTICATION_METHOD, MQTT_PROP_TYPE_STRING}, + {MQTT_PROP_AUTHENTICATION_DATA, MQTT_PROP_TYPE_BINARY_DATA}, + {MQTT_PROP_REQUEST_PROBLEM_INFORMATION, MQTT_PROP_TYPE_BYTE}, + {MQTT_PROP_WILL_DELAY_INTERVAL, MQTT_PROP_TYPE_INT}, + {MQTT_PROP_REQUEST_RESPONSE_INFORMATION, MQTT_PROP_TYPE_BYTE}, + {MQTT_PROP_RESPONSE_INFORMATION, MQTT_PROP_TYPE_STRING}, + {MQTT_PROP_SERVER_REFERENCE, MQTT_PROP_TYPE_STRING}, + {MQTT_PROP_REASON_STRING, MQTT_PROP_TYPE_STRING}, + {MQTT_PROP_RECEIVE_MAXIMUM, MQTT_PROP_TYPE_SHORT}, + {MQTT_PROP_TOPIC_ALIAS_MAXIMUM, MQTT_PROP_TYPE_SHORT}, + {MQTT_PROP_TOPIC_ALIAS, MQTT_PROP_TYPE_SHORT}, + {MQTT_PROP_MAXIMUM_QOS, MQTT_PROP_TYPE_BYTE}, + {MQTT_PROP_RETAIN_AVAILABLE, MQTT_PROP_TYPE_BYTE}, + {MQTT_PROP_USER_PROPERTY, MQTT_PROP_TYPE_STRING_PAIR}, + {MQTT_PROP_MAXIMUM_PACKET_SIZE, MQTT_PROP_TYPE_INT}, + {MQTT_PROP_WILDCARD_SUBSCRIPTION_AVAILABLE, MQTT_PROP_TYPE_BYTE}, + {MQTT_PROP_SUBSCRIPTION_IDENTIFIER_AVAILABLE, MQTT_PROP_TYPE_BYTE}, + {MQTT_PROP_SHARED_SUBSCRIPTION_AVAILABLE, MQTT_PROP_TYPE_BYTE}}; + +void mg_mqtt_send_header(struct mg_connection *c, uint8_t cmd, uint8_t flags, + uint32_t len) { + uint8_t buf[1 + sizeof(len)], *vlen = &buf[1]; + buf[0] = (uint8_t) ((cmd << 4) | flags); + do { + *vlen = len % 0x80; + len /= 0x80; + if (len > 0) *vlen |= 0x80; + vlen++; + } while (len > 0 && vlen < &buf[sizeof(buf)]); + mg_send(c, buf, (size_t) (vlen - buf)); +} + +static void mg_send_u16(struct mg_connection *c, uint16_t value) { + mg_send(c, &value, sizeof(value)); +} + +static void mg_send_u32(struct mg_connection *c, uint32_t value) { + mg_send(c, &value, sizeof(value)); +} + +static uint8_t varint_size(size_t length) { + uint8_t bytes_needed = 0; + do { + bytes_needed++; + length /= 0x80; + } while (length > 0); + return bytes_needed; +} + +static size_t encode_varint(uint8_t *buf, size_t value) { + size_t len = 0; + + do { + uint8_t b = (uint8_t) (value % 128); + value /= 128; + if (value > 0) b |= 0x80; + buf[len++] = b; + } while (value > 0); + + return len; +} + +static size_t decode_varint(const uint8_t *buf, size_t len, size_t *value) { + size_t multiplier = 1, offset; + *value = 0; + + for (offset = 0; offset < 4 && offset < len; offset++) { + uint8_t encoded_byte = buf[offset]; + *value += (encoded_byte & 0x7f) * multiplier; + multiplier *= 128; + + if ((encoded_byte & 0x80) == 0) return offset + 1; + } + + return 0; +} + +static int mqtt_prop_type_by_id(uint8_t prop_id) { + size_t i, num_properties = sizeof(s_prop_map) / sizeof(s_prop_map[0]); + for (i = 0; i < num_properties; ++i) { + if (s_prop_map[i].id == prop_id) return s_prop_map[i].type; + } + return -1; // Property ID not found +} + +// Returns the size of the properties section, without the +// size of the content's length +static size_t get_properties_length(struct mg_mqtt_prop *props, size_t count) { + size_t i, size = 0; + for (i = 0; i < count; i++) { + size++; // identifier + switch (mqtt_prop_type_by_id(props[i].id)) { + case MQTT_PROP_TYPE_STRING_PAIR: + size += (uint32_t) (props[i].val.len + props[i].key.len + + 2 * sizeof(uint16_t)); + break; + case MQTT_PROP_TYPE_STRING: + size += (uint32_t) (props[i].val.len + sizeof(uint16_t)); + break; + case MQTT_PROP_TYPE_BINARY_DATA: + size += (uint32_t) (props[i].val.len + sizeof(uint16_t)); + break; + case MQTT_PROP_TYPE_VARIABLE_INT: + size += varint_size((uint32_t) props[i].iv); + break; + case MQTT_PROP_TYPE_INT: + size += (uint32_t) sizeof(uint32_t); + break; + case MQTT_PROP_TYPE_SHORT: + size += (uint32_t) sizeof(uint16_t); + break; + case MQTT_PROP_TYPE_BYTE: + size += (uint32_t) sizeof(uint8_t); + break; + default: + return size; // cannot parse further down + } + } + + return size; +} + +// returns the entire size of the properties section, including the +// size of the variable length of the content +static size_t get_props_size(struct mg_mqtt_prop *props, size_t count) { + size_t size = get_properties_length(props, count); + size += varint_size(size); + return size; +} + +static void mg_send_mqtt_properties(struct mg_connection *c, + struct mg_mqtt_prop *props, size_t nprops) { + size_t total_size = get_properties_length(props, nprops); + uint8_t buf_v[4] = {0, 0, 0, 0}; + uint8_t buf[4] = {0, 0, 0, 0}; + size_t i, len = encode_varint(buf, total_size); + + mg_send(c, buf, (size_t) len); + for (i = 0; i < nprops; i++) { + mg_send(c, &props[i].id, sizeof(props[i].id)); + switch (mqtt_prop_type_by_id(props[i].id)) { + case MQTT_PROP_TYPE_STRING_PAIR: + mg_send_u16(c, mg_htons((uint16_t) props[i].key.len)); + mg_send(c, props[i].key.buf, props[i].key.len); + mg_send_u16(c, mg_htons((uint16_t) props[i].val.len)); + mg_send(c, props[i].val.buf, props[i].val.len); + break; + case MQTT_PROP_TYPE_BYTE: + mg_send(c, &props[i].iv, sizeof(uint8_t)); + break; + case MQTT_PROP_TYPE_SHORT: + mg_send_u16(c, mg_htons((uint16_t) props[i].iv)); + break; + case MQTT_PROP_TYPE_INT: + mg_send_u32(c, mg_htonl((uint32_t) props[i].iv)); + break; + case MQTT_PROP_TYPE_STRING: + mg_send_u16(c, mg_htons((uint16_t) props[i].val.len)); + mg_send(c, props[i].val.buf, props[i].val.len); + break; + case MQTT_PROP_TYPE_BINARY_DATA: + mg_send_u16(c, mg_htons((uint16_t) props[i].val.len)); + mg_send(c, props[i].val.buf, props[i].val.len); + break; + case MQTT_PROP_TYPE_VARIABLE_INT: + len = encode_varint(buf_v, props[i].iv); + mg_send(c, buf_v, (size_t) len); + break; + } + } +} + +size_t mg_mqtt_next_prop(struct mg_mqtt_message *msg, struct mg_mqtt_prop *prop, + size_t ofs) { + uint8_t *i = (uint8_t *) msg->dgram.buf + msg->props_start + ofs; + uint8_t *end = (uint8_t *) msg->dgram.buf + msg->dgram.len; + size_t new_pos = ofs, len; + prop->id = i[0]; + + if (ofs >= msg->dgram.len || ofs >= msg->props_start + msg->props_size) + return 0; + i++, new_pos++; + + switch (mqtt_prop_type_by_id(prop->id)) { + case MQTT_PROP_TYPE_STRING_PAIR: + prop->key.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); + prop->key.buf = (char *) i + 2; + i += 2 + prop->key.len; + prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); + prop->val.buf = (char *) i + 2; + new_pos += 2 * sizeof(uint16_t) + prop->val.len + prop->key.len; + break; + case MQTT_PROP_TYPE_BYTE: + prop->iv = (uint8_t) i[0]; + new_pos++; + break; + case MQTT_PROP_TYPE_SHORT: + prop->iv = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); + new_pos += sizeof(uint16_t); + break; + case MQTT_PROP_TYPE_INT: + prop->iv = ((uint32_t) i[0] << 24) | ((uint32_t) i[1] << 16) | + ((uint32_t) i[2] << 8) | i[3]; + new_pos += sizeof(uint32_t); + break; + case MQTT_PROP_TYPE_STRING: + prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); + prop->val.buf = (char *) i + 2; + new_pos += 2 + prop->val.len; + break; + case MQTT_PROP_TYPE_BINARY_DATA: + prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); + prop->val.buf = (char *) i + 2; + new_pos += 2 + prop->val.len; + break; + case MQTT_PROP_TYPE_VARIABLE_INT: + len = decode_varint(i, (size_t) (end - i), (size_t *) &prop->iv); + new_pos = (!len) ? 0 : new_pos + len; + break; + default: + new_pos = 0; + } + + return new_pos; +} + +void mg_mqtt_login(struct mg_connection *c, const struct mg_mqtt_opts *opts) { + char client_id[21]; + struct mg_str cid = opts->client_id; + size_t total_len = 7 + 1 + 2 + 2; + uint8_t hdr[8] = {0, 4, 'M', 'Q', 'T', 'T', opts->version, 0}; + + if (cid.len == 0) { + mg_random_str(client_id, sizeof(client_id) - 1); + client_id[sizeof(client_id) - 1] = '\0'; + cid = mg_str(client_id); + } + + if (hdr[6] == 0) hdr[6] = 4; // If version is not set, use 4 (3.1.1) + c->is_mqtt5 = hdr[6] == 5; // Set version 5 flag + hdr[7] = (uint8_t) ((opts->qos & 3) << 3); // Connection flags + if (opts->user.len > 0) { + total_len += 2 + (uint32_t) opts->user.len; + hdr[7] |= MQTT_HAS_USER_NAME; + } + if (opts->pass.len > 0) { + total_len += 2 + (uint32_t) opts->pass.len; + hdr[7] |= MQTT_HAS_PASSWORD; + } + if (opts->topic.len > 0) { // allow zero-length msgs, message.len is size_t + total_len += 4 + (uint32_t) opts->topic.len + (uint32_t) opts->message.len; + hdr[7] |= MQTT_HAS_WILL; + } + if (opts->clean || cid.len == 0) hdr[7] |= MQTT_CLEAN_SESSION; + if (opts->retain) hdr[7] |= MQTT_WILL_RETAIN; + total_len += (uint32_t) cid.len; + if (c->is_mqtt5) { + total_len += get_props_size(opts->props, opts->num_props); + if (hdr[7] & MQTT_HAS_WILL) + total_len += get_props_size(opts->will_props, opts->num_will_props); + } + + mg_mqtt_send_header(c, MQTT_CMD_CONNECT, 0, (uint32_t) total_len); + mg_send(c, hdr, sizeof(hdr)); + // keepalive == 0 means "do not disconnect us!" + mg_send_u16(c, mg_htons((uint16_t) opts->keepalive)); + + if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props); + + mg_send_u16(c, mg_htons((uint16_t) cid.len)); + mg_send(c, cid.buf, cid.len); + + if (hdr[7] & MQTT_HAS_WILL) { + if (c->is_mqtt5) + mg_send_mqtt_properties(c, opts->will_props, opts->num_will_props); + + mg_send_u16(c, mg_htons((uint16_t) opts->topic.len)); + mg_send(c, opts->topic.buf, opts->topic.len); + mg_send_u16(c, mg_htons((uint16_t) opts->message.len)); + mg_send(c, opts->message.buf, opts->message.len); + } + if (opts->user.len > 0) { + mg_send_u16(c, mg_htons((uint16_t) opts->user.len)); + mg_send(c, opts->user.buf, opts->user.len); + } + if (opts->pass.len > 0) { + mg_send_u16(c, mg_htons((uint16_t) opts->pass.len)); + mg_send(c, opts->pass.buf, opts->pass.len); + } +} + +uint16_t mg_mqtt_pub(struct mg_connection *c, const struct mg_mqtt_opts *opts) { + uint16_t id = opts->retransmit_id; + uint8_t flags = (uint8_t) (((opts->qos & 3) << 1) | (opts->retain ? 1 : 0)); + size_t len = 2 + opts->topic.len + opts->message.len; + MG_DEBUG(("%lu [%.*s] -> [%.*s]", c->id, (int) opts->topic.len, + (char *) opts->topic.buf, (int) opts->message.len, + (char *) opts->message.buf)); + if (opts->qos > 0) len += 2; + if (c->is_mqtt5) len += get_props_size(opts->props, opts->num_props); + + if (opts->qos > 0 && id != 0) flags |= 1 << 3; + mg_mqtt_send_header(c, MQTT_CMD_PUBLISH, flags, (uint32_t) len); + mg_send_u16(c, mg_htons((uint16_t) opts->topic.len)); + mg_send(c, opts->topic.buf, opts->topic.len); + if (opts->qos > 0) { // need to send 'id' field + if (id == 0) { // generate new one if not resending + if (++c->mgr->mqtt_id == 0) ++c->mgr->mqtt_id; + id = c->mgr->mqtt_id; + } + mg_send_u16(c, mg_htons(id)); + } + + if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props); + + if (opts->message.len > 0) mg_send(c, opts->message.buf, opts->message.len); + return id; +} + +void mg_mqtt_sub(struct mg_connection *c, const struct mg_mqtt_opts *opts) { + uint8_t qos_ = opts->qos & 3; + size_t plen = c->is_mqtt5 ? get_props_size(opts->props, opts->num_props) : 0; + size_t len = 2 + opts->topic.len + 2 + 1 + plen; + + mg_mqtt_send_header(c, MQTT_CMD_SUBSCRIBE, 2, (uint32_t) len); + if (++c->mgr->mqtt_id == 0) ++c->mgr->mqtt_id; + mg_send_u16(c, mg_htons(c->mgr->mqtt_id)); + if (c->is_mqtt5) mg_send_mqtt_properties(c, opts->props, opts->num_props); + + mg_send_u16(c, mg_htons((uint16_t) opts->topic.len)); + mg_send(c, opts->topic.buf, opts->topic.len); + mg_send(c, &qos_, sizeof(qos_)); +} + +int mg_mqtt_parse(const uint8_t *buf, size_t len, uint8_t version, + struct mg_mqtt_message *m) { + uint8_t lc = 0, *p, *end; + uint32_t n = 0, len_len = 0; + + memset(m, 0, sizeof(*m)); + m->dgram.buf = (char *) buf; + if (len < 2) return MQTT_INCOMPLETE; + m->cmd = (uint8_t) (buf[0] >> 4); + m->qos = (buf[0] >> 1) & 3; + + n = len_len = 0; + p = (uint8_t *) buf + 1; + while ((size_t) (p - buf) < len) { + lc = *((uint8_t *) p++); + n += (uint32_t) ((lc & 0x7f) << 7 * len_len); + len_len++; + if (!(lc & 0x80)) break; + if (len_len >= 4) return MQTT_MALFORMED; + } + end = p + n; + if ((lc & 0x80) || (end > buf + len)) return MQTT_INCOMPLETE; + m->dgram.len = (size_t) (end - buf); + + switch (m->cmd) { + case MQTT_CMD_CONNACK: + if (end - p < 2) return MQTT_MALFORMED; + m->ack = p[1]; + break; + case MQTT_CMD_PUBACK: + case MQTT_CMD_PUBREC: + case MQTT_CMD_PUBREL: + case MQTT_CMD_PUBCOMP: + case MQTT_CMD_SUBSCRIBE: + case MQTT_CMD_SUBACK: + case MQTT_CMD_UNSUBSCRIBE: + case MQTT_CMD_UNSUBACK: + if (p + 2 > end) return MQTT_MALFORMED; + m->id = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]); + p += 2; + break; + case MQTT_CMD_PUBLISH: { + if (p + 2 > end) return MQTT_MALFORMED; + m->topic.len = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]); + m->topic.buf = (char *) p + 2; + p += 2 + m->topic.len; + if (p > end) return MQTT_MALFORMED; + if (m->qos > 0) { + if (p + 2 > end) return MQTT_MALFORMED; + m->id = (uint16_t) ((((uint16_t) p[0]) << 8) | p[1]); + p += 2; + } + if (p > end) return MQTT_MALFORMED; + if (version == 5 && p + 2 < end) { + len_len = + (uint32_t) decode_varint(p, (size_t) (end - p), &m->props_size); + if (!len_len) return MQTT_MALFORMED; + m->props_start = (size_t) (p + len_len - buf); + p += len_len + m->props_size; + } + if (p > end) return MQTT_MALFORMED; + m->data.buf = (char *) p; + m->data.len = (size_t) (end - p); + break; + } + default: + break; + } + return MQTT_OK; +} + +static void mqtt_cb(struct mg_connection *c, int ev, void *ev_data) { + if (ev == MG_EV_READ) { + for (;;) { + uint8_t version = c->is_mqtt5 ? 5 : 4; + struct mg_mqtt_message mm; + int rc = mg_mqtt_parse(c->recv.buf, c->recv.len, version, &mm); + if (rc == MQTT_MALFORMED) { + MG_ERROR(("%lu MQTT malformed message", c->id)); + c->is_closing = 1; + break; + } else if (rc == MQTT_OK) { + MG_VERBOSE(("%lu MQTT CMD %d len %d [%.*s]", c->id, mm.cmd, + (int) mm.dgram.len, (int) mm.data.len, mm.data.buf)); + switch (mm.cmd) { + case MQTT_CMD_CONNACK: + mg_call(c, MG_EV_MQTT_OPEN, &mm.ack); + if (mm.ack == 0) { + MG_DEBUG(("%lu Connected", c->id)); + } else { + MG_ERROR(("%lu MQTT auth failed, code %d", c->id, mm.ack)); + c->is_closing = 1; + } + break; + case MQTT_CMD_PUBLISH: { + /*MG_DEBUG(("%lu [%.*s] -> [%.*s]", c->id, (int) mm.topic.len, + mm.topic.buf, (int) mm.data.len, mm.data.buf));*/ + if (mm.qos > 0) { + uint16_t id = mg_ntohs(mm.id); + uint32_t remaining_len = sizeof(id); + if (c->is_mqtt5) remaining_len += 2; // 3.4.2 + + mg_mqtt_send_header( + c, + (uint8_t) (mm.qos == 2 ? MQTT_CMD_PUBREC : MQTT_CMD_PUBACK), + 0, remaining_len); + mg_send(c, &id, sizeof(id)); + + if (c->is_mqtt5) { + uint16_t zero = 0; + mg_send(c, &zero, sizeof(zero)); + } + } + mg_call(c, MG_EV_MQTT_MSG, &mm); // let the app handle qos stuff + break; + } + case MQTT_CMD_PUBREC: { // MQTT5: 3.5.2-1 TODO(): variable header rc + uint16_t id = mg_ntohs(mm.id); + uint32_t remaining_len = sizeof(id); // MQTT5 3.6.2-1 + mg_mqtt_send_header(c, MQTT_CMD_PUBREL, 2, remaining_len); + mg_send(c, &id, sizeof(id)); // MQTT5 3.6.1-1, flags = 2 + break; + } + case MQTT_CMD_PUBREL: { // MQTT5: 3.6.2-1 TODO(): variable header rc + uint16_t id = mg_ntohs(mm.id); + uint32_t remaining_len = sizeof(id); // MQTT5 3.7.2-1 + mg_mqtt_send_header(c, MQTT_CMD_PUBCOMP, 0, remaining_len); + mg_send(c, &id, sizeof(id)); + break; + } + } + mg_call(c, MG_EV_MQTT_CMD, &mm); + mg_iobuf_del(&c->recv, 0, mm.dgram.len); + } else { + break; + } + } + } + (void) ev_data; +} + +void mg_mqtt_ping(struct mg_connection *nc) { + mg_mqtt_send_header(nc, MQTT_CMD_PINGREQ, 0, 0); +} + +void mg_mqtt_pong(struct mg_connection *nc) { + mg_mqtt_send_header(nc, MQTT_CMD_PINGRESP, 0, 0); +} + +void mg_mqtt_disconnect(struct mg_connection *c, + const struct mg_mqtt_opts *opts) { + size_t len = 0; + if (c->is_mqtt5) len = 1 + get_props_size(opts->props, opts->num_props); + mg_mqtt_send_header(c, MQTT_CMD_DISCONNECT, 0, (uint32_t) len); + + if (c->is_mqtt5) { + uint8_t zero = 0; + mg_send(c, &zero, sizeof(zero)); // reason code + mg_send_mqtt_properties(c, opts->props, opts->num_props); + } +} + +struct mg_connection *mg_mqtt_connect(struct mg_mgr *mgr, const char *url, + const struct mg_mqtt_opts *opts, + mg_event_handler_t fn, void *fn_data) { + struct mg_connection *c = mg_connect(mgr, url, fn, fn_data); + if (c != NULL) { + struct mg_mqtt_opts empty; + memset(&empty, 0, sizeof(empty)); + mg_mqtt_login(c, opts == NULL ? &empty : opts); + c->pfn = mqtt_cb; + } + return c; +} + +struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url, + mg_event_handler_t fn, void *fn_data) { + struct mg_connection *c = mg_listen(mgr, url, fn, fn_data); + if (c != NULL) c->pfn = mqtt_cb, c->pfn_data = mgr; + return c; +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/net.c" +#endif + + + + + + + + + +size_t mg_vprintf(struct mg_connection *c, const char *fmt, va_list *ap) { + size_t old = c->send.len; + mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap); + return c->send.len - old; +} + +size_t mg_printf(struct mg_connection *c, const char *fmt, ...) { + size_t len = 0; + va_list ap; + va_start(ap, fmt); + len = mg_vprintf(c, fmt, &ap); + va_end(ap); + return len; +} + +static bool mg_atonl(struct mg_str str, struct mg_addr *addr) { + uint32_t localhost = mg_htonl(0x7f000001); + if (mg_strcasecmp(str, mg_str("localhost")) != 0) return false; + memcpy(addr->ip, &localhost, sizeof(uint32_t)); + addr->is_ip6 = false; + return true; +} + +static bool mg_atone(struct mg_str str, struct mg_addr *addr) { + if (str.len > 0) return false; + memset(addr->ip, 0, sizeof(addr->ip)); + addr->is_ip6 = false; + return true; +} + +static bool mg_aton4(struct mg_str str, struct mg_addr *addr) { + uint8_t data[4] = {0, 0, 0, 0}; + size_t i, num_dots = 0; + for (i = 0; i < str.len; i++) { + if (str.buf[i] >= '0' && str.buf[i] <= '9') { + int octet = data[num_dots] * 10 + (str.buf[i] - '0'); + if (octet > 255) return false; + data[num_dots] = (uint8_t) octet; + } else if (str.buf[i] == '.') { + if (num_dots >= 3 || i == 0 || str.buf[i - 1] == '.') return false; + num_dots++; + } else { + return false; + } + } + if (num_dots != 3 || str.buf[i - 1] == '.') return false; + memcpy(&addr->ip, data, sizeof(data)); + addr->is_ip6 = false; + return true; +} + +static bool mg_v4mapped(struct mg_str str, struct mg_addr *addr) { + int i; + uint32_t ipv4; + if (str.len < 14) return false; + if (str.buf[0] != ':' || str.buf[1] != ':' || str.buf[6] != ':') return false; + for (i = 2; i < 6; i++) { + if (str.buf[i] != 'f' && str.buf[i] != 'F') return false; + } + // struct mg_str s = mg_str_n(&str.buf[7], str.len - 7); + if (!mg_aton4(mg_str_n(&str.buf[7], str.len - 7), addr)) return false; + memcpy(&ipv4, addr->ip, sizeof(ipv4)); + memset(addr->ip, 0, sizeof(addr->ip)); + addr->ip[10] = addr->ip[11] = 255; + memcpy(&addr->ip[12], &ipv4, 4); + addr->is_ip6 = true; + return true; +} + +static bool mg_aton6(struct mg_str str, struct mg_addr *addr) { + size_t i, j = 0, n = 0, dc = 42; + addr->scope_id = 0; + if (str.len > 2 && str.buf[0] == '[') str.buf++, str.len -= 2; + if (mg_v4mapped(str, addr)) return true; + for (i = 0; i < str.len; i++) { + if ((str.buf[i] >= '0' && str.buf[i] <= '9') || + (str.buf[i] >= 'a' && str.buf[i] <= 'f') || + (str.buf[i] >= 'A' && str.buf[i] <= 'F')) { + unsigned long val; // TODO(): This loops on chars, refactor + if (i > j + 3) return false; + // MG_DEBUG(("%lu %lu [%.*s]", i, j, (int) (i - j + 1), &str.buf[j])); + mg_str_to_num(mg_str_n(&str.buf[j], i - j + 1), 16, &val, sizeof(val)); + addr->ip[n] = (uint8_t) ((val >> 8) & 255); + addr->ip[n + 1] = (uint8_t) (val & 255); + } else if (str.buf[i] == ':') { + j = i + 1; + if (i > 0 && str.buf[i - 1] == ':') { + dc = n; // Double colon + if (i > 1 && str.buf[i - 2] == ':') return false; + } else if (i > 0) { + n += 2; + } + if (n > 14) return false; + addr->ip[n] = addr->ip[n + 1] = 0; // For trailing :: + } else if (str.buf[i] == '%') { // Scope ID, last in string + return mg_str_to_num(mg_str_n(&str.buf[i + 1], str.len - i - 1), 10, + &addr->scope_id, sizeof(uint8_t)); + } else { + return false; + } + } + if (n < 14 && dc == 42) return false; + if (n < 14) { + memmove(&addr->ip[dc + (14 - n)], &addr->ip[dc], n - dc + 2); + memset(&addr->ip[dc], 0, 14 - n); + } + + addr->is_ip6 = true; + return true; +} + +bool mg_aton(struct mg_str str, struct mg_addr *addr) { + // MG_INFO(("[%.*s]", (int) str.len, str.buf)); + return mg_atone(str, addr) || mg_atonl(str, addr) || mg_aton4(str, addr) || + mg_aton6(str, addr); +} + +struct mg_connection *mg_alloc_conn(struct mg_mgr *mgr) { + struct mg_connection *c = + (struct mg_connection *) calloc(1, sizeof(*c) + mgr->extraconnsize); + if (c != NULL) { + c->mgr = mgr; + c->send.align = c->recv.align = c->rtls.align = MG_IO_SIZE; + c->id = ++mgr->nextid; + MG_PROF_INIT(c); + } + return c; +} + +void mg_close_conn(struct mg_connection *c) { + mg_resolve_cancel(c); // Close any pending DNS query + LIST_DELETE(struct mg_connection, &c->mgr->conns, c); + if (c == c->mgr->dns4.c) c->mgr->dns4.c = NULL; + if (c == c->mgr->dns6.c) c->mgr->dns6.c = NULL; + // Order of operations is important. `MG_EV_CLOSE` event must be fired + // before we deallocate received data, see #1331 + mg_call(c, MG_EV_CLOSE, NULL); + MG_DEBUG(("%lu %ld closed", c->id, c->fd)); + MG_PROF_DUMP(c); + MG_PROF_FREE(c); + + mg_tls_free(c); + mg_iobuf_free(&c->recv); + mg_iobuf_free(&c->send); + mg_iobuf_free(&c->rtls); + mg_bzero((unsigned char *) c, sizeof(*c)); + free(c); +} + +struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url, + mg_event_handler_t fn, void *fn_data) { + struct mg_connection *c = NULL; + if (url == NULL || url[0] == '\0') { + MG_ERROR(("null url")); + } else if ((c = mg_alloc_conn(mgr)) == NULL) { + MG_ERROR(("OOM")); + } else { + LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c); + c->is_udp = (strncmp(url, "udp:", 4) == 0); + c->fd = (void *) (size_t) MG_INVALID_SOCKET; + c->fn = fn; + c->is_client = true; + c->fn_data = fn_data; + MG_DEBUG(("%lu %ld %s", c->id, c->fd, url)); + mg_call(c, MG_EV_OPEN, (void *) url); + mg_resolve(c, url); + } + return c; +} + +struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url, + mg_event_handler_t fn, void *fn_data) { + struct mg_connection *c = NULL; + if ((c = mg_alloc_conn(mgr)) == NULL) { + MG_ERROR(("OOM %s", url)); + } else if (!mg_open_listener(c, url)) { + MG_ERROR(("Failed: %s, errno %d", url, errno)); + MG_PROF_FREE(c); + free(c); + c = NULL; + } else { + c->is_listening = 1; + c->is_udp = strncmp(url, "udp:", 4) == 0; + LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c); + c->fn = fn; + c->fn_data = fn_data; + mg_call(c, MG_EV_OPEN, NULL); + if (mg_url_is_ssl(url)) c->is_tls = 1; // Accepted connection must + MG_DEBUG(("%lu %ld %s", c->id, c->fd, url)); + } + return c; +} + +struct mg_connection *mg_wrapfd(struct mg_mgr *mgr, int fd, + mg_event_handler_t fn, void *fn_data) { + struct mg_connection *c = mg_alloc_conn(mgr); + if (c != NULL) { + c->fd = (void *) (size_t) fd; + c->fn = fn; + c->fn_data = fn_data; + MG_EPOLL_ADD(c); + mg_call(c, MG_EV_OPEN, NULL); + LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c); + } + return c; +} + +struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds, + unsigned flags, void (*fn)(void *), void *arg) { + struct mg_timer *t = (struct mg_timer *) calloc(1, sizeof(*t)); + if (t != NULL) { + mg_timer_init(&mgr->timers, t, milliseconds, flags, fn, arg); + t->id = mgr->timerid++; + } + return t; +} + +long mg_io_recv(struct mg_connection *c, void *buf, size_t len) { + if (c->rtls.len == 0) return MG_IO_WAIT; + if (len > c->rtls.len) len = c->rtls.len; + memcpy(buf, c->rtls.buf, len); + mg_iobuf_del(&c->rtls, 0, len); + return (long) len; +} + +void mg_mgr_free(struct mg_mgr *mgr) { + struct mg_connection *c; + struct mg_timer *tmp, *t = mgr->timers; + while (t != NULL) tmp = t->next, free(t), t = tmp; + mgr->timers = NULL; // Important. Next call to poll won't touch timers + for (c = mgr->conns; c != NULL; c = c->next) c->is_closing = 1; + mg_mgr_poll(mgr, 0); +#if MG_ENABLE_FREERTOS_TCP + FreeRTOS_DeleteSocketSet(mgr->ss); +#endif + MG_DEBUG(("All connections closed")); +#if MG_ENABLE_EPOLL + if (mgr->epoll_fd >= 0) close(mgr->epoll_fd), mgr->epoll_fd = -1; +#endif + mg_tls_ctx_free(mgr); +} + +void mg_mgr_init(struct mg_mgr *mgr) { + memset(mgr, 0, sizeof(*mgr)); +#if MG_ENABLE_EPOLL + if ((mgr->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0) + MG_ERROR(("epoll_create1 errno %d", errno)); +#else + mgr->epoll_fd = -1; +#endif +#if MG_ARCH == MG_ARCH_WIN32 && MG_ENABLE_WINSOCK + // clang-format off + { WSADATA data; WSAStartup(MAKEWORD(2, 2), &data); } + // clang-format on +#elif MG_ENABLE_FREERTOS_TCP + mgr->ss = FreeRTOS_CreateSocketSet(); +#elif defined(__unix) || defined(__unix__) || defined(__APPLE__) + // Ignore SIGPIPE signal, so if client cancels the request, it + // won't kill the whole process. + signal(SIGPIPE, SIG_IGN); +#elif MG_ENABLE_TCPIP_DRIVER_INIT && defined(MG_TCPIP_DRIVER_INIT) + MG_TCPIP_DRIVER_INIT(mgr); +#endif + mgr->pipe = MG_INVALID_SOCKET; + mgr->dnstimeout = 3000; + mgr->dns4.url = "udp://8.8.8.8:53"; + mgr->dns6.url = "udp://[2001:4860:4860::8888]:53"; + mg_tls_ctx_init(mgr); +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/net_builtin.c" +#endif + + +#if defined(MG_ENABLE_TCPIP) && MG_ENABLE_TCPIP +#define MG_EPHEMERAL_PORT_BASE 32768 +#define PDIFF(a, b) ((size_t) (((char *) (b)) - ((char *) (a)))) + +#ifndef MIP_TCP_KEEPALIVE_MS +#define MIP_TCP_KEEPALIVE_MS 45000 // TCP keep-alive period, ms +#endif + +#define MIP_TCP_ACK_MS 150 // Timeout for ACKing +#define MIP_TCP_ARP_MS 100 // Timeout for ARP response +#define MIP_TCP_SYN_MS 15000 // Timeout for connection establishment +#define MIP_TCP_FIN_MS 1000 // Timeout for closing connection +#define MIP_TCP_WIN 6000 // TCP window size + +struct connstate { + uint32_t seq, ack; // TCP seq/ack counters + uint64_t timer; // TCP keep-alive / ACK timer + uint32_t acked; // Last ACK-ed number + size_t unacked; // Not acked bytes + uint8_t mac[6]; // Peer MAC address + uint8_t ttype; // Timer type. 0: ack, 1: keep-alive +#define MIP_TTYPE_KEEPALIVE 0 // Connection is idle for long, send keepalive +#define MIP_TTYPE_ACK 1 // Peer sent us data, we have to ack it soon +#define MIP_TTYPE_ARP 2 // ARP resolve sent, waiting for response +#define MIP_TTYPE_SYN 3 // SYN sent, waiting for response +#define MIP_TTYPE_FIN 4 // FIN sent, waiting until terminating the connection + uint8_t tmiss; // Number of keep-alive misses + struct mg_iobuf raw; // For TLS only. Incoming raw data +}; + +#pragma pack(push, 1) + +struct lcp { + uint8_t addr, ctrl, proto[2], code, id, len[2]; +}; + +struct eth { + uint8_t dst[6]; // Destination MAC address + uint8_t src[6]; // Source MAC address + uint16_t type; // Ethernet type +}; + +struct ip { + uint8_t ver; // Version + uint8_t tos; // Unused + uint16_t len; // Length + uint16_t id; // Unused + uint16_t frag; // Fragmentation +#define IP_FRAG_OFFSET_MSK 0xFF1F +#define IP_MORE_FRAGS_MSK 0x20 + uint8_t ttl; // Time to live + uint8_t proto; // Upper level protocol + uint16_t csum; // Checksum + uint32_t src; // Source IP + uint32_t dst; // Destination IP +}; + +struct ip6 { + uint8_t ver; // Version + uint8_t opts[3]; // Options + uint16_t len; // Length + uint8_t proto; // Upper level protocol + uint8_t ttl; // Time to live + uint8_t src[16]; // Source IP + uint8_t dst[16]; // Destination IP +}; + +struct icmp { + uint8_t type; + uint8_t code; + uint16_t csum; +}; + +struct arp { + uint16_t fmt; // Format of hardware address + uint16_t pro; // Format of protocol address + uint8_t hlen; // Length of hardware address + uint8_t plen; // Length of protocol address + uint16_t op; // Operation + uint8_t sha[6]; // Sender hardware address + uint32_t spa; // Sender protocol address + uint8_t tha[6]; // Target hardware address + uint32_t tpa; // Target protocol address +}; + +struct tcp { + uint16_t sport; // Source port + uint16_t dport; // Destination port + uint32_t seq; // Sequence number + uint32_t ack; // Acknowledgement number + uint8_t off; // Data offset + uint8_t flags; // TCP flags +#define TH_FIN 0x01 +#define TH_SYN 0x02 +#define TH_RST 0x04 +#define TH_PUSH 0x08 +#define TH_ACK 0x10 +#define TH_URG 0x20 +#define TH_ECE 0x40 +#define TH_CWR 0x80 + uint16_t win; // Window + uint16_t csum; // Checksum + uint16_t urp; // Urgent pointer +}; + +struct udp { + uint16_t sport; // Source port + uint16_t dport; // Destination port + uint16_t len; // UDP length + uint16_t csum; // UDP checksum +}; + +struct dhcp { + uint8_t op, htype, hlen, hops; + uint32_t xid; + uint16_t secs, flags; + uint32_t ciaddr, yiaddr, siaddr, giaddr; + uint8_t hwaddr[208]; + uint32_t magic; + uint8_t options[32]; +}; + +#pragma pack(pop) + +struct pkt { + struct mg_str raw; // Raw packet data + struct mg_str pay; // Payload data + struct eth *eth; + struct llc *llc; + struct arp *arp; + struct ip *ip; + struct ip6 *ip6; + struct icmp *icmp; + struct tcp *tcp; + struct udp *udp; + struct dhcp *dhcp; +}; + +static void send_syn(struct mg_connection *c); + +static void mkpay(struct pkt *pkt, void *p) { + pkt->pay = + mg_str_n((char *) p, (size_t) (&pkt->raw.buf[pkt->raw.len] - (char *) p)); +} + +static uint32_t csumup(uint32_t sum, const void *buf, size_t len) { + size_t i; + const uint8_t *p = (const uint8_t *) buf; + for (i = 0; i < len; i++) sum += i & 1 ? p[i] : (uint32_t) (p[i] << 8); + return sum; +} + +static uint16_t csumfin(uint32_t sum) { + while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16); + return mg_htons(~sum & 0xffff); +} + +static uint16_t ipcsum(const void *buf, size_t len) { + uint32_t sum = csumup(0, buf, len); + return csumfin(sum); +} + +static void settmout(struct mg_connection *c, uint8_t type) { + struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv; + struct connstate *s = (struct connstate *) (c + 1); + unsigned n = type == MIP_TTYPE_ACK ? MIP_TCP_ACK_MS + : type == MIP_TTYPE_ARP ? MIP_TCP_ARP_MS + : type == MIP_TTYPE_SYN ? MIP_TCP_SYN_MS + : type == MIP_TTYPE_FIN ? MIP_TCP_FIN_MS + : MIP_TCP_KEEPALIVE_MS; + s->timer = ifp->now + n; + s->ttype = type; + MG_VERBOSE(("%lu %d -> %llx", c->id, type, s->timer)); +} + +static size_t ether_output(struct mg_tcpip_if *ifp, size_t len) { + size_t n = ifp->driver->tx(ifp->tx.buf, len, ifp); + if (n == len) ifp->nsent++; + return n; +} + +static void arp_ask(struct mg_tcpip_if *ifp, uint32_t ip) { + struct eth *eth = (struct eth *) ifp->tx.buf; + struct arp *arp = (struct arp *) (eth + 1); + memset(eth->dst, 255, sizeof(eth->dst)); + memcpy(eth->src, ifp->mac, sizeof(eth->src)); + eth->type = mg_htons(0x806); + memset(arp, 0, sizeof(*arp)); + arp->fmt = mg_htons(1), arp->pro = mg_htons(0x800), arp->hlen = 6, + arp->plen = 4; + arp->op = mg_htons(1), arp->tpa = ip, arp->spa = ifp->ip; + memcpy(arp->sha, ifp->mac, sizeof(arp->sha)); + ether_output(ifp, PDIFF(eth, arp + 1)); +} + +static void onstatechange(struct mg_tcpip_if *ifp) { + if (ifp->state == MG_TCPIP_STATE_READY) { + MG_INFO(("READY, IP: %M", mg_print_ip4, &ifp->ip)); + MG_INFO((" GW: %M", mg_print_ip4, &ifp->gw)); + MG_INFO((" MAC: %M", mg_print_mac, &ifp->mac)); + arp_ask(ifp, ifp->gw); + } else if (ifp->state == MG_TCPIP_STATE_UP) { + MG_ERROR(("Link up")); + srand((unsigned int) mg_millis()); + } else if (ifp->state == MG_TCPIP_STATE_DOWN) { + MG_ERROR(("Link down")); + } +} + +static struct ip *tx_ip(struct mg_tcpip_if *ifp, uint8_t *mac_dst, + uint8_t proto, uint32_t ip_src, uint32_t ip_dst, + size_t plen) { + struct eth *eth = (struct eth *) ifp->tx.buf; + struct ip *ip = (struct ip *) (eth + 1); + memcpy(eth->dst, mac_dst, sizeof(eth->dst)); + memcpy(eth->src, ifp->mac, sizeof(eth->src)); // Use our MAC + eth->type = mg_htons(0x800); + memset(ip, 0, sizeof(*ip)); + ip->ver = 0x45; // Version 4, header length 5 words + ip->frag = 0x40; // Don't fragment + ip->len = mg_htons((uint16_t) (sizeof(*ip) + plen)); + ip->ttl = 64; + ip->proto = proto; + ip->src = ip_src; + ip->dst = ip_dst; + ip->csum = ipcsum(ip, sizeof(*ip)); + return ip; +} + +static void tx_udp(struct mg_tcpip_if *ifp, uint8_t *mac_dst, uint32_t ip_src, + uint16_t sport, uint32_t ip_dst, uint16_t dport, + const void *buf, size_t len) { + struct ip *ip = + tx_ip(ifp, mac_dst, 17, ip_src, ip_dst, len + sizeof(struct udp)); + struct udp *udp = (struct udp *) (ip + 1); + // MG_DEBUG(("UDP XX LEN %d %d", (int) len, (int) ifp->tx.len)); + udp->sport = sport; + udp->dport = dport; + udp->len = mg_htons((uint16_t) (sizeof(*udp) + len)); + udp->csum = 0; + uint32_t cs = csumup(0, udp, sizeof(*udp)); + cs = csumup(cs, buf, len); + cs = csumup(cs, &ip->src, sizeof(ip->src)); + cs = csumup(cs, &ip->dst, sizeof(ip->dst)); + cs += (uint32_t) (ip->proto + sizeof(*udp) + len); + udp->csum = csumfin(cs); + memmove(udp + 1, buf, len); + // MG_DEBUG(("UDP LEN %d %d", (int) len, (int) ifp->frame_len)); + ether_output(ifp, sizeof(struct eth) + sizeof(*ip) + sizeof(*udp) + len); +} + +static void tx_dhcp(struct mg_tcpip_if *ifp, uint8_t *mac_dst, uint32_t ip_src, + uint32_t ip_dst, uint8_t *opts, size_t optslen, + bool ciaddr) { + // https://datatracker.ietf.org/doc/html/rfc2132#section-9.6 + struct dhcp dhcp = {1, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0}}; + dhcp.magic = mg_htonl(0x63825363); + memcpy(&dhcp.hwaddr, ifp->mac, sizeof(ifp->mac)); + memcpy(&dhcp.xid, ifp->mac + 2, sizeof(dhcp.xid)); + memcpy(&dhcp.options, opts, optslen); + if (ciaddr) dhcp.ciaddr = ip_src; + tx_udp(ifp, mac_dst, ip_src, mg_htons(68), ip_dst, mg_htons(67), &dhcp, + sizeof(dhcp)); +} + +static const uint8_t broadcast[] = {255, 255, 255, 255, 255, 255}; + +// RFC-2131 #4.3.6, #4.4.1 +static void tx_dhcp_request_sel(struct mg_tcpip_if *ifp, uint32_t ip_req, + uint32_t ip_srv) { + uint8_t opts[] = { + 53, 1, 3, // Type: DHCP request + 55, 2, 1, 3, // GW and mask + 12, 3, 'm', 'i', 'p', // Host name: "mip" + 54, 4, 0, 0, 0, 0, // DHCP server ID + 50, 4, 0, 0, 0, 0, // Requested IP + 255 // End of options + }; + memcpy(opts + 14, &ip_srv, sizeof(ip_srv)); + memcpy(opts + 20, &ip_req, sizeof(ip_req)); + tx_dhcp(ifp, (uint8_t *) broadcast, 0, 0xffffffff, opts, sizeof(opts), false); + MG_DEBUG(("DHCP req sent")); +} + +// RFC-2131 #4.3.6, #4.4.5 (renewing: unicast, rebinding: bcast) +static void tx_dhcp_request_re(struct mg_tcpip_if *ifp, uint8_t *mac_dst, + uint32_t ip_src, uint32_t ip_dst) { + uint8_t opts[] = { + 53, 1, 3, // Type: DHCP request + 255 // End of options + }; + tx_dhcp(ifp, mac_dst, ip_src, ip_dst, opts, sizeof(opts), true); + MG_DEBUG(("DHCP req sent")); +} + +static void tx_dhcp_discover(struct mg_tcpip_if *ifp) { + uint8_t opts[] = { + 53, 1, 1, // Type: DHCP discover + 55, 2, 1, 3, // Parameters: ip, mask + 255 // End of options + }; + tx_dhcp(ifp, (uint8_t *) broadcast, 0, 0xffffffff, opts, sizeof(opts), false); + MG_DEBUG(("DHCP discover sent. Our MAC: %M", mg_print_mac, ifp->mac)); +} + +static struct mg_connection *getpeer(struct mg_mgr *mgr, struct pkt *pkt, + bool lsn) { + struct mg_connection *c = NULL; + for (c = mgr->conns; c != NULL; c = c->next) { + if (c->is_arplooking && pkt->arp && + memcmp(&pkt->arp->spa, c->rem.ip, sizeof(pkt->arp->spa)) == 0) + break; + if (c->is_udp && pkt->udp && c->loc.port == pkt->udp->dport) break; + if (!c->is_udp && pkt->tcp && c->loc.port == pkt->tcp->dport && + lsn == c->is_listening && (lsn || c->rem.port == pkt->tcp->sport)) + break; + } + return c; +} + +static void rx_arp(struct mg_tcpip_if *ifp, struct pkt *pkt) { + if (pkt->arp->op == mg_htons(1) && pkt->arp->tpa == ifp->ip) { + // ARP request. Make a response, then send + // MG_DEBUG(("ARP op %d %M: %M", mg_ntohs(pkt->arp->op), mg_print_ip4, + // &pkt->arp->spa, mg_print_ip4, &pkt->arp->tpa)); + struct eth *eth = (struct eth *) ifp->tx.buf; + struct arp *arp = (struct arp *) (eth + 1); + memcpy(eth->dst, pkt->eth->src, sizeof(eth->dst)); + memcpy(eth->src, ifp->mac, sizeof(eth->src)); + eth->type = mg_htons(0x806); + *arp = *pkt->arp; + arp->op = mg_htons(2); + memcpy(arp->tha, pkt->arp->sha, sizeof(pkt->arp->tha)); + memcpy(arp->sha, ifp->mac, sizeof(pkt->arp->sha)); + arp->tpa = pkt->arp->spa; + arp->spa = ifp->ip; + MG_DEBUG(("ARP: tell %M we're %M", mg_print_ip4, &arp->tpa, mg_print_mac, + &ifp->mac)); + ether_output(ifp, PDIFF(eth, arp + 1)); + } else if (pkt->arp->op == mg_htons(2)) { + if (memcmp(pkt->arp->tha, ifp->mac, sizeof(pkt->arp->tha)) != 0) return; + if (pkt->arp->spa == ifp->gw) { + // Got response for the GW ARP request. Set ifp->gwmac + memcpy(ifp->gwmac, pkt->arp->sha, sizeof(ifp->gwmac)); + } else { + struct mg_connection *c = getpeer(ifp->mgr, pkt, false); + if (c != NULL && c->is_arplooking) { + struct connstate *s = (struct connstate *) (c + 1); + memcpy(s->mac, pkt->arp->sha, sizeof(s->mac)); + MG_DEBUG(("%lu ARP resolved %M -> %M", c->id, mg_print_ip4, c->rem.ip, + mg_print_mac, s->mac)); + c->is_arplooking = 0; + send_syn(c); + settmout(c, MIP_TTYPE_SYN); + } + } + } +} + +static void rx_icmp(struct mg_tcpip_if *ifp, struct pkt *pkt) { + // MG_DEBUG(("ICMP %d", (int) len)); + if (pkt->icmp->type == 8 && pkt->ip != NULL && pkt->ip->dst == ifp->ip) { + size_t hlen = sizeof(struct eth) + sizeof(struct ip) + sizeof(struct icmp); + size_t space = ifp->tx.len - hlen, plen = pkt->pay.len; + if (plen > space) plen = space; + struct ip *ip = tx_ip(ifp, pkt->eth->src, 1, ifp->ip, pkt->ip->src, + sizeof(struct icmp) + plen); + struct icmp *icmp = (struct icmp *) (ip + 1); + memset(icmp, 0, sizeof(*icmp)); // Set csum to 0 + memcpy(icmp + 1, pkt->pay.buf, plen); // Copy RX payload to TX + icmp->csum = ipcsum(icmp, sizeof(*icmp) + plen); + ether_output(ifp, hlen + plen); + } +} + +static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { + uint32_t ip = 0, gw = 0, mask = 0, lease = 0; + uint8_t msgtype = 0, state = ifp->state; + // perform size check first, then access fields + uint8_t *p = pkt->dhcp->options, + *end = (uint8_t *) &pkt->raw.buf[pkt->raw.len]; + if (end < (uint8_t *) (pkt->dhcp + 1)) return; + if (memcmp(&pkt->dhcp->xid, ifp->mac + 2, sizeof(pkt->dhcp->xid))) return; + while (p + 1 < end && p[0] != 255) { // Parse options RFC-1533 #9 + if (p[0] == 1 && p[1] == sizeof(ifp->mask) && p + 6 < end) { // Mask + memcpy(&mask, p + 2, sizeof(mask)); + } else if (p[0] == 3 && p[1] == sizeof(ifp->gw) && p + 6 < end) { // GW + memcpy(&gw, p + 2, sizeof(gw)); + ip = pkt->dhcp->yiaddr; + } else if (p[0] == 51 && p[1] == 4 && p + 6 < end) { // Lease + memcpy(&lease, p + 2, sizeof(lease)); + lease = mg_ntohl(lease); + } else if (p[0] == 53 && p[1] == 1 && p + 6 < end) { // Msg Type + msgtype = p[2]; + } + p += p[1] + 2; + } + // Process message type, RFC-1533 (9.4); RFC-2131 (3.1, 4) + if (msgtype == 6 && ifp->ip == ip) { // DHCPNACK, release IP + ifp->state = MG_TCPIP_STATE_UP, ifp->ip = 0; + } else if (msgtype == 2 && ifp->state == MG_TCPIP_STATE_UP && ip && gw && + lease) { // DHCPOFFER + // select IP, (4.4.1) (fallback to IP source addr on foul play) + tx_dhcp_request_sel(ifp, ip, + pkt->dhcp->siaddr ? pkt->dhcp->siaddr : pkt->ip->src); + ifp->state = MG_TCPIP_STATE_REQ; // REQUESTING state + } else if (msgtype == 5) { // DHCPACK + if (ifp->state == MG_TCPIP_STATE_REQ && ip && gw && lease) { // got an IP + ifp->lease_expire = ifp->now + lease * 1000; + MG_INFO(("Lease: %u sec (%lld)", lease, ifp->lease_expire / 1000)); + // assume DHCP server = router until ARP resolves + memcpy(ifp->gwmac, pkt->eth->src, sizeof(ifp->gwmac)); + ifp->ip = ip, ifp->gw = gw, ifp->mask = mask; + ifp->state = MG_TCPIP_STATE_READY; // BOUND state + uint64_t rand; + mg_random(&rand, sizeof(rand)); + srand((unsigned int) (rand + mg_millis())); + } else if (ifp->state == MG_TCPIP_STATE_READY && ifp->ip == ip) { // renew + ifp->lease_expire = ifp->now + lease * 1000; + MG_INFO(("Lease: %u sec (%lld)", lease, ifp->lease_expire / 1000)); + } // TODO(): accept provided T1/T2 and store server IP for renewal (4.4) + } + if (ifp->state != state) onstatechange(ifp); +} + +// Simple DHCP server that assigns a next IP address: ifp->ip + 1 +static void rx_dhcp_server(struct mg_tcpip_if *ifp, struct pkt *pkt) { + uint8_t op = 0, *p = pkt->dhcp->options, + *end = (uint8_t *) &pkt->raw.buf[pkt->raw.len]; + if (end < (uint8_t *) (pkt->dhcp + 1)) return; + // struct dhcp *req = pkt->dhcp; + struct dhcp res = {2, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0}}; + res.yiaddr = ifp->ip; + ((uint8_t *) (&res.yiaddr))[3]++; // Offer our IP + 1 + while (p + 1 < end && p[0] != 255) { // Parse options + if (p[0] == 53 && p[1] == 1 && p + 2 < end) { // Message type + op = p[2]; + } + p += p[1] + 2; + } + if (op == 1 || op == 3) { // DHCP Discover or DHCP Request + uint8_t msg = op == 1 ? 2 : 5; // Message type: DHCP OFFER or DHCP ACK + uint8_t opts[] = { + 53, 1, msg, // Message type + 1, 4, 0, 0, 0, 0, // Subnet mask + 54, 4, 0, 0, 0, 0, // Server ID + 12, 3, 'm', 'i', 'p', // Host name: "mip" + 51, 4, 255, 255, 255, 255, // Lease time + 255 // End of options + }; + memcpy(&res.hwaddr, pkt->dhcp->hwaddr, 6); + memcpy(opts + 5, &ifp->mask, sizeof(ifp->mask)); + memcpy(opts + 11, &ifp->ip, sizeof(ifp->ip)); + memcpy(&res.options, opts, sizeof(opts)); + res.magic = pkt->dhcp->magic; + res.xid = pkt->dhcp->xid; + if (ifp->enable_get_gateway) { + ifp->gw = res.yiaddr; + memcpy(ifp->gwmac, pkt->eth->src, sizeof(ifp->gwmac)); + } + tx_udp(ifp, pkt->eth->src, ifp->ip, mg_htons(67), + op == 1 ? ~0U : res.yiaddr, mg_htons(68), &res, sizeof(res)); + } +} + +static void rx_udp(struct mg_tcpip_if *ifp, struct pkt *pkt) { + struct mg_connection *c = getpeer(ifp->mgr, pkt, true); + if (c == NULL) { + // No UDP listener on this port. Should send ICMP, but keep silent. + } else { + c->rem.port = pkt->udp->sport; + memcpy(c->rem.ip, &pkt->ip->src, sizeof(uint32_t)); + struct connstate *s = (struct connstate *) (c + 1); + memcpy(s->mac, pkt->eth->src, sizeof(s->mac)); + if (c->recv.len >= MG_MAX_RECV_SIZE) { + mg_error(c, "max_recv_buf_size reached"); + } else if (c->recv.size - c->recv.len < pkt->pay.len && + !mg_iobuf_resize(&c->recv, c->recv.len + pkt->pay.len)) { + mg_error(c, "oom"); + } else { + memcpy(&c->recv.buf[c->recv.len], pkt->pay.buf, pkt->pay.len); + c->recv.len += pkt->pay.len; + mg_call(c, MG_EV_READ, &pkt->pay.len); + } + } +} + +static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *dst_mac, uint32_t dst_ip, + uint8_t flags, uint16_t sport, uint16_t dport, + uint32_t seq, uint32_t ack, const void *buf, size_t len) { +#if 0 + uint8_t opts[] = {2, 4, 5, 0xb4, 4, 2, 0, 0}; // MSS = 1460, SACK permitted + if (flags & TH_SYN) { + // Handshake? Set MSS + buf = opts; + len = sizeof(opts); + } +#endif + struct ip *ip = + tx_ip(ifp, dst_mac, 6, ifp->ip, dst_ip, sizeof(struct tcp) + len); + struct tcp *tcp = (struct tcp *) (ip + 1); + memset(tcp, 0, sizeof(*tcp)); + if (buf != NULL && len) memmove(tcp + 1, buf, len); + tcp->sport = sport; + tcp->dport = dport; + tcp->seq = seq; + tcp->ack = ack; + tcp->flags = flags; + tcp->win = mg_htons(MIP_TCP_WIN); + tcp->off = (uint8_t) (sizeof(*tcp) / 4 << 4); + // if (flags & TH_SYN) tcp->off = 0x70; // Handshake? header size 28 bytes + + uint32_t cs = 0; + uint16_t n = (uint16_t) (sizeof(*tcp) + len); + uint8_t pseudo[] = {0, ip->proto, (uint8_t) (n >> 8), (uint8_t) (n & 255)}; + cs = csumup(cs, tcp, n); + cs = csumup(cs, &ip->src, sizeof(ip->src)); + cs = csumup(cs, &ip->dst, sizeof(ip->dst)); + cs = csumup(cs, pseudo, sizeof(pseudo)); + tcp->csum = csumfin(cs); + MG_VERBOSE(("TCP %M:%hu -> %M:%hu fl %x len %u", mg_print_ip4, &ip->src, + mg_ntohs(tcp->sport), mg_print_ip4, &ip->dst, + mg_ntohs(tcp->dport), tcp->flags, len)); + // mg_hexdump(ifp->tx.buf, PDIFF(ifp->tx.buf, tcp + 1) + len); + return ether_output(ifp, PDIFF(ifp->tx.buf, tcp + 1) + len); +} + +static size_t tx_tcp_pkt(struct mg_tcpip_if *ifp, struct pkt *pkt, + uint8_t flags, uint32_t seq, const void *buf, + size_t len) { + uint32_t delta = (pkt->tcp->flags & (TH_SYN | TH_FIN)) ? 1 : 0; + return tx_tcp(ifp, pkt->eth->src, pkt->ip->src, flags, pkt->tcp->dport, + pkt->tcp->sport, seq, mg_htonl(mg_ntohl(pkt->tcp->seq) + delta), + buf, len); +} + +static struct mg_connection *accept_conn(struct mg_connection *lsn, + struct pkt *pkt) { + struct mg_connection *c = mg_alloc_conn(lsn->mgr); + if (c == NULL) { + MG_ERROR(("OOM")); + return NULL; + } + struct connstate *s = (struct connstate *) (c + 1); + s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq); + memcpy(s->mac, pkt->eth->src, sizeof(s->mac)); + settmout(c, MIP_TTYPE_KEEPALIVE); + memcpy(c->rem.ip, &pkt->ip->src, sizeof(uint32_t)); + c->rem.port = pkt->tcp->sport; + MG_DEBUG(("%lu accepted %M", c->id, mg_print_ip_port, &c->rem)); + LIST_ADD_HEAD(struct mg_connection, &lsn->mgr->conns, c); + c->is_accepted = 1; + c->is_hexdumping = lsn->is_hexdumping; + c->pfn = lsn->pfn; + c->loc = lsn->loc; + c->pfn_data = lsn->pfn_data; + c->fn = lsn->fn; + c->fn_data = lsn->fn_data; + mg_call(c, MG_EV_OPEN, NULL); + mg_call(c, MG_EV_ACCEPT, NULL); + return c; +} + +static size_t trim_len(struct mg_connection *c, size_t len) { + struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv; + size_t eth_h_len = 14, ip_max_h_len = 24, tcp_max_h_len = 60, udp_h_len = 8; + size_t max_headers_len = + eth_h_len + ip_max_h_len + (c->is_udp ? udp_h_len : tcp_max_h_len); + size_t min_mtu = c->is_udp ? 68 /* RFC-791 */ : max_headers_len - eth_h_len; + + // If the frame exceeds the available buffer, trim the length + if (len + max_headers_len > ifp->tx.len) { + len = ifp->tx.len - max_headers_len; + } + // Ensure the MTU isn't lower than the minimum allowed value + if (ifp->mtu < min_mtu) { + MG_ERROR(("MTU is lower than minimum, capping to %lu", min_mtu)); + ifp->mtu = (uint16_t) min_mtu; + } + // If the total packet size exceeds the MTU, trim the length + if (len + max_headers_len - eth_h_len > ifp->mtu) { + len = ifp->mtu - max_headers_len + eth_h_len; + if (c->is_udp) { + MG_ERROR(("UDP datagram exceeds MTU. Truncating it.")); + } + } + + return len; +} + +long mg_io_send(struct mg_connection *c, const void *buf, size_t len) { + struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv; + struct connstate *s = (struct connstate *) (c + 1); + uint32_t dst_ip = *(uint32_t *) c->rem.ip; + len = trim_len(c, len); + if (c->is_udp) { + tx_udp(ifp, s->mac, ifp->ip, c->loc.port, dst_ip, c->rem.port, buf, len); + } else { + size_t sent = + tx_tcp(ifp, s->mac, dst_ip, TH_PUSH | TH_ACK, c->loc.port, c->rem.port, + mg_htonl(s->seq), mg_htonl(s->ack), buf, len); + if (sent == 0) { + return MG_IO_WAIT; + } else if (sent == (size_t) -1) { + return MG_IO_ERR; + } else { + s->seq += (uint32_t) len; + if (s->ttype == MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_KEEPALIVE); + } + } + return (long) len; +} + +static void handle_tls_recv(struct mg_connection *c, struct mg_iobuf *io) { + long n = mg_tls_recv(c, &io->buf[io->len], io->size - io->len); + if (n == MG_IO_ERR) { + mg_error(c, "TLS recv error"); + } else if (n > 0) { + // Decrypted successfully - trigger MG_EV_READ + io->len += (size_t) n; + mg_call(c, MG_EV_READ, &n); + } +} + +static void read_conn(struct mg_connection *c, struct pkt *pkt) { + struct connstate *s = (struct connstate *) (c + 1); + struct mg_iobuf *io = c->is_tls ? &c->rtls : &c->recv; + uint32_t seq = mg_ntohl(pkt->tcp->seq); + uint32_t rem_ip; + memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); + if (pkt->tcp->flags & TH_FIN) { + // If we initiated the closure, we reply with ACK upon receiving FIN + // If we didn't initiate it, we reply with FIN as part of the normal TCP + // closure process + uint8_t flags = TH_ACK; + s->ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len + 1); + if (c->is_draining && s->ttype == MIP_TTYPE_FIN) { + if (s->seq == mg_htonl(pkt->tcp->ack)) { // Simultaneous closure ? + s->seq++; // Yes. Increment our SEQ + } else { // Otherwise, + s->seq = mg_htonl(pkt->tcp->ack); // Set to peer's ACK + } + } else { + flags |= TH_FIN; + c->is_draining = 1; + settmout(c, MIP_TTYPE_FIN); + } + tx_tcp((struct mg_tcpip_if *) c->mgr->priv, s->mac, rem_ip, flags, + c->loc.port, c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), "", 0); + } else if (pkt->pay.len == 0) { + // TODO(cpq): handle this peer's ACK + } else if (seq != s->ack) { + uint32_t ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len); + if (s->ack == ack) { + MG_VERBOSE(("ignoring duplicate pkt")); + } else { + MG_VERBOSE(("SEQ != ACK: %x %x %x", seq, s->ack, ack)); + tx_tcp((struct mg_tcpip_if *) c->mgr->priv, s->mac, rem_ip, TH_ACK, + c->loc.port, c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), "", + 0); + } + } else if (io->size - io->len < pkt->pay.len && + !mg_iobuf_resize(io, io->len + pkt->pay.len)) { + mg_error(c, "oom"); + } else { + // Copy TCP payload into the IO buffer. If the connection is plain text, + // we copy to c->recv. If the connection is TLS, this data is encrypted, + // therefore we copy that encrypted data to the c->rtls iobuffer instead, + // and then call mg_tls_recv() to decrypt it. NOTE: mg_tls_recv() will + // call back mg_io_recv() which grabs raw data from c->rtls + memcpy(&io->buf[io->len], pkt->pay.buf, pkt->pay.len); + io->len += pkt->pay.len; + + MG_VERBOSE(("%lu SEQ %x -> %x", c->id, mg_htonl(pkt->tcp->seq), s->ack)); + // Advance ACK counter + s->ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len); + s->unacked += pkt->pay.len; + // size_t diff = s->acked <= s->ack ? s->ack - s->acked : s->ack; + if (s->unacked > MIP_TCP_WIN / 2 && s->acked != s->ack) { + // Send ACK immediately + MG_VERBOSE(("%lu imm ACK %lu", c->id, s->acked)); + tx_tcp((struct mg_tcpip_if *) c->mgr->priv, s->mac, rem_ip, TH_ACK, + c->loc.port, c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), NULL, + 0); + s->unacked = 0; + s->acked = s->ack; + if (s->ttype != MIP_TTYPE_KEEPALIVE) settmout(c, MIP_TTYPE_KEEPALIVE); + } else { + // if not already running, setup a timer to send an ACK later + if (s->ttype != MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_ACK); + } + + if (c->is_tls && c->is_tls_hs) { + mg_tls_handshake(c); + } else if (c->is_tls) { + // TLS connection. Make room for decrypted data in c->recv + io = &c->recv; + if (io->size - io->len < pkt->pay.len && + !mg_iobuf_resize(io, io->len + pkt->pay.len)) { + mg_error(c, "oom"); + } else { + // Decrypt data directly into c->recv + handle_tls_recv(c, io); + } + } else { + // Plain text connection, data is already in c->recv, trigger + // MG_EV_READ + mg_call(c, MG_EV_READ, &pkt->pay.len); + } + } +} + +static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) { + struct mg_connection *c = getpeer(ifp->mgr, pkt, false); + struct connstate *s = c == NULL ? NULL : (struct connstate *) (c + 1); +#if 0 + MG_INFO(("%lu %hhu %d", c ? c->id : 0, pkt->tcp->flags, (int) pkt->pay.len)); +#endif + if (c != NULL && c->is_connecting && pkt->tcp->flags == (TH_SYN | TH_ACK)) { + s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq) + 1; + tx_tcp_pkt(ifp, pkt, TH_ACK, pkt->tcp->ack, NULL, 0); + c->is_connecting = 0; // Client connected + settmout(c, MIP_TTYPE_KEEPALIVE); + mg_call(c, MG_EV_CONNECT, NULL); // Let user know + } else if (c != NULL && c->is_connecting && pkt->tcp->flags != TH_ACK) { + // mg_hexdump(pkt->raw.buf, pkt->raw.len); + tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0); + } else if (c != NULL && pkt->tcp->flags & TH_RST) { + mg_error(c, "peer RST"); // RFC-1122 4.2.2.13 + } else if (c != NULL) { +#if 0 + MG_DEBUG(("%lu %d %M:%hu -> %M:%hu", c->id, (int) pkt->raw.len, + mg_print_ip4, &pkt->ip->src, mg_ntohs(pkt->tcp->sport), + mg_print_ip4, &pkt->ip->dst, mg_ntohs(pkt->tcp->dport))); + mg_hexdump(pkt->pay.buf, pkt->pay.len); +#endif + s->tmiss = 0; // Reset missed keep-alive counter + if (s->ttype == MIP_TTYPE_KEEPALIVE) // Advance keep-alive timer + settmout(c, + MIP_TTYPE_KEEPALIVE); // unless a former ACK timeout is pending + read_conn(c, pkt); // Override timer with ACK timeout if needed + } else if ((c = getpeer(ifp->mgr, pkt, true)) == NULL) { + tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0); + } else if (pkt->tcp->flags & TH_RST) { + if (c->is_accepted) mg_error(c, "peer RST"); // RFC-1122 4.2.2.13 + // ignore RST if not connected + } else if (pkt->tcp->flags & TH_SYN) { + // Use peer's source port as ISN, in order to recognise the handshake + uint32_t isn = mg_htonl((uint32_t) mg_ntohs(pkt->tcp->sport)); + tx_tcp_pkt(ifp, pkt, TH_SYN | TH_ACK, isn, NULL, 0); + } else if (pkt->tcp->flags & TH_FIN) { + tx_tcp_pkt(ifp, pkt, TH_FIN | TH_ACK, pkt->tcp->ack, NULL, 0); + } else if (mg_htonl(pkt->tcp->ack) == mg_htons(pkt->tcp->sport) + 1U) { + accept_conn(c, pkt); + } else if (!c->is_accepted) { // no peer + tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0); + } else { + // MG_VERBOSE(("dropped silently..")); + } +} + +static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) { + if (pkt->ip->frag & IP_MORE_FRAGS_MSK || pkt->ip->frag & IP_FRAG_OFFSET_MSK) { + if (pkt->ip->proto == 17) pkt->udp = (struct udp *) (pkt->ip + 1); + if (pkt->ip->proto == 6) pkt->tcp = (struct tcp *) (pkt->ip + 1); + struct mg_connection *c = getpeer(ifp->mgr, pkt, false); + if (c) mg_error(c, "Received fragmented packet"); + } else if (pkt->ip->proto == 1) { + pkt->icmp = (struct icmp *) (pkt->ip + 1); + if (pkt->pay.len < sizeof(*pkt->icmp)) return; + mkpay(pkt, pkt->icmp + 1); + rx_icmp(ifp, pkt); + } else if (pkt->ip->proto == 17) { + pkt->udp = (struct udp *) (pkt->ip + 1); + if (pkt->pay.len < sizeof(*pkt->udp)) return; + mkpay(pkt, pkt->udp + 1); + MG_VERBOSE(("UDP %M:%hu -> %M:%hu len %u", mg_print_ip4, &pkt->ip->src, + mg_ntohs(pkt->udp->sport), mg_print_ip4, &pkt->ip->dst, + mg_ntohs(pkt->udp->dport), (int) pkt->pay.len)); + if (ifp->enable_dhcp_client && pkt->udp->dport == mg_htons(68)) { + pkt->dhcp = (struct dhcp *) (pkt->udp + 1); + mkpay(pkt, pkt->dhcp + 1); + rx_dhcp_client(ifp, pkt); + } else if (ifp->enable_dhcp_server && pkt->udp->dport == mg_htons(67)) { + pkt->dhcp = (struct dhcp *) (pkt->udp + 1); + mkpay(pkt, pkt->dhcp + 1); + rx_dhcp_server(ifp, pkt); + } else { + rx_udp(ifp, pkt); + } + } else if (pkt->ip->proto == 6) { + pkt->tcp = (struct tcp *) (pkt->ip + 1); + if (pkt->pay.len < sizeof(*pkt->tcp)) return; + mkpay(pkt, pkt->tcp + 1); + uint16_t iplen = mg_ntohs(pkt->ip->len); + uint16_t off = (uint16_t) (sizeof(*pkt->ip) + ((pkt->tcp->off >> 4) * 4U)); + if (iplen >= off) pkt->pay.len = (size_t) (iplen - off); + MG_VERBOSE(("TCP %M:%hu -> %M:%hu len %u", mg_print_ip4, &pkt->ip->src, + mg_ntohs(pkt->tcp->sport), mg_print_ip4, &pkt->ip->dst, + mg_ntohs(pkt->tcp->dport), (int) pkt->pay.len)); + rx_tcp(ifp, pkt); + } +} + +static void rx_ip6(struct mg_tcpip_if *ifp, struct pkt *pkt) { + // MG_DEBUG(("IP %d", (int) len)); + if (pkt->ip6->proto == 1 || pkt->ip6->proto == 58) { + pkt->icmp = (struct icmp *) (pkt->ip6 + 1); + if (pkt->pay.len < sizeof(*pkt->icmp)) return; + mkpay(pkt, pkt->icmp + 1); + rx_icmp(ifp, pkt); + } else if (pkt->ip6->proto == 17) { + pkt->udp = (struct udp *) (pkt->ip6 + 1); + if (pkt->pay.len < sizeof(*pkt->udp)) return; + // MG_DEBUG((" UDP %u %u -> %u", len, mg_htons(udp->sport), + // mg_htons(udp->dport))); + mkpay(pkt, pkt->udp + 1); + } +} + +static void mg_tcpip_rx(struct mg_tcpip_if *ifp, void *buf, size_t len) { + struct pkt pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.raw.buf = (char *) buf; + pkt.raw.len = len; + pkt.eth = (struct eth *) buf; + // mg_hexdump(buf, len > 16 ? 16: len); + if (pkt.raw.len < sizeof(*pkt.eth)) return; // Truncated - runt? + if (ifp->enable_mac_check && + memcmp(pkt.eth->dst, ifp->mac, sizeof(pkt.eth->dst)) != 0 && + memcmp(pkt.eth->dst, broadcast, sizeof(pkt.eth->dst)) != 0) + return; + if (ifp->enable_crc32_check && len > 4) { + len -= 4; // TODO(scaprile): check on bigendian + uint32_t crc = mg_crc32(0, (const char *) buf, len); + if (memcmp((void *) ((size_t) buf + len), &crc, sizeof(crc))) return; + } + if (pkt.eth->type == mg_htons(0x806)) { + pkt.arp = (struct arp *) (pkt.eth + 1); + if (sizeof(*pkt.eth) + sizeof(*pkt.arp) > pkt.raw.len) return; // Truncated + rx_arp(ifp, &pkt); + } else if (pkt.eth->type == mg_htons(0x86dd)) { + pkt.ip6 = (struct ip6 *) (pkt.eth + 1); + if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip6)) return; // Truncated + if ((pkt.ip6->ver >> 4) != 0x6) return; // Not IP + mkpay(&pkt, pkt.ip6 + 1); + rx_ip6(ifp, &pkt); + } else if (pkt.eth->type == mg_htons(0x800)) { + pkt.ip = (struct ip *) (pkt.eth + 1); + if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip)) return; // Truncated + // Truncate frame to what IP header tells us + if ((size_t) mg_ntohs(pkt.ip->len) + sizeof(struct eth) < pkt.raw.len) { + pkt.raw.len = (size_t) mg_ntohs(pkt.ip->len) + sizeof(struct eth); + } + if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip)) return; // Truncated + if ((pkt.ip->ver >> 4) != 4) return; // Not IP + mkpay(&pkt, pkt.ip + 1); + rx_ip(ifp, &pkt); + } else { + MG_DEBUG(("Unknown eth type %x", mg_htons(pkt.eth->type))); + if (mg_log_level >= MG_LL_VERBOSE) mg_hexdump(buf, len >= 32 ? 32 : len); + } +} + +static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) { + struct mg_connection *c; + bool expired_1000ms = mg_timer_expired(&ifp->timer_1000ms, 1000, now); + ifp->now = now; + +#if MG_ENABLE_TCPIP_PRINT_DEBUG_STATS + if (expired_1000ms) { + const char *names[] = {"down", "up", "req", "ready"}; + MG_INFO(("Status: %s, IP: %M, rx:%u, tx:%u, dr:%u, er:%u", + names[ifp->state], mg_print_ip4, &ifp->ip, ifp->nrecv, ifp->nsent, + ifp->ndrop, ifp->nerr)); + } +#endif + // Handle physical interface up/down status + if (expired_1000ms && ifp->driver->up) { + bool up = ifp->driver->up(ifp); + bool current = ifp->state != MG_TCPIP_STATE_DOWN; + if (up != current) { + ifp->state = up == false ? MG_TCPIP_STATE_DOWN + : ifp->enable_dhcp_client ? MG_TCPIP_STATE_UP + : MG_TCPIP_STATE_READY; + if (!up && ifp->enable_dhcp_client) ifp->ip = 0; + onstatechange(ifp); + } + if (ifp->state == MG_TCPIP_STATE_DOWN) MG_ERROR(("Network is down")); + } + if (ifp->state == MG_TCPIP_STATE_DOWN) return; + + // DHCP RFC-2131 (4.4) + if (ifp->state == MG_TCPIP_STATE_UP && expired_1000ms) { + tx_dhcp_discover(ifp); // INIT (4.4.1) + } else if (expired_1000ms && ifp->state == MG_TCPIP_STATE_READY && + ifp->lease_expire > 0) { // BOUND / RENEWING / REBINDING + if (ifp->now >= ifp->lease_expire) { + ifp->state = MG_TCPIP_STATE_UP, ifp->ip = 0; // expired, release IP + onstatechange(ifp); + } else if (ifp->now + 30UL * 60UL * 1000UL > ifp->lease_expire && + ((ifp->now / 1000) % 60) == 0) { + // hack: 30 min before deadline, try to rebind (4.3.6) every min + tx_dhcp_request_re(ifp, (uint8_t *) broadcast, ifp->ip, 0xffffffff); + } // TODO(): Handle T1 (RENEWING) and T2 (REBINDING) (4.4.5) + } + + // Read data from the network + if (ifp->driver->rx != NULL) { // Polling driver. We must call it + size_t len = + ifp->driver->rx(ifp->recv_queue.buf, ifp->recv_queue.size, ifp); + if (len > 0) { + ifp->nrecv++; + mg_tcpip_rx(ifp, ifp->recv_queue.buf, len); + } + } else { // Interrupt-based driver. Fills recv queue itself + char *buf; + size_t len = mg_queue_next(&ifp->recv_queue, &buf); + if (len > 0) { + mg_tcpip_rx(ifp, buf, len); + mg_queue_del(&ifp->recv_queue, len); + } + } + + // Process timeouts + for (c = ifp->mgr->conns; c != NULL; c = c->next) { + if (c->is_udp || c->is_listening || c->is_resolving) continue; + struct connstate *s = (struct connstate *) (c + 1); + uint32_t rem_ip; + memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); + if (now > s->timer) { + if (s->ttype == MIP_TTYPE_ACK && s->acked != s->ack) { + MG_VERBOSE(("%lu ack %x %x", c->id, s->seq, s->ack)); + tx_tcp(ifp, s->mac, rem_ip, TH_ACK, c->loc.port, c->rem.port, + mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0); + s->acked = s->ack; + } else if (s->ttype == MIP_TTYPE_ARP) { + mg_error(c, "ARP timeout"); + } else if (s->ttype == MIP_TTYPE_SYN) { + mg_error(c, "Connection timeout"); + } else if (s->ttype == MIP_TTYPE_FIN) { + c->is_closing = 1; + continue; + } else { + if (s->tmiss++ > 2) { + mg_error(c, "keepalive"); + } else { + MG_VERBOSE(("%lu keepalive", c->id)); + tx_tcp(ifp, s->mac, rem_ip, TH_ACK, c->loc.port, c->rem.port, + mg_htonl(s->seq - 1), mg_htonl(s->ack), NULL, 0); + } + } + + settmout(c, MIP_TTYPE_KEEPALIVE); + } + } +} + +// This function executes in interrupt context, thus it should copy data +// somewhere fast. Note that newlib's malloc is not thread safe, thus use +// our lock-free queue with preallocated buffer to copy data and return asap +void mg_tcpip_qwrite(void *buf, size_t len, struct mg_tcpip_if *ifp) { + char *p; + if (mg_queue_book(&ifp->recv_queue, &p, len) >= len) { + memcpy(p, buf, len); + mg_queue_add(&ifp->recv_queue, len); + ifp->nrecv++; + } else { + ifp->ndrop++; + } +} + +void mg_tcpip_init(struct mg_mgr *mgr, struct mg_tcpip_if *ifp) { + // If MAC address is not set, make a random one + if (ifp->mac[0] == 0 && ifp->mac[1] == 0 && ifp->mac[2] == 0 && + ifp->mac[3] == 0 && ifp->mac[4] == 0 && ifp->mac[5] == 0) { + ifp->mac[0] = 0x02; // Locally administered, unicast + mg_random(&ifp->mac[1], sizeof(ifp->mac) - 1); + MG_INFO(("MAC not set. Generated random: %M", mg_print_mac, ifp->mac)); + } + + if (ifp->driver->init && !ifp->driver->init(ifp)) { + MG_ERROR(("driver init failed")); + } else { + size_t framesize = 1540; + ifp->tx.buf = (char *) calloc(1, framesize), ifp->tx.len = framesize; + if (ifp->recv_queue.size == 0) + ifp->recv_queue.size = ifp->driver->rx ? framesize : 8192; + ifp->recv_queue.buf = (char *) calloc(1, ifp->recv_queue.size); + ifp->timer_1000ms = mg_millis(); + mgr->priv = ifp; + ifp->mgr = mgr; + ifp->mtu = MG_TCPIP_MTU_DEFAULT; + mgr->extraconnsize = sizeof(struct connstate); + if (ifp->ip == 0) ifp->enable_dhcp_client = true; + memset(ifp->gwmac, 255, sizeof(ifp->gwmac)); // Set to broadcast + mg_random(&ifp->eport, sizeof(ifp->eport)); // Random from 0 to 65535 + ifp->eport |= MG_EPHEMERAL_PORT_BASE; // Random from + // MG_EPHEMERAL_PORT_BASE to 65535 + if (ifp->tx.buf == NULL || ifp->recv_queue.buf == NULL) MG_ERROR(("OOM")); + } +} + +void mg_tcpip_free(struct mg_tcpip_if *ifp) { + free(ifp->recv_queue.buf); + free(ifp->tx.buf); +} + +static void send_syn(struct mg_connection *c) { + struct connstate *s = (struct connstate *) (c + 1); + uint32_t isn = mg_htonl((uint32_t) mg_ntohs(c->loc.port)); + struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv; + uint32_t rem_ip; + memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); + tx_tcp(ifp, s->mac, rem_ip, TH_SYN, c->loc.port, c->rem.port, isn, 0, NULL, + 0); +} + +void mg_connect_resolved(struct mg_connection *c) { + struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv; + uint32_t rem_ip; + memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); + c->is_resolving = 0; + if (ifp->eport < MG_EPHEMERAL_PORT_BASE) ifp->eport = MG_EPHEMERAL_PORT_BASE; + memcpy(c->loc.ip, &ifp->ip, sizeof(uint32_t)); + c->loc.port = mg_htons(ifp->eport++); + MG_DEBUG(("%lu %M -> %M", c->id, mg_print_ip_port, &c->loc, mg_print_ip_port, + &c->rem)); + mg_call(c, MG_EV_RESOLVE, NULL); + if (c->is_udp && (rem_ip == 0xffffffff || rem_ip == (ifp->ip | ~ifp->mask))) { + struct connstate *s = (struct connstate *) (c + 1); + memset(s->mac, 0xFF, sizeof(s->mac)); // global or local broadcast + } else if (ifp->ip && ((rem_ip & ifp->mask) == (ifp->ip & ifp->mask))) { + // If we're in the same LAN, fire an ARP lookup. + MG_DEBUG(("%lu ARP lookup...", c->id)); + arp_ask(ifp, rem_ip); + settmout(c, MIP_TTYPE_ARP); + c->is_arplooking = 1; + c->is_connecting = 1; + } else if ((*((uint8_t *) &rem_ip) & 0xE0) == 0xE0) { + struct connstate *s = (struct connstate *) (c + 1); // 224 to 239, E0 to EF + uint8_t mcastp[3] = {0x01, 0x00, 0x5E}; // multicast group + memcpy(s->mac, mcastp, 3); + memcpy(s->mac + 3, ((uint8_t *) &rem_ip) + 1, 3); // 23 LSb + s->mac[3] &= 0x7F; + } else { + struct connstate *s = (struct connstate *) (c + 1); + memcpy(s->mac, ifp->gwmac, sizeof(ifp->gwmac)); + if (c->is_udp) { + mg_call(c, MG_EV_CONNECT, NULL); + } else { + send_syn(c); + settmout(c, MIP_TTYPE_SYN); + c->is_connecting = 1; + } + } +} + +bool mg_open_listener(struct mg_connection *c, const char *url) { + c->loc.port = mg_htons(mg_url_port(url)); + return true; +} + +static void write_conn(struct mg_connection *c) { + long len = c->is_tls ? mg_tls_send(c, c->send.buf, c->send.len) + : mg_io_send(c, c->send.buf, c->send.len); + if (len == MG_IO_ERR) { + mg_error(c, "tx err"); + } else if (len > 0) { + mg_iobuf_del(&c->send, 0, (size_t) len); + mg_call(c, MG_EV_WRITE, &len); + } +} + +static void init_closure(struct mg_connection *c) { + struct connstate *s = (struct connstate *) (c + 1); + if (c->is_udp == false && c->is_listening == false && + c->is_connecting == false) { // For TCP conns, + struct mg_tcpip_if *ifp = + (struct mg_tcpip_if *) c->mgr->priv; // send TCP FIN + uint32_t rem_ip; + memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); + tx_tcp(ifp, s->mac, rem_ip, TH_FIN | TH_ACK, c->loc.port, c->rem.port, + mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0); + settmout(c, MIP_TTYPE_FIN); + } +} + +static void close_conn(struct mg_connection *c) { + struct connstate *s = (struct connstate *) (c + 1); + mg_iobuf_free(&s->raw); // For TLS connections, release raw data + mg_close_conn(c); +} + +static bool can_write(struct mg_connection *c) { + return c->is_connecting == 0 && c->is_resolving == 0 && c->send.len > 0 && + c->is_tls_hs == 0 && c->is_arplooking == 0; +} + +void mg_mgr_poll(struct mg_mgr *mgr, int ms) { + struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) mgr->priv; + struct mg_connection *c, *tmp; + uint64_t now = mg_millis(); + mg_timer_poll(&mgr->timers, now); + if (ifp == NULL || ifp->driver == NULL) return; + mg_tcpip_poll(ifp, now); + for (c = mgr->conns; c != NULL; c = tmp) { + tmp = c->next; + struct connstate *s = (struct connstate *) (c + 1); + mg_call(c, MG_EV_POLL, &now); + MG_VERBOSE(("%lu .. %c%c%c%c%c", c->id, c->is_tls ? 'T' : 't', + c->is_connecting ? 'C' : 'c', c->is_tls_hs ? 'H' : 'h', + c->is_resolving ? 'R' : 'r', c->is_closing ? 'C' : 'c')); + if (c->is_tls && mg_tls_pending(c) > 0) + handle_tls_recv(c, (struct mg_iobuf *) &c->rtls); + if (can_write(c)) write_conn(c); + if (c->is_draining && c->send.len == 0 && s->ttype != MIP_TTYPE_FIN) + init_closure(c); + if (c->is_closing) close_conn(c); + } + (void) ms; +} + +bool mg_send(struct mg_connection *c, const void *buf, size_t len) { + struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv; + bool res = false; + uint32_t rem_ip; + memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); + if (ifp->ip == 0 || ifp->state != MG_TCPIP_STATE_READY) { + mg_error(c, "net down"); + } else if (c->is_udp) { + struct connstate *s = (struct connstate *) (c + 1); + len = trim_len(c, len); // Trimming length if necessary + tx_udp(ifp, s->mac, ifp->ip, c->loc.port, rem_ip, c->rem.port, buf, len); + res = true; + } else { + res = mg_iobuf_add(&c->send, c->send.len, buf, len); + } + return res; +} +#endif // MG_ENABLE_TCPIP + +#ifdef MG_ENABLE_LINES +#line 1 "src/ota_dummy.c" +#endif + + + +#if MG_OTA == MG_OTA_NONE +bool mg_ota_begin(size_t new_firmware_size) { + (void) new_firmware_size; + return true; +} +bool mg_ota_write(const void *buf, size_t len) { + (void) buf, (void) len; + return true; +} +bool mg_ota_end(void) { + return true; +} +bool mg_ota_commit(void) { + return true; +} +bool mg_ota_rollback(void) { + return true; +} +int mg_ota_status(int fw) { + (void) fw; + return 0; +} +uint32_t mg_ota_crc32(int fw) { + (void) fw; + return 0; +} +uint32_t mg_ota_timestamp(int fw) { + (void) fw; + return 0; +} +size_t mg_ota_size(int fw) { + (void) fw; + return 0; +} +MG_IRAM void mg_ota_boot(void) { +} +#endif + +#ifdef MG_ENABLE_LINES +#line 1 "src/ota_esp32.c" +#endif + + +#if MG_ARCH == MG_ARCH_ESP32 && MG_OTA == MG_OTA_ESP32 + +static const esp_partition_t *s_ota_update_partition; +static esp_ota_handle_t s_ota_update_handle; +static bool s_ota_success; + +// Those empty macros do nothing, but mark places in the code which could +// potentially trigger a watchdog reboot due to the log flash erase operation +#define disable_wdt() +#define enable_wdt() + +bool mg_ota_begin(size_t new_firmware_size) { + if (s_ota_update_partition != NULL) { + MG_ERROR(("Update in progress. Call mg_ota_end() ?")); + return false; + } else { + s_ota_success = false; + disable_wdt(); + s_ota_update_partition = esp_ota_get_next_update_partition(NULL); + esp_err_t err = esp_ota_begin(s_ota_update_partition, new_firmware_size, + &s_ota_update_handle); + enable_wdt(); + MG_DEBUG(("esp_ota_begin(): %d", err)); + s_ota_success = (err == ESP_OK); + } + return s_ota_success; +} + +bool mg_ota_write(const void *buf, size_t len) { + disable_wdt(); + esp_err_t err = esp_ota_write(s_ota_update_handle, buf, len); + enable_wdt(); + MG_INFO(("esp_ota_write(): %d", err)); + s_ota_success = err == ESP_OK; + return s_ota_success; +} + +bool mg_ota_end(void) { + esp_err_t err = esp_ota_end(s_ota_update_handle); + MG_DEBUG(("esp_ota_end(%p): %d", s_ota_update_handle, err)); + if (s_ota_success && err == ESP_OK) { + err = esp_ota_set_boot_partition(s_ota_update_partition); + s_ota_success = (err == ESP_OK); + } + MG_DEBUG(("Finished ESP32 OTA, success: %d", s_ota_success)); + s_ota_update_partition = NULL; + return s_ota_success; +} + +#endif + +#ifdef MG_ENABLE_LINES +#line 1 "src/ota_flash.c" +#endif + + + + + +// This OTA implementation uses the internal flash API outlined in device.h +// It splits flash into 2 equal partitions, and stores OTA status in the +// last sector of the partition. + +#if MG_OTA == MG_OTA_FLASH + +#define MG_OTADATA_KEY 0xb07afed0 + +static char *s_addr; // Current address to write to +static size_t s_size; // Firmware size to flash. In-progress indicator +static uint32_t s_crc32; // Firmware checksum + +struct mg_otadata { + uint32_t crc32, size, timestamp, status; +}; + +bool mg_ota_begin(size_t new_firmware_size) { + bool ok = false; + if (s_size) { + MG_ERROR(("OTA already in progress. Call mg_ota_end()")); + } else { + size_t half = mg_flash_size() / 2, max = half - mg_flash_sector_size(); + s_crc32 = 0; + s_addr = (char *) mg_flash_start() + half; + MG_DEBUG(("Firmware %lu bytes, max %lu", new_firmware_size, max)); + if (new_firmware_size < max) { + ok = true; + s_size = new_firmware_size; + MG_INFO(("Starting OTA, firmware size %lu", s_size)); + } else { + MG_ERROR(("Firmware %lu is too big to fit %lu", new_firmware_size, max)); + } + } + return ok; +} + +bool mg_ota_write(const void *buf, size_t len) { + bool ok = false; + if (s_size == 0) { + MG_ERROR(("OTA is not started, call mg_ota_begin()")); + } else { + size_t align = mg_flash_write_align(); + size_t len_aligned_down = MG_ROUND_DOWN(len, align); + if (len_aligned_down) ok = mg_flash_write(s_addr, buf, len_aligned_down); + if (len_aligned_down < len) { + size_t left = len - len_aligned_down; + char tmp[align]; + memset(tmp, 0xff, sizeof(tmp)); + memcpy(tmp, (char *) buf + len_aligned_down, left); + ok = mg_flash_write(s_addr + len_aligned_down, tmp, sizeof(tmp)); + } + s_crc32 = mg_crc32(s_crc32, (char *) buf, len); // Update CRC + MG_DEBUG(("%#x %p %lu -> %d", s_addr - len, buf, len, ok)); + s_addr += len; + } + return ok; +} + +MG_IRAM static uint32_t mg_fwkey(int fw) { + uint32_t key = MG_OTADATA_KEY + fw; + int bank = mg_flash_bank(); + if (bank == 2 && fw == MG_FIRMWARE_PREVIOUS) key--; + if (bank == 2 && fw == MG_FIRMWARE_CURRENT) key++; + return key; +} + +bool mg_ota_end(void) { + char *base = (char *) mg_flash_start() + mg_flash_size() / 2; + bool ok = false; + if (s_size) { + size_t size = s_addr - base; + uint32_t crc32 = mg_crc32(0, base, s_size); + if (size == s_size && crc32 == s_crc32) { + uint32_t now = (uint32_t) (mg_now() / 1000); + struct mg_otadata od = {crc32, size, now, MG_OTA_FIRST_BOOT}; + uint32_t key = mg_fwkey(MG_FIRMWARE_PREVIOUS); + ok = mg_flash_save(NULL, key, &od, sizeof(od)); + } + MG_DEBUG(("CRC: %x/%x, size: %lu/%lu, status: %s", s_crc32, crc32, s_size, + size, ok ? "ok" : "fail")); + s_size = 0; + if (ok) ok = mg_flash_swap_bank(); + } + MG_INFO(("Finishing OTA: %s", ok ? "ok" : "fail")); + return ok; +} + +MG_IRAM static struct mg_otadata mg_otadata(int fw) { + uint32_t key = mg_fwkey(fw); + struct mg_otadata od = {}; + MG_INFO(("Loading %s OTA data", fw == MG_FIRMWARE_CURRENT ? "curr" : "prev")); + mg_flash_load(NULL, key, &od, sizeof(od)); + // MG_DEBUG(("Loaded OTA data. fw %d, bank %d, key %p", fw, bank, key)); + // mg_hexdump(&od, sizeof(od)); + return od; +} + +int mg_ota_status(int fw) { + struct mg_otadata od = mg_otadata(fw); + return od.status; +} +uint32_t mg_ota_crc32(int fw) { + struct mg_otadata od = mg_otadata(fw); + return od.crc32; +} +uint32_t mg_ota_timestamp(int fw) { + struct mg_otadata od = mg_otadata(fw); + return od.timestamp; +} +size_t mg_ota_size(int fw) { + struct mg_otadata od = mg_otadata(fw); + return od.size; +} + +MG_IRAM bool mg_ota_commit(void) { + bool ok = true; + struct mg_otadata od = mg_otadata(MG_FIRMWARE_CURRENT); + if (od.status != MG_OTA_COMMITTED) { + od.status = MG_OTA_COMMITTED; + MG_INFO(("Committing current firmware, OD size %lu", sizeof(od))); + ok = mg_flash_save(NULL, mg_fwkey(MG_FIRMWARE_CURRENT), &od, sizeof(od)); + } + return ok; +} + +bool mg_ota_rollback(void) { + MG_DEBUG(("Rolling firmware back")); + if (mg_flash_bank() == 0) { + // No dual bank support. Mark previous firmware as FIRST_BOOT + struct mg_otadata prev = mg_otadata(MG_FIRMWARE_PREVIOUS); + prev.status = MG_OTA_FIRST_BOOT; + return mg_flash_save(NULL, MG_OTADATA_KEY + MG_FIRMWARE_PREVIOUS, &prev, + sizeof(prev)); + } else { + return mg_flash_swap_bank(); + } +} + +MG_IRAM void mg_ota_boot(void) { + MG_INFO(("Booting. Flash bank: %d", mg_flash_bank())); + struct mg_otadata curr = mg_otadata(MG_FIRMWARE_CURRENT); + struct mg_otadata prev = mg_otadata(MG_FIRMWARE_PREVIOUS); + + if (curr.status == MG_OTA_FIRST_BOOT) { + if (prev.status == MG_OTA_UNAVAILABLE) { + MG_INFO(("Setting previous firmware state to committed")); + prev.status = MG_OTA_COMMITTED; + mg_flash_save(NULL, mg_fwkey(MG_FIRMWARE_PREVIOUS), &prev, sizeof(prev)); + } + curr.status = MG_OTA_UNCOMMITTED; + MG_INFO(("First boot, setting status to UNCOMMITTED")); + mg_flash_save(NULL, mg_fwkey(MG_FIRMWARE_CURRENT), &curr, sizeof(curr)); + } else if (prev.status == MG_OTA_FIRST_BOOT && mg_flash_bank() == 0) { + // Swap paritions. Pray power does not disappear + size_t fs = mg_flash_size(), ss = mg_flash_sector_size(); + char *partition1 = mg_flash_start(); + char *partition2 = mg_flash_start() + fs / 2; + size_t ofs, max = fs / 2 - ss; // Set swap size to the whole partition + + if (curr.status != MG_OTA_UNAVAILABLE && + prev.status != MG_OTA_UNAVAILABLE) { + // We know exact sizes of both firmwares. + // Shrink swap size to the MAX(firmware1, firmware2) + size_t sz = curr.size > prev.size ? curr.size : prev.size; + if (sz > 0 && sz < max) max = sz; + } + + // MG_OTA_FIRST_BOOT -> MG_OTA_UNCOMMITTED + prev.status = MG_OTA_UNCOMMITTED; + mg_flash_save(NULL, MG_OTADATA_KEY + MG_FIRMWARE_CURRENT, &prev, + sizeof(prev)); + mg_flash_save(NULL, MG_OTADATA_KEY + MG_FIRMWARE_PREVIOUS, &curr, + sizeof(curr)); + + MG_INFO(("Swapping partitions, size %u (%u sectors)", max, max / ss)); + MG_INFO(("Do NOT power off...")); + mg_log_level = MG_LL_NONE; + + // We use the last sector of partition2 for OTA data/config storage + // Therefore we can use last sector of partition1 for swapping + char *tmpsector = partition1 + fs / 2 - ss; // Last sector of partition1 + (void) tmpsector; + for (ofs = 0; ofs < max; ofs += ss) { + // mg_flash_erase(tmpsector); + mg_flash_write(tmpsector, partition1 + ofs, ss); + // mg_flash_erase(partition1 + ofs); + mg_flash_write(partition1 + ofs, partition2 + ofs, ss); + // mg_flash_erase(partition2 + ofs); + mg_flash_write(partition2 + ofs, tmpsector, ss); + } + mg_device_reset(); + } +} +#endif + +#ifdef MG_ENABLE_LINES +#line 1 "src/printf.c" +#endif + + + + +size_t mg_queue_vprintf(struct mg_queue *q, const char *fmt, va_list *ap) { + size_t len = mg_snprintf(NULL, 0, fmt, ap); + char *buf; + if (len == 0 || mg_queue_book(q, &buf, len + 1) < len + 1) { + len = 0; // Nah. Not enough space + } else { + len = mg_vsnprintf((char *) buf, len + 1, fmt, ap); + mg_queue_add(q, len); + } + return len; +} + +size_t mg_queue_printf(struct mg_queue *q, const char *fmt, ...) { + va_list ap; + size_t len; + va_start(ap, fmt); + len = mg_queue_vprintf(q, fmt, &ap); + va_end(ap); + return len; +} + +static void mg_pfn_iobuf_private(char ch, void *param, bool expand) { + struct mg_iobuf *io = (struct mg_iobuf *) param; + if (expand && io->len + 2 > io->size) mg_iobuf_resize(io, io->len + 2); + if (io->len + 2 <= io->size) { + io->buf[io->len++] = (uint8_t) ch; + io->buf[io->len] = 0; + } else if (io->len < io->size) { + io->buf[io->len++] = 0; // Guarantee to 0-terminate + } +} + +static void mg_putchar_iobuf_static(char ch, void *param) { + mg_pfn_iobuf_private(ch, param, false); +} + +void mg_pfn_iobuf(char ch, void *param) { + mg_pfn_iobuf_private(ch, param, true); +} + +size_t mg_vsnprintf(char *buf, size_t len, const char *fmt, va_list *ap) { + struct mg_iobuf io = {(uint8_t *) buf, len, 0, 0}; + size_t n = mg_vxprintf(mg_putchar_iobuf_static, &io, fmt, ap); + if (n < len) buf[n] = '\0'; + return n; +} + +size_t mg_snprintf(char *buf, size_t len, const char *fmt, ...) { + va_list ap; + size_t n; + va_start(ap, fmt); + n = mg_vsnprintf(buf, len, fmt, &ap); + va_end(ap); + return n; +} + +char *mg_vmprintf(const char *fmt, va_list *ap) { + struct mg_iobuf io = {0, 0, 0, 256}; + mg_vxprintf(mg_pfn_iobuf, &io, fmt, ap); + return (char *) io.buf; +} + +char *mg_mprintf(const char *fmt, ...) { + char *s; + va_list ap; + va_start(ap, fmt); + s = mg_vmprintf(fmt, &ap); + va_end(ap); + return s; +} + +void mg_pfn_stdout(char c, void *param) { + putchar(c); + (void) param; +} + +static size_t print_ip4(void (*out)(char, void *), void *arg, uint8_t *p) { + return mg_xprintf(out, arg, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); +} + +static size_t print_ip6(void (*out)(char, void *), void *arg, uint16_t *p) { + return mg_xprintf(out, arg, "[%x:%x:%x:%x:%x:%x:%x:%x]", mg_ntohs(p[0]), + mg_ntohs(p[1]), mg_ntohs(p[2]), mg_ntohs(p[3]), + mg_ntohs(p[4]), mg_ntohs(p[5]), mg_ntohs(p[6]), + mg_ntohs(p[7])); +} + +size_t mg_print_ip4(void (*out)(char, void *), void *arg, va_list *ap) { + uint8_t *p = va_arg(*ap, uint8_t *); + return print_ip4(out, arg, p); +} + +size_t mg_print_ip6(void (*out)(char, void *), void *arg, va_list *ap) { + uint16_t *p = va_arg(*ap, uint16_t *); + return print_ip6(out, arg, p); +} + +size_t mg_print_ip(void (*out)(char, void *), void *arg, va_list *ap) { + struct mg_addr *addr = va_arg(*ap, struct mg_addr *); + if (addr->is_ip6) return print_ip6(out, arg, (uint16_t *) addr->ip); + return print_ip4(out, arg, (uint8_t *) &addr->ip); +} + +size_t mg_print_ip_port(void (*out)(char, void *), void *arg, va_list *ap) { + struct mg_addr *a = va_arg(*ap, struct mg_addr *); + return mg_xprintf(out, arg, "%M:%hu", mg_print_ip, a, mg_ntohs(a->port)); +} + +size_t mg_print_mac(void (*out)(char, void *), void *arg, va_list *ap) { + uint8_t *p = va_arg(*ap, uint8_t *); + return mg_xprintf(out, arg, "%02x:%02x:%02x:%02x:%02x:%02x", p[0], p[1], p[2], + p[3], p[4], p[5]); +} + +static char mg_esc(int c, bool esc) { + const char *p, *esc1 = "\b\f\n\r\t\\\"", *esc2 = "bfnrt\\\""; + for (p = esc ? esc1 : esc2; *p != '\0'; p++) { + if (*p == c) return esc ? esc2[p - esc1] : esc1[p - esc2]; + } + return 0; +} + +static char mg_escape(int c) { + return mg_esc(c, true); +} + +static size_t qcpy(void (*out)(char, void *), void *ptr, char *buf, + size_t len) { + size_t i = 0, extra = 0; + for (i = 0; i < len && buf[i] != '\0'; i++) { + char c = mg_escape(buf[i]); + if (c) { + out('\\', ptr), out(c, ptr), extra++; + } else { + out(buf[i], ptr); + } + } + return i + extra; +} + +static size_t bcpy(void (*out)(char, void *), void *arg, uint8_t *buf, + size_t len) { + size_t i, j, n = 0; + const char *t = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + for (i = 0; i < len; i += 3) { + uint8_t c1 = buf[i], c2 = i + 1 < len ? buf[i + 1] : 0, + c3 = i + 2 < len ? buf[i + 2] : 0; + char tmp[4] = {t[c1 >> 2], t[(c1 & 3) << 4 | (c2 >> 4)], '=', '='}; + if (i + 1 < len) tmp[2] = t[(c2 & 15) << 2 | (c3 >> 6)]; + if (i + 2 < len) tmp[3] = t[c3 & 63]; + for (j = 0; j < sizeof(tmp) && tmp[j] != '\0'; j++) out(tmp[j], arg); + n += j; + } + return n; +} + +size_t mg_print_hex(void (*out)(char, void *), void *arg, va_list *ap) { + size_t bl = (size_t) va_arg(*ap, int); + uint8_t *p = va_arg(*ap, uint8_t *); + const char *hex = "0123456789abcdef"; + size_t j; + for (j = 0; j < bl; j++) { + out(hex[(p[j] >> 4) & 0x0F], arg); + out(hex[p[j] & 0x0F], arg); + } + return 2 * bl; +} +size_t mg_print_base64(void (*out)(char, void *), void *arg, va_list *ap) { + size_t len = (size_t) va_arg(*ap, int); + uint8_t *buf = va_arg(*ap, uint8_t *); + return bcpy(out, arg, buf, len); +} + +size_t mg_print_esc(void (*out)(char, void *), void *arg, va_list *ap) { + size_t len = (size_t) va_arg(*ap, int); + char *p = va_arg(*ap, char *); + if (len == 0) len = p == NULL ? 0 : strlen(p); + return qcpy(out, arg, p, len); +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/queue.c" +#endif + + + +#if (defined(__GNUC__) && (__GNUC__ > 4) || \ + (defined(__GNUC_MINOR__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 1)) || \ + defined(__clang__) +#define MG_MEMORY_BARRIER() __sync_synchronize() +#elif defined(_MSC_VER) && _MSC_VER >= 1700 +#define MG_MEMORY_BARRIER() MemoryBarrier() +#elif !defined(MG_MEMORY_BARRIER) +#define MG_MEMORY_BARRIER() +#endif + +// Every message in a queue is prepended by a 32-bit message length (ML). +// If ML is 0, then it is the end, and reader must wrap to the beginning. +// +// Queue when q->tail <= q->head: +// |----- free -----| ML | message1 | ML | message2 | ----- free ------| +// ^ ^ ^ ^ +// buf tail head len +// +// Queue when q->tail > q->head: +// | ML | message2 |----- free ------| ML | message1 | 0 |---- free ----| +// ^ ^ ^ ^ +// buf head tail len + +void mg_queue_init(struct mg_queue *q, char *buf, size_t size) { + q->size = size; + q->buf = buf; + q->head = q->tail = 0; +} + +static size_t mg_queue_read_len(struct mg_queue *q) { + uint32_t n = 0; + MG_MEMORY_BARRIER(); + memcpy(&n, q->buf + q->tail, sizeof(n)); + assert(q->tail + n + sizeof(n) <= q->size); + return n; +} + +static void mg_queue_write_len(struct mg_queue *q, size_t len) { + uint32_t n = (uint32_t) len; + memcpy(q->buf + q->head, &n, sizeof(n)); + MG_MEMORY_BARRIER(); +} + +size_t mg_queue_book(struct mg_queue *q, char **buf, size_t len) { + size_t space = 0, hs = sizeof(uint32_t) * 2; // *2 is for the 0 marker + if (q->head >= q->tail && q->head + len + hs <= q->size) { + space = q->size - q->head - hs; // There is enough space + } else if (q->head >= q->tail && q->tail > hs) { + mg_queue_write_len(q, 0); // Not enough space ahead + q->head = 0; // Wrap head to the beginning + } + if (q->head + hs + len < q->tail) space = q->tail - q->head - hs; + if (buf != NULL) *buf = q->buf + q->head + sizeof(uint32_t); + return space; +} + +size_t mg_queue_next(struct mg_queue *q, char **buf) { + size_t len = 0; + if (q->tail != q->head) { + len = mg_queue_read_len(q); + if (len == 0) { // Zero (head wrapped) ? + q->tail = 0; // Reset tail to the start + if (q->head > q->tail) len = mg_queue_read_len(q); // Read again + } + } + if (buf != NULL) *buf = q->buf + q->tail + sizeof(uint32_t); + assert(q->tail + len <= q->size); + return len; +} + +void mg_queue_add(struct mg_queue *q, size_t len) { + assert(len > 0); + mg_queue_write_len(q, len); + assert(q->head + sizeof(uint32_t) * 2 + len <= q->size); + q->head += len + sizeof(uint32_t); +} + +void mg_queue_del(struct mg_queue *q, size_t len) { + q->tail += len + sizeof(uint32_t); + assert(q->tail + sizeof(uint32_t) <= q->size); +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/rpc.c" +#endif + + + +void mg_rpc_add(struct mg_rpc **head, struct mg_str method, + void (*fn)(struct mg_rpc_req *), void *fn_data) { + struct mg_rpc *rpc = (struct mg_rpc *) calloc(1, sizeof(*rpc)); + if (rpc != NULL) { + rpc->method.buf = mg_mprintf("%.*s", method.len, method.buf); + rpc->method.len = method.len; + rpc->fn = fn; + rpc->fn_data = fn_data; + rpc->next = *head, *head = rpc; + } +} + +void mg_rpc_del(struct mg_rpc **head, void (*fn)(struct mg_rpc_req *)) { + struct mg_rpc *r; + while ((r = *head) != NULL) { + if (r->fn == fn || fn == NULL) { + *head = r->next; + free((void *) r->method.buf); + free(r); + } else { + head = &(*head)->next; + } + } +} + +static void mg_rpc_call(struct mg_rpc_req *r, struct mg_str method) { + struct mg_rpc *h = r->head == NULL ? NULL : *r->head; + while (h != NULL && !mg_match(method, h->method, NULL)) h = h->next; + if (h != NULL) { + r->rpc = h; + h->fn(r); + } else { + mg_rpc_err(r, -32601, "\"%.*s not found\"", (int) method.len, method.buf); + } +} + +void mg_rpc_process(struct mg_rpc_req *r) { + int len, off = mg_json_get(r->frame, "$.method", &len); + if (off > 0 && r->frame.buf[off] == '"') { + struct mg_str method = mg_str_n(&r->frame.buf[off + 1], (size_t) len - 2); + mg_rpc_call(r, method); + } else if ((off = mg_json_get(r->frame, "$.result", &len)) > 0 || + (off = mg_json_get(r->frame, "$.error", &len)) > 0) { + mg_rpc_call(r, mg_str("")); // JSON response! call "" method handler + } else { + mg_rpc_err(r, -32700, "%m", mg_print_esc, (int) r->frame.len, + r->frame.buf); // Invalid + } +} + +void mg_rpc_vok(struct mg_rpc_req *r, const char *fmt, va_list *ap) { + int len, off = mg_json_get(r->frame, "$.id", &len); + if (off > 0) { + mg_xprintf(r->pfn, r->pfn_data, "{%m:%.*s,%m:", mg_print_esc, 0, "id", len, + &r->frame.buf[off], mg_print_esc, 0, "result"); + mg_vxprintf(r->pfn, r->pfn_data, fmt == NULL ? "null" : fmt, ap); + mg_xprintf(r->pfn, r->pfn_data, "}"); + } +} + +void mg_rpc_ok(struct mg_rpc_req *r, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + mg_rpc_vok(r, fmt, &ap); + va_end(ap); +} + +void mg_rpc_verr(struct mg_rpc_req *r, int code, const char *fmt, va_list *ap) { + int len, off = mg_json_get(r->frame, "$.id", &len); + mg_xprintf(r->pfn, r->pfn_data, "{"); + if (off > 0) { + mg_xprintf(r->pfn, r->pfn_data, "%m:%.*s,", mg_print_esc, 0, "id", len, + &r->frame.buf[off]); + } + mg_xprintf(r->pfn, r->pfn_data, "%m:{%m:%d,%m:", mg_print_esc, 0, "error", + mg_print_esc, 0, "code", code, mg_print_esc, 0, "message"); + mg_vxprintf(r->pfn, r->pfn_data, fmt == NULL ? "null" : fmt, ap); + mg_xprintf(r->pfn, r->pfn_data, "}}"); +} + +void mg_rpc_err(struct mg_rpc_req *r, int code, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + mg_rpc_verr(r, code, fmt, &ap); + va_end(ap); +} + +static size_t print_methods(mg_pfn_t pfn, void *pfn_data, va_list *ap) { + struct mg_rpc *h, **head = (struct mg_rpc **) va_arg(*ap, void **); + size_t len = 0; + for (h = *head; h != NULL; h = h->next) { + if (h->method.len == 0) continue; // Ignore response handler + len += mg_xprintf(pfn, pfn_data, "%s%m", h == *head ? "" : ",", + mg_print_esc, (int) h->method.len, h->method.buf); + } + return len; +} + +void mg_rpc_list(struct mg_rpc_req *r) { + mg_rpc_ok(r, "[%M]", print_methods, r->head); +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/sha1.c" +#endif +/* Copyright(c) By Steve Reid */ +/* 100% Public Domain */ + + + +union char64long16 { + unsigned char c[64]; + uint32_t l[16]; +}; + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +static uint32_t blk0(union char64long16 *block, int i) { + if (MG_BIG_ENDIAN) { + } else { + block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | + (rol(block->l[i], 8) & 0x00FF00FF); + } + return block->l[i]; +} + +/* Avoid redefine warning (ARM /usr/include/sys/ucontext.h define R0~R4) */ +#undef blk +#undef R0 +#undef R1 +#undef R2 +#undef R3 +#undef R4 + +#define blk(i) \ + (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ \ + block->l[(i + 2) & 15] ^ block->l[i & 15], \ + 1)) +#define R0(v, w, x, y, z, i) \ + z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R1(v, w, x, y, z, i) \ + z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R2(v, w, x, y, z, i) \ + z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \ + w = rol(w, 30); +#define R3(v, w, x, y, z, i) \ + z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ + w = rol(w, 30); +#define R4(v, w, x, y, z, i) \ + z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ + w = rol(w, 30); + +static void mg_sha1_transform(uint32_t state[5], + const unsigned char *buffer) { + uint32_t a, b, c, d, e; + union char64long16 block[1]; + + memcpy(block, buffer, 64); + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + R0(a, b, c, d, e, 0); + R0(e, a, b, c, d, 1); + R0(d, e, a, b, c, 2); + R0(c, d, e, a, b, 3); + R0(b, c, d, e, a, 4); + R0(a, b, c, d, e, 5); + R0(e, a, b, c, d, 6); + R0(d, e, a, b, c, 7); + R0(c, d, e, a, b, 8); + R0(b, c, d, e, a, 9); + R0(a, b, c, d, e, 10); + R0(e, a, b, c, d, 11); + R0(d, e, a, b, c, 12); + R0(c, d, e, a, b, 13); + R0(b, c, d, e, a, 14); + R0(a, b, c, d, e, 15); + R1(e, a, b, c, d, 16); + R1(d, e, a, b, c, 17); + R1(c, d, e, a, b, 18); + R1(b, c, d, e, a, 19); + R2(a, b, c, d, e, 20); + R2(e, a, b, c, d, 21); + R2(d, e, a, b, c, 22); + R2(c, d, e, a, b, 23); + R2(b, c, d, e, a, 24); + R2(a, b, c, d, e, 25); + R2(e, a, b, c, d, 26); + R2(d, e, a, b, c, 27); + R2(c, d, e, a, b, 28); + R2(b, c, d, e, a, 29); + R2(a, b, c, d, e, 30); + R2(e, a, b, c, d, 31); + R2(d, e, a, b, c, 32); + R2(c, d, e, a, b, 33); + R2(b, c, d, e, a, 34); + R2(a, b, c, d, e, 35); + R2(e, a, b, c, d, 36); + R2(d, e, a, b, c, 37); + R2(c, d, e, a, b, 38); + R2(b, c, d, e, a, 39); + R3(a, b, c, d, e, 40); + R3(e, a, b, c, d, 41); + R3(d, e, a, b, c, 42); + R3(c, d, e, a, b, 43); + R3(b, c, d, e, a, 44); + R3(a, b, c, d, e, 45); + R3(e, a, b, c, d, 46); + R3(d, e, a, b, c, 47); + R3(c, d, e, a, b, 48); + R3(b, c, d, e, a, 49); + R3(a, b, c, d, e, 50); + R3(e, a, b, c, d, 51); + R3(d, e, a, b, c, 52); + R3(c, d, e, a, b, 53); + R3(b, c, d, e, a, 54); + R3(a, b, c, d, e, 55); + R3(e, a, b, c, d, 56); + R3(d, e, a, b, c, 57); + R3(c, d, e, a, b, 58); + R3(b, c, d, e, a, 59); + R4(a, b, c, d, e, 60); + R4(e, a, b, c, d, 61); + R4(d, e, a, b, c, 62); + R4(c, d, e, a, b, 63); + R4(b, c, d, e, a, 64); + R4(a, b, c, d, e, 65); + R4(e, a, b, c, d, 66); + R4(d, e, a, b, c, 67); + R4(c, d, e, a, b, 68); + R4(b, c, d, e, a, 69); + R4(a, b, c, d, e, 70); + R4(e, a, b, c, d, 71); + R4(d, e, a, b, c, 72); + R4(c, d, e, a, b, 73); + R4(b, c, d, e, a, 74); + R4(a, b, c, d, e, 75); + R4(e, a, b, c, d, 76); + R4(d, e, a, b, c, 77); + R4(c, d, e, a, b, 78); + R4(b, c, d, e, a, 79); + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Erase working structures. The order of operations is important, + * used to ensure that compiler doesn't optimize those out. */ + memset(block, 0, sizeof(block)); + a = b = c = d = e = 0; + (void) a; + (void) b; + (void) c; + (void) d; + (void) e; +} + +void mg_sha1_init(mg_sha1_ctx *context) { + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + +void mg_sha1_update(mg_sha1_ctx *context, const unsigned char *data, + size_t len) { + size_t i, j; + + j = context->count[0]; + if ((context->count[0] += (uint32_t) len << 3) < j) context->count[1]++; + context->count[1] += (uint32_t) (len >> 29); + j = (j >> 3) & 63; + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64 - j)); + mg_sha1_transform(context->state, context->buffer); + for (; i + 63 < len; i += 64) { + mg_sha1_transform(context->state, &data[i]); + } + j = 0; + } else + i = 0; + memcpy(&context->buffer[j], &data[i], len - i); +} + +void mg_sha1_final(unsigned char digest[20], mg_sha1_ctx *context) { + unsigned i; + unsigned char finalcount[8], c; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >> + ((3 - (i & 3)) * 8)) & + 255); + } + c = 0200; + mg_sha1_update(context, &c, 1); + while ((context->count[0] & 504) != 448) { + c = 0000; + mg_sha1_update(context, &c, 1); + } + mg_sha1_update(context, finalcount, 8); + for (i = 0; i < 20; i++) { + digest[i] = + (unsigned char) ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); + } + memset(context, '\0', sizeof(*context)); + memset(&finalcount, '\0', sizeof(finalcount)); +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/sha256.c" +#endif +// https://github.com/B-Con/crypto-algorithms +// Author: Brad Conte (brad AT bradconte.com) +// Disclaimer: This code is presented "as is" without any guarantees. +// Details: Defines the API for the corresponding SHA1 implementation. +// Copyright: public domain + + + +#define ror(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) +#define ch(x, y, z) (((x) & (y)) ^ (~(x) & (z))) +#define maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define ep0(x) (ror(x, 2) ^ ror(x, 13) ^ ror(x, 22)) +#define ep1(x) (ror(x, 6) ^ ror(x, 11) ^ ror(x, 25)) +#define sig0(x) (ror(x, 7) ^ ror(x, 18) ^ ((x) >> 3)) +#define sig1(x) (ror(x, 17) ^ ror(x, 19) ^ ((x) >> 10)) + +static const uint32_t mg_sha256_k[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, + 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, + 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, + 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, + 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; + +void mg_sha256_init(mg_sha256_ctx *ctx) { + ctx->len = 0; + ctx->bits = 0; + ctx->state[0] = 0x6a09e667; + ctx->state[1] = 0xbb67ae85; + ctx->state[2] = 0x3c6ef372; + ctx->state[3] = 0xa54ff53a; + ctx->state[4] = 0x510e527f; + ctx->state[5] = 0x9b05688c; + ctx->state[6] = 0x1f83d9ab; + ctx->state[7] = 0x5be0cd19; +} + +static void mg_sha256_chunk(mg_sha256_ctx *ctx) { + int i, j; + uint32_t a, b, c, d, e, f, g, h; + uint32_t m[64]; + for (i = 0, j = 0; i < 16; ++i, j += 4) + m[i] = (uint32_t) (((uint32_t) ctx->buffer[j] << 24) | + ((uint32_t) ctx->buffer[j + 1] << 16) | + ((uint32_t) ctx->buffer[j + 2] << 8) | + ((uint32_t) ctx->buffer[j + 3])); + for (; i < 64; ++i) + m[i] = sig1(m[i - 2]) + m[i - 7] + sig0(m[i - 15]) + m[i - 16]; + + a = ctx->state[0]; + b = ctx->state[1]; + c = ctx->state[2]; + d = ctx->state[3]; + e = ctx->state[4]; + f = ctx->state[5]; + g = ctx->state[6]; + h = ctx->state[7]; + + for (i = 0; i < 64; ++i) { + uint32_t t1 = h + ep1(e) + ch(e, f, g) + mg_sha256_k[i] + m[i]; + uint32_t t2 = ep0(a) + maj(a, b, c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; + ctx->state[4] += e; + ctx->state[5] += f; + ctx->state[6] += g; + ctx->state[7] += h; +} + +void mg_sha256_update(mg_sha256_ctx *ctx, const unsigned char *data, + size_t len) { + size_t i; + for (i = 0; i < len; i++) { + ctx->buffer[ctx->len] = data[i]; + if ((++ctx->len) == 64) { + mg_sha256_chunk(ctx); + ctx->bits += 512; + ctx->len = 0; + } + } +} + +// TODO: make final reusable (remove side effects) +void mg_sha256_final(unsigned char digest[32], mg_sha256_ctx *ctx) { + uint32_t i = ctx->len; + if (i < 56) { + ctx->buffer[i++] = 0x80; + while (i < 56) { + ctx->buffer[i++] = 0x00; + } + } else { + ctx->buffer[i++] = 0x80; + while (i < 64) { + ctx->buffer[i++] = 0x00; + } + mg_sha256_chunk(ctx); + memset(ctx->buffer, 0, 56); + } + + ctx->bits += ctx->len * 8; + ctx->buffer[63] = (uint8_t) ((ctx->bits) & 0xff); + ctx->buffer[62] = (uint8_t) ((ctx->bits >> 8) & 0xff); + ctx->buffer[61] = (uint8_t) ((ctx->bits >> 16) & 0xff); + ctx->buffer[60] = (uint8_t) ((ctx->bits >> 24) & 0xff); + ctx->buffer[59] = (uint8_t) ((ctx->bits >> 32) & 0xff); + ctx->buffer[58] = (uint8_t) ((ctx->bits >> 40) & 0xff); + ctx->buffer[57] = (uint8_t) ((ctx->bits >> 48) & 0xff); + ctx->buffer[56] = (uint8_t) ((ctx->bits >> 56) & 0xff); + mg_sha256_chunk(ctx); + + for (i = 0; i < 4; ++i) { + digest[i] = (uint8_t) ((ctx->state[0] >> (24 - i * 8)) & 0xff); + digest[i + 4] = (uint8_t) ((ctx->state[1] >> (24 - i * 8)) & 0xff); + digest[i + 8] = (uint8_t) ((ctx->state[2] >> (24 - i * 8)) & 0xff); + digest[i + 12] = (uint8_t) ((ctx->state[3] >> (24 - i * 8)) & 0xff); + digest[i + 16] = (uint8_t) ((ctx->state[4] >> (24 - i * 8)) & 0xff); + digest[i + 20] = (uint8_t) ((ctx->state[5] >> (24 - i * 8)) & 0xff); + digest[i + 24] = (uint8_t) ((ctx->state[6] >> (24 - i * 8)) & 0xff); + digest[i + 28] = (uint8_t) ((ctx->state[7] >> (24 - i * 8)) & 0xff); + } +} + +void mg_hmac_sha256(uint8_t dst[32], uint8_t *key, size_t keysz, uint8_t *data, + size_t datasz) { + mg_sha256_ctx ctx; + uint8_t k[64] = {0}; + uint8_t o_pad[64], i_pad[64]; + unsigned int i; + memset(i_pad, 0x36, sizeof(i_pad)); + memset(o_pad, 0x5c, sizeof(o_pad)); + if (keysz < 64) { + if (keysz > 0) memmove(k, key, keysz); + } else { + mg_sha256_init(&ctx); + mg_sha256_update(&ctx, key, keysz); + mg_sha256_final(k, &ctx); + } + for (i = 0; i < sizeof(k); i++) { + i_pad[i] ^= k[i]; + o_pad[i] ^= k[i]; + } + mg_sha256_init(&ctx); + mg_sha256_update(&ctx, i_pad, sizeof(i_pad)); + mg_sha256_update(&ctx, data, datasz); + mg_sha256_final(dst, &ctx); + mg_sha256_init(&ctx); + mg_sha256_update(&ctx, o_pad, sizeof(o_pad)); + mg_sha256_update(&ctx, dst, 32); + mg_sha256_final(dst, &ctx); +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/sntp.c" +#endif + + + + + + +#define SNTP_TIME_OFFSET 2208988800U // (1970 - 1900) in seconds +#define SNTP_MAX_FRAC 4294967295.0 // 2 ** 32 - 1 + +static int64_t gettimestamp(const uint32_t *data) { + uint32_t sec = mg_ntohl(data[0]), frac = mg_ntohl(data[1]); + if (sec) sec -= SNTP_TIME_OFFSET; + return ((int64_t) sec) * 1000 + (int64_t) (frac / SNTP_MAX_FRAC * 1000.0); +} + +int64_t mg_sntp_parse(const unsigned char *buf, size_t len) { + int64_t res = -1; + int mode = len > 0 ? buf[0] & 7 : 0; + int version = len > 0 ? (buf[0] >> 3) & 7 : 0; + if (len < 48) { + MG_ERROR(("%s", "corrupt packet")); + } else if (mode != 4 && mode != 5) { + MG_ERROR(("%s", "not a server reply")); + } else if (buf[1] == 0) { + MG_ERROR(("%s", "server sent a kiss of death")); + } else if (version == 4 || version == 3) { + // int64_t ref = gettimestamp((uint32_t *) &buf[16]); + int64_t t0 = gettimestamp((uint32_t *) &buf[24]); + int64_t t1 = gettimestamp((uint32_t *) &buf[32]); + int64_t t2 = gettimestamp((uint32_t *) &buf[40]); + int64_t t3 = (int64_t) mg_millis(); + int64_t delta = (t3 - t0) - (t2 - t1); + MG_VERBOSE(("%lld %lld %lld %lld delta:%lld", t0, t1, t2, t3, delta)); + res = t2 + delta / 2; + } else { + MG_ERROR(("unexpected version: %d", version)); + } + return res; +} + +static void sntp_cb(struct mg_connection *c, int ev, void *ev_data) { + if (ev == MG_EV_READ) { + int64_t milliseconds = mg_sntp_parse(c->recv.buf, c->recv.len); + if (milliseconds > 0) { + MG_DEBUG(("%lu got time: %lld ms from epoch", c->id, milliseconds)); + mg_call(c, MG_EV_SNTP_TIME, (uint64_t *) &milliseconds); + MG_VERBOSE(("%u.%u", (unsigned) (milliseconds / 1000), + (unsigned) (milliseconds % 1000))); + } + mg_iobuf_del(&c->recv, 0, c->recv.len); // Free receive buffer + } else if (ev == MG_EV_CONNECT) { + mg_sntp_request(c); + } else if (ev == MG_EV_CLOSE) { + } + (void) ev_data; +} + +void mg_sntp_request(struct mg_connection *c) { + if (c->is_resolving) { + MG_ERROR(("%lu wait until resolved", c->id)); + } else { + int64_t now = (int64_t) mg_millis(); // Use int64_t, for vc98 + uint8_t buf[48] = {0}; + uint32_t *t = (uint32_t *) &buf[40]; + double frac = ((double) (now % 1000)) / 1000.0 * SNTP_MAX_FRAC; + buf[0] = (0 << 6) | (4 << 3) | 3; + t[0] = mg_htonl((uint32_t) (now / 1000) + SNTP_TIME_OFFSET); + t[1] = mg_htonl((uint32_t) frac); + mg_send(c, buf, sizeof(buf)); + } +} + +struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, const char *url, + mg_event_handler_t fn, void *fnd) { + struct mg_connection *c = NULL; + if (url == NULL) url = "udp://time.google.com:123"; + if ((c = mg_connect(mgr, url, fn, fnd)) != NULL) c->pfn = sntp_cb; + return c; +} + +#ifdef MG_ENABLE_LINES +#line 1 "src/sock.c" +#endif + + + + + + + + + + + +#if MG_ENABLE_SOCKET + +#ifndef closesocket +#define closesocket(x) close(x) +#endif + +#define FD(c_) ((MG_SOCKET_TYPE) (size_t) (c_)->fd) +#define S2PTR(s_) ((void *) (size_t) (s_)) + +#ifndef MSG_NONBLOCKING +#define MSG_NONBLOCKING 0 +#endif + +#ifndef AF_INET6 +#define AF_INET6 10 +#endif + +#ifndef MG_SOCK_ERR +#define MG_SOCK_ERR(errcode) ((errcode) < 0 ? errno : 0) +#endif + +#ifndef MG_SOCK_INTR +#define MG_SOCK_INTR(fd) (fd == MG_INVALID_SOCKET && MG_SOCK_ERR(-1) == EINTR) +#endif + +#ifndef MG_SOCK_PENDING +#define MG_SOCK_PENDING(errcode) \ + (((errcode) < 0) && (errno == EINPROGRESS || errno == EWOULDBLOCK)) +#endif + +#ifndef MG_SOCK_RESET +#define MG_SOCK_RESET(errcode) \ + (((errcode) < 0) && (errno == EPIPE || errno == ECONNRESET)) +#endif + +union usa { + struct sockaddr sa; + struct sockaddr_in sin; +#if MG_ENABLE_IPV6 + struct sockaddr_in6 sin6; +#endif +}; + +static socklen_t tousa(struct mg_addr *a, union usa *usa) { + socklen_t len = sizeof(usa->sin); + memset(usa, 0, sizeof(*usa)); + usa->sin.sin_family = AF_INET; + usa->sin.sin_port = a->port; + memcpy(&usa->sin.sin_addr, a->ip, sizeof(uint32_t)); +#if MG_ENABLE_IPV6 + if (a->is_ip6) { + usa->sin.sin_family = AF_INET6; + usa->sin6.sin6_port = a->port; + usa->sin6.sin6_scope_id = a->scope_id; + memcpy(&usa->sin6.sin6_addr, a->ip, sizeof(a->ip)); + len = sizeof(usa->sin6); + } +#endif + return len; +} + +static void tomgaddr(union usa *usa, struct mg_addr *a, bool is_ip6) { + a->is_ip6 = is_ip6; + a->port = usa->sin.sin_port; + memcpy(&a->ip, &usa->sin.sin_addr, sizeof(uint32_t)); +#if MG_ENABLE_IPV6 + if (is_ip6) { + memcpy(a->ip, &usa->sin6.sin6_addr, sizeof(a->ip)); + a->port = usa->sin6.sin6_port; + a->scope_id = (uint8_t) usa->sin6.sin6_scope_id; + } +#endif +} + +static void setlocaddr(MG_SOCKET_TYPE fd, struct mg_addr *addr) { + union usa usa; + socklen_t n = sizeof(usa); + if (getsockname(fd, &usa.sa, &n) == 0) { + tomgaddr(&usa, addr, n != sizeof(usa.sin)); + } +} + +static void iolog(struct mg_connection *c, char *buf, long n, bool r) { + if (n == MG_IO_WAIT) { + // Do nothing + } else if (n <= 0) { + c->is_closing = 1; // Termination. Don't call mg_error(): #1529 + } else if (n > 0) { + if (c->is_hexdumping) { + MG_INFO(("\n-- %lu %M %s %M %ld", c->id, mg_print_ip_port, &c->loc, + r ? "<-" : "->", mg_print_ip_port, &c->rem, n)); + mg_hexdump(buf, (size_t) n); + } + if (r) { + c->recv.len += (size_t) n; + mg_call(c, MG_EV_READ, &n); + } else { + mg_iobuf_del(&c->send, 0, (size_t) n); + // if (c->send.len == 0) mg_iobuf_resize(&c->send, 0); + if (c->send.len == 0) { + MG_EPOLL_MOD(c, 0); + } + mg_call(c, MG_EV_WRITE, &n); } } - return flags; } -static int uri_to_path(struct mg_connection *c, struct mg_http_message *hm, - const struct mg_http_serve_opts *opts, char *path, - size_t path_size) { - struct mg_fs *fs = opts->fs == NULL ? &mg_fs_posix : opts->fs; - struct mg_str k, v, s = mg_str(opts->root_dir), u = {0, 0}, p = {0, 0}; - while (mg_commalist(&s, &k, &v)) { - if (v.len == 0) v = k, k = mg_str("/"); - if (hm->uri.len < k.len) continue; - if (mg_strcmp(k, mg_str_n(hm->uri.ptr, k.len)) != 0) continue; - u = k, p = v; +long mg_io_send(struct mg_connection *c, const void *buf, size_t len) { + long n; + if (c->is_udp) { + union usa usa; + socklen_t slen = tousa(&c->rem, &usa); + n = sendto(FD(c), (char *) buf, len, 0, &usa.sa, slen); + if (n > 0) setlocaddr(FD(c), &c->loc); + } else { + n = send(FD(c), (char *) buf, len, MSG_NONBLOCKING); } - return uri_to_path2(c, hm, fs, u, p, path, path_size); + MG_VERBOSE(("%lu %ld %d", c->id, n, MG_SOCK_ERR(n))); + if (MG_SOCK_PENDING(n)) return MG_IO_WAIT; + if (MG_SOCK_RESET(n)) return MG_IO_RESET; + if (n <= 0) return MG_IO_ERR; + return n; } -void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm, - const struct mg_http_serve_opts *opts) { - char path[MG_PATH_MAX]; - const char *sp = opts->ssi_pattern; - int flags = uri_to_path(c, hm, opts, path, sizeof(path)); - if (flags < 0) { - // Do nothing: the response has already been sent by uri_to_path() - } else if (flags & MG_FS_DIR) { - listdir(c, hm, opts, path); - } else if (flags && sp != NULL && - mg_globmatch(sp, strlen(sp), path, strlen(path))) { - mg_http_serve_ssi(c, opts->root_dir, path); +bool mg_send(struct mg_connection *c, const void *buf, size_t len) { + if (c->is_udp) { + long n = mg_io_send(c, buf, len); + MG_DEBUG(("%lu %ld %lu:%lu:%lu %ld err %d", c->id, c->fd, c->send.len, + c->recv.len, c->rtls.len, n, MG_SOCK_ERR(n))); + iolog(c, (char *) buf, n, false); + return n > 0; } else { - mg_http_serve_file(c, hm, path, opts); + return mg_iobuf_add(&c->send, c->send.len, buf, len); } } -static bool mg_is_url_safe(int c) { - return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || c == '.' || c == '_' || c == '-' || c == '~'; +static void mg_set_non_blocking_mode(MG_SOCKET_TYPE fd) { +#if defined(MG_CUSTOM_NONBLOCK) + MG_CUSTOM_NONBLOCK(fd); +#elif MG_ARCH == MG_ARCH_WIN32 && MG_ENABLE_WINSOCK + unsigned long on = 1; + ioctlsocket(fd, FIONBIO, &on); +#elif MG_ENABLE_RL + unsigned long on = 1; + ioctlsocket(fd, FIONBIO, &on); +#elif MG_ENABLE_FREERTOS_TCP + const BaseType_t off = 0; + if (setsockopt(fd, 0, FREERTOS_SO_RCVTIMEO, &off, sizeof(off)) != 0) (void) 0; + if (setsockopt(fd, 0, FREERTOS_SO_SNDTIMEO, &off, sizeof(off)) != 0) (void) 0; +#elif MG_ENABLE_LWIP + lwip_fcntl(fd, F_SETFL, O_NONBLOCK); +#elif MG_ARCH == MG_ARCH_AZURERTOS + fcntl(fd, F_SETFL, O_NONBLOCK); +#elif MG_ARCH == MG_ARCH_TIRTOS + int val = 0; + setsockopt(fd, SOL_SOCKET, SO_BLOCKING, &val, sizeof(val)); + // SPRU524J section 3.3.3 page 63, SO_SNDLOWAT + int sz = sizeof(val); + getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &val, &sz); + val /= 2; // set send low-water mark at half send buffer size + setsockopt(fd, SOL_SOCKET, SO_SNDLOWAT, &val, sizeof(val)); +#else + fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); // Non-blocking mode + fcntl(fd, F_SETFD, FD_CLOEXEC); // Set close-on-exec +#endif } -size_t mg_url_encode(const char *s, size_t sl, char *buf, size_t len) { - size_t i, n = 0; - for (i = 0; i < sl; i++) { - int c = *(unsigned char *) &s[i]; - if (n + 4 >= len) return 0; - if (mg_is_url_safe(c)) { - buf[n++] = s[i]; +bool mg_open_listener(struct mg_connection *c, const char *url) { + MG_SOCKET_TYPE fd = MG_INVALID_SOCKET; + bool success = false; + c->loc.port = mg_htons(mg_url_port(url)); + if (!mg_aton(mg_url_host(url), &c->loc)) { + MG_ERROR(("invalid listening URL: %s", url)); + } else { + union usa usa; + socklen_t slen = tousa(&c->loc, &usa); + int rc, on = 1, af = c->loc.is_ip6 ? AF_INET6 : AF_INET; + int type = strncmp(url, "udp:", 4) == 0 ? SOCK_DGRAM : SOCK_STREAM; + int proto = type == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP; + (void) on; + + if ((fd = socket(af, type, proto)) == MG_INVALID_SOCKET) { + MG_ERROR(("socket: %d", MG_SOCK_ERR(-1))); +#if defined(SO_EXCLUSIVEADDRUSE) + } else if ((rc = setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, + (char *) &on, sizeof(on))) != 0) { + // "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE" + MG_ERROR(("setsockopt(SO_EXCLUSIVEADDRUSE): %d %d", on, MG_SOCK_ERR(rc))); +#elif defined(SO_REUSEADDR) && (!defined(LWIP_SOCKET) || SO_REUSE) + } else if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, + sizeof(on))) != 0) { + // 1. SO_REUSEADDR semantics on UNIX and Windows is different. On + // Windows, SO_REUSEADDR allows to bind a socket to a port without error + // even if the port is already open by another program. This is not the + // behavior SO_REUSEADDR was designed for, and leads to hard-to-track + // failure scenarios. + // + // 2. For LWIP, SO_REUSEADDR should be explicitly enabled by defining + // SO_REUSE = 1 in lwipopts.h, otherwise the code below will compile but + // won't work! (setsockopt will return EINVAL) + MG_ERROR(("setsockopt(SO_REUSEADDR): %d", MG_SOCK_ERR(rc))); +#endif +#if MG_IPV6_V6ONLY + // Bind only to the V6 address, not V4 address on this port + } else if (c->loc.is_ip6 && + (rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &on, + sizeof(on))) != 0) { + // See #2089. Allow to bind v4 and v6 sockets on the same port + MG_ERROR(("setsockopt(IPV6_V6ONLY): %d", MG_SOCK_ERR(rc))); +#endif + } else if ((rc = bind(fd, &usa.sa, slen)) != 0) { + MG_ERROR(("bind: %d", MG_SOCK_ERR(rc))); + } else if ((type == SOCK_STREAM && + (rc = listen(fd, MG_SOCK_LISTEN_BACKLOG_SIZE)) != 0)) { + // NOTE(lsm): FreeRTOS uses backlog value as a connection limit + // In case port was set to 0, get the real port number + MG_ERROR(("listen: %d", MG_SOCK_ERR(rc))); } else { - buf[n++] = '%'; - mg_hex(&s[i], 1, &buf[n]); - n += 2; + setlocaddr(fd, &c->loc); + mg_set_non_blocking_mode(fd); + c->fd = S2PTR(fd); + MG_EPOLL_ADD(c); + success = true; } } - if (len > 0 && n < len - 1) buf[n] = '\0'; // Null-terminate the destination - if (len > 0) buf[len - 1] = '\0'; // Always. - return n; + if (success == false && fd != MG_INVALID_SOCKET) closesocket(fd); + return success; } -void mg_http_creds(struct mg_http_message *hm, char *user, size_t userlen, - char *pass, size_t passlen) { - struct mg_str *v = mg_http_get_header(hm, "Authorization"); - user[0] = pass[0] = '\0'; - if (v != NULL && v->len > 6 && memcmp(v->ptr, "Basic ", 6) == 0) { - char buf[256]; - int n = mg_base64_decode(v->ptr + 6, (int) v->len - 6, buf); - const char *p = (const char *) memchr(buf, ':', n > 0 ? (size_t) n : 0); - if (p != NULL) { - mg_snprintf(user, userlen, "%.*s", (int) (p - buf), buf); - mg_snprintf(pass, passlen, "%.*s", n - (int) (p - buf) - 1, p + 1); - } - } else if (v != NULL && v->len > 7 && memcmp(v->ptr, "Bearer ", 7) == 0) { - mg_snprintf(pass, passlen, "%.*s", (int) v->len - 7, v->ptr + 7); - } else if ((v = mg_http_get_header(hm, "Cookie")) != NULL) { - struct mg_str t = mg_http_get_header_var(*v, mg_str_n("access_token", 12)); - if (t.len > 0) mg_snprintf(pass, passlen, "%.*s", (int) t.len, t.ptr); +static long recv_raw(struct mg_connection *c, void *buf, size_t len) { + long n = 0; + if (c->is_udp) { + union usa usa; + socklen_t slen = tousa(&c->rem, &usa); + n = recvfrom(FD(c), (char *) buf, len, 0, &usa.sa, &slen); + if (n > 0) tomgaddr(&usa, &c->rem, slen != sizeof(usa.sin)); } else { - mg_http_get_var(&hm->query, "access_token", pass, passlen); + n = recv(FD(c), (char *) buf, len, MSG_NONBLOCKING); } + MG_VERBOSE(("%lu %ld %d", c->id, n, MG_SOCK_ERR(n))); + if (MG_SOCK_PENDING(n)) return MG_IO_WAIT; + if (MG_SOCK_RESET(n)) return MG_IO_RESET; + if (n <= 0) return MG_IO_ERR; + return n; } -static struct mg_str stripquotes(struct mg_str s) { - return s.len > 1 && s.ptr[0] == '"' && s.ptr[s.len - 1] == '"' - ? mg_str_n(s.ptr + 1, s.len - 2) - : s; +static bool ioalloc(struct mg_connection *c, struct mg_iobuf *io) { + bool res = false; + if (io->len >= MG_MAX_RECV_SIZE) { + mg_error(c, "MG_MAX_RECV_SIZE"); + } else if (io->size <= io->len && + !mg_iobuf_resize(io, io->size + MG_IO_SIZE)) { + mg_error(c, "OOM"); + } else { + res = true; + } + return res; } -struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v) { - size_t i; - for (i = 0; v.len > 0 && i + v.len + 2 < s.len; i++) { - if (s.ptr[i + v.len] == '=' && memcmp(&s.ptr[i], v.ptr, v.len) == 0) { - const char *p = &s.ptr[i + v.len + 1], *b = p, *x = &s.ptr[s.len]; - int q = p < x && *p == '"' ? 1 : 0; - while (p < x && - (q ? p == b || *p != '"' : *p != ';' && *p != ' ' && *p != ',')) - p++; - // MG_INFO(("[%.*s] [%.*s] [%.*s]", (int) s.len, s.ptr, (int) v.len, - // v.ptr, (int) (p - b), b)); - return stripquotes(mg_str_n(b, (size_t) (p - b + q))); +// NOTE(lsm): do only one iteration of reads, cause some systems +// (e.g. FreeRTOS stack) return 0 instead of -1/EWOULDBLOCK when no data +static void read_conn(struct mg_connection *c) { + if (ioalloc(c, &c->recv)) { + char *buf = (char *) &c->recv.buf[c->recv.len]; + size_t len = c->recv.size - c->recv.len; + long n = -1; + if (c->is_tls) { + if (!ioalloc(c, &c->rtls)) return; + n = recv_raw(c, (char *) &c->rtls.buf[c->rtls.len], + c->rtls.size - c->rtls.len); + if (n == MG_IO_ERR && c->rtls.len == 0) { + // Close only if we have fully drained both raw (rtls) and TLS buffers + c->is_closing = 1; + } else { + if (n > 0) c->rtls.len += (size_t) n; + if (c->is_tls_hs) mg_tls_handshake(c); + n = c->is_tls_hs ? (long) MG_IO_WAIT : mg_tls_recv(c, buf, len); + } + } else { + n = recv_raw(c, buf, len); } + MG_DEBUG(("%lu %ld %lu:%lu:%lu %ld err %d", c->id, c->fd, c->send.len, + c->recv.len, c->rtls.len, n, MG_SOCK_ERR(n))); + iolog(c, buf, n, true); } - return mg_str_n(NULL, 0); } -bool mg_http_match_uri(const struct mg_http_message *hm, const char *glob) { - return mg_match(hm->uri, mg_str(glob), NULL); +static void write_conn(struct mg_connection *c) { + char *buf = (char *) c->send.buf; + size_t len = c->send.len; + long n = c->is_tls ? mg_tls_send(c, buf, len) : mg_io_send(c, buf, len); + MG_DEBUG(("%lu %ld snd %ld/%ld rcv %ld/%ld n=%ld err=%d", c->id, c->fd, + (long) c->send.len, (long) c->send.size, (long) c->recv.len, + (long) c->recv.size, n, MG_SOCK_ERR(n))); + iolog(c, buf, n, false); } -long mg_http_upload(struct mg_connection *c, struct mg_http_message *hm, - struct mg_fs *fs, const char *path, size_t max_size) { - char buf[20] = "0"; - long res = 0, offset; - mg_http_get_var(&hm->query, "offset", buf, sizeof(buf)); - offset = strtol(buf, NULL, 0); - if (hm->body.len == 0) { - mg_http_reply(c, 200, "", "%ld", res); // Nothing to write +static void close_conn(struct mg_connection *c) { + if (FD(c) != MG_INVALID_SOCKET) { +#if MG_ENABLE_EPOLL + epoll_ctl(c->mgr->epoll_fd, EPOLL_CTL_DEL, FD(c), NULL); +#endif + closesocket(FD(c)); +#if MG_ENABLE_FREERTOS_TCP + FreeRTOS_FD_CLR(c->fd, c->mgr->ss, eSELECT_ALL); +#endif + } + mg_close_conn(c); +} + +static void connect_conn(struct mg_connection *c) { + union usa usa; + socklen_t n = sizeof(usa); + // Use getpeername() to test whether we have connected + if (getpeername(FD(c), &usa.sa, &n) == 0) { + c->is_connecting = 0; + setlocaddr(FD(c), &c->loc); + mg_call(c, MG_EV_CONNECT, NULL); + MG_EPOLL_MOD(c, 0); + if (c->is_tls_hs) mg_tls_handshake(c); } else { - struct mg_fd *fd; - size_t current_size = 0; - MG_DEBUG(("%s -> %d bytes @ %ld", path, (int) hm->body.len, offset)); - if (offset == 0) fs->rm(path); // If offset if 0, truncate file - fs->st(path, ¤t_size, NULL); - if (offset < 0) { - mg_http_reply(c, 400, "", "offset required"); - res = -1; - } else if (offset > 0 && current_size != (size_t) offset) { - mg_http_reply(c, 400, "", "%s: offset mismatch", path); - res = -2; - } else if ((size_t) offset + hm->body.len > max_size) { - mg_http_reply(c, 400, "", "%s: over max size of %lu", path, - (unsigned long) max_size); - res = -3; - } else if ((fd = mg_fs_open(fs, path, MG_FS_WRITE)) == NULL) { - mg_http_reply(c, 400, "", "open(%s): %d", path, errno); - res = -4; + mg_error(c, "socket error"); + } +} + +static void setsockopts(struct mg_connection *c) { +#if MG_ENABLE_FREERTOS_TCP || MG_ARCH == MG_ARCH_AZURERTOS || \ + MG_ARCH == MG_ARCH_TIRTOS + (void) c; +#else + int on = 1; +#if !defined(SOL_TCP) +#define SOL_TCP IPPROTO_TCP +#endif + if (setsockopt(FD(c), SOL_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) != 0) + (void) 0; + if (setsockopt(FD(c), SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)) != + 0) + (void) 0; +#endif +} + +void mg_connect_resolved(struct mg_connection *c) { + int type = c->is_udp ? SOCK_DGRAM : SOCK_STREAM; + int rc, af = c->rem.is_ip6 ? AF_INET6 : AF_INET; // c->rem has resolved IP + c->fd = S2PTR(socket(af, type, 0)); // Create outbound socket + c->is_resolving = 0; // Clear resolving flag + if (FD(c) == MG_INVALID_SOCKET) { + mg_error(c, "socket(): %d", MG_SOCK_ERR(-1)); + } else if (c->is_udp) { + MG_EPOLL_ADD(c); +#if MG_ARCH == MG_ARCH_TIRTOS + union usa usa; // TI-RTOS NDK requires binding to receive on UDP sockets + socklen_t slen = tousa(&c->loc, &usa); + if ((rc = bind(c->fd, &usa.sa, slen)) != 0) + MG_ERROR(("bind: %d", MG_SOCK_ERR(rc))); +#endif + setlocaddr(FD(c), &c->loc); + mg_call(c, MG_EV_RESOLVE, NULL); + mg_call(c, MG_EV_CONNECT, NULL); + } else { + union usa usa; + socklen_t slen = tousa(&c->rem, &usa); + mg_set_non_blocking_mode(FD(c)); + setsockopts(c); + MG_EPOLL_ADD(c); + mg_call(c, MG_EV_RESOLVE, NULL); + rc = connect(FD(c), &usa.sa, slen); // Attempt to connect + if (rc == 0) { // Success + setlocaddr(FD(c), &c->loc); + mg_call(c, MG_EV_CONNECT, NULL); // Send MG_EV_CONNECT to the user + } else if (MG_SOCK_PENDING(rc)) { // Need to wait for TCP handshake + MG_DEBUG(("%lu %ld -> %M pend", c->id, c->fd, mg_print_ip_port, &c->rem)); + c->is_connecting = 1; } else { - res = offset + (long) fs->wr(fd->fd, hm->body.ptr, hm->body.len); - mg_fs_close(fd); - mg_http_reply(c, 200, "", "%ld", res); + mg_error(c, "connect: %d", MG_SOCK_ERR(rc)); } } - return res; -} - -int mg_http_status(const struct mg_http_message *hm) { - return atoi(hm->uri.ptr); -} - -// If a server sends data to the client using chunked encoding, Mongoose strips -// off the chunking prefix (hex length and \r\n) and suffix (\r\n), appends the -// stripped data to the body, and fires the MG_EV_HTTP_CHUNK event. When zero -// chunk is received, we fire MG_EV_HTTP_MSG, and the body already has all -// chunking prefixes/suffixes stripped. -// -// If a server sends data without chunked encoding, we also fire a series of -// MG_EV_HTTP_CHUNK events for every received piece of data, and then we fire -// MG_EV_HTTP_MSG event in the end. -// -// We track total processed length in the c->pfn_data, which is a void * -// pointer: we store a size_t value there. -static bool getchunk(struct mg_str s, size_t *prefixlen, size_t *datalen) { - size_t i = 0, n; - while (i < s.len && s.ptr[i] != '\r' && s.ptr[i] != '\n') i++; - n = mg_unhexn(s.ptr, i); - // MG_INFO(("%d %d", (int) (i + n + 4), (int) s.len)); - if (s.len < i + n + 4) return false; // Chunk not yet fully buffered - if (s.ptr[i] != '\r' || s.ptr[i + 1] != '\n') return false; - if (s.ptr[i + n + 2] != '\r' || s.ptr[i + n + 3] != '\n') return false; - *prefixlen = i + 2; - *datalen = n; - return true; } -static bool mg_is_chunked(struct mg_http_message *hm) { - const char *needle = "chunked"; - struct mg_str *te = mg_http_get_header(hm, "Transfer-Encoding"); - return te != NULL && mg_vcasecmp(te, needle) == 0; -} - -void mg_http_delete_chunk(struct mg_connection *c, struct mg_http_message *hm) { - size_t ofs = (size_t) (hm->chunk.ptr - (char *) c->recv.buf); - mg_iobuf_del(&c->recv, ofs, hm->chunk.len); - c->pfn_data = (void *) ((size_t) c->pfn_data | MG_DMARK); -} - -static void deliver_chunked_chunks(struct mg_connection *c, size_t hlen, - struct mg_http_message *hm, bool *next) { - // | ... headers ... | HEXNUM\r\n ..data.. \r\n | ...... - // +------------------+--------------------------+---- - // | hlen | chunk1 | ...... - char *buf = (char *) &c->recv.buf[hlen], *p = buf; - size_t len = c->recv.len - hlen; - size_t processed = ((size_t) c->pfn_data) & ~MG_DMARK; - size_t mark, pl, dl, del = 0, ofs = 0; - bool last = false; - if (processed <= len) len -= processed, buf += processed; - while (!last && getchunk(mg_str_n(buf + ofs, len - ofs), &pl, &dl)) { - size_t saved = c->recv.len; - memmove(p + processed, buf + ofs + pl, dl); - // MG_INFO(("P2 [%.*s]", (int) (processed + dl), p)); - hm->chunk = mg_str_n(p + processed, dl); - mg_call(c, MG_EV_HTTP_CHUNK, hm); - ofs += pl + dl + 2, del += pl + 2; // 2 is for \r\n suffix - processed += dl; - if (c->recv.len != saved) processed -= dl, buf -= dl; - // mg_hexdump(c->recv.buf, hlen + processed); - last = (dl == 0); - } - mg_iobuf_del(&c->recv, hlen + processed, del); - mark = ((size_t) c->pfn_data) & MG_DMARK; - c->pfn_data = (void *) (processed | mark); - if (last) { - hm->body.len = processed; - hm->message.len = hlen + processed; - c->pfn_data = NULL; - if (mark) mg_iobuf_del(&c->recv, 0, hlen), *next = true; - // MG_INFO(("LAST, mark: %lx", mark)); - // mg_hexdump(c->recv.buf, c->recv.len); - } +static MG_SOCKET_TYPE raccept(MG_SOCKET_TYPE sock, union usa *usa, + socklen_t *len) { + MG_SOCKET_TYPE fd = MG_INVALID_SOCKET; + do { + memset(usa, 0, sizeof(*usa)); + fd = accept(sock, &usa->sa, len); + } while (MG_SOCK_INTR(fd)); + return fd; } -static void deliver_normal_chunks(struct mg_connection *c, size_t hlen, - struct mg_http_message *hm, bool *next) { - size_t left, processed = ((size_t) c->pfn_data) & ~MG_DMARK; - size_t deleted = ((size_t) c->pfn_data) & MG_DMARK; - hm->chunk = mg_str_n((char *) &c->recv.buf[hlen], c->recv.len - hlen); - if (processed <= hm->chunk.len && !deleted) { - hm->chunk.len -= processed; - hm->chunk.ptr += processed; - } - left = hm->body.len < processed ? 0 : hm->body.len - processed; - if (hm->chunk.len > left) hm->chunk.len = left; - if (hm->chunk.len > 0) mg_call(c, MG_EV_HTTP_CHUNK, hm); - processed += hm->chunk.len; - deleted = ((size_t) c->pfn_data) & MG_DMARK; // Re-evaluate after user call - if (processed >= hm->body.len) { // Last, 0-len chunk - hm->chunk.len = 0; // Reset length - mg_call(c, MG_EV_HTTP_CHUNK, hm); // Call user handler - c->pfn_data = NULL; // Reset processed counter - if (processed && deleted) mg_iobuf_del(&c->recv, 0, hlen), *next = true; +static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) { + struct mg_connection *c = NULL; + union usa usa; + socklen_t sa_len = sizeof(usa); + MG_SOCKET_TYPE fd = raccept(FD(lsn), &usa, &sa_len); + if (fd == MG_INVALID_SOCKET) { +#if MG_ARCH == MG_ARCH_AZURERTOS || defined(__ECOS) + // AzureRTOS, in non-block socket mode can mark listening socket readable + // even it is not. See comment for 'select' func implementation in + // nx_bsd.c That's not an error, just should try later + if (errno != EAGAIN) +#endif + MG_ERROR(("%lu accept failed, errno %d", lsn->id, MG_SOCK_ERR(-1))); +#if (MG_ARCH != MG_ARCH_WIN32) && !MG_ENABLE_FREERTOS_TCP && \ + (MG_ARCH != MG_ARCH_TIRTOS) && !MG_ENABLE_POLL && !MG_ENABLE_EPOLL + } else if ((long) fd >= FD_SETSIZE) { + MG_ERROR(("%ld > %ld", (long) fd, (long) FD_SETSIZE)); + closesocket(fd); +#endif + } else if ((c = mg_alloc_conn(mgr)) == NULL) { + MG_ERROR(("%lu OOM", lsn->id)); + closesocket(fd); } else { - c->pfn_data = (void *) (processed | deleted); // if it is set + tomgaddr(&usa, &c->rem, sa_len != sizeof(usa.sin)); + LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c); + c->fd = S2PTR(fd); + MG_EPOLL_ADD(c); + mg_set_non_blocking_mode(FD(c)); + setsockopts(c); + c->is_accepted = 1; + c->is_hexdumping = lsn->is_hexdumping; + c->loc = lsn->loc; + c->pfn = lsn->pfn; + c->pfn_data = lsn->pfn_data; + c->fn = lsn->fn; + c->fn_data = lsn->fn_data; + MG_DEBUG(("%lu %ld accepted %M -> %M", c->id, c->fd, mg_print_ip_port, + &c->rem, mg_print_ip_port, &c->loc)); + mg_call(c, MG_EV_OPEN, NULL); + mg_call(c, MG_EV_ACCEPT, NULL); } } -static void http_cb(struct mg_connection *c, int ev, void *evd, void *fnd) { - if (ev == MG_EV_READ || ev == MG_EV_CLOSE) { - struct mg_http_message hm; - // mg_hexdump(c->recv.buf, c->recv.len); - while (c->recv.buf != NULL && c->recv.len > 0) { - bool next = false; - int hlen = mg_http_parse((char *) c->recv.buf, c->recv.len, &hm); - if (hlen < 0) { - mg_error(c, "HTTP parse:\n%.*s", (int) c->recv.len, c->recv.buf); - break; - } - if (c->is_resp) break; // Response is still generated - if (hlen == 0) break; // Request is not buffered yet - if (ev == MG_EV_CLOSE) { // If client did not set Content-Length - hm.message.len = c->recv.len; // and closes now, deliver a MSG - hm.body.len = hm.message.len - (size_t) (hm.body.ptr - hm.message.ptr); - } - if (mg_is_chunked(&hm)) { - deliver_chunked_chunks(c, (size_t) hlen, &hm, &next); - } else { - deliver_normal_chunks(c, (size_t) hlen, &hm, &next); - } - if (next) continue; // Chunks & request were deleted - // Chunk events are delivered. If we have full body, deliver MSG - if (c->recv.len < hm.message.len) break; - if (c->is_accepted) c->is_resp = 1; // Start generating response - mg_call(c, MG_EV_HTTP_MSG, &hm); // User handler can clear is_resp - mg_iobuf_del(&c->recv, 0, hm.message.len); - } - } - (void) evd, (void) fnd; +static bool can_read(const struct mg_connection *c) { + return c->is_full == false; } -struct mg_connection *mg_http_connect(struct mg_mgr *mgr, const char *url, - mg_event_handler_t fn, void *fn_data) { - struct mg_connection *c = mg_connect(mgr, url, fn, fn_data); - if (c != NULL) c->pfn = http_cb; - return c; +static bool can_write(const struct mg_connection *c) { + return c->is_connecting || (c->send.len > 0 && c->is_tls_hs == 0); } -struct mg_connection *mg_http_listen(struct mg_mgr *mgr, const char *url, - mg_event_handler_t fn, void *fn_data) { - struct mg_connection *c = mg_listen(mgr, url, fn, fn_data); - if (c != NULL) c->pfn = http_cb; - return c; +static bool skip_iotest(const struct mg_connection *c) { + return (c->is_closing || c->is_resolving || FD(c) == MG_INVALID_SOCKET) || + (can_read(c) == false && can_write(c) == false); } -#ifdef MG_ENABLE_LINES -#line 1 "src/iobuf.c" -#endif - - - - -// Not using memset for zeroing memory, cause it can be dropped by compiler -// See https://github.com/cesanta/mongoose/pull/1265 -static void zeromem(volatile unsigned char *buf, size_t len) { - if (buf != NULL) { - while (len--) *buf++ = 0; +static void mg_iotest(struct mg_mgr *mgr, int ms) { +#if MG_ENABLE_FREERTOS_TCP + struct mg_connection *c; + for (c = mgr->conns; c != NULL; c = c->next) { + c->is_readable = c->is_writable = 0; + if (skip_iotest(c)) continue; + if (can_read(c)) + FreeRTOS_FD_SET(c->fd, mgr->ss, eSELECT_READ | eSELECT_EXCEPT); + if (can_write(c)) FreeRTOS_FD_SET(c->fd, mgr->ss, eSELECT_WRITE); + if (c->is_closing) ms = 1; } -} - -static size_t roundup(size_t size, size_t align) { - return align == 0 ? size : (size + align - 1) / align * align; -} - -int mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) { - int ok = 1; - new_size = roundup(new_size, io->align); - if (new_size == 0) { - zeromem(io->buf, io->size); - free(io->buf); - io->buf = NULL; - io->len = io->size = 0; - } else if (new_size != io->size) { - // NOTE(lsm): do not use realloc here. Use calloc/free only, to ease the - // porting to some obscure platforms like FreeRTOS - void *p = calloc(1, new_size); - if (p != NULL) { - size_t len = new_size < io->len ? new_size : io->len; - if (len > 0 && io->buf != NULL) memmove(p, io->buf, len); - zeromem(io->buf, io->size); - free(io->buf); - io->buf = (unsigned char *) p; - io->size = new_size; + FreeRTOS_select(mgr->ss, pdMS_TO_TICKS(ms)); + for (c = mgr->conns; c != NULL; c = c->next) { + EventBits_t bits = FreeRTOS_FD_ISSET(c->fd, mgr->ss); + c->is_readable = bits & (eSELECT_READ | eSELECT_EXCEPT) ? 1U : 0; + c->is_writable = bits & eSELECT_WRITE ? 1U : 0; + if (c->fd != MG_INVALID_SOCKET) + FreeRTOS_FD_CLR(c->fd, mgr->ss, + eSELECT_READ | eSELECT_EXCEPT | eSELECT_WRITE); + } +#elif MG_ENABLE_EPOLL + size_t max = 1; + for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) { + c->is_readable = c->is_writable = 0; + if (c->rtls.len > 0 || mg_tls_pending(c) > 0) ms = 1, c->is_readable = 1; + if (can_write(c)) MG_EPOLL_MOD(c, 1); + if (c->is_closing) ms = 1; + max++; + } + struct epoll_event *evs = (struct epoll_event *) alloca(max * sizeof(evs[0])); + int n = epoll_wait(mgr->epoll_fd, evs, (int) max, ms); + for (int i = 0; i < n; i++) { + struct mg_connection *c = (struct mg_connection *) evs[i].data.ptr; + if (evs[i].events & EPOLLERR) { + mg_error(c, "socket error"); + } else if (c->is_readable == 0) { + bool rd = evs[i].events & (EPOLLIN | EPOLLHUP); + bool wr = evs[i].events & EPOLLOUT; + c->is_readable = can_read(c) && rd ? 1U : 0; + c->is_writable = can_write(c) && wr ? 1U : 0; + if (c->rtls.len > 0 || mg_tls_pending(c) > 0) c->is_readable = 1; + } + } + (void) skip_iotest; +#elif MG_ENABLE_POLL + nfds_t n = 0; + for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) n++; + struct pollfd *fds = (struct pollfd *) alloca(n * sizeof(fds[0])); + memset(fds, 0, n * sizeof(fds[0])); + n = 0; + for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) { + c->is_readable = c->is_writable = 0; + if (skip_iotest(c)) { + // Socket not valid, ignore + } else if (c->rtls.len > 0 || mg_tls_pending(c) > 0) { + ms = 1; // Don't wait if TLS is ready } else { - ok = 0; - MG_ERROR(("%lld->%lld", (uint64_t) io->size, (uint64_t) new_size)); + fds[n].fd = FD(c); + if (can_read(c)) fds[n].events |= POLLIN; + if (can_write(c)) fds[n].events |= POLLOUT; + if (c->is_closing) ms = 1; + n++; } } - return ok; -} - -int mg_iobuf_init(struct mg_iobuf *io, size_t size, size_t align) { - io->buf = NULL; - io->align = align; - io->size = io->len = 0; - return mg_iobuf_resize(io, size); -} -size_t mg_iobuf_add(struct mg_iobuf *io, size_t ofs, const void *buf, - size_t len) { - size_t new_size = roundup(io->len + len, io->align); - mg_iobuf_resize(io, new_size); // Attempt to resize - if (new_size != io->size) len = 0; // Resize failure, append nothing - if (ofs < io->len) memmove(io->buf + ofs + len, io->buf + ofs, io->len - ofs); - if (buf != NULL) memmove(io->buf + ofs, buf, len); - if (ofs > io->len) io->len += ofs - io->len; - io->len += len; - return len; -} + // MG_INFO(("poll n=%d ms=%d", (int) n, ms)); + if (poll(fds, n, ms) < 0) { +#if MG_ARCH == MG_ARCH_WIN32 + if (n == 0) Sleep(ms); // On Windows, poll fails if no sockets +#endif + memset(fds, 0, n * sizeof(fds[0])); + } + n = 0; + for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) { + if (skip_iotest(c)) { + // Socket not valid, ignore + } else if (c->rtls.len > 0 || mg_tls_pending(c) > 0) { + c->is_readable = 1; + } else { + if (fds[n].revents & POLLERR) { + mg_error(c, "socket error"); + } else { + c->is_readable = + (unsigned) (fds[n].revents & (POLLIN | POLLHUP) ? 1 : 0); + c->is_writable = (unsigned) (fds[n].revents & POLLOUT ? 1 : 0); + if (c->rtls.len > 0 || mg_tls_pending(c) > 0) c->is_readable = 1; + } + n++; + } + } +#else + struct timeval tv = {ms / 1000, (ms % 1000) * 1000}, tv_zero = {0, 0}, *tvp; + struct mg_connection *c; + fd_set rset, wset, eset; + MG_SOCKET_TYPE maxfd = 0; + int rc; -size_t mg_iobuf_del(struct mg_iobuf *io, size_t ofs, size_t len) { - if (ofs > io->len) ofs = io->len; - if (ofs + len > io->len) len = io->len - ofs; - if (io->buf) memmove(io->buf + ofs, io->buf + ofs + len, io->len - ofs - len); - if (io->buf) zeromem(io->buf + io->len - len, len); - io->len -= len; - return len; -} + FD_ZERO(&rset); + FD_ZERO(&wset); + FD_ZERO(&eset); + tvp = ms < 0 ? NULL : &tv; + for (c = mgr->conns; c != NULL; c = c->next) { + c->is_readable = c->is_writable = 0; + if (skip_iotest(c)) continue; + FD_SET(FD(c), &eset); + if (can_read(c)) FD_SET(FD(c), &rset); + if (can_write(c)) FD_SET(FD(c), &wset); + if (c->rtls.len > 0 || mg_tls_pending(c) > 0) tvp = &tv_zero; + if (FD(c) > maxfd) maxfd = FD(c); + if (c->is_closing) ms = 1; + } -void mg_iobuf_free(struct mg_iobuf *io) { - mg_iobuf_resize(io, 0); -} + if ((rc = select((int) maxfd + 1, &rset, &wset, &eset, tvp)) < 0) { +#if MG_ARCH == MG_ARCH_WIN32 + if (maxfd == 0) Sleep(ms); // On Windows, select fails if no sockets +#else + MG_ERROR(("select: %d %d", rc, MG_SOCK_ERR(rc))); +#endif + FD_ZERO(&rset); + FD_ZERO(&wset); + FD_ZERO(&eset); + } -#ifdef MG_ENABLE_LINES -#line 1 "src/json.c" + for (c = mgr->conns; c != NULL; c = c->next) { + if (FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &eset)) { + mg_error(c, "socket error"); + } else { + c->is_readable = FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &rset); + c->is_writable = FD(c) != MG_INVALID_SOCKET && FD_ISSET(FD(c), &wset); + if (c->rtls.len > 0 || mg_tls_pending(c) > 0) c->is_readable = 1; + } + } #endif +} +static bool mg_socketpair(MG_SOCKET_TYPE sp[2], union usa usa[2]) { + socklen_t n = sizeof(usa[0].sin); + bool success = false; + sp[0] = sp[1] = MG_INVALID_SOCKET; + (void) memset(&usa[0], 0, sizeof(usa[0])); + usa[0].sin.sin_family = AF_INET; + *(uint32_t *) &usa->sin.sin_addr = mg_htonl(0x7f000001U); // 127.0.0.1 + usa[1] = usa[0]; - -static const char *escapeseq(int esc) { - return esc ? "\b\f\n\r\t\\\"" : "bfnrt\\\""; + if ((sp[0] = socket(AF_INET, SOCK_DGRAM, 0)) != MG_INVALID_SOCKET && + (sp[1] = socket(AF_INET, SOCK_DGRAM, 0)) != MG_INVALID_SOCKET && + bind(sp[0], &usa[0].sa, n) == 0 && // + bind(sp[1], &usa[1].sa, n) == 0 && // + getsockname(sp[0], &usa[0].sa, &n) == 0 && // + getsockname(sp[1], &usa[1].sa, &n) == 0 && // + connect(sp[0], &usa[1].sa, n) == 0 && // + connect(sp[1], &usa[0].sa, n) == 0) { // + success = true; + } + if (!success) { + if (sp[0] != MG_INVALID_SOCKET) closesocket(sp[0]); + if (sp[1] != MG_INVALID_SOCKET) closesocket(sp[1]); + sp[0] = sp[1] = MG_INVALID_SOCKET; + } + return success; } -static char json_esc(int c, int esc) { - const char *p, *esc1 = escapeseq(esc), *esc2 = escapeseq(!esc); - for (p = esc1; *p != '\0'; p++) { - if (*p == c) return esc2[p - esc1]; +// mg_wakeup() event handler +static void wufn(struct mg_connection *c, int ev, void *ev_data) { + if (ev == MG_EV_READ) { + unsigned long *id = (unsigned long *) c->recv.buf; + // MG_INFO(("Got data")); + // mg_hexdump(c->recv.buf, c->recv.len); + if (c->recv.len >= sizeof(*id)) { + struct mg_connection *t; + for (t = c->mgr->conns; t != NULL; t = t->next) { + if (t->id == *id) { + struct mg_str data = mg_str_n((char *) c->recv.buf + sizeof(*id), + c->recv.len - sizeof(*id)); + mg_call(t, MG_EV_WAKEUP, &data); + } + } + } + c->recv.len = 0; // Consume received data + } else if (ev == MG_EV_CLOSE) { + closesocket(c->mgr->pipe); // When we're closing, close the other + c->mgr->pipe = MG_INVALID_SOCKET; // side of the socketpair, too } - return 0; + (void) ev_data; } -static int mg_pass_string(const char *s, int len) { - int i; - for (i = 0; i < len; i++) { - if (s[i] == '\\' && i + 1 < len && json_esc(s[i + 1], 1)) { - i++; - } else if (s[i] == '\0') { - return MG_JSON_INVALID; - } else if (s[i] == '"') { - return i; +bool mg_wakeup_init(struct mg_mgr *mgr) { + bool ok = false; + if (mgr->pipe == MG_INVALID_SOCKET) { + union usa usa[2]; + MG_SOCKET_TYPE sp[2] = {MG_INVALID_SOCKET, MG_INVALID_SOCKET}; + struct mg_connection *c = NULL; + if (!mg_socketpair(sp, usa)) { + MG_ERROR(("Cannot create socket pair")); + } else if ((c = mg_wrapfd(mgr, (int) sp[1], wufn, NULL)) == NULL) { + closesocket(sp[0]); + closesocket(sp[1]); + sp[0] = sp[1] = MG_INVALID_SOCKET; + } else { + tomgaddr(&usa[0], &c->rem, false); + MG_DEBUG(("%lu %p pipe %lu", c->id, c->fd, (unsigned long) sp[0])); + mgr->pipe = sp[0]; + ok = true; } } - return MG_JSON_INVALID; + return ok; } -static double mg_atod(const char *p, int len, int *numlen) { - double d = 0.0; - int i = 0, sign = 1; - - // Sign - if (i < len && *p == '-') { - sign = -1, i++; - } else if (i < len && *p == '+') { - i++; +bool mg_wakeup(struct mg_mgr *mgr, unsigned long conn_id, const void *buf, + size_t len) { + if (mgr->pipe != MG_INVALID_SOCKET && conn_id > 0) { + char *extended_buf = (char *) alloca(len + sizeof(conn_id)); + memcpy(extended_buf, &conn_id, sizeof(conn_id)); + memcpy(extended_buf + sizeof(conn_id), buf, len); + send(mgr->pipe, extended_buf, len + sizeof(conn_id), MSG_NONBLOCKING); + return true; } + return false; +} - // Decimal - for (; i < len && p[i] >= '0' && p[i] <= '9'; i++) { - d *= 10.0; - d += p[i] - '0'; - } - d *= sign; +void mg_mgr_poll(struct mg_mgr *mgr, int ms) { + struct mg_connection *c, *tmp; + uint64_t now; - // Fractional - if (i < len && p[i] == '.') { - double frac = 0.0, base = 0.1; - i++; - for (; i < len && p[i] >= '0' && p[i] <= '9'; i++) { - frac += base * (p[i] - '0'); - base /= 10.0; + mg_iotest(mgr, ms); + now = mg_millis(); + mg_timer_poll(&mgr->timers, now); + + for (c = mgr->conns; c != NULL; c = tmp) { + bool is_resp = c->is_resp; + tmp = c->next; + mg_call(c, MG_EV_POLL, &now); + if (is_resp && !c->is_resp) { + long n = 0; + mg_call(c, MG_EV_READ, &n); + } + MG_VERBOSE(("%lu %c%c %c%c%c%c%c %lu %lu", c->id, + c->is_readable ? 'r' : '-', c->is_writable ? 'w' : '-', + c->is_tls ? 'T' : 't', c->is_connecting ? 'C' : 'c', + c->is_tls_hs ? 'H' : 'h', c->is_resolving ? 'R' : 'r', + c->is_closing ? 'C' : 'c', mg_tls_pending(c), c->rtls.len)); + if (c->is_resolving || c->is_closing) { + // Do nothing + } else if (c->is_listening && c->is_udp == 0) { + if (c->is_readable) accept_conn(mgr, c); + } else if (c->is_connecting) { + if (c->is_readable || c->is_writable) connect_conn(c); + //} else if (c->is_tls_hs) { + // if ((c->is_readable || c->is_writable)) mg_tls_handshake(c); + } else { + if (c->is_readable) read_conn(c); + if (c->is_writable) write_conn(c); } - d += frac * sign; - } - // Exponential - if (i < len && (p[i] == 'e' || p[i] == 'E')) { - int j, exp = 0, minus = 0; - i++; - if (i < len && p[i] == '-') minus = 1, i++; - if (i < len && p[i] == '+') i++; - while (i < len && p[i] >= '0' && p[i] <= '9' && exp < 308) - exp = exp * 10 + (p[i++] - '0'); - if (minus) exp = -exp; - for (j = 0; j < exp; j++) d *= 10.0; - for (j = 0; j < -exp; j++) d /= 10.0; + if (c->is_draining && c->send.len == 0) c->is_closing = 1; + if (c->is_closing) close_conn(c); } - - if (numlen != NULL) *numlen = i; - return d; } +#endif -int mg_json_get(struct mg_str json, const char *path, int *toklen) { - const char *s = json.ptr; - int len = (int) json.len; - enum { S_VALUE, S_KEY, S_COLON, S_COMMA_OR_EOO } expecting = S_VALUE; - unsigned char nesting[MG_JSON_MAX_DEPTH]; - int i = 0; // Current offset in `s` - int j = 0; // Offset in `s` we're looking for (return value) - int depth = 0; // Current depth (nesting level) - int ed = 0; // Expected depth - int pos = 1; // Current position in `path` - int ci = -1, ei = -1; // Current and expected index in array +#ifdef MG_ENABLE_LINES +#line 1 "src/ssi.c" +#endif - if (toklen) *toklen = 0; - if (path[0] != '$') return MG_JSON_INVALID; -#define MG_CHECKRET(x) \ - do { \ - if (depth == ed && path[pos] == '\0' && ci == ei) { \ - if (toklen) *toklen = i - j + 1; \ - return j; \ - } \ - } while (0) -// In the ascii table, the distance between `[` and `]` is 2. -// Ditto for `{` and `}`. Hence +2 in the code below. -#define MG_EOO(x) \ - do { \ - if (depth == ed && ci != ei) return MG_JSON_NOT_FOUND; \ - if (c != nesting[depth - 1] + 2) return MG_JSON_INVALID; \ - depth--; \ - MG_CHECKRET(x); \ - } while (0) - for (i = 0; i < len; i++) { - unsigned char c = ((unsigned char *) s)[i]; - if (c == ' ' || c == '\t' || c == '\n' || c == '\r') continue; - switch (expecting) { - case S_VALUE: - // p("V %s [%.*s] %d %d %d %d\n", path, pos, path, depth, ed, ci, ei); - if (depth == ed) j = i; - if (c == '{') { - if (depth >= (int) sizeof(nesting)) return MG_JSON_TOO_DEEP; - if (depth == ed && path[pos] == '.' && ci == ei) { - // If we start the object, reset array indices - ed++, pos++, ci = ei = -1; - } - nesting[depth++] = c; - expecting = S_KEY; - break; - } else if (c == '[') { - if (depth >= (int) sizeof(nesting)) return MG_JSON_TOO_DEEP; - if (depth == ed && path[pos] == '[' && ei == ci) { - ed++, pos++, ci = 0; - for (ei = 0; path[pos] != ']' && path[pos] != '\0'; pos++) { - ei *= 10; - ei += path[pos] - '0'; - } - if (path[pos] != 0) pos++; - } - nesting[depth++] = c; - break; - } else if (c == ']' && depth > 0) { // Empty array - MG_EOO(']'); - } else if (c == 't' && i + 3 < len && memcmp(&s[i], "true", 4) == 0) { - i += 3; - } else if (c == 'n' && i + 3 < len && memcmp(&s[i], "null", 4) == 0) { - i += 3; - } else if (c == 'f' && i + 4 < len && memcmp(&s[i], "false", 5) == 0) { - i += 4; - } else if (c == '-' || ((c >= '0' && c <= '9'))) { - int numlen = 0; - mg_atod(&s[i], len - i, &numlen); - i += numlen - 1; - } else if (c == '"') { - int n = mg_pass_string(&s[i + 1], len - i - 1); - if (n < 0) return n; - i += n + 1; - } else { - return MG_JSON_INVALID; - } - MG_CHECKRET('V'); - if (depth == ed && ei >= 0) ci++; - expecting = S_COMMA_OR_EOO; - break; +#ifndef MG_MAX_SSI_DEPTH +#define MG_MAX_SSI_DEPTH 5 +#endif - case S_KEY: - if (c == '"') { - int n = mg_pass_string(&s[i + 1], len - i - 1); - if (n < 0) return n; - if (i + 1 + n >= len) return MG_JSON_NOT_FOUND; - if (depth < ed) return MG_JSON_NOT_FOUND; - if (depth == ed && path[pos - 1] != '.') return MG_JSON_NOT_FOUND; - // printf("K %s [%.*s] [%.*s] %d %d %d\n", path, pos, path, n, - // &s[i + 1], n, depth, ed); - // NOTE(cpq): in the check sequence below is important. - // strncmp() must go first: it fails fast if the remaining length of - // the path is smaller than `n`. - if (depth == ed && path[pos - 1] == '.' && - strncmp(&s[i + 1], &path[pos], (size_t) n) == 0 && - (path[pos + n] == '\0' || path[pos + n] == '.' || - path[pos + n] == '[')) { - pos += n; - } - i += n + 1; - expecting = S_COLON; - } else if (c == '}') { // Empty object - MG_EOO('}'); - expecting = S_COMMA_OR_EOO; - } else { - return MG_JSON_INVALID; - } - break; +#ifndef MG_SSI_BUFSIZ +#define MG_SSI_BUFSIZ 1024 +#endif - case S_COLON: - if (c == ':') { - expecting = S_VALUE; +#if MG_ENABLE_SSI +static char *mg_ssi(const char *path, const char *root, int depth) { + struct mg_iobuf b = {NULL, 0, 0, MG_IO_SIZE}; + FILE *fp = fopen(path, "rb"); + if (fp != NULL) { + char buf[MG_SSI_BUFSIZ], arg[sizeof(buf)]; + int ch, intag = 0; + size_t len = 0; + buf[0] = arg[0] = '\0'; + while ((ch = fgetc(fp)) != EOF) { + if (intag && ch == '>' && buf[len - 1] == '-' && buf[len - 2] == '-') { + buf[len++] = (char) (ch & 0xff); + buf[len] = '\0'; + if (sscanf(buf, " %#x %#x", s_txdesc[s_txno][1], tsr)); + if (!(s_txdesc[s_txno][1] & MG_BIT(31))) s_txdesc[s_txno][1] |= MG_BIT(31); + } + + GMAC_REGS->GMAC_RSR = rsr; + GMAC_REGS->GMAC_TSR = tsr; } -struct mip_driver mip_driver_w5500 = {w5500_init, w5500_tx, w5500_rx, w5500_up}; +struct mg_tcpip_driver mg_tcpip_driver_same54 = { + mg_tcpip_driver_same54_init, mg_tcpip_driver_same54_tx, NULL, + mg_tcpip_driver_same54_up}; #endif #ifdef MG_ENABLE_LINES -#line 1 "mip/mip.c" +#line 1 "src/drivers/stm32f.c" #endif -#if MG_ENABLE_MIP - -#define MIP_ETHEMERAL_PORT 49152 -#define U16(ptr) ((((uint16_t) (ptr)[0]) << 8) | (ptr)[1]) -#define PDIFF(a, b) ((size_t) (((char *) (b)) - ((char *) (a)))) - -#ifndef MIP_QSIZE -#define MIP_QSIZE (16 * 1024) // Queue size -#endif +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_STM32F) && \ + MG_ENABLE_DRIVER_STM32F +struct stm32f_eth { + volatile uint32_t MACCR, MACFFR, MACHTHR, MACHTLR, MACMIIAR, MACMIIDR, MACFCR, + MACVLANTR, RESERVED0[2], MACRWUFFR, MACPMTCSR, RESERVED1, MACDBGR, MACSR, + MACIMR, MACA0HR, MACA0LR, MACA1HR, MACA1LR, MACA2HR, MACA2LR, MACA3HR, + MACA3LR, RESERVED2[40], MMCCR, MMCRIR, MMCTIR, MMCRIMR, MMCTIMR, + RESERVED3[14], MMCTGFSCCR, MMCTGFMSCCR, RESERVED4[5], MMCTGFCR, + RESERVED5[10], MMCRFCECR, MMCRFAECR, RESERVED6[10], MMCRGUFCR, + RESERVED7[334], PTPTSCR, PTPSSIR, PTPTSHR, PTPTSLR, PTPTSHUR, PTPTSLUR, + PTPTSAR, PTPTTHR, PTPTTLR, RESERVED8, PTPTSSR, PTPPPSCR, RESERVED9[564], + DMABMR, DMATPDR, DMARPDR, DMARDLAR, DMATDLAR, DMASR, DMAOMR, DMAIER, + DMAMFBOCR, DMARSWTR, RESERVED10[8], DMACHTDR, DMACHRDR, DMACHTBAR, + DMACHRBAR; +}; +#undef ETH +#define ETH ((struct stm32f_eth *) (uintptr_t) 0x40028000) -#ifndef MIP_TCP_KEEPALIVE_MS -#define MIP_TCP_KEEPALIVE_MS 45000 // TCP keep-alive period, ms -#endif +#define ETH_PKT_SIZE 1540 // Max frame size +#define ETH_DESC_CNT 4 // Descriptors count +#define ETH_DS 4 // Descriptor size (words) -#define MIP_TCP_ACK_MS 150 // Timeout for ACKing +static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors +static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors +static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers +static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers +static uint8_t s_txno; // Current TX descriptor +static uint8_t s_rxno; // Current RX descriptor -struct connstate { - uint32_t seq, ack; // TCP seq/ack counters - uint64_t timer; // TCP keep-alive / ACK timer - uint8_t mac[6]; // Peer MAC address - uint8_t ttype; // Timer type. 0: ack, 1: keep-alive -#define MIP_TTYPE_KEEPALIVE 0 // Connection is idle for long, send keepalive -#define MIP_TTYPE_ACK 1 // Peer sent us data, we have to ack it soon - uint8_t tmiss; // Number of keep-alive misses - struct mg_iobuf raw; // For TLS only. Incoming raw data -}; +static struct mg_tcpip_if *s_ifp; // MIP interface -#pragma pack(push, 1) +static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) { + ETH->MACMIIAR &= (7 << 2); + ETH->MACMIIAR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6); + ETH->MACMIIAR |= MG_BIT(0); + while (ETH->MACMIIAR & MG_BIT(0)) (void) 0; + return ETH->MACMIIDR & 0xffff; +} -struct lcp { - uint8_t addr, ctrl, proto[2], code, id, len[2]; -}; +static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { + ETH->MACMIIDR = val; + ETH->MACMIIAR &= (7 << 2); + ETH->MACMIIAR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6) | MG_BIT(1); + ETH->MACMIIAR |= MG_BIT(0); + while (ETH->MACMIIAR & MG_BIT(0)) (void) 0; +} -struct eth { - uint8_t dst[6]; // Destination MAC address - uint8_t src[6]; // Source MAC address - uint16_t type; // Ethernet type -}; +static uint32_t get_hclk(void) { + struct rcc { + volatile uint32_t CR, PLLCFGR, CFGR; + } *rcc = (struct rcc *) 0x40023800; + uint32_t clk = 0, hsi = 16000000 /* 16 MHz */, hse = 8000000 /* 8MHz */; -struct ip { - uint8_t ver; // Version - uint8_t tos; // Unused - uint16_t len; // Length - uint16_t id; // Unused - uint16_t frag; // Fragmentation - uint8_t ttl; // Time to live - uint8_t proto; // Upper level protocol - uint16_t csum; // Checksum - uint32_t src; // Source IP - uint32_t dst; // Destination IP -}; + if (rcc->CFGR & (1 << 2)) { + clk = hse; + } else if (rcc->CFGR & (1 << 3)) { + uint32_t vco, m, n, p; + m = (rcc->PLLCFGR & (0x3f << 0)) >> 0; + n = (rcc->PLLCFGR & (0x1ff << 6)) >> 6; + p = (((rcc->PLLCFGR & (3 << 16)) >> 16) + 1) * 2; + clk = (rcc->PLLCFGR & (1 << 22)) ? hse : hsi; + vco = (uint32_t) ((uint64_t) clk * n / m); + clk = vco / p; + } else { + clk = hsi; + } + uint32_t hpre = (rcc->CFGR & (15 << 4)) >> 4; + if (hpre < 8) return clk; -struct ip6 { - uint8_t ver; // Version - uint8_t opts[3]; // Options - uint16_t len; // Length - uint8_t proto; // Upper level protocol - uint8_t ttl; // Time to live - uint8_t src[16]; // Source IP - uint8_t dst[16]; // Destination IP -}; + uint8_t ahbptab[8] = {1, 2, 3, 4, 6, 7, 8, 9}; // log2(div) + return ((uint32_t) clk) >> ahbptab[hpre - 8]; +} -struct icmp { - uint8_t type; - uint8_t code; - uint16_t csum; -}; +// Guess CR from HCLK. MDC clock is generated from HCLK (AHB); as per 802.3, +// it must not exceed 2.5MHz As the AHB clock can be (and usually is) derived +// from the HSI (internal RC), and it can go above specs, the datasheets +// specify a range of frequencies and activate one of a series of dividers to +// keep the MDC clock safely below 2.5MHz. We guess a divider setting based on +// HCLK with a +5% drift. If the user uses a different clock from our +// defaults, needs to set the macros on top Valid for STM32F74xxx/75xxx +// (38.8.1) and STM32F42xxx/43xxx (33.8.1) (both 4.5% worst case drift) +static int guess_mdc_cr(void) { + uint8_t crs[] = {2, 3, 0, 1, 4, 5}; // ETH->MACMIIAR::CR values + uint8_t div[] = {16, 26, 42, 62, 102, 124}; // Respective HCLK dividers + uint32_t hclk = get_hclk(); // Guess system HCLK + int result = -1; // Invalid CR value + if (hclk < 25000000) { + MG_ERROR(("HCLK too low")); + } else { + for (int i = 0; i < 6; i++) { + if (hclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) { + result = crs[i]; + break; + } + } + if (result < 0) MG_ERROR(("HCLK too high")); + } + MG_DEBUG(("HCLK: %u, CR: %d", hclk, result)); + return result; +} -struct arp { - uint16_t fmt; // Format of hardware address - uint16_t pro; // Format of protocol address - uint8_t hlen; // Length of hardware address - uint8_t plen; // Length of protocol address - uint16_t op; // Operation - uint8_t sha[6]; // Sender hardware address - uint32_t spa; // Sender protocol address - uint8_t tha[6]; // Target hardware address - uint32_t tpa; // Target protocol address -}; +static bool mg_tcpip_driver_stm32f_init(struct mg_tcpip_if *ifp) { + struct mg_tcpip_driver_stm32f_data *d = + (struct mg_tcpip_driver_stm32f_data *) ifp->driver_data; + uint8_t phy_addr = d == NULL ? 0 : d->phy_addr; + s_ifp = ifp; -struct tcp { - uint16_t sport; // Source port - uint16_t dport; // Destination port - uint32_t seq; // Sequence number - uint32_t ack; // Acknowledgement number - uint8_t off; // Data offset - uint8_t flags; // TCP flags -#define TH_FIN 0x01 -#define TH_SYN 0x02 -#define TH_RST 0x04 -#define TH_PUSH 0x08 -#define TH_ACK 0x10 -#define TH_URG 0x20 -#define TH_ECE 0x40 -#define TH_CWR 0x80 - uint16_t win; // Window - uint16_t csum; // Checksum - uint16_t urp; // Urgent pointer -}; + // Init RX descriptors + for (int i = 0; i < ETH_DESC_CNT; i++) { + s_rxdesc[i][0] = MG_BIT(31); // Own + s_rxdesc[i][1] = sizeof(s_rxbuf[i]) | MG_BIT(14); // 2nd address chained + s_rxdesc[i][2] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer + s_rxdesc[i][3] = + (uint32_t) (uintptr_t) s_rxdesc[(i + 1) % ETH_DESC_CNT]; // Chain + } -struct udp { - uint16_t sport; // Source port - uint16_t dport; // Destination port - uint16_t len; // UDP length - uint16_t csum; // UDP checksum -}; + // Init TX descriptors + for (int i = 0; i < ETH_DESC_CNT; i++) { + s_txdesc[i][2] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer + s_txdesc[i][3] = + (uint32_t) (uintptr_t) s_txdesc[(i + 1) % ETH_DESC_CNT]; // Chain + } -struct dhcp { - uint8_t op, htype, hlen, hops; - uint32_t xid; - uint16_t secs, flags; - uint32_t ciaddr, yiaddr, siaddr, giaddr; - uint8_t hwaddr[208]; - uint32_t magic; - uint8_t options[32]; -}; + ETH->DMABMR |= MG_BIT(0); // Software reset + while ((ETH->DMABMR & MG_BIT(0)) != 0) (void) 0; // Wait until done -#pragma pack(pop) + // Set MDC clock divider. If user told us the value, use it. Otherwise, guess + int cr = (d == NULL || d->mdc_cr < 0) ? guess_mdc_cr() : d->mdc_cr; + ETH->MACMIIAR = ((uint32_t) cr & 7) << 2; -struct pkt { - struct mg_str raw; // Raw packet data - struct mg_str pay; // Payload data - struct eth *eth; - struct llc *llc; - struct arp *arp; - struct ip *ip; - struct ip6 *ip6; - struct icmp *icmp; - struct tcp *tcp; - struct udp *udp; - struct dhcp *dhcp; -}; + // NOTE(cpq): we do not use extended descriptor bit 7, and do not use + // hardware checksum. Therefore, descriptor size is 4, not 8 + // ETH->DMABMR = MG_BIT(13) | MG_BIT(16) | MG_BIT(22) | MG_BIT(23) | + // MG_BIT(25); + ETH->MACIMR = MG_BIT(3) | MG_BIT(9); // Mask timestamp & PMT IT + ETH->MACFCR = MG_BIT(7); // Disable zero quarta pause + // ETH->MACFFR = MG_BIT(31); // Receive all + struct mg_phy phy = {eth_read_phy, eth_write_phy}; + mg_phy_init(&phy, phy_addr, MG_PHY_CLOCKS_MAC); + ETH->DMARDLAR = (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors + ETH->DMATDLAR = (uint32_t) (uintptr_t) s_txdesc; // RX descriptors + ETH->DMAIER = MG_BIT(6) | MG_BIT(16); // RIE, NISE + ETH->MACCR = + MG_BIT(2) | MG_BIT(3) | MG_BIT(11) | MG_BIT(14); // RE, TE, Duplex, Fast + ETH->DMAOMR = + MG_BIT(1) | MG_BIT(13) | MG_BIT(21) | MG_BIT(25); // SR, ST, TSF, RSF -static void q_copyin(struct queue *q, const uint8_t *buf, size_t len, - size_t head) { - size_t left = q->len - head; - memcpy(&q->buf[head], buf, left < len ? left : len); - if (left < len) memcpy(q->buf, &buf[left], len - left); + // MAC address filtering + ETH->MACA0HR = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4]; + ETH->MACA0LR = (uint32_t) (ifp->mac[3] << 24) | + ((uint32_t) ifp->mac[2] << 16) | + ((uint32_t) ifp->mac[1] << 8) | ifp->mac[0]; + return true; } -static void q_copyout(struct queue *q, uint8_t *buf, size_t len, size_t tail) { - size_t left = q->len - tail; - memcpy(buf, &q->buf[tail], left < len ? left : len); - if (left < len) memcpy(&buf[left], q->buf, len - left); +static size_t mg_tcpip_driver_stm32f_tx(const void *buf, size_t len, + struct mg_tcpip_if *ifp) { + if (len > sizeof(s_txbuf[s_txno])) { + MG_ERROR(("Frame too big, %ld", (long) len)); + len = 0; // Frame is too big + } else if ((s_txdesc[s_txno][0] & MG_BIT(31))) { + ifp->nerr++; + MG_ERROR(("No free descriptors")); + // printf("D0 %lx SR %lx\n", (long) s_txdesc[0][0], (long) ETH->DMASR); + len = 0; // All descriptors are busy, fail + } else { + memcpy(s_txbuf[s_txno], buf, len); // Copy data + s_txdesc[s_txno][1] = (uint32_t) len; // Set data len + s_txdesc[s_txno][0] = MG_BIT(20) | MG_BIT(28) | MG_BIT(29); // Chain,FS,LS + s_txdesc[s_txno][0] |= MG_BIT(31); // Set OWN bit - let DMA take over + if (++s_txno >= ETH_DESC_CNT) s_txno = 0; + } + MG_DSB(); // ensure descriptors have been written + ETH->DMASR = MG_BIT(2) | MG_BIT(5); // Clear any prior TBUS/TUS + ETH->DMATPDR = 0; // and resume + return len; } -static bool q_write(struct queue *q, const void *buf, size_t len) { - bool success = false; - size_t left = (q->len - q->head + q->tail - 1) % q->len; - if (len + sizeof(size_t) <= left) { - q_copyin(q, (uint8_t *) &len, sizeof(len), q->head); - q_copyin(q, (uint8_t *) buf, len, (q->head + sizeof(size_t)) % q->len); - q->head = (q->head + sizeof(len) + len) % q->len; - success = true; +static bool mg_tcpip_driver_stm32f_up(struct mg_tcpip_if *ifp) { + struct mg_tcpip_driver_stm32f_data *d = + (struct mg_tcpip_driver_stm32f_data *) ifp->driver_data; + uint8_t phy_addr = d == NULL ? 0 : d->phy_addr; + uint8_t speed = MG_PHY_SPEED_10M; + bool up = false, full_duplex = false; + struct mg_phy phy = {eth_read_phy, eth_write_phy}; + up = mg_phy_up(&phy, phy_addr, &full_duplex, &speed); + if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up + // tmp = reg with flags set to the most likely situation: 100M full-duplex + // if(link is slow or half) set flags otherwise + // reg = tmp + uint32_t maccr = ETH->MACCR | MG_BIT(14) | MG_BIT(11); // 100M, Full-duplex + if (speed == MG_PHY_SPEED_10M) maccr &= ~MG_BIT(14); // 10M + if (full_duplex == false) maccr &= ~MG_BIT(11); // Half-duplex + ETH->MACCR = maccr; // IRQ handler does not fiddle with this register + MG_DEBUG(("Link is %uM %s-duplex", maccr & MG_BIT(14) ? 100 : 10, + maccr & MG_BIT(11) ? "full" : "half")); } - return success; + return up; } -#ifdef MIP_QPROFILE -static inline size_t q_space(struct queue *q) { - return q->tail > q->head ? q->tail - q->head : q->tail + (q->len - q->head); +#ifdef __riscv +__attribute__((interrupt())) // For RISCV CH32V307, which share the same MAC +#endif +void ETH_IRQHandler(void); +void ETH_IRQHandler(void) { + if (ETH->DMASR & MG_BIT(6)) { // Frame received, loop + ETH->DMASR = MG_BIT(16) | MG_BIT(6); // Clear flag + for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever + if (s_rxdesc[s_rxno][0] & MG_BIT(31)) break; // exit when done + if (((s_rxdesc[s_rxno][0] & (MG_BIT(8) | MG_BIT(9))) == + (MG_BIT(8) | MG_BIT(9))) && + !(s_rxdesc[s_rxno][0] & MG_BIT(15))) { // skip partial/errored frames + uint32_t len = ((s_rxdesc[s_rxno][0] >> 16) & (MG_BIT(14) - 1)); + // printf("%lx %lu %lx %.8lx\n", s_rxno, len, s_rxdesc[s_rxno][0], + // ETH->DMASR); + mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp); + } + s_rxdesc[s_rxno][0] = MG_BIT(31); + if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; + } + } + // Cleanup flags + ETH->DMASR = MG_BIT(16) // NIS, normal interrupt summary + | MG_BIT(7); // Clear possible RBUS while processing + ETH->DMARPDR = 0; // and resume RX } + +struct mg_tcpip_driver mg_tcpip_driver_stm32f = { + mg_tcpip_driver_stm32f_init, mg_tcpip_driver_stm32f_tx, NULL, + mg_tcpip_driver_stm32f_up}; #endif -static inline size_t q_avail(struct queue *q) { - size_t n = 0; - if (q->tail != q->head) q_copyout(q, (uint8_t *) &n, sizeof(n), q->tail); - return n; -} +#ifdef MG_ENABLE_LINES +#line 1 "src/drivers/stm32h.c" +#endif -static size_t q_read(struct queue *q, void *buf) { - size_t n = q_avail(q); - if (n > 0) { - q_copyout(q, (uint8_t *) buf, n, (q->tail + sizeof(n)) % q->len); - q->tail = (q->tail + sizeof(n) + n) % q->len; - } - return n; -} -static struct mg_str mkstr(void *buf, size_t len) { - struct mg_str str = {(char *) buf, len}; - return str; -} +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_STM32H) && \ + MG_ENABLE_DRIVER_STM32H +struct stm32h_eth { + volatile uint32_t MACCR, MACECR, MACPFR, MACWTR, MACHT0R, MACHT1R, + RESERVED1[14], MACVTR, RESERVED2, MACVHTR, RESERVED3, MACVIR, MACIVIR, + RESERVED4[2], MACTFCR, RESERVED5[7], MACRFCR, RESERVED6[7], MACISR, + MACIER, MACRXTXSR, RESERVED7, MACPCSR, MACRWKPFR, RESERVED8[2], MACLCSR, + MACLTCR, MACLETR, MAC1USTCR, RESERVED9[12], MACVR, MACDR, RESERVED10, + MACHWF0R, MACHWF1R, MACHWF2R, RESERVED11[54], MACMDIOAR, MACMDIODR, + RESERVED12[2], MACARPAR, RESERVED13[59], MACA0HR, MACA0LR, MACA1HR, + MACA1LR, MACA2HR, MACA2LR, MACA3HR, MACA3LR, RESERVED14[248], MMCCR, + MMCRIR, MMCTIR, MMCRIMR, MMCTIMR, RESERVED15[14], MMCTSCGPR, MMCTMCGPR, + RESERVED16[5], MMCTPCGR, RESERVED17[10], MMCRCRCEPR, MMCRAEPR, + RESERVED18[10], MMCRUPGR, RESERVED19[9], MMCTLPIMSTR, MMCTLPITCR, + MMCRLPIMSTR, MMCRLPITCR, RESERVED20[65], MACL3L4C0R, MACL4A0R, + RESERVED21[2], MACL3A0R0R, MACL3A1R0R, MACL3A2R0R, MACL3A3R0R, + RESERVED22[4], MACL3L4C1R, MACL4A1R, RESERVED23[2], MACL3A0R1R, + MACL3A1R1R, MACL3A2R1R, MACL3A3R1R, RESERVED24[108], MACTSCR, MACSSIR, + MACSTSR, MACSTNR, MACSTSUR, MACSTNUR, MACTSAR, RESERVED25, MACTSSR, + RESERVED26[3], MACTTSSNR, MACTTSSSR, RESERVED27[2], MACACR, RESERVED28, + MACATSNR, MACATSSR, MACTSIACR, MACTSEACR, MACTSICNR, MACTSECNR, + RESERVED29[4], MACPPSCR, RESERVED30[3], MACPPSTTSR, MACPPSTTNR, MACPPSIR, + MACPPSWR, RESERVED31[12], MACPOCR, MACSPI0R, MACSPI1R, MACSPI2R, MACLMIR, + RESERVED32[11], MTLOMR, RESERVED33[7], MTLISR, RESERVED34[55], MTLTQOMR, + MTLTQUR, MTLTQDR, RESERVED35[8], MTLQICSR, MTLRQOMR, MTLRQMPOCR, MTLRQDR, + RESERVED36[177], DMAMR, DMASBMR, DMAISR, DMADSR, RESERVED37[60], DMACCR, + DMACTCR, DMACRCR, RESERVED38[2], DMACTDLAR, RESERVED39, DMACRDLAR, + DMACTDTPR, RESERVED40, DMACRDTPR, DMACTDRLR, DMACRDRLR, DMACIER, + DMACRIWTR, DMACSFCSR, RESERVED41, DMACCATDR, RESERVED42, DMACCARDR, + RESERVED43, DMACCATBR, RESERVED44, DMACCARBR, DMACSR, RESERVED45[2], + DMACMFCR; +}; +#undef ETH +#define ETH \ + ((struct stm32h_eth *) (uintptr_t) (0x40000000UL + 0x00020000UL + 0x8000UL)) -static void mkpay(struct pkt *pkt, void *p) { - pkt->pay = mkstr(p, (size_t) (&pkt->raw.ptr[pkt->raw.len] - (char *) p)); +#define ETH_PKT_SIZE 1540 // Max frame size +#define ETH_DESC_CNT 4 // Descriptors count +#define ETH_DS 4 // Descriptor size (words) + +static volatile uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors +static volatile uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors +static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers +static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers +static struct mg_tcpip_if *s_ifp; // MIP interface + +static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) { + ETH->MACMDIOAR &= (0xF << 8); + ETH->MACMDIOAR |= ((uint32_t) addr << 21) | ((uint32_t) reg << 16) | 3 << 2; + ETH->MACMDIOAR |= MG_BIT(0); + while (ETH->MACMDIOAR & MG_BIT(0)) (void) 0; + return (uint16_t) ETH->MACMDIODR; } -static uint32_t csumup(uint32_t sum, const void *buf, size_t len) { - const uint8_t *p = (const uint8_t *) buf; - for (size_t i = 0; i < len; i++) sum += i & 1 ? p[i] : (uint32_t) (p[i] << 8); - return sum; +static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { + ETH->MACMDIODR = val; + ETH->MACMDIOAR &= (0xF << 8); + ETH->MACMDIOAR |= ((uint32_t) addr << 21) | ((uint32_t) reg << 16) | 1 << 2; + ETH->MACMDIOAR |= MG_BIT(0); + while (ETH->MACMDIOAR & MG_BIT(0)) (void) 0; } -static uint16_t csumfin(uint32_t sum) { - while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16); - return mg_htons(~sum & 0xffff); +static uint32_t get_hclk(void) { + struct rcc { + volatile uint32_t CR, HSICFGR, CRRCR, CSICFGR, CFGR, RESERVED1, D1CFGR, + D2CFGR, D3CFGR, RESERVED2, PLLCKSELR, PLLCFGR, PLL1DIVR, PLL1FRACR, + PLL2DIVR, PLL2FRACR, PLL3DIVR, PLL3FRACR, RESERVED3, D1CCIPR, D2CCIP1R, + D2CCIP2R, D3CCIPR, RESERVED4, CIER, CIFR, CICR, RESERVED5, BDCR, CSR, + RESERVED6, AHB3RSTR, AHB1RSTR, AHB2RSTR, AHB4RSTR, APB3RSTR, APB1LRSTR, + APB1HRSTR, APB2RSTR, APB4RSTR, GCR, RESERVED8, D3AMR, RESERVED11[9], + RSR, AHB3ENR, AHB1ENR, AHB2ENR, AHB4ENR, APB3ENR, APB1LENR, APB1HENR, + APB2ENR, APB4ENR, RESERVED12, AHB3LPENR, AHB1LPENR, AHB2LPENR, + AHB4LPENR, APB3LPENR, APB1LLPENR, APB1HLPENR, APB2LPENR, APB4LPENR, + RESERVED13[4]; + } *rcc = ((struct rcc *) (0x40000000 + 0x18020000 + 0x4400)); + uint32_t clk = 0, hsi = 64000000 /* 64 MHz */, hse = 8000000 /* 8MHz */, + csi = 4000000 /* 4MHz */; + unsigned int sel = (rcc->CFGR & (7 << 3)) >> 3; + + if (sel == 1) { + clk = csi; + } else if (sel == 2) { + clk = hse; + } else if (sel == 3) { + uint32_t vco, m, n, p; + unsigned int src = (rcc->PLLCKSELR & (3 << 0)) >> 0; + m = ((rcc->PLLCKSELR & (0x3F << 4)) >> 4); + n = ((rcc->PLL1DIVR & (0x1FF << 0)) >> 0) + 1 + + ((rcc->PLLCFGR & MG_BIT(0)) ? 1 : 0); // round-up in fractional mode + p = ((rcc->PLL1DIVR & (0x7F << 9)) >> 9) + 1; + if (src == 1) { + clk = csi; + } else if (src == 2) { + clk = hse; + } else { + clk = hsi; + clk >>= ((rcc->CR & 3) >> 3); + } + vco = (uint32_t) ((uint64_t) clk * n / m); + clk = vco / p; + } else { + clk = hsi; + clk >>= ((rcc->CR & 3) >> 3); + } + const uint8_t cptab[12] = {1, 2, 3, 4, 6, 7, 8, 9}; // log2(div) + uint32_t d1cpre = (rcc->D1CFGR & (0x0F << 8)) >> 8; + if (d1cpre >= 8) clk >>= cptab[d1cpre - 8]; + MG_DEBUG(("D1 CLK: %u", clk)); + uint32_t hpre = (rcc->D1CFGR & (0x0F << 0)) >> 0; + if (hpre < 8) return clk; + return ((uint32_t) clk) >> cptab[hpre - 8]; +} + +// Guess CR from AHB1 clock. MDC clock is generated from the ETH peripheral +// clock (AHB1); as per 802.3, it must not exceed 2. As the AHB clock can +// be derived from HSI or CSI (internal RC) clocks, and those can go above +// specs, the datasheets specify a range of frequencies and activate one of a +// series of dividers to keep the MDC clock safely below 2.5MHz. We guess a +// divider setting based on HCLK with some drift. If the user uses a different +// clock from our defaults, needs to set the macros on top. Valid for +// STM32H74xxx/75xxx (58.11.4)(4.5% worst case drift)(CSI clock has a 7.5 % +// worst case drift @ max temp) +static int guess_mdc_cr(void) { + const uint8_t crs[] = {2, 3, 0, 1, 4, 5}; // ETH->MACMDIOAR::CR values + const uint8_t div[] = {16, 26, 42, 62, 102, 124}; // Respective HCLK dividers + uint32_t hclk = get_hclk(); // Guess system HCLK + int result = -1; // Invalid CR value + for (int i = 0; i < 6; i++) { + if (hclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) { + result = crs[i]; + break; + } + } + if (result < 0) MG_ERROR(("HCLK too high")); + MG_DEBUG(("HCLK: %u, CR: %d", hclk, result)); + return result; } -static uint16_t ipcsum(const void *buf, size_t len) { - uint32_t sum = csumup(0, buf, len); - return csumfin(sum); -} +static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) { + struct mg_tcpip_driver_stm32h_data *d = + (struct mg_tcpip_driver_stm32h_data *) ifp->driver_data; + s_ifp = ifp; + uint8_t phy_addr = d == NULL ? 0 : d->phy_addr; + uint8_t phy_conf = d == NULL ? MG_PHY_CLOCKS_MAC : d->phy_conf; -// ARP cache is organised as a doubly linked list. A successful cache lookup -// moves an entry to the head of the list. New entries are added by replacing -// the last entry in the list with a new IP/MAC. -// ARP cache format: | prev | next | Entry0 | Entry1 | .... | EntryN | -// ARP entry format: | prev | next | IP (4bytes) | MAC (6bytes) | -// prev and next are 1-byte offsets in the cache, so cache size is max 256 bytes -// ARP entry size is 12 bytes -static void arp_cache_init(uint8_t *p, int n, int size) { - for (int i = 0; i < n; i++) p[2 + i * size] = (uint8_t) (2 + (i - 1) * size); - for (int i = 0; i < n; i++) p[3 + i * size] = (uint8_t) (2 + (i + 1) * size); - p[0] = p[2] = (uint8_t) (2 + (n - 1) * size); - p[1] = p[3 + (n - 1) * size] = 2; -} + // Init RX descriptors + for (int i = 0; i < ETH_DESC_CNT; i++) { + s_rxdesc[i][0] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer + s_rxdesc[i][3] = MG_BIT(31) | MG_BIT(30) | MG_BIT(24); // OWN, IOC, BUF1V + } -#if 0 -static inline void arp_cache_dump(const uint8_t *p) { - MG_INFO(("ARP cache:")); - for (uint8_t i = 0, j = p[1]; i < MIP_ARP_ENTRIES; i++, j = p[j + 1]) { - MG_INFO((" %I -> %A", 4, &p[j + 2], &p[j + 6])); + // Init TX descriptors + for (int i = 0; i < ETH_DESC_CNT; i++) { + s_txdesc[i][0] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer } -} -#endif -static const uint8_t bcastmac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + ETH->DMAMR |= MG_BIT(0); // Software reset + while ((ETH->DMAMR & MG_BIT(0)) != 0) (void) 0; // Wait until done -static uint8_t *arp_cache_find(struct mip_if *ifp, uint32_t ip) { - uint8_t *p = ifp->arp_cache; - if (ip == 0) return NULL; - // use broadcast MAC for local and global broadcast IP - if (ip == 0xffffffffU || ip == (ifp->ip | ~ifp->mask)) - return (uint8_t *) bcastmac; - for (uint8_t i = 0, j = p[1]; i < MIP_ARP_ENTRIES; i++, j = p[j + 1]) { - if (memcmp(p + j + 2, &ip, sizeof(ip)) == 0) { - p[1] = j, p[0] = p[j]; // Found entry! Point list head to us - // MG_DEBUG(("ARP find: %I @ %A", 4, &ip, &p[j + 6])); - return p + j + 6; // And return MAC address - } - } - return NULL; -} + // Set MDC clock divider. If user told us the value, use it. Otherwise, guess + int cr = (d == NULL || d->mdc_cr < 0) ? guess_mdc_cr() : d->mdc_cr; + ETH->MACMDIOAR = ((uint32_t) cr & 0xF) << 8; + + // NOTE(scaprile): We do not use timing facilities so the DMA engine does not + // re-write buffer address + ETH->DMAMR = 0 << 16; // use interrupt mode 0 (58.8.1) (reset value) + ETH->DMASBMR |= MG_BIT(12); // AAL NOTE(scaprile): is this actually needed + ETH->MACIER = 0; // Do not enable additional irq sources (reset value) + ETH->MACTFCR = MG_BIT(7); // Disable zero-quanta pause + // ETH->MACPFR = MG_BIT(31); // Receive all + struct mg_phy phy = {eth_read_phy, eth_write_phy}; + mg_phy_init(&phy, phy_addr, phy_conf); + ETH->DMACRDLAR = + (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors start address + ETH->DMACRDRLR = ETH_DESC_CNT - 1; // ring length + ETH->DMACRDTPR = + (uint32_t) (uintptr_t) &s_rxdesc[ETH_DESC_CNT - + 1]; // last valid descriptor address + ETH->DMACTDLAR = + (uint32_t) (uintptr_t) s_txdesc; // TX descriptors start address + ETH->DMACTDRLR = ETH_DESC_CNT - 1; // ring length + ETH->DMACTDTPR = + (uint32_t) (uintptr_t) s_txdesc; // first available descriptor address + ETH->DMACCR = 0; // DSL = 0 (contiguous descriptor table) (reset value) + ETH->DMACIER = MG_BIT(6) | MG_BIT(15); // RIE, NIE + ETH->MACCR = MG_BIT(0) | MG_BIT(1) | MG_BIT(13) | MG_BIT(14) | + MG_BIT(15); // RE, TE, Duplex, Fast, Reserved + ETH->MTLTQOMR |= MG_BIT(1); // TSF + ETH->MTLRQOMR |= MG_BIT(5); // RSF + ETH->DMACTCR |= MG_BIT(0); // ST + ETH->DMACRCR |= MG_BIT(0); // SR -static void arp_cache_add(struct mip_if *ifp, uint32_t ip, uint8_t mac[6]) { - uint8_t *p = ifp->arp_cache; - if (ip == 0 || ip == ~0U) return; // Bad IP - if (arp_cache_find(ifp, ip) != NULL) return; // Already exists, do nothing - memcpy(p + p[0] + 2, &ip, sizeof(ip)); // Replace last entry: IP address - memcpy(p + p[0] + 6, mac, 6); // And MAC address - p[1] = p[0], p[0] = p[p[1]]; // Point list head to us - MG_DEBUG(("ARP cache: added %I @ %A", 4, &ip, mac)); + // MAC address filtering + ETH->MACA0HR = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4]; + ETH->MACA0LR = (uint32_t) (ifp->mac[3] << 24) | + ((uint32_t) ifp->mac[2] << 16) | + ((uint32_t) ifp->mac[1] << 8) | ifp->mac[0]; + return true; } -static size_t ether_output(struct mip_if *ifp, size_t len) { - // size_t min = 64; // Pad short frames to 64 bytes (minimum Ethernet size) - // if (len < min) memset(ifp->tx.ptr + len, 0, min - len), len = min; - // mg_hexdump(ifp->tx.ptr, len); - return ifp->driver->tx(ifp->tx.ptr, len, ifp); +static uint32_t s_txno; +static size_t mg_tcpip_driver_stm32h_tx(const void *buf, size_t len, + struct mg_tcpip_if *ifp) { + if (len > sizeof(s_txbuf[s_txno])) { + MG_ERROR(("Frame too big, %ld", (long) len)); + len = 0; // Frame is too big + } else if ((s_txdesc[s_txno][3] & MG_BIT(31))) { + ifp->nerr++; + MG_ERROR(("No free descriptors: %u %08X %08X %08X", s_txno, + s_txdesc[s_txno][3], ETH->DMACSR, ETH->DMACTCR)); + for (int i = 0; i < ETH_DESC_CNT; i++) MG_ERROR(("%08X", s_txdesc[i][3])); + len = 0; // All descriptors are busy, fail + } else { + memcpy(s_txbuf[s_txno], buf, len); // Copy data + s_txdesc[s_txno][2] = (uint32_t) len; // Set data len + s_txdesc[s_txno][3] = MG_BIT(28) | MG_BIT(29); // FD, LD + s_txdesc[s_txno][3] |= MG_BIT(31); // Set OWN bit - let DMA take over + if (++s_txno >= ETH_DESC_CNT) s_txno = 0; + } + ETH->DMACSR |= MG_BIT(2) | MG_BIT(1); // Clear any prior TBU, TPS + ETH->DMACTDTPR = (uint32_t) (uintptr_t) &s_txdesc[s_txno]; // and resume + return len; + (void) ifp; } -static void arp_ask(struct mip_if *ifp, uint32_t ip) { - struct eth *eth = (struct eth *) ifp->tx.ptr; - struct arp *arp = (struct arp *) (eth + 1); - memset(eth->dst, 255, sizeof(eth->dst)); - memcpy(eth->src, ifp->mac, sizeof(eth->src)); - eth->type = mg_htons(0x806); - memset(arp, 0, sizeof(*arp)); - arp->fmt = mg_htons(1), arp->pro = mg_htons(0x800), arp->hlen = 6, - arp->plen = 4; - arp->op = mg_htons(1), arp->tpa = ip, arp->spa = ifp->ip; - memcpy(arp->sha, ifp->mac, sizeof(arp->sha)); - ether_output(ifp, PDIFF(eth, arp + 1)); +static bool mg_tcpip_driver_stm32h_up(struct mg_tcpip_if *ifp) { + struct mg_tcpip_driver_stm32h_data *d = + (struct mg_tcpip_driver_stm32h_data *) ifp->driver_data; + uint8_t phy_addr = d == NULL ? 0 : d->phy_addr; + uint8_t speed = MG_PHY_SPEED_10M; + bool up = false, full_duplex = false; + struct mg_phy phy = {eth_read_phy, eth_write_phy}; + up = mg_phy_up(&phy, phy_addr, &full_duplex, &speed); + if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up + // tmp = reg with flags set to the most likely situation: 100M full-duplex + // if(link is slow or half) set flags otherwise + // reg = tmp + uint32_t maccr = ETH->MACCR | MG_BIT(14) | MG_BIT(13); // 100M, Full-duplex + if (speed == MG_PHY_SPEED_10M) maccr &= ~MG_BIT(14); // 10M + if (full_duplex == false) maccr &= ~MG_BIT(13); // Half-duplex + ETH->MACCR = maccr; // IRQ handler does not fiddle with this register + MG_DEBUG(("Link is %uM %s-duplex", maccr & MG_BIT(14) ? 100 : 10, + maccr & MG_BIT(13) ? "full" : "half")); + } + return up; } -static void onstatechange(struct mip_if *ifp) { - if (ifp->state == MIP_STATE_READY) { - MG_INFO(("READY, IP: %I", 4, &ifp->ip)); - MG_INFO((" GW: %I", 4, &ifp->gw)); - if (ifp->lease_expire > ifp->now) { - MG_INFO( - (" Lease: %lld sec", (ifp->lease_expire - ifp->now) / 1000)); +void ETH_IRQHandler(void); +static uint32_t s_rxno; +void ETH_IRQHandler(void) { + if (ETH->DMACSR & MG_BIT(6)) { // Frame received, loop + ETH->DMACSR = MG_BIT(15) | MG_BIT(6); // Clear flag + for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever + if (s_rxdesc[s_rxno][3] & MG_BIT(31)) break; // exit when done + if (((s_rxdesc[s_rxno][3] & (MG_BIT(28) | MG_BIT(29))) == + (MG_BIT(28) | MG_BIT(29))) && + !(s_rxdesc[s_rxno][3] & MG_BIT(15))) { // skip partial/errored frames + uint32_t len = s_rxdesc[s_rxno][3] & (MG_BIT(15) - 1); + // MG_DEBUG(("%lx %lu %lx %08lx", s_rxno, len, s_rxdesc[s_rxno][3], + // ETH->DMACSR)); + mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp); + } + s_rxdesc[s_rxno][3] = + MG_BIT(31) | MG_BIT(30) | MG_BIT(24); // OWN, IOC, BUF1V + if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; } - arp_ask(ifp, ifp->gw); - } else if (ifp->state == MIP_STATE_UP) { - MG_ERROR(("Link up")); - } else if (ifp->state == MIP_STATE_DOWN) { - MG_ERROR(("Link down")); } + ETH->DMACSR = + MG_BIT(7) | MG_BIT(8); // Clear possible RBU RPS while processing + ETH->DMACRDTPR = + (uint32_t) (uintptr_t) &s_rxdesc[ETH_DESC_CNT - 1]; // and resume RX } -static struct ip *tx_ip(struct mip_if *ifp, uint8_t proto, uint32_t ip_src, - uint32_t ip_dst, size_t plen) { - struct eth *eth = (struct eth *) ifp->tx.ptr; - struct ip *ip = (struct ip *) (eth + 1); - uint8_t *mac = arp_cache_find(ifp, ip_dst); // Dst IP in ARP cache ? - if (!mac && ((ip_dst & ifp->mask) == (ifp->ip & ifp->mask))) - arp_ask(ifp, ip_dst); // Same net, lookup - if (!mac) mac = arp_cache_find(ifp, ifp->gw); // Use gateway MAC - if (!mac) arp_ask(ifp, ifp->gw); // Not found? lookup - if (mac) memcpy(eth->dst, mac, sizeof(eth->dst)); // Found? Use it - if (!mac) memset(eth->dst, 255, sizeof(eth->dst)); // No? Use broadcast - memcpy(eth->src, ifp->mac, sizeof(eth->src)); // TODO(cpq): ARP lookup - eth->type = mg_htons(0x800); - memset(ip, 0, sizeof(*ip)); - ip->ver = 0x45; // Version 4, header length 5 words - ip->frag = 0x40; // Don't fragment - ip->len = mg_htons((uint16_t) (sizeof(*ip) + plen)); - ip->ttl = 64; - ip->proto = proto; - ip->src = ip_src; - ip->dst = ip_dst; - ip->csum = ipcsum(ip, sizeof(*ip)); - return ip; -} +struct mg_tcpip_driver mg_tcpip_driver_stm32h = { + mg_tcpip_driver_stm32h_init, mg_tcpip_driver_stm32h_tx, NULL, + mg_tcpip_driver_stm32h_up}; +#endif -static void tx_udp(struct mip_if *ifp, uint32_t ip_src, uint16_t sport, - uint32_t ip_dst, uint16_t dport, const void *buf, - size_t len) { - struct ip *ip = tx_ip(ifp, 17, ip_src, ip_dst, len + sizeof(struct udp)); - struct udp *udp = (struct udp *) (ip + 1); - // MG_DEBUG(("UDP XX LEN %d %d", (int) len, (int) ifp->tx.len)); - udp->sport = sport; - udp->dport = dport; - udp->len = mg_htons((uint16_t) (sizeof(*udp) + len)); - udp->csum = 0; - uint32_t cs = csumup(0, udp, sizeof(*udp)); - cs = csumup(cs, buf, len); - cs = csumup(cs, &ip->src, sizeof(ip->src)); - cs = csumup(cs, &ip->dst, sizeof(ip->dst)); - cs += (uint32_t) (ip->proto + sizeof(*udp) + len); - udp->csum = csumfin(cs); - memmove(udp + 1, buf, len); - // MG_DEBUG(("UDP LEN %d %d", (int) len, (int) ifp->frame_len)); - ether_output(ifp, sizeof(struct eth) + sizeof(*ip) + sizeof(*udp) + len); -} +#ifdef MG_ENABLE_LINES +#line 1 "src/drivers/tm4c.c" +#endif -static void tx_dhcp(struct mip_if *ifp, uint32_t src, uint32_t dst, - uint8_t *opts, size_t optslen) { - struct dhcp dhcp = {1, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0}}; - dhcp.magic = mg_htonl(0x63825363); - memcpy(&dhcp.hwaddr, ifp->mac, sizeof(ifp->mac)); - memcpy(&dhcp.xid, ifp->mac + 2, sizeof(dhcp.xid)); - memcpy(&dhcp.options, opts, optslen); - tx_udp(ifp, src, mg_htons(68), dst, mg_htons(67), &dhcp, sizeof(dhcp)); -} -static void tx_dhcp_request(struct mip_if *ifp, uint32_t src, uint32_t dst) { - uint8_t opts[] = { - 53, 1, 3, // Type: DHCP request - 55, 2, 1, 3, // GW and mask - 12, 3, 'm', 'i', 'p', // Host name: "mip" - 54, 4, 0, 0, 0, 0, // DHCP server ID - 50, 4, 0, 0, 0, 0, // Requested IP - 255 // End of options - }; - memcpy(opts + 14, &dst, sizeof(dst)); - memcpy(opts + 20, &src, sizeof(src)); - tx_dhcp(ifp, src, dst, opts, sizeof(opts)); -} +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_TM4C) && MG_ENABLE_DRIVER_TM4C +struct tm4c_emac { + volatile uint32_t EMACCFG, EMACFRAMEFLTR, EMACHASHTBLH, EMACHASHTBLL, + EMACMIIADDR, EMACMIIDATA, EMACFLOWCTL, EMACVLANTG, RESERVED0, EMACSTATUS, + EMACRWUFF, EMACPMTCTLSTAT, RESERVED1[2], EMACRIS, EMACIM, EMACADDR0H, + EMACADDR0L, EMACADDR1H, EMACADDR1L, EMACADDR2H, EMACADDR2L, EMACADDR3H, + EMACADDR3L, RESERVED2[31], EMACWDOGTO, RESERVED3[8], EMACMMCCTRL, + EMACMMCRXRIS, EMACMMCTXRIS, EMACMMCRXIM, EMACMMCTXIM, RESERVED4, + EMACTXCNTGB, RESERVED5[12], EMACTXCNTSCOL, EMACTXCNTMCOL, RESERVED6[4], + EMACTXOCTCNTG, RESERVED7[6], EMACRXCNTGB, RESERVED8[4], EMACRXCNTCRCERR, + EMACRXCNTALGNERR, RESERVED9[10], EMACRXCNTGUNI, RESERVED10[239], + EMACVLNINCREP, EMACVLANHASH, RESERVED11[93], EMACTIMSTCTRL, EMACSUBSECINC, + EMACTIMSEC, EMACTIMNANO, EMACTIMSECU, EMACTIMNANOU, EMACTIMADD, + EMACTARGSEC, EMACTARGNANO, EMACHWORDSEC, EMACTIMSTAT, EMACPPSCTRL, + RESERVED12[12], EMACPPS0INTVL, EMACPPS0WIDTH, RESERVED13[294], + EMACDMABUSMOD, EMACTXPOLLD, EMACRXPOLLD, EMACRXDLADDR, EMACTXDLADDR, + EMACDMARIS, EMACDMAOPMODE, EMACDMAIM, EMACMFBOC, EMACRXINTWDT, + RESERVED14[8], EMACHOSTXDESC, EMACHOSRXDESC, EMACHOSTXBA, EMACHOSRXBA, + RESERVED15[218], EMACPP, EMACPC, EMACCC, RESERVED16, EMACEPHYRIS, + EMACEPHYIM, EMACEPHYIMSC; +}; +#undef EMAC +#define EMAC ((struct tm4c_emac *) (uintptr_t) 0x400EC000) -static void tx_dhcp_discover(struct mip_if *ifp) { - uint8_t opts[] = { - 53, 1, 1, // Type: DHCP discover - 55, 2, 1, 3, // Parameters: ip, mask - 255 // End of options - }; - tx_dhcp(ifp, 0, 0xffffffff, opts, sizeof(opts)); - MG_DEBUG(("DHCP discover sent")); -} +#define ETH_PKT_SIZE 1540 // Max frame size +#define ETH_DESC_CNT 4 // Descriptors count +#define ETH_DS 4 // Descriptor size (words) -static void rx_arp(struct mip_if *ifp, struct pkt *pkt) { - if (pkt->arp->op == mg_htons(1) && pkt->arp->tpa == ifp->ip) { - // ARP request. Make a response, then send - MG_DEBUG(("ARP op %d %I: %I?", mg_ntohs(pkt->arp->op), 4, &pkt->arp->spa, 4, - &pkt->arp->tpa)); - struct eth *eth = (struct eth *) ifp->tx.ptr; - struct arp *arp = (struct arp *) (eth + 1); - memcpy(eth->dst, pkt->eth->src, sizeof(eth->dst)); - memcpy(eth->src, ifp->mac, sizeof(eth->src)); - eth->type = mg_htons(0x806); - *arp = *pkt->arp; - arp->op = mg_htons(2); - memcpy(arp->tha, pkt->arp->sha, sizeof(pkt->arp->tha)); - memcpy(arp->sha, ifp->mac, sizeof(pkt->arp->sha)); - arp->tpa = pkt->arp->spa; - arp->spa = ifp->ip; - MG_DEBUG(("ARP response: we're %I", 4, &ifp->ip)); - ether_output(ifp, PDIFF(eth, arp + 1)); - } else if (pkt->arp->op == mg_htons(2)) { - if (memcmp(pkt->arp->tha, ifp->mac, sizeof(pkt->arp->tha)) != 0) return; - // MG_INFO(("ARP RESPONSE")); - arp_cache_add(ifp, pkt->arp->spa, pkt->arp->sha); - } +static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors +static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors +static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers +static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers +static struct mg_tcpip_if *s_ifp; // MIP interface +enum { + EPHY_ADDR = 0, + EPHYBMCR = 0, + EPHYBMSR = 1, + EPHYSTS = 16 +}; // PHY constants + +static inline void tm4cspin(volatile uint32_t count) { + while (count--) (void) 0; } -static void rx_icmp(struct mip_if *ifp, struct pkt *pkt) { - // MG_DEBUG(("ICMP %d", (int) len)); - if (pkt->icmp->type == 8 && pkt->ip != NULL && pkt->ip->dst == ifp->ip) { - size_t hlen = sizeof(struct eth) + sizeof(struct ip) + sizeof(struct icmp); - size_t space = ifp->tx.len - hlen, plen = pkt->pay.len; - if (plen > space) plen = space; - struct ip *ip = - tx_ip(ifp, 1, ifp->ip, pkt->ip->src, sizeof(struct icmp) + plen); - struct icmp *icmp = (struct icmp *) (ip + 1); - memset(icmp, 0, sizeof(*icmp)); // Set csum to 0 - memcpy(icmp + 1, pkt->pay.ptr, plen); // Copy RX payload to TX - icmp->csum = ipcsum(icmp, sizeof(*icmp) + plen); - ether_output(ifp, hlen + plen); - } +static uint32_t emac_read_phy(uint8_t addr, uint8_t reg) { + EMAC->EMACMIIADDR &= (0xf << 2); + EMAC->EMACMIIADDR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6); + EMAC->EMACMIIADDR |= MG_BIT(0); + while (EMAC->EMACMIIADDR & MG_BIT(0)) tm4cspin(1); + return EMAC->EMACMIIDATA; } -static void rx_dhcp_client(struct mip_if *ifp, struct pkt *pkt) { - uint32_t ip = 0, gw = 0, mask = 0; - uint8_t *p = pkt->dhcp->options, - *end = (uint8_t *) &pkt->raw.ptr[pkt->raw.len]; - if (end < (uint8_t *) (pkt->dhcp + 1)) return; - while (p + 1 < end && p[0] != 255) { // Parse options - if (p[0] == 1 && p[1] == sizeof(ifp->mask) && p + 6 < end) { // Mask - memcpy(&mask, p + 2, sizeof(mask)); - } else if (p[0] == 3 && p[1] == sizeof(ifp->gw) && p + 6 < end) { // GW - memcpy(&gw, p + 2, sizeof(gw)); - ip = pkt->dhcp->yiaddr; - } else if (p[0] == 51 && p[1] == 4 && p + 6 < end) { // Lease - uint32_t lease = 0; - memcpy(&lease, p + 2, sizeof(lease)); - ifp->lease_expire = ifp->now + mg_ntohl(lease) * 1000; - } - p += p[1] + 2; - } - if (ip && mask && gw && ifp->ip == 0) { - arp_cache_add(ifp, pkt->dhcp->siaddr, ((struct eth *) pkt->raw.ptr)->src); - ifp->ip = ip, ifp->gw = gw, ifp->mask = mask; - ifp->state = MIP_STATE_READY; - onstatechange(ifp); - tx_dhcp_request(ifp, ip, pkt->dhcp->siaddr); - } +static void emac_write_phy(uint8_t addr, uint8_t reg, uint32_t val) { + EMAC->EMACMIIDATA = val; + EMAC->EMACMIIADDR &= (0xf << 2); + EMAC->EMACMIIADDR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6) | MG_BIT(1); + EMAC->EMACMIIADDR |= MG_BIT(0); + while (EMAC->EMACMIIADDR & MG_BIT(0)) tm4cspin(1); } -// Simple DHCP server that assigns a next IP address: ifp->ip + 1 -static void rx_dhcp_server(struct mip_if *ifp, struct pkt *pkt) { - uint8_t op = 0, *p = pkt->dhcp->options, - *end = (uint8_t *) &pkt->raw.ptr[pkt->raw.len]; - if (end < (uint8_t *) (pkt->dhcp + 1)) return; - // struct dhcp *req = pkt->dhcp; - struct dhcp res = {2, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0}}; - res.yiaddr = ifp->ip; - ((uint8_t *) (&res.yiaddr))[3]++; // Offer our IP + 1 - while (p + 1 < end && p[0] != 255) { // Parse options - if (p[0] == 53 && p[1] == 1 && p + 2 < end) { // Message type - op = p[2]; +static uint32_t get_sysclk(void) { + struct sysctl { + volatile uint32_t DONTCARE0[44], RSCLKCFG, DONTCARE1[43], PLLFREQ0, + PLLFREQ1; + } *sysctl = (struct sysctl *) 0x400FE000; + uint32_t clk = 0, piosc = 16000000 /* 16 MHz */, mosc = 25000000 /* 25MHz */; + if (sysctl->RSCLKCFG & (1 << 28)) { // USEPLL + uint32_t fin, vco, mdiv, n, q, psysdiv; + uint32_t pllsrc = (sysctl->RSCLKCFG & (0xf << 24)) >> 24; + if (pllsrc == 0) { + clk = piosc; + } else if (pllsrc == 3) { + clk = mosc; + } else { + MG_ERROR(("Unsupported clock source")); } - p += p[1] + 2; - } - if (op == 1 || op == 3) { // DHCP Discover or DHCP Request - uint8_t msg = op == 1 ? 2 : 5; // Message type: DHCP OFFER or DHCP ACK - uint8_t opts[] = { - 53, 1, msg, // Message type - 1, 4, 0, 0, 0, 0, // Subnet mask - 54, 4, 0, 0, 0, 0, // Server ID - 12, 3, 'm', 'i', 'p', // Host name: "mip" - 51, 4, 255, 255, 255, 255, // Lease time - 255 // End of options - }; - memcpy(&res.hwaddr, pkt->dhcp->hwaddr, 6); - memcpy(opts + 5, &ifp->mask, sizeof(ifp->mask)); - memcpy(opts + 11, &ifp->ip, sizeof(ifp->ip)); - memcpy(&res.options, opts, sizeof(opts)); - res.magic = pkt->dhcp->magic; - res.xid = pkt->dhcp->xid; - arp_cache_add(ifp, res.yiaddr, pkt->eth->src); - tx_udp(ifp, ifp->ip, mg_htons(67), op == 1 ? ~0U : res.yiaddr, mg_htons(68), - &res, sizeof(res)); + q = (sysctl->PLLFREQ1 & (0x1f << 8)) >> 8; + n = (sysctl->PLLFREQ1 & (0x1f << 0)) >> 0; + fin = clk / ((q + 1) * (n + 1)); + mdiv = (sysctl->PLLFREQ0 & (0x3ff << 0)) >> + 0; // mint + (mfrac / 1024); MFRAC not supported + psysdiv = (sysctl->RSCLKCFG & (0x3f << 0)) >> 0; + vco = (uint32_t) ((uint64_t) fin * mdiv); + return vco / (psysdiv + 1); } -} - -static struct mg_connection *getpeer(struct mg_mgr *mgr, struct pkt *pkt, - bool lsn) { - struct mg_connection *c = NULL; - for (c = mgr->conns; c != NULL; c = c->next) { - if (c->is_udp && pkt->udp && c->loc.port == pkt->udp->dport) break; - if (!c->is_udp && pkt->tcp && c->loc.port == pkt->tcp->dport && - lsn == c->is_listening && (lsn || c->rem.port == pkt->tcp->sport)) - break; + uint32_t oscsrc = (sysctl->RSCLKCFG & (0xf << 20)) >> 20; + if (oscsrc == 0) { + clk = piosc; + } else if (oscsrc == 3) { + clk = mosc; + } else { + MG_ERROR(("Unsupported clock source")); } - return c; + uint32_t osysdiv = (sysctl->RSCLKCFG & (0xf << 16)) >> 16; + return clk / (osysdiv + 1); } -static void rx_udp(struct mip_if *ifp, struct pkt *pkt) { - struct mg_connection *c = getpeer(ifp->mgr, pkt, true); - if (c == NULL) { - // No UDP listener on this port. Should send ICMP, but keep silent. - } else if (c != NULL) { - c->rem.port = pkt->udp->sport; - c->rem.ip = pkt->ip->src; - if (c->recv.len >= MG_MAX_RECV_SIZE) { - mg_error(c, "max_recv_buf_size reached"); - } else if (c->recv.size - c->recv.len < pkt->pay.len && - !mg_iobuf_resize(&c->recv, c->recv.len + pkt->pay.len)) { - mg_error(c, "oom"); - } else { - memcpy(&c->recv.buf[c->recv.len], pkt->pay.ptr, pkt->pay.len); - c->recv.len += pkt->pay.len; - mg_call(c, MG_EV_READ, &pkt->pay.len); +// Guess CR from SYSCLK. MDC clock is generated from SYSCLK (AHB); as per +// 802.3, it must not exceed 2.5MHz (also 20.4.2.6) As the AHB clock can be +// derived from the PIOSC (internal RC), and it can go above specs, the +// datasheets specify a range of frequencies and activate one of a series of +// dividers to keep the MDC clock safely below 2.5MHz. We guess a divider +// setting based on SYSCLK with a +5% drift. If the user uses a different clock +// from our defaults, needs to set the macros on top Valid for TM4C129x (20.7) +// (4.5% worst case drift) +// The PHY receives the main oscillator (MOSC) (20.3.1) +static int guess_mdc_cr(void) { + uint8_t crs[] = {2, 3, 0, 1}; // EMAC->MACMIIAR::CR values + uint8_t div[] = {16, 26, 42, 62}; // Respective HCLK dividers + uint32_t sysclk = get_sysclk(); // Guess system SYSCLK + int result = -1; // Invalid CR value + if (sysclk < 25000000) { + MG_ERROR(("SYSCLK too low")); + } else { + for (int i = 0; i < 4; i++) { + if (sysclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) { + result = crs[i]; + break; + } } + if (result < 0) MG_ERROR(("SYSCLK too high")); } + MG_DEBUG(("SYSCLK: %u, CR: %d", sysclk, result)); + return result; } -static size_t tx_tcp(struct mip_if *ifp, uint32_t dst_ip, uint8_t flags, - uint16_t sport, uint16_t dport, uint32_t seq, uint32_t ack, - const void *buf, size_t len) { - struct ip *ip = tx_ip(ifp, 6, ifp->ip, dst_ip, sizeof(struct tcp) + len); - struct tcp *tcp = (struct tcp *) (ip + 1); - memset(tcp, 0, sizeof(*tcp)); - if (buf != NULL && len) memmove(tcp + 1, buf, len); - tcp->sport = sport; - tcp->dport = dport; - tcp->seq = seq; - tcp->ack = ack; - tcp->flags = flags; - tcp->win = mg_htons(8192); - tcp->off = (uint8_t) (sizeof(*tcp) / 4 << 4); - uint32_t cs = 0; - uint16_t n = (uint16_t) (sizeof(*tcp) + len); - uint8_t pseudo[] = {0, ip->proto, (uint8_t) (n >> 8), (uint8_t) (n & 255)}; - cs = csumup(cs, tcp, n); - cs = csumup(cs, &ip->src, sizeof(ip->src)); - cs = csumup(cs, &ip->dst, sizeof(ip->dst)); - cs = csumup(cs, pseudo, sizeof(pseudo)); - tcp->csum = csumfin(cs); - return ether_output(ifp, PDIFF(ifp->tx.ptr, tcp + 1) + len); -} +static bool mg_tcpip_driver_tm4c_init(struct mg_tcpip_if *ifp) { + struct mg_tcpip_driver_tm4c_data *d = + (struct mg_tcpip_driver_tm4c_data *) ifp->driver_data; + s_ifp = ifp; -static size_t tx_tcp_pkt(struct mip_if *ifp, struct pkt *pkt, uint8_t flags, - uint32_t seq, const void *buf, size_t len) { - uint32_t delta = (pkt->tcp->flags & (TH_SYN | TH_FIN)) ? 1 : 0; - return tx_tcp(ifp, pkt->ip->src, flags, pkt->tcp->dport, pkt->tcp->sport, seq, - mg_htonl(mg_ntohl(pkt->tcp->seq) + delta), buf, len); -} + // Init RX descriptors + for (int i = 0; i < ETH_DESC_CNT; i++) { + s_rxdesc[i][0] = MG_BIT(31); // Own + s_rxdesc[i][1] = sizeof(s_rxbuf[i]) | MG_BIT(14); // 2nd address chained + s_rxdesc[i][2] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer + s_rxdesc[i][3] = + (uint32_t) (uintptr_t) s_rxdesc[(i + 1) % ETH_DESC_CNT]; // Chain + // MG_DEBUG(("%d %p", i, s_rxdesc[i])); + } -static void settmout(struct mg_connection *c, uint8_t type) { - struct mip_if *ifp = (struct mip_if *) c->mgr->priv; - struct connstate *s = (struct connstate *) (c + 1); - unsigned n = type == MIP_TTYPE_ACK ? MIP_TCP_ACK_MS : MIP_TCP_KEEPALIVE_MS; - s->timer = ifp->now + n; - s->ttype = type; - MG_VERBOSE(("%lu %d -> %llx", c->id, type, s->timer)); -} + // Init TX descriptors + for (int i = 0; i < ETH_DESC_CNT; i++) { + s_txdesc[i][2] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer + s_txdesc[i][3] = + (uint32_t) (uintptr_t) s_txdesc[(i + 1) % ETH_DESC_CNT]; // Chain + } -static struct mg_connection *accept_conn(struct mg_connection *lsn, - struct pkt *pkt) { - struct mg_connection *c = mg_alloc_conn(lsn->mgr); - struct connstate *s = (struct connstate *) (c + 1); - s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq); - settmout(c, MIP_TTYPE_KEEPALIVE); - c->rem.ip = pkt->ip->src; - c->rem.port = pkt->tcp->sport; - MG_DEBUG( - ("%lu accepted %I:%hu", c->id, 4, &c->rem.ip, mg_ntohs(c->rem.port))); - LIST_ADD_HEAD(struct mg_connection, &lsn->mgr->conns, c); - c->is_accepted = 1; - c->is_hexdumping = lsn->is_hexdumping; - c->pfn = lsn->pfn; - c->loc = lsn->loc; - c->pfn_data = lsn->pfn_data; - c->fn = lsn->fn; - c->fn_data = lsn->fn_data; - mg_call(c, MG_EV_OPEN, NULL); - mg_call(c, MG_EV_ACCEPT, NULL); - return c; + EMAC->EMACDMABUSMOD |= MG_BIT(0); // Software reset + while ((EMAC->EMACDMABUSMOD & MG_BIT(0)) != 0) tm4cspin(1); // Wait until done + + // Set MDC clock divider. If user told us the value, use it. Otherwise, guess + int cr = (d == NULL || d->mdc_cr < 0) ? guess_mdc_cr() : d->mdc_cr; + EMAC->EMACMIIADDR = ((uint32_t) cr & 0xf) << 2; + + // NOTE(cpq): we do not use extended descriptor bit 7, and do not use + // hardware checksum. Therefore, descriptor size is 4, not 8 + // EMAC->EMACDMABUSMOD = MG_BIT(13) | MG_BIT(16) | MG_BIT(22) | MG_BIT(23) | MG_BIT(25); + EMAC->EMACIM = MG_BIT(3) | MG_BIT(9); // Mask timestamp & PMT IT + EMAC->EMACFLOWCTL = MG_BIT(7); // Disable zero-quanta pause + // EMAC->EMACFRAMEFLTR = MG_BIT(31); // Receive all + // EMAC->EMACPC defaults to internal PHY (EPHY) in MMI mode + emac_write_phy(EPHY_ADDR, EPHYBMCR, MG_BIT(15)); // Reset internal PHY (EPHY) + emac_write_phy(EPHY_ADDR, EPHYBMCR, MG_BIT(12)); // Set autonegotiation + EMAC->EMACRXDLADDR = (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors + EMAC->EMACTXDLADDR = (uint32_t) (uintptr_t) s_txdesc; // TX descriptors + EMAC->EMACDMAIM = MG_BIT(6) | MG_BIT(16); // RIE, NIE + EMAC->EMACCFG = MG_BIT(2) | MG_BIT(3) | MG_BIT(11) | MG_BIT(14); // RE, TE, Duplex, Fast + EMAC->EMACDMAOPMODE = + MG_BIT(1) | MG_BIT(13) | MG_BIT(21) | MG_BIT(25); // SR, ST, TSF, RSF + EMAC->EMACADDR0H = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4]; + EMAC->EMACADDR0L = (uint32_t) (ifp->mac[3] << 24) | + ((uint32_t) ifp->mac[2] << 16) | + ((uint32_t) ifp->mac[1] << 8) | ifp->mac[0]; + // NOTE(scaprile) There are 3 additional slots for filtering, disabled by + // default. This also applies to the STM32 driver (at least for F7) + return true; } -long mg_io_send(struct mg_connection *c, const void *buf, size_t len) { - struct mip_if *ifp = (struct mip_if *) c->mgr->priv; - struct connstate *s = (struct connstate *) (c + 1); - size_t max_headers_len = 14 + 24 /* max IP */ + 60 /* max TCP */; - if (len + max_headers_len > ifp->tx.len) len = ifp->tx.len - max_headers_len; - if (tx_tcp(ifp, c->rem.ip, TH_PUSH | TH_ACK, c->loc.port, c->rem.port, - mg_htonl(s->seq), mg_htonl(s->ack), buf, len) > 0) { - s->seq += (uint32_t) len; - if (s->ttype == MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_KEEPALIVE); +static uint32_t s_txno; +static size_t mg_tcpip_driver_tm4c_tx(const void *buf, size_t len, + struct mg_tcpip_if *ifp) { + if (len > sizeof(s_txbuf[s_txno])) { + MG_ERROR(("Frame too big, %ld", (long) len)); + len = 0; // fail + } else if ((s_txdesc[s_txno][0] & MG_BIT(31))) { + ifp->nerr++; + MG_ERROR(("No descriptors available")); + // printf("D0 %lx SR %lx\n", (long) s_txdesc[0][0], (long) + // EMAC->EMACDMARIS); + len = 0; // fail } else { - return MG_IO_ERR; + memcpy(s_txbuf[s_txno], buf, len); // Copy data + s_txdesc[s_txno][1] = (uint32_t) len; // Set data len + s_txdesc[s_txno][0] = + MG_BIT(20) | MG_BIT(28) | MG_BIT(29) | MG_BIT(30); // Chain,FS,LS,IC + s_txdesc[s_txno][0] |= MG_BIT(31); // Set OWN bit - let DMA take over + if (++s_txno >= ETH_DESC_CNT) s_txno = 0; } - return (long) len; + EMAC->EMACDMARIS = MG_BIT(2) | MG_BIT(5); // Clear any prior TU/UNF + EMAC->EMACTXPOLLD = 0; // and resume + return len; + (void) ifp; } -long mg_io_recv(struct mg_connection *c, void *buf, size_t len) { - struct connstate *s = (struct connstate *) (c + 1); - if (s->raw.len == 0) return MG_IO_WAIT; - if (len > s->raw.len) len = s->raw.len; - memcpy(buf, s->raw.buf, len); - mg_iobuf_del(&s->raw, 0, len); - MG_DEBUG(("%lu", len)); - return (long) len; +static bool mg_tcpip_driver_tm4c_up(struct mg_tcpip_if *ifp) { + uint32_t bmsr = emac_read_phy(EPHY_ADDR, EPHYBMSR); + bool up = (bmsr & MG_BIT(2)) ? 1 : 0; + if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up + uint32_t sts = emac_read_phy(EPHY_ADDR, EPHYSTS); + // tmp = reg with flags set to the most likely situation: 100M full-duplex + // if(link is slow or half) set flags otherwise + // reg = tmp + uint32_t emaccfg = EMAC->EMACCFG | MG_BIT(14) | MG_BIT(11); // 100M, Full-duplex + if (sts & MG_BIT(1)) emaccfg &= ~MG_BIT(14); // 10M + if ((sts & MG_BIT(2)) == 0) emaccfg &= ~MG_BIT(11); // Half-duplex + EMAC->EMACCFG = emaccfg; // IRQ handler does not fiddle with this register + MG_DEBUG(("Link is %uM %s-duplex", emaccfg & MG_BIT(14) ? 100 : 10, + emaccfg & MG_BIT(11) ? "full" : "half")); + } + return up; } -static void read_conn(struct mg_connection *c, struct pkt *pkt) { - struct connstate *s = (struct connstate *) (c + 1); - struct mg_iobuf *io = c->is_tls ? &s->raw : &c->recv; - uint32_t seq = mg_ntohl(pkt->tcp->seq); - s->raw.align = c->recv.align; - if (pkt->tcp->flags & TH_FIN) { - s->ack = mg_htonl(pkt->tcp->seq) + 1, s->seq = mg_htonl(pkt->tcp->ack); - c->is_closing = 1; - } else if (pkt->pay.len == 0) { - // TODO(cpq): handle this peer's ACK - } else if (seq != s->ack) { - // TODO(cpq): peer sent us SEQ which we don't expect. Retransmit rather - // than close this connection - mg_error(c, "SEQ != ACK: %x %x", seq, s->ack); - } else if (io->size - io->len < pkt->pay.len && - !mg_iobuf_resize(io, io->len + pkt->pay.len)) { - mg_error(c, "oom"); - } else { - // Copy TCP payload into the IO buffer. If the connection is plain text, we - // copy to c->recv. If the connection is TLS, this data is encrypted, - // therefore we copy that encrypted data to the s->raw iobuffer instead, - // and then call mg_tls_recv() to decrypt it. NOTE: mg_tls_recv() will - // call back mg_io_recv() which grabs raw data from s->raw - memcpy(&io->buf[io->len], pkt->pay.ptr, pkt->pay.len); - io->len += pkt->pay.len; - - MG_DEBUG(("%lu SEQ %x -> %x", c->id, mg_htonl(pkt->tcp->seq), s->ack)); - // Advance ACK counter - s->ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len); -#if 0 - // Send ACK immediately - MG_DEBUG((" imm ACK", c->id, mg_htonl(pkt->tcp->seq), s->ack)); - tx_tcp((struct mip_if *) c->mgr->priv, c->rem.ip, TH_ACK, c->loc.port, - c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), "", 0); -#else - // if not already running, setup a timer to send an ACK later - if (s->ttype != MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_ACK); -#endif - - if (c->is_tls) { - // TLS connection. Make room for decrypted data in c->recv - io = &c->recv; - if (io->size - io->len < pkt->pay.len && - !mg_iobuf_resize(io, io->len + pkt->pay.len)) { - mg_error(c, "oom"); - } else { - // Decrypt data directly into c->recv - long n = mg_tls_recv(c, &io->buf[io->len], io->size - io->len); - if (n == MG_IO_ERR) { - mg_error(c, "TLS recv error"); - } else if (n > 0) { - // Decrypted successfully - trigger MG_EV_READ - io->len += (size_t) n; - mg_call(c, MG_EV_READ, &n); - } +void EMAC0_IRQHandler(void); +static uint32_t s_rxno; +void EMAC0_IRQHandler(void) { + if (EMAC->EMACDMARIS & MG_BIT(6)) { // Frame received, loop + EMAC->EMACDMARIS = MG_BIT(16) | MG_BIT(6); // Clear flag + for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever + if (s_rxdesc[s_rxno][0] & MG_BIT(31)) break; // exit when done + if (((s_rxdesc[s_rxno][0] & (MG_BIT(8) | MG_BIT(9))) == (MG_BIT(8) | MG_BIT(9))) && + !(s_rxdesc[s_rxno][0] & MG_BIT(15))) { // skip partial/errored frames + uint32_t len = ((s_rxdesc[s_rxno][0] >> 16) & (MG_BIT(14) - 1)); + // printf("%lx %lu %lx %.8lx\n", s_rxno, len, s_rxdesc[s_rxno][0], + // EMAC->EMACDMARIS); + mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp); } - } else { - // Plain text connection, data is already in c->recv, trigger MG_EV_READ - mg_call(c, MG_EV_READ, &pkt->pay.len); + s_rxdesc[s_rxno][0] = MG_BIT(31); + if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; } } + EMAC->EMACDMARIS = MG_BIT(7); // Clear possible RU while processing + EMAC->EMACRXPOLLD = 0; // and resume RX } -static void rx_tcp(struct mip_if *ifp, struct pkt *pkt) { - struct mg_connection *c = getpeer(ifp->mgr, pkt, false); - struct connstate *s = c == NULL ? NULL : (struct connstate *) (c + 1); -#if 0 - MG_INFO(("%lu %hhu %d", c ? c->id : 0, pkt->tcp->flags, (int) pkt->pay.len)); +struct mg_tcpip_driver mg_tcpip_driver_tm4c = {mg_tcpip_driver_tm4c_init, + mg_tcpip_driver_tm4c_tx, NULL, + mg_tcpip_driver_tm4c_up}; #endif - if (c != NULL && c->is_connecting && pkt->tcp->flags & (TH_SYN | TH_ACK)) { - s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq) + 1; - tx_tcp_pkt(ifp, pkt, TH_ACK, pkt->tcp->ack, NULL, 0); - c->is_connecting = 0; // Client connected - settmout(c, MIP_TTYPE_KEEPALIVE); - mg_call(c, MG_EV_CONNECT, NULL); // Let user know - } else if (c != NULL && c->is_connecting) { - tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0); - } else if (c != NULL && pkt->tcp->flags & TH_RST) { - mg_error(c, "peer RST"); // RFC-1122 4.2.2.13 - } else if (c != NULL) { -#if 0 - MG_DEBUG(("%lu %d %I:%hu -> %I:%hu", c->id, (int) pkt->raw.len, - 4, &pkt->ip->src, mg_ntohs(pkt->tcp->sport), - 4, &pkt->ip->dst, mg_ntohs(pkt->tcp->dport))); - mg_hexdump(pkt->pay.buf, pkt->pay.len); + +#ifdef MG_ENABLE_LINES +#line 1 "src/drivers/w5500.c" #endif - s->tmiss = 0; // Reset missed keep-alive counter - if (s->ttype == MIP_TTYPE_KEEPALIVE) // Advance keep-alive timer - settmout(c, MIP_TTYPE_KEEPALIVE); // unless a former ACK timeout is pending - read_conn(c, pkt); // Override timer with ACK timeout if needed - } else if ((c = getpeer(ifp->mgr, pkt, true)) == NULL) { - tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0); - } else if (pkt->tcp->flags & TH_RST) { - if (c->is_accepted) mg_error(c, "peer RST"); // RFC-1122 4.2.2.13 - // ignore RST if not connected - } else if (pkt->tcp->flags & TH_SYN) { - // Use peer's source port as ISN, in order to recognise the handshake - uint32_t isn = mg_htonl((uint32_t) mg_ntohs(pkt->tcp->sport)); - tx_tcp_pkt(ifp, pkt, TH_SYN | TH_ACK, isn, NULL, 0); - } else if (pkt->tcp->flags & TH_FIN) { - tx_tcp_pkt(ifp, pkt, TH_FIN | TH_ACK, pkt->tcp->ack, NULL, 0); - } else if (mg_htonl(pkt->tcp->ack) == mg_htons(pkt->tcp->sport) + 1U) { - accept_conn(c, pkt); - } else if (!c->is_accepted ) { // no peer - tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0); - } else { - // MG_DEBUG(("dropped silently..")); + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_W5500) && MG_ENABLE_DRIVER_W5500 + +enum { W5500_CR = 0, W5500_S0 = 1, W5500_TX0 = 2, W5500_RX0 = 3 }; + +static void w5500_txn(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr, + bool wr, void *buf, size_t len) { + size_t i; + uint8_t *p = (uint8_t *) buf; + uint8_t cmd[] = {(uint8_t) (addr >> 8), (uint8_t) (addr & 255), + (uint8_t) ((block << 3) | (wr ? 4 : 0))}; + s->begin(s->spi); + for (i = 0; i < sizeof(cmd); i++) s->txn(s->spi, cmd[i]); + for (i = 0; i < len; i++) { + uint8_t r = s->txn(s->spi, p[i]); + if (!wr) p[i] = r; } + s->end(s->spi); } -static void rx_ip(struct mip_if *ifp, struct pkt *pkt) { - // MG_DEBUG(("IP %d", (int) pkt->pay.len)); - if (pkt->ip->proto == 1) { - pkt->icmp = (struct icmp *) (pkt->ip + 1); - if (pkt->pay.len < sizeof(*pkt->icmp)) return; - mkpay(pkt, pkt->icmp + 1); - rx_icmp(ifp, pkt); - } else if (pkt->ip->proto == 17) { - pkt->udp = (struct udp *) (pkt->ip + 1); - if (pkt->pay.len < sizeof(*pkt->udp)) return; - mkpay(pkt, pkt->udp + 1); - if (pkt->udp->dport == mg_htons(68)) { - pkt->dhcp = (struct dhcp *) (pkt->udp + 1); - mkpay(pkt, pkt->dhcp + 1); - rx_dhcp_client(ifp, pkt); - } else if (ifp->enable_dhcp_server && pkt->udp->dport == mg_htons(67)) { - pkt->dhcp = (struct dhcp *) (pkt->udp + 1); - mkpay(pkt, pkt->dhcp + 1); - rx_dhcp_server(ifp, pkt); - } else { - rx_udp(ifp, pkt); +// clang-format off +static void w5500_wn(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr, void *buf, size_t len) { w5500_txn(s, block, addr, true, buf, len); } +static void w5500_w1(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr, uint8_t val) { w5500_wn(s, block, addr, &val, 1); } +static void w5500_w2(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr, uint16_t val) { uint8_t buf[2] = {(uint8_t) (val >> 8), (uint8_t) (val & 255)}; w5500_wn(s, block, addr, buf, sizeof(buf)); } +static void w5500_rn(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr, void *buf, size_t len) { w5500_txn(s, block, addr, false, buf, len); } +static uint8_t w5500_r1(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr) { uint8_t r = 0; w5500_rn(s, block, addr, &r, 1); return r; } +static uint16_t w5500_r2(struct mg_tcpip_spi *s, uint8_t block, uint16_t addr) { uint8_t buf[2] = {0, 0}; w5500_rn(s, block, addr, buf, sizeof(buf)); return (uint16_t) ((buf[0] << 8) | buf[1]); } +// clang-format on + +static size_t w5500_rx(void *buf, size_t buflen, struct mg_tcpip_if *ifp) { + struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data; + uint16_t r = 0, n = 0, len = (uint16_t) buflen, n2; // Read recv len + while ((n2 = w5500_r2(s, W5500_S0, 0x26)) > n) n = n2; // Until it is stable + // printf("RSR: %d\n", (int) n); + if (n > 0) { + uint16_t ptr = w5500_r2(s, W5500_S0, 0x28); // Get read pointer + n = w5500_r2(s, W5500_RX0, ptr); // Read frame length + if (n <= len + 2 && n > 1) { + r = (uint16_t) (n - 2); + w5500_rn(s, W5500_RX0, (uint16_t) (ptr + 2), buf, r); } - } else if (pkt->ip->proto == 6) { - pkt->tcp = (struct tcp *) (pkt->ip + 1); - if (pkt->pay.len < sizeof(*pkt->tcp)) return; - mkpay(pkt, pkt->tcp + 1); - uint16_t iplen = mg_ntohs(pkt->ip->len); - uint16_t off = (uint16_t) (sizeof(*pkt->ip) + ((pkt->tcp->off >> 4) * 4U)); - if (iplen >= off) pkt->pay.len = (size_t) (iplen - off); - rx_tcp(ifp, pkt); + w5500_w2(s, W5500_S0, 0x28, (uint16_t) (ptr + n)); // Advance read pointer + w5500_w1(s, W5500_S0, 1, 0x40); // Sock0 CR -> RECV + // printf(" RX_RD: tot=%u n=%u r=%u\n", n2, n, r); } + return r; } -static void rx_ip6(struct mip_if *ifp, struct pkt *pkt) { - // MG_DEBUG(("IP %d", (int) len)); - if (pkt->ip6->proto == 1 || pkt->ip6->proto == 58) { - pkt->icmp = (struct icmp *) (pkt->ip6 + 1); - if (pkt->pay.len < sizeof(*pkt->icmp)) return; - mkpay(pkt, pkt->icmp + 1); - rx_icmp(ifp, pkt); - } else if (pkt->ip6->proto == 17) { - pkt->udp = (struct udp *) (pkt->ip6 + 1); - if (pkt->pay.len < sizeof(*pkt->udp)) return; - // MG_DEBUG((" UDP %u %u -> %u", len, mg_htons(udp->sport), - // mg_htons(udp->dport))); - mkpay(pkt, pkt->udp + 1); +static size_t w5500_tx(const void *buf, size_t buflen, + struct mg_tcpip_if *ifp) { + struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data; + uint16_t i, ptr, n = 0, len = (uint16_t) buflen; + while (n < len) n = w5500_r2(s, W5500_S0, 0x20); // Wait for space + ptr = w5500_r2(s, W5500_S0, 0x24); // Get write pointer + w5500_wn(s, W5500_TX0, ptr, (void *) buf, len); // Write data + w5500_w2(s, W5500_S0, 0x24, (uint16_t) (ptr + len)); // Advance write pointer + w5500_w1(s, W5500_S0, 1, 0x20); // Sock0 CR -> SEND + for (i = 0; i < 40; i++) { + uint8_t ir = w5500_r1(s, W5500_S0, 2); // Read S0 IR + if (ir == 0) continue; + // printf("IR %d, len=%d, free=%d, ptr %d\n", ir, (int) len, (int) n, ptr); + w5500_w1(s, W5500_S0, 2, ir); // Write S0 IR: clear it! + if (ir & 8) len = 0; // Timeout. Report error + if (ir & (16 | 8)) break; // Stop on SEND_OK or timeout } + return len; } -static void mip_rx(struct mip_if *ifp, void *buf, size_t len) { - const uint8_t broadcast[] = {255, 255, 255, 255, 255, 255}; - struct pkt pkt; - memset(&pkt, 0, sizeof(pkt)); - pkt.raw.ptr = (char *) buf; - pkt.raw.len = len; - pkt.eth = (struct eth *) buf; - if (pkt.raw.len < sizeof(*pkt.eth)) return; // Truncated - runt? - if (memcmp(pkt.eth->dst, ifp->mac, sizeof(pkt.eth->dst)) != 0 && - memcmp(pkt.eth->dst, broadcast, sizeof(pkt.eth->dst)) != 0) { - // Not for us. Drop silently - } else if (pkt.eth->type == mg_htons(0x806)) { - pkt.arp = (struct arp *) (pkt.eth + 1); - if (sizeof(*pkt.eth) + sizeof(*pkt.arp) > pkt.raw.len) return; // Truncated - rx_arp(ifp, &pkt); - } else if (pkt.eth->type == mg_htons(0x86dd)) { - pkt.ip6 = (struct ip6 *) (pkt.eth + 1); - if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip6)) return; // Truncated - if ((pkt.ip6->ver >> 4) != 0x6) return; // Not IP - mkpay(&pkt, pkt.ip6 + 1); - rx_ip6(ifp, &pkt); - } else if (pkt.eth->type == mg_htons(0x800)) { - pkt.ip = (struct ip *) (pkt.eth + 1); - if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip)) return; // Truncated - // Truncate frame to what IP header tells us - if ((size_t) mg_ntohs(pkt.ip->len) + sizeof(struct eth) < pkt.raw.len) { - pkt.raw.len = (size_t) mg_ntohs(pkt.ip->len) + sizeof(struct eth); - } - if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip)) return; // Truncated - if ((pkt.ip->ver >> 4) != 4) return; // Not IP - mkpay(&pkt, pkt.ip + 1); - rx_ip(ifp, &pkt); - } else { - MG_DEBUG((" Unknown eth type %x", mg_htons(pkt.eth->type))); +static bool w5500_init(struct mg_tcpip_if *ifp) { + struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) ifp->driver_data; + s->end(s->spi); + w5500_w1(s, W5500_CR, 0, 0x80); // Reset chip: CR -> 0x80 + w5500_w1(s, W5500_CR, 0x2e, 0); // CR PHYCFGR -> reset + w5500_w1(s, W5500_CR, 0x2e, 0xf8); // CR PHYCFGR -> set + // w5500_wn(s, W5500_CR, 9, s->mac, 6); // Set source MAC + w5500_w1(s, W5500_S0, 0x1e, 16); // Sock0 RX buf size + w5500_w1(s, W5500_S0, 0x1f, 16); // Sock0 TX buf size + w5500_w1(s, W5500_S0, 0, 4); // Sock0 MR -> MACRAW + w5500_w1(s, W5500_S0, 1, 1); // Sock0 CR -> OPEN + return w5500_r1(s, W5500_S0, 3) == 0x42; // Sock0 SR == MACRAW +} + +static bool w5500_up(struct mg_tcpip_if *ifp) { + struct mg_tcpip_spi *spi = (struct mg_tcpip_spi *) ifp->driver_data; + uint8_t phycfgr = w5500_r1(spi, W5500_CR, 0x2e); + return phycfgr & 1; // Bit 0 of PHYCFGR is LNK (0 - down, 1 - up) +} + +struct mg_tcpip_driver mg_tcpip_driver_w5500 = {w5500_init, w5500_tx, w5500_rx, + w5500_up}; +#endif + +#ifdef MG_ENABLE_LINES +#line 1 "src/drivers/xmc.c" +#endif + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC) && MG_ENABLE_DRIVER_XMC + +struct ETH_GLOBAL_TypeDef { + volatile uint32_t MAC_CONFIGURATION, MAC_FRAME_FILTER, HASH_TABLE_HIGH, + HASH_TABLE_LOW, GMII_ADDRESS, GMII_DATA, FLOW_CONTROL, VLAN_TAG, VERSION, + DEBUG, REMOTE_WAKE_UP_FRAME_FILTER, PMT_CONTROL_STATUS, RESERVED[2], + INTERRUPT_STATUS, INTERRUPT_MASK, MAC_ADDRESS0_HIGH, MAC_ADDRESS0_LOW, + MAC_ADDRESS1_HIGH, MAC_ADDRESS1_LOW, MAC_ADDRESS2_HIGH, MAC_ADDRESS2_LOW, + MAC_ADDRESS3_HIGH, MAC_ADDRESS3_LOW, RESERVED1[40], MMC_CONTROL, + MMC_RECEIVE_INTERRUPT, MMC_TRANSMIT_INTERRUPT, MMC_RECEIVE_INTERRUPT_MASK, + MMC_TRANSMIT_INTERRUPT_MASK, TX_STATISTICS[26], RESERVED2, + RX_STATISTICS_1[26], RESERVED3[6], MMC_IPC_RECEIVE_INTERRUPT_MASK, + RESERVED4, MMC_IPC_RECEIVE_INTERRUPT, RESERVED5, RX_STATISTICS_2[30], + RESERVED7[286], TIMESTAMP_CONTROL, SUB_SECOND_INCREMENT, + SYSTEM_TIME_SECONDS, SYSTEM_TIME_NANOSECONDS, + SYSTEM_TIME_SECONDS_UPDATE, SYSTEM_TIME_NANOSECONDS_UPDATE, + TIMESTAMP_ADDEND, TARGET_TIME_SECONDS, TARGET_TIME_NANOSECONDS, + SYSTEM_TIME_HIGHER_WORD_SECONDS, TIMESTAMP_STATUS, + PPS_CONTROL, RESERVED8[564], BUS_MODE, TRANSMIT_POLL_DEMAND, + RECEIVE_POLL_DEMAND, RECEIVE_DESCRIPTOR_LIST_ADDRESS, + TRANSMIT_DESCRIPTOR_LIST_ADDRESS, STATUS, OPERATION_MODE, + INTERRUPT_ENABLE, MISSED_FRAME_AND_BUFFER_OVERFLOW_COUNTER, + RECEIVE_INTERRUPT_WATCHDOG_TIMER, RESERVED9, AHB_STATUS, + RESERVED10[6], CURRENT_HOST_TRANSMIT_DESCRIPTOR, + CURRENT_HOST_RECEIVE_DESCRIPTOR, CURRENT_HOST_TRANSMIT_BUFFER_ADDRESS, + CURRENT_HOST_RECEIVE_BUFFER_ADDRESS, HW_FEATURE; +}; + +#undef ETH0 +#define ETH0 ((struct ETH_GLOBAL_TypeDef*) 0x5000C000UL) + +#define ETH_PKT_SIZE 1536 // Max frame size +#define ETH_DESC_CNT 4 // Descriptors count +#define ETH_DS 4 // Descriptor size (words) + +static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; +static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; +static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors +static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors +static uint8_t s_txno; // Current TX descriptor +static uint8_t s_rxno; // Current RX descriptor + +static struct mg_tcpip_if *s_ifp; // MIP interface +enum { MG_PHY_ADDR = 0, MG_PHYREG_BCR = 0, MG_PHYREG_BSR = 1 }; + +static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) { + ETH0->GMII_ADDRESS = (ETH0->GMII_ADDRESS & 0x3c) | + ((uint32_t)addr << 11) | + ((uint32_t)reg << 6) | 1; + while ((ETH0->GMII_ADDRESS & 1) != 0) (void) 0; + return (uint16_t)(ETH0->GMII_DATA & 0xffff); +} + +static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { + ETH0->GMII_DATA = val; + ETH0->GMII_ADDRESS = (ETH0->GMII_ADDRESS & 0x3c) | + ((uint32_t)addr << 11) | + ((uint32_t)reg << 6) | 3; + while ((ETH0->GMII_ADDRESS & 1) != 0) (void) 0; +} + +static uint32_t get_clock_rate(struct mg_tcpip_driver_xmc_data *d) { + if (d->mdc_cr == -1) { + // assume ETH clock is 60MHz by default + // then according to 13.2.8.1, we need to set value 3 + return 3; } + + return d->mdc_cr; } -static void mip_poll(struct mip_if *ifp, uint64_t uptime_ms) { - if (ifp == NULL || ifp->driver == NULL) return; - bool expired_1000ms = mg_timer_expired(&ifp->timer_1000ms, 1000, uptime_ms); - ifp->now = uptime_ms; +static bool mg_tcpip_driver_xmc_init(struct mg_tcpip_if *ifp) { + struct mg_tcpip_driver_xmc_data *d = + (struct mg_tcpip_driver_xmc_data *) ifp->driver_data; + s_ifp = ifp; - // Handle physical interface up/down status - if (expired_1000ms && ifp->driver->up) { - bool up = ifp->driver->up(ifp); - bool current = ifp->state != MIP_STATE_DOWN; - if (up != current) { - ifp->state = up == false ? MIP_STATE_DOWN - : ifp->enable_dhcp_client ? MIP_STATE_UP - : MIP_STATE_READY; - if (!up && ifp->enable_dhcp_client) ifp->ip = 0; - onstatechange(ifp); + // reset MAC + ETH0->BUS_MODE |= 1; + while (ETH0->BUS_MODE & 1) (void) 0; + + // set clock rate + ETH0->GMII_ADDRESS = get_clock_rate(d) << 2; + + // init phy + struct mg_phy phy = {eth_read_phy, eth_write_phy}; + mg_phy_init(&phy, d->phy_addr, MG_PHY_CLOCKS_MAC); + + // configure MAC: DO, DM, FES, TC + ETH0->MAC_CONFIGURATION = MG_BIT(13) | MG_BIT(11) | MG_BIT(14) | MG_BIT(24); + + // set the MAC address + ETH0->MAC_ADDRESS0_HIGH = MG_U32(0, 0, ifp->mac[5], ifp->mac[4]); + ETH0->MAC_ADDRESS0_LOW = + MG_U32(ifp->mac[3], ifp->mac[2], ifp->mac[1], ifp->mac[0]); + + // Configure the receive filter + ETH0->MAC_FRAME_FILTER = MG_BIT(10) | MG_BIT(2); // HFP, HMC + // Disable flow control + ETH0->FLOW_CONTROL = 0; + // Enable store and forward mode + ETH0->OPERATION_MODE = MG_BIT(25) | MG_BIT(21); // RSF, TSF + + // Configure DMA bus mode (AAL, USP, RPBL, PBL) + ETH0->BUS_MODE = MG_BIT(25) | MG_BIT(23) | (32 << 17) | (32 << 8); + + // init RX descriptors + for (int i = 0; i < ETH_DESC_CNT; i++) { + s_rxdesc[i][0] = MG_BIT(31); // OWN descriptor + s_rxdesc[i][1] = MG_BIT(14) | ETH_PKT_SIZE; + s_rxdesc[i][2] = (uint32_t) s_rxbuf[i]; + if (i == ETH_DESC_CNT - 1) { + s_rxdesc[i][3] = (uint32_t) &s_rxdesc[0][0]; + } else { + s_rxdesc[i][3] = (uint32_t) &s_rxdesc[i + 1][0]; } } - if (ifp->state == MIP_STATE_DOWN) return; - // if (expired_1000ms) arp_cache_dump(ifp->arp_cache); + ETH0->RECEIVE_DESCRIPTOR_LIST_ADDRESS = (uint32_t) &s_rxdesc[0][0]; - if (ifp->ip == 0 && expired_1000ms) { - tx_dhcp_discover(ifp); // If IP not configured, send DHCP - } else if (ifp->enable_dhcp_client == false && expired_1000ms && ifp->gw && - arp_cache_find(ifp, ifp->gw) == NULL) { - arp_ask(ifp, ifp->gw); // If GW's MAC address in not in ARP cache + // init TX descriptors + for (int i = 0; i < ETH_DESC_CNT; i++) { + s_txdesc[i][0] = MG_BIT(30) | MG_BIT(20); + s_txdesc[i][2] = (uint32_t) s_txbuf[i]; + if (i == ETH_DESC_CNT - 1) { + s_txdesc[i][3] = (uint32_t) &s_txdesc[0][0]; + } else { + s_txdesc[i][3] = (uint32_t) &s_txdesc[i + 1][0]; + } } + ETH0->TRANSMIT_DESCRIPTOR_LIST_ADDRESS = (uint32_t) &s_txdesc[0][0]; - // Read data from the network - size_t len = ifp->driver->rx((void *) ifp->rx.ptr, ifp->rx.len, ifp); - mip_rx(ifp, (void *) ifp->rx.ptr, len); - qp_mark(QP_FRAMEDONE, (int) q_space(&ifp->queue)); + // Clear interrupts + ETH0->STATUS = 0xFFFFFFFF; - // Process timeouts - for (struct mg_connection *c = ifp->mgr->conns; c != NULL; c = c->next) { - if (c->is_udp || c->is_listening) continue; - if (c->is_connecting || c->is_resolving) continue; - struct connstate *s = (struct connstate *) (c + 1); - if (uptime_ms > s->timer) { - if (s->ttype == MIP_TTYPE_ACK) { - MG_DEBUG(("%lu ack %x %x", c->id, s->seq, s->ack)); - tx_tcp(ifp, c->rem.ip, TH_ACK, c->loc.port, c->rem.port, - mg_htonl(s->seq), mg_htonl(s->ack), "", 0); - } else { - if (s->tmiss++ > 2) { - mg_error(c, "keepalive"); - } else { - MG_DEBUG(("%lu keepalive", c->id)); - tx_tcp(ifp, c->rem.ip, TH_ACK, c->loc.port, c->rem.port, - mg_htonl(s->seq - 1), mg_htonl(s->ack), "", 0); - } - } - settmout(c, MIP_TTYPE_KEEPALIVE); - } - } -#ifdef MIP_QPROFILE - qp_log(); -#endif + // Disable MAC interrupts + ETH0->MMC_TRANSMIT_INTERRUPT_MASK = 0xFFFFFFFF; + ETH0->MMC_RECEIVE_INTERRUPT_MASK = 0xFFFFFFFF; + ETH0->MMC_IPC_RECEIVE_INTERRUPT_MASK = 0xFFFFFFFF; + ETH0->INTERRUPT_MASK = MG_BIT(9) | MG_BIT(3); // TSIM, PMTIM + + //Enable interrupts (NIE, RIE, TIE) + ETH0->INTERRUPT_ENABLE = MG_BIT(16) | MG_BIT(6) | MG_BIT(0); + + // Enable MAC transmission and reception (TE, RE) + ETH0->MAC_CONFIGURATION |= MG_BIT(3) | MG_BIT(2); + // Enable DMA transmission and reception (ST, SR) + ETH0->OPERATION_MODE |= MG_BIT(13) | MG_BIT(1); + return true; } -// This function executes in interrupt context, thus it should copy data -// somewhere fast. Note that newlib's malloc is not thread safe, thus use -// our lock-free queue with preallocated buffer to copy data and return asap -void mip_qwrite(void *buf, size_t len, struct mip_if *ifp) { - if (q_write(&ifp->queue, buf, len)) { - qp_mark(QP_FRAMEPUSHED, (int) q_space(&ifp->queue)); +static size_t mg_tcpip_driver_xmc_tx(const void *buf, size_t len, + struct mg_tcpip_if *ifp) { + if (len > sizeof(s_txbuf[s_txno])) { + MG_ERROR(("Frame too big, %ld", (long) len)); + len = 0; // Frame is too big + } else if ((s_txdesc[s_txno][0] & MG_BIT(31))) { + ifp->nerr++; + MG_ERROR(("No free descriptors")); + len = 0; // All descriptors are busy, fail } else { - ifp->dropped++; - qp_mark(QP_FRAMEDROPPED, ifp->dropped); - MG_ERROR(("dropped %d", (int) len)); + memcpy(s_txbuf[s_txno], buf, len); + s_txdesc[s_txno][1] = len; + // Table 13-19 Transmit Descriptor Word 0 (IC, LS, FS, TCH) + s_txdesc[s_txno][0] = MG_BIT(30) | MG_BIT(29) | MG_BIT(28) | MG_BIT(20); + s_txdesc[s_txno][0] |= MG_BIT(31); // OWN bit: handle control to DMA + if (++s_txno >= ETH_DESC_CNT) s_txno = 0; } -} -size_t mip_qread(void *buf, struct mip_if *ifp) { - size_t len = q_read(&ifp->queue, buf); - qp_mark(QP_FRAMEPOPPED, (int) q_space(&ifp->queue)); + // Resume processing + ETH0->STATUS = MG_BIT(2); // clear Transmit unavailable + ETH0->TRANSMIT_POLL_DEMAND = 0; return len; } -size_t mip_driver_rx(void *buf, size_t len, struct mip_if *ifp) { - return mip_qread((void *) ifp->rx.ptr, ifp); - (void) len, (void) buf; -} +static bool mg_tcpip_driver_xmc_up(struct mg_tcpip_if *ifp) { + struct mg_tcpip_driver_xmc_data *d = + (struct mg_tcpip_driver_xmc_data *) ifp->driver_data; + uint8_t speed = MG_PHY_SPEED_10M; + bool up = false, full_duplex = false; + struct mg_phy phy = {eth_read_phy, eth_write_phy}; + up = mg_phy_up(&phy, d->phy_addr, &full_duplex, &speed); + if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up + MG_DEBUG(("Link is %uM %s-duplex", speed == MG_PHY_SPEED_10M ? 10 : 100, + full_duplex ? "full" : "half")); + } + return up; +} + +void ETH0_IRQHandler(void); +void ETH0_IRQHandler(void) { + uint32_t irq_status = ETH0->STATUS; + + // check if a frame was received + if (irq_status & MG_BIT(6)) { + for (uint8_t i = 0; i < ETH_DESC_CNT; i++) { + if ((s_rxdesc[s_rxno][0] & MG_BIT(31)) == 0) { + size_t len = (s_rxdesc[s_rxno][0] & 0x3fff0000) >> 16; + mg_tcpip_qwrite(s_rxbuf[s_rxno], len, s_ifp); + s_rxdesc[s_rxno][0] = MG_BIT(31); // OWN bit: handle control to DMA + // Resume processing + ETH0->STATUS = MG_BIT(7) | MG_BIT(6); // clear RU and RI + ETH0->RECEIVE_POLL_DEMAND = 0; + if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; + } + } + ETH0->STATUS = MG_BIT(6); + } -void mip_init(struct mg_mgr *mgr, struct mip_if *ifp) { - if (ifp->driver->init && !ifp->driver->init(ifp)) { - MG_ERROR(("driver init failed")); - } else { - size_t maxpktsize = 1540; - ifp->rx.ptr = (char *) calloc(1, maxpktsize), ifp->rx.len = maxpktsize; - ifp->tx.ptr = (char *) calloc(1, maxpktsize), ifp->tx.len = maxpktsize; - if (ifp->queue.len) ifp->queue.buf = (uint8_t *) calloc(1, ifp->queue.len); - ifp->timer_1000ms = mg_millis(); - arp_cache_init(ifp->arp_cache, MIP_ARP_ENTRIES, 12); - mgr->priv = ifp; - ifp->mgr = mgr; - mgr->extraconnsize = sizeof(struct connstate); - if (ifp->ip == 0) ifp->enable_dhcp_client = true; -#ifdef MIP_QPROFILE - qp_init(); -#endif + // clear Successful transmission interrupt + if (irq_status & 1) { + ETH0->STATUS = 1; } -} -void mip_free(struct mip_if *ifp) { - free((char *) ifp->rx.ptr); - free((char *) ifp->tx.ptr); + // clear normal interrupt + if (irq_status & MG_BIT(16)) { + ETH0->STATUS = MG_BIT(16); + } } -int mg_mkpipe(struct mg_mgr *m, mg_event_handler_t fn, void *d, bool udp) { - (void) m, (void) fn, (void) d, (void) udp; - MG_ERROR(("Not implemented")); - return -1; -} +struct mg_tcpip_driver mg_tcpip_driver_xmc = { + mg_tcpip_driver_xmc_init, mg_tcpip_driver_xmc_tx, NULL, + mg_tcpip_driver_xmc_up}; +#endif -#if 0 -static uint16_t mkeport(void) { - uint16_t a = 0, b = mg_millis() & 0xffffU, c = MIP_ETHEMERAL_PORT; - mg_random(&a, sizeof(a)); - c += (a ^ b) % (0xffffU - MIP_ETHEMERAL_PORT); - return c; -} +#ifdef MG_ENABLE_LINES +#line 1 "src/drivers/xmc7.c" #endif -void mg_connect_resolved(struct mg_connection *c) { - struct mip_if *ifp = (struct mip_if *) c->mgr->priv; - c->is_resolving = 0; - if (ifp->eport < MIP_ETHEMERAL_PORT) ifp->eport = MIP_ETHEMERAL_PORT; - c->loc.ip = ifp->ip; - c->loc.port = mg_htons(ifp->eport++); - MG_DEBUG(("%lu %I:%hu->%I:%hu", c->id, 4, &c->loc.ip, mg_ntohs(c->loc.port), - 4, &c->rem.ip, mg_ntohs(c->rem.port))); - mg_call(c, MG_EV_RESOLVE, NULL); - if (c->is_udp) { - mg_call(c, MG_EV_CONNECT, NULL); - } else { - uint32_t isn = mg_htonl((uint32_t) mg_ntohs(c->loc.port)); - tx_tcp(ifp, c->rem.ip, TH_SYN, c->loc.port, c->rem.port, isn, 0, NULL, 0); - c->is_connecting = 1; - } -} -bool mg_open_listener(struct mg_connection *c, const char *url) { - c->loc.port = mg_htons(mg_url_port(url)); - return true; -} +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC7) && MG_ENABLE_DRIVER_XMC7 + +struct ETH_Type { + volatile uint32_t CTL, STATUS, RESERVED[1022], NETWORK_CONTROL, + NETWORK_CONFIG, NETWORK_STATUS, USER_IO_REGISTER, DMA_CONFIG, + TRANSMIT_STATUS, RECEIVE_Q_PTR, TRANSMIT_Q_PTR, RECEIVE_STATUS, + INT_STATUS, INT_ENABLE, INT_DISABLE, INT_MASK, PHY_MANAGEMENT, PAUSE_TIME, + TX_PAUSE_QUANTUM, PBUF_TXCUTTHRU, PBUF_RXCUTTHRU, JUMBO_MAX_LENGTH, + EXTERNAL_FIFO_INTERFACE, RESERVED1, AXI_MAX_PIPELINE, RSC_CONTROL, + INT_MODERATION, SYS_WAKE_TIME, RESERVED2[7], HASH_BOTTOM, HASH_TOP, + SPEC_ADD1_BOTTOM, SPEC_ADD1_TOP, SPEC_ADD2_BOTTOM, SPEC_ADD2_TOP, + SPEC_ADD3_BOTTOM, SPEC_ADD3_TOP, SPEC_ADD4_BOTTOM, SPEC_ADD4_TOP, + SPEC_TYPE1, SPEC_TYPE2, SPEC_TYPE3, SPEC_TYPE4, WOL_REGISTER, + STRETCH_RATIO, STACKED_VLAN, TX_PFC_PAUSE, MASK_ADD1_BOTTOM, + MASK_ADD1_TOP, DMA_ADDR_OR_MASK, RX_PTP_UNICAST, TX_PTP_UNICAST, + TSU_NSEC_CMP, TSU_SEC_CMP, TSU_MSB_SEC_CMP, TSU_PTP_TX_MSB_SEC, + TSU_PTP_RX_MSB_SEC, TSU_PEER_TX_MSB_SEC, TSU_PEER_RX_MSB_SEC, + DPRAM_FILL_DBG, REVISION_REG, OCTETS_TXED_BOTTOM, OCTETS_TXED_TOP, + FRAMES_TXED_OK, BROADCAST_TXED, MULTICAST_TXED, PAUSE_FRAMES_TXED, + FRAMES_TXED_64, FRAMES_TXED_65, FRAMES_TXED_128, FRAMES_TXED_256, + FRAMES_TXED_512, FRAMES_TXED_1024, FRAMES_TXED_1519, TX_UNDERRUNS, + SINGLE_COLLISIONS, MULTIPLE_COLLISIONS, EXCESSIVE_COLLISIONS, + LATE_COLLISIONS, DEFERRED_FRAMES, CRS_ERRORS, OCTETS_RXED_BOTTOM, + OCTETS_RXED_TOP, FRAMES_RXED_OK, BROADCAST_RXED, MULTICAST_RXED, + PAUSE_FRAMES_RXED, FRAMES_RXED_64, FRAMES_RXED_65, FRAMES_RXED_128, + FRAMES_RXED_256, FRAMES_RXED_512, FRAMES_RXED_1024, FRAMES_RXED_1519, + UNDERSIZE_FRAMES, EXCESSIVE_RX_LENGTH, RX_JABBERS, FCS_ERRORS, + RX_LENGTH_ERRORS, RX_SYMBOL_ERRORS, ALIGNMENT_ERRORS, RX_RESOURCE_ERRORS, + RX_OVERRUNS, RX_IP_CK_ERRORS, RX_TCP_CK_ERRORS, RX_UDP_CK_ERRORS, + AUTO_FLUSHED_PKTS, RESERVED3, TSU_TIMER_INCR_SUB_NSEC, TSU_TIMER_MSB_SEC, + TSU_STROBE_MSB_SEC, TSU_STROBE_SEC, TSU_STROBE_NSEC, TSU_TIMER_SEC, + TSU_TIMER_NSEC, TSU_TIMER_ADJUST, TSU_TIMER_INCR, TSU_PTP_TX_SEC, + TSU_PTP_TX_NSEC, TSU_PTP_RX_SEC, TSU_PTP_RX_NSEC, TSU_PEER_TX_SEC, + TSU_PEER_TX_NSEC, TSU_PEER_RX_SEC, TSU_PEER_RX_NSEC, PCS_CONTROL, + PCS_STATUS, RESERVED4[2], PCS_AN_ADV, PCS_AN_LP_BASE, PCS_AN_EXP, + PCS_AN_NP_TX, PCS_AN_LP_NP, RESERVED5[6], PCS_AN_EXT_STATUS, RESERVED6[8], + TX_PAUSE_QUANTUM1, TX_PAUSE_QUANTUM2, TX_PAUSE_QUANTUM3, RESERVED7, + RX_LPI, RX_LPI_TIME, TX_LPI, TX_LPI_TIME, DESIGNCFG_DEBUG1, + DESIGNCFG_DEBUG2, DESIGNCFG_DEBUG3, DESIGNCFG_DEBUG4, DESIGNCFG_DEBUG5, + DESIGNCFG_DEBUG6, DESIGNCFG_DEBUG7, DESIGNCFG_DEBUG8, DESIGNCFG_DEBUG9, + DESIGNCFG_DEBUG10, RESERVED8[22], SPEC_ADD5_BOTTOM, SPEC_ADD5_TOP, + RESERVED9[60], SPEC_ADD36_BOTTOM, SPEC_ADD36_TOP, INT_Q1_STATUS, + INT_Q2_STATUS, INT_Q3_STATUS, RESERVED10[11], INT_Q15_STATUS, RESERVED11, + TRANSMIT_Q1_PTR, TRANSMIT_Q2_PTR, TRANSMIT_Q3_PTR, RESERVED12[11], + TRANSMIT_Q15_PTR, RESERVED13, RECEIVE_Q1_PTR, RECEIVE_Q2_PTR, + RECEIVE_Q3_PTR, RESERVED14[3], RECEIVE_Q7_PTR, RESERVED15, + DMA_RXBUF_SIZE_Q1, DMA_RXBUF_SIZE_Q2, DMA_RXBUF_SIZE_Q3, RESERVED16[3], + DMA_RXBUF_SIZE_Q7, CBS_CONTROL, CBS_IDLESLOPE_Q_A, CBS_IDLESLOPE_Q_B, + UPPER_TX_Q_BASE_ADDR, TX_BD_CONTROL, RX_BD_CONTROL, UPPER_RX_Q_BASE_ADDR, + RESERVED17[2], HIDDEN_REG0, HIDDEN_REG1, HIDDEN_REG2, HIDDEN_REG3, + RESERVED18[2], HIDDEN_REG4, HIDDEN_REG5; +}; -static void write_conn(struct mg_connection *c) { - long len = c->is_tls ? mg_tls_send(c, c->send.buf, c->send.len) - : mg_io_send(c, c->send.buf, c->send.len); - if (len > 0) { - mg_iobuf_del(&c->send, 0, (size_t) len); - mg_call(c, MG_EV_WRITE, &len); - } +#define ETH0 ((struct ETH_Type *) 0x40490000) + +#define ETH_PKT_SIZE 1536 // Max frame size +#define ETH_DESC_CNT 4 // Descriptors count +#define ETH_DS 2 // Descriptor size (words) + +static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; +static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; +static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]; // RX descriptors +static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors +static uint8_t s_txno; // Current TX descriptor +static uint8_t s_rxno; // Current RX descriptor + +static struct mg_tcpip_if *s_ifp; // MIP interface +enum { MG_PHY_ADDR = 0, MG_PHYREG_BCR = 0, MG_PHYREG_BSR = 1 }; + +static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) { + // WRITE1, READ OPERATION, PHY, REG, WRITE10 + ETH0->PHY_MANAGEMENT = MG_BIT(30) | MG_BIT(29) | ((addr & 0xf) << 24) | + ((reg & 0x1f) << 18) | MG_BIT(17); + while ((ETH0->NETWORK_STATUS & MG_BIT(2)) == 0) (void) 0; + return ETH0->PHY_MANAGEMENT & 0xffff; } -static void close_conn(struct mg_connection *c) { - struct connstate *s = (struct connstate *) (c + 1); - mg_iobuf_free(&s->raw); // For TLS connections, release raw data - if (c->is_udp == false && c->is_listening == false) { // For TCP conns, - struct mip_if *ifp = (struct mip_if *) c->mgr->priv; // send TCP FIN - tx_tcp(ifp, c->rem.ip, TH_FIN | TH_ACK, c->loc.port, c->rem.port, - mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0); - } - mg_close_conn(c); +static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { + ETH0->PHY_MANAGEMENT = MG_BIT(30) | MG_BIT(28) | ((addr & 0xf) << 24) | + ((reg & 0x1f) << 18) | MG_BIT(17) | val; + while ((ETH0->NETWORK_STATUS & MG_BIT(2)) == 0) (void) 0; } -static bool can_write(struct mg_connection *c) { - return c->is_connecting == 0 && c->is_resolving == 0 && c->send.len > 0 && - c->is_tls_hs == 0; +static uint32_t get_clock_rate(struct mg_tcpip_driver_xmc7_data *d) { + // see ETH0 -> NETWORK_CONFIG register + (void) d; + return 3; } -void mg_mgr_poll(struct mg_mgr *mgr, int ms) { - struct mg_connection *c, *tmp; - uint64_t now = mg_millis(); - mip_poll((struct mip_if *) mgr->priv, now); - mg_timer_poll(&mgr->timers, now); - for (c = mgr->conns; c != NULL; c = tmp) { - tmp = c->next; - mg_call(c, MG_EV_POLL, &now); - MG_VERBOSE(("%lu .. %c%c%c%c%c", c->id, c->is_tls ? 'T' : 't', - c->is_connecting ? 'C' : 'c', c->is_tls_hs ? 'H' : 'h', - c->is_resolving ? 'R' : 'r', c->is_closing ? 'C' : 'c')); - if (c->is_tls_hs) mg_tls_handshake(c); - if (can_write(c)) write_conn(c); - if (c->is_draining && c->send.len == 0) c->is_closing = 1; - if (c->is_closing) close_conn(c); +static bool mg_tcpip_driver_xmc7_init(struct mg_tcpip_if *ifp) { + struct mg_tcpip_driver_xmc7_data *d = + (struct mg_tcpip_driver_xmc7_data *) ifp->driver_data; + s_ifp = ifp; + + // enable controller, set RGMII mode + ETH0->CTL = MG_BIT(31) | 2; + + uint32_t cr = get_clock_rate(d); + // set NSP change, ignore RX FCS, data bus width, clock rate + // frame length 1536, full duplex, speed + ETH0->NETWORK_CONFIG = MG_BIT(29) | MG_BIT(26) | MG_BIT(21) | + ((cr & 7) << 18) | MG_BIT(8) | MG_BIT(4) | + MG_BIT(1) | MG_BIT(0); + + // config DMA settings: Force TX burst, Discard on Error, set RX buffer size + // to 1536, TX_PBUF_SIZE, RX_PBUF_SIZE, AMBA_BURST_LENGTH + ETH0->DMA_CONFIG = + MG_BIT(26) | MG_BIT(24) | (0x18 << 16) | MG_BIT(10) | (3 << 8) | 4; + + // initialize descriptors + for (int i = 0; i < ETH_DESC_CNT; i++) { + s_rxdesc[i][0] = (uint32_t) s_rxbuf[i]; + if (i == ETH_DESC_CNT - 1) { + s_rxdesc[i][0] |= MG_BIT(1); // mark last descriptor + } + + s_txdesc[i][0] = (uint32_t) s_txbuf[i]; + s_txdesc[i][1] = MG_BIT(31); // OWN descriptor + if (i == ETH_DESC_CNT - 1) { + s_txdesc[i][1] |= MG_BIT(30); // mark last descriptor + } } - (void) ms; + ETH0->RECEIVE_Q_PTR = (uint32_t) s_rxdesc; + ETH0->TRANSMIT_Q_PTR = (uint32_t) s_txdesc; + + // disable other queues + ETH0->TRANSMIT_Q2_PTR = 1; + ETH0->TRANSMIT_Q1_PTR = 1; + ETH0->RECEIVE_Q2_PTR = 1; + ETH0->RECEIVE_Q1_PTR = 1; + + // enable interrupts (TX and RX complete) + ETH0->INT_ENABLE = MG_BIT(7) | MG_BIT(1); + + // set MAC address + ETH0->SPEC_ADD1_BOTTOM = + ifp->mac[3] << 24 | ifp->mac[2] << 16 | ifp->mac[1] << 8 | ifp->mac[0]; + ETH0->SPEC_ADD1_TOP = ifp->mac[5] << 8 | ifp->mac[4]; + + // enable MDIO, TX, RX + ETH0->NETWORK_CONTROL = MG_BIT(4) | MG_BIT(3) | MG_BIT(2); + + // start transmission + ETH0->NETWORK_CONTROL |= MG_BIT(9); + + // init phy + struct mg_phy phy = {eth_read_phy, eth_write_phy}; + mg_phy_init(&phy, d->phy_addr, MG_PHY_CLOCKS_MAC); + + (void) d; + return true; } -bool mg_send(struct mg_connection *c, const void *buf, size_t len) { - struct mip_if *ifp = (struct mip_if *) c->mgr->priv; - bool res = false; - if (ifp->ip == 0 || ifp->state != MIP_STATE_READY) { - mg_error(c, "net down"); - } else if (c->is_udp) { - tx_udp(ifp, ifp->ip, c->loc.port, c->rem.ip, c->rem.port, buf, len); - res = true; +static size_t mg_tcpip_driver_xmc7_tx(const void *buf, size_t len, + struct mg_tcpip_if *ifp) { + if (len > sizeof(s_txbuf[s_txno])) { + MG_ERROR(("Frame too big, %ld", (long) len)); + len = 0; // Frame is too big + } else if (((s_txdesc[s_txno][1] & MG_BIT(31)) == 0)) { + ifp->nerr++; + MG_ERROR(("No free descriptors")); + len = 0; // All descriptors are busy, fail } else { - res = mg_iobuf_add(&c->send, c->send.len, buf, len); - } - return res; -} + memcpy(s_txbuf[s_txno], buf, len); + s_txdesc[s_txno][1] = (s_txno == ETH_DESC_CNT - 1 ? MG_BIT(30) : 0) | + MG_BIT(15) | len; // Last buffer and length -#ifdef MIP_QPROFILE + ETH0->NETWORK_CONTROL |= MG_BIT(9); // enable transmission + if (++s_txno >= ETH_DESC_CNT) s_txno = 0; + } -#pragma pack(push, 1) -struct qpentry { - uint32_t timestamp; - uint16_t type; - uint16_t len; -}; -#pragma pack(pop) + MG_DSB(); + ETH0->TRANSMIT_STATUS = ETH0->TRANSMIT_STATUS; + ETH0->NETWORK_CONTROL |= MG_BIT(9); // enable transmission -static struct queue qp; + return len; +} -// This is called from IRQ and main contexts; two producers, single consumer -// TODO(scaprile): avoid concurrency issues (2 queues ?) -void qp_mark(unsigned int type, int len) { - static bool ovf = false; - static uint16_t irq_ctr = 0, drop_ctr = 0; - struct qpentry e = {.timestamp = (uint32_t) mg_millis(), - .type = (uint16_t) type, - .len = (uint16_t) len}; - if (type == QP_IRQTRIGGERED) e.len = ++irq_ctr; - if (ovf) { - e.type = (uint16_t) QP_QUEUEOVF; - e.len = drop_ctr; +static bool mg_tcpip_driver_xmc7_up(struct mg_tcpip_if *ifp) { + struct mg_tcpip_driver_xmc7_data *d = + (struct mg_tcpip_driver_xmc7_data *) ifp->driver_data; + uint8_t speed = MG_PHY_SPEED_10M; + bool up = false, full_duplex = false; + struct mg_phy phy = {eth_read_phy, eth_write_phy}; + up = mg_phy_up(&phy, d->phy_addr, &full_duplex, &speed); + if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up + if (speed == MG_PHY_SPEED_1000M) { + ETH0->NETWORK_CONFIG |= MG_BIT(10); + } + MG_DEBUG(("Link is %uM %s-duplex", + speed == MG_PHY_SPEED_10M ? 10 : + (speed == MG_PHY_SPEED_100M ? 100 : 1000), + full_duplex ? "full" : "half")); } - ovf = !q_write(&qp, &e, sizeof(e)); + (void) d; + return up; } -void qp_log(void) { - struct qpentry e; - const char *titles[] = {"IRQ ", "PUSH", "POP ", "DONE", "DROP", "OVFL"}; - for (int i = 0; i < 10 && q_read(&qp, &e); i++) { - MG_INFO(("%lx %s %u", e.timestamp, titles[e.type], e.len)); +void ETH_IRQHandler(void) { + uint32_t irq_status = ETH0->INT_STATUS; + if (irq_status & MG_BIT(1)) { + for (uint8_t i = 0; i < ETH_DESC_CNT; i++) { + if (s_rxdesc[s_rxno][0] & MG_BIT(0)) { + size_t len = s_rxdesc[s_rxno][1] & (MG_BIT(13) - 1); + //MG_INFO(("Receive complete: %ld bytes", len)); + mg_tcpip_qwrite(s_rxbuf[s_rxno], len, s_ifp); + s_rxdesc[s_rxno][0] &= ~MG_BIT(0); // OWN bit: handle control to DMA + if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; + } + } } -} -void qp_init(void) { - qp.len = 500 * (sizeof(size_t) + sizeof(struct qpentry)); - qp.buf = calloc(1, qp.len); // THERE IS NO FREE + ETH0->INT_STATUS = irq_status; } -#endif // MIP_QPROFILE -#endif // MG_ENABLE_MIP +struct mg_tcpip_driver mg_tcpip_driver_xmc7 = {mg_tcpip_driver_xmc7_init, + mg_tcpip_driver_xmc7_tx, NULL, + mg_tcpip_driver_xmc7_up}; +#endif diff --git a/mongoose/mongoose.h b/mongoose/mongoose.h index 350aad9c..3a439a6e 100644 --- a/mongoose/mongoose.h +++ b/mongoose/mongoose.h @@ -1,5 +1,5 @@ // Copyright (c) 2004-2013 Sergey Lyubka -// Copyright (c) 2013-2022 Cesanta Software Limited +// Copyright (c) 2013-2024 Cesanta Software Limited // All rights reserved // // This software is dual-licensed: you can redistribute it and/or modify @@ -15,58 +15,48 @@ // 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 +// SPDX-License-Identifier: GPL-2.0-only or commercial #ifndef MONGOOSE_H #define MONGOOSE_H -#define MG_VERSION "7.8" +#define MG_VERSION "7.14" #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_RTX 9 // Keil MDK RTX -#define MG_ARCH_TIRTOS 10 // Texas Semi TI-RTOS -#define MG_ARCH_RP2040 11 // Raspberry Pi RP2040 +#define MG_ARCH_CUSTOM 0 // User creates its own mongoose_config.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 #endif #endif // !defined(MG_ARCH) #if !defined(MG_ARCH) || (MG_ARCH == MG_ARCH_CUSTOM) -#include "mongoose_custom.h" // keep this include +#include "mongoose_config.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=..." +#error "MG_ARCH is not specified and we couldn't guess it. Define MG_ARCH=... in your compiler" #endif // http://esr.ibiblio.org/?p=5095 @@ -130,7 +120,8 @@ extern "C" { #include #include -#include +#include // Use angle brackets to avoid +#include // amalgamation ditching them #define MG_PATH_MAX 128 @@ -166,15 +157,24 @@ extern "C" { #if MG_ARCH == MG_ARCH_FREERTOS #include -// #include // Cannot include errno - might conflict with lwip! +#if !defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP +#include +#endif #include #include #include #include #include -#include // rand(), strtol(), atoi() +#include // rand(), strtol(), atoi() #include +#if defined(__ARMCC_VERSION) +#define mode_t size_t +#include +#include +#elif defined(__CCRH__) +#else #include +#endif #include #include @@ -186,7 +186,7 @@ extern "C" { #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) +#define strdup(s) mg_mprintf("%s", s) // Re-route calloc/free to the FreeRTOS's functions, don't use stdlib static inline void *mg_calloc(size_t cnt, size_t size) { @@ -240,9 +240,34 @@ static inline int mg_mkdir(const char *path, mode_t mode) { #include int mkdir(const char *, mode_t); #endif - - -#if MG_ARCH == MG_ARCH_RTX + + +#if MG_ARCH == MG_ARCH_RTTHREAD + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include From patchwork Sat Jun 15 19:11:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Glembotzki X-Patchwork-Id: 1948199 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=Y00sBorY; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=S9rlJHmi; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::33d; helo=mail-wm1-x33d.google.com; envelope-from=swupdate+bncbdy5juxlviebb4gsw6zqmgqe6qh5b6a@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-wm1-x33d.google.com (mail-wm1-x33d.google.com [IPv6:2a00:1450:4864:20::33d]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W1mFS5RVgz20Pb for ; Sun, 16 Jun 2024 05:20:28 +1000 (AEST) Received: by mail-wm1-x33d.google.com with SMTP id 5b1f17b1804b1-42183fdb37csf24126505e9.3 for ; Sat, 15 Jun 2024 12:20:28 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718479218; cv=pass; d=google.com; s=arc-20160816; b=IqTOq1I3abP/hXm6VGYWkvcLqdNel/zdzJbHstD//ykO0q39ehqvp2pGcHuHWbYYWq 7jcXSQPW83X/+MDW7RvBLNWEVxC3p+4SwWWY/K/b9MZrGje60nzCuqrrITuQ8XydmsuL 8Hix4EUbnctK4rfcOzwpwjNuwZF8SfJZSiqrDfc07DJ7byrapqsYch+DQdqcObHv/QYK F+Fz63ssZItL6qgvad05Iax5OHC4nzvzPssZYTfjOe4t3zYMsgnsYQHQa+4zzhLSX+gG cLxRUkvOcvaJ3tFxr98th2eDl3mihTQRSrE4aAgwo/HCsX5lDS9HgfaHgnwNUa3XkHTu zzZQ== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:dkim-signature :dkim-signature; bh=9SwlhHVG5Qbg2Cb/768W7nwNcqH8MxskjQlDBzXJhk8=; fh=iBrkbFtS9wMSm6fOSy5P9yunpub/IIiIaGNfdtoADt0=; b=UIEACM9WLFTK3DYal+ZjxDq2zbO/4GTnTAKa6uCwq1Wjn1DBTx8i/CmNNF0LBDCb09 py4z9cdy1IH6lfOhp4YNbonxnKLdrBlOc9QuhPgSIeW6VdFjJFoLSGmnZ5Bgj5zlEDPs faL54LAcjwajVghYWZdoy2makEGr0yIjUloMN77FqMD6NTSn588PhvILjKq8p3hCwXXp 5dM6Ux4mOt+SUm6kqB8JAp9wz/AXSz7QTDtsoA0FwR7IuRScNtB+cXmEEfXr9GsjopI4 GZOXIT+CofYGqA+cKeCG/M/6T/Y3NppPw+RlftenN4/mH+bRpJtjMi2qp1SLbN6ezrcQ ckcw==; darn=patchwork.ozlabs.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=fhUh8n5B; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::62d as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1718479218; x=1719084018; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:sender:from:to:cc:subject:date:message-id :reply-to; bh=9SwlhHVG5Qbg2Cb/768W7nwNcqH8MxskjQlDBzXJhk8=; b=Y00sBorYv7rOLHRD2a9T4/yrRa4xKolb1xMtkoO6etu4aPGMNI9uXUsN07Lopq3koF ReGPEgge39ojJzLFg3af2n0yGpQ54KUUzsOvB1O+9MQAgt2S4YIoQaGO6tU/4DFiH53Q Ar7h74L2EvRHDpbqJP5vUBM6Glpz7mfPPhMdSYcalUMvK9/+WysTTmx+DoKTeICqs+Hg +yGEd16H9uW7SG0O8j946gg57GcBhv7AgGD6WSYyqWP32EaUanlemi4/jMw0qsZ47tJq E35p+TMmhUKx00Ow+Bfuz/p+Fuw1SX0L0wg6u7uLFfI+YAOkSzSbgv9jSp4Y2sWE0ANW HnMA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718479218; x=1719084018; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=9SwlhHVG5Qbg2Cb/768W7nwNcqH8MxskjQlDBzXJhk8=; b=S9rlJHmiL6T1cIXJLtUa7tEdEYTE4hpdE02KPBUdaXMFM1p8KQsErsBmw1rlT5RT4j OZKWJG3mvQwcRb5BeF9MKuCSCNW33MCSCB0C0zqyhwVflD56jotvRNyAO4y+cw1VC1Aa dvHzQTtNtVhiFQeQBy69zvk1e3+vF2169eMuRsh6yVW51N2V0BSinGuQtqyO4gAeW6Kg ZKFgW2aeUvvCMfJ/BOW6zvqTEQiJdxCwd6yVOGQg3VjMDYRKPO3nLW+DaES3RN9lZYl1 b/rShuevOPovcBXJWYDVJuT6slfVK4AUKMXfKtvwenTQ5Syi+4Y3I2IlU7TsVX1ecL6R FyQQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718479218; x=1719084018; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :x-beenthere:x-gm-message-state:sender:from:to:cc:subject:date :message-id:reply-to; bh=9SwlhHVG5Qbg2Cb/768W7nwNcqH8MxskjQlDBzXJhk8=; b=Icrwd0FofaTfSje9h9LTeStqtlOgkOfxCtZDyEbRa0ufK0E4qdyB5nqnBydm91RHt1 n1LGC6Mne6sAuMAV4Rcc6yazyFRdrXqgjUmQB+uaVrswTGmBjtjENZFL2Z40aFllu+qI Kv5xPBO6e2G2BVezV8GnOGYUFkV94yzOUEHsKvlK2Okuxv4ClQQrCw6j4fryjZStqyU5 Z75qCl/ly2FVjCd9tIBcn3In7BjTy8bEexVS2FsS7XvOPveUL6diuD4G8z4oQDYPmCgQ HrPaQR2yZMc1D/zWGgY2F+Y6Rt1hRhraNfuaL24VRz878MOAfnngiKZhdMLGBHqB4uF9 qJIQ== Sender: swupdate@googlegroups.com X-Forwarded-Encrypted: i=2; AJvYcCWhMFiYDUyM+h/B8FmUzKp4LJtl+0685FTkMrT42H1HTn5SHVp8gnqDdFXNLv3fUSbx6bT6RrxUmJsQc/Z0L3+Hua5c0MCyGzDT9cVzZw== X-Gm-Message-State: AOJu0Yx+fkui5G2vodDsmfOcFxdh4vRck4Oa2Nto9HmYOjqC6xvr6IBi rxMIWAHFfOBoGasFNql6+y7Fo5ssBx8Vc5rHlKhXmPx65lPcxEOr X-Google-Smtp-Source: AGHT+IFiemGMX4Lnc+jU4yjp0cB+QvUJa34iK+fGIzOOB3y1UDeqBieI4dBogcnJL6lbqAG4ZqMIuA== X-Received: by 2002:a05:600c:1f90:b0:421:9502:3f24 with SMTP id 5b1f17b1804b1-423048264cdmr44827595e9.14.1718479217431; Sat, 15 Jun 2024 12:20:17 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a05:600c:3b8b:b0:421:7f30:7ce8 with SMTP id 5b1f17b1804b1-423b6616fe2ls2487885e9.1.-pod-prod-02-eu; Sat, 15 Jun 2024 12:20:15 -0700 (PDT) X-Received: by 2002:a05:600c:1e23:b0:41a:b54a:9ad8 with SMTP id 5b1f17b1804b1-423047dca64mr53495495e9.0.1718479214702; Sat, 15 Jun 2024 12:20:14 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1718479214; cv=none; d=google.com; s=arc-20160816; b=vgmM7g2ccSVjeOmcJmQ99JKU8vW54oqUYac1AHwMiyNE/5DToPCSrjP3c82GxZGSzk Rd7bTN7XWNfLhlxOJdnc+VgcLNgXMYymWdqdz5vheR40lvKk3u8cmutnvhuEZG/SjDi1 +RYDce7rbvkWm1r51nugHTcGWJOZ1E0wWmhoZvqFyzECbK+99ag1nchxQqDEzhwh6u/T mCJ2YNbS73V4squtL6E7LUE16TLDKHY5Jit28NxYcyW/I5aOLYFaCkx8AkbaU8DynY2r BUGwxn6QlWpImbp4Zoe97kZM4m4O1Pg7fKaehQ0PsKneeww6zo8F+S32CUB4YW1YHdPy OvVw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=rqYmM6bY7TgKyjrTtvIoxFOxiRC/94Kz6BUBVv7sj80=; fh=zydHuzCQWrku2OPQyZfraJZFcOpEXLQ/YBcu3QNiBd0=; b=z7lszeNuJYvFaXMNwUC9xL0aO83iM/Prl9qPGs7FYD1e2fRPs5eXL3ZAoPsRY5/oTO T6w8iG6UUnAhnV1MX+quZCb/DLOJJvrbjJIR+z9dqStu7LFMfLZgPdhAPvwlABNYPyDr xZzWRKkV85/YCOV8iPmaeNAHDZ+z/Hpb3lU6/kYDq/WwBPtXlMaugQYYG8rwCKxZO3mE 2yLpIBRNeJgKr60LNrzzAJh5ejnlg/NK4TQ5gZZGfjAaDgL2f9JsZ7ZDlhBQEqAjqXV7 bNSeyCVibl3Sue8LNAYd4MqfFsLo2K5djHROLv0nZOvHZ4ASHwOtFb11oXd0nsdg0Mdv aIHA==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=fhUh8n5B; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::62d as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-ej1-x62d.google.com (mail-ej1-x62d.google.com. [2a00:1450:4864:20::62d]) by gmr-mx.google.com with ESMTPS id 5b1f17b1804b1-42284b090dfsi6260845e9.0.2024.06.15.12.20.14 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 15 Jun 2024 12:20:14 -0700 (PDT) Received-SPF: pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::62d as permitted sender) client-ip=2a00:1450:4864:20::62d; Received: by mail-ej1-x62d.google.com with SMTP id a640c23a62f3a-a6265d3ba8fso377571666b.0 for ; Sat, 15 Jun 2024 12:20:14 -0700 (PDT) X-Received: by 2002:a17:906:eb55:b0:a5c:d67a:e8ef with SMTP id a640c23a62f3a-a6f60d297e4mr392415066b.31.1718479213456; Sat, 15 Jun 2024 12:20:13 -0700 (PDT) Received: from PC-2635.irisgmbh.local ([2a02:8108:96c0:76fc::80bb]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a6f56db61e0sm327283766b.49.2024.06.15.12.20.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 12:20:12 -0700 (PDT) From: Michael Glembotzki To: swupdate@googlegroups.com Cc: Michael Glembotzki Subject: [swupdate] [PATCH 02/21] mongoose: Fix licenses as in c8341e29b Date: Sat, 15 Jun 2024 21:11:15 +0200 Message-ID: <20240615191941.40301-3-Michael.Glembotzki@iris-sensing.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> References: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> MIME-Version: 1.0 X-Original-Sender: m.glembo@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=fhUh8n5B; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::62d as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , Signed-off-by: Michael Glembotzki --- mongoose/mongoose.c | 2 +- mongoose/mongoose.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mongoose/mongoose.c b/mongoose/mongoose.c index 3fc0e14a..1768bf70 100644 --- a/mongoose/mongoose.c +++ b/mongoose/mongoose.c @@ -15,7 +15,7 @@ // 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 +// SPDX-License-Identifier: GPL-2.0-only #include "mongoose.h" diff --git a/mongoose/mongoose.h b/mongoose/mongoose.h index 3a439a6e..b59e2b06 100644 --- a/mongoose/mongoose.h +++ b/mongoose/mongoose.h @@ -15,7 +15,7 @@ // 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 +// SPDX-License-Identifier: GPL-2.0-only #ifndef MONGOOSE_H #define MONGOOSE_H From patchwork Sat Jun 15 19:11:16 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Glembotzki X-Patchwork-Id: 1948198 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=OETpa/W/; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=SXbZFJti; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::43f; helo=mail-wr1-x43f.google.com; envelope-from=swupdate+bncbdy5juxlviebb4osw6zqmgqe4swcxxi@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-wr1-x43f.google.com (mail-wr1-x43f.google.com [IPv6:2a00:1450:4864:20::43f]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W1mFK578kz20Pb for ; Sun, 16 Jun 2024 05:20:21 +1000 (AEST) Received: by mail-wr1-x43f.google.com with SMTP id ffacd0b85a97d-35f251f1c23sf275919f8f.3 for ; Sat, 15 Jun 2024 12:20:21 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718479219; cv=pass; d=google.com; s=arc-20160816; b=p0htXoI/nu3nggeyyS9BtjgJu1Jnxewwo2X9Oue8ASxyvDX/ChzlXIeEM+SAnxvocq 0T1xYFHHi40vX18rS6AsVb/hXThQBMgzG0oX/4gUVWGpN1K5bjJH21ha6XV1khbzvAAw wXsP+MVN9mvlAbnUt9vv6MlQII/1QQ0NTtHauBldDlxgopiGV90DF2MAkqon1w9lGCrV 2ti7fOFeNVUybNENBTpNViiGucP+UyHQkh9Vm9PlpWAnMFNH+DVgDgdbQzlNf/Nq8nKk e1t2hABr1MQy/rIgTt+4oQv7EdeQh4orX2zXKOMDYUYB3F2hZjDlB+ky7lyzs/t6Wb/Q iXFA== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:dkim-signature :dkim-signature; bh=tbepqBBjfLAnEYu7yhhcokYd3QGtFdMuTUbVM5Nu1eg=; fh=4+iP71D8wM9HbCF0qgizbpQH5Bgu56A1666mWYct1dg=; b=W6sBd80ZEVWLbJEOA4H5zJNUmhN6G17Qz2Oe5HRfIgmDScpmIdI8CUKHJ2N5Kyc9Cw pFBtlgypFqw+ikFtDHNOm9IDmvS+Xg5VUhOpyw+RSwbkc4VOx/sY743QIne9UHGfGHE7 fgDCWeC8GmAgHFAIdN2irbEaBMr4S1xqwxHe0fN/cBnkxkcEBxndd/5OEzQcG/MJv3pr U0IVdYmfGAuUqgUFIkZ0D2Eac5l8OMMU/oBHczIpcvcH6wjiA9CoWHQlYOzGf9kb92rq wgtMXNvTDGe/Weud+brxd2EkZTDI6I1jY8Pdx3BJgDYJcjD+DAN8R0AnactSYZy4kOey Gtvw==; darn=patchwork.ozlabs.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=em6Pn4lB; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::630 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1718479219; x=1719084019; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:sender:from:to:cc:subject:date:message-id :reply-to; bh=tbepqBBjfLAnEYu7yhhcokYd3QGtFdMuTUbVM5Nu1eg=; b=OETpa/W/snXDuAMbQ8e+CsvTAANpPmgTVzZK05VEdVVotYhNqWvUe7HukCfv6l+6VE MGWYklV0zoK3R0n/xfp9rnzWfNDIZBFtagPA0AEEHweo/aQP9t6LKUuDoTNl5yt/8qkF igTXKwEWiiGDamZIckG2YBLv+a2+vyIIvwp9mw+vC8abHeJ2ydtFcRiWXxX6XGwW1h+Z cTdvNMpNyXi7jnEDFclHGcyxYBtez4I0soXoH/x7ycvDjhTOKUgb29iV2K7rJ1vaeo/4 vu5PRpjKtDsjeULyAdcNhQGr9OR9QIiuu2/OlX+ZkrAt1ssYADAAl73dSUDUSw0heDH2 UBZg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718479219; x=1719084019; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=tbepqBBjfLAnEYu7yhhcokYd3QGtFdMuTUbVM5Nu1eg=; b=SXbZFJtiy3TU8C2J8swkAwa81bApc0qZg4Ytfuozht2r9g7HqnOUs2KxaI7H962E4b e53rPULeO3zcrgiDmajUTCHujw4VfygmYUrdLPObxjJYa0EhheSbLdIojThL+5XQALdG 0/fjpJ5zbnjp8IcXdGXZLO0kwuRv6DqnvFykZteOp/h+PLr08lcXPzUW2J7XOxYJnImL BnXJrRBN51/TJv3/AeB9885fNFUzEEoKZ9mb2iObaGS0nGdTINCNWWAfI79GvsSgIkg9 Fch2C7aL7fSpB7Wg7HGxzTVdVmlmt4zvs/Ilnzl2v1FSNwjWFFBN0zkS1WLMiKkH2NtK YRSA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718479219; x=1719084019; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :x-beenthere:x-gm-message-state:sender:from:to:cc:subject:date :message-id:reply-to; bh=tbepqBBjfLAnEYu7yhhcokYd3QGtFdMuTUbVM5Nu1eg=; b=wYMe83LubXKD6Vz32WOPbi363rrz625mB1eqCLv4V3bdkO1LxQ09stEZtvkvVZ555+ kp3q+1Mi1bpobZFBn/ICH7g6utQNuRDDIldqX7ijx2C/78WbcqXIWnwhCK9qbRwJ9tLI U1yMRgo1NS0Cr8tzegThGSgUZtGFIsRDbap0faP2JB2bniYAQpE23v/58bEOqT7aRHUq ti1qcoZ0cK3/mzlwObCtgqrSdVtwLV5WukEBjFiRmdrtZa1l/nkJ8s1wiGmKMfTD5Nx5 g+6g9Q5K6iFUJ5yhc4oCz+qE1IVWaoeLKFseBa7jDEZQ13edkrbre9N5YnmsTMDn88Py wriw== Sender: swupdate@googlegroups.com X-Forwarded-Encrypted: i=2; AJvYcCVItH2aBK3Ak481Dbu6NAbpYSn7zgGVfQjTfe15kWRx3X384brnpLU/baLmtypMaU+qwxrkxUcmYJhT7ZBUd/GGi5Dgkf2+TzjpIrupPw== X-Gm-Message-State: AOJu0YxdVIUGHNwNU1EJ38Vyr3zujzG02da65tZoXqbP1BlqMx287CBB B60aMfuVSUjCF5XJ22Wg+uS8dsiuPJOZrPoBi/MOb1PQCcLxo791 X-Google-Smtp-Source: AGHT+IHISpcLoEqU5eLP2rg39Kom2bSAJyccGjBdISbGrL0WxuKQ2SPI7aR49KigMhRFZWWYN3K1Qw== X-Received: by 2002:a05:600c:3ba3:b0:422:78c:82f6 with SMTP id 5b1f17b1804b1-42304859b63mr45381855e9.3.1718479217942; Sat, 15 Jun 2024 12:20:17 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a05:600c:4f83:b0:421:7e41:1867 with SMTP id 5b1f17b1804b1-422b6dc6f7als12022465e9.0.-pod-prod-08-eu; Sat, 15 Jun 2024 12:20:15 -0700 (PDT) X-Received: by 2002:a7b:c8cb:0:b0:421:7c64:6f3d with SMTP id 5b1f17b1804b1-42304828f2amr66506965e9.16.1718479215051; Sat, 15 Jun 2024 12:20:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1718479215; cv=none; d=google.com; s=arc-20160816; b=m53Lc0U6qdQmJaBkPdXHqa8mgeLrD45qDXNMHTQ3fm8iA09W1Khmz3CWqYYWhWX+aR c27pYmN0wtEpByU5POIoLYD7mmKc/YNR+jcD+NX+LqIUtqDYayaSYzyg8AEL5u4vYOYr SIRNHsXyQOBxpf6eG53OzzMMWbAwm2/xkfw3RkMv1VvbR+/ycWHaoRvErweE+nDo6mFT a8BeG06g1XKTZMMtNV1Ewz9bojrv+kWq8f6Xhhm1ma8+F5vbMQKiIY9Lc2BLJYiQHJvx fjH3xwWRpX25kPWdUY4m3iUVQWFLRPxBKLgDCH9CzNYw4S63IPYLGsZK5bDTMFoAeGF6 uNvA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=sJ6UmDPhjUyBL5PpGALKMi6wsPtB4jLbjruHPVc1T5w=; fh=zydHuzCQWrku2OPQyZfraJZFcOpEXLQ/YBcu3QNiBd0=; b=Q7qnt05FmgF4vtmuMfJ+BNyOvYAf0dVXEDFtMzpVx/ciJto3gfDMt//smI2n+G29uD UkwT+NyJFgmttd0SSdpeSaLYs3YyAkA7Wtx6u70SxfsjFbAEWQ9ihqF0/BG148S1SwY7 3XqNYw8Oq/ygux6+SRlNAcFR+eouP1wpkBj7oHt9dY8EmJbyjkrB8WXgPJQDNsoS0hEz p8hONzrb8auRKpkAx2bEFxYKq+UO/Cu44xsMQqSvT0Luqt2Ryu/1rGS2Gx0I+Oqxr5YN Xob6bD0nTXtj+3BtmS0OcYzNeQDfVCoEMVV3jRVmHOlipSLnF7fVUIZxB8qSGalmgEd8 u9IA==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=em6Pn4lB; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::630 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-ej1-x630.google.com (mail-ej1-x630.google.com. [2a00:1450:4864:20::630]) by gmr-mx.google.com with ESMTPS id 5b1f17b1804b1-42284b090dfsi6260155e9.0.2024.06.15.12.20.15 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 15 Jun 2024 12:20:15 -0700 (PDT) Received-SPF: pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::630 as permitted sender) client-ip=2a00:1450:4864:20::630; Received: by mail-ej1-x630.google.com with SMTP id a640c23a62f3a-a6f04afcce1so410970266b.2 for ; Sat, 15 Jun 2024 12:20:15 -0700 (PDT) X-Received: by 2002:a17:906:d1cf:b0:a6f:4ba4:c389 with SMTP id a640c23a62f3a-a6f60d13b0fmr442526866b.16.1718479214226; Sat, 15 Jun 2024 12:20:14 -0700 (PDT) Received: from PC-2635.irisgmbh.local ([2a02:8108:96c0:76fc::80bb]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a6f56db61e0sm327283766b.49.2024.06.15.12.20.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 12:20:13 -0700 (PDT) From: Michael Glembotzki To: swupdate@googlegroups.com Cc: Michael Glembotzki Subject: [swupdate] [PATCH 03/21] mongoose: Backport: bring mg_strdup() back from master Date: Sat, 15 Jun 2024 21:11:16 +0200 Message-ID: <20240615191941.40301-4-Michael.Glembotzki@iris-sensing.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> References: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> MIME-Version: 1.0 X-Original-Sender: m.glembo@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=em6Pn4lB; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::630 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , mg_strdup was deprecated in 7.14, but was brought back in ab75bfa6. mongoose rev-id: ab75bfa6e70a6985becf1eed912f93ba668be363 Signed-off-by: Michael Glembotzki --- mongoose/mongoose.c | 20 ++++++++++++++++---- mongoose/mongoose.h | 5 +++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/mongoose/mongoose.c b/mongoose/mongoose.c index 1768bf70..44066893 100644 --- a/mongoose/mongoose.c +++ b/mongoose/mongoose.c @@ -6633,8 +6633,7 @@ void mg_rpc_add(struct mg_rpc **head, struct mg_str method, void (*fn)(struct mg_rpc_req *), void *fn_data) { struct mg_rpc *rpc = (struct mg_rpc *) calloc(1, sizeof(*rpc)); if (rpc != NULL) { - rpc->method.buf = mg_mprintf("%.*s", method.len, method.buf); - rpc->method.len = method.len; + rpc->method = mg_strdup(method); rpc->fn = fn; rpc->fn_data = fn_data; rpc->next = *head, *head = rpc; @@ -8048,6 +8047,20 @@ int mg_casecmp(const char *s1, const char *s2) { return diff; } +struct mg_str mg_strdup(const struct mg_str s) { + struct mg_str r = {NULL, 0}; + if (s.len > 0 && s.buf != NULL) { + char *sc = (char *) calloc(1, s.len + 1); + if (sc != NULL) { + memcpy(sc, s.buf, s.len); + sc[s.len] = '\0'; + r.buf = sc; + r.len = s.len; + } + } + return r; +} + int mg_strcmp(const struct mg_str str1, const struct mg_str str2) { size_t i = 0; while (i < str1.len && i < str2.len) { @@ -10605,8 +10618,7 @@ static int mg_parse_pem(const struct mg_str pem, const struct mg_str label, const char *c; struct mg_str caps[5]; if (!mg_match(pem, mg_str("#-----BEGIN #-----#-----END #-----#"), caps)) { - der->buf = mg_mprintf("%.*s", pem.len, pem.buf); - der->len = pem.len; + *der = mg_strdup(pem); return 0; } if (mg_strcmp(caps[1], label) != 0 || mg_strcmp(caps[3], label) != 0) { diff --git a/mongoose/mongoose.h b/mongoose/mongoose.h index b59e2b06..6b71240f 100644 --- a/mongoose/mongoose.h +++ b/mongoose/mongoose.h @@ -186,7 +186,7 @@ extern "C" { #define calloc(a, b) mg_calloc(a, b) #define free(a) vPortFree(a) #define malloc(a) pvPortMalloc(a) -#define strdup(s) mg_mprintf("%s", s) +#define strdup(s) ((char *) mg_strdup(mg_str(s)).buf) // Re-route calloc/free to the FreeRTOS's functions, don't use stdlib static inline void *mg_calloc(size_t cnt, size_t size) { @@ -288,7 +288,7 @@ extern uint32_t rt_time_get(void); #include "cmsis_os2.h" // keep this include #endif -#define strdup(s) mg_mprintf("%s", s) +#define strdup(s) ((char *) mg_strdup(mg_str(s)).buf) #if defined(__ARMCC_VERSION) #define mode_t size_t @@ -861,6 +861,7 @@ struct mg_str mg_str_n(const char *s, size_t n); int mg_casecmp(const char *s1, const char *s2); int mg_strcmp(const struct mg_str str1, const struct mg_str str2); int mg_strcasecmp(const struct mg_str str1, const struct mg_str str2); +struct mg_str mg_strdup(const struct mg_str s); bool mg_match(struct mg_str str, struct mg_str pattern, struct mg_str *caps); bool mg_span(struct mg_str s, struct mg_str *a, struct mg_str *b, char delim); From patchwork Sat Jun 15 19:11:17 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Glembotzki X-Patchwork-Id: 1948202 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=vIPc/V6D; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=DW/2pwIa; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::23f; helo=mail-lj1-x23f.google.com; envelope-from=swupdate+bncbdy5juxlviebb4wsw6zqmgqev4b24sa@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-lj1-x23f.google.com (mail-lj1-x23f.google.com [IPv6:2a00:1450:4864:20::23f]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W1mFS6s5Nz23tx for ; Sun, 16 Jun 2024 05:20:28 +1000 (AEST) Received: by mail-lj1-x23f.google.com with SMTP id 38308e7fff4ca-2eaeaefbcc6sf4873121fa.3 for ; Sat, 15 Jun 2024 12:20:28 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718479221; cv=pass; d=google.com; s=arc-20160816; b=gB45xfvhhqiWwIm0q/iZ4okE1h+d2ldiRsRjxKbEMYebxzEHsyfc6EIFAXNiFzJYfG NNsGGQ0W8Gn08hcAWZcHhvxl8g+NI6Jx3WsTS0GI7RRWCT3Zv2VITDPCOIYF9hpa1CmI eTAEIxpCND9l7PyhE9bLYz3YbRFpekVTsgdlrspcTgp8r6GjzM1MOUYxjKLuc66y+ox8 ECBz7P5nRvvhK4MGUg7K0ab6/b2Cc/o41tmU9ZJzNNiFhO4XGEwEFsJ99jg7LoB/pdR2 WcV0q9rVGuZl4YJHbmvn4eGhRRC0bw1N7FR6sE0C/mQi9fJ82fFSZq17rFTEUnSbUO9V l0uw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:dkim-signature :dkim-signature; bh=V1zBHmcuKQZFvVxJA3r0suarM4eHzZFcWCyzgj6Yd/o=; fh=c+wSWaQlAF99X3k4eEmcgQG2uws13OTj/Kae2VINN/4=; b=DjYq2kdrEsecTGkJdSp+/WJkD723SXMi61TU4ZQXEAttqzS+sov8JDW05kxJf8d9Dr xzOmrvrwL0tGnqTvf9BVTPg8G/606MeArX7t5E1eMU1ZUx+GbIwP5p5w1Ea30tcFzbgQ nSH7TF5O14hJZR0IsvbQ6aJBC6ZzxffW72PTGIPoLxnWwj7hDh7rIpPDAqxsDizBkWsu xuzpAf5WVpwnFRpe/zCam2256fJodSW/uZrz3N4S8+MTGo5UOh5S9R8MCmyA7YZHt33p tBAynxHgiHo8ZOoaOyv4QzZOZncp9Z2AQBxi7WMS6cya+JWIfSxeyT7Sv/9tRlW5ZTEM l9RA==; darn=patchwork.ozlabs.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=ciXBHPCi; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::62e as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1718479221; x=1719084021; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:sender:from:to:cc:subject:date:message-id :reply-to; bh=V1zBHmcuKQZFvVxJA3r0suarM4eHzZFcWCyzgj6Yd/o=; b=vIPc/V6DTEigc4TZUt2/8C9e1soMNWMKHNO3dGJYBtdaOF+7vvRc6lRGAhxGY0N9S4 HJEWOTQzdprXa02UHm8gSDDCeVVoPKiQhReLWuNrQYI7i1emQV/9h/yq4dpDygapylO9 TNiN8vCUDJbNNoY8X1zUE8jMXEOJ9MCrzmyFFM/cyh5iLRcVJmOKI7Rz7WQe6GvVF/wk MvJpxKCwppllB0wpLUBGN0LJrV/ygThN09t4h0u/23A+TYmrLfphbPztNzyCLTXCi5PK CKRn0qlBMAayLlVxTpmFTCepLd5dMj4GfHUeh2FOrsKCl5+RT4p/Ujg7LlM3Zc7KYzLj h8yA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718479221; x=1719084021; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=V1zBHmcuKQZFvVxJA3r0suarM4eHzZFcWCyzgj6Yd/o=; b=DW/2pwIaCPFevUzSyRt2swl7qGsxgP/52BsPOjqiO5a4fz8e1c8GFTWc59QMlbEkaR w69bo4J1H3DBtfM4bxN74N3EvIPYo6QvNrGpl2C4q6tbXgwGQO+smCnzs5iROAPXCcZx w1oz5EkFywGderBdSwFvCE5RbiMKMZqIcTO0kEo4MqfPcavKmqsBe61S81qHQxYr0yyE W7gtz4JySRK9GLbc30Lw7FfU+GQG5m/rDnc9BfwF/5jaU94WhX6/rUb5VjVfpfqJ6K3P YGW8Y9sCYCCSSlNzOL7wuWhC5Q9GSiEuJvSceTZ+/YuQ572tk0SYeJ5GYTJFjkNd488a 6qKA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718479221; x=1719084021; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :x-beenthere:x-gm-message-state:sender:from:to:cc:subject:date :message-id:reply-to; bh=V1zBHmcuKQZFvVxJA3r0suarM4eHzZFcWCyzgj6Yd/o=; b=b2Q5OVLlVvRlhb94gJEa4A9gyxQ+dWhLic4etlWRtGcylo6v72J5fyCXAGwgp32KaT 9YezGLfpBP2eU+4loCrG/Rms/xm1UWgS/MfliW3s0MGw5ZLN9w3HUBaUKfBRUVlHH5eC FGqcw5FdO/5o5AY6GwAlLF/dw4MpJOQraEYyBaq27IxZGSIJVpu/RlPX9/g9HE9ux2On yRmFwf+Ko3/eQB3Ziz1dH2Bn6wF43Xlr8o74q8O698IRp9laJXw8MAH+XP/bUXcrnHs0 KSchWnV9y/GXaLqPvfBEKHPnX+yeVYrV1qsYRdFe7Nd1p2vG8s/QSI32UVxk2Vsyy1sB ljlQ== Sender: swupdate@googlegroups.com X-Forwarded-Encrypted: i=2; AJvYcCV02BpK+NmpucQCfLwrEenkklnqt1Zjd//R7TwUiDybYfhCcx4fVjYDhpKYdqfr9PuxGgiyJ2f8avxoeN0WDjRQ04KxmNsMEgpcsbbo8Q== X-Gm-Message-State: AOJu0YzCqrd4cRikglJvPo+yplQwdCO+2aHjzZ+K5Y4lTyjgxUnFFOTB WfLMD8TMHShLZDvWddKkVIqA0bREho0eLoHkZP1vYOc+NNYgDTQu X-Google-Smtp-Source: AGHT+IGr+lpriAosnOP7/iHcEjl5nuMwP7lpfmfZqYJUzNoDwRrWmrgnOHahhQXZq64YgZvmFrEUTA== X-Received: by 2002:a05:651c:2108:b0:2eb:da20:7b3f with SMTP id 38308e7fff4ca-2ec0e463c43mr41358711fa.1.1718479219491; Sat, 15 Jun 2024 12:20:19 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a2e:97cb:0:b0:2ec:2bb:f35c with SMTP id 38308e7fff4ca-2ec02bbf3d5ls12880311fa.1.-pod-prod-03-eu; Sat, 15 Jun 2024 12:20:16 -0700 (PDT) X-Received: by 2002:ac2:46ed:0:b0:52c:83c2:9670 with SMTP id 2adb3069b0e04-52ca6e9dcb7mr3579687e87.69.1718479216278; Sat, 15 Jun 2024 12:20:16 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1718479216; cv=none; d=google.com; s=arc-20160816; b=Uik2Cy+9sUvM7SyKqpvpvxFOu7AT5pM+0abOgKzL8KaO6lvRy8JZuNRcTwtp32US1A 9KQHSKVAi8CcQR6zTIlDvCBr6yrES4KeFRn83hGFW/F8wLynsJCM2X73AR6aBNUWl4ba PfoeRwgLXNZOaT+aVUBj7gOkxRxZOlgtOPZrjS6HX2fCNyCeO0uF9AQXiz3112TqbkHq 7114BWAUVBDOuRtGSApCH3ZBaUsyY7aetGyVbzTzgMMz3YkE2APkLYbUib6KBrrC4yJO xBr8WcqfomGDrluEd08fSwL7X8outUUBMRrlezIi3DQx0ahsxoh2MzN6i8wUoP3Trcqe 5kYA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=QdSlvGQz1vUR/9sqdYIVj0bXGa6kF7pkJEQTQFw2NIQ=; fh=zydHuzCQWrku2OPQyZfraJZFcOpEXLQ/YBcu3QNiBd0=; b=DFvzpzqiU49Ci7cZ8jG2VPOUfr9UKQs8aYOsGEgUKllEj3EtteV/t6Qkge1KYhgmxg 7TVexcShgg4f4sAmhnAkIJ8/C17MGdfmwXMQVxOVyhHnBwpg5TDnLfNSbSiwrn4TOaq3 lLdMBC/wIGd9SKZNRaGsNoA0jN2VdSVdPfPLu4Bpl1a1lfbVGZoU+kvY1gLZP5+H6iif UrOZJ87s9fO6WdUR5N9GOIgkqxqfH5eouXaCxwVBDRDwNlWihdsj4oDUVLrYajbEkNQe 9dmJDW7Rsdc1Lr8vDU/UWQ4k/6UzFn4lZXAbUPQA/N5pgBRsL7miLC/Eai0jnYee05hz iCAg==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=ciXBHPCi; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::62e as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-ej1-x62e.google.com (mail-ej1-x62e.google.com. [2a00:1450:4864:20::62e]) by gmr-mx.google.com with ESMTPS id 5b1f17b1804b1-422855708b8si572635e9.1.2024.06.15.12.20.16 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 15 Jun 2024 12:20:16 -0700 (PDT) Received-SPF: pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::62e as permitted sender) client-ip=2a00:1450:4864:20::62e; Received: by mail-ej1-x62e.google.com with SMTP id a640c23a62f3a-a6f13dddf7eso403887166b.0 for ; Sat, 15 Jun 2024 12:20:16 -0700 (PDT) X-Received: by 2002:a17:907:c819:b0:a6f:65e5:c98 with SMTP id a640c23a62f3a-a6f65e50e76mr431836966b.1.1718479215495; Sat, 15 Jun 2024 12:20:15 -0700 (PDT) Received: from PC-2635.irisgmbh.local ([2a02:8108:96c0:76fc::80bb]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a6f56db61e0sm327283766b.49.2024.06.15.12.20.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 12:20:14 -0700 (PDT) From: Michael Glembotzki To: swupdate@googlegroups.com Cc: Michael Glembotzki Subject: [swupdate] [PATCH 04/21] mongoose: Forward port deprecated mg_strstr() Date: Sat, 15 Jun 2024 21:11:17 +0200 Message-ID: <20240615191941.40301-5-Michael.Glembotzki@iris-sensing.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> References: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> MIME-Version: 1.0 X-Original-Sender: m.glembo@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=ciXBHPCi; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::62e as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , mongoose rev-id: b46bee0540c83c780ae9622ef18b9cc8a7b3ebab Signed-off-by: Michael Glembotzki --- mongoose/mongoose_multipart.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/mongoose/mongoose_multipart.c b/mongoose/mongoose_multipart.c index fccc5a62..5e57d326 100644 --- a/mongoose/mongoose_multipart.c +++ b/mongoose/mongoose_multipart.c @@ -48,6 +48,19 @@ static void mg_http_free_proto_data_mp_stream( memset(mp, 0, sizeof(*mp)); } +static const char *mg_strstr(const struct mg_str haystack, + const struct mg_str needle) { + size_t i; + if (needle.len > haystack.len) return NULL; + if (needle.len == 0) return haystack.buf; + for (i = 0; i <= haystack.len - needle.len; i++) { + if (memcmp(haystack.buf + i, needle.buf, needle.len) == 0) { + return haystack.buf + i; + } + } + return NULL; +} + static void mg_http_multipart_begin(struct mg_connection *c, struct mg_http_message *hm) { struct mg_http_multipart_stream *mp_stream; From patchwork Sat Jun 15 19:11:18 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Glembotzki X-Patchwork-Id: 1948200 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=QgntzbUS; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=U5RsEPkU; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::33d; helo=mail-wm1-x33d.google.com; envelope-from=swupdate+bncbdy5juxlviebb46sw6zqmgqeiwlq3ay@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-wm1-x33d.google.com (mail-wm1-x33d.google.com [IPv6:2a00:1450:4864:20::33d]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W1mFS5dGtz20ZB for ; Sun, 16 Jun 2024 05:20:28 +1000 (AEST) Received: by mail-wm1-x33d.google.com with SMTP id 5b1f17b1804b1-421739476b3sf28139655e9.2 for ; Sat, 15 Jun 2024 12:20:28 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718479222; cv=pass; d=google.com; s=arc-20160816; b=gzEaLyOP+zqnPBRefLtMfkRMFpiEfBhqSFKFnlNR2p9IAur2xENnTNu4ziUy40KcqT nXlVjrDprfH0P0jYtKIeCPaWexxJ7NrUIGRZ/tK0cOCwWuP6/BKka5bQD8gskPu3IcRp 2H7/GKXBaCu7lKhKX4fiPN+xQ+c9qJzmFgDYZupKAZB28HCrha3INe/LFK14uLd1zDlS g+VHIeMioN4xFdaTfxdmLxOOVQ8ebgy81VFfcuLatHLKf//tOuA8FPM2JOIZBA5p3uNi TfID6G9UbX2xEkgcLb3o0qMexL/QXplKOej1AT/kyhcISJtuu2LcgfzS1VBFaxs4pII+ kiAg== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:dkim-signature :dkim-signature; bh=MErXvDEJzmNprYCnFW9eHtZK7l0nRteXVFp54GDYN70=; fh=S4YHzENMXufjjwR1fCiNMqRQOIw4+Eb7TJYtfdT6ZOQ=; b=CCIl3pQXwbHEciItTEipjGzM+rzt9Gf6QgBk/QEhkJ5asWqZQn8Tro93kHPp2IQX73 gBHQDhMplET92oCGaEDeoxi/F7sLwy6rMC0+tevKovVeYb7zhpK+xmGh/wtLohHXqqFd kyflijelZAwER6qqrBp583PbjBB5TmtiR/trvSCL7ecu84+DDLmmh+buNWtN15D1pfG3 igFvgJqduJ1XqwmJGWf8snL0fbJHSlAVNK/NuZdvgPOdCXBWMkD5xEhxJIh88pCQteZi UWPUVBJ2EaYD0/Nv3UbjYwx9nWB4VXeOEz7v7Gv32ffOkzokMKA82WpdE6NTo2UcyUtL aH0g==; darn=patchwork.ozlabs.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b="Wd4/0as8"; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::233 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1718479222; x=1719084022; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:sender:from:to:cc:subject:date:message-id :reply-to; bh=MErXvDEJzmNprYCnFW9eHtZK7l0nRteXVFp54GDYN70=; b=QgntzbUSrG0nqOPpKi+4+K0oPLXm9ohzllb3mPn7fhl+VFKMscXZ6ghz5CxVS60X7Z dwXeKJzWoXWPdL8eEsY4ALCoEq2Xp0yJRp5klHsEDYs03YkclqnGMmXCjgxNGHOpjchb ymGV3inyJ4w/VxDeIIlPqoZGFphNJg8drjzVLcaH5Xb63aEBBH+nI9V/22PRjqvKtjew ijYFVHNWvfx1I+i1XbyvRcXby6LcVn8AD6DXQp4Zx0/oybxuWQt3/0CDWJaARcYElZNh Ze9g4iWPByAo7zT6GCBFEB1Cyi0k45NmhihyoJDXLH7EioEqIuCQ2izYBM0CaMPO/pEp y65A== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718479222; x=1719084022; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=MErXvDEJzmNprYCnFW9eHtZK7l0nRteXVFp54GDYN70=; b=U5RsEPkU8mr8Sbnwt5hjUmKEkc851Iv5bYgqsZzgOHrOJB7/VPqnGUsRST4NPxanza rHGVd3XJ2dvZV19rwHa6sWi8EqKZOJAZEo8fq9RsI3ssmTQFo9gZ+uzswdJoKq7jZASP fAXnZ+NXiXJbLxe5aSTEFbKaaLVj3O/6ZUJBJtxmA4gZ4DE+5f1ijORDHreH7jxv/pRu BPaMNdsq3NdORDM8gR+wMbXyMp45zRySrSMod5zXIXIUgfqHOW3GisGT2VAHNQua+2nh DS2C3UlF0jutZlPe/1kRJc/yUDVTDh5UCSfpiVWEJ6XNR37VvaomZNz9DzAR+SMgx9un AFow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718479222; x=1719084022; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :x-beenthere:x-gm-message-state:sender:from:to:cc:subject:date :message-id:reply-to; bh=MErXvDEJzmNprYCnFW9eHtZK7l0nRteXVFp54GDYN70=; b=f6pV5DRWF0bxDsnEYG4YQ7oIeY7TGH2FXYM755bud+fEmlurJGnoOl5lxWT/Hh1KzK iY77gdelPlkbj2g+ylQpEmXJsf6ntYhcS8dsja0hphU8hQ/b33jf6IiDw8Y0XwYIGlJ+ F8vp6/Wfuq8xipHZUp4NL6ryvqN8TA4JjFiesBMmaQH4uO4z0lCS3RKsDx/6e4Ciaxw8 YUshaQdjZ2HesTBurWd2Cmx9eGdqANHFPU+WNYut2GIF88bKQ6z8SAkkRkFtUuAIWbUT 82n+EJU17bE6DFEMTquMJJ1EwTD1vqt2ZUQCUvUVn0Vedx8CMGIa9lQDHsI/YA/7f6s/ Fizw== Sender: swupdate@googlegroups.com X-Forwarded-Encrypted: i=2; AJvYcCWJQ6Lr+RA8n+8ygxKmBV9fkNzZI/+dkYY3+1ROQqBN5V8egs1pN8AjLPW8cPyQbAvSgXfkDIO+dOe9UnihQqr0wTJfgsvN3PvMMvlb9g== X-Gm-Message-State: AOJu0YxkmU8/xdSbwrF/EDEYGhON2Dl0/WVs4/LrUE6ckDPtgZVEweP1 n59Pm0dmp8OCGZ4VgyAomRZrk6jTbbBbj6ZLhBaJSyEHzML6HPpP X-Google-Smtp-Source: AGHT+IEwmBBdfIEMxmzCv6qJQesQ+UFpHzsW3US2wXWfyq6ndGmCCwSgUq2aKWbSqgqOwU5gHlQwcw== X-Received: by 2002:a05:600c:4509:b0:421:f04d:ebcc with SMTP id 5b1f17b1804b1-42304826620mr51756615e9.24.1718479220757; Sat, 15 Jun 2024 12:20:20 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a1c:4b12:0:b0:422:cb6c:76e0 with SMTP id 5b1f17b1804b1-422cb6c799dls15262995e9.2.-pod-prod-05-eu; Sat, 15 Jun 2024 12:20:18 -0700 (PDT) X-Received: by 2002:adf:e2d1:0:b0:360:7c17:5936 with SMTP id ffacd0b85a97d-3607c175a00mr4279187f8f.58.1718479218032; Sat, 15 Jun 2024 12:20:18 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1718479218; cv=none; d=google.com; s=arc-20160816; b=NrCwHz/mfr1aYLapytMXYJY9pAFP5t4tehqXHE6EvarfiNX7RGPYI5oheebTFopGCk jsxlR4j7bIc3F48C55SkGDC+6/szOqm3hROqNPVBX3dDrTYfTwe+fUBaMDuRMlsqV41H gJpjoDaPgT6QUALD8YK6RuTFyONH7XKlewu2w4OyFPRQHtP2TK3X18bbaZs+oh6zkd2u 2JkZB/Qul3pGlkaiB/fYv2eKmM4HW4i/Y/fxizo3YWTXSEyo1jlMIlJ1XtThvRHQ3pKM GiT8WTTQOo0VJav4UMaQJ5NmwPNPc4JXTEW9nGIGu/VmWSWQ1actZFOIgy90JHLm4PmN M5/A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=NfyJhg8lq4sXonCV32RiyirEvsl0Wcw0IAFumk7cFtw=; fh=zydHuzCQWrku2OPQyZfraJZFcOpEXLQ/YBcu3QNiBd0=; b=qcZfRcgC385H6vs3YpErWfpjlcaQlEGbBHku0AyznxsRfu257R3CrQd35HwNUkK9Sy yD0iZboxpaiDd2/uCi/erDEHMF5vU/QTX1MmBAWHApguRNIVrtk4QHU79OTSWD9FEd+X /qfpb+Y9arJNPqS4V8qF6LVhjhUzydE8wjqdJ8tR87TdbHdXexL1tYra3i0uB2g2Br4v k24H9JHNzMQ3yiZOYBzOb2Gc4pYxtjPQ1EnbProVAZmehLBo9kdXM0oFPpHBfjw0/gdM UMwAwB03w/PGW5B5/KFobYCow/fBqE4iwdpbXSZNzEjST44C2MvsJoN9fPJuljmFBszo I6Yw==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b="Wd4/0as8"; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::233 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-lj1-x233.google.com (mail-lj1-x233.google.com. [2a00:1450:4864:20::233]) by gmr-mx.google.com with ESMTPS id ffacd0b85a97d-360867eb198si62018f8f.8.2024.06.15.12.20.18 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 15 Jun 2024 12:20:18 -0700 (PDT) Received-SPF: pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::233 as permitted sender) client-ip=2a00:1450:4864:20::233; Received: by mail-lj1-x233.google.com with SMTP id 38308e7fff4ca-2ec17eb4493so22341181fa.2 for ; Sat, 15 Jun 2024 12:20:17 -0700 (PDT) X-Received: by 2002:ac2:4989:0:b0:52b:c2b9:d988 with SMTP id 2adb3069b0e04-52ca6e6e859mr4344008e87.40.1718479216676; Sat, 15 Jun 2024 12:20:16 -0700 (PDT) Received: from PC-2635.irisgmbh.local ([2a02:8108:96c0:76fc::80bb]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a6f56db61e0sm327283766b.49.2024.06.15.12.20.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 12:20:15 -0700 (PDT) From: Michael Glembotzki To: swupdate@googlegroups.com Cc: Michael Glembotzki Subject: [swupdate] [PATCH 05/21] mongoose: Remove deprecated events MG_EV_HTTP_MULTIPART_REQUEST Date: Sat, 15 Jun 2024 21:11:18 +0200 Message-ID: <20240615191941.40301-6-Michael.Glembotzki@iris-sensing.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> References: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> MIME-Version: 1.0 X-Original-Sender: m.glembo@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b="Wd4/0as8"; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::233 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , Events MG_EV_HTTP_MULTIPART_REQUEST and MG_EV_HTTP_MULTIPART_REQUEST_END have been removed in 7.0. The mg_call()'s have no effect. Signed-off-by: Michael Glembotzki --- mongoose/mongoose_multipart.c | 4 ---- mongoose/mongoose_multipart.h | 6 ++---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/mongoose/mongoose_multipart.c b/mongoose/mongoose_multipart.c index 5e57d326..fb62c1e4 100644 --- a/mongoose/mongoose_multipart.c +++ b/mongoose/mongoose_multipart.c @@ -112,9 +112,6 @@ static void mg_http_multipart_begin(struct mg_connection *c, mp_stream->part.name.len = mp_stream->part.filename.len = 0; mp_stream->len = hm->body.len; c->pfn_data = mp_stream; - - mg_call(c, MG_EV_HTTP_MULTIPART_REQUEST, hm); - mg_iobuf_del(io, 0, hm->head.len + 2); } } @@ -149,7 +146,6 @@ static void mg_http_multipart_finalize(struct mg_connection *c) { mp_stream->part.filename.ptr = NULL; free((void *) mp_stream->part.name.ptr); mp_stream->part.name.ptr = NULL; - mg_http_multipart_call_handler(c, MG_EV_HTTP_MULTIPART_REQUEST_END, NULL, 0); mg_http_free_proto_data_mp_stream(mp_stream); mp_stream->state = MPS_FINISHED; free(mp_stream); diff --git a/mongoose/mongoose_multipart.h b/mongoose/mongoose_multipart.h index 552ede2d..1d2b7dcf 100644 --- a/mongoose/mongoose_multipart.h +++ b/mongoose/mongoose_multipart.h @@ -22,11 +22,9 @@ #include "mongoose.h" enum { - MG_EV_HTTP_MULTIPART_REQUEST=MG_EV_USER + 1, // struct mg_http_message * - MG_EV_HTTP_PART_BEGIN, // struct mg_http_multipart_part * + MG_EV_HTTP_PART_BEGIN=MG_EV_USER + 1, // struct mg_http_multipart_part * MG_EV_HTTP_PART_DATA, // struct mg_http_multipart_part * - MG_EV_HTTP_PART_END, // struct mg_http_multipart_part * - MG_EV_HTTP_MULTIPART_REQUEST_END // struct mg_http_multipart_part * + MG_EV_HTTP_PART_END // struct mg_http_multipart_part * }; /* HTTP multipart part */ From patchwork Sat Jun 15 19:11:19 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Glembotzki X-Patchwork-Id: 1948204 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=YRkZ1HxX; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=Z13nh2Fy; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::337; helo=mail-wm1-x337.google.com; envelope-from=swupdate+bncbdy5juxlviebb5osw6zqmgqegghrmeq@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-wm1-x337.google.com (mail-wm1-x337.google.com [IPv6:2a00:1450:4864:20::337]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W1mFS67C7z20fS for ; Sun, 16 Jun 2024 05:20:28 +1000 (AEST) Received: by mail-wm1-x337.google.com with SMTP id 5b1f17b1804b1-421f3b7b27esf28219775e9.1 for ; Sat, 15 Jun 2024 12:20:28 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718479222; cv=pass; d=google.com; s=arc-20160816; b=uSechhfeMYpkGGGkx9jw0CG0XtQ0kOarAsc2JcboZpbATNAOvNMACqPzfqKT8RiBpQ V8VT/62JVSH8GdgmJjb9ptmwkNqPwuAq+5cl4kZNvGuDVRjSlqJm4nn78vFlKXREkRMv NjVB+5sPpdt9HaR5OR93jAJ5nL2EyHmtzqCtGP3vJ5Ncqmqo9jxajXlp0ZUXPpLbJJBW mUy/KZf1xv7XRa463ArVQaRdRELHDfRBZHC8Z2MDuqp7eHlR+E9oMEEjVS9HFDEdf44G WYCEdpf6I+wsWRWNONPNS541Qi0pIHQKnZYIEwA+FMcI8/B7/7s18xlm7Vh+pIOBfw+Z 1XsA== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:dkim-signature :dkim-signature; bh=KYeXW377gBe9+2cO4oghdHMMMAVt7c6MqaZiyFhEg6U=; fh=VBHPtygCbH5lEGlycD0leIno2hZaCgtoO8Nqrhjx7/U=; b=jFg5xs2gAtgdZBWMhkx8sZgWYAXa+sltVCyJae5BZBIbKxs6twemOBaQI+7k9XqFTS WbSIXzF9bbeXt0RVVl0Jzo/SDsiuFxXMJn1KLhK6b/krT9IsjZhH2SRFVB42zosBKvou E+UBRD3TkEOoNv9nwy5ifHipcDSm8qk8Lo3JcS4JYYn0MfJHKWfqEn7ApT37mMejYH46 KOxMUEK3qFB5As6txq6hRT3snSrhSChVxDHZVlEv/bcDdrpRkxj6uHbYSAlIfL0fvFv9 e4inPmKCRfUApBtkkpNjq+x4//9mGnqnn/LHAspfd6RBiEiQnXN9ys5KG4EKBYinMv0K NN5g==; darn=patchwork.ozlabs.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=LI7UcPb5; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::22f as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1718479222; x=1719084022; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:sender:from:to:cc:subject:date:message-id :reply-to; bh=KYeXW377gBe9+2cO4oghdHMMMAVt7c6MqaZiyFhEg6U=; b=YRkZ1HxXSIrI2J6eJAfyvoGMGb78afUAe1dHpJrWy+RBs/Eqc47tyEe2gvjTd6azyx J0bDgw5x6PZPE2r3fCBvK8hiSXZ6wM5Uu1yLELwbFhFFWYj6ndINOa9XmUSeNSWOJx0A A8ouGY00iQX8OYd1poO7/HGg76FN1WKFGmvf4NdGPkcZZ6c6nhe9QIG+8+Sj5Fdg49r/ 0V7GjuuEywVPxpqzktEexI9i6rydGBkrM7ypbSjorIQa4+gmqbWwaQl7R3SoajfgMP43 s9Z7Al2T0psjzbB3fnE6FmgctvT9xDsTjEtWOLeBVgxn479rT3dCaRUUp1eX3m2NBGlp exFQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718479222; x=1719084022; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=KYeXW377gBe9+2cO4oghdHMMMAVt7c6MqaZiyFhEg6U=; b=Z13nh2FyyJvObH4uSx46LCMypHBLk13Lmizhy7HuIm36mZEnl/FfAHyPUHirQpemia CjoV2Feo2Mne8H8fmiMH+rTnjLzdm6uYY/DrIEzMLMQ8ey3modPuh44ANRvL8iDANz0t AAtPfsW/KbiqZx0CVbh0Fm4VMzo5Svc5s8y0SmTO49XBUU4KD3Gq7hmL8SS/xWRPldNH mdjOyLKulUkLEngxSBjQtzGok+27dKZ4t64JmtPGCuqzSZ7O3oIm2YS8r8DvSVJ6zMmY 9XnPb7iS+Nix+jl4ALV/1Jp+QDMDbYVLBaRbROfIw7TQyU2ErymPd8xIWcpy2gRVYdfG 0GOQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718479222; x=1719084022; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :x-beenthere:x-gm-message-state:sender:from:to:cc:subject:date :message-id:reply-to; bh=KYeXW377gBe9+2cO4oghdHMMMAVt7c6MqaZiyFhEg6U=; b=PQcNxO878rZ/4mn/U55kjWL68tkDG0+pRHcXe3puq//cgbiZSwcZ0GhI3xeKcNGCX0 TEJnhUdMbpY7ddc8pw4K1Uhu3X5cZFkief3+4/A/7hf+9kAmJSb4Ryn3MJWO+fnwJBxD 1HITeeQlJ9SpXslKAclk+uiJt7lIdGZCwPeUjFtCOmp0J5l+c8i2Lxiyc1mc3J+6SgcE ro32rqaWjFRgO+159d1yXixgS6jV7FteERo2Y2E1ZaPYWI54Oweba1EdVDElErOiOVY2 kolWVcWjNNJVS3rhjk6NK1qNXvGoOAqxfCh5S5EoCu9K1lRgyghaerpOkRTnT6B/dVYc fqBQ== Sender: swupdate@googlegroups.com X-Forwarded-Encrypted: i=2; AJvYcCWCas7dIOm521719QOEwOnSktdGPP+o0mMW71LZ/j0LZ9ghyr60gvjnUSdph2AGUYHx/yHFDCm888tmTG1lVIxQlCegJO8D/b/DEycF+A== X-Gm-Message-State: AOJu0Yyx9msRazbHxZH3Cl4ztNkymTDroxeUIP+UBXhIjdl4N97sT9cb qtr1pDovK93FNOaj2UYnAMV8AtUR0euaAZHF+bqVW11yEnuMbFD+ X-Google-Smtp-Source: AGHT+IG3ONZdNPTPtgNys2trKBNHLj86R2GKSCiWUTtO03WrdbiJ/XUPWFiYHC3aiDr6MtP6LGxBww== X-Received: by 2002:a05:600c:4f07:b0:421:7e19:5afa with SMTP id 5b1f17b1804b1-42304844b70mr62486175e9.30.1718479222019; Sat, 15 Jun 2024 12:20:22 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a05:600c:3b86:b0:421:7d7f:c621 with SMTP id 5b1f17b1804b1-422b8cabba4ls15595995e9.1.-pod-prod-05-eu; Sat, 15 Jun 2024 12:20:19 -0700 (PDT) X-Received: by 2002:a05:600c:a01:b0:422:50d7:100b with SMTP id 5b1f17b1804b1-42304820c95mr56501945e9.14.1718479219128; Sat, 15 Jun 2024 12:20:19 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1718479219; cv=none; d=google.com; s=arc-20160816; b=lwpPBISUrNFF8oSuEKHpPxGvHgvFO3ruf/+ZDNIbulmvt/4t8td4o8ja4tqlaw83b7 X4CZirz8Bs3C3kRVXuE8RyPwGEuCIZ+vj12YPVAqAOAp17ri/WiQkytjQOVUy3zxCFv7 //i4+cqVFW7Vl1Pcir6JgRJ2lrDflFPjKol6sjLmpygSWF+KXhEoPWluWnlcWV2WsGpA cZnRRMmCJ08PcAsOlXF/kmlMdmFWTsQTX4afESihp4Ta0FlBdPiQfaQ0r77RLLPhx3Ag o1f2n5HyxisH51/0REcrXMhbgdcRsU8Wj1Tjn+TBboOXjQ+/6pwyCfMgXKhci8WH2jKY ii1g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=kCI+fyL64e7eZoDJwLBDGJN/CsLkEmd8y9siW0RWjBg=; fh=zydHuzCQWrku2OPQyZfraJZFcOpEXLQ/YBcu3QNiBd0=; b=wqrLkQnn5MHrjk7gsh/eHvnwlW02oZe2A22zgZuhRRpjxjITFp7U2redYiSIM/96tV jWZOoxu46TA6RAVn6Bu0dS+bO+ahsh+jlS4LX86xB1tyK+6ju+/xi6e0JkiMAHfweglQ 1Q1E7V8jqLLOPRHBebZwKqMrvDK7k38NrNZ1HMETMLonSbfuC7QtC0vDlbc+wX6+O7Qn i2H92j1t6md8jO0JbEjOE3IJ8rOLChGsG6lDtqE41BF2EfXizmu7nZmplQkVSm36gttZ JJcr/8QeRtkxJb+ZIwVeT3/NhR9P4EJNSqHvFMgY55BWmjew2Z1kszJ3I3iFVTX3mKI3 zzPw==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=LI7UcPb5; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::22f as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-lj1-x22f.google.com (mail-lj1-x22f.google.com. [2a00:1450:4864:20::22f]) by gmr-mx.google.com with ESMTPS id 5b1f17b1804b1-422855708b8si572675e9.1.2024.06.15.12.20.19 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 15 Jun 2024 12:20:19 -0700 (PDT) Received-SPF: pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::22f as permitted sender) client-ip=2a00:1450:4864:20::22f; Received: by mail-lj1-x22f.google.com with SMTP id 38308e7fff4ca-2eaae2a6dc1so58953181fa.0 for ; Sat, 15 Jun 2024 12:20:19 -0700 (PDT) X-Received: by 2002:a2e:a415:0:b0:2ec:1e6e:13f9 with SMTP id 38308e7fff4ca-2ec1e6e1442mr20275671fa.52.1718479217580; Sat, 15 Jun 2024 12:20:17 -0700 (PDT) Received: from PC-2635.irisgmbh.local ([2a02:8108:96c0:76fc::80bb]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a6f56db61e0sm327283766b.49.2024.06.15.12.20.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 12:20:17 -0700 (PDT) From: Michael Glembotzki To: swupdate@googlegroups.com Cc: Michael Glembotzki Subject: [swupdate] [PATCH 06/21] mongoose: Remove double free calls Date: Sat, 15 Jun 2024 21:11:19 +0200 Message-ID: <20240615191941.40301-7-Michael.Glembotzki@iris-sensing.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> References: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> MIME-Version: 1.0 X-Original-Sender: m.glembo@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=LI7UcPb5; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::22f as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , mp_streami->part.name and mp_stream->part.filename are already freed in mg_http_free_proto_data_mp_stream(). Signed-off-by: Michael Glembotzki --- mongoose/mongoose_multipart.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mongoose/mongoose_multipart.c b/mongoose/mongoose_multipart.c index fb62c1e4..3361169c 100644 --- a/mongoose/mongoose_multipart.c +++ b/mongoose/mongoose_multipart.c @@ -142,10 +142,6 @@ static void mg_http_multipart_finalize(struct mg_connection *c) { struct mg_http_multipart_stream *mp_stream = c->pfn_data; mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_END, NULL, 0); - free((void *) mp_stream->part.filename.ptr); - mp_stream->part.filename.ptr = NULL; - free((void *) mp_stream->part.name.ptr); - mp_stream->part.name.ptr = NULL; mg_http_free_proto_data_mp_stream(mp_stream); mp_stream->state = MPS_FINISHED; free(mp_stream); From patchwork Sat Jun 15 19:11:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Glembotzki X-Patchwork-Id: 1948203 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=vZRa60E5; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=fbgbX8gc; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::237; helo=mail-lj1-x237.google.com; envelope-from=swupdate+bncbdy5juxlviebb5osw6zqmgqegghrmeq@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-lj1-x237.google.com (mail-lj1-x237.google.com [IPv6:2a00:1450:4864:20::237]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W1mFT05Qvz23v8 for ; Sun, 16 Jun 2024 05:20:28 +1000 (AEST) Received: by mail-lj1-x237.google.com with SMTP id 38308e7fff4ca-2ec01fa1a72sf24329331fa.2 for ; Sat, 15 Jun 2024 12:20:28 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718479224; cv=pass; d=google.com; s=arc-20160816; b=aLyZ+lB4lWy5/NL6dZTGndKlhpokDdmPDuRuNM7OrcoOyOxwYiE7jFIA6KxtNdvoom T3cnh3glkexcNkaG4snKIxUXVn19+PCcILSMjpwrnylCrWpCtCqA/8ySR8ClYb3OV0yg Yf6gNvw7XnevhQFxAjbuWaPBmNekpytMOIHwubC5lMX/VCgDdoG0oVLcFOe60XezB8Fo m4c/UTrDE/l3Jznei7fMPNXkqx1UlbZGh2sBn0S+5wB1pVJkkdZKo1bNmgQOq/p1EM8E +el+173QGxVkfVY3z9tsoCfcjjXUjuVJhFZLqSEG3t6ZHpPpJoBa8qDa1Oi+p1lBNMxw mNig== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:dkim-signature :dkim-signature; bh=YdMHSHamls9QHp1ho8rqRYYjr6g1M8amEBalhBS8fXQ=; fh=9wjSvTviJ3Go4WjnOvEeKXd3y9xRObNsP1J77magifE=; b=IuafxwNwUOLjSDa2n2hVKjA+1JPEfZIK6jgw2xcY3C2t6n0Nv+0rKCwnBl+BIAxihQ aJLFjP2h2vj6oXhoiHuecbEJrCPn/JTq81mQA8TBlBk9IdgH6JlYNbflbpZc6J7Ckdlq 84IKejO5dhp/MtUE5W+9BSKNLZKwQgtkbLAOLIHFK9qeOl5PSGVyZuuTyX5pIWn+vJWl Ljolkp5HCYhdHxJDzHheQZQNOF5170T/5cjFDW3PrPqyEi1dExzP/XRrPiulBcEwKSzg ZoOyuefoWbK95VhmdxqP2EErCexmbSI7Viy3m/afpmtnQRCAoH92+2ISpAI5sNklivrJ tjUQ==; darn=patchwork.ozlabs.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=mzlHtXAR; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::629 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1718479224; x=1719084024; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:sender:from:to:cc:subject:date:message-id :reply-to; bh=YdMHSHamls9QHp1ho8rqRYYjr6g1M8amEBalhBS8fXQ=; b=vZRa60E56TNBDikfopFt3cPkdtUG1dcJcnRGe05lQ30cZPk2rYp+Z3RzRS76650YH1 a1/P1dwF4zNi1tN90pbbsIMCr5DhReL4ok9cLDlA4/7YOwfzQ8OjD5xvwjaoZGuhjuP4 cs5a2piz4Aqy/dX3r++4h9chqxSYbLXweBFygqtJlrEzq047pCWpNAg86KSos45BDvWc fh4TlQUxaLy0p00x0DcrVM6iEjwimoJsPckYBf03rfy1rA0nkQZXC1ulugC5nVOUiMvE yVHONZ/d7jCxWDXU+qvurh0766k7mbX5KVlXfg0jz/P5wCqL/1p9OR0Kp5J9/sgfLKbS dszA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718479224; x=1719084024; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=YdMHSHamls9QHp1ho8rqRYYjr6g1M8amEBalhBS8fXQ=; b=fbgbX8gcno04P5y0I0/10w0FSZ3YgaI4xGUV61/hMXxe3ZnMxX/XYSwgsJIK7wZbSF NsrceSKXVzA9NbhJI03vBkC+qqvy3QRISJ2qSkeDqMqsJDO1LZglJX+50kmraXz6xpAN mxzPpoDFC6WEoBf1OjHoXlHj6f8JMwVDh2OGNFPqDOGTsJZwPXImdlMThruxGurfvsnz J4bqlKx6qlPYLbW5gwrsUc7VctNN9P4o2f3njlepW7uVN+4CB2nrFy004F0ZR+WvqzYK GMdYti1Ta1t/r9i5NuKBw3FRYU8E1jbufUIKmFVcjFyz79GEKnB3I/yRd/js0H5bJWhn okkw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718479224; x=1719084024; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :x-beenthere:x-gm-message-state:sender:from:to:cc:subject:date :message-id:reply-to; bh=YdMHSHamls9QHp1ho8rqRYYjr6g1M8amEBalhBS8fXQ=; b=wE+O/2rFAnTMbSF+iTxlXivi+abTRH8OoXZNBqZ2NN/CktaogPzJ+j42T3FT9HX8MB J0k2uX0gQHkfyYE/WC9B0/jQ39XSm5eVLRuBiT1epNGgs4oKmD2bZUeYiKgyTa7CnXju o8bVuohVutWIYp1JWyM79Mbl3zKqcPSqZiBJtPUUdsXZCDiTbLhu73SLugAnXVT+95we lOR697XdzU2KAj4GP6ancPUmQfPDGgjR1K3TYdKe2zckLSHfPFjRTfh3a+IR2E359W1Z ztreLR9CMK9i4kVLXU23CmQ0Vhz3gRiRjKZjN5zjuZyj047a80IPLoRiHXd8xGyepQe9 k8tg== Sender: swupdate@googlegroups.com X-Forwarded-Encrypted: i=2; AJvYcCXJjNKQLXbTt7HTZKseI/L5lndDQ6QOnVXVjg0wGo2AuqOXF+qiKvHWof5KCW/ami9vVOb1M9vikb/3GD6o577unl0b0lMUjEzfAQwT0g== X-Gm-Message-State: AOJu0Yx16T6EFIzulrRQ5K10JUa9WyGKPkNlQ2G78173a2lJy5Jk+hsq 5XHx684oJkD58DlmCpV9ScGPEtwQyb1meAKIkZErn2EKFxFoe3IP X-Google-Smtp-Source: AGHT+IG7MKmqwcnZ7lkXzO+++NBd2tImxSPe7MTg+GHpJpfQlld9t4h5S0QV77sqIdBZgmrHR3JKUg== X-Received: by 2002:ac2:4ed8:0:b0:52c:9d31:3f25 with SMTP id 2adb3069b0e04-52ca6e90302mr4080165e87.43.1718479222330; Sat, 15 Jun 2024 12:20:22 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a05:600c:3b0c:b0:421:7e41:1878 with SMTP id 5b1f17b1804b1-422b6cce65fls14485905e9.0.-pod-prod-07-eu; Sat, 15 Jun 2024 12:20:20 -0700 (PDT) X-Received: by 2002:a05:600c:35ca:b0:421:7c7d:bfda with SMTP id 5b1f17b1804b1-4230485a4a5mr46828905e9.34.1718479219651; Sat, 15 Jun 2024 12:20:19 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1718479219; cv=none; d=google.com; s=arc-20160816; b=hGFC5AuqEyfbq48e8vh5MrRhxMttXDQARuHjgrMUB8eTFozP4WsBlWGb546L0ctBMa woUjqJBw8Y8Rb0WUSD3+TleMRphEallL2SHM0C7LpGLvGYaKTg8xfMiA0mFy05ji9xpT NSXgO3t9HE73b84qm3QM/dlQV0/oyauxGbenpd+vaz4tevO9Ukjxwgg55a6FMMcye3vd MD4O9oeIdyOxPRxZjixeo/JtUj1JfStTwj3pqjxUpS6edjaA5REexrMVsNp84HJUBBDk 4UEmiXZlkTO9MXgjUTzRJzH1A/H83IpjRVd+vxGl6dLDJAvX2QT0Yi2wtFq8yQjVuMju 3+5A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=kn2NunkyE4fYuZq2NkygmtArSKSHvDPDXhCevYyXUwI=; fh=zydHuzCQWrku2OPQyZfraJZFcOpEXLQ/YBcu3QNiBd0=; b=sBuSQT3Xp1foz1vRNOif7gOfnMVS+MtSfOyDKbKwTG55LtXocDivgmvk3yCYmP43hv CZqhBtB6sKWKrnQ5mKkfN1bHwrMA4FvQfyJYJspPNM0TsgWyiqm1E7ZR/a58k8zpNh2u 9V/Hx5VcfpcY0Obxgai0Pbq20daoXRbIE69YlyGkhrB/HagT8ox1er0v/SWpqdRV2lou 3Wu7VxACAmussxdEOmxIniYBucxNcO0Mjwosqnv41dWvLdZZFLebecH+z4TzEFnxvoCx JsaV4cqFAlOUzxav6CU5xlg9Nnm68Q/iC6rIiDYFXEZTOUJ387zphoz8oC9gavkU3kNq U8hg==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=mzlHtXAR; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::629 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-ej1-x629.google.com (mail-ej1-x629.google.com. [2a00:1450:4864:20::629]) by gmr-mx.google.com with ESMTPS id 5b1f17b1804b1-4228556ff26si2751555e9.1.2024.06.15.12.20.19 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 15 Jun 2024 12:20:19 -0700 (PDT) Received-SPF: pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::629 as permitted sender) client-ip=2a00:1450:4864:20::629; Received: by mail-ej1-x629.google.com with SMTP id a640c23a62f3a-a6265d48ec3so448208266b.0 for ; Sat, 15 Jun 2024 12:20:19 -0700 (PDT) X-Received: by 2002:a17:907:1189:b0:a6f:51b3:cbbd with SMTP id a640c23a62f3a-a6f60cefedamr376302466b.4.1718479218435; Sat, 15 Jun 2024 12:20:18 -0700 (PDT) Received: from PC-2635.irisgmbh.local ([2a02:8108:96c0:76fc::80bb]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a6f56db61e0sm327283766b.49.2024.06.15.12.20.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 12:20:18 -0700 (PDT) From: Michael Glembotzki To: swupdate@googlegroups.com Cc: Michael Glembotzki Subject: [swupdate] [PATCH 07/21] mongoose: Replace deprecated event MG_EV_HTTP_CHUNK Date: Sat, 15 Jun 2024 21:11:20 +0200 Message-ID: <20240615191941.40301-8-Michael.Glembotzki@iris-sensing.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> References: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> MIME-Version: 1.0 X-Original-Sender: m.glembo@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=mzlHtXAR; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::629 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , mongoose rev-id: 736e7a2cf96b4768e2c5c32985becad839750947 Signed-off-by: Michael Glembotzki --- mongoose/mongoose_interface.c | 2 +- mongoose/mongoose_multipart.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mongoose/mongoose_interface.c b/mongoose/mongoose_interface.c index 3fbe88e2..eecaa407 100644 --- a/mongoose/mongoose_interface.c +++ b/mongoose/mongoose_interface.c @@ -710,7 +710,7 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data, void *fn } else { nc->pfn = upload_handler; nc->pfn_data = NULL; - multipart_upload_handler(nc, MG_EV_HTTP_CHUNK, &hm, NULL); + multipart_upload_handler(nc, ev, &hm, NULL); } } } diff --git a/mongoose/mongoose_multipart.c b/mongoose/mongoose_multipart.c index 3361169c..a2932356 100644 --- a/mongoose/mongoose_multipart.c +++ b/mongoose/mongoose_multipart.c @@ -336,7 +336,7 @@ void multipart_upload_handler(struct mg_connection *c, int ev, void *ev_data, return; } - if (ev == MG_EV_HTTP_CHUNK) { + if (ev == MG_EV_READ) { if(mg_vcasecmp(&hm->method, "POST") != 0) { mg_http_reply(c, 405, "", "%s", "Method Not Allowed\n"); c->is_draining = 1; From patchwork Sat Jun 15 19:11:21 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Glembotzki X-Patchwork-Id: 1948201 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=pqoVSd4A; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=NGhClTTQ; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::23b; helo=mail-lj1-x23b.google.com; envelope-from=swupdate+bncbdy5juxlviebb5wsw6zqmgqerop5ywq@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-lj1-x23b.google.com (mail-lj1-x23b.google.com [IPv6:2a00:1450:4864:20::23b]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W1mFS5pCnz20fR for ; Sun, 16 Jun 2024 05:20:28 +1000 (AEST) Received: by mail-lj1-x23b.google.com with SMTP id 38308e7fff4ca-2ebeddcba43sf22539831fa.2 for ; Sat, 15 Jun 2024 12:20:28 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718479224; cv=pass; d=google.com; s=arc-20160816; b=xJgnYnbTm/u0+OXXOSfoEPLawMuBJP2Xruh4bSELzlHqL/pztqhvy0FI3gw1m2fLr/ 02Kfx21qr0frA+OScExEgRuH04pPmjaXQY5Bi3tng0+/VWnQTuvEkMctzoQrWDFMr5Hz g5n28wBHaZ/wD2wAGYViOIlk2b/GTScvHXCT+1RU36MSvBRX53QqVfxS28Rb5voRzBQW /QGICyMXnKFBOQgW5kVUXoR4hgDY5WVlVa4GpDXCFPGfVXpnSBeKL/zR2o/d+4XP8e+7 ZDBIkxq43PCOlpiDpQOvxpGF4hIL9RUbYV8SU/juUDaWd3GrBUjQKyO+pHcJziLfF8g4 fWJg== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:dkim-signature :dkim-signature; bh=LFy4hjVQ3hSxwZoojySZECFRKb5HPQZaASLPimNxA8s=; fh=708ivVwxd6RpotFnFS2CsohMDWivqbTT+tmyfXlIMIA=; b=F3zoRjFHQysvqrYR7Iaj8gBiT3L7E8EgWDYtPNbiUfaNJTlv6j0c270wJuEhljX3eA XA7J5YWyzumsJmlWyvyZs01wHahZ91xydVYMp3iihgn2zymxUJhVBKN+/N8yXdVFSPWF ch7GW71NNlMxh7VJoPS3FyKKn+dL1yAjpL28MviJr8JbrV02ThrseuCa7kSgt3kBYdMx XacyDp8uSmroARoDejkURVyUmZFWGJmb5iUqHZn7SXmHiNUwhL+Hqag+9FdGH3hwsG// c2t66Zfg9QwVztmAZ0NbM0qG1p0HtFt70n1U7lCrcIMJMFwaBcyPzhv7dON8b7LJ94RA NXkw==; darn=patchwork.ozlabs.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b="dt5B0E/H"; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::52e as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1718479224; x=1719084024; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:sender:from:to:cc:subject:date:message-id :reply-to; bh=LFy4hjVQ3hSxwZoojySZECFRKb5HPQZaASLPimNxA8s=; b=pqoVSd4ACfMp9ru1zzpJ0yRJwLAe/kYlY4BKJ0qOUH9V8HlYIsnDQ2XrYntkg3/feG OxANj3+zrsaMBfR6RrUyTO8yWeIky8D1PiDw1A2vp4M9v1tE4CtOzuwPyGx+nmwBOJzE 2lapFtc8r/51NgBtoVjysRXrS+t8GTNrePh+AZXh3jixPswJcS+TGeNucph63txn6laf mUJ4MoXMemZPgiXoWy4snY5mHd6sKvf/IwcH1g8vsH5ADdE0jOla82U2AKnr/Wt0PafH V+/uRbSBDzdbdOWQzqJcnd4K8KzgBnoqWaW2wvfmkPj6WgejIVtsjpIRXjqfg7ilLa8Z UBDA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718479224; x=1719084024; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=LFy4hjVQ3hSxwZoojySZECFRKb5HPQZaASLPimNxA8s=; b=NGhClTTQMf6l72Wz48qDLGohcCivlLT/xUIRwwAAw10OuPvsLWiK2lJFvBHFSAE75Q 0rxhXI95+XE2SYFT7PS+zLRNmCviAIlaiV9jkl9RLtsykUwFnC96Jlz4eL3kd+ZBOZ9h s7LzJ318HrBduxnToO0/cUV4mz4D4di6WyuF3PIg2/Daz5ma4efgWeOyEvfbCA+eKy84 UM4gNevZ/k/AVqHX8rIAuaoSEvAocLcVkBMsvMC0jZY1mHY9GkWUA1goPQTX0qvWPVCG xEo8lmZzi0shLumRlcpdN4mh/3ABdd1NbDjewKMbjM/Iwc3zm2qqdIWvPTKmRslgM/Dz ZtGA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718479224; x=1719084024; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :x-beenthere:x-gm-message-state:sender:from:to:cc:subject:date :message-id:reply-to; bh=LFy4hjVQ3hSxwZoojySZECFRKb5HPQZaASLPimNxA8s=; b=QIoYrcFpI8IVIcVLiRGiLM1TfcA6hC1k7AxtzQa1RodnBLveS/zDaZxMrRbAmkUrmZ mtiDB9Zq8fMn0vCbz40EoEEpH1Ub7qqEk8m2GuPl8eedHlkCXmS5rgtU8Ufi0G/Bk9jM P1aGQQJPeQocrFSWCytQskZAeEJxOvwt30yfwVxlfpda/Krbdyv1wjTdjJXjCWXwHCfs hU1OOJsZhoNg7INwbZLzzsS/P4H72KuZWZpjjSeDQwmAYexGdWSBFp/xSpD1NR5DCSdv bNS5c+fqAlC9adQuxP0N2yjUGoiQEFGwjvY4zVehjTZyqpuWBUZCE1gW1seRkRgFi4dg aU0A== Sender: swupdate@googlegroups.com X-Forwarded-Encrypted: i=2; AJvYcCW+i7N3XdvCoO1Q2IyMFEici3Aj8qy4i8A9Oh45ZM57Y8dkU2ekVpqy2ISnjWjgbTtc7KKF/PdqEx6YDOLaOOGdyahgg8Xpv47qCLVEKA== X-Gm-Message-State: AOJu0YxSgE3eq6F3efkzfEKZfCJYgknm3YM8WmQXvDIC+xtJap73PyX7 hclm9sXE3EUT/5ijCZQt89AwoFNyoIfbGFarjmsL0Dnuzlt/Mk+N X-Google-Smtp-Source: AGHT+IF9hsZN6WCis26pJpC2L0WuarpvWcMI+nqY9LALr9okXjPELKoOzSFkqaiUiEH0noV0ljxuvA== X-Received: by 2002:a2e:86ca:0:b0:2ec:2508:f370 with SMTP id 38308e7fff4ca-2ec2508f404mr7703451fa.51.1718479223123; Sat, 15 Jun 2024 12:20:23 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a05:651c:237:b0:2eb:e93b:935 with SMTP id 38308e7fff4ca-2ec0284c0bbls15083071fa.0.-pod-prod-06-eu; Sat, 15 Jun 2024 12:20:20 -0700 (PDT) X-Received: by 2002:a2e:8751:0:b0:2ec:174b:75bb with SMTP id 38308e7fff4ca-2ec174b77d9mr30838771fa.28.1718479220154; Sat, 15 Jun 2024 12:20:20 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1718479220; cv=none; d=google.com; s=arc-20160816; b=tkcLhJU3B3BWR5GXTGFI3kervYe8dC/y1cCMjjfHh+1KNioKtiCwD7IL4ySq5fPLn7 r0rBCoFUHriRL5YwJT2pCbAB+P3l1UvfDgujYfH/716P+hZJ2fZEgw4XLjo4+6wAvYFn 3OjehfBUs9C63UBgs7gL9wmkYf6JWTbDgnIbWVke2x7WRIMdInhdVF/PyiSIgaFiIWBh g7esIh4A2Mj30i+M56Y4xsT2jJYPJbV25uuqSLMpkk/K/oGbVd7nv7NXIyqHPpUdIH7j hV53QNve/8gziM62RaYl13uueJjU0pxbh6+HF12Dba774I/TYrn4QXLtdyTKZePzABdx jU3w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=LQzhFe9RJJySfNn6Gvv4JV2o1jUz0uCXmsH0ocHB8VY=; fh=zydHuzCQWrku2OPQyZfraJZFcOpEXLQ/YBcu3QNiBd0=; b=MFw/rdtK8lcMHhSiiz1P3ghiQAWx/SwrHGGAHsBwrZKOXjHRfWkCwCmp4RIR2uJDE3 6ATzQrJekk2jq5KAN3iNUxZ6YEblKxCNG6/csxyPIJWcu1mnul/nSXOKQOraJ3M/0iRg OKImzK8sl41qGopW2TtwreEh0cevXhPmqHCBKuB98D9XZ3mXzfA4u6nVGjXRfzuKK1GO A6INRlr+WibODqTQNOnVsFuP+/kOVuz+TIB8dKXR4/8c5ek/JSD891a639iODQ0oWblW 4rZr73gRnImNfU2trY0TTP1ODMni2lPBs3Wb+Yq30p46bprewKeeon/UDVFukpykva9X W4NA==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b="dt5B0E/H"; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::52e as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-ed1-x52e.google.com (mail-ed1-x52e.google.com. [2a00:1450:4864:20::52e]) by gmr-mx.google.com with ESMTPS id 4fb4d7f45d1cf-57cb743880asi111227a12.3.2024.06.15.12.20.20 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 15 Jun 2024 12:20:20 -0700 (PDT) Received-SPF: pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::52e as permitted sender) client-ip=2a00:1450:4864:20::52e; Received: by mail-ed1-x52e.google.com with SMTP id 4fb4d7f45d1cf-57cce3bc8c6so705486a12.3 for ; Sat, 15 Jun 2024 12:20:20 -0700 (PDT) X-Received: by 2002:a17:906:91b:b0:a69:2288:41da with SMTP id a640c23a62f3a-a6f60d1e08bmr370140566b.30.1718479219378; Sat, 15 Jun 2024 12:20:19 -0700 (PDT) Received: from PC-2635.irisgmbh.local ([2a02:8108:96c0:76fc::80bb]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a6f56db61e0sm327283766b.49.2024.06.15.12.20.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 12:20:18 -0700 (PDT) From: Michael Glembotzki To: swupdate@googlegroups.com Cc: Michael Glembotzki Subject: [swupdate] [PATCH 08/21] mongoose: Fix mg_event_handler_t interface change Date: Sat, 15 Jun 2024 21:11:21 +0200 Message-ID: <20240615191941.40301-9-Michael.Glembotzki@iris-sensing.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> References: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> MIME-Version: 1.0 X-Original-Sender: m.glembo@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b="dt5B0E/H"; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::52e as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , mongoose rev-id: 5826d0e41c83170b824d73f1bee723c1be38b8b4 Signed-off-by: Michael Glembotzki --- mongoose/mongoose_interface.c | 11 +++++------ mongoose/mongoose_multipart.c | 3 +-- mongoose/mongoose_multipart.h | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/mongoose/mongoose_interface.c b/mongoose/mongoose_interface.c index eecaa407..b3ebc62f 100644 --- a/mongoose/mongoose_interface.c +++ b/mongoose/mongoose_interface.c @@ -359,7 +359,7 @@ static void restart_handler(struct mg_connection *nc, void *ev_data) } static void broadcast_callback(struct mg_connection *nc, int ev, - void __attribute__ ((__unused__)) *ev_data, void __attribute__ ((__unused__)) *fn_data) + void __attribute__ ((__unused__)) *ev_data) { static uint64_t last_io_time = 0; if (ev == MG_EV_READ) { @@ -563,8 +563,7 @@ static void timer_ev_handler(void *fn_data) /* * Code common to V1 and V2 */ -static void upload_handler(struct mg_connection *nc, int ev, void *ev_data, - void __attribute__ ((__unused__)) *fn_data) +static void upload_handler(struct mg_connection *nc, int ev, void *ev_data) { struct mg_http_multipart *mp; struct file_upload_state *fus; @@ -685,7 +684,7 @@ static void websocket_handler(struct mg_connection *nc, void *ev_data) mg_ws_upgrade(nc, hm, NULL); } -static void ev_handler(struct mg_connection *nc, int ev, void *ev_data, void *fn_data) +static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { if (nc->data[0] != 'M' && ev == MG_EV_HTTP_MSG) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; @@ -710,14 +709,14 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data, void *fn } else { nc->pfn = upload_handler; nc->pfn_data = NULL; - multipart_upload_handler(nc, ev, &hm, NULL); + multipart_upload_handler(nc, ev, &hm); } } } } else if (nc->data[0] == 'M' && (ev == MG_EV_READ || ev == MG_EV_POLL || ev == MG_EV_CLOSE)) { if (nc->recv.len >= MG_MAX_RECV_SIZE && ev == MG_EV_READ) nc->is_full = true; - multipart_upload_handler(nc, ev, ev_data, fn_data); + multipart_upload_handler(nc, ev, ev_data); if (nc->recv.len < MG_MAX_RECV_SIZE && ev == MG_EV_POLL) nc->is_full = false; #if MG_ENABLE_SSL diff --git a/mongoose/mongoose_multipart.c b/mongoose/mongoose_multipart.c index a2932356..265c02b9 100644 --- a/mongoose/mongoose_multipart.c +++ b/mongoose/mongoose_multipart.c @@ -315,8 +315,7 @@ static void mg_http_multipart_continue(struct mg_connection *c) { } } -void multipart_upload_handler(struct mg_connection *c, int ev, void *ev_data, - void __attribute__ ((__unused__)) *fn_data) +void multipart_upload_handler(struct mg_connection *c, int ev, void *ev_data) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_multipart_stream *mp_stream = c->pfn_data; diff --git a/mongoose/mongoose_multipart.h b/mongoose/mongoose_multipart.h index 1d2b7dcf..e0dee845 100644 --- a/mongoose/mongoose_multipart.h +++ b/mongoose/mongoose_multipart.h @@ -43,4 +43,4 @@ struct mg_http_multipart { size_t len; }; -void multipart_upload_handler(struct mg_connection *nc, int ev, void *ev_data, void *fn_data); +void multipart_upload_handler(struct mg_connection *nc, int ev, void *ev_data); From patchwork Sat Jun 15 19:11:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Glembotzki X-Patchwork-Id: 1948205 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=U6fjFrRx; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=l4hvEU1+; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::13e; helo=mail-lf1-x13e.google.com; envelope-from=swupdate+bncbdy5juxlviebb6gsw6zqmgqezj6niwi@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-lf1-x13e.google.com (mail-lf1-x13e.google.com [IPv6:2a00:1450:4864:20::13e]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W1mFT0R6mz23vC for ; Sun, 16 Jun 2024 05:20:28 +1000 (AEST) Received: by mail-lf1-x13e.google.com with SMTP id 2adb3069b0e04-52c8338fd51sf1923203e87.1 for ; Sat, 15 Jun 2024 12:20:28 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718479225; cv=pass; d=google.com; s=arc-20160816; b=zM8HdfZKoVSyjkjBtVDFBk9KFnwXdf7IkoaUp6+aPZWWqIcEGiQt5VfgRvRfRPJBzv DKG65KJ7k7e+tdBUMZxdDC6O3LIY3VN8OGKfc9/9XHUbPnWBNCffTREK/w2ZhH/k4IBx Y8Fxczed463wtjaMcmqQRVEpj061VmGWuVB8kg+DX1V5SFZygMvQ5UiecW0My+UpMHer adLLxLa1a4WajXdW0u7ANAljZGf+3FwW4BIaFbD0grTmCEiIRFu/6lpc/j2u9x/RZmt3 WvB6ENmnV2bEAYHQSkMF7P7GAKytUpgWAxKI8qSoqYAb+CPz6HG19k2Ts++RQb5UyoZz BMkw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:dkim-signature :dkim-signature; bh=/ItXyRtFww0hgluS8THbYHJmQ6VZZSRLMpUf1dm0dfA=; fh=Ld1J7DYK8ahRwcJJv6z65vnevvVVEnm9ZEXIqrI/wjs=; b=t119OGU4k2/YjSW588M7K/nXgxVYe5McEJBz+sxwnaytgXVWd/p1FIW1ic7PheKqkk a6Gn9WqqY6b3IUlvpNiZGFXLkzZgIrFFdY0prG1R+BT34mp5TX0UhtskN8Zqq6shIOGy A6Kcb4GAMBYIZOjmGyXbEvPVfrsObdhrJ2KKCL2wEP6ifphtSr039D4tGWgbaHSzS6Sk hvl/0wG2oM3b5d/GwPEggpFn/r+lAqE9XYNCzKTvlB4KlVykrj9aBMN3hBIDiU2ABe80 0NUkI7gt0vxLb6RNF6+DNWrTRcBzl6Uw2AiJ/eC7yiwMvIzHEme7O0x147vnRuReiP2W Mw/A==; darn=patchwork.ozlabs.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=UdeEaFIW; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::631 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1718479225; x=1719084025; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:sender:from:to:cc:subject:date:message-id :reply-to; bh=/ItXyRtFww0hgluS8THbYHJmQ6VZZSRLMpUf1dm0dfA=; b=U6fjFrRxipOz/Dh2pOv+wZkI98tYQKB3bySMCQvL5GJV4HxMFbp2JyCO/9zPbG+51e D2r2RCbe5UyYVHevhsnldFvnH4n1mRoD8UVfoe2Suxm18OAG7olyYM3n0v2c9hHVzteh ztMMxZluq1ICfb/Ql81z7m7UWimMyPzDmYyUC1C8VlVtHWOhRfaAbNsVay8Qhlcmbj81 FDpixLRWenTidYPk3ro7a2F5Nt9DvTGs33VtEgd2D/VwnZXQzT/h7mrpXXv5gqLX8rhy IPXUKRCAwiDL6/nrRxhHYbxm9U9nOdT7cBulEFZoH08+MBvsmHuidwHJi6pLhiUG/lsx qCTQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718479225; x=1719084025; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=/ItXyRtFww0hgluS8THbYHJmQ6VZZSRLMpUf1dm0dfA=; b=l4hvEU1+c77BG/+uI6paV32QqkF3ILiEN/ht9HEov/bROS487eZFP9kw3jf2uy+o9L ULlOIscQgtAC3ssAkdBvda8fJYBeAGzV67JpX8TQDl85PWxrIKAdH/x/a+xo++bgSQRZ ZCuLWXpSinuN0V/Bgu2SxdYwgzsMW+yQgBEZ4+eTyPZwJts3KBSLUa0/9F8XLrFpJZSM C+m4HWy0IiyFlP0xpFyiTIUEm0AFhMAK5stKs9CDkPKqN/CXC395khKCYlIh815PoN9P 6oZmyUT1QesAPapFrAZuXGykftdCTJ7QvkR2rxkrN+kpftc8Q4OXTSo3LBYIGF3JDSX0 1YYw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718479225; x=1719084025; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :x-beenthere:x-gm-message-state:sender:from:to:cc:subject:date :message-id:reply-to; bh=/ItXyRtFww0hgluS8THbYHJmQ6VZZSRLMpUf1dm0dfA=; b=IGMzRbpGatQDn7Nc5WB3IoRi7LpfcKVE4Xg8K/lEDBnOZdZVCUuk0YZ1FqMnU+5h3C rpYheVQMnL41qQW3Ha/uEXMhofG/3AYwz1usS/HjfiSN4WIZOowaWnLa3tay1bGLI+iW o6HTFLJEVuSf+uUAlFz99QY8YTmxTYbl3xTOEXXnK0p9S3TPmapapBeG6fVx8PVpAx67 4jCUCvetAQQ6qrNGmBnuH+uusAiw0cFaF0yRgEPLu/4zqZ+ZNXiFxHAUPzan9Ywm+ivv dkEpdAQffBdru3NaWhqxIsy8uPDNgLLGin9SCxSSRNqUAWG83z8rRUuQJ+lDfN4YzHsD NNPA== Sender: swupdate@googlegroups.com X-Forwarded-Encrypted: i=2; AJvYcCWZYHjamGNGzr8DLeBFuonSKc138jRx3kyPKOKbtUPU7NSgppmwEdicQ6KH/SCqxpdZoF9yNdbTCLmYyQ+pq2BJ3a9FgM/fAg9TtP853w== X-Gm-Message-State: AOJu0YzUeRNJcJpktlLfRPMY44o+HaWLvQuegpOVPbKAivpDV7N8+9F8 nxaZ6xADtYF82xNFQsAGfGPcxiA28H89RnBPUAVL+qTUNSyLbX7q X-Google-Smtp-Source: AGHT+IEPAk8SDUnms9xaBcTks2/OdpEkursALjS/GPe0knUDMU5pectPZ0s8bTeC6kPM90QY113Ttw== X-Received: by 2002:a19:3819:0:b0:52c:b257:bdbf with SMTP id 2adb3069b0e04-52cb257beadmr465597e87.8.1718479225188; Sat, 15 Jun 2024 12:20:25 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:ac2:4d94:0:b0:52c:a191:2696 with SMTP id 2adb3069b0e04-52ca191283fls613129e87.0.-pod-prod-00-eu; Sat, 15 Jun 2024 12:20:22 -0700 (PDT) X-Received: by 2002:a05:6512:31cb:b0:52b:bd97:ffd7 with SMTP id 2adb3069b0e04-52cb04af3fdmr829702e87.29.1718479221554; Sat, 15 Jun 2024 12:20:21 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1718479221; cv=none; d=google.com; s=arc-20160816; b=AqKbYtjCPeQHfdwE7Eh0W1AzYo3sw5oaq1EzK+HUpa1WkDbHWH4YRIoKVsC49XKhUT m016wqHVJyKxcWraoWULzthdZsILmnRN0ymgIZxAQ/Vrn9yeUUzGmWZkQvpbohd9YcZh pUUc4/srt8nrYchNRy4nFlFcZiisbAIUewaNtKJgAOOt5fnMElIC3Hra0+jTUZs/mOLR Kzm0srh8Oi992AQ0109Fz871nzYjf1A87V+Gbx/7FE5+vxNtlK1Siv7uDSOoWPMuQrbZ bd4aHxbck+HLyMX12ksJVm7qp5KQ8N6ymr2Bjr475mkkV4XEG9TWRPl1aDahmDin5cPJ Lvug== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=pN7wbSdre8mc5H2QetiMWOP8+y1w0RJnPWEgTEeiwiQ=; fh=zydHuzCQWrku2OPQyZfraJZFcOpEXLQ/YBcu3QNiBd0=; b=HzInpedJdKwx2nF+TUxTOYmTfV+Io404VcfXHJy5J3UpkcNAqj94xCVZFdIJhB4bpS lu9w+k4WE7hJoPRSSw25l4q+rVXVsig4SOROBgVTkqiqisvSJypiNRD+lfqDZw31rFV8 T2aX/J1RkzxNXkm/0x0IxqrdT5LGTgEuI16QWFjPe0PdViTp/fwfX8f2fabiouI9eYaO 6NJ79BjzAFheKcajCroCKPZYscihb5t2tA6sy5FcU1Cy1HYoa/UgEH1kVIK23W4P5kAz FYNXld7oB1WysGr+ar7uoT69+7g+zG+DpvNHoMcb8liiP6ZBM1IJF2CE36IxbemhqiQR fafw==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=UdeEaFIW; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::631 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-ej1-x631.google.com (mail-ej1-x631.google.com. [2a00:1450:4864:20::631]) by gmr-mx.google.com with ESMTPS id 2adb3069b0e04-52ca27c60e5si142595e87.0.2024.06.15.12.20.21 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 15 Jun 2024 12:20:21 -0700 (PDT) Received-SPF: pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::631 as permitted sender) client-ip=2a00:1450:4864:20::631; Received: by mail-ej1-x631.google.com with SMTP id a640c23a62f3a-a6f1cf00b3aso502532066b.0 for ; Sat, 15 Jun 2024 12:20:21 -0700 (PDT) X-Received: by 2002:a17:906:d28a:b0:a62:49ae:cd7b with SMTP id a640c23a62f3a-a6f608a7977mr365800266b.24.1718479220536; Sat, 15 Jun 2024 12:20:20 -0700 (PDT) Received: from PC-2635.irisgmbh.local ([2a02:8108:96c0:76fc::80bb]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a6f56db61e0sm327283766b.49.2024.06.15.12.20.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 12:20:19 -0700 (PDT) From: Michael Glembotzki To: swupdate@googlegroups.com Cc: Michael Glembotzki Subject: [swupdate] [PATCH 09/21] mongoose: Replace deprecated mg_http_match_uri() with mg_match() Date: Sat, 15 Jun 2024 21:11:22 +0200 Message-ID: <20240615191941.40301-10-Michael.Glembotzki@iris-sensing.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> References: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> MIME-Version: 1.0 X-Original-Sender: m.glembo@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=UdeEaFIW; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::631 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , mongoose rev-id: a025577b30be2fe0a90358702b41b7d8e5afe69f Signed-off-by: Michael Glembotzki --- mongoose/mongoose_interface.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mongoose/mongoose_interface.c b/mongoose/mongoose_interface.c index b3ebc62f..ba2e8d35 100644 --- a/mongoose/mongoose_interface.c +++ b/mongoose/mongoose_interface.c @@ -692,7 +692,7 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) mg_http_send_digest_auth_request(nc, global_auth_domain); else if (mg_http_get_header(hm, "Sec-WebSocket-Key") != NULL) websocket_handler(nc, ev_data); - else if (mg_http_match_uri(hm, "/restart")) + else if (mg_match(hm->uri, mg_str("/restart"), NULL)) restart_handler(nc, ev_data); else mg_http_serve_dir(nc, ev_data, &s_http_server_opts); @@ -700,7 +700,7 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) struct mg_http_message hm; int hlen = mg_http_parse((char *) nc->recv.buf, nc->recv.len, &hm); if (hlen > 0) { - if (mg_http_match_uri(&hm, "/upload")) { + if (mg_match(hm.uri, mg_str("/upload"), NULL)) { if (!mg_http_is_authorized(&hm, global_auth_domain, global_auth_file)) { if (nc->pfn != NULL) mg_http_send_digest_auth_request(nc, global_auth_domain); From patchwork Sat Jun 15 19:11:23 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Glembotzki X-Patchwork-Id: 1948207 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=RTiuHIMQ; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=c7ffGdAl; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::23d; helo=mail-lj1-x23d.google.com; envelope-from=swupdate+bncbdy5juxlviebb6gsw6zqmgqezj6niwi@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-lj1-x23d.google.com (mail-lj1-x23d.google.com [IPv6:2a00:1450:4864:20::23d]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W1mFV65RBz20Pb for ; Sun, 16 Jun 2024 05:20:30 +1000 (AEST) Received: by mail-lj1-x23d.google.com with SMTP id 38308e7fff4ca-2eae96cecaesf23079491fa.2 for ; Sat, 15 Jun 2024 12:20:30 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718479227; cv=pass; d=google.com; s=arc-20160816; b=NV6x/NOqxJ1L0Hv7m/uZmOIKk1lDoWbuaTl3o5KGzyxIDvUGXnrj2SFkoYPVrkTsrQ 5C8C/XDfeJbSNg1BPJK8VNA4c45xX6DzqBNAzghvrjOyORQCIf+PwDCQjE/0e6mp7X5Z OXmS9zQun0mG42TCytUhmdj0Bj5kBQjxebnoWLcR+ubTr8G8OmgF2Mz8tnxZR4k1tvXV E1xAPTimcY0kED9v8qRhTlPbqSg+DKQFr/fMBpPt+EjRHQNiFpK155ytCwUwHbXWZePb JuVEDEEfp0vpUOV+C9FOtMZgb6mWhYXnVuvlZyLD+ZYla6xJUIH2uY3uZyb5wYvG2zxv 5o3A== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:dkim-signature :dkim-signature; bh=V2iei7lpjkzWZGt28WXkmTRCjZnI37pOyAfezDx3C+U=; fh=qmdIzz/HG626NjAeGVkxtadgTHnKMC2lb7CoBD8UDOs=; b=YDt+FrIK4D5TIkO2l4NJ6jPTIb7fv6+53u1AOr0Uz0rDD1BOhjLeGk13xa7uHQdguk G12qWKhN2esaTtO2TnnggL6p0zqTxHOcM9MFFZMgubeha5BFoyWCwqBHcxOpR6mPSemj WvupUYOeFMmvk2bfhkH6lzmy4RjQToMEmne+cqO83mFuaG3JYltinpMrEgxTfZf3N9W8 dyPWYHMmbvuWchMRAiOkHI/3u1nOvM9Rn9C1ixMu8c/h8AKPSmCrXOtSw8itbwMlR3Ad P2zvfqJ1ClHT9NbW4Ty1PTwMPg60heWzeaLuSPanp76avXWeY4NlE8PB1tR0GrZqYOOX nEuQ==; darn=patchwork.ozlabs.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=Y2ZEdeul; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::535 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1718479227; x=1719084027; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:sender:from:to:cc:subject:date:message-id :reply-to; bh=V2iei7lpjkzWZGt28WXkmTRCjZnI37pOyAfezDx3C+U=; b=RTiuHIMQX0WZx1BSA0dUjLnytdHHIw3K/kASNUMxfjIgyj77E6LFbsIN6LS14esBcE p2Jpcg7Rc9eF776iW6bzxvDuozoF8ZMJ10NP+OetntqRWLBrgtyydPkVpjHQJVRrAImM DDu1RgVmXFmpnADP7o7Phxk4iN1JdO+IbQCRgCeQITnac9XJVaxwfrmK5cUK+dN68tuV feV/88DAvI73crfcZ2iz5PBAnYczUDC7K4Kx44mxS7Fc5jNu72+TGyaEpmCDc7j3fGT8 R45UhKs+iecjCmaAYfZQr/3KABHQk7GuTQFLmA/PqnVh6YLpmP+QNBRxI04sMlKmo1bv fX3w== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718479227; x=1719084027; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=V2iei7lpjkzWZGt28WXkmTRCjZnI37pOyAfezDx3C+U=; b=c7ffGdAlzyblMIedxVwCRyvEPYXr9Wd59wa4IwaAmlT6+CFpH9JUONW/uRbMWdNmii LYXoPbeMvWu/IKuLidz7N2Rvayxt1R26WUbIVWSNdbEL6BzBy2/I4t9MzoepchRQBCY8 y1z24BnePftFs8ybEmJlG7awRCjf0fRMcQLaJTBWwcQWu1hZzQIr0JRfM3/ChtIGSBui 25xTJAVDXJMZGzel2m1hPNnITYzBSV97xF+dAzbX/38py+zINyr1aPYVMPtr1jMvuFCM EbXt17ephk/fshDn5/65cZ8wq8JScFxq06gZyfDMyBnu7K46jr3iKLAUbFrc14AQmdq+ d0gw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718479227; x=1719084027; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :x-beenthere:x-gm-message-state:sender:from:to:cc:subject:date :message-id:reply-to; bh=V2iei7lpjkzWZGt28WXkmTRCjZnI37pOyAfezDx3C+U=; b=Cn0AUVmpVFsZ/PXRoDvygOQsSYCQCbVh9T03WkBR2xptrCJ3OFR1S07IOlP/rLnAN+ G119M0x0eSKNYZ5MfWOAaKU4SrmR/HzpNenJlpIThabxsSfJZRtdGKNTw+OYvtNIdYme Gh8/F5RvrE+8t4NgBJ38Ia77C32qo0XuwzBZW3jSjWy+6MXsihkf3C9KUjynPleDTWO4 OoEYlzPsSrwSQMlFhSflAI1aGw1h2GCk6Ug5Xh2mSNoxAFQ0IIj7FY8azGAwL0d0L4N9 Mi8fOObLOKHzkckYcrXrUBmphJ+PBZxBwUmx7O2kI4bmhm7/npkSTY86X4XGiavE0cn3 pt3Q== Sender: swupdate@googlegroups.com X-Forwarded-Encrypted: i=2; AJvYcCVlN8yVXZ9Y+aemfXhUNOAElbvzfRymi7fTG6bsYK/GqAK/EwtLlBUQ+tilYdj8pgbq9AgRfzhBnVD+fWLYl5cPvmyAFwoOSQL+rlwbQg== X-Gm-Message-State: AOJu0YzkfAgC3MBcH/wfLJpdUMJ3UUkwCBEVaRYeTtSM3Ze3TQZNFZzI 7zbOk3G499rn8i74aIWZp0fXXd4LQ9t/ZJ/qrC7+0ShSm6XqKxPz X-Google-Smtp-Source: AGHT+IHHBL1W2TLrEXREhV8o5W7YVESn6KViqCw5pV8LkOz0n72DMUkeDMRiO74DCIGAlClEwWj4aQ== X-Received: by 2002:a2e:8250:0:b0:2eb:ed3a:9c65 with SMTP id 38308e7fff4ca-2ec0e46e7aamr33375331fa.15.1718479225652; Sat, 15 Jun 2024 12:20:25 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a05:651c:1063:b0:2ec:1d51:6fb9 with SMTP id 38308e7fff4ca-2ec1d517022ls3580551fa.0.-pod-prod-02-eu; Sat, 15 Jun 2024 12:20:23 -0700 (PDT) X-Received: by 2002:a05:6512:31c4:b0:51e:11d5:bca5 with SMTP id 2adb3069b0e04-52ca6e909a0mr3697803e87.54.1718479222756; Sat, 15 Jun 2024 12:20:22 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1718479222; cv=none; d=google.com; s=arc-20160816; b=ICWhoI1MLyPBSimNhNLx2HN3EoYvU1ccaorRr99o7U2aZf3itxva4HMgLGaNRUdh1z sy2570ledVjEclP53ec6myw/Bn1+nRVAOEvgET33c7dDpZsbRrogzv5Hk626cJG8sqwj O2jOJ2BzRcuN12vz5IFtKj/5LIEkQ9GazaOu9TPT6GHBAoBNR8iGftkOzECRz91H2F2G T6qp2LtcvwiC2xLVW+Ulw+oY8uV6Kgn51izGriQ0eXXYiFyuclLkf/1odXfKweQJHVkp Y8lQtcWd0HbptzoY90J8E20LcgnFXsnEz8z7UsCR0ZfwwjEWeXrQSRlN8bobAXiAzUUa dKiA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=Rqi1aBWtKfLSLrWKKQbjtgFAhBl2m/7jzRTbFigsgTY=; fh=zydHuzCQWrku2OPQyZfraJZFcOpEXLQ/YBcu3QNiBd0=; b=vYge9UphnqR55jmi+wu2sP2rUnT9I62rcHzda1RV75+Xyn814sokW4duUwg/EC5P1O vMU6S83XCZXecCXJQA+ndCSvDhkRmBIQF5w7C0dLpr7GtBxNRy2zBiykgdhLlIG+p7bR 6iDZEZ8/0Kf9jFPpg+4lpEVRclBfVzR06lJzCzgSmqizcciS5NDQqwKWZHxgIZTU99Dz J+F3DM5yvXB/HhBkRAZyCr6VtJvuoT9oh16IXQDMj4XgWXKLUyGYurNA8VnSvOcIAKG3 gQ94StRaNoycPT0jiGrglJ8+N2ZufcljpVtTplJmYHDaH+tz/jJyGRRCWtiOC6orkzte 1abQ==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=Y2ZEdeul; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::535 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-ed1-x535.google.com (mail-ed1-x535.google.com. [2a00:1450:4864:20::535]) by gmr-mx.google.com with ESMTPS id 2adb3069b0e04-52ca282f5bdsi107646e87.6.2024.06.15.12.20.22 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 15 Jun 2024 12:20:22 -0700 (PDT) Received-SPF: pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::535 as permitted sender) client-ip=2a00:1450:4864:20::535; Received: by mail-ed1-x535.google.com with SMTP id 4fb4d7f45d1cf-57c73a3b3d7so3638172a12.1 for ; Sat, 15 Jun 2024 12:20:22 -0700 (PDT) X-Received: by 2002:a17:906:2c02:b0:a6f:24fe:f2a7 with SMTP id a640c23a62f3a-a6f60cf1dcbmr393138366b.10.1718479221618; Sat, 15 Jun 2024 12:20:21 -0700 (PDT) Received: from PC-2635.irisgmbh.local ([2a02:8108:96c0:76fc::80bb]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a6f56db61e0sm327283766b.49.2024.06.15.12.20.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 12:20:20 -0700 (PDT) From: Michael Glembotzki To: swupdate@googlegroups.com Cc: Michael Glembotzki Subject: [swupdate] [PATCH 10/21] mongoose: Replace deprecated mg_vcasecmp with mg_strcasecmp Date: Sat, 15 Jun 2024 21:11:23 +0200 Message-ID: <20240615191941.40301-11-Michael.Glembotzki@iris-sensing.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> References: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> MIME-Version: 1.0 X-Original-Sender: m.glembo@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=Y2ZEdeul; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::535 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , mongoose rev-id: b46bee0540c83c780ae9622ef18b9cc8a7b3ebab Signed-off-by: Michael Glembotzki --- mongoose/mongoose_interface.c | 2 +- mongoose/mongoose_multipart.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mongoose/mongoose_interface.c b/mongoose/mongoose_interface.c index ba2e8d35..66de0723 100644 --- a/mongoose/mongoose_interface.c +++ b/mongoose/mongoose_interface.c @@ -344,7 +344,7 @@ static void restart_handler(struct mg_connection *nc, void *ev_data) struct mg_http_message *hm = (struct mg_http_message *) ev_data; ipc_message msg = {}; - if(mg_vcasecmp(&hm->method, "POST") != 0) { + if(mg_strcasecmp(hm->method, mg_str("POST")) != 0) { mg_http_reply(nc, 405, "", "%s", "Method Not Allowed\n"); return; } diff --git a/mongoose/mongoose_multipart.c b/mongoose/mongoose_multipart.c index 265c02b9..29ec8a0b 100644 --- a/mongoose/mongoose_multipart.c +++ b/mongoose/mongoose_multipart.c @@ -336,7 +336,7 @@ void multipart_upload_handler(struct mg_connection *c, int ev, void *ev_data) } if (ev == MG_EV_READ) { - if(mg_vcasecmp(&hm->method, "POST") != 0) { + if(mg_strcasecmp(hm->method, mg_str("POST")) != 0) { mg_http_reply(c, 405, "", "%s", "Method Not Allowed\n"); c->is_draining = 1; return; From patchwork Sat Jun 15 19:11:24 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Glembotzki X-Patchwork-Id: 1948208 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=ou6Glhjq; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=iumeR98U; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::237; helo=mail-lj1-x237.google.com; envelope-from=swupdate+bncbdy5juxlviebb6wsw6zqmgqebidzfzy@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-lj1-x237.google.com (mail-lj1-x237.google.com [IPv6:2a00:1450:4864:20::237]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W1mFV6zTLz20ZB for ; Sun, 16 Jun 2024 05:20:30 +1000 (AEST) Received: by mail-lj1-x237.google.com with SMTP id 38308e7fff4ca-2ec1709d233sf12514651fa.3 for ; Sat, 15 Jun 2024 12:20:30 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718479228; cv=pass; d=google.com; s=arc-20160816; b=AQakTqBbAgDeTgKTIQOXhPVfZzahSyxoe1USxFw5GtW60+7gqYFd1+MlVItesZqtxP Lm092ROy3ulC3y6jm0Hp9ieyspCIllaPNNyabWvudwPtULBActMLYfiSREwI4EgLz3JM OPQGSMhl7a9HOwFm/n/dIu7pSZa/fjMJ9CVOhPHKgzenAd9+v+4VnVjQ4Ulw2FZ3oJwD TjGWUKKHbmqirk7NZOhvTeTlTiC0cP7ivOit86gqKb2LhGJOzt9a1cBpAYvlFG0xn2TR YmVTQwjMlt+8xBc2cCFicbm9FApXUPWts6pTu0s1jPec1AXazR+IXRFU/StZdnuAqQ8T TxvA== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:dkim-signature :dkim-signature; bh=l126ItX1TjL5FY2zoTPQkMPZ6SKbr4V2m6NCivN28dw=; fh=XIG8s2aAnBw/nuIb0b0/jdpHpH4pQ/kGJyfVzHwhHgw=; b=l19vOYi3IheDpamBqPogSLSIaGVMjjKdsq/neuqfko+Aexd7mprgUNzsShTzLaUI1Y J4J9ZTJOCwoXgmWmVgs2rXFOc18QmG1GPoqoptAGnqoqiK0s1TiHJ1xorsT/m5gKLMHT kmqGveicbLkkJb5YeWYF2CuwEzz4Mw98/V2wdlNqsfyOU3eOjrSG7esWbnGWfR/Gr/mA j9flr2OT/CdLmc7mk5IrdED4QaHHKzRUsfLsEUYIOMCSYAYCPHzdKte2yKMnlOuVzpP+ krLYEbKVgh1rCfNzq3xfX91xTN9u3uYlJz7rm/gRVyOYsGddPBtKaIhYH860gNbM71rZ qcSw==; darn=patchwork.ozlabs.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=JuVfFErK; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::630 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1718479228; x=1719084028; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:sender:from:to:cc:subject:date:message-id :reply-to; bh=l126ItX1TjL5FY2zoTPQkMPZ6SKbr4V2m6NCivN28dw=; b=ou6GlhjqU3IKkNwlpDrqvh+pdHnqrbhagcCwSAJ4iaR2dIhJNhKVhf1W0LmCmbB49k Y06LhbndifajjHWsEjo/SDdLaIUkIdv++1B/JxxVGGMVf3njKVO3WY0bX5C0qr3PsOq7 71tePg3BP+8tCL5469BUNsL+YpprTmo91FeD09VH1Ef02MNOjZ4wPcJN0UsoCF6jXGel V0M3SLTuffyfddm5cRgYoukeq5fefMyqT6U/6go+y/tLFjQV26Huqfg88Pj4lUVNE2QU RtkLEDMOoF2NSoCT6U5ORnt4/vxdRun8T3aygA11q6un5gCTQS3+8mu80agIS7g//D7M Mgfg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718479228; x=1719084028; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=l126ItX1TjL5FY2zoTPQkMPZ6SKbr4V2m6NCivN28dw=; b=iumeR98U3xPOgpb9OvxcfSWyINj/T3SBQ75lDji6uvEXdUHyWP28So4wdtKX2SQgDK C3vkVwKBSOqyLJJwNXS2cwEKGvEPROVRlulMdNX/ZwYiT5jL3bfHU+XyQ0rl7KUgMHi0 upjS1ss+2UqAQgUeR+S4nhNwmizqBcF1vFp83hX41VJH6g3IR6zHWLa4DJAIOUE3Fx/Y mRnNvikEJg1PPXHzmc0DloLyH03LaT1gBDIfbQgjYCu3Q8+ryOpR5SuC0+3kiJOWxOIH PdOl6zuCEymptYfmNIwB1drkGC5afdfHTgsXDfWed7Y/5V/kywXIEbcWwy8D2ysyd7+Z KP+g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718479228; x=1719084028; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :x-beenthere:x-gm-message-state:sender:from:to:cc:subject:date :message-id:reply-to; bh=l126ItX1TjL5FY2zoTPQkMPZ6SKbr4V2m6NCivN28dw=; b=A3gJTNQGWUjtKqFng6cqvFP07yNiYkfoBsXYfmQumb6J9Ig+OY9jWcydioBky2bzoJ qXrEc4FqWvyr34v9URnsJsmDRpsOyL72T2s0keGnIKYzOiiYVILs/OypYNSuA8xeXSGA tI48SgQPPqXjFVLiKZffQX9YtPext3bnwOZTXg6830ozuxXb4HBylY2R/M7t/3px22Bf 1tz+l+hvPCh0f8HTF4t9L5QOcvu9Yhx5fUHRZsBtj7uRKOz0wJAH9KuSWeJaqtPZNHF8 isVYhTJqXrfk74mHABbZo/qOdkpsFIudnqj7ErMdCGy2iPgbcrrueYejV2/cAtu6pnsU 5Jyg== Sender: swupdate@googlegroups.com X-Forwarded-Encrypted: i=2; AJvYcCWpE6Tbax0Sse5Pw+OGxZHnLH/4oi+p0olUfaQ3qiRRD97yWU1jUurBD574Oxa0WjxNkn9Y7HaXw7zfZCxVsK18iWHQ8Cq+TNewWgolNA== X-Gm-Message-State: AOJu0Yxz3MNazFpyZOkC8DwrdKqYluJ87RHofX17Jt5tnSYTlfb/9+zx Z9/ewwv9wMuOlQwAA8Vvp/QA70+eRDbDZQpIy4hExZnU6MFooKl9 X-Google-Smtp-Source: AGHT+IGemgOTohqrUmCa2KslAhmAHKVtJYw6Tz+hyz4lRvUcCy9lLEbYlXUmyxSxwgjxduTyeDgaNw== X-Received: by 2002:a2e:6e17:0:b0:2ec:199:8b0e with SMTP id 38308e7fff4ca-2ec0e5b5edemr40389831fa.8.1718479226876; Sat, 15 Jun 2024 12:20:26 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a05:651c:103c:b0:2ea:ea7c:240d with SMTP id 38308e7fff4ca-2ec0292eb66ls15745911fa.1.-pod-prod-06-eu; Sat, 15 Jun 2024 12:20:24 -0700 (PDT) X-Received: by 2002:a2e:3619:0:b0:2ec:1dfc:45bf with SMTP id 38308e7fff4ca-2ec1dfc46e6mr17228051fa.42.1718479223838; Sat, 15 Jun 2024 12:20:23 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1718479223; cv=none; d=google.com; s=arc-20160816; b=K1PAct0NB1yDS4cS5mFlqFMt7qIBrlCFZAnwMBVHVyARO+sEswAwc4H0adnlwl5jGK 05C/U01Vij4b5osdxoAnUYevnGnOWJuXihJHj7BKrbO3ruHrR/x4IxMMItd3PDINbaul 4vXgcDfp3rT+iqy1xlkh+l38pRQ2rQUrcJOyY0GSPG9+5n8VGvx8FX4+XKDVAzRWCgaE cmTN6A4F+mtdx+BN844amSAoFclWd7ibCrYoGYMzNlNwA+S82+k9u8xjG3JO7EqVCI4b AYWm5UgAjuoVz8z81oCCk+KoUgXgSQwEbsZjvkPI1InVa2eWM7rgRPmqgRRIGdKSY0pZ 87GA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=ccYwuPiN3c7I0a5+ZXVxtl9OOYdvruqvCLYDyGHh3fw=; fh=zydHuzCQWrku2OPQyZfraJZFcOpEXLQ/YBcu3QNiBd0=; b=STh896cKzLt8H/DMGUyDZHzukTIj3n/cn1UxEMX+8bRGuDVKOypc0GsiKl4hXdpuCk RI2w0M8NgkL4j0WhMTwcCcoVSdKJ4fjV9oJzrnJiLUqNEXZ8OCPxVPiZBBFQDOKTxlFC 5SJph7SwDoe4gsC/GTIq660wkmucTjOh/XWMdxy+PrUGpv9xDTN98cppU1AEp1xhcAyk 6OfYEw9LTaFLs8uqwGlAZvEodqq2Vn9/2qqfk+l3NP6N++3TBUNjevMapcSxPLfkSY9l 4x2P8pXUJNzN1tC47DPyRfOhsxE3s+Q9iQDD6VZJFAgdMWdE8dp5RJqLqk1xsdgVyvaN y44w==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=JuVfFErK; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::630 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-ej1-x630.google.com (mail-ej1-x630.google.com. [2a00:1450:4864:20::630]) by gmr-mx.google.com with ESMTPS id 38308e7fff4ca-2ec05cbb4desi960161fa.6.2024.06.15.12.20.23 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 15 Jun 2024 12:20:23 -0700 (PDT) Received-SPF: pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::630 as permitted sender) client-ip=2a00:1450:4864:20::630; Received: by mail-ej1-x630.google.com with SMTP id a640c23a62f3a-a6267778b3aso329363066b.3 for ; Sat, 15 Jun 2024 12:20:23 -0700 (PDT) X-Received: by 2002:a17:906:99d4:b0:a6f:64b0:1250 with SMTP id a640c23a62f3a-a6f64b01749mr347024466b.35.1718479222785; Sat, 15 Jun 2024 12:20:22 -0700 (PDT) Received: from PC-2635.irisgmbh.local ([2a02:8108:96c0:76fc::80bb]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a6f56db61e0sm327283766b.49.2024.06.15.12.20.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 12:20:21 -0700 (PDT) From: Michael Glembotzki To: swupdate@googlegroups.com Cc: Michael Glembotzki Subject: [swupdate] [PATCH 11/21] mongoose: Replace deprecated struct mg_str::ptr with struct mg_str::buf Date: Sat, 15 Jun 2024 21:11:24 +0200 Message-ID: <20240615191941.40301-12-Michael.Glembotzki@iris-sensing.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> References: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> MIME-Version: 1.0 X-Original-Sender: m.glembo@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=JuVfFErK; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::630 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , .. and fix removed constness. mongoose rev-id: b46bee0540c83c780ae9622ef18b9cc8a7b3ebab Signed-off-by: Michael Glembotzki --- mongoose/mongoose_interface.c | 16 ++++++++-------- mongoose/mongoose_multipart.c | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/mongoose/mongoose_interface.c b/mongoose/mongoose_interface.c index 66de0723..21b2bf9c 100644 --- a/mongoose/mongoose_interface.c +++ b/mongoose/mongoose_interface.c @@ -190,9 +190,9 @@ static void mg_mkmd5resp(struct mg_str method, struct mg_str uri, struct mg_str static const char colon[] = ":"; static const size_t one = 1; char ha2[33]; - cs_md5(ha2, method.ptr, method.len, colon, one, uri.ptr, uri.len, NULL); - cs_md5(resp, ha1.ptr, ha1.len, colon, one, nonce.ptr, nonce.len, colon, one, nc.ptr, - nc.len, colon, one, cnonce.ptr, cnonce.len, colon, one, qop.ptr, qop.len, + cs_md5(ha2, method.buf, method.len, colon, one, uri.buf, uri.len, NULL); + cs_md5(resp, ha1.buf, ha1.len, colon, one, nonce.buf, nonce.len, colon, one, nc.buf, + nc.len, colon, one, cnonce.buf, cnonce.len, colon, one, qop.buf, qop.len, colon, one, ha2, sizeof(ha2) - 1, NULL); } @@ -212,7 +212,7 @@ static double mg_time(void) static int mg_check_nonce(struct mg_str nonce) { unsigned long now = (unsigned long) mg_time(); - unsigned long val = (unsigned long) strtoul(nonce.ptr, NULL, 16); + unsigned long val = (unsigned long) strtoul(nonce.buf, NULL, 16); return (now >= val) && (now - val < 60 * 60); } @@ -236,7 +236,7 @@ static int mg_check_digest_auth(struct mg_str method, struct mg_str uri, mg_vcmp(&auth_domain, f_domain) == 0) { /* Username and domain matched, check the password */ mg_mkmd5resp(method, uri, mg_str_s(f_ha1), nonce, nc, cnonce, qop, exp_resp); - return mg_ncasecmp(response.ptr, exp_resp, strlen(exp_resp)) == 0; + return mg_ncasecmp(response.buf, exp_resp, strlen(exp_resp)) == 0; } } @@ -268,7 +268,7 @@ static int mg_http_check_digest_auth(struct mg_http_message *hm, struct mg_str a return mg_check_digest_auth( hm->method, mg_str_n( - hm->uri.ptr, + hm->uri.buf, hm->uri.len + (hm->query.len ? hm->query.len + 1 : 0)), username, cnonce, response, qop, nc, nonce, auth_domain, fp); } @@ -585,7 +585,7 @@ static void upload_handler(struct mg_connection *nc, int ev, void *ev_data) struct swupdate_request req; swupdate_prepare_req(&req); req.len = mp->len; - strncpy(req.info, mp->part.filename.ptr, sizeof(req.info) - 1); + strncpy(req.info, mp->part.filename.buf, sizeof(req.info) - 1); req.source = SOURCE_WEBSERVER; fus->fd = ipc_inst_start_ext(&req, sizeof(req)); if (fus->fd < 0) { @@ -620,7 +620,7 @@ static void upload_handler(struct mg_connection *nc, int ev, void *ev_data) if (!fus) break; - written = write(fus->fd, (char *) mp->part.body.ptr, mp->part.body.len); + written = write(fus->fd, (char *) mp->part.body.buf, mp->part.body.len); /* * IPC seems to block, wait for a while */ diff --git a/mongoose/mongoose_multipart.c b/mongoose/mongoose_multipart.c index 29ec8a0b..6db59aff 100644 --- a/mongoose/mongoose_multipart.c +++ b/mongoose/mongoose_multipart.c @@ -42,9 +42,9 @@ struct mg_http_multipart_stream { static void mg_http_free_proto_data_mp_stream( struct mg_http_multipart_stream *mp) { - free((void *) mp->boundary.ptr); - free((void *) mp->part.name.ptr); - free((void *) mp->part.filename.ptr); + free((void *) mp->boundary.buf); + free((void *) mp->part.name.buf); + free((void *) mp->part.filename.buf); memset(mp, 0, sizeof(*mp)); } @@ -76,7 +76,7 @@ static void mg_http_multipart_begin(struct mg_connection *c, } /* Content-type should start with "multipart" */ - if (ct->len < 9 || strncmp(ct->ptr, "multipart", 9) != 0) { + if (ct->len < 9 || strncmp(ct->buf, "multipart", 9) != 0) { return; } @@ -108,7 +108,7 @@ static void mg_http_multipart_begin(struct mg_connection *c, } mp_stream->state = MPS_BEGIN; mp_stream->boundary = mg_strdup(boundary); - mp_stream->part.name.ptr = mp_stream->part.filename.ptr = NULL; + mp_stream->part.name.buf = mp_stream->part.filename.buf = NULL; mp_stream->part.name.len = mp_stream->part.filename.len = 0; mp_stream->len = hm->body.len; c->pfn_data = mp_stream; @@ -128,7 +128,7 @@ static size_t mg_http_multipart_call_handler(struct mg_connection *c, int ev, mp.part.name = mp_stream->part.name; mp.part.filename = mp_stream->part.filename; mp.user_data = mp_stream->user_data; - mp.part.body.ptr = data; + mp.part.body.buf = (char*) data; mp.part.body.len = data_len; mp.num_data_consumed = data_len; mp.len = mp_stream->len; @@ -207,7 +207,7 @@ static int mg_http_multipart_process_boundary(struct mg_connection *c) { sizeof(CONTENT_DISPOSITION) - 1) == 0) { struct mg_str header; - header.ptr = block_begin + sizeof(CONTENT_DISPOSITION) - 1; + header.buf = (char*) (block_begin + sizeof(CONTENT_DISPOSITION) - 1); header.len = line_len - sizeof(CONTENT_DISPOSITION) - 1; mp_stream->part.name = mg_strdup(mg_http_get_header_var(header, mg_str_n("name", 4))); @@ -342,7 +342,7 @@ void multipart_upload_handler(struct mg_connection *c, int ev, void *ev_data) return; } s = mg_http_get_header(hm, "Content-Type"); - if (s != NULL && s->len >= 9 && strncmp(s->ptr, "multipart", 9) == 0) { + if (s != NULL && s->len >= 9 && strncmp(s->buf, "multipart", 9) == 0) { /* New request - new proto data */ c->data[0] = 'M'; From patchwork Sat Jun 15 19:11:25 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Glembotzki X-Patchwork-Id: 1948209 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=Jmy/ZRKx; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=PiK6jPVs; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::33b; helo=mail-wm1-x33b.google.com; envelope-from=swupdate+bncbdy5juxlviebb6wsw6zqmgqebidzfzy@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-wm1-x33b.google.com (mail-wm1-x33b.google.com [IPv6:2a00:1450:4864:20::33b]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W1mFW4T12z20fR for ; Sun, 16 Jun 2024 05:20:31 +1000 (AEST) Received: by mail-wm1-x33b.google.com with SMTP id 5b1f17b1804b1-42120e033e2sf18034095e9.0 for ; Sat, 15 Jun 2024 12:20:31 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718479228; cv=pass; d=google.com; s=arc-20160816; b=0mxZe1dutTBEwmkB/4LFeMQC6P+NTDj/09io7X+p02r9+VpaWCpHtjbINOEYJei40r Cb1N26W/YY+ZjMSNxjgPbo6KFswWZlsjo35m5CEuFdK61+iYjLdLHRcuhd/G7zlOazww 7+besxGj549Cz6/x912LtSoBw8ZQHl0XpZa+qDGLV6Yinu7Om2CpO0KBJhPK/vbZpxnY ElWgqkbCVXcBO6FPyfsvuQLNBhiq3PlidZZdtgYoDaSqfpACBW23MC8BvWhRoQwaHGXx +mkLXvdwwFHQjtcIDHRJLCwgmjns/pNX3qBKCg4xEZ2PfyN76pvEzt9q+vwKL/5rL4OD v3iQ== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:dkim-signature :dkim-signature; bh=kVMmoUQB7vf4A11gjZLnZSm1zDqM9FJ3ZCGKsCoveYY=; fh=9BvmdHxfmtgWhlPPswO4wNBjZYjGQVms35Ii3qtQH4I=; b=cdkXrG74+4u9YhHYpI7YZyFkkKjPqhrEjOoNM9r8+QUwvccYdCrAL0BYWMznKAe2ex swaKwHIvwHWgVFGxt8KW3tw7a+CR6ZCLHswWbA1H8ZSRbzYQkQ7pjbz20gO2PuZO6A6/ JasCpQ+5dsvD+gAcSvOrns41FOoIL+MxDTFhGJ7Qa9miWR7a3gkXr5HpsjXy7tG45Atj hrIrkINkWLSTd89MyQr2RTgYCQVPztVPXKb0jmlhOMEFLoHxtVLi/WrEWYLVfCrr7O5D qsfyeKIC6+mXZup2rMCvmuAgL8wj+sX6SSHAa5LElj6QbEmRos4Jr8oIRl/S2ooxIUHM cv8w==; darn=patchwork.ozlabs.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=BLQ86GrD; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::630 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1718479228; x=1719084028; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:sender:from:to:cc:subject:date:message-id :reply-to; bh=kVMmoUQB7vf4A11gjZLnZSm1zDqM9FJ3ZCGKsCoveYY=; b=Jmy/ZRKxqxMoxzL+ZzLQvku4X94boAsmDUZ7K3ST3Yl29AeE4JfIV1ST1/x1WV92cr efWlj+q37Yh3RA+osFLW0ygBVc+Ff1oLjrchTCGxkNotkhgXv5jaL8oSaXiRja3LcQ4N xaEE+UVgDtcId0p+ex2e++LAL7JQy8HLx3GwPO6CJpU1jyn1LaG5Z2kBGKt2DWlILoMF KzAKY+Uejjz1ta1ML+qIzYtpjnOru/5A5POzGFZZsoyRv7XrfNWylDkxoUYdpHoJuwsJ OqfzDosnW99u8FcAwktPOP0ROwtgO+YIsKfQmCLGMoy9nBCCpfytfCHOy55kQcaSSDDo OGOA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718479228; x=1719084028; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=kVMmoUQB7vf4A11gjZLnZSm1zDqM9FJ3ZCGKsCoveYY=; b=PiK6jPVsRr19OmLAWRkaASFwSTrp6MW2V7ARfrfJ5LnRtRq3AHB42QO7tRombFnbYx nrxVE9uIZpbHyUu2CsYbmoq8L/kwjbbBkqhtLR10uhbpLGN/89Bm1nMSf//D2iiTyXS4 /5QCD2vRztVMmtK84BkGFmzzoimMIZzYH1n+Mg4srtwZHLqCCcYIzMd6vJ5uEvQls0VW aUvzP3wwR8ar/qYzVNXkHlfcXJ/D1NElNoyGYOYwKsN4zDTAsLJtzXlRtyRPKnb9DwyR BVxRT7pXfn3wyT6OeFKMNyP2BksC6vDNZkn+f6MNOie0Zudwkpazhkw6nfARfB3rZnGX OW6A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718479228; x=1719084028; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :x-beenthere:x-gm-message-state:sender:from:to:cc:subject:date :message-id:reply-to; bh=kVMmoUQB7vf4A11gjZLnZSm1zDqM9FJ3ZCGKsCoveYY=; b=dNe8WBMG2wJFVLjB2ITQZZP7UkOjPhIld8i3NZu48fGpRjqVSEJJ86YXw+rdWHtMVS 8j0Zgd94CuLt3SM/uR3qJ1fnjD2i8s/2G/Qf2U8wvB1DXN5PokfcT0H1zXeV/MZ3vsxp +wS+JS32RLet7+K/MTRlNN0h5SpkRBHqYlyaKiyhz9Hq3+q7cUJuRgiL5xRcqbnCkAPJ Es1F8rWuSC5hyi+JF3N6GDkMQrSk3ns6NTNeUTAJvXfyFJYhKGm7rucRRDSce49PfZTN GGds4+CEOFnztfYHr6lKkcwEGTbgJgrXfuMpCpnWNn2A8R9jFKVIBBFMRmFBLvLmI48L CO+g== Sender: swupdate@googlegroups.com X-Forwarded-Encrypted: i=2; AJvYcCW03cZEFvc1/LVsiu7kDWFkNccpC16iSmBYPcjYZZQuOqLHGiNcnW4s6RSKpS8J+R2vRlZubTyvO+vxz1Yb92NyUgu5Qfu2YPJayO5XZA== X-Gm-Message-State: AOJu0Yzy/uLsvc+k7hXaraTfDhUOiOmgMSxMir5yQI4VWMG5BVf618L4 cDqU0BiN1ETZWi0LVRj3cwY6W0GTFGuqo8ZxVfl2VbvpCHkL6Et+ X-Google-Smtp-Source: AGHT+IEWkxOB5YPnrUCKWs4lm9nBg7Jjw/o+KOPCWuE94p5zuofav8lt4X6Vnet9/0VIc1k5yzX6mg== X-Received: by 2002:a05:600c:3b1f:b0:421:bf9f:a163 with SMTP id 5b1f17b1804b1-42305f8ccf3mr50537085e9.4.1718479227296; Sat, 15 Jun 2024 12:20:27 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a05:600c:1c97:b0:421:7f30:7cf9 with SMTP id 5b1f17b1804b1-422b8da9b51ls11970445e9.2.-pod-prod-08-eu; Sat, 15 Jun 2024 12:20:25 -0700 (PDT) X-Received: by 2002:a05:600c:4383:b0:41b:60ae:7827 with SMTP id 5b1f17b1804b1-42304828ed3mr45847805e9.24.1718479224762; Sat, 15 Jun 2024 12:20:24 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1718479224; cv=none; d=google.com; s=arc-20160816; b=QBCOykBtvTOZADE51zw3/jzcAjrOcOfuq7Ieh33HFmbKnTyYiDT4FonFJ0aju1t+gU bZzNUoB/y0FU8EHVFsEs1A9euiy8iarFAYlWCe1fdEhxG4E3cU5H3KHCkL52ywImL7Ev 4ECGqbNufMO5gOtyEDM0OrkKfPANRHSTx1PHJvNmbqUktzt3gQ/Ut0QSFSATgoY4vQHG ZRhbyheVZzyDnYwUgooOAqHeM7m4+mq6nr+IzMUEwrRdQr41CELHVvH3ErZ55kPujzuX cq4V0HbJ16aAazziHnIxJpDqtafSrqTLDSifFdpgZsr59vH4DLtHy2GFQDVHsoqG+cFu UEvw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=zURJ9QNvjX7Gbs+fvJD5WocbwFFZc8zLGKoNuGuj2Ow=; fh=zydHuzCQWrku2OPQyZfraJZFcOpEXLQ/YBcu3QNiBd0=; b=Cf2GrgGZSLeXpzJLnhJB2sNZfoI780R9vwDamU1OTiAUM5epOnQUP6PhPeauWoAzRb MXzo/J4SmN9D13N4Gh6PFaIFHMX8NtIJAkHLz+MG6KmvK9vJ8ufYWGTf2IO6coNGqehz JB+Xx0tZFZBfK9F1tv6H/cfSIMAAiuCVVAIcBhBhLo77Fk7cENAl4mJRetSl0XES3zPu Qx2PzV5WoTPTgQPKvRVe83C1L0eb/H+mOAMi22+/qs+w9vVH7lSdkbshJ6HiWxbTDr3b FKEyDKni0x7VhJQXw6kF/LNrJgI0hTWx0U/gWYVjIWH1NT3vL2Xb/17rFP00IZc4jzH+ Eiiw==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=BLQ86GrD; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::630 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-ej1-x630.google.com (mail-ej1-x630.google.com. [2a00:1450:4864:20::630]) by gmr-mx.google.com with ESMTPS id 5b1f17b1804b1-42284b090dfsi6260155e9.0.2024.06.15.12.20.24 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 15 Jun 2024 12:20:24 -0700 (PDT) Received-SPF: pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::630 as permitted sender) client-ip=2a00:1450:4864:20::630; Received: by mail-ej1-x630.google.com with SMTP id a640c23a62f3a-a6f04afcce1so410979266b.2 for ; Sat, 15 Jun 2024 12:20:24 -0700 (PDT) X-Received: by 2002:a17:907:a096:b0:a6f:796d:c741 with SMTP id a640c23a62f3a-a6f796dc83cmr141013466b.10.1718479224043; Sat, 15 Jun 2024 12:20:24 -0700 (PDT) Received: from PC-2635.irisgmbh.local ([2a02:8108:96c0:76fc::80bb]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a6f56db61e0sm327283766b.49.2024.06.15.12.20.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 12:20:23 -0700 (PDT) From: Michael Glembotzki To: swupdate@googlegroups.com Cc: Michael Glembotzki Subject: [swupdate] [PATCH 12/21] mongoose: Replace deprecated static mg_ncasecmp() with strncmp() Date: Sat, 15 Jun 2024 21:11:25 +0200 Message-ID: <20240615191941.40301-13-Michael.Glembotzki@iris-sensing.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> References: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> MIME-Version: 1.0 X-Original-Sender: m.glembo@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=BLQ86GrD; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::630 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , mongoose rev-id: b46bee0540c83c780ae9622ef18b9cc8a7b3ebab Signed-off-by: Michael Glembotzki --- mongoose/mongoose_interface.c | 2 +- mongoose/mongoose_multipart.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mongoose/mongoose_interface.c b/mongoose/mongoose_interface.c index 21b2bf9c..5a4e98fd 100644 --- a/mongoose/mongoose_interface.c +++ b/mongoose/mongoose_interface.c @@ -236,7 +236,7 @@ static int mg_check_digest_auth(struct mg_str method, struct mg_str uri, mg_vcmp(&auth_domain, f_domain) == 0) { /* Username and domain matched, check the password */ mg_mkmd5resp(method, uri, mg_str_s(f_ha1), nonce, nc, cnonce, qop, exp_resp); - return mg_ncasecmp(response.buf, exp_resp, strlen(exp_resp)) == 0; + return strncmp(response.buf, exp_resp, strlen(exp_resp)) == 0; } } diff --git a/mongoose/mongoose_multipart.c b/mongoose/mongoose_multipart.c index 6db59aff..b60de2e1 100644 --- a/mongoose/mongoose_multipart.c +++ b/mongoose/mongoose_multipart.c @@ -203,7 +203,7 @@ static int mg_http_multipart_process_boundary(struct mg_connection *c) { (line_len = mg_get_line_len(block_begin, data_size)) != 0) { mp_stream->len -= (line_len + 2); if (line_len > sizeof(CONTENT_DISPOSITION) && - mg_ncasecmp(block_begin, CONTENT_DISPOSITION, + strncmp(block_begin, CONTENT_DISPOSITION, sizeof(CONTENT_DISPOSITION) - 1) == 0) { struct mg_str header; @@ -219,7 +219,7 @@ static int mg_http_multipart_process_boundary(struct mg_connection *c) { continue; } - if (line_len == 2 && mg_ncasecmp(block_begin, "\r\n", 2) == 0) { + if (line_len == 2 && strncmp(block_begin, "\r\n", 2) == 0) { if (mp_stream->processing_part != 0) { mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_END, NULL, 0); } From patchwork Sat Jun 15 19:11:26 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Glembotzki X-Patchwork-Id: 1948210 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=QsaX3xlE; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=AHGjhfwr; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::23d; helo=mail-lj1-x23d.google.com; envelope-from=swupdate+bncbdy5juxlviebb7gsw6zqmgqer6qf3aa@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-lj1-x23d.google.com (mail-lj1-x23d.google.com [IPv6:2a00:1450:4864:20::23d]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W1mFX5CRGz20Pb for ; Sun, 16 Jun 2024 05:20:32 +1000 (AEST) Received: by mail-lj1-x23d.google.com with SMTP id 38308e7fff4ca-2ec266e43b4sf2271051fa.2 for ; Sat, 15 Jun 2024 12:20:32 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718479230; cv=pass; d=google.com; s=arc-20160816; b=m0CWDVHcUmn9wRRI+Kan0gIEVb7/oJuZZB20OdFVc2Ix7OccvrbxSj4xtjz/aoF7e0 c63bGtetmLYItoVtZ8I8h0zorJ5mnM2i1x8+i2SC2oU/BbF1rU8LM067apPswJOqmg3g aIbVcKySTmxV6bgkmYhPxSTqOeqyeD6jdJd+YjXn9qd+k0eaOLkfDu8cpYIQZS5R9P0R wsWuiWwFu9jKCkhEMnzwTAc86nLXGVgKgAIGMNiIYyMakPmm+Xqcsdey+/gq5VjpyqbD WdTBLB+uZxSP8eB8v+iP8JHaZnWEC0k4tG0NxNnPdCqslNQmg7Lq9LQ2oSq8w2nVjPTo JCjA== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:dkim-signature :dkim-signature; bh=UPnfVBecTqzTQPC6zfPxx6SLCenJlrerkMLGX7xcUjM=; fh=gXXC2Dvlt8/Z7WWtMozJfmH5zdBOpHNdgSd19dyC6ac=; b=Pm4bDMJwewvwFRSb08ESls4vRVdEf17uOKGJxgHlCCxrGrfWQE2015ZtstbQAyWAcb F4dH6IzmZM31t7NCpowTrqGETjEXctPPQPdFMHw9b0IfBRyZl5Z3iTVkoZgY/tR5G63z S9xUoz30NunvQ/tJl8smndRDUKmeaUKuCFw4CMM6PN7pjIBN4hnN/8KrFl6bHTf5u2fo PFmKgxR5sCalsQdo/+XjLBLbNzf4BI5j29B17nvcg/eYEMTuV+vKp3RWwDZCV0vAKN1p JMt3nyHAs5vRJip2KRy93FlEydZDuXlk557CbQD9nBMPWAHC9FdE3e/JY+jDhpcpR+tR bRvA==; darn=patchwork.ozlabs.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b="VuX//eu2"; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::132 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1718479230; x=1719084030; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:sender:from:to:cc:subject:date:message-id :reply-to; bh=UPnfVBecTqzTQPC6zfPxx6SLCenJlrerkMLGX7xcUjM=; b=QsaX3xlEvj9eJg/7uJkvEs1TZ0K/ZV/ECM+W1QJL1EpUZEmKTz9qLpXJHKLuIUNEov 60zCHAvhdHx9Iefz9MEP4pFBPkYOKpcGUA2kNTd1cMYsoPHdahcBbIi+IjOaGQfKHmdN ZUrzHQqX5AE+a/7P/6SmLgfc0ERLoEmPUkVs5jCkpxrIEyoUx0Vaw0MLiHyffWh72aB7 k+LcYRXsnggvI/2VMYXaOAAYju9VD0r116BUlNtEDWII7qps/mH7I3UdKITdCaOagcaY e8ttUYsv0QVAXYTGwitA/NJChJl8BCtWmBRLjAh0hzUcJZxUqduJRcaj5KLO5eJlay6T oGUg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718479230; x=1719084030; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=UPnfVBecTqzTQPC6zfPxx6SLCenJlrerkMLGX7xcUjM=; b=AHGjhfwr0E4wT04Lwc4nOzDXDjcEAD7OcO0JvETHY03oykDvIx1TjHXnkNT05ZZ50j 6ImG/Ew1tKoOQUDOBUtlbOC/+0xjKS2y1l9QWqvG9xb3fK31BZkPF/WUBm+IcP7+qUJn iCkMlXp0HBYTuJCSY62Bm2bEFmAnUucxRzzz5IfD3A6vLv8JxSJDakGwdJ6EamA6SOcf MIpLV+Sp1TYsRCxERfV+pD7y8+6jI26nKUwma8qb19JCe9DhIxZLu9EMB5b2cylPguyf uHQAbtwQ+J97eKjR3lrO/cSiWNzfATDq41tn8wM2SgL52JuGmVR+j8/iXQeWJrks+krq FkWg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718479230; x=1719084030; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :x-beenthere:x-gm-message-state:sender:from:to:cc:subject:date :message-id:reply-to; bh=UPnfVBecTqzTQPC6zfPxx6SLCenJlrerkMLGX7xcUjM=; b=tkhjNHm5vPOMC+EzWMBdCHeiw7AaMtheZezMXyp58PeM76xY31IS5oz7pFAonq9LpV /iw/RnRyMok2i7L1WB9m8P8TczMOqoMituZA3ysm7vFzffWR49Fqy9oZSFussxl4UEnR Y5e3wXCnwl6kM4s0zaOdsojlxGsn+7bBd1+UxRzpmdzb3W/T3tlvaiCEXgTTDYkXlcPq iGPMjm+dG51ORAwpQfZ0TkNiXSFIq6rsdRdgB5fkVdVl5SQ6H0X0rHe3DIk7PX67yOIT +9za2j4F1FBmyQ0RhjiMSrCBwUY3LTvUk/4ZCLsEHxX8OI/0FFLg9eGkJLVwxfKEbqUi OjCw== Sender: swupdate@googlegroups.com X-Forwarded-Encrypted: i=2; AJvYcCXc14Wdu5CGll4AOMVWn8QS+TvlO1BzQd7W/k3Y04kQngVieAa+YxDJ3uqAbn5aX0JXfoTi/4feSKnDKPFLd4BRfymSnb26Ptxy/ECVNw== X-Gm-Message-State: AOJu0Yw+MDu038R3hby/C+Ae1xBNY7+bPyIDGwDcaFCWhv4bXwwPIUHo LZdKMKkEyaEZnm1Ef1Ngp66UWFyvAWcKFnH9k0B1IWRav/9JfwBG X-Google-Smtp-Source: AGHT+IFV8notuY+JMw7qbhmj9mqjP03sRvMzvNTmOpnj76VnMc1fki0ARxat99LGJhKn8mqLWrwZxg== X-Received: by 2002:a2e:3814:0:b0:2ec:2283:38f6 with SMTP id 38308e7fff4ca-2ec228339ddmr13792871fa.40.1718479228806; Sat, 15 Jun 2024 12:20:28 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a2e:9983:0:b0:2ec:38f:e74a with SMTP id 38308e7fff4ca-2ec038fe82bls14787171fa.2.-pod-prod-08-eu; Sat, 15 Jun 2024 12:20:26 -0700 (PDT) X-Received: by 2002:a2e:9894:0:b0:2eb:e865:494c with SMTP id 38308e7fff4ca-2ec0e5d1179mr50674791fa.26.1718479225919; Sat, 15 Jun 2024 12:20:25 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1718479225; cv=none; d=google.com; s=arc-20160816; b=bT/agwStNS6p9tN3lorYvX/x3HAEsxAUK9pRfoJTxIu9Ro+hNMFndVvuX6MSYuOMvA PJeTuQ5i1zJuojzPxPQx2G8dYzpQDvb7jz8MDjpn/78Dqkwpdg/5RqeLmOzMppkyRnK0 9C+uhxvITJu+hF8fAT/ACfF90xb03HXiS3D/sQpm0WzMmtt7t413iovnJAuQiXqPj2lc jwTasLL2vWQIzUYM0IP03HCJbIdZ2Bp1pHsgtdwrGNwomrMjLJQzNO1qYVjseCmJTYL/ N+BTebPZRAgfzu0bACQS1XRc4FfFCAX7RGQob7eHPS0ELyYtMbokSO49evjNS9ESizik dqpg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=bblelc7tG+Z+Y1bRmKhgm04cBRL5ebAwqzKl0ZH2/to=; fh=zydHuzCQWrku2OPQyZfraJZFcOpEXLQ/YBcu3QNiBd0=; b=Q/Y21RTMz6F1SjkFgF7RSP7GVsOrSxT5osT/IqUeZjY+lWqoa1lN6NUHkBBloDWqcj R4CfSLjh39Az6IVo7S9vq8HZ18xzyTceLs98J/kpcancb5tpo8WSzXuFTXqBq4B/Bp9P 3/IY8ilmKZ8DS+/w3HQXT6H17qtOSkEOZPrGQNrBg14a8PyvS5t+BaHvu31BbjZJa81m DobxFRB+kwrOMuJQZ+EA1sg/2xu/8+1Rl3ncG3AHntFN1GNFLU3X3D52BN75VN8fEmvy ySoJCtlbnWZzu5BF2RPtioVn+FrLIQBDfE2MCb4V8MSC/hNxwlgVvGNFq5n8G7pSc/eC fDyw==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b="VuX//eu2"; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::132 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-lf1-x132.google.com (mail-lf1-x132.google.com. [2a00:1450:4864:20::132]) by gmr-mx.google.com with ESMTPS id 38308e7fff4ca-2ec05c27b5csi1340041fa.1.2024.06.15.12.20.25 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 15 Jun 2024 12:20:25 -0700 (PDT) Received-SPF: pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::132 as permitted sender) client-ip=2a00:1450:4864:20::132; Received: by mail-lf1-x132.google.com with SMTP id 2adb3069b0e04-52bbdc237f0so3737301e87.0 for ; Sat, 15 Jun 2024 12:20:25 -0700 (PDT) X-Received: by 2002:ac2:5e3a:0:b0:52c:885a:f17 with SMTP id 2adb3069b0e04-52ca6e6dc5emr4035603e87.31.1718479225108; Sat, 15 Jun 2024 12:20:25 -0700 (PDT) Received: from PC-2635.irisgmbh.local ([2a02:8108:96c0:76fc::80bb]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a6f56db61e0sm327283766b.49.2024.06.15.12.20.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 12:20:24 -0700 (PDT) From: Michael Glembotzki To: swupdate@googlegroups.com Cc: Michael Glembotzki Subject: [swupdate] [PATCH 13/21] mongoose: Replace deprecated mg_vcmp() with mg_strcmp() Date: Sat, 15 Jun 2024 21:11:26 +0200 Message-ID: <20240615191941.40301-14-Michael.Glembotzki@iris-sensing.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> References: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> MIME-Version: 1.0 X-Original-Sender: m.glembo@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b="VuX//eu2"; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::132 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , mongoose rev-id: b46bee0540c83c780ae9622ef18b9cc8a7b3ebab Signed-off-by: Michael Glembotzki --- mongoose/mongoose_interface.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mongoose/mongoose_interface.c b/mongoose/mongoose_interface.c index 5a4e98fd..f0c58524 100644 --- a/mongoose/mongoose_interface.c +++ b/mongoose/mongoose_interface.c @@ -232,8 +232,8 @@ static int mg_check_digest_auth(struct mg_str method, struct mg_str uri, */ while (fgets(buf, sizeof(buf), fp) != NULL) { if (sscanf(buf, "%[^:]:%[^:]:%s", f_user, f_domain, f_ha1) == 3 && - mg_vcmp(&username, f_user) == 0 && - mg_vcmp(&auth_domain, f_domain) == 0) { + mg_strcmp(username, mg_str(f_user)) == 0 && + mg_strcmp(auth_domain, mg_str(f_domain)) == 0) { /* Username and domain matched, check the password */ mg_mkmd5resp(method, uri, mg_str_s(f_ha1), nonce, nc, cnonce, qop, exp_resp); return strncmp(response.buf, exp_resp, strlen(exp_resp)) == 0; From patchwork Sat Jun 15 19:11:27 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Glembotzki X-Patchwork-Id: 1948212 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=rn8eyJix; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=NvhhZbFW; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::239; helo=mail-lj1-x239.google.com; envelope-from=swupdate+bncbdy5juxlviebb7osw6zqmgqesosmppq@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-lj1-x239.google.com (mail-lj1-x239.google.com [IPv6:2a00:1450:4864:20::239]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W1mFb1WwHz20ZB for ; Sun, 16 Jun 2024 05:20:35 +1000 (AEST) Received: by mail-lj1-x239.google.com with SMTP id 38308e7fff4ca-2ebeef33f21sf25585271fa.2 for ; Sat, 15 Jun 2024 12:20:34 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718479231; cv=pass; d=google.com; s=arc-20160816; b=rJGmE3LvIO1f1rVuIYfJd7UNQqXsMQ7KVkYHmiwis4vdPaOvpr2oEnva5Mg4p2uxJN rh/OyPC3fPZ0ZfviozXw/B7Vr+mwDYwthT9qM2AWyQF4KCH9HmNKsSrsXGkzFxv/e7l3 1Xy5hHF73D0PHl5sKJrlcTGh1WcUm3Mt0QZCZTo12B2ySNhKn0/L6zOZpSpK3DIoLhhU dhgVGOwYfnxPllp5aUmQ4O+OipUn9cf9O/aEwTvT9cuY4DrlmHXMCX5e5jDYKwS1aIkX ltmnEol26fspPBTI9er6h2Zf9UnvF1MCpUhCgykklcBe7alPIjpsFZPR9orutFwb20yJ NUuw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:dkim-signature :dkim-signature; bh=sW+OaeRPdZ2X9t5lZC+HPMhLHRtz+g5Y8DaSy35oe9U=; fh=pF+QqsbfBPfzB719j1vmCb2p6mMyELjdf8u+CBAaxjI=; b=R+pvOtREYKiuQHOY1AQaxL2TkLv6J1Xr/IuXx/J0KSbJUiK8tCE31oXz5X1bm5n7X3 DFFh1XTc/+J1n4GhZbFX0Mp1PS427OaqVZvemyNtMd8a3xdvt0Bwby9XxgQv4fMxI0OV Rf8xZXz8zreNcvlRbHh9oT8/DF7Yupt9MbaWrnFc4hrDlOHYQRc0MaV0wFO42YaS3leB +3lj2AtD0e8NvejiuDs/m205iaL/+Hlx1fU2pgvDIMWeFc/VS+WBva9dcV4Gcm3144iG vNI9udHziyB0pXUnjexWiFalVZH9g7yeRwDL7dryZ3bg6quqcW2EIu5XvIuQw4zcYaLw M5mQ==; darn=patchwork.ozlabs.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=a71M64c6; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::12e as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1718479231; x=1719084031; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:sender:from:to:cc:subject:date:message-id :reply-to; bh=sW+OaeRPdZ2X9t5lZC+HPMhLHRtz+g5Y8DaSy35oe9U=; b=rn8eyJixY0iB02J2xUclFbLjp60sVwUEgi0S19SscKnua/OwlWvsoDERvF6t6zt9Wc C2lMK6kmtH38cATMZmtydThuy8V3yATwWpJ21Vf8aP5W86XJkW9W0fAG8HzszS+eSJwe iWoo6CNwQBsJGwkf5+P3gi2mVio863Gx2TMIFuHa0FFI3oUH35cNYERlovB1z8PFiE7F mPLvBMSPXm0SKhA40a2KsF9ky7SNgFy3ZIhtm6gjXUkpZLq6AUrQC/zYB9X+OSeTuS0o hF4YEsbPkAGLQzZoOMNj/MLyLyvp0WAhTHdyrsOqsdNT/RU7pVlGnp71olCP85iBLduU TUow== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718479231; x=1719084031; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=sW+OaeRPdZ2X9t5lZC+HPMhLHRtz+g5Y8DaSy35oe9U=; b=NvhhZbFW5Em120dsG6YxdRSvqLstMQCKOimJCP11MM/Wft7kNAxXeBu25EAdyjF83G FHMYTL13kgR9TgKjPk6u/Qrw+as+kSekTo3N602uIxH2jjIgidzq5EmKCkIkHMhaq5vO LH7g/UG0rp7twcFCCDSg6YLjrUqQM+0sfhmChIr5yO3u4q8zyZRY7UsRK94jcyJiHcGD f6jiNjwR0CXre7CpAR40tr+QyIYHvDfGFaa4tjlQZMGd5cEbQX/I/QWpAydOdVAg2cqe dqczmYzqacAJnktAO2tUeyBl+TprK093K5fLTFPia2vQKZDnlL3vpdTm9mHRHz98wwrl Amtw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718479231; x=1719084031; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :x-beenthere:x-gm-message-state:sender:from:to:cc:subject:date :message-id:reply-to; bh=sW+OaeRPdZ2X9t5lZC+HPMhLHRtz+g5Y8DaSy35oe9U=; b=MC9T4EbB2a/D5xG3bnOgD61qDL68UoRkEqmQpyhl3eawCZjUCihdZdEuN2mtgGrggM a3/vsrQgfsp++J3wF3po+IaJpa46Ldq21kWW4pAZqnlIaqIevo4K6hYi/DxydA6cFX6C fzIGpXbsAwhE1kMBXZkJX9ymQ5vp00NTWYTus7LUsqyTTeDzHXTyILW+Apyca2EaOA73 HaxFeh0IGWsXpk2jCaAkMx60tCOgQ4KUbG2bfIyJYfPs5lRhLquxIMAn3xe6l65a+9rT +J2aZAj7iu/ri/QlODPtDXHEZ8O7RSho18nHrcE+HYYLfRfmuKJvtK6LTdLekMmSoJgU encg== Sender: swupdate@googlegroups.com X-Forwarded-Encrypted: i=2; AJvYcCWA1BTJf0yjxVcv4zJ3tIVZZt5rVmkPglLa0lDrgTy7DPyi3tdLgNPqX3O+6u/03U9w6Ow9ZFi5bjDjP8wd9K4+ce1Y1DHmolJKMUdClg== X-Gm-Message-State: AOJu0YwU83byY1E7oPMZMiCh8EE1Y0N1mFu719vKBeEKoXeUc05YCQSh U+LeFq0f2Qy8dMzV/jUZAlPNnTF4BC7lbqk4hHZRZRldTnZstm+N X-Google-Smtp-Source: AGHT+IHmlMeypTs9uLejMmBsNuo+WFSNMz3A5PdgHmtxhJuESLzxdjvslMfhTH3vpOmMQ6BLilNaUw== X-Received: by 2002:a2e:be05:0:b0:2ec:eee:f19b with SMTP id 38308e7fff4ca-2ec0eeef79fmr53723971fa.40.1718479230080; Sat, 15 Jun 2024 12:20:30 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a2e:b8c4:0:b0:2eb:dd8c:a60e with SMTP id 38308e7fff4ca-2ec02930badls21255771fa.1.-pod-prod-05-eu; Sat, 15 Jun 2024 12:20:27 -0700 (PDT) X-Received: by 2002:a05:651c:547:b0:2ec:f8a:6f0f with SMTP id 38308e7fff4ca-2ec0f8a6fdbmr56139651fa.4.1718479227031; Sat, 15 Jun 2024 12:20:27 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1718479227; cv=none; d=google.com; s=arc-20160816; b=H2B+4HkrfwfowwigfSXGUzicXUJcWJ0VY0IjAwaR7Ccbctxn22jBrLf1t4ni4SInUE z3S2iooaG35XZDoBSwuGKTHlCKSCUqeo00wRSrpTC1XQZcB+ygw7u3MiSqScfyRCIrY6 so8sF4deDRdV57IxYkuoNRNCfBR5EO/2xnG569BAR58Iycp7En7VE/ZVvrjU/G+dNoF4 YxRXGJFD9WyW7hk62f+t6YAmxWn8DdJ+vkVXqx7YihKL9iM4ZyvRhUPokrTbSxk5cy27 3pImRMFha8dBcUHmOpYKbCvPtiIhpIE2OyanUyj8xeQS8MV/VPqyXNx5u+WNbnSuaM52 BUtw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=azrxuQTB3AVqlSZi+TM9qwRPWFf7Bf8bzvrTgz5baqc=; fh=zydHuzCQWrku2OPQyZfraJZFcOpEXLQ/YBcu3QNiBd0=; b=DEoKozhSjGgg7ri0y3K7buTVNe8z3TPE6/V8PHDAlk2qPCnUg5z4kt27FKp+rN4CPT oAweNtqa+S3eXxCujiwd6oZsFK6Ttw/8t/P0/Jld/VXnSIaqNsiIVj81TdJb0pzJsWKj hDcjHl38bTIJcARb/hlTuPBzjdgoQrfA84LUYdOPeBtbWHWALebTxjIQhWC5MEi1ZIjX zGoTcg32UWQLiDe7IYw+iKt7QfRO+5aMMkSXwz6AOQ8Q2kDNgPQDE3GglR5VzleZerL0 LaxsAhNNS1Gssz0OiRefoKsjhJGQT0RKJSC9RzXTMkZCbSkweTDiVvKSx6gOaSVkKYXU xnEw==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=a71M64c6; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::12e as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-lf1-x12e.google.com (mail-lf1-x12e.google.com. [2a00:1450:4864:20::12e]) by gmr-mx.google.com with ESMTPS id 38308e7fff4ca-2ec0599b1ebsi1320341fa.0.2024.06.15.12.20.27 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 15 Jun 2024 12:20:27 -0700 (PDT) Received-SPF: pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::12e as permitted sender) client-ip=2a00:1450:4864:20::12e; Received: by mail-lf1-x12e.google.com with SMTP id 2adb3069b0e04-52bc29c79fdso4522518e87.1 for ; Sat, 15 Jun 2024 12:20:27 -0700 (PDT) X-Received: by 2002:ac2:420a:0:b0:52b:bf92:bcd with SMTP id 2adb3069b0e04-52ca6e67674mr4382073e87.22.1718479226182; Sat, 15 Jun 2024 12:20:26 -0700 (PDT) Received: from PC-2635.irisgmbh.local ([2a02:8108:96c0:76fc::80bb]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a6f56db61e0sm327283766b.49.2024.06.15.12.20.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 12:20:25 -0700 (PDT) From: Michael Glembotzki To: swupdate@googlegroups.com Cc: Michael Glembotzki Subject: [swupdate] [PATCH 14/21] mongoose: Replace deprecated mg_hex() Date: Sat, 15 Jun 2024 21:11:27 +0200 Message-ID: <20240615191941.40301-15-Michael.Glembotzki@iris-sensing.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> References: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> MIME-Version: 1.0 X-Original-Sender: m.glembo@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=a71M64c6; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::12e as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , mongoose rev-id: b46bee0540c83c780ae9622ef18b9cc8a7b3ebab Signed-off-by: Michael Glembotzki --- mongoose/mongoose_interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongoose/mongoose_interface.c b/mongoose/mongoose_interface.c index f0c58524..4f189cd3 100644 --- a/mongoose/mongoose_interface.c +++ b/mongoose/mongoose_interface.c @@ -180,7 +180,7 @@ static void cs_md5(char buf[33], ...) va_end(ap); mg_hash_md5_v(num_msgs, msgs, msg_lens, hash); - mg_hex(hash, sizeof(hash), buf); + mg_snprintf(buf, 33, "%M", mg_print_hex, sizeof(hash), hash); } static void mg_mkmd5resp(struct mg_str method, struct mg_str uri, struct mg_str ha1, From patchwork Sat Jun 15 19:11:28 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Glembotzki X-Patchwork-Id: 1948211 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=D/Jupu/I; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=YQ1Wnj7b; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::537; helo=mail-ed1-x537.google.com; envelope-from=swupdate+bncbdy5juxlviebb7wsw6zqmgqe6qw6yqa@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-ed1-x537.google.com (mail-ed1-x537.google.com [IPv6:2a00:1450:4864:20::537]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W1mFZ6C7Mz20Pb for ; Sun, 16 Jun 2024 05:20:34 +1000 (AEST) Received: by mail-ed1-x537.google.com with SMTP id 4fb4d7f45d1cf-57a460247f3sf1905011a12.3 for ; Sat, 15 Jun 2024 12:20:34 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718479232; cv=pass; d=google.com; s=arc-20160816; b=UosdWAT1/T9kPQF922Db4Js6hn1TbMXhZ5i+7yYKG+8drP7AbRWF9c4vADX1I7Esq1 rY+kJCttCjV60cXUFCfG1YAa1eYAtLQ6JdWDxbgMiGX3xo/9g8Qhra7DLowJulErJPzb /kWsbEXSxaEuWSyndS0AiPOpVpGtiqxmF/44vlfbBaVOD8n/0QXjCP95GHLBdRa430DE VVeXuT0NVBamHw2Cu1eeugdyGfhkv8YfUswz3SCacXO7ssvDd7jdp/XOgxFxog4EFqI4 1ozRJFIAdt1nwEzy6mPdbm59rVc2CUq/SnI28N+LA7sBzMUTwHVX8kT8M9rROhJDC5fY Ngcg== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:dkim-signature :dkim-signature; bh=X8jDADxhnXraBCkPgTWHcyYNdsmTj9y571povC9X4mE=; fh=Be9aZ8udEJj0yoDfOoouQmfhfgoUyK/sJ5OQ6RC6CpE=; b=nAXw2YKwCVOFtcbCMQBeGIDF7R0WNs5LfEZckrLKr4JdKoHr+8K1v3tWkezi4o9a+I dekFRn1n5+bUkRsXCUevP29KVpsPfh2hBYcOaLDuiSXx43wX1RRmiZwnfxuip1Rg8Qnn OwFx1YDzaAAuEivRgv7VQ37Wi8x3kWGrG4Yfn3XF/D5/MgPk+udf5RwwSk9SXZoawd9a mYZmXsYhXUQ1fqerkI1osrBaB9qXMQOLmMdhKrgQRc74f6g5HmItiTn1NKdvlZGosSDM o5jalLu/W5dzYL+vLpBPvXvjoOJkZrZ2DaN9/p4mbwCsbmkKZbg4KM6F2xJxWkArifqo 3eTA==; darn=patchwork.ozlabs.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b="DHr/6+6l"; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::62a as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1718479232; x=1719084032; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:sender:from:to:cc:subject:date:message-id :reply-to; bh=X8jDADxhnXraBCkPgTWHcyYNdsmTj9y571povC9X4mE=; b=D/Jupu/IDOOs6gRQXAe9n4WXXAJG7wF7JwPdjcolxZVXQ4ILsLL0vYbrIzawf1RztC IbHrJuNW0zbEgIQcsYVddhLfBDWm/fPzeJJN+TbHVK3gbqbqIUR1onOWU7JNwhKPMXU+ QQAZPbj04rBJdRK1eNnUtNtVfwAJa8ixvemUTqZ5M/VK5WZuyhqO+SOQXrTtnGyPigmS gXazZI90M7TA5iDdpqrznZFXgCuiH+cYpUCZ61IGFFI6d6qHBoGoDs8IhpR1bcFPXW31 SuwlpTPBIt18ViADC3VsIv4Kp4haUvF+a8KoRugPBxLemHhsBGTL+lJRb/VmXebmknEf DG0g== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718479232; x=1719084032; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=X8jDADxhnXraBCkPgTWHcyYNdsmTj9y571povC9X4mE=; b=YQ1Wnj7bT72ULr0Cjxy6vROHPnAy/qXeZN6TQ3MQYiuXpNG50kbFaGr7hscsIxNE3l CzQX0e6LRNYS1vPjUeJ2UtpjokillKRietpeBVzVSpps4oKw7txZAFXyUL1ZY6WCRsqF sMkCbFHxaY5PILb/2+O3AdY8CKeYUxflferWPjdAxchIu58cGl0gpQ7UUd3DEa10b6re F/81oVPBRWFrakAQsFlQrDpNw0VDGNGjnZxkqDpHL+RmBNEvwgtjqYPGEGdj2dIhvD8W yZyKNulqfIpLRcVCnlXyO4bKYqQevwqU5af1vmsd5dyc1YJjq2BLCHE2l94TjyuTM/KA oYaQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718479232; x=1719084032; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :x-beenthere:x-gm-message-state:sender:from:to:cc:subject:date :message-id:reply-to; bh=X8jDADxhnXraBCkPgTWHcyYNdsmTj9y571povC9X4mE=; b=cJypzEuE76ojjvRsQgxfg9reaCdSlb30/g9h0oCqZ8A7PxkmUNUV9omG7427kTqmup KueYq12HyACTmvruXupIQQEdZu2V738vVcsat51qUaox+NqeztNC6F6gT96pEIXiRrFO ZYqQu0qAR8ma+aIsrUCFDsnqZTwn5EIocxsbcyoVnh/Wo3PY4DhEEc6xJZuE1njVC04I C1LDtISDT4pIgtYUzNE5Usx2z4VigTfSFgBcdu5Ttr0riW5O6R8O56KDRoMEGOYxEsuD yUszuOkBzrOcS+KjWyjdXHCHV5KkhD39HfZ17zTJ1T8QcnP58oIbxoHaBqq7Kk0QrpTP EKDg== Sender: swupdate@googlegroups.com X-Forwarded-Encrypted: i=2; AJvYcCVTvyREhg2P5d/q7vaHZmuj6F+9Eyw3BGf3dDwJ2rA6I9CTcytkL7a86M5wop0PKLvfpfg6BiXxRlpYnpoAt1D2SrKnbkQrrqehI2muMQ== X-Gm-Message-State: AOJu0YxlOajDFJTtLVT2HV/Mj/GWTfe8OKxfIVkTlbuimSwJbld/Wl1n JAExw4NfHpg5ZSMR7HO7+33C5VCxoFQnkZpO+WcpxUNz1uFQIlOx X-Google-Smtp-Source: AGHT+IE20ZH3fi5xAi31oQl1gILqyIryrfqWImLFtkZWbT567tz7PWCXItmgOQw39tUhHa2OlERSfw== X-Received: by 2002:a50:cd0e:0:b0:57c:6a02:31d with SMTP id 4fb4d7f45d1cf-57cbd8f2993mr3570907a12.33.1718479231246; Sat, 15 Jun 2024 12:20:31 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a05:6402:5106:b0:57c:b688:3d74 with SMTP id 4fb4d7f45d1cf-57cb6884529ls117852a12.0.-pod-prod-06-eu; Sat, 15 Jun 2024 12:20:28 -0700 (PDT) X-Received: by 2002:a50:c346:0:b0:578:f472:d9d5 with SMTP id 4fb4d7f45d1cf-57cbd906889mr3660210a12.37.1718479228273; Sat, 15 Jun 2024 12:20:28 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1718479228; cv=none; d=google.com; s=arc-20160816; b=ZL5nviHTqt/CpVYiXpY/C+doNcC5glNoxDFPjGYyXnqf+1ZlDTny78DmYh1q9VHLb+ 9XNTUauNdC9cIsgpzIeg8gUf9IGWBPYeAq/AgGUGbxcrnP0RtETO0Eha9rAoHgTyfdve WAvQDlyJoES8phi7FPwd0Y0OckfYSErlpnA+AF6Yb/ZwOLewvGeG/Pbmwkwp9MR+4asa kD96l6atCE6ZrkWCh1YGSkVM7Sx795sBwu4URbf2Ndu2gne11KW6I1JpD3nulD5E7NRA 6KUCNAggDIGptTdUYDT1BTsTSOqigmULZeDjPMsDxM9ZZQbywQ2VzutKujlntSCJtTDo /z/g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=p55tFtTtRKqVtDFqAeBNGklmUNX40EgBjah2a0FA340=; fh=zydHuzCQWrku2OPQyZfraJZFcOpEXLQ/YBcu3QNiBd0=; b=iZQlZ67ZX1JhxT8zA6/7PYBwk5PGpXm/GwOEgC+tnJm7FSnKjZlshbW7UvZDo8OjCs Oa49rCNIBYy/tnalGvwgcyhCXEAQGmc2vMUrID2xSaxnKTBYwuRXcnXZhc6jYVP0Bumk N+Dh39F8AaCiPrclnIjCqUxFqZHCptCLbbRG778xDMOYcIu9v+SMtgxLhuK+6R9TiAJZ tOevlKoeHBwov6z0lngMCgl04jIxNvboDji7J8+lsZrUpsZR8oBMlDzOMjx3UrJsu1R7 tFdRSDrnBAcJG3RNUGPmWANpTfF8AWgToMn9mlBNsw065Q+BhNI/OyPCd+6mJtr3SO3K 2tmA==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b="DHr/6+6l"; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::62a as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-ej1-x62a.google.com (mail-ej1-x62a.google.com. [2a00:1450:4864:20::62a]) by gmr-mx.google.com with ESMTPS id 4fb4d7f45d1cf-57cb743880asi111232a12.3.2024.06.15.12.20.28 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 15 Jun 2024 12:20:28 -0700 (PDT) Received-SPF: pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::62a as permitted sender) client-ip=2a00:1450:4864:20::62a; Received: by mail-ej1-x62a.google.com with SMTP id a640c23a62f3a-a6f177b78dcso423872666b.1 for ; Sat, 15 Jun 2024 12:20:28 -0700 (PDT) X-Received: by 2002:a17:906:6889:b0:a6f:1b3a:8898 with SMTP id a640c23a62f3a-a6f60cee45emr414363466b.2.1718479227489; Sat, 15 Jun 2024 12:20:27 -0700 (PDT) Received: from PC-2635.irisgmbh.local ([2a02:8108:96c0:76fc::80bb]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a6f56db61e0sm327283766b.49.2024.06.15.12.20.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 12:20:26 -0700 (PDT) From: Michael Glembotzki To: swupdate@googlegroups.com Cc: Michael Glembotzki Subject: [swupdate] [PATCH 15/21] mongoose: Makefile: Rename MG_ENABLE_SSL with MG_TLS Date: Sat, 15 Jun 2024 21:11:28 +0200 Message-ID: <20240615191941.40301-16-Michael.Glembotzki@iris-sensing.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> References: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> MIME-Version: 1.0 X-Original-Sender: m.glembo@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b="DHr/6+6l"; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::62a as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , Change was done with 7.0 Signed-off-by: Michael Glembotzki --- mongoose/Makefile | 10 ++++++---- mongoose/mongoose_interface.c | 22 +++++++++++----------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/mongoose/Makefile b/mongoose/Makefile index fc9d0e08..4017c55a 100644 --- a/mongoose/Makefile +++ b/mongoose/Makefile @@ -15,13 +15,15 @@ ifneq ($(CONFIG_MONGOOSEIPV6),) KBUILD_CFLAGS += -DMG_ENABLE_IPV6=1 endif ifneq ($(CONFIG_MONGOOSESSL),) -KBUILD_CFLAGS += -DMG_ENABLE_SSL=1 +ifeq ($(CONFIG_SSL_IMPL_OPENSSL),y) +KBUILD_CFLAGS += -DMG_TLS=2 endif -ifeq ($(CONFIG_SSL_IMPL_OPENSSL)$(CONFIG_SSL_IMPL_WOLFSSL),y) -KBUILD_CFLAGS += -DMG_ENABLE_OPENSSL=1 +ifeq ($(CONFIG_SSL_IMPL_WOLFSSL),y) +KBUILD_CFLAGS += -DMG_TLS=5 endif ifeq ($(CONFIG_SSL_IMPL_MBEDTLS),y) -KBUILD_CFLAGS += -DMG_ENABLE_MBEDTLS=1 +KBUILD_CFLAGS += -DMG_TLS=1 +endif endif endif endif diff --git a/mongoose/mongoose_interface.c b/mongoose/mongoose_interface.c index 4f189cd3..2fed8bcd 100644 --- a/mongoose/mongoose_interface.c +++ b/mongoose/mongoose_interface.c @@ -35,8 +35,8 @@ #include "mongoose_multipart.h" #include "util.h" -#ifndef MG_ENABLE_SSL -#define MG_ENABLE_SSL 0 +#ifndef MG_TLS +#define MG_TLS 0 #endif #define MG_PORT "8080" @@ -48,7 +48,7 @@ struct mongoose_options { char *port; char *global_auth_file; char *auth_domain; -#if MG_ENABLE_SSL +#if MG_TLS char *ssl_cert; char *ssl_key; #endif @@ -69,7 +69,7 @@ static unsigned int watchdog_conn = 0; static struct mg_http_serve_opts s_http_server_opts; const char *global_auth_domain; const char *global_auth_file; -#if MG_ENABLE_SSL +#if MG_TLS static bool ssl; static struct mg_tls_opts tls_opts; #endif @@ -719,7 +719,7 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) multipart_upload_handler(nc, ev, ev_data); if (nc->recv.len < MG_MAX_RECV_SIZE && ev == MG_EV_POLL) nc->is_full = false; -#if MG_ENABLE_SSL +#if MG_TLS } else if (ev == MG_EV_ACCEPT && ssl) { mg_tls_init(nc, &tls_opts); #endif @@ -747,7 +747,7 @@ static int mongoose_settings(void *elem, void __attribute__ ((__unused__)) *dat if (strlen(tmp)) { opts->port = strdup(tmp); } -#if MG_ENABLE_SSL +#if MG_TLS GET_FIELD_STRING_RESET(LIBCFG_PARSER, elem, "ssl_certificate", tmp); if (strlen(tmp)) { opts->ssl_cert = strdup(tmp); @@ -778,7 +778,7 @@ static int mongoose_settings(void *elem, void __attribute__ ((__unused__)) *dat static struct option long_options[] = { {"listing", no_argument, NULL, 'l'}, {"port", required_argument, NULL, 'p'}, -#if MG_ENABLE_SSL +#if MG_TLS {"ssl", no_argument, NULL, 's'}, {"ssl-cert", required_argument, NULL, 'C'}, {"ssl-key", required_argument, NULL, 'K'}, @@ -797,7 +797,7 @@ void mongoose_print_help(void) "\tmongoose arguments:\n" "\t -l, --listing : enable directory listing\n" "\t -p, --port : server port number (default: %s)\n" -#if MG_ENABLE_SSL +#if MG_TLS "\t -s, --ssl : enable ssl support\n" "\t -C, --ssl-cert : ssl certificate to present to clients\n" "\t -K, --ssl-key : key corresponding to the ssl certificate\n" @@ -818,7 +818,7 @@ int start_mongoose(const char *cfgfname, int argc, char *argv[]) char buf[50] = "\0"; int choice; -#if MG_ENABLE_SSL +#if MG_TLS ssl = false; #endif @@ -868,7 +868,7 @@ int start_mongoose(const char *cfgfname, int argc, char *argv[]) case 't': watchdog_conn = strtoul(optarg, NULL, 10); break; -#if MG_ENABLE_SSL +#if MG_TLS case 's': ssl = true; break; @@ -898,7 +898,7 @@ int start_mongoose(const char *cfgfname, int argc, char *argv[]) global_auth_file = opts.global_auth_file; global_auth_domain = opts.auth_domain; -#if MG_ENABLE_SSL +#if MG_TLS if (ssl) { tls_opts.cert = opts.ssl_cert; tls_opts.certkey = opts.ssl_key; From patchwork Sat Jun 15 19:11:29 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Glembotzki X-Patchwork-Id: 1948213 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=GnH3ilEx; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=BGdp/OKq; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::23e; helo=mail-lj1-x23e.google.com; envelope-from=swupdate+bncbdy5juxlviebb76sw6zqmgqew5gwqoi@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-lj1-x23e.google.com (mail-lj1-x23e.google.com [IPv6:2a00:1450:4864:20::23e]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W1mFc43K3z20Pb for ; Sun, 16 Jun 2024 05:20:36 +1000 (AEST) Received: by mail-lj1-x23e.google.com with SMTP id 38308e7fff4ca-2ebea49680fsf27876411fa.0 for ; Sat, 15 Jun 2024 12:20:36 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718479233; cv=pass; d=google.com; s=arc-20160816; b=OTMJwGAVtoqipb8vpAkeDkdUPiOmgNZJcQYws2l8ItNWA6fUkBiCQhlneV5/74reR/ y4/EZwxDdAMZmM39tp858VklawXhHhcx5aVgrZH40y8Vvckz5q9ETAX/SHDbHfOoYBEN MuZdBMnJUZ/tXHsWZGKkhnp3suteey77nEVe9aXsDVDULnRE3/SQ/gI0rk3Xmh55F7Ue l6miPBwq1J/uc1Zqbw6sRJ3evMYkzkkEE5sONkRn3qTXAe7RS5HO5cof8m/yazq2DtnW IS+lHzUpvgr0NDWmbXjpQSficks7hmf4iyzfHhcSSeBeau5noBp/ybwJvjU9F3Brm4as KC+g== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:dkim-signature :dkim-signature; bh=SbGbC50Jj3dVap6LgnZYBrqust/k+BVaI6Rt3pJyoCA=; fh=uddIR/VQ28a7SC6zx8sEhCcG/dLQLZQz1lT0P17dMGQ=; b=CcgaWWKH1RNF57C5e22ht/p6cTL1N88ToC+ub7JSNxtLj7yoayHG+Wvvw9iqEB8wUr Xl7qbg6eCxuuAcW7w2YWbb83jxxozprs/WIj8UeIk6ziMH8kfhhW0/xyVN7hykjlQDMS v0eaTE0V7tikQJ31awm2sF0nKS2ALFAWockGWqiZeKCLN4o8gqFF5KHazRgX/gLtwbLQ wtgG8movR2CfCKKKh+MH9RC6eEKssBwEL1rdeqs0eBjBQu1hPdoGoZHF/SQP+/MsR7/s AdqOZQDAL6WBwEQnfb1yEFbFohyZEpJ/zjSCW1V7jOvow1rGfY4Nr2CydCOF4VQF4SRz Xrng==; darn=patchwork.ozlabs.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=LTyszviz; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::635 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1718479233; x=1719084033; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:sender:from:to:cc:subject:date:message-id :reply-to; bh=SbGbC50Jj3dVap6LgnZYBrqust/k+BVaI6Rt3pJyoCA=; b=GnH3ilExAs9G0RMJT3PSEKDOuQt9GRGvh6FNaj/2zz/EdpDTT8AuI4M7FOt52MRF0/ 1je5DAi+uTuIeetbZUe+a7LLa2uX+7KnuXry4xr3czaaNEKKF1GSqceSx9msajwmen2i PLijwuwUUw0sFNMlpGvWkZ3qqS1sPuzVM/iphYlJ3vwOOJm22cPboMKrCFRTCCS0QZ5L Ot3qqkWsePUiAtBZvMo6t1/N9z/MYh3vA6sluHoPgm/tZ/Gx8v3nK+z8g0xHi3+ZEKDv K2sw0SH5MDzJx192fBlv6HxD15aLvjmsQNg35vQn1GfKbsZDTlzuLkm7/NRkJS4u1wUN FYKw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718479233; x=1719084033; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=SbGbC50Jj3dVap6LgnZYBrqust/k+BVaI6Rt3pJyoCA=; b=BGdp/OKq0kVL5vLRvWjc1YPgctpi549HEgyWy5C1HcXfgKaRo+0DmOa4ZVxs0qbVEK hHO8e96XQhhUCqlRdSJwiLgSo9Wy9n9BYQaGuSOsQiaSEdv1gOCrptx/CHoVlhX3Q0RD CBcJakLE4f0+r8U3mOLEjIVW1N2pdcPbNVIVZx20335e/yO+GgB8Cx4uQnD0g9edWMTV Jzos2QDYZfC+D8gKWzorNAjsxG3VzYnZPUxjLGKYjfadKboGFEnmm4WGxCu51bbYh32b neVWehg3LND7Nc0vYoIzYD6KoL/1YkEZsw1/EJPlOhLHEke4bSbTxW/1AqcrT9YgFZSE UrhA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718479233; x=1719084033; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :x-beenthere:x-gm-message-state:sender:from:to:cc:subject:date :message-id:reply-to; bh=SbGbC50Jj3dVap6LgnZYBrqust/k+BVaI6Rt3pJyoCA=; b=h1b8Id906g7ZfXteAx2wUuMJBeCxuldzUc+SNDR5G9XTnFTn6W4VeSbWSS7u2ex3Dh Ik/I7azCPLjboMyuvFLVSTbgE59q0IncvulwaFwtdmj7WSskmBxXEDiZZe9b6Giz4XgE X1tvlN9En7y1aVtmFD+QKZ8y/hfD44Lpa4VM9OiYOWA7Gwqo+D7Opi9sVSMFR10t1OjR J81J7osufpp44jXYDUgzBrsVXqwnnxUian+nr2Q0y77Fr/hY+XIvqSWc7Mk8nLiplnUs paIFkr5wUvy5/jyeKsO5lVBT+bzE8Csh7lTldENYKcbsuSz8Bv5GzSz21TI8SNjb10tD IehQ== Sender: swupdate@googlegroups.com X-Forwarded-Encrypted: i=2; AJvYcCVYF/tHMzmDy94LoEybLxavOPm6bY31BocZy3eEwNaS1sNUxEfwtq9wlUtpJLiw03cdBtOEHN5p5v7itCvdd/1FugeL4lbosKWL22LAxg== X-Gm-Message-State: AOJu0YwL23NcSoO5B1usZvjSAWSHCvPf5YDSfwZqsMVeXfgOQNwa5z04 oSa0tSkKzcX/2kZK+08HB/BSaiRGA14+5hBrRVwDqJJEKhX0ApEY X-Google-Smtp-Source: AGHT+IF8SU6TuJpkRY8F3ZPq0s73dAGLwgwX5JxhZBVBZ20xJispnkT3fvnSxzZC/2dItaKrkVpqQw== X-Received: by 2002:a2e:9cc8:0:b0:2ec:5e6:1c7b with SMTP id 38308e7fff4ca-2ec0e601063mr45342831fa.34.1718479232483; Sat, 15 Jun 2024 12:20:32 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a2e:9983:0:b0:2ec:38f:e74a with SMTP id 38308e7fff4ca-2ec038fe82bls14787341fa.2.-pod-prod-08-eu; Sat, 15 Jun 2024 12:20:30 -0700 (PDT) X-Received: by 2002:a2e:96d7:0:b0:2eb:f6bd:e4ec with SMTP id 38308e7fff4ca-2ec0e5d1350mr45510811fa.24.1718479229800; Sat, 15 Jun 2024 12:20:29 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1718479229; cv=none; d=google.com; s=arc-20160816; b=wYNs9Q336HaVbXEEJX7oYwYVKhrUR0NBIYFajFpk6GpErUmpnhp2UDWw2ZK+YTbNCv crGJURGHZdzDmH6IRNKf4vQlUVpYFINaUZQ5gCaGe9AS0J4X00TL5RP5BmPZ/s2oPOws NlYy48v/t9bQOV+x7QBNSQ0Fyaaa1q/WjPN7J1/ktZwo/uvzNf6VeHJTl7wcevcyiG05 3YERBM8dSNOJRdJdlzXZ3zuofPMsyi54B/ZHMoQO2g7ex4eoA7/KFnwpmrMC64MuVK30 QFPBxZtNkDo/eC8u+gfoV7L1K4u7dR+jC/SgJwlzVa7w0bTOytj3XZxpgw99F1nFOQ7N H8Lg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=HPas/96NmDx8v0Ni2XIEqS6rdlM16lnv0EayDEumtQQ=; fh=zydHuzCQWrku2OPQyZfraJZFcOpEXLQ/YBcu3QNiBd0=; b=Cuikw1YFUEC7XGCERNvdzr0310n+G8Uwo3yhiIzEOcGpcv2Yy3Ru8aF1NFuCnYPFo2 3zgdhe9gsvFHTFc8trrk+LXWnCpY9U9Gim4exrPIUGMAozEPqEkj93G/bAMrI+PYjiEf fDBZQk8ib+EXPI7V3uayPLYzxYtqnWljNWe39r88wbyzzKMwizWCeM2vfiWfYern8JWn Qx9N6yMuWcxF18o+qkKGLJDuaMIwNNfWm2CggM34ODT2L0PFtMU8xktqagNMxcrKqUpF tRfs34xq/6sQQ4Xx2hMErXddn0JJIiRWbhn8TU528u+ASbwkilsVNKq7CFSABMja8bA8 cmGw==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=LTyszviz; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::635 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-ej1-x635.google.com (mail-ej1-x635.google.com. [2a00:1450:4864:20::635]) by gmr-mx.google.com with ESMTPS id 38308e7fff4ca-2ec05c27b5csi1340071fa.1.2024.06.15.12.20.29 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 15 Jun 2024 12:20:29 -0700 (PDT) Received-SPF: pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::635 as permitted sender) client-ip=2a00:1450:4864:20::635; Received: by mail-ej1-x635.google.com with SMTP id a640c23a62f3a-a6f1da33826so464980366b.0 for ; Sat, 15 Jun 2024 12:20:29 -0700 (PDT) X-Received: by 2002:a17:906:b088:b0:a6e:5801:ed43 with SMTP id a640c23a62f3a-a6f60d38249mr477484666b.30.1718479228580; Sat, 15 Jun 2024 12:20:28 -0700 (PDT) Received: from PC-2635.irisgmbh.local ([2a02:8108:96c0:76fc::80bb]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a6f56db61e0sm327283766b.49.2024.06.15.12.20.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 12:20:27 -0700 (PDT) From: Michael Glembotzki To: swupdate@googlegroups.com Cc: Michael Glembotzki Subject: [swupdate] [PATCH 16/21] mongoose: Makefile: Rename MG_ENABLE_FILE with MG_ENABLE_POSIX_FS Date: Sat, 15 Jun 2024 21:11:29 +0200 Message-ID: <20240615191941.40301-17-Michael.Glembotzki@iris-sensing.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> References: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> MIME-Version: 1.0 X-Original-Sender: m.glembo@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=LTyszviz; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::635 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , mongoose rev-id: 7bec3b49542b2db3149e40297a932296f1c97afb Signed-off-by: Michael Glembotzki --- mongoose/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongoose/Makefile b/mongoose/Makefile index 4017c55a..2e2a5971 100644 --- a/mongoose/Makefile +++ b/mongoose/Makefile @@ -6,7 +6,7 @@ ifneq ($(CONFIG_WEBSERVER),) ifneq ($(CONFIG_MONGOOSE),) KBUILD_CFLAGS += -DMG_ENABLE_DIRLIST=1 KBUILD_CFLAGS += -DMG_ENABLE_EPOLL=1 -KBUILD_CFLAGS += -DMG_ENABLE_FILE=1 +KBUILD_CFLAGS += -DMG_ENABLE_POSIX_FS=1 KBUILD_CFLAGS += -DMG_ENABLE_LOG=0 KBUILD_CFLAGS += -DMG_ENABLE_MD5=1 KBUILD_CFLAGS += -DMG_ENABLE_THREADS=1 From patchwork Sat Jun 15 19:11:30 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Glembotzki X-Patchwork-Id: 1948216 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=CVqs5kPl; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=AfcIhlC5; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::23a; helo=mail-lj1-x23a.google.com; envelope-from=swupdate+bncbdy5juxlviebbagtw6zqmgqemeon67y@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-lj1-x23a.google.com (mail-lj1-x23a.google.com [IPv6:2a00:1450:4864:20::23a]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W1mFf10K1z20fR for ; Sun, 16 Jun 2024 05:20:37 +1000 (AEST) Received: by mail-lj1-x23a.google.com with SMTP id 38308e7fff4ca-2ebd982d244sf23409981fa.3 for ; Sat, 15 Jun 2024 12:20:37 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718479235; cv=pass; d=google.com; s=arc-20160816; b=FIiELWXvdN/VbxcKRrFmKozmlgK78kKFGyKsSc0k08y77vqNeP30Q7uaoVPaw3t5bW 8ihV5o0Wl7iJFZG0BtbyW9SHFmlzpYeE2V+EyG8JgozZ0ZQCno0S1for52HEb4k8XMqX Wl9HWC6mV/kd6F7sKdDuD4W4X5AVv1w373kl1CtrR66XQVtGCvOGsQl7f/5gu20+ppA0 3TvyWpPoRe+/DaSSZ1+aLrmkqcLsP+3uMksq3Mf/IKsydeb/EYu/WFljarQo33mtylCi f1/O9t8XCKqSPQD8Ldg2dOKDUTjiIxG4zj6Q/rMuh7J9zkqw2c/yAxGWt3lAadAfMVHa 7Kqg== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:dkim-signature :dkim-signature; bh=1lTmW+VVNaPUtAJX8u51C78n6spx0U3Q+XGtbfBEcOw=; fh=vFqtFKbiFhV1uMrs8m2it6YsN5c0QXSHPb8vikU4E28=; b=zgfjZnjPJRjv7bHQ3HpsMArvOn7noaSeCFyad8XP1tclDNzMXyhG9ThxU3wrreQGH2 9w+gL2EjuR4gGNREjJ6pLzUWeG3eWagjCmmaIacPXsHm9HYT89Z9B37kydWTCsAQCFmH ILqz8sApXXRn9PmA+QBYxp0WcxV7YYdoDgM5Q2A5MHN9i5uZl4FsM0cfofWJ8yB9PUvS GlAtPJre/gQ7lCWx5HM6PIzEMlmEgsnlkfWmq5sgIzbZAd2nkTHw/IXBVEYBFMWIpfKp Ijy0nuq2RPWvTxKbYXr9ARqIvwIZlkqi0FogxNXgx0U/zn0OwDOE9ZdkxpObxLnGR/f+ 9TFA==; darn=patchwork.ozlabs.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=gHlgrkvz; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::636 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1718479235; x=1719084035; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:sender:from:to:cc:subject:date:message-id :reply-to; bh=1lTmW+VVNaPUtAJX8u51C78n6spx0U3Q+XGtbfBEcOw=; b=CVqs5kPlWiCux2v7oBnxJNPSMTvrNBRJMvPt/77FuqZbr2nBUH5GITp2IRr8VxDwNZ V39m0NfWCgY0G+sNEfJAE+3psvHHS0WEQq715bbocTduf7FaK5fnP3PLwRa/AUZ6gkRt MZUhGoNz40CA7Vfg9HxI5YyXg5YuC8L2nFcuDod2RtThvPOUnbY6mDLSh3AreptVuUsJ U5jX2L788O5hZspdWfdWjy/Tz8fbidLr+ed7usDmpRbFY9wi5HeCyGCO4WAI2nj0lQ3X uKn6TicgiP1SUqefjztM1zwzCfQHLNVusnIegbkysORKPssUAbLenA521MLwQwZ5y/oO eNsA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718479235; x=1719084035; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=1lTmW+VVNaPUtAJX8u51C78n6spx0U3Q+XGtbfBEcOw=; b=AfcIhlC5KkcTo3QWOjJZWlxUL1TYcXfujUoAzslIZIR2M8ngMDtB0Xe4rWlILlNim4 CwpHhzeeK2I8uArixY2izL6IuoSYpnPqT+K50Pp/cjNxAx9Fn+Ns5lSdY4kvIlAYMM/N ZOhjKhv56JGUwKwWWfy/8ajArleFwpjr8VxzEY9LSXlC08PnO7BnXCU0gY9okHLzdFQh v6fa4EfUka4gI9DhjQISWVhTIxp8TepYpNqFapbtKeFeba+/bFJji6vJ/uwhMmBt8eo2 vxQDbxT5iMR6Xya82bhRHxx74kw3c+nIihV1R5TFTRNvke+HA9Qqh3QoEsn1i7FHkKEx PVog== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718479235; x=1719084035; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :x-beenthere:x-gm-message-state:sender:from:to:cc:subject:date :message-id:reply-to; bh=1lTmW+VVNaPUtAJX8u51C78n6spx0U3Q+XGtbfBEcOw=; b=ANYxgBgvuV7GadShwJXViFs0Qbe4qBUMvlelXXkXKmRIIHHu7YLU+dWK3jdu3fLkhN coLAKjQXtq7apALU13v+LooJ9za5ytCtm9eyAH/5meJOGshzjpAEv1CjbYkVi+MNfoGU qtpBCvOEPynQ02Ia9f8P+i8NELHQTAYDKY7SjxVYaEXnBgeXijR3POdFqiNLXwlhuu3n OX5HudaOnWJPf1U8bVXVFDrzB5Y9ITUUfxk8vzduYg76PmyON8mR+wGSluM7cEkrK7t4 4ePNMlOqu6Ruj1kR/xkIkLpjyjAr74BxcBiVZdqMAa/sHbFpbcKE7v9CSRXZx53DtYU8 GMkw== Sender: swupdate@googlegroups.com X-Forwarded-Encrypted: i=2; AJvYcCXWCEFLtYiQSxCkHrZjgABLj3RrheP+2kSKNTSWVI3VDmF4DWKq4H74KE8U9uyFruafuhCQtwSw3/goEVZsZEUveH26Qm6Wx1QrkLY2cw== X-Gm-Message-State: AOJu0YxS6VmSM2Yp1be3n0qzxVbjHFXmZPxSK2P8xhp1oPs7brhP2W60 jBrM3cGRtgrTkzkAKowYh43z9BKWfnCywawYVwJnBxhurwYYUgSZ X-Google-Smtp-Source: AGHT+IGAj7vdKUKjXFm447/vBihvuunOhDvzL9uGv+vDW43MVvTtZkUI9X+//u9PmzQRhwMheSkbGA== X-Received: by 2002:a2e:a601:0:b0:2ec:18e5:e68f with SMTP id 38308e7fff4ca-2ec18e5e82fmr30967851fa.33.1718479233812; Sat, 15 Jun 2024 12:20:33 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a2e:a608:0:b0:2ea:b32c:c86e with SMTP id 38308e7fff4ca-2ec02874af0ls1882021fa.0.-pod-prod-04-eu; Sat, 15 Jun 2024 12:20:30 -0700 (PDT) X-Received: by 2002:a19:6904:0:b0:52c:7fe8:6489 with SMTP id 2adb3069b0e04-52ca6e98eb2mr3385157e87.63.1718479230431; Sat, 15 Jun 2024 12:20:30 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1718479230; cv=none; d=google.com; s=arc-20160816; b=jBSf4RPhl8S0TNVa8RCa/Iapk9ggO+BoLJqa4FO9OIcXiOPRsneFZz+KgXb1byY0e/ goU0nD7xdXbEuRoLanKzLSBg3HBtg7m2/yy7kQ5OmKDXFkvtCCJJHz8UEC8BlEQHwrZN tRLzTN9e9DKdDs185NPFAR4tA1DXliPWpWJbiMldB7zbFZF4z6lr7REdmNoZlHi2JdDf o5A2ucpNgTwQcIhOCYTO5sGSVohRR+AzMtmupV4H5TLh+3p+nXoc6HZ9R8cCIGgud924 s3THvVOngp219yFj6LA8+mMIORe3oWEpHY+ydkUrRb1bufPtWAIRLL1wvZXcY5JdKaP8 dGMQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=sw5kiljrh2wtBk4SHpU01JYhHXoKjpNhxyS4fpImulw=; fh=zydHuzCQWrku2OPQyZfraJZFcOpEXLQ/YBcu3QNiBd0=; b=AVAlyRrBHHpqX1uI6uYUrTouc3O/7jxfczMd+tVD9HYTRJlYe52QCc49FPKcFHhlbf oAJ6ZL280ZAwwCU+ofMbI0gMSEyI7+rhVt9wTjFjRs3JaQchUmVdFBNEe/hLXAn1uhZV kzKJV4aj7CRJCCX6Hpj3nJYS7KWrv9wpvIDcpTvsKvtalvEZN3nzKLg9nu6uz5yvAL1k sWhxcoQ8IfMcyJbUQfo5WIh8L0zwuwu9L+DFzixCOaVQ1x4+0QkGHSOlg8YlZ4NaBJM7 uyMoyVKVkiuDpo8rwFOCHjYasH5E+i72yWH8QkC5I+7ypF48mgHrgpwsLAFu7b4yYFW9 lvtw==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=gHlgrkvz; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::636 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-ej1-x636.google.com (mail-ej1-x636.google.com. [2a00:1450:4864:20::636]) by gmr-mx.google.com with ESMTPS id 2adb3069b0e04-52ca282f0f1si119580e87.5.2024.06.15.12.20.30 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 15 Jun 2024 12:20:30 -0700 (PDT) Received-SPF: pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::636 as permitted sender) client-ip=2a00:1450:4864:20::636; Received: by mail-ej1-x636.google.com with SMTP id a640c23a62f3a-a6f1c4800easo408335166b.3 for ; Sat, 15 Jun 2024 12:20:30 -0700 (PDT) X-Received: by 2002:a17:906:308c:b0:a6f:33d6:2d4b with SMTP id a640c23a62f3a-a6f60de8311mr337778366b.75.1718479229287; Sat, 15 Jun 2024 12:20:29 -0700 (PDT) Received: from PC-2635.irisgmbh.local ([2a02:8108:96c0:76fc::80bb]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a6f56db61e0sm327283766b.49.2024.06.15.12.20.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 12:20:28 -0700 (PDT) From: Michael Glembotzki To: swupdate@googlegroups.com Cc: Michael Glembotzki Subject: [swupdate] [PATCH 17/21] mongoose: Makefile: Remove MG_ENABLE_THREADS Date: Sat, 15 Jun 2024 21:11:30 +0200 Message-ID: <20240615191941.40301-18-Michael.Glembotzki@iris-sensing.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> References: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> MIME-Version: 1.0 X-Original-Sender: m.glembo@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=gHlgrkvz; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::636 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , MG_ENABLE_THREADS was removed in 7.0. Signed-off-by: Michael Glembotzki --- mongoose/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/mongoose/Makefile b/mongoose/Makefile index 2e2a5971..5e0bf5c6 100644 --- a/mongoose/Makefile +++ b/mongoose/Makefile @@ -9,7 +9,6 @@ KBUILD_CFLAGS += -DMG_ENABLE_EPOLL=1 KBUILD_CFLAGS += -DMG_ENABLE_POSIX_FS=1 KBUILD_CFLAGS += -DMG_ENABLE_LOG=0 KBUILD_CFLAGS += -DMG_ENABLE_MD5=1 -KBUILD_CFLAGS += -DMG_ENABLE_THREADS=1 KBUILD_CFLAGS += -DMG_MAX_RECV_BUF_SIZE=262144 ifneq ($(CONFIG_MONGOOSEIPV6),) KBUILD_CFLAGS += -DMG_ENABLE_IPV6=1 From patchwork Sat Jun 15 19:11:31 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Glembotzki X-Patchwork-Id: 1948215 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=NcdZiQ4a; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=TzrrwPYs; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::239; helo=mail-lj1-x239.google.com; envelope-from=swupdate+bncbdy5juxlviebbaotw6zqmgqev6kh5bq@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-lj1-x239.google.com (mail-lj1-x239.google.com [IPv6:2a00:1450:4864:20::239]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W1mFd6jFSz20ZB for ; Sun, 16 Jun 2024 05:20:37 +1000 (AEST) Received: by mail-lj1-x239.google.com with SMTP id 38308e7fff4ca-2ec01fa1a72sf24330501fa.2 for ; Sat, 15 Jun 2024 12:20:37 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718479235; cv=pass; d=google.com; s=arc-20160816; b=ocl8iSdnxo5FG0XX6+bfLeHoHrMtsIW3gu5FnsSN7eV3pli/M+uwDfMNuhQI12dukd XOjo8Os/bdvE1gV5XwyGLuSnhV5Nv5KH74TjQqrnkBnt5NJlqaXOIYCLlPY9A+GsWAWi Z8RCLlE9RYMseq3fvG1JrK7zbLt4NJnM24GPZhT3cWf7ECbALbljZYJmwGUbEOd41MFK MrPNWsinGIIAMfAY1ZMDt6DBNRz7gnjwE7FrpebD+5mm9Q+wpAkcbLYUm6PNcFPvjnjI jYE+szDIjcjK8V/eV0cqQJ+zZlUs3fvoCmA6qdMspKpyyEuj1ukWmodLxbSggJysAvzF yHZg== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:dkim-signature :dkim-signature; bh=sbWdaxRH9wtQ5jtXWnnn0dLFFNhT3qI69lOoFhkOLSo=; fh=aLynoDpboYiFE7Vr8X2p82xpYpxJzG83QwWgvy++L3g=; b=cff1Sy5tlOIVBaURkzZt3ZdR4bGvnkvtMYapEJV0JxXQijqO01dtT/qvmzafrTFLHE YdIWHgxWc4/HZmr6SAMuTJLoe3Nm2957SGeh2lQL69iUhj3ONdJqpuK/aOEO1TICmXg+ piIC0TTudU+Kg3Mbyw21eeM6N2yTNehmhLarfSTczUcgrf3da8teu40BFHaBo4vYdzFD P2FcznRfWGNB68lu6oSARdCEN3D73GzeJ/MQIlZ9TkPNRdG72+ems2zMmEO0O3bwr8Hj dOntatmK/U5XVGEikLt4xMZSB/Z5VPpzJq7KLjKkUrI+ZzmtGwmsUQwUKRyT3HX5kQzi H0vw==; darn=patchwork.ozlabs.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=lXvhocxO; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::62f as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1718479235; x=1719084035; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:sender:from:to:cc:subject:date:message-id :reply-to; bh=sbWdaxRH9wtQ5jtXWnnn0dLFFNhT3qI69lOoFhkOLSo=; b=NcdZiQ4aTpSmNBMftaIqYW6O8dLJgFGajPgAUP/tv4ymkky6NQBU0dYwC11wDW4P/o RGrJJx8a4DHIc7dYqGzLrZ0UQhzzgFDNQK4anq+Tu0nekKiexFpDVmDLXFevu0hpbvn4 DHXeL5DOBocSLVIgRxDNctqt6o6t4lxifxjUzhTHg9dX6lQtmA4sC2yS+rDWbihUt9W+ SxuA9z/dsN1k8YxQrKCrlKv7z1jRTrtoRVEdYrZalbTj29PziEogt6EdGXJbFq/Ul3kO 9dpq2NDDt7XPTXoTupK2ZeIivuiJwueQsAMSDE/qPZKjw6fF05I0Tly/0gEI6HC8gQ+H Q9/Q== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718479235; x=1719084035; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=sbWdaxRH9wtQ5jtXWnnn0dLFFNhT3qI69lOoFhkOLSo=; b=TzrrwPYsm82LgYAxg8i5CkJ9w2Oxv3nqTR23Tvzkt2To/bVPm+/YXTBKfQzSNYk3tw rInyzgpRyMvPoDu0A/YIDpBOCFrk/0DJaJ0FwwNX41wOQxb+qD8v2zuQvZESvVd89gqq KeJeIq+zdY5pYZxFjabYZjYZSbdztEPa0wi4R/QZkBlSfK9iAMb1J9p+AEsX4Sx41zhs YgOnCSQpyccmmqZP5yP7ohhJlnt3bhypGqqzj3nexwwt15pagWDTKBpQTXJnEEF5PWH8 RIzdg+gGDTmANUxDNg5R/ZsRZhf3ewe3r41sk6qh7+hUoTFW5Qb/HTWUAQa36F4miSsX 1tfA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718479235; x=1719084035; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :x-beenthere:x-gm-message-state:sender:from:to:cc:subject:date :message-id:reply-to; bh=sbWdaxRH9wtQ5jtXWnnn0dLFFNhT3qI69lOoFhkOLSo=; b=Xgu8GUllR47ZEErB8boiYjR5OMvOVvrkNSWO7h5GX5YxutybUMvLazhQnVSCuNgh+0 A8w5kjbePuQfniN4SapCJqTevgGvTzXqIZ9Cl0Ya+VctzVDqskJlNR0x5CbxoFmmXm3h ABNAxX1FK7+z7LpieEeigbAlLJf9ACvYKmoJ295jglI6TjfmfCCb+aDABPBuDBR2xlxV 2rRdoG1Bk4nIvGzY4Pqtduj35eDaM2uLZ3L7wat3T8GlvXLeYUFrHh1rEgz+oo7k+XUc OBDUjvkgw0toA3CDanBI7hyStDVvtC5BflCNUrDzdOnFPEbPDVtKTjdN/5E5KieiERoa Vg1A== Sender: swupdate@googlegroups.com X-Forwarded-Encrypted: i=2; AJvYcCXomFkvMDhoC2lFhHVZnVR3Ke7QrNx+s/F8yUD4cB8gf9YygjjekpPMhzBT3uzgGyJZdGcxNu20SkhLB7NjECwFdiiYRRJarbmlBAXgOg== X-Gm-Message-State: AOJu0Yz/rGmhOYHiCR+vngW78L6C8RyWGvos28mgkybCtox9lNFMHIXM A6KymJByriAF+J2wFuNH3L9+4t836QoQINxE2ooYYiGkPFqczAQV X-Google-Smtp-Source: AGHT+IGHRHqWWmxEUgziubTErXkmxwuoZZL5T2IV77Qo4ZkdtWV9bf1nQp1gcrfJiSKCoiA6Eisnyw== X-Received: by 2002:a2e:9bc7:0:b0:2ec:204:1e with SMTP id 38308e7fff4ca-2ec0e5b5865mr39161341fa.3.1718479234100; Sat, 15 Jun 2024 12:20:34 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a2e:2d02:0:b0:2ec:301:4beb with SMTP id 38308e7fff4ca-2ec03014f7dls13483521fa.0.-pod-prod-07-eu; Sat, 15 Jun 2024 12:20:31 -0700 (PDT) X-Received: by 2002:a2e:a602:0:b0:2ec:1d30:7309 with SMTP id 38308e7fff4ca-2ec1d307514mr22338641fa.33.1718479231135; Sat, 15 Jun 2024 12:20:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1718479231; cv=none; d=google.com; s=arc-20160816; b=yTN9QGhHwh1bjYgBpgT7s2SZQsgHUrr1XLLf9598KNDcTXAdZo9w37r513Pp3Rio8P s8P6nArXJYVsyVKclR+DMRycVVQBprWCyAzy9tcGbr3knGs4Mp7UogmP7TYnxMATxwlQ TKS+9nqBsQuwJ4C7d0wMHd30tfgELgYPGeKI3g8tpYhD1jaQYB2MHphyJS0jnhfKxhQh D8yBVaXj0Sh67L0KzF349qRYiGYPtsu521Ea2FCTDXQjBhB24Ar7jVwsmbY8EkqxERFB 7wyscI1lycRclIK//Df6p3remRmS5rGhrb3MPORkyGY1y9OMM9Pf+2lacXzDsLUs88Zm FrfQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=xEKl7kIkpQOhizD7qzB/V19MwMAw/Vt+CIJClwsZVRQ=; fh=zydHuzCQWrku2OPQyZfraJZFcOpEXLQ/YBcu3QNiBd0=; b=CEhBes6bFyQxSXtL13lb0qkcqagRAkaJaAzr9ZejvqEX76EgRu2nIVbVSDQWIf18KH MkhyNahZ9mg7JXQYCd2D5gwrmV4/KOHDXQxtWt/yJeqKMPVrfKtpgZpo5EkAyVx/DqCT l08cEsW41b3Oa5xuMtxurE23hBAt1dgKldL+uljne+tIxKdnkISR0H7y2WjsU53/astn LE0Hpgihr5B9ZDv4Z3Pe/ISOeqbEOZ2WRSSjdPUhxQ2VzuiS8LFahTQrTPrnpjKtU6VM bOjDKizkTd/9kduLUGr8KDNYnouwK+m2HvWoO+3+mYidnBNXO7gIc/VEfK+nUnpK4Ilt wX+g==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=lXvhocxO; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::62f as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-ej1-x62f.google.com (mail-ej1-x62f.google.com. [2a00:1450:4864:20::62f]) by gmr-mx.google.com with ESMTPS id 38308e7fff4ca-2ec05cbb4desi960181fa.6.2024.06.15.12.20.31 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 15 Jun 2024 12:20:31 -0700 (PDT) Received-SPF: pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::62f as permitted sender) client-ip=2a00:1450:4864:20::62f; Received: by mail-ej1-x62f.google.com with SMTP id a640c23a62f3a-a6efe62f583so320940066b.3 for ; Sat, 15 Jun 2024 12:20:31 -0700 (PDT) X-Received: by 2002:a17:906:fa92:b0:a6f:15c9:9aa3 with SMTP id a640c23a62f3a-a6f60de1b3bmr404851766b.67.1718479229943; Sat, 15 Jun 2024 12:20:29 -0700 (PDT) Received: from PC-2635.irisgmbh.local ([2a02:8108:96c0:76fc::80bb]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a6f56db61e0sm327283766b.49.2024.06.15.12.20.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 12:20:29 -0700 (PDT) From: Michael Glembotzki To: swupdate@googlegroups.com Cc: Michael Glembotzki Subject: [swupdate] [PATCH 18/21] mongoose: Makefile: Rename MG_MAX_RECV_BUF_SIZE to MG_MAX_RECV_SIZE Date: Sat, 15 Jun 2024 21:11:31 +0200 Message-ID: <20240615191941.40301-19-Michael.Glembotzki@iris-sensing.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> References: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> MIME-Version: 1.0 X-Original-Sender: m.glembo@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=lXvhocxO; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::62f as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , mongoose rev-id: a88ea776a913fba4832cf727caf2ea59dcdccf9d Signed-off-by: Michael Glembotzki --- mongoose/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongoose/Makefile b/mongoose/Makefile index 5e0bf5c6..c42f1e76 100644 --- a/mongoose/Makefile +++ b/mongoose/Makefile @@ -9,7 +9,7 @@ KBUILD_CFLAGS += -DMG_ENABLE_EPOLL=1 KBUILD_CFLAGS += -DMG_ENABLE_POSIX_FS=1 KBUILD_CFLAGS += -DMG_ENABLE_LOG=0 KBUILD_CFLAGS += -DMG_ENABLE_MD5=1 -KBUILD_CFLAGS += -DMG_MAX_RECV_BUF_SIZE=262144 +KBUILD_CFLAGS += -DMG_MAX_RECV_SIZE=262144 ifneq ($(CONFIG_MONGOOSEIPV6),) KBUILD_CFLAGS += -DMG_ENABLE_IPV6=1 endif From patchwork Sat Jun 15 19:11:32 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Glembotzki X-Patchwork-Id: 1948217 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=iJBFsGbh; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=IF63jsMv; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::23e; helo=mail-lj1-x23e.google.com; envelope-from=swupdate+bncbdy5juxlviebbaotw6zqmgqev6kh5bq@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-lj1-x23e.google.com (mail-lj1-x23e.google.com [IPv6:2a00:1450:4864:20::23e]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W1mFf2Lsdz20fS for ; Sun, 16 Jun 2024 05:20:38 +1000 (AEST) Received: by mail-lj1-x23e.google.com with SMTP id 38308e7fff4ca-2ebec81af32sf1591871fa.1 for ; Sat, 15 Jun 2024 12:20:38 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718479236; cv=pass; d=google.com; s=arc-20160816; b=FDA3WXntW7Ey52ZoSgRenmLd7BwKkLRihCDDMVGHy9j9kv+//pu7UhgbB0dPMRy2a8 38VIs1oors4+mfxMsAigGzVSG5PycazXX0RBkK22EyEOn0QZ8owzhJOjth2ATo1W1Jtw bhQ8tiHTRT9cKYVxiyY56Qng4l6XHHU8veXA9POWKcMz46GmilHF1CIFPkEURGMzr7nD ONL/dUIsXtmPqaj80ZSkqTV64/F2NyHb74ERTq4/dIGcAvMlFmJBMZCG6YqMPYGqmJld 0qIiaypquOrLDF1aUW0XkuzWBTpPP/pWTtAvvgq4GnLnqzqFMci7iKyqhQeP4XSOkfEQ MHpQ== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:dkim-signature :dkim-signature; bh=ZXJ6yKoPoUTh5U8iqrn+CFUH3HzjgqXHMnotdWrkHow=; fh=zsR26JtkIzvPHJWBELCSQbFUbjOOKjW6wQhI3a3lwpg=; b=t7WDGGmG2z6eOyv8cZyHHp2gHAASpiFa/OX3jAynEXYpjNju8yz1QEK+OjDGBSxflN 2nK67v/4A5gCWyFY8S1Gua7vl/atE/Er8lF4KNa1HdGwq7qCt8Q6wxlW8fhHKtsRgnYS M19pWaBQgupHXbt4HVAI450nNmrEtyHAa1Na0pkr5etfjveTevtn1CB80kvFTcYnhb8E RI39imh2K2vQQnd/GrjFZleTwlprnDmZN2vyCqdekLg4m8NmJNRv4UrOJ9NdmvgxPxh9 5VDMqDJ5R+Ti3PeA1a2F8yfoe3fiBljeNTWtICz7IvPI7tmDk4IkQVyJwZ84z5ejw3pS mnKw==; darn=patchwork.ozlabs.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=MvXj04wI; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::635 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1718479236; x=1719084036; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:sender:from:to:cc:subject:date:message-id :reply-to; bh=ZXJ6yKoPoUTh5U8iqrn+CFUH3HzjgqXHMnotdWrkHow=; b=iJBFsGbhk1lWbCOEaYYKnnYqIB8VXcMnEttj2GeTI4MgxVpqGiTP9pR0hyZ6ejkQEC G8WjFdV+5ZkjkmuBswwr9oxJrN2A8tjJGeGCtJrxCkJPVfQcOvMW5GCk4TRC/r8NYyOO vG/TK5JpL7p5PmhfWd+cMS8JV6mvCvLWYnZPIoVTCTEe2hEgVICrbxk1TYo85Y0//NDf NuwSVAjWAHTTJSQLBr1zTptugV7EvzdA+UYpaXdXWE6AhgVtSSeVSnXNNPbKILK0BY3A 0MZLg76QD7Y5/ozEs2Wu1Vu96N39QpEzX4LNJUXNm2XO580scVeqS6e+v6L89YI9U389 DR/w== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718479236; x=1719084036; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=ZXJ6yKoPoUTh5U8iqrn+CFUH3HzjgqXHMnotdWrkHow=; b=IF63jsMvbmTbcNizlelq7ZBXO5V9qdZ7aup3c3m3mabSxSH5F40vvc7lAxOQQTnsjx NzwERX7TVGNJ8oP0gWTsgoMJN1xdODZy3Uk/vajo8gIsq05M7/i8qpX9Yz27h5aLioy/ LC+3pQoa7eq2LP93iW9YIDmuKoF2Cpwdf3AN5JWidPMkHlroImu0nnUwIqwJjc6Jbqb+ fMF5KxkpKZVLd6ghNUmDmjY35DEmLAfBLk0/jXt1tNv9Ra8AbJEIOlWSKAiTuF0D5v/r lyCCI4cgZGjpVOnXyPSNJfpoKMfWFQTjxWadIl6ANrrlRCY0meaOrEI7eT9e6k3QxcRB GHww== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718479236; x=1719084036; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :x-beenthere:x-gm-message-state:sender:from:to:cc:subject:date :message-id:reply-to; bh=ZXJ6yKoPoUTh5U8iqrn+CFUH3HzjgqXHMnotdWrkHow=; b=vltg2olGQtpkBLm6azHw90Sy+2DudRW3aHZqTLYMU4kRARUsBMltdCX7GqcwsM+6x0 L8w+k4JfIivurUQR2/PA6a09waB5qWI4I0muFlOifu0pCW1NBmwbiScjgqVqw03w8z/d P+tbtzIHCMZze8Wuhgt0fUui275l+Bv+YNInRnrHSZd6WgxNQVR3T4gzkSHHaAcXPIi0 6v8GcugYd3RytbNY/GgKRwsfsJuGFCP4Hgysmh/7n8zFsnGlQuQTO240ceDiQL2kmF+G Ma7mlYh/5jfo/H4bK/d7EmZ+huXEP//GtcmcpdQ2UzZk9lf5venso+sARCDeHeVmmZUq S13w== Sender: swupdate@googlegroups.com X-Forwarded-Encrypted: i=2; AJvYcCUnL6J8cFJZIO1PQ/qARReRrNCogrWBWlJRIPecQlAxfnab+kebhfu+47pJx6XmwQpdxOMVizrsa4GwpNJFA+hOITU9xUykpkD/LYpI0w== X-Gm-Message-State: AOJu0YyWgs4o8lXcQ2jSwy8jKCKcZoFhYFTFtISr9JOdc5Q8fKXrdjCk tgMzqjfSSB0pmLci33iaxfgqfndeahByH4PnbabpgMe9nddHHc+2 X-Google-Smtp-Source: AGHT+IH6dT3uzwnlwjFqi6sn9q3Wzz6uyJG0y0IBP8bqSAXk5YcV0SnflBRDeg2b5dGSUqRp0aXuzQ== X-Received: by 2002:a05:651c:154a:b0:2ec:143e:2893 with SMTP id 38308e7fff4ca-2ec143e2926mr34081641fa.2.1718479234456; Sat, 15 Jun 2024 12:20:34 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a2e:a309:0:b0:2eb:d7dc:e4 with SMTP id 38308e7fff4ca-2ec0287fe60ls20753661fa.0.-pod-prod-08-eu; Sat, 15 Jun 2024 12:20:31 -0700 (PDT) X-Received: by 2002:a2e:91d4:0:b0:2ec:29b4:ceea with SMTP id 38308e7fff4ca-2ec29b4cfa1mr588001fa.1.1718479231516; Sat, 15 Jun 2024 12:20:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1718479231; cv=none; d=google.com; s=arc-20160816; b=Np2m+FM5q1uq/phutLgF7o0bFDMqAbB0PsJTz2Qi7ZXCcfI4lYh31Xy+43Sx5HvFYl it4u8zZm9BZcBYHh18F4MB2u5eF+msq3hrcy97Yr7DfHyUGJICO7t7d+fMQfTujVkQ0o kOVNoIfw+gyvqVfZ4wOg0lWyHQnw7acbhaBNV8iUJ4Rvt1hd7X+9CdD8/jXEZqh5nQBx rbSXFrtGAETn6Tg1dJqDOFfQOam2ZeLEcme3UUogpepStDVenIrJVSd2KPUBa0Mm7aJp O8wtVsKbbX4kQiTy5M7aij1Qwwoxexf36X6xgxs2wvYNc0z7GeiEFdvWNy5Hdau3lW+Z Yjbg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=7vxyRfNzxa/4X/+u4mXNXUoGsGl+t5hsh0He5k350yE=; fh=zydHuzCQWrku2OPQyZfraJZFcOpEXLQ/YBcu3QNiBd0=; b=OQVxAJOiyqQ5wMr8JSanPKJwnxr+MRoQVN5sBv4ucjb5SmBnGXaAeAoNq8BliAhqMe sfNh6pZxLXZCXmctgV9dBk/iMrqRcucyHebN80SBBVjw606H47l8DJOdZFS77FL3EdDb KQ/QNXxMyKC2xMwSbxUaEz138/N8pznWV/ImiGedImpdsvqJ7DKibPQozrd4QGFhpR9d gmF77/UtutUVKyCuEPzhjAd5ouCU6SgcZThkhaDxU7TUa/2+FcDwWTxk1fd2K1eYPEWb qtzIecKXSO0vqfZdUGYfX/gYPGnwA+gu6ZFZTMvugsHchYcESSPRh6Y7KGvRFMavu2Sv KuUA==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=MvXj04wI; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::635 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-ej1-x635.google.com (mail-ej1-x635.google.com. [2a00:1450:4864:20::635]) by gmr-mx.google.com with ESMTPS id 38308e7fff4ca-2ec05c27b5csi1340071fa.1.2024.06.15.12.20.31 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 15 Jun 2024 12:20:31 -0700 (PDT) Received-SPF: pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::635 as permitted sender) client-ip=2a00:1450:4864:20::635; Received: by mail-ej1-x635.google.com with SMTP id a640c23a62f3a-a6f1da33826so464981766b.0 for ; Sat, 15 Jun 2024 12:20:31 -0700 (PDT) X-Received: by 2002:a17:906:354b:b0:a6f:4804:d41a with SMTP id a640c23a62f3a-a6f60dc4f05mr553332366b.55.1718479230600; Sat, 15 Jun 2024 12:20:30 -0700 (PDT) Received: from PC-2635.irisgmbh.local ([2a02:8108:96c0:76fc::80bb]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a6f56db61e0sm327283766b.49.2024.06.15.12.20.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 12:20:30 -0700 (PDT) From: Michael Glembotzki To: swupdate@googlegroups.com Cc: Michael Glembotzki Subject: [swupdate] [PATCH 19/21] mongoose: Use mg_file_read for cert/key Date: Sat, 15 Jun 2024 21:11:32 +0200 Message-ID: <20240615191941.40301-20-Michael.Glembotzki@iris-sensing.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> References: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> MIME-Version: 1.0 X-Original-Sender: m.glembo@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=MvXj04wI; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::635 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , The specification of the cert/key path has been changed. The key/cert content is now expected as mg_str in tls_opts.cert/tls_opts.key. Signed-off-by: Michael Glembotzki --- mongoose/mongoose_interface.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mongoose/mongoose_interface.c b/mongoose/mongoose_interface.c index 2fed8bcd..b47b9f55 100644 --- a/mongoose/mongoose_interface.c +++ b/mongoose/mongoose_interface.c @@ -900,8 +900,8 @@ int start_mongoose(const char *cfgfname, int argc, char *argv[]) #if MG_TLS if (ssl) { - tls_opts.cert = opts.ssl_cert; - tls_opts.certkey = opts.ssl_key; + tls_opts.cert = mg_file_read(&mg_fs_posix, opts.ssl_cert); + tls_opts.key = mg_file_read(&mg_fs_posix, opts.ssl_key); } #endif From patchwork Sat Jun 15 19:11:33 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Glembotzki X-Patchwork-Id: 1948214 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=qziM00r1; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=LfKx3Znu; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::33b; helo=mail-wm1-x33b.google.com; envelope-from=swupdate+bncbdy5juxlviebbaotw6zqmgqev6kh5bq@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-wm1-x33b.google.com (mail-wm1-x33b.google.com [IPv6:2a00:1450:4864:20::33b]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W1mFd6QGGz20Pb for ; Sun, 16 Jun 2024 05:20:37 +1000 (AEST) Received: by mail-wm1-x33b.google.com with SMTP id 5b1f17b1804b1-42108822a8esf21069965e9.0 for ; Sat, 15 Jun 2024 12:20:37 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718479235; cv=pass; d=google.com; s=arc-20160816; b=O4Fkca7NRd+pYJWFmC1LlJsqOEjJJDrGTRanhU3QP3CfnsiTBQnxBGJVTL7MUrqu0B RJEDDsrRTCJ/dmeubK43cXMO02oIsx0iwzrcK/VmrKZuKeBiCkml2sg3A10DnyPK5Kf4 KXHowtcLfAh9piWva4coSJHnqQ0CWzgbDPFsen7JANSph8gUUgM3g5laFFtBpexXhEws Fa/ge6orl5F+Nfj+1xfqW/YYS6EHHsoTpKYaJUp6JTeOfWs2Ij9kea72QaJ/1FbgOLWb 9ZypwHusqMpYB12s+D4HUwi6LVOvge6Vv1CgJv2WCtdsJqyokXJkYPKzIEz+iRnrRE6w wU2Q== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:dkim-signature :dkim-signature; bh=Emf1D91O3bhJfcITyHaxAfYuEK8Gi1ld9QmWFjJN4XQ=; fh=6lEMQBbDFFOM+kqs+KvjWYqRUzGaBuXnH8TMr0XEN+M=; b=UFyu7EVw2AijX5rkMp2inWZ4EFP3MY3Ppqp8lXG8Bn8Lf3m6JQfgrrWsx2lEP9Ffwy G0KAfV5x0D2hgTkzxOXlrYgUd3Klu0AIYcW7/lku/wc1jsTBksMOaoaISoyQDHpYphX/ Is71/L+FmfAvA767cg017ozbqAlb2Yq3gPG7HBGh3Og0aSSKSbo/kxX7rBV9baag5U5Z XhHH+bzRMQRp9oLt+Y1L5sVthXQGoqG+BOSsSXeIATDNadMTD+WyWJ7sxt6mv4DVn1gW 9NTs7ZXGjGhIjxudB8vFYzgwNdraBQm6PlbY3FEWzSxo+CRDUcGTRiox0CYm9DE1YvCi qZ0w==; darn=patchwork.ozlabs.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=gR4PU6lF; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::632 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1718479235; x=1719084035; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:sender:from:to:cc:subject:date:message-id :reply-to; bh=Emf1D91O3bhJfcITyHaxAfYuEK8Gi1ld9QmWFjJN4XQ=; b=qziM00r1/1McSBa2CtOGXrVjRGeSvRE0ENhPvH6Hc2Oko5n1zVxUk8azljkIuvtE6m cvN6NyW1vuHSuNJpeC1vHq3RfdzcknsH9kUFYUmX6dMj+qXmKBR1/fVDqct3BsLZMCch w5KppHLHKMrp0dRwKy0GROv4wwST8BqVel7Xzeok2hD+9LjpsqcPcjDR8bYriO2vaTxn 3aLCcXTE2/SuRdmzlPCkAct6ah+tfm4p8BMiIGxM9TQu+5ZS+aNm9oF5xzpHFrRKnblT 62qxNC5nArYdGlUjUCjvWQ9zmRFHn0bdzCeNGKKtyh2+b/0fuztKNV/WZW7CK772F5IL dDSA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718479235; x=1719084035; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=Emf1D91O3bhJfcITyHaxAfYuEK8Gi1ld9QmWFjJN4XQ=; b=LfKx3ZnuN1d2aY2f+kTMISK6/qBzMzYtB5bQASLyaKkVuqJThOyeGYYbXZD3Qty7jB pIWMMDRsz2zJmDs7wkok/jKi2ZjAljP3of+FuAcNJL6hXteFejnnP5TXDMgHyq29rDBI uyayxiwFuuTCsoUOlia3bhPITn2OCl3GO1slMszXNpKwJrEpj9rtrGX5wSr1yXB9i0E2 p+x4Qb4nYhyXxO3XyXsYWf5HxioBZzMUwP76iBvXRIW3fVDmElS67MdcYDDP9qt8nix9 bNa019U8v7zA+K04bO2tr9TQIgQPMEXj/2urCBR3oSxbo7v1xAgGr9qaLtispzqVavd4 7Rgw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718479235; x=1719084035; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :x-beenthere:x-gm-message-state:sender:from:to:cc:subject:date :message-id:reply-to; bh=Emf1D91O3bhJfcITyHaxAfYuEK8Gi1ld9QmWFjJN4XQ=; b=oaavgoxYUFl6prHErleibhsO7AYJSl3O9edqPMwO6GNDARQIy+xqtcQu2RUYDZW5Q5 jdyHuPoWd70GxcDSp+NcjmTgt8We6XwWNqOI1By/CuW1oXOltg6HF0+3B1JmqrL7YQ98 HhaGk6VqPdMBg63Lf12WPkpC8axbvIcuorpJJK/l5Utv7K2XfpWwPPKh6KAwLQOXbhJR XZbRXYdJCimkByuWutuM6f+SMBUNnG0l5UWVrKQ6z9meSOhHUmezeeAtCyfgrx5uKvza Dx4qSsEnKuf8n1aOS+5kfgBErPr44B13MUkYBDOahxeX7pVObQRy5eH+UnaOT7G6jSJl rlTw== Sender: swupdate@googlegroups.com X-Forwarded-Encrypted: i=2; AJvYcCWb4wQvlfpfNNkGhaNWr6dxJaDa9R488P+YMfc8Ypz6Y2olZAwM/zl0fo+KipM916E6+lrbmwEszOPpRX2efZ3pdvBMQuU+TIR7axcLzg== X-Gm-Message-State: AOJu0Yx46Fyv99kwF/mUJxF+2BBlxyMpUO2DxeaSz1q+U0YM4fwiWc/1 Q1QHtjzuNx3f2vkpwN0bfefx3sviP/8iwzQXs/qlyFmyexV/e9t9 X-Google-Smtp-Source: AGHT+IFZQEDmNQfRgkBE7v47fxnktMsSYKFypEPUGvwfhoJdoeH+F5V79h07pkXcKz40ML1aTZo9EQ== X-Received: by 2002:a05:600c:5492:b0:421:83fd:900f with SMTP id 5b1f17b1804b1-42304820ed0mr62140385e9.5.1718479234488; Sat, 15 Jun 2024 12:20:34 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a5d:5583:0:b0:35f:d3f:68c with SMTP id ffacd0b85a97d-3607194e089ls1148957f8f.1.-pod-prod-00-eu; Sat, 15 Jun 2024 12:20:32 -0700 (PDT) X-Received: by 2002:adf:e25c:0:b0:34f:8f7c:8fe2 with SMTP id ffacd0b85a97d-360718d550bmr9314396f8f.10.1718479231965; Sat, 15 Jun 2024 12:20:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1718479231; cv=none; d=google.com; s=arc-20160816; b=YDamtKsR9EDZVJs1O3YQTX32NZ+59rNwfo8KFEbqlOx3V1jDcvbTe/lXaq/O36M0F0 NYdxjtPuxdSya+x7N9sgOjobsT1vG8R/Zl4Nly/DJW+SBnKC/5H6LqWc4L6RUQpC/bhH mLHit4SD18Ab82GS/kQCR0Comuao9FXxt+RqgtXGoAnXvdkrqvmM1newvocnuACcruBg RPU6lwKfDBUKRPHYvkNEIjj4Mvk4ZBqvlxvWx+7b0vZaLyDi+vLQ/+Pe8UA7Th/3wJWV aCuoWMEe3VFSvr0c3qg9i97/FZUkQHiYNwj4VxGGbq8uyhU0TCzbaAUrDzARKzNLUTfR 6zCg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=BnxfjbyFJ6JHavPSUlxIwcTZNprFV08p41t3LXv+U7M=; fh=zydHuzCQWrku2OPQyZfraJZFcOpEXLQ/YBcu3QNiBd0=; b=CLe3BVvaxR8yLZzqO24THljt6FiqkUQ0Lh5rf6AadnYeEFSiGepWTMnP6tCpTz304h bE1OcdPD2oJJPBy4beR81N7O633K7VZNVdaUEzAvIXorcK7iDyfCp8y2wZQxHuZx7stp 8WeKPClt6MhYRnyVQwfxr1KaFTfMqREntAFUrZghDCM4yRw85h177H45QyiF2C74NQ4i i8ZkE4iHEI/5LXQptQVpNyMCP1JaPPj62Qz07CegaLmlSHG6WyXXP/gMedK57AnGzUAk Wt9NvaCLjTSA3sXq1BVD8nbrDOeJl4JVUZ4zRLS7BmSCJyh/2OJJ2xTZKXKIxq1516uG oXsw==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=gR4PU6lF; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::632 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-ej1-x632.google.com (mail-ej1-x632.google.com. [2a00:1450:4864:20::632]) by gmr-mx.google.com with ESMTPS id 5b1f17b1804b1-422855708b8si572585e9.1.2024.06.15.12.20.31 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 15 Jun 2024 12:20:31 -0700 (PDT) Received-SPF: pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::632 as permitted sender) client-ip=2a00:1450:4864:20::632; Received: by mail-ej1-x632.google.com with SMTP id a640c23a62f3a-a6269885572so741465866b.1 for ; Sat, 15 Jun 2024 12:20:31 -0700 (PDT) X-Received: by 2002:a17:907:9406:b0:a6f:1727:cf4b with SMTP id a640c23a62f3a-a6f608a7945mr473304866b.23.1718479231258; Sat, 15 Jun 2024 12:20:31 -0700 (PDT) Received: from PC-2635.irisgmbh.local ([2a02:8108:96c0:76fc::80bb]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a6f56db61e0sm327283766b.49.2024.06.15.12.20.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 12:20:30 -0700 (PDT) From: Michael Glembotzki To: swupdate@googlegroups.com Cc: Michael Glembotzki Subject: [swupdate] [PATCH 20/21] mongoose: Fix url in mongoose start message Date: Sat, 15 Jun 2024 21:11:33 +0200 Message-ID: <20240615191941.40301-21-Michael.Glembotzki@iris-sensing.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> References: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> MIME-Version: 1.0 X-Original-Sender: m.glembo@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=gR4PU6lF; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::632 as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , %I is not resolved. Replace the %I format specifier with %s. char *url is already there. [start_mongoose] : Mongoose web server v7.14 with PID 1277 listening on %I:8080 and serving /var/www/swupdate to [start_mongoose] : Mongoose web server v7.14 with PID 1306 listening on 127.0.0.1:8080 and serving /var/www/swupdate Signed-off-by: Michael Glembotzki --- mongoose/mongoose_interface.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mongoose/mongoose_interface.c b/mongoose/mongoose_interface.c index b47b9f55..f67b1089 100644 --- a/mongoose/mongoose_interface.c +++ b/mongoose/mongoose_interface.c @@ -815,7 +815,6 @@ int start_mongoose(const char *cfgfname, int argc, char *argv[]) struct mg_mgr mgr; struct mg_connection *nc; char *url = NULL; - char buf[50] = "\0"; int choice; #if MG_TLS @@ -938,9 +937,8 @@ int start_mongoose(const char *cfgfname, int argc, char *argv[]) start_thread(broadcast_message_thread, NULL); start_thread(broadcast_progress_thread, NULL); - mg_snprintf(buf, sizeof(buf), "%I", 4, &nc->loc.ip); - INFO("Mongoose web server v%s with PID %d listening on %s:%" PRIu16 " and serving %s", - MG_VERSION, getpid(), buf, mg_ntohs(nc->loc.port), s_http_server_opts.root_dir); + INFO("Mongoose web server v%s with PID %d listening on %s and serving %s", + MG_VERSION, getpid(), url, s_http_server_opts.root_dir); while (s_signo == 0) mg_mgr_poll(&mgr, 100); From patchwork Sat Jun 15 19:11:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Glembotzki X-Patchwork-Id: 1948218 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=hIWv+oKJ; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=XIyk/y+j; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::63b; helo=mail-ej1-x63b.google.com; envelope-from=swupdate+bncbdy5juxlviebba6tw6zqmgqe3wdeh7i@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-ej1-x63b.google.com (mail-ej1-x63b.google.com [IPv6:2a00:1450:4864:20::63b]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W1mFg3gwnz20Pb for ; Sun, 16 Jun 2024 05:20:39 +1000 (AEST) Received: by mail-ej1-x63b.google.com with SMTP id a640c23a62f3a-a6f0f008f9asf95328966b.3 for ; Sat, 15 Jun 2024 12:20:39 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1718479236; cv=pass; d=google.com; s=arc-20160816; b=VVR1QckFIEWanTOYSfhNOnJEIeOy6/dRi3k74NdyIB5THu+QHB7kgAdFKHTYUuVHZu qMKAOEsmTDHKGrv+QNh4V/cezJPPfKQVWy8BejNJhQ5CMPbdPpId1w4kVBSDyFbfiUka R5Q1j12etV1xiQL9b5RgiJASLQj9PB7/g10YHuMFS22/NqtrF5xsBThPZ/tPBcP8Dnpc 718uB8nVEB5VaxktxqgDFMOXfE9avIYfZg7XCbzAjWTGeMxecAbzUafGoNSHqBftfejy 1+olt9H+R/pX1FBNk5qWNdle+Lo9JIgLTf0dwzjst7CBUoaHlu/4LOcCVOjvDBBKwfK1 UAew== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:dkim-signature :dkim-signature; bh=Damtbiy8JYAwqZ4f0J69EeHu41hyQtnoiTwpc1T86HY=; fh=8j7+QGzOea9910WMwYM3UzYnDPcyaHVXq2aOMuTdeZw=; b=v3kzjph2bw8BYbww+cunnqgBrY0SLRJ3KUmOTEr5bZegEjW6mPuUKXX4UtT+Ucm9VA 7BQVMom065EC5pD004psgz4v4UBBhVuO0JNlbRUJr6UmRdpM31u8eORa6ztUOThOkDXR yQl+cOnp3tI/5ClXkxIK7Ur1hN++QFNNVvp2NO93u/gaeuYwQepMyDvm3mV/OC/cJAsZ NrwB+k5OlTPM4NuFbKghzq7eq5Clpqrbn2kBxltd58W0n5aQFOo1pjvXun8HWeRyxfgx VNJzvhpyMu6LWhNTe8zbjuX3JkcGg6nsza+CnIYdj/KQkZhzPTQ8x6Hsn9YONBcdLlch 8onQ==; darn=patchwork.ozlabs.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=cTfAhYjv; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::12f as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1718479236; x=1719084036; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:sender:from:to:cc:subject:date:message-id :reply-to; bh=Damtbiy8JYAwqZ4f0J69EeHu41hyQtnoiTwpc1T86HY=; b=hIWv+oKJOafkBt/a8vpmaCX6Ej9R5FWEZRwgxhUCaHPkSa6NuqJrAsR+VT/7t6qF/+ DVkredFDoGHD/Zzq1NYkf5yHshiriS8def+L6nt28durCXR/CuUZ+KrrIhH06X4Bx4Lm oEFKEUd0H0rBSmS1qKkzWHb32iMiC/DOenA/8yfbj3NyOJKo3ADNlhFtP/D4O0hg6DpP zyg3HA1FTfUXF0ss+43e7iyrIPJ1Z7f44RDapnkTbAASaMlr/NeTix9SMSnP1kgZyMoh yDUouTMSXbpj914zAjBFFxs2Dbh7ts3U+mYQsI+DmxuYgq6tikbnWQmhJb2Nj6EnRJQD oogQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718479236; x=1719084036; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=Damtbiy8JYAwqZ4f0J69EeHu41hyQtnoiTwpc1T86HY=; b=XIyk/y+jcvF5TYXPz1kU4y3z/DGwF7vuEkYk8pMt/DjJIyzaPQbl33kAJaLclcy5JF PHdKduTbQxkJX/vpJpXY1HLryxqUfZYJ/mYwgtlMgPWXJ4ecfNF8dK3Nwx0A6D0RZpQu j0Yo3uO2zCE4hWybwK+q3rAzQcZu1v9AZmKHCoExpOEwMeZ4SRxVQ7Alqd2nFRKxS99n tzTqInQBCS1P+TPPUJm31v0tq9ciLBs6AhD7uQzcwtkqOC2OprZ6AEi5XjXmxj8rMoH3 Fyrd+g9MKAJdY1/n8TLkr+O9tJxFn+jv0aouFyFMevYgJP4OLxE1WMBagBB13XluLqK9 RQ1A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718479236; x=1719084036; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :x-beenthere:x-gm-message-state:sender:from:to:cc:subject:date :message-id:reply-to; bh=Damtbiy8JYAwqZ4f0J69EeHu41hyQtnoiTwpc1T86HY=; b=Jlx4HzYkjWO4JjyCE7qH5hS74gU580XzlNlWhfdn1QpPOPAiIi2Pnp7JlQzUlCXQ2c jfc7pJzTldaEUpaYp9Am5zTowmmJA87nzIB9j3U17R0W3cJJBYUkUHNEPag2gv+d3Y8H 9j833dQqjCOdGZW+Wyc3uRclMovOtquvxcIMGmx92+EbrV5B9xBJp4ooyY73YK45TzHd sH00lBAV13boVnQS8HZL7gO4ERbmKyGdf/R47E6yJsajGmHPmt2gvIs8ruyUSXSJNhsr RFb1/XVZ5nN69QT4rit4yAxvkL+7LCpoUtjX2PzYUCa7XQQqXKCGj/oMsAHoQ4W/1sM+ abfQ== Sender: swupdate@googlegroups.com X-Forwarded-Encrypted: i=2; AJvYcCVDc3sNpCEge+PvmP2LSpo5LfcRHc8lJ02+kYk8FHtVhlDRpoKCqTphDwi0WHjHFlwWNaWJjAqQdxSMaPOoN6PThSuWlu8Y5K+cBKOWcA== X-Gm-Message-State: AOJu0Yy2kT1GRyT4Dk7Umij7eXPblqNxg9GuR6OCbD3l2kR/EQ+u6mJ/ z2ffMsjFDnjgBRYqPh1+XnDErYwLaSyghhxr5VhWeTo/4A5Xan7k X-Google-Smtp-Source: AGHT+IFpgB2CkT83ZUcMnVdiGbtYpfxKxxEemYPYXv6gTAMLuZaYfdWOWUBPpRGIC4bGEK1ICfrBAw== X-Received: by 2002:aa7:d487:0:b0:57c:d228:772f with SMTP id 4fb4d7f45d1cf-57cd2287a42mr1318259a12.10.1718479235918; Sat, 15 Jun 2024 12:20:35 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a05:6402:27d3:b0:57c:a472:931c with SMTP id 4fb4d7f45d1cf-57cb4a604bcls625768a12.0.-pod-prod-05-eu; Sat, 15 Jun 2024 12:20:33 -0700 (PDT) X-Received: by 2002:a50:ab17:0:b0:57c:70be:6558 with SMTP id 4fb4d7f45d1cf-57cbd6c7462mr4410742a12.27.1718479233337; Sat, 15 Jun 2024 12:20:33 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1718479233; cv=none; d=google.com; s=arc-20160816; b=LuVoUtJRaZZFw/O9dS9rwSWcsuCL5ajXY4T6zH0y+0pEN0b6cRQbIIhMnzC/W+WFdd KdSNR0EWM1X8/TExMlwHn0p2jt8iEgawgtRlG+abR0azD1lwfWhi4RONE9kbI3LBi+s9 Ekyw2kWmyxZFST9Ip/+NaV7XMvcvjVxk20t+RpMRfBaKw42aZVdaO6oBr9jFH3L632EV cD3grqcDISU7o7kz7P5J2twtCUI1W0txbeEVFD2kUnN/EB4Aiw55xO6qKx8cPtEyIqvd Ux5IO5Y4QRfYPT8Nw5flcQ1QOSEZ48JURX7lgYWs3S1R76VigVK8szvAMl+OTUO6wgfE ZHvw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=YZmRABg+UkVVbVBxe0e71B7g6gbZnSz/4Y2W10Lfsuk=; fh=zydHuzCQWrku2OPQyZfraJZFcOpEXLQ/YBcu3QNiBd0=; b=GYZ9hgir4iucfEFaWlItpNwshbNgeZMjNcJYCCS5XQH1Onj3xcOYKreMAO8S4F1Mb2 fPfwXeA2z44nnDHMrtYG8bZej7dfPDyRsb8TH1mdS0EKxKEQkt3kCKpW14LDZKbPV8pb XV3Ud2j4WhkgeoDTbk1QZkANzp1t2ZOIlP/UmuIldi0/HaUeIiXtXI6ANTvx8h+4JKiR cxEmMxA0O8rVFUbZ+FWE54Aij655phHI+BG5QdfCuWoS2/05t1iWOiR+Rhu3iIV0HUdk vHsmY8fvOWVMAmZC9hxEdKt/EOoeRkZCb2NWLK9ru7tNmSUfJlG2GnYHC5/jdNs6BbLv voPw==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=cTfAhYjv; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::12f as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-lf1-x12f.google.com (mail-lf1-x12f.google.com. [2a00:1450:4864:20::12f]) by gmr-mx.google.com with ESMTPS id 4fb4d7f45d1cf-57cb7449f1csi133552a12.4.2024.06.15.12.20.33 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 15 Jun 2024 12:20:33 -0700 (PDT) Received-SPF: pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::12f as permitted sender) client-ip=2a00:1450:4864:20::12f; Received: by mail-lf1-x12f.google.com with SMTP id 2adb3069b0e04-52c9034860dso4080692e87.2 for ; Sat, 15 Jun 2024 12:20:33 -0700 (PDT) X-Received: by 2002:a19:9142:0:b0:52c:999b:5306 with SMTP id 2adb3069b0e04-52ca6e6717amr4588892e87.17.1718479232247; Sat, 15 Jun 2024 12:20:32 -0700 (PDT) Received: from PC-2635.irisgmbh.local ([2a02:8108:96c0:76fc::80bb]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a6f56db61e0sm327283766b.49.2024.06.15.12.20.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Jun 2024 12:20:31 -0700 (PDT) From: Michael Glembotzki To: swupdate@googlegroups.com Cc: Michael Glembotzki Subject: [swupdate] [PATCH 21/21] mongoose: Replace deprecated mg_mkpipe() with mg_wakeup() Date: Sat, 15 Jun 2024 21:11:34 +0200 Message-ID: <20240615191941.40301-22-Michael.Glembotzki@iris-sensing.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> References: <20240615191941.40301-1-Michael.Glembotzki@iris-sensing.com> MIME-Version: 1.0 X-Original-Sender: m.glembo@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=cTfAhYjv; spf=pass (google.com: domain of m.glembo@gmail.com designates 2a00:1450:4864:20::12f as permitted sender) smtp.mailfrom=m.glembo@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , Use the new mg_wakeup() [1] mechansim to send data from the broadcast(s) to the parent event manager thread. Based on mongoose multi-threaded example [2]. [1] https://mongoose.ws/documentation/#mg_wakeup [2] https://github.com/cesanta/mongoose/blob/master/tutorials/core/multi-threaded-12m/main.c Signed-off-by: Michael Glembotzki --- mongoose/mongoose_interface.c | 104 ++++++++++++++++++++-------------- 1 file changed, 61 insertions(+), 43 deletions(-) diff --git a/mongoose/mongoose_interface.c b/mongoose/mongoose_interface.c index f67b1089..260ed8f9 100644 --- a/mongoose/mongoose_interface.c +++ b/mongoose/mongoose_interface.c @@ -64,6 +64,11 @@ struct file_upload_state { uint64_t last_io_time; }; +struct parent_connection_info { + struct mg_mgr *mgr; + unsigned long conn_id; +}; + static bool run_postupdate; static unsigned int watchdog_conn = 0; static struct mg_http_serve_opts s_http_server_opts; @@ -74,8 +79,6 @@ static bool ssl; static struct mg_tls_opts tls_opts; #endif -static int ws_pipe; - static int s_signo = 0; static void signal_handler(int signo) { s_signo = signo; @@ -358,30 +361,6 @@ static void restart_handler(struct mg_connection *nc, void *ev_data) mg_http_reply(nc, 201, "", "%s", "Device will reboot now.\n"); } -static void broadcast_callback(struct mg_connection *nc, int ev, - void __attribute__ ((__unused__)) *ev_data) -{ - static uint64_t last_io_time = 0; - if (ev == MG_EV_READ) { - struct mg_connection *t; - for (t = nc->mgr->conns; t != NULL; t = t->next) { - if (!t->is_websocket) continue; - mg_ws_send(t,(char *)nc->recv.buf, nc->recv.len, WEBSOCKET_OP_TEXT); - } - mg_iobuf_del(&nc->recv, 0, nc->recv.len); - last_io_time = mg_millis(); - } else if (ev == MG_EV_POLL) { - struct mg_connection *t; - uint64_t now = *((uint64_t *)ev_data); - if (now < last_io_time + 20000) return; - for (t = nc->mgr->conns; t != NULL; t = t->next) { - if (!t->is_websocket) continue; - mg_ws_send(t, "", 0, WEBSOCKET_OP_PING); - } - last_io_time = now; - } -} - static int level_to_rfc_5424(int level) { switch(level) { @@ -398,14 +377,18 @@ static int level_to_rfc_5424(int level) } } -static void broadcast(char *str) +static void broadcast(struct parent_connection_info *p, char *str) { - send(ws_pipe, str, strlen(str), 0); + mg_wakeup(p->mgr, p->conn_id, str, strlen(str)); } -static void *broadcast_message_thread(void __attribute__ ((__unused__)) *data) +static void *broadcast_message_thread(void *data) { int fd = -1; + struct parent_connection_info *p = (struct parent_connection_info *) data; + + if(!p) + return NULL; for (;;) { ipc_message msg; @@ -423,7 +406,7 @@ static void *broadcast_message_thread(void __attribute__ ((__unused__)) *data) ret = ipc_notify_receive(&fd, &msg); if (ret != sizeof(msg)) - return NULL; + break; if (strlen(msg.data.notify.msg) != 0 && msg.data.status.current != PROGRESS) { @@ -441,18 +424,24 @@ static void *broadcast_message_thread(void __attribute__ ((__unused__)) *data) level_to_rfc_5424(msg.data.notify.level), /* RFC 5424 */ text); - broadcast(str); + broadcast(p, str); } } + free(p); + return NULL; } -static void *broadcast_progress_thread(void __attribute__ ((__unused__)) *data) +static void *broadcast_progress_thread(void *data) { RECOVERY_STATUS status = -1; sourcetype source = -1; unsigned int step = 0; uint8_t percent = 0; int fd = -1; + struct parent_connection_info *p = (struct parent_connection_info *) data; + + if(!p) + return NULL; for (;;) { struct progress_msg msg; @@ -472,7 +461,7 @@ static void *broadcast_progress_thread(void __attribute__ ((__unused__)) *data) ret = progress_ipc_receive(&fd, &msg); if (ret != sizeof(msg)) - return NULL; + break; if (msg.status != PROGRESS && (msg.status != status || msg.status == FAILURE)) { @@ -486,7 +475,7 @@ static void *broadcast_progress_thread(void __attribute__ ((__unused__)) *data) "\t\"status\": \"%s\"\r\n" "}\r\n", escaped); - broadcast(str); + broadcast(p, str); } if (msg.source != source) { @@ -498,7 +487,7 @@ static void *broadcast_progress_thread(void __attribute__ ((__unused__)) *data) "\t\"source\": \"%s\"\r\n" "}\r\n", get_source_string(msg.source)); - broadcast(str); + broadcast(p, str); } if (msg.status == SUCCESS && msg.source == SOURCE_WEBSERVER && run_postupdate) { @@ -516,7 +505,7 @@ static void *broadcast_progress_thread(void __attribute__ ((__unused__)) *data) "\t\"source\": \"%s\"\r\n" "}\r\n", escaped); - broadcast(str); + broadcast(p, str); } if ((msg.cur_step != step || msg.cur_percent != percent) && @@ -538,9 +527,11 @@ static void *broadcast_progress_thread(void __attribute__ ((__unused__)) *data) msg.cur_step, escaped, msg.cur_percent); - broadcast(str); + broadcast(p, str); } } + free(p); + return NULL; } static void timer_ev_handler(void *fn_data) @@ -682,11 +673,20 @@ static void websocket_handler(struct mg_connection *nc, void *ev_data) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; mg_ws_upgrade(nc, hm, NULL); + nc->data[0] = 'W'; // Set unique Websocket marker } static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { - if (nc->data[0] != 'M' && ev == MG_EV_HTTP_MSG) { + static uint64_t last_io_time = 0; + if (ev == MG_EV_OPEN && nc->is_listening) { + struct parent_connection_info *data = calloc(2, sizeof(struct parent_connection_info)); + data[0].mgr = nc->mgr; + data[0].conn_id = nc->id; + memcpy(&data[1], &data[0], sizeof(struct parent_connection_info)); + start_thread(broadcast_message_thread, &data[0]); + start_thread(broadcast_progress_thread, &data[1]); + } else if (nc->data[0] != 'M' && nc->data[0] != 'W' && ev == MG_EV_HTTP_MSG) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (!mg_http_is_authorized(hm, global_auth_domain, global_auth_file)) mg_http_send_digest_auth_request(nc, global_auth_domain); @@ -696,7 +696,7 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) restart_handler(nc, ev_data); else mg_http_serve_dir(nc, ev_data, &s_http_server_opts); - } else if (nc->data[0] != 'M' && ev == MG_EV_READ) { + } else if (nc->data[0] != 'M' && nc->data[0] != 'W' && ev == MG_EV_READ) { struct mg_http_message hm; int hlen = mg_http_parse((char *) nc->recv.buf, nc->recv.len, &hm); if (hlen > 0) { @@ -727,6 +727,27 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) ERROR("%p %s", nc->fd, (char *) ev_data); } else if (ev == MG_EV_WS_MSG) { mg_iobuf_del(&nc->recv, 0, nc->recv.len); + } else if (ev == MG_EV_WAKEUP) { + // forward broadcast messages + struct mg_str *data = (struct mg_str *) ev_data; + struct mg_connection *t; + for (t = nc->mgr->conns; t != NULL; t = t->next) { + if (t->data[0] == 'W') { + mg_ws_send(t, data->buf, data->len, WEBSOCKET_OP_TEXT); + } + } + last_io_time = mg_millis(); + } else if (ev == MG_EV_POLL) { + // websocket heartbeat every 20s + struct mg_connection *t; + uint64_t now = *((uint64_t *)ev_data); + if (now < last_io_time + 20000) return; + for (t = nc->mgr->conns; t != NULL; t = t->next) { + if (t->data[0] == 'W') { + mg_ws_send(t, "", 0, WEBSOCKET_OP_PING); + } + } + last_io_time = now; } } @@ -908,8 +929,6 @@ int start_mongoose(const char *cfgfname, int argc, char *argv[]) signal(SIGTERM, signal_handler); mg_mgr_init(&mgr); - ws_pipe = mg_mkpipe(&mgr, broadcast_callback, NULL, true); - /* Parse url with port only fallback */ if (opts.port) { if (mg_url_port(opts.port) != 0) { @@ -934,8 +953,7 @@ int start_mongoose(const char *cfgfname, int argc, char *argv[]) exit(EXIT_FAILURE); } - start_thread(broadcast_message_thread, NULL); - start_thread(broadcast_progress_thread, NULL); + mg_wakeup_init(&mgr); INFO("Mongoose web server v%s with PID %d listening on %s and serving %s", MG_VERSION, getpid(), url, s_http_server_opts.root_dir);