MIDAS
Loading...
Searching...
No Matches
mongoose616.cxx File Reference
#include "mongoose616.h"
#include <string>
#include <regex>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <limits.h>
#include <stddef.h>
#include <sys/time.h>
#include <assert.h>
#include <ctype.h>
#include <stdlib.h>
#include <signal.h>
#include <reent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <inc/hw_types.h>
#include <inc/hw_memmap.h>
#include <driverlib/prcm.h>
#include <driverlib/rom.h>
#include <driverlib/rom_map.h>
#include <driverlib/uart.h>
#include <driverlib/utils.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Clock.h>
#include <errno.h>
#include <oslib/osi.h>
#include <stdint.h>
#include <lwip/init.h>
#include <lwip/pbuf.h>
#include <lwip/tcp.h>
#include <lwip/tcpip.h>
#include <lwip/tcp_impl.h>
#include <lwip/udp.h>
Include dependency graph for mongoose616.cxx:

Go to the source code of this file.

Classes

struct  ctl_msg
 
union  char64long16
 
struct  mg_q_msg
 
struct  mg_lwip_conn_state
 
struct  mg_lwip_netif_tcpip_call_ctx
 
struct  mg_lwip_if_connect_tcp_ctx
 
struct  mg_lwip_if_listen_ctx
 
struct  mg_lwip_tcp_write_ctx
 
struct  udp_sendto_ctx
 
struct  tcp_recved_ctx
 
struct  mg_ev_mgr_lwip_signal
 
struct  mg_ev_mgr_lwip_data
 

Macros

#define CS_MONGOOSE_SRC_INTERNAL_H_
 
#define MBUF_REALLOC   MG_REALLOC
 
#define MBUF_FREE   MG_FREE
 
#define MG_SET_PTRPTR(_ptr, _v)
 
#define MG_INTERNAL   static
 
#define MG_CTL_MSG_MESSAGE_SIZE   8192
 
#define MIN(a, b)   ((a) < (b) ? (a) : (b))
 
#define CS_COMMON_MG_MEM_H_
 
#define MG_MALLOC   malloc
 
#define MG_CALLOC   calloc
 
#define MG_REALLOC   realloc
 
#define MG_FREE   free
 
#define NUM_UPPERCASES   ('Z' - 'A' + 1)
 
#define NUM_LETTERS   (NUM_UPPERCASES * 2)
 
#define NUM_DIGITS   ('9' - '0' + 1)
 
#define BASE64_ENCODE_BODY
 
#define BASE64_OUT(ch)
 
#define BASE64_FLUSH()
 
#define CS_COMMON_CS_DBG_H_
 
#define CS_ENABLE_DEBUG   0
 
#define CS_LOG_PREFIX_LEN   24
 
#define CS_LOG_ENABLE_TS_DIFF   0
 
#define LOG(l, x)
 
#define DBG(x)
 
#define CS_COMMON_CS_DIRENT_H_
 
#define CS_COMMON_CS_ENDIAN_H_
 
#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)
 
#define SHA1HANDSOFF
 
#define rol(value, bits)   (((value) << (bits)) | ((value) >> (32 - (bits))))
 
#define blk(i)
 
#define R0(v, w, x, y, z, i)
 
#define R1(v, w, x, y, z, i)
 
#define R2(v, w, x, y, z, i)
 
#define R3(v, w, x, y, z, i)
 
#define R4(v, w, x, y, z, i)
 
#define C_DISABLE_BUILTIN_SNPRINTF   0
 
#define C_SNPRINTF_APPEND_CHAR(ch)
 
#define C_SNPRINTF_FLAG_ZERO   1
 
#define MG_MAX_HOST_LEN   200
 
#define MG_TCP_IO_SIZE   1460000
 
#define MG_UDP_IO_SIZE   1460
 
#define MG_COPY_COMMON_CONNECTION_OPTIONS(dst, src)    memcpy(dst, src, sizeof(*dst));
 
#define _MG_ALLOWED_CONNECT_FLAGS_MASK
 
#define _MG_CALLBACK_MODIFIABLE_FLAGS_MASK
 
#define intptr_t   long
 
#define CS_MONGOOSE_SRC_NET_IF_SOCKET_H_
 
#define MG_ENABLE_NET_IF_SOCKET   MG_NET_IF == MG_NET_IF_SOCKET
 
#define CS_MONGOOSE_SRC_NET_IF_SOCKS_H_
 
#define MG_NULL_IFACE_VTABLE
 
#define _MG_F_FD_CAN_READ   1
 
#define _MG_F_FD_CAN_WRITE   1 << 1
 
#define _MG_F_FD_ERROR   1 << 2
 
#define MG_SOCKET_IFACE_VTABLE
 
#define MAX(a, b)   ((a) > (b) ? (a) : (b))
 
#define CONSOLE_UART   UARTA0_BASE
 
#define CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_
 
#define CS_COMMON_PLATFORMS_SIMPLELINK_SL_NET_IF_H_
 
#define MG_ENABLE_NET_IF_SIMPLELINK   MG_NET_IF == MG_NET_IF_SIMPLELINK
 
#define MG_TCP_RECV_BUFFER_SIZE   1024
 
#define MG_UDP_RECV_BUFFER_SIZE   1500
 
#define _MG_F_FD_CAN_READ   1
 
#define _MG_F_FD_CAN_WRITE   1 << 1
 
#define _MG_F_FD_ERROR   1 << 2
 
#define MG_SL_IFACE_VTABLE
 
#define CS_COMMON_PLATFORMS_LWIP_MG_NET_IF_LWIP_H_
 
#define MG_ENABLE_NET_IF_LWIP_LOW_LEVEL   MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL
 
#define ip_2_ip4(addr)   (addr)
 
#define TCP_NEW   tcp_new
 
#define TCP_BIND   tcp_bind
 
#define UDP_BIND   udp_bind
 
#define IPADDR_NTOA   ipaddr_ntoa
 
#define SET_ADDR(dst, src)   (dst)->sin.sin_addr.s_addr = ip_2_ip4(src)->addr
 
#define mgos_lock()
 
#define mgos_unlock()
 
#define MG_LWIP_IFACE_VTABLE
 
#define MG_SIG_QUEUE_LEN   32
 
#define CS_COMMON_PLATFORMS_PIC32_NET_IF_H_
 
#define MG_ENABLE_NET_IF_PIC32   MG_NET_IF == MG_NET_IF_PIC32
 
#define MG_PIC32_IFACE_VTABLE
 

Typedefs

typedef int cs_dirent_dummy
 

Enumerations

enum  cs_log_level {
  LL_NONE = -1 , LL_ERROR = 0 , LL_WARN = 1 , LL_INFO = 2 ,
  LL_DEBUG = 3 , LL_VERBOSE_DEBUG = 4 , _LL_MIN = -2 , _LL_MAX = 5
}
 
enum  mg_q_msg_type { MG_Q_MSG_CB }
 
enum  mg_sig_type {
  MG_SIG_CONNECT_RESULT = 1 , MG_SIG_RECV = 2 , MG_SIG_CLOSE_CONN = 3 , MG_SIG_TOMBSTONE = 4 ,
  MG_SIG_ACCEPT = 5
}
 

Functions

MG_INTERNAL struct mg_connectionmg_do_connect (struct mg_connection *nc, int proto, union socket_address *sa)
 
MG_INTERNAL int mg_parse_address (const char *str, union socket_address *sa, int *proto, char *host, size_t host_len)
 
MG_INTERNAL void mg_call (struct mg_connection *nc, mg_event_handler_t ev_handler, void *user_data, int ev, void *ev_data)
 
void mg_forward (struct mg_connection *from, struct mg_connection *to)
 
MG_INTERNAL void mg_add_conn (struct mg_mgr *mgr, struct mg_connection *c)
 
MG_INTERNAL void mg_remove_conn (struct mg_connection *c)
 
MG_INTERNAL struct mg_connectionmg_create_connection (struct mg_mgr *mgr, mg_event_handler_t callback, struct mg_add_sock_opts opts)
 
MG_INTERNAL int mg_get_errno (void)
 
MG_INTERNAL void mg_close_conn (struct mg_connection *conn)
 
static void cs_base64_emit_code (struct cs_base64_ctx *ctx, int v)
 
static void cs_base64_emit_chunk (struct cs_base64_ctx *ctx)
 
void cs_base64_init (struct cs_base64_ctx *ctx, cs_base64_putc_t b64_putc, void *user_data)
 
void cs_base64_update (struct cs_base64_ctx *ctx, const char *str, size_t len)
 
void cs_base64_finish (struct cs_base64_ctx *ctx)
 
void cs_base64_encode (const unsigned char *src, int src_len, char *dst)
 
static unsigned char from_b64 (unsigned char ch)
 
int cs_base64_decode (const unsigned char *s, int len, char *dst, int *dec_len)
 
void cs_log_set_level (enum cs_log_level level)
 
void cs_log_set_file_level (const char *file_level)
 
int cs_log_print_prefix (enum cs_log_level level, const char *fname, int line)
 
double cs_time (void) WEAK
 
double cs_timegm (const struct tm *tm)
 
static void byteReverse (unsigned char *buf, unsigned longs)
 
void cs_md5_init (cs_md5_ctx *ctx)
 
static void cs_md5_transform (uint32_t buf[4], uint32_t const in[16])
 
void cs_md5_update (cs_md5_ctx *ctx, const unsigned char *buf, size_t len)
 
void cs_md5_final (unsigned char digest[16], cs_md5_ctx *ctx)
 
static uint32_t blk0 (union char64long16 *block, int i)
 
void cs_sha1_transform (uint32_t state[5], const unsigned char buffer[64])
 
void cs_sha1_init (cs_sha1_ctx *context)
 
void cs_sha1_update (cs_sha1_ctx *context, const unsigned char *data, uint32_t len)
 
void cs_sha1_final (unsigned char digest[20], cs_sha1_ctx *context)
 
void cs_hmac_sha1 (const unsigned char *key, size_t keylen, const unsigned char *data, size_t datalen, unsigned char out[20])
 
void mbuf_init (struct mbuf *mbuf, size_t initial_size) WEAK
 
void mbuf_free (struct mbuf *mbuf) WEAK
 
void mbuf_resize (struct mbuf *a, size_t new_size) WEAK
 
void mbuf_trim (struct mbuf *mbuf) WEAK
 
size_t mbuf_insert (struct mbuf *a, size_t off, const void *buf, size_t) WEAK
 
size_t mbuf_append (struct mbuf *a, const void *buf, size_t len) WEAK
 
size_t mbuf_append_and_free (struct mbuf *a, void *buf, size_t len) WEAK
 
void mbuf_remove (struct mbuf *mb, size_t n) WEAK
 
void mbuf_clear (struct mbuf *mb) WEAK
 
void mbuf_move (struct mbuf *from, struct mbuf *to) WEAK
 
int mg_ncasecmp (const char *s1, const char *s2, size_t len) WEAK
 
struct mg_str mg_mk_str (const char *s) WEAK
 
struct mg_str mg_mk_str_n (const char *s, size_t len) WEAK
 
int mg_vcmp (const struct mg_str *str1, const char *str2) WEAK
 
int mg_vcasecmp (const struct mg_str *str1, const char *str2) WEAK
 
static struct mg_str mg_strdup_common (const struct mg_str s, int nul_terminate)
 
struct mg_str mg_strdup (const struct mg_str s) WEAK
 
struct mg_str mg_strdup_nul (const struct mg_str s) WEAK
 
const charmg_strchr (const struct mg_str s, int c) WEAK
 
int mg_strcmp (const struct mg_str str1, const struct mg_str str2) WEAK
 
int mg_strncmp (const struct mg_str, const struct mg_str, size_t n) WEAK
 
void mg_strfree (struct mg_str *s) WEAK
 
const charmg_strstr (const struct mg_str haystack, const struct mg_str needle) WEAK
 
struct mg_str mg_strstrip (struct mg_str s) WEAK
 
int mg_str_starts_with (struct mg_str s, struct mg_str prefix) WEAK
 
size_t c_strnlen (const char *s, size_t maxlen) WEAK
 
static int c_itoa (char *buf, size_t buf_size, int64_t num, int base, int flags, int field_width)
 
int c_vsnprintf (char *buf, size_t buf_size, const char *fmt, va_list ap) WEAK
 
int c_snprintf (char *buf, size_t buf_size, const char *fmt,...) WEAK
 
const charc_strnstr (const char *s, const char *find, size_t slen) WEAK
 
void cs_to_hex (char *to, const unsigned char *p, size_t len) WEAK
 
static int fourbit (int ch)
 
void cs_from_hex (char *to, const char *p, size_t len) WEAK
 
static int str_util_lowercase (const char *s)
 
int mg_casecmp (const char *s1, const char *s2) WEAK
 
int mg_asprintf (char **buf, size_t size, const char *fmt,...) WEAK
 
int mg_avprintf (char **buf, size_t size, const char *fmt, va_list ap) WEAK
 
const charmg_next_comma_list_entry (const char *, struct mg_str *, struct mg_str *) WEAK
 
struct mg_str mg_next_comma_list_entry_n (struct mg_str list, struct mg_str *val, struct mg_str *eq_val) WEAK
 
size_t mg_match_prefix_n (const struct mg_str, const struct mg_str) WEAK
 
size_t mg_match_prefix (const char *, int, const char *) WEAK
 
MG_INTERNAL void mg_timer (struct mg_connection *c, double now)
 
MG_INTERNAL size_t recv_avail_size (struct mg_connection *conn, size_t max)
 
static int mg_do_recv (struct mg_connection *nc)
 
int mg_if_poll (struct mg_connection *nc, double now)
 
void mg_destroy_conn (struct mg_connection *conn, int destroy_if)
 
void mg_mgr_init (struct mg_mgr *m, void *user_data)
 
void mg_mgr_init_opt (struct mg_mgr *m, void *user_data, struct mg_mgr_init_opts opts)
 
void mg_mgr_free (struct mg_mgr *m)
 
int mg_mgr_poll (struct mg_mgr *m, int timeout_ms)
 
int mg_vprintf (struct mg_connection *nc, const char *fmt, va_list ap)
 
int mg_printf (struct mg_connection *conn, const char *fmt,...)
 
MG_INTERNAL struct mg_connectionmg_create_connection_base (struct mg_mgr *mgr, mg_event_handler_t callback, struct mg_add_sock_opts opts)
 
struct mg_connectionmg_if_accept_new_conn (struct mg_connection *lc)
 
void mg_if_accept_tcp_cb (struct mg_connection *nc, union socket_address *sa, size_t sa_len)
 
void mg_send (struct mg_connection *nc, const void *buf, int len)
 
static int mg_recv_tcp (struct mg_connection *nc, char *buf, size_t len)
 
static int mg_recv_udp (struct mg_connection *nc, char *buf, size_t len)
 
void mg_if_can_recv_cb (struct mg_connection *nc)
 
void mg_if_can_send_cb (struct mg_connection *nc)
 
void mg_if_connect_cb (struct mg_connection *nc, int err)
 
struct mg_connectionmg_connect (struct mg_mgr *mgr, const char *address, MG_CB(mg_event_handler_t callback, void *user_data))
 
void mg_ev_handler_empty (struct mg_connection *c, int ev, void *ev_data MG_UD_ARG(void *user_data))
 
struct mg_connectionmg_connect_opt (struct mg_mgr *mgr, const char *address, MG_CB(mg_event_handler_t callback, void *user_data), struct mg_connect_opts opts)
 
struct mg_connectionmg_bind (struct mg_mgr *srv, const char *address, MG_CB(mg_event_handler_t event_handler, void *user_data))
 
struct mg_connectionmg_bind_opt (struct mg_mgr *mgr, const char *address, MG_CB(mg_event_handler_t callback, void *user_data), struct mg_bind_opts opts)
 
struct mg_connectionmg_next (struct mg_mgr *s, struct mg_connection *conn)
 
static int isbyte (int n)
 
static int parse_net (const char *spec, uint32_t *net, uint32_t *mask)
 
int mg_check_ip_acl (const char *acl, uint32_t remote_ip)
 
double mg_set_timer (struct mg_connection *c, double timestamp)
 
void mg_sock_set (struct mg_connection *nc, sock_t sock)
 
void mg_if_get_conn_addr (struct mg_connection *nc, int remote, union socket_address *sa)
 
struct mg_connectionmg_add_sock_opt (struct mg_mgr *s, sock_t sock, MG_CB(mg_event_handler_t callback, void *user_data), struct mg_add_sock_opts opts)
 
struct mg_connectionmg_add_sock (struct mg_mgr *s, sock_t sock, MG_CB(mg_event_handler_t callback, void *user_data))
 
double mg_time (void)
 
struct mg_ifacemg_if_create_iface (const struct mg_iface_vtable *vtable, struct mg_mgr *mgr)
 
struct mg_ifacemg_find_iface (struct mg_mgr *mgr, const struct mg_iface_vtable *vtable, struct mg_iface *from)
 
double mg_mgr_min_timer (const struct mg_mgr *mgr)
 
static void mg_null_if_connect_tcp (struct mg_connection *c, const union socket_address *sa)
 
static void mg_null_if_connect_udp (struct mg_connection *c)
 
static int mg_null_if_listen_tcp (struct mg_connection *c, union socket_address *sa)
 
static int mg_null_if_listen_udp (struct mg_connection *c, union socket_address *sa)
 
static int mg_null_if_tcp_send (struct mg_connection *c, const void *buf, size_t len)
 
static int mg_null_if_udp_send (struct mg_connection *c, const void *buf, size_t len)
 
int mg_null_if_tcp_recv (struct mg_connection *c, void *buf, size_t len)
 
int mg_null_if_udp_recv (struct mg_connection *c, void *buf, size_t len, union socket_address *sa, size_t *sa_len)
 
static int mg_null_if_create_conn (struct mg_connection *c)
 
static void mg_null_if_destroy_conn (struct mg_connection *c)
 
static void mg_null_if_sock_set (struct mg_connection *c, sock_t sock)
 
static void mg_null_if_init (struct mg_iface *iface)
 
static void mg_null_if_free (struct mg_iface *iface)
 
static void mg_null_if_add_conn (struct mg_connection *c)
 
static void mg_null_if_remove_conn (struct mg_connection *c)
 
static time_t mg_null_if_poll (struct mg_iface *iface, int timeout_ms)
 
static void mg_null_if_get_conn_addr (struct mg_connection *c, int remote, union socket_address *sa)
 
static sock_t mg_open_listening_socket (union socket_address *sa, int type, int proto)
 
void mg_set_non_blocking_mode (sock_t sock)
 
static int mg_is_error (void)
 
void mg_socket_if_connect_tcp (struct mg_connection *nc, const union socket_address *sa)
 
void mg_socket_if_connect_udp (struct mg_connection *nc)
 
int mg_socket_if_listen_tcp (struct mg_connection *nc, union socket_address *sa)
 
static int mg_socket_if_listen_udp (struct mg_connection *nc, union socket_address *sa)
 
static int mg_socket_if_tcp_send (struct mg_connection *nc, const void *buf, size_t len)
 
static int mg_socket_if_udp_send (struct mg_connection *nc, const void *buf, size_t len)
 
static int mg_socket_if_tcp_recv (struct mg_connection *nc, void *buf, size_t len)
 
static int mg_socket_if_udp_recv (struct mg_connection *nc, void *buf, size_t len, union socket_address *sa, size_t *sa_len)
 
int mg_socket_if_create_conn (struct mg_connection *nc)
 
void mg_socket_if_destroy_conn (struct mg_connection *nc)
 
static int mg_accept_conn (struct mg_connection *lc)
 
void mg_mgr_handle_conn (struct mg_connection *nc, int fd_flags, double now)
 
void mg_socket_if_sock_set (struct mg_connection *nc, sock_t sock)
 
void mg_socket_if_init (struct mg_iface *iface)
 
void mg_socket_if_free (struct mg_iface *iface)
 
void mg_socket_if_add_conn (struct mg_connection *nc)
 
void mg_socket_if_remove_conn (struct mg_connection *nc)
 
void mg_add_to_set (sock_t sock, fd_set *set, sock_t *max_fd)
 
time_t mg_socket_if_poll (struct mg_iface *iface, int timeout_ms)
 
static void mg_sock_get_addr (sock_t sock, int remote, union socket_address *sa)
 
void mg_sock_to_str (sock_t sock, char *buf, size_t len, int flags)
 
void mg_socket_if_get_conn_addr (struct mg_connection *nc, int remote, union socket_address *sa)
 
static void parse_uri_component (const char **p, const char *end, const char *seps, struct mg_str *res)
 
int mg_parse_uri (const struct mg_str uri, struct mg_str *scheme, struct mg_str *user_info, struct mg_str *host, unsigned int *port, struct mg_str *path, struct mg_str *query, struct mg_str *fragment)
 
int mg_normalize_uri_path (const struct mg_str *in, struct mg_str *out)
 
int mg_assemble_uri (const struct mg_str *scheme, const struct mg_str *user_info, const struct mg_str *host, unsigned int port, const struct mg_str *path, const struct mg_str *query, const struct mg_str *fragment, int normalize_path, struct mg_str *uri)
 
const charmg_skip (const char *s, const char *end, const char *delims, struct mg_str *v)
 
void mg_base64_encode (const unsigned char *src, int src_len, char *dst)
 
int mg_base64_decode (const unsigned char *s, int len, char *dst)
 
void mg_set_close_on_exec (sock_t sock)
 
int mg_sock_addr_to_str (const union socket_address *sa, char *buf, size_t len, int flags)
 
int mg_conn_addr_to_str (struct mg_connection *nc, char *buf, size_t len, int flags)
 
int mg_is_big_endian (void)
 
void mg_mbuf_append_base64_putc (char ch, void *user_data)
 
void mg_mbuf_append_base64 (struct mbuf *mbuf, const void *data, size_t len)
 
void mg_basic_auth_header (const struct mg_str user, const struct mg_str pass, struct mbuf *buf)
 
struct mg_str mg_url_encode_opt (const struct mg_str src, const struct mg_str safe, unsigned int flags)
 
struct mg_str mg_url_encode (const struct mg_str src)
 
void fprint_str (FILE *fp, const char *str)
 
void _exit (int status)
 
void _not_implemented (const char *what)
 
int _kill (int pid, int sig)
 
int _getpid ()
 
int _isatty (int fd)
 
int gettimeofday (struct timeval *tp, void *tzp)
 
const charinet_ntop (int af, const void *src, char *dst, socklen_t size)
 
charinet_ntoa (struct in_addr n)
 
int inet_pton (int af, const char *src, void *dst)
 
static void mg_task (void *arg)
 
bool mg_start_task (int priority, int stack_size, mg_init_cb mg_init)
 
void mg_run_in_task (void(*cb)(struct mg_mgr *mgr, void *arg), void *cb_arg)
 
static sock_t mg_open_listening_socket (struct mg_connection *nc, union socket_address *sa, int type, int proto)
 
static int mg_is_error (int n)
 
static void mg_sl_if_connect_tcp (struct mg_connection *nc, const union socket_address *sa)
 
static void mg_sl_if_connect_udp (struct mg_connection *nc)
 
static int mg_sl_if_listen_tcp (struct mg_connection *nc, union socket_address *sa)
 
static int mg_sl_if_listen_udp (struct mg_connection *nc, union socket_address *sa)
 
static int mg_sl_if_tcp_send (struct mg_connection *nc, const void *buf, size_t len)
 
static int mg_sl_if_udp_send (struct mg_connection *nc, const void *buf, size_t len)
 
static int mg_sl_if_tcp_recv (struct mg_connection *nc, void *buf, size_t len)
 
static int mg_sl_if_udp_recv (struct mg_connection *nc, void *buf, size_t len, union socket_address *sa, size_t *sa_len)
 
static int mg_sl_if_create_conn (struct mg_connection *nc)
 
void mg_sl_if_destroy_conn (struct mg_connection *nc)
 
void mg_sl_if_sock_set (struct mg_connection *nc, sock_t sock)
 
void mg_sl_if_init (struct mg_iface *iface)
 
void mg_sl_if_free (struct mg_iface *iface)
 
void mg_sl_if_add_conn (struct mg_connection *nc)
 
void mg_sl_if_remove_conn (struct mg_connection *nc)
 
time_t mg_sl_if_poll (struct mg_iface *iface, int timeout_ms)
 
void mg_sl_if_get_conn_addr (struct mg_connection *nc, int remote, union socket_address *sa)
 
void sl_restart_cb (struct mg_mgr *mgr)
 
void mg_lwip_post_signal (enum mg_sig_type sig, struct mg_connection *nc)
 
void mg_lwip_mgr_schedule_poll (struct mg_mgr *mgr)
 
static void xxx_tcpip (void *arg)
 
void mg_lwip_netif_run_on_tcpip (void(*fn)(void *), void *arg)
 
void mg_lwip_if_init (struct mg_iface *iface)
 
void mg_lwip_if_free (struct mg_iface *iface)
 
void mg_lwip_if_add_conn (struct mg_connection *nc)
 
void mg_lwip_if_remove_conn (struct mg_connection *nc)
 
time_t mg_lwip_if_poll (struct mg_iface *iface, int timeout_ms)
 
static void mg_lwip_recv_common (struct mg_connection *nc, struct pbuf *p)
 
static err_t mg_lwip_tcp_conn_cb (void *arg, struct tcp_pcb *tpcb, err_t err)
 
static void mg_lwip_tcp_error_cb (void *arg, err_t err)
 
static err_t mg_lwip_tcp_recv_cb (void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
 
static err_t mg_lwip_tcp_sent_cb (void *arg, struct tcp_pcb *tpcb, u16_t num_sent)
 
static void mg_lwip_if_connect_tcp_tcpip (void *arg)
 
void mg_lwip_if_connect_tcp (struct mg_connection *nc, const union socket_address *sa)
 
static void mg_lwip_udp_recv_cb (void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
 
static int mg_lwip_if_udp_recv (struct mg_connection *nc, void *buf, size_t len, union socket_address *sa, size_t *sa_len)
 
static void mg_lwip_if_connect_udp_tcpip (void *arg)
 
void mg_lwip_if_connect_udp (struct mg_connection *nc)
 
static void tcp_close_tcpip (void *arg)
 
void mg_lwip_handle_accept (struct mg_connection *nc)
 
static err_t mg_lwip_accept_cb (void *arg, struct tcp_pcb *newtpcb, err_t err)
 
static void mg_lwip_if_listen_tcp_tcpip (void *arg)
 
int mg_lwip_if_listen_tcp (struct mg_connection *nc, union socket_address *sa)
 
static void mg_lwip_if_listen_udp_tcpip (void *arg)
 
int mg_lwip_if_listen_udp (struct mg_connection *nc, union socket_address *sa)
 
static void tcp_output_tcpip (void *arg)
 
static void mg_lwip_tcp_write_tcpip (void *arg)
 
int mg_lwip_if_tcp_send (struct mg_connection *nc, const void *buf, size_t len)
 
static void udp_sendto_tcpip (void *arg)
 
static int mg_lwip_if_udp_send (struct mg_connection *nc, const void *data, size_t len)
 
static int mg_lwip_if_can_send (struct mg_connection *nc, struct mg_lwip_conn_state *cs)
 
void tcp_recved_tcpip (void *arg)
 
static int mg_lwip_if_tcp_recv (struct mg_connection *nc, void *buf, size_t len)
 
int mg_lwip_if_create_conn (struct mg_connection *nc)
 
static void udp_remove_tcpip (void *arg)
 
void mg_lwip_if_destroy_conn (struct mg_connection *nc)
 
void mg_lwip_if_get_conn_addr (struct mg_connection *nc, int remote, union socket_address *sa)
 
void mg_lwip_if_sock_set (struct mg_connection *nc, sock_t sock)
 
void mg_ev_mgr_lwip_process_signals (struct mg_mgr *mgr)
 
int mg_pic32_if_create_conn (struct mg_connection *nc)
 
void mg_pic32_if_recved (struct mg_connection *nc, size_t len)
 
void mg_pic32_if_add_conn (struct mg_connection *nc)
 
void mg_pic32_if_init (struct mg_iface *iface)
 
void mg_pic32_if_free (struct mg_iface *iface)
 
void mg_pic32_if_remove_conn (struct mg_connection *nc)
 
void mg_pic32_if_destroy_conn (struct mg_connection *nc)
 
int mg_pic32_if_listen_udp (struct mg_connection *nc, union socket_address *sa)
 
void mg_pic32_if_udp_send (struct mg_connection *nc, const void *buf, size_t len)
 
void mg_pic32_if_tcp_send (struct mg_connection *nc, const void *buf, size_t len)
 
int mg_pic32_if_listen_tcp (struct mg_connection *nc, union socket_address *sa)
 
static void mg_handle_send (struct mg_connection *nc)
 
static void mg_handle_recv (struct mg_connection *nc)
 
time_t mg_pic32_if_poll (struct mg_iface *iface, int timeout_ms)
 
void mg_pic32_if_sock_set (struct mg_connection *nc, sock_t sock)
 
void mg_pic32_if_get_conn_addr (struct mg_connection *nc, int remote, union socket_address *sa)
 
void mg_pic32_if_connect_tcp (struct mg_connection *nc, const union socket_address *sa)
 
void mg_pic32_if_connect_udp (struct mg_connection *nc)
 

Variables

void *(* test_malloc )(size_t size)
 
void *(* test_calloc )(size_t count, size_t size)
 
enum cs_log_level cs_log_level
 
enum cs_log_level cs_log_level WEAK
 
const struct mg_iface_vtable mg_socket_iface_vtable = MG_SOCKET_IFACE_VTABLE
 
const struct mg_iface_vtable mg_default_iface_vtable = MG_NULL_IFACE_VTABLE
 
const struct mg_iface_vtablemg_ifaces []
 
int mg_num_ifaces = (int) (sizeof(mg_ifaces) / sizeof(mg_ifaces[0]))
 
static OsiMsgQ_t s_mg_q
 
const struct mg_iface_vtable mg_simplelink_iface_vtable = MG_SL_IFACE_VTABLE
 
const struct mg_iface_vtable mg_lwip_iface_vtable = MG_LWIP_IFACE_VTABLE
 
static sys_sem_t s_tcpip_call_lock_sem = NULL
 
static sys_sem_t s_tcpip_call_sync_sem = NULL
 
const struct mg_iface_vtable mg_pic32_iface_vtable = MG_PIC32_IFACE_VTABLE
 

Macro Definition Documentation

◆ _MG_ALLOWED_CONNECT_FLAGS_MASK

#define _MG_ALLOWED_CONNECT_FLAGS_MASK
Value:
#define MG_F_USER_6
Definition mongoose6.h:1298
#define MG_F_USER_2
Definition mongoose6.h:1294
#define MG_F_USER_4
Definition mongoose6.h:1296
#define MG_F_WEBSOCKET_NO_DEFRAG
Definition mongoose6.h:1290
#define MG_F_USER_1
Definition mongoose6.h:1293
#define MG_F_USER_5
Definition mongoose6.h:1297
#define MG_F_USER_3
Definition mongoose6.h:1295
#define MG_F_ENABLE_BROADCAST

Definition at line 2408 of file mongoose616.cxx.

2421 {
2422 DBG(("%p %p", mgr, c));
2423 c->mgr = mgr;
2424 c->next = mgr->active_connections;
2425 mgr->active_connections = c;
2426 c->prev = NULL;
2427 if (c->next != NULL) c->next->prev = c;
2428 if (c->sock != INVALID_SOCKET) {
2429 c->iface->vtable->add_conn(c);
2430 }
2431}
2432
2433MG_INTERNAL void mg_remove_conn(struct mg_connection *conn) {
2434 if (conn->prev == NULL) conn->mgr->active_connections = conn->next;
2435 if (conn->prev) conn->prev->next = conn->next;
2436 if (conn->next) conn->next->prev = conn->prev;
2437 conn->prev = conn->next = NULL;
2438 conn->iface->vtable->remove_conn(conn);
2439}
2440
2441MG_INTERNAL void mg_call(struct mg_connection *nc,
2442 mg_event_handler_t ev_handler, void *user_data, int ev,
2443 void *ev_data) {
2444 if (ev_handler == NULL) {
2445 /*
2446 * If protocol handler is specified, call it. Otherwise, call user-specified
2447 * event handler.
2448 */
2450 }
2451 if (ev != MG_EV_POLL) {
2452 DBG(("%p %s ev=%d ev_data=%p flags=0x%lx rmbl=%d smbl=%d", nc,
2453 ev_handler == nc->handler ? "user" : "proto", ev, ev_data, nc->flags,
2454 (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
2455 }
2456
2457#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
2458 if (nc->mgr->hexdump_file != NULL && ev != MG_EV_POLL && ev != MG_EV_RECV &&
2459 ev != MG_EV_SEND /* handled separately */) {
2461 }
2462#endif
2463 if (ev_handler != NULL) {
2464 unsigned long flags_before = nc->flags;
2465 ev_handler(nc, ev, ev_data MG_UD_ARG(user_data));
2466 /* Prevent user handler from fiddling with system flags. */
2467 if (ev_handler == nc->handler && nc->flags != flags_before) {
2470 }
2471 }
2472 if (ev != MG_EV_POLL) nc->mgr->num_calls++;
2473 if (ev != MG_EV_POLL) {
2474 DBG(("%p after %s flags=0x%lx rmbl=%d smbl=%d", nc,
2475 ev_handler == nc->handler ? "user" : "proto", nc->flags,
2476 (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
2477 }
2478#if !MG_ENABLE_CALLBACK_USERDATA
2479 (void) user_data;
2480#endif
2481}
2482
2483MG_INTERNAL void mg_timer(struct mg_connection *c, double now) {
2484 if (c->ev_timer_time > 0 && now >= c->ev_timer_time) {
2485 double old_value = c->ev_timer_time;
2486 c->ev_timer_time = 0;
2487 mg_call(c, NULL, c->user_data, MG_EV_TIMER, &old_value);
2488 }
2489}
2490
2491MG_INTERNAL size_t recv_avail_size(struct mg_connection *conn, size_t max) {
2492 size_t avail;
2493 if (conn->recv_mbuf_limit < conn->recv_mbuf.len) return 0;
2494 avail = conn->recv_mbuf_limit - conn->recv_mbuf.len;
2495 return avail > max ? max : avail;
2496}
2497
2498static int mg_do_recv(struct mg_connection *nc);
2499
2500int mg_if_poll(struct mg_connection *nc, double now) {
2501 if (nc->flags & MG_F_CLOSE_IMMEDIATELY) {
2502 mg_close_conn(nc);
2503 return 0;
2504 } else if (nc->flags & MG_F_SEND_AND_CLOSE) {
2505 if (nc->send_mbuf.len == 0) {
2507 mg_close_conn(nc);
2508 return 0;
2509 }
2510 } else if (nc->flags & MG_F_RECV_AND_CLOSE) {
2511 mg_close_conn(nc);
2512 return 0;
2513 }
2514#if MG_ENABLE_SSL
2515 if ((nc->flags & (MG_F_SSL | MG_F_LISTENING | MG_F_CONNECTING)) == MG_F_SSL) {
2516 /* SSL library may have data to be delivered to the app in its buffers,
2517 * drain them. */
2518 int recved = 0;
2519 do {
2520 if (nc->flags & (MG_F_WANT_READ | MG_F_WANT_WRITE)) break;
2521 if (recv_avail_size(nc, MG_TCP_IO_SIZE) <= 0) break;
2522 recved = mg_do_recv(nc);
2523 } while (recved > 0);
2524 }
2525#endif /* MG_ENABLE_SSL */
2526 mg_timer(nc, now);
2527 {
2528 time_t now_t = (time_t) now;
2529 mg_call(nc, NULL, nc->user_data, MG_EV_POLL, &now_t);
2530 }
2531 return 1;
2532}
2533
2534void mg_destroy_conn(struct mg_connection *conn, int destroy_if) {
2535 if (conn->sock != INVALID_SOCKET) { /* Don't print timer-only conns */
2536 LOG(LL_DEBUG, ("%p 0x%lx %d", conn, conn->flags, destroy_if));
2537 }
2538 if (destroy_if) conn->iface->vtable->destroy_conn(conn);
2539 if (conn->proto_data != NULL && conn->proto_data_destructor != NULL) {
2540 conn->proto_data_destructor(conn->proto_data);
2541 }
2542#if MG_ENABLE_SSL
2543 mg_ssl_if_conn_free(conn);
2544#endif
2545 mbuf_free(&conn->recv_mbuf);
2546 mbuf_free(&conn->send_mbuf);
2547
2548 memset(conn, 0, sizeof(*conn));
2549 MG_FREE(conn);
2550}
2551
2552void mg_close_conn(struct mg_connection *conn) {
2553 /* See if there's any remaining data to deliver. Skip if user completely
2554 * throttled the connection there will be no progress anyway. */
2555 if (conn->sock != INVALID_SOCKET && mg_do_recv(conn) == -2) {
2556 /* Receive is throttled, wait. */
2557 conn->flags |= MG_F_RECV_AND_CLOSE;
2558 return;
2559 }
2560#if MG_ENABLE_SSL
2561 if (conn->flags & MG_F_SSL_HANDSHAKE_DONE) {
2563 }
2564#endif
2565 /*
2566 * Clearly mark the connection as going away (if not already).
2567 * Some net_if impls (LwIP) need this for cleanly handling half-dead conns.
2568 */
2570 mg_remove_conn(conn);
2571 conn->iface->vtable->destroy_conn(conn);
2572 mg_call(conn, NULL, conn->user_data, MG_EV_CLOSE, NULL);
2573 mg_destroy_conn(conn, 0 /* destroy_if */);
2574}
2575
2576void mg_mgr_init(struct mg_mgr *m, void *user_data) {
2577 struct mg_mgr_init_opts opts;
2578 memset(&opts, 0, sizeof(opts));
2579 mg_mgr_init_opt(m, user_data, opts);
2580}
2581
2582void mg_mgr_init_opt(struct mg_mgr *m, void *user_data,
2583 struct mg_mgr_init_opts opts) {
2584 memset(m, 0, sizeof(*m));
2585#if MG_ENABLE_BROADCAST
2586 m->ctl[0] = m->ctl[1] = INVALID_SOCKET;
2587#endif
2588 m->user_data = user_data;
2589
2590#ifdef _WIN32
2591 {
2592 WSADATA data;
2593 WSAStartup(MAKEWORD(2, 2), &data);
2594 }
2595#elif defined(__unix__)
2596 /* Ignore SIGPIPE signal, so if client cancels the request, it
2597 * won't kill the whole process. */
2599#endif
2600
2601 {
2602 int i;
2603 if (opts.num_ifaces == 0) {
2604 opts.num_ifaces = mg_num_ifaces;
2605 opts.ifaces = mg_ifaces;
2606 }
2607 if (opts.main_iface != NULL) {
2608 opts.ifaces[MG_MAIN_IFACE] = opts.main_iface;
2609 }
2610 m->num_ifaces = opts.num_ifaces;
2611 m->ifaces =
2612 (struct mg_iface **) MG_MALLOC(sizeof(*m->ifaces) * opts.num_ifaces);
2613 for (i = 0; i < opts.num_ifaces; i++) {
2614 m->ifaces[i] = mg_if_create_iface(opts.ifaces[i], m);
2615 m->ifaces[i]->vtable->init(m->ifaces[i]);
2616 }
2617 }
2618 if (opts.nameserver != NULL) {
2619 m->nameserver = strdup(opts.nameserver);
2620 }
2621 DBG(("=================================="));
2622 DBG(("init mgr=%p", m));
2623#if MG_ENABLE_SSL
2624 {
2625 static int init_done;
2626 if (!init_done) {
2628 init_done++;
2629 }
2630 }
2631#endif
2632}
2633
2634void mg_mgr_free(struct mg_mgr *m) {
2635 struct mg_connection *conn, *tmp_conn;
2636
2637 DBG(("%p", m));
2638 if (m == NULL) return;
2639 /* Do one last poll, see https://github.com/cesanta/mongoose/issues/286 */
2640 mg_mgr_poll(m, 0);
2641
2642#if MG_ENABLE_BROADCAST
2643 if (m->ctl[0] != INVALID_SOCKET) closesocket(m->ctl[0]);
2644 if (m->ctl[1] != INVALID_SOCKET) closesocket(m->ctl[1]);
2645 m->ctl[0] = m->ctl[1] = INVALID_SOCKET;
2646#endif
2647
2648 for (conn = m->active_connections; conn != NULL; conn = tmp_conn) {
2649 tmp_conn = conn->next;
2651 mg_close_conn(conn);
2652 }
2653
2654 {
2655 int i;
2656 for (i = 0; i < m->num_ifaces; i++) {
2657 m->ifaces[i]->vtable->free(m->ifaces[i]);
2658 MG_FREE(m->ifaces[i]);
2659 }
2660 MG_FREE(m->ifaces);
2661 }
2662
2663 MG_FREE((char *) m->nameserver);
2664}
2665
2666int mg_mgr_poll(struct mg_mgr *m, int timeout_ms) {
2667 int i, num_calls_before = m->num_calls;
2668
2669 for (i = 0; i < m->num_ifaces; i++) {
2670 m->ifaces[i]->vtable->poll(m->ifaces[i], timeout_ms);
2671 }
2672
2673 return (m->num_calls - num_calls_before);
2674}
2675
2676int mg_vprintf(struct mg_connection *nc, const char *fmt, va_list ap) {
2678 int len;
2679
2680 if ((len = mg_avprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
2681 mg_send(nc, buf, len);
2682 }
2683 if (buf != mem && buf != NULL) {
2684 MG_FREE(buf); /* LCOV_EXCL_LINE */
2685 } /* LCOV_EXCL_LINE */
2686
2687 return len;
2688}
2689
2690int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
2691 int len;
2692 va_list ap;
2693 va_start(ap, fmt);
2694 len = mg_vprintf(conn, fmt, ap);
2695 va_end(ap);
2696 return len;
2697}
2698
2699#if MG_ENABLE_SYNC_RESOLVER
2700/* TODO(lsm): use non-blocking resolver */
2701static int mg_resolve2(const char *host, struct in_addr *ina) {
2702#if MG_ENABLE_GETADDRINFO
2703 int rv = 0;
2704 struct addrinfo hints, *servinfo, *p;
2705 struct sockaddr_in *h = NULL;
2706 memset(&hints, 0, sizeof hints);
2707 hints.ai_family = AF_INET;
2708 hints.ai_socktype = SOCK_STREAM;
2709 if ((rv = getaddrinfo(host, NULL, NULL, &servinfo)) != 0) {
2710 DBG(("getaddrinfo(%s) failed: %s", host, strerror(mg_get_errno())));
2711 return 0;
2712 }
2713 for (p = servinfo; p != NULL; p = p->ai_next) {
2714 memcpy(&h, &p->ai_addr, sizeof(h));
2715 memcpy(ina, &h->sin_addr, sizeof(*ina));
2716 }
2718 return 1;
2719#else
2720 struct hostent *he;
2721 if ((he = gethostbyname(host)) == NULL) {
2722 DBG(("gethostbyname(%s) failed: %s", host, strerror(mg_get_errno())));
2723 } else {
2724 memcpy(ina, he->h_addr_list[0], sizeof(*ina));
2725 return 1;
2726 }
2727 return 0;
2728#endif /* MG_ENABLE_GETADDRINFO */
2729}
2730
2731int mg_resolve(const char *host, char *buf, size_t n) {
2732 struct in_addr ad;
2733 return mg_resolve2(host, &ad) ? snprintf(buf, n, "%s", inet_ntoa(ad)) : 0;
2734}
2735#endif /* MG_ENABLE_SYNC_RESOLVER */
2736
2739 struct mg_add_sock_opts opts) {
2740 struct mg_connection *conn;
2741
2742 if ((conn = (struct mg_connection *) MG_CALLOC(1, sizeof(*conn))) != NULL) {
2743 conn->sock = INVALID_SOCKET;
2744 conn->handler = callback;
2745 conn->mgr = mgr;
2746 conn->last_io_time = (time_t) mg_time();
2747 conn->iface =
2748 (opts.iface != NULL ? opts.iface : mgr->ifaces[MG_MAIN_IFACE]);
2750 conn->user_data = opts.user_data;
2751 /*
2752 * SIZE_MAX is defined as a long long constant in
2753 * system headers on some platforms and so it
2754 * doesn't compile with pedantic ansi flags.
2755 */
2756 conn->recv_mbuf_limit = ~0;
2757 } else {
2758 MG_SET_PTRPTR(opts.error_string, "failed to create connection");
2759 }
2760
2761 return conn;
2762}
2763
2766 struct mg_add_sock_opts opts) {
2768
2769 if (conn != NULL && !conn->iface->vtable->create_conn(conn)) {
2770 MG_FREE(conn);
2771 conn = NULL;
2772 }
2773 if (conn == NULL) {
2774 MG_SET_PTRPTR(opts.error_string, "failed to init connection");
2775 }
2776
2777 return conn;
2778}
2779
2780/*
2781 * Address format: [PROTO://][HOST]:PORT
2782 *
2783 * HOST could be IPv4/IPv6 address or a host name.
2784 * `host` is a destination buffer to hold parsed HOST part. Should be at least
2785 * MG_MAX_HOST_LEN bytes long.
2786 * `proto` is a returned socket type, either SOCK_STREAM or SOCK_DGRAM
2787 *
2788 * Return:
2789 * -1 on parse error
2790 * 0 if HOST needs DNS lookup
2791 * >0 length of the address string
2792 */
2793MG_INTERNAL int mg_parse_address(const char *str, union socket_address *sa,
2794 int *proto, char *host, size_t host_len) {
2795 unsigned int a, b, c, d, port = 0;
2796 int ch, len = 0;
2797#if MG_ENABLE_IPV6
2798 char buf[100];
2799#endif
2800
2801 /*
2802 * MacOS needs that. If we do not zero it, subsequent bind() will fail.
2803 * Also, all-zeroes in the socket address means binding to all addresses
2804 * for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT).
2805 */
2806 memset(sa, 0, sizeof(*sa));
2807 sa->sin.sin_family = AF_INET;
2808
2809 *proto = SOCK_STREAM;
2810
2811 if (strncmp(str, "udp://", 6) == 0) {
2812 str += 6;
2813 *proto = SOCK_DGRAM;
2814 } else if (strncmp(str, "tcp://", 6) == 0) {
2815 str += 6;
2816 }
2817
2818 if (sscanf(str, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len) == 5) {
2819 /* Bind to a specific IPv4 address, e.g. 192.168.1.5:8080 */
2820 sa->sin.sin_addr.s_addr =
2821 htonl(((uint32_t) a << 24) | ((uint32_t) b << 16) | c << 8 | d);
2822 sa->sin.sin_port = htons((uint16_t) port);
2823#if MG_ENABLE_IPV6
2824 } else if (sscanf(str, "[%99[^]]]:%u%n", buf, &port, &len) == 2 &&
2825 inet_pton(AF_INET6, buf, &sa->sin6.sin6_addr)) {
2826 /* IPv6 address, e.g. [3ffe:2a00:100:7031::1]:8080 */
2827 sa->sin6.sin6_family = AF_INET6;
2828 sa->sin.sin_port = htons((uint16_t) port);
2829#endif
2830#if MG_ENABLE_ASYNC_RESOLVER
2831 } else if (strlen(str) < host_len &&
2832 sscanf(str, "%[^ :]:%u%n", host, &port, &len) == 2) {
2833 sa->sin.sin_port = htons((uint16_t) port);
2834 if (mg_resolve_from_hosts_file(host, sa) != 0) {
2835 /*
2836 * if resolving from hosts file failed and the host
2837 * we are trying to resolve is `localhost` - we should
2838 * try to resolve it using `gethostbyname` and do not try
2839 * to resolve it via DNS server if gethostbyname has failed too
2840 */
2841 if (mg_ncasecmp(host, "localhost", 9) != 0) {
2842 return 0;
2843 }
2844
2845#if MG_ENABLE_SYNC_RESOLVER
2846 if (!mg_resolve2(host, &sa->sin.sin_addr)) {
2847 return -1;
2848 }
2849#else
2850 return -1;
2851#endif
2852 }
2853#endif
2854 } else if (sscanf(str, ":%u%n", &port, &len) == 1 ||
2855 sscanf(str, "%u%n", &port, &len) == 1) {
2856 /* If only port is specified, bind to IPv4, INADDR_ANY */
2857 sa->sin.sin_port = htons((uint16_t) port);
2858 } else {
2859 return -1;
2860 }
2861
2862 /* Required for MG_ENABLE_ASYNC_RESOLVER=0 */
2863 (void) host;
2864 (void) host_len;
2865
2866 ch = str[len]; /* Character that follows the address */
2867 return port < 0xffffUL && (ch == '\0' || ch == ',' || isspace(ch)) ? len : -1;
2868}
2869
2870#if MG_ENABLE_SSL
2872 int err = 0;
2873 int server_side = (nc->listener != NULL);
2874 enum mg_ssl_if_result res;
2875 if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) return;
2877
2878 if (res == MG_SSL_OK) {
2881 if (server_side) {
2882 mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
2883 } else {
2884 mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err);
2885 }
2886 } else if (res == MG_SSL_WANT_READ) {
2887 nc->flags |= MG_F_WANT_READ;
2888 } else if (res == MG_SSL_WANT_WRITE) {
2889 nc->flags |= MG_F_WANT_WRITE;
2890 } else {
2891 if (!server_side) {
2892 err = res;
2893 mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err);
2894 }
2896 }
2897}
2898#endif /* MG_ENABLE_SSL */
2899
2901 struct mg_add_sock_opts opts;
2902 struct mg_connection *nc;
2903 memset(&opts, 0, sizeof(opts));
2904 nc = mg_create_connection(lc->mgr, lc->handler, opts);
2905 if (nc == NULL) return NULL;
2906 nc->listener = lc;
2907 nc->proto_handler = lc->proto_handler;
2908 nc->user_data = lc->user_data;
2910 nc->iface = lc->iface;
2911 if (lc->flags & MG_F_SSL) nc->flags |= MG_F_SSL;
2912 mg_add_conn(nc->mgr, nc);
2913 LOG(LL_DEBUG, ("%p %p %d %d", lc, nc, nc->sock, (int) nc->flags));
2914 return nc;
2915}
2916
2917void mg_if_accept_tcp_cb(struct mg_connection *nc, union socket_address *sa,
2918 size_t sa_len) {
2919 LOG(LL_DEBUG, ("%p %s://%s:%hu", nc, (nc->flags & MG_F_UDP ? "udp" : "tcp"),
2920 inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port)));
2921 nc->sa = *sa;
2922#if MG_ENABLE_SSL
2923 if (nc->listener->flags & MG_F_SSL) {
2924 nc->flags |= MG_F_SSL;
2925 if (mg_ssl_if_conn_accept(nc, nc->listener) == MG_SSL_OK) {
2926 mg_ssl_handshake(nc);
2927 } else {
2928 mg_close_conn(nc);
2929 }
2930 } else
2931#endif
2932 {
2933 mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
2934 }
2935 (void) sa_len;
2936}
2937
2938void mg_send(struct mg_connection *nc, const void *buf, int len) {
2939 nc->last_io_time = (time_t) mg_time();
2940 mbuf_append(&nc->send_mbuf, buf, len);
2941}
2942
2943static int mg_recv_tcp(struct mg_connection *nc, char *buf, size_t len);
2944static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len);
2945
2946static int mg_do_recv(struct mg_connection *nc) {
2947 int res = 0;
2948 char *buf = NULL;
2949 size_t len = (nc->flags & MG_F_UDP ? MG_UDP_IO_SIZE : MG_TCP_IO_SIZE);
2951 ((nc->flags & MG_F_LISTENING) && !(nc->flags & MG_F_UDP))) {
2952 return -1;
2953 }
2954 do {
2955 len = recv_avail_size(nc, len);
2956 if (len == 0) {
2957 res = -2;
2958 break;
2959 }
2960 if (nc->recv_mbuf.size < nc->recv_mbuf.len + len) {
2961 mbuf_resize(&nc->recv_mbuf, nc->recv_mbuf.len + len);
2962 }
2963 buf = nc->recv_mbuf.buf + nc->recv_mbuf.len;
2964 len = nc->recv_mbuf.size - nc->recv_mbuf.len;
2965 if (nc->flags & MG_F_UDP) {
2966 res = mg_recv_udp(nc, buf, len);
2967 } else {
2968 res = mg_recv_tcp(nc, buf, len);
2969 }
2970 } while (res > 0 && !(nc->flags & (MG_F_CLOSE_IMMEDIATELY | MG_F_UDP)));
2971 return res;
2972}
2973
2974void mg_if_can_recv_cb(struct mg_connection *nc) {
2975 mg_do_recv(nc);
2976}
2977
2978static int mg_recv_tcp(struct mg_connection *nc, char *buf, size_t len) {
2979 int n = 0;
2980#if MG_ENABLE_SSL
2981 if (nc->flags & MG_F_SSL) {
2982 if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
2983 n = mg_ssl_if_read(nc, buf, len);
2984 DBG(("%p <- %d bytes (SSL)", nc, n));
2985 if (n < 0) {
2986 if (n == MG_SSL_WANT_READ) {
2987 nc->flags |= MG_F_WANT_READ;
2988 n = 0;
2989 } else {
2991 }
2992 } else if (n > 0) {
2993 nc->flags &= ~MG_F_WANT_READ;
2994 }
2995 } else {
2996 mg_ssl_handshake(nc);
2997 }
2998 } else
2999#endif
3000 {
3001 n = nc->iface->vtable->tcp_recv(nc, buf, len);
3002 DBG(("%p <- %d bytes", nc, n));
3003 }
3004 if (n > 0) {
3005 nc->recv_mbuf.len += n;
3006 nc->last_io_time = (time_t) mg_time();
3007#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
3008 if (nc->mgr && nc->mgr->hexdump_file != NULL) {
3010 }
3011#endif
3012 mbuf_trim(&nc->recv_mbuf);
3013 mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n);
3014 } else if (n < 0) {
3016 }
3017 mbuf_trim(&nc->recv_mbuf);
3018 return n;
3019}
3020
3021static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len) {
3022 int n = 0;
3023 struct mg_connection *lc = nc;
3024 union socket_address sa;
3025 size_t sa_len = sizeof(sa);
3026 n = nc->iface->vtable->udp_recv(lc, buf, len, &sa, &sa_len);
3027 if (n < 0) {
3029 goto out;
3030 }
3031 if (nc->flags & MG_F_LISTENING) {
3032 /*
3033 * Do we have an existing connection for this source?
3034 * This is very inefficient for long connection lists.
3035 */
3036 lc = nc;
3037 for (nc = mg_next(lc->mgr, NULL); nc != NULL; nc = mg_next(lc->mgr, nc)) {
3038 if (memcmp(&nc->sa.sa, &sa.sa, sa_len) == 0 && nc->listener == lc) {
3039 break;
3040 }
3041 }
3042 if (nc == NULL) {
3043 struct mg_add_sock_opts opts;
3044 memset(&opts, 0, sizeof(opts));
3045 /* Create fake connection w/out sock initialization */
3046 nc = mg_create_connection_base(lc->mgr, lc->handler, opts);
3047 if (nc != NULL) {
3048 nc->sock = lc->sock;
3049 nc->listener = lc;
3050 nc->sa = sa;
3051 nc->proto_handler = lc->proto_handler;
3052 nc->user_data = lc->user_data;
3054 nc->flags = MG_F_UDP;
3055 /*
3056 * Long-lived UDP "connections" i.e. interactions that involve more
3057 * than one request and response are rare, most are transactional:
3058 * response is sent and the "connection" is closed. Or - should be.
3059 * But users (including ourselves) tend to forget about that part,
3060 * because UDP is connectionless and one does not think about
3061 * processing a UDP request as handling a connection that needs to be
3062 * closed. Thus, we begin with SEND_AND_CLOSE flag set, which should
3063 * be a reasonable default for most use cases, but it is possible to
3064 * turn it off the connection should be kept alive after processing.
3065 */
3067 mg_add_conn(lc->mgr, nc);
3068 mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
3069 }
3070 }
3071 }
3072 if (nc != NULL) {
3073 DBG(("%p <- %d bytes from %s:%d", nc, n, inet_ntoa(nc->sa.sin.sin_addr),
3074 ntohs(nc->sa.sin.sin_port)));
3075 if (nc == lc) {
3076 nc->recv_mbuf.len += n;
3077 } else {
3078 mbuf_append(&nc->recv_mbuf, buf, n);
3079 }
3080 mbuf_trim(&lc->recv_mbuf);
3081 lc->last_io_time = nc->last_io_time = (time_t) mg_time();
3082#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
3083 if (nc->mgr && nc->mgr->hexdump_file != NULL) {
3085 }
3086#endif
3087 if (n != 0) {
3088 mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n);
3089 }
3090 }
3091
3092out:
3093 mbuf_free(&lc->recv_mbuf);
3094 return n;
3095}
3096
3097void mg_if_can_send_cb(struct mg_connection *nc) {
3098 int n = 0;
3099 const char *buf = nc->send_mbuf.buf;
3100 size_t len = nc->send_mbuf.len;
3101
3103 return;
3104 }
3105 if (!(nc->flags & MG_F_UDP)) {
3106 if (nc->flags & MG_F_LISTENING) return;
3107 if (len > MG_TCP_IO_SIZE) len = MG_TCP_IO_SIZE;
3108 }
3109#if MG_ENABLE_SSL
3110 if (nc->flags & MG_F_SSL) {
3111 if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
3112 if (len > 0) {
3113 n = mg_ssl_if_write(nc, buf, len);
3114 DBG(("%p -> %d bytes (SSL)", nc, n));
3115 }
3116 if (n < 0) {
3117 if (n == MG_SSL_WANT_WRITE) {
3118 nc->flags |= MG_F_WANT_WRITE;
3119 n = 0;
3120 } else {
3122 }
3123 } else {
3124 nc->flags &= ~MG_F_WANT_WRITE;
3125 }
3126 } else {
3127 mg_ssl_handshake(nc);
3128 }
3129 } else
3130#endif
3131 if (len > 0) {
3132 if (nc->flags & MG_F_UDP) {
3133 n = nc->iface->vtable->udp_send(nc, buf, len);
3134 } else {
3135 n = nc->iface->vtable->tcp_send(nc, buf, len);
3136 }
3137 DBG(("%p -> %d bytes", nc, n));
3138 }
3139
3140#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
3141 if (n > 0 && nc->mgr && nc->mgr->hexdump_file != NULL) {
3143 }
3144#endif
3145 if (n < 0) {
3147 } else if (n > 0) {
3148 nc->last_io_time = (time_t) mg_time();
3149 mbuf_remove(&nc->send_mbuf, n);
3150 mbuf_trim(&nc->send_mbuf);
3151 }
3152 if (n != 0) mg_call(nc, NULL, nc->user_data, MG_EV_SEND, &n);
3153}
3154
3155/*
3156 * Schedules an async connect for a resolved address and proto.
3157 * Called from two places: `mg_connect_opt()` and from async resolver.
3158 * When called from the async resolver, it must trigger `MG_EV_CONNECT` event
3159 * with a failure flag to indicate connection failure.
3160 */
3162 int proto,
3163 union socket_address *sa) {
3164 LOG(LL_DEBUG, ("%p %s://%s:%hu", nc, proto == SOCK_DGRAM ? "udp" : "tcp",
3165 inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port)));
3166
3167 nc->flags |= MG_F_CONNECTING;
3168 if (proto == SOCK_DGRAM) {
3169 nc->iface->vtable->connect_udp(nc);
3170 } else {
3171 nc->iface->vtable->connect_tcp(nc, sa);
3172 }
3173 mg_add_conn(nc->mgr, nc);
3174 return nc;
3175}
3176
3177void mg_if_connect_cb(struct mg_connection *nc, int err) {
3178 LOG(LL_DEBUG,
3179 ("%p %s://%s:%hu -> %d", nc, (nc->flags & MG_F_UDP ? "udp" : "tcp"),
3180 inet_ntoa(nc->sa.sin.sin_addr), ntohs(nc->sa.sin.sin_port), err));
3181 nc->flags &= ~MG_F_CONNECTING;
3182 if (err != 0) {
3184 }
3185#if MG_ENABLE_SSL
3186 if (err == 0 && (nc->flags & MG_F_SSL)) {
3187 mg_ssl_handshake(nc);
3188 } else
3189#endif
3190 {
3191 mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err);
3192 }
3193}
3194
3195#if MG_ENABLE_ASYNC_RESOLVER
3196/*
3197 * Callback for the async resolver on mg_connect_opt() call.
3198 * Main task of this function is to trigger MG_EV_CONNECT event with
3199 * either failure (and dealloc the connection)
3200 * or success (and proceed with connect()
3201 */
3202static void resolve_cb(struct mg_dns_message *msg, void *data,
3203 enum mg_resolve_err e) {
3204 struct mg_connection *nc = (struct mg_connection *) data;
3205 int i;
3206 int failure = -1;
3207
3208 nc->flags &= ~MG_F_RESOLVING;
3209 if (msg != NULL) {
3210 /*
3211 * Take the first DNS A answer and run...
3212 */
3213 for (i = 0; i < msg->num_answers; i++) {
3214 if (msg->answers[i].rtype == MG_DNS_A_RECORD) {
3215 /*
3216 * Async resolver guarantees that there is at least one answer.
3217 * TODO(lsm): handle IPv6 answers too
3218 */
3219 mg_dns_parse_record_data(msg, &msg->answers[i], &nc->sa.sin.sin_addr,
3220 4);
3222 &nc->sa);
3223 return;
3224 }
3225 }
3226 }
3227
3228 if (e == MG_RESOLVE_TIMEOUT) {
3229 double now = mg_time();
3230 mg_call(nc, NULL, nc->user_data, MG_EV_TIMER, &now);
3231 }
3232
3233 /*
3234 * If we get there was no MG_DNS_A_RECORD in the answer
3235 */
3236 mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &failure);
3238 mg_destroy_conn(nc, 1 /* destroy_if */);
3239}
3240#endif
3241
3242struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *address,
3244 void *user_data)) {
3245 struct mg_connect_opts opts;
3246 memset(&opts, 0, sizeof(opts));
3247 return mg_connect_opt(mgr, address, MG_CB(callback, user_data), opts);
3248}
3249
3250void mg_ev_handler_empty(struct mg_connection *c, int ev,
3251 void *ev_data MG_UD_ARG(void *user_data)) {
3252 (void) c;
3253 (void) ev;
3254 (void) ev_data;
3255#if MG_ENABLE_CALLBACK_USERDATA
3256 (void) user_data;
3257#endif
3258}
3259
3260struct mg_connection *mg_connect_opt(struct mg_mgr *mgr, const char *address,
3262 void *user_data),
3263 struct mg_connect_opts opts) {
3264 struct mg_connection *nc = NULL;
3265 int proto, rc;
3267 char host[MG_MAX_HOST_LEN];
3268
3270
3272
3273 if ((nc = mg_create_connection(mgr, callback, add_sock_opts)) == NULL) {
3274 return NULL;
3275 }
3276
3277 if ((rc = mg_parse_address(address, &nc->sa, &proto, host, sizeof(host))) <
3278 0) {
3279 /* Address is malformed */
3280 MG_SET_PTRPTR(opts.error_string, "cannot parse address");
3281 mg_destroy_conn(nc, 1 /* destroy_if */);
3282 return NULL;
3283 }
3284
3286 nc->flags |= (proto == SOCK_DGRAM) ? MG_F_UDP : 0;
3287#if MG_ENABLE_CALLBACK_USERDATA
3288 nc->user_data = user_data;
3289#else
3290 nc->user_data = opts.user_data;
3291#endif
3292
3293#if MG_ENABLE_SSL
3294 LOG(LL_DEBUG,
3295 ("%p %s %s,%s,%s", nc, address, (opts.ssl_cert ? opts.ssl_cert : "-"),
3296 (opts.ssl_key ? opts.ssl_key : "-"),
3297 (opts.ssl_ca_cert ? opts.ssl_ca_cert : "-")));
3298
3299 if (opts.ssl_cert != NULL || opts.ssl_ca_cert != NULL ||
3300 opts.ssl_psk_identity != NULL) {
3301 const char *err_msg = NULL;
3302 struct mg_ssl_if_conn_params params;
3303 if (nc->flags & MG_F_UDP) {
3304 MG_SET_PTRPTR(opts.error_string, "SSL for UDP is not supported");
3305 mg_destroy_conn(nc, 1 /* destroy_if */);
3306 return NULL;
3307 }
3308 memset(&params, 0, sizeof(params));
3309 params.cert = opts.ssl_cert;
3310 params.key = opts.ssl_key;
3311 params.ca_cert = opts.ssl_ca_cert;
3312 params.cipher_suites = opts.ssl_cipher_suites;
3313 params.psk_identity = opts.ssl_psk_identity;
3314 params.psk_key = opts.ssl_psk_key;
3315 if (opts.ssl_ca_cert != NULL) {
3316 if (opts.ssl_server_name != NULL) {
3317 if (strcmp(opts.ssl_server_name, "*") != 0) {
3318 params.server_name = opts.ssl_server_name;
3319 }
3320 } else if (rc == 0) { /* If it's a DNS name, use host. */
3321 params.server_name = host;
3322 }
3323 }
3324 if (mg_ssl_if_conn_init(nc, &params, &err_msg) != MG_SSL_OK) {
3325 MG_SET_PTRPTR(opts.error_string, err_msg);
3326 mg_destroy_conn(nc, 1 /* destroy_if */);
3327 return NULL;
3328 }
3329 nc->flags |= MG_F_SSL;
3330 }
3331#endif /* MG_ENABLE_SSL */
3332
3333 if (rc == 0) {
3334#if MG_ENABLE_ASYNC_RESOLVER
3335 /*
3336 * DNS resolution is required for host.
3337 * mg_parse_address() fills port in nc->sa, which we pass to resolve_cb()
3338 */
3339 struct mg_connection *dns_conn = NULL;
3340 struct mg_resolve_async_opts o;
3341 memset(&o, 0, sizeof(o));
3342 o.dns_conn = &dns_conn;
3343 o.nameserver = opts.nameserver;
3345 o) != 0) {
3346 MG_SET_PTRPTR(opts.error_string, "cannot schedule DNS lookup");
3347 mg_destroy_conn(nc, 1 /* destroy_if */);
3348 return NULL;
3349 }
3350 nc->priv_2 = dns_conn;
3351 nc->flags |= MG_F_RESOLVING;
3352 return nc;
3353#else
3354 MG_SET_PTRPTR(opts.error_string, "Resolver is disabled");
3355 mg_destroy_conn(nc, 1 /* destroy_if */);
3356 return NULL;
3357#endif
3358 } else {
3359 /* Address is parsed and resolved to IP. proceed with connect() */
3360 return mg_do_connect(nc, proto, &nc->sa);
3361 }
3362}
3363
3364struct mg_connection *mg_bind(struct mg_mgr *srv, const char *address,
3365 MG_CB(mg_event_handler_t event_handler,
3366 void *user_data)) {
3367 struct mg_bind_opts opts;
3368 memset(&opts, 0, sizeof(opts));
3369 return mg_bind_opt(srv, address, MG_CB(event_handler, user_data), opts);
3370}
3371
3372struct mg_connection *mg_bind_opt(struct mg_mgr *mgr, const char *address,
3374 void *user_data),
3375 struct mg_bind_opts opts) {
3376 union socket_address sa;
3377 struct mg_connection *nc = NULL;
3378 int proto, rc;
3380 char host[MG_MAX_HOST_LEN];
3381
3382#if MG_ENABLE_CALLBACK_USERDATA
3384#endif
3385
3387
3389
3390 if (mg_parse_address(address, &sa, &proto, host, sizeof(host)) <= 0) {
3391 MG_SET_PTRPTR(opts.error_string, "cannot parse address");
3392 return NULL;
3393 }
3394
3396 if (nc == NULL) {
3397 return NULL;
3398 }
3399
3400 nc->sa = sa;
3401 nc->flags |= MG_F_LISTENING;
3402 if (proto == SOCK_DGRAM) nc->flags |= MG_F_UDP;
3403
3404#if MG_ENABLE_SSL
3405 DBG(("%p %s %s,%s,%s", nc, address, (opts.ssl_cert ? opts.ssl_cert : "-"),
3406 (opts.ssl_key ? opts.ssl_key : "-"),
3407 (opts.ssl_ca_cert ? opts.ssl_ca_cert : "-")));
3408
3409 if (opts.ssl_cert != NULL || opts.ssl_ca_cert != NULL) {
3410 const char *err_msg = NULL;
3411 struct mg_ssl_if_conn_params params;
3412 if (nc->flags & MG_F_UDP) {
3413 MG_SET_PTRPTR(opts.error_string, "SSL for UDP is not supported");
3414 mg_destroy_conn(nc, 1 /* destroy_if */);
3415 return NULL;
3416 }
3417 memset(&params, 0, sizeof(params));
3418 params.cert = opts.ssl_cert;
3419 params.key = opts.ssl_key;
3420 params.ca_cert = opts.ssl_ca_cert;
3421 params.cipher_suites = opts.ssl_cipher_suites;
3422 if (mg_ssl_if_conn_init(nc, &params, &err_msg) != MG_SSL_OK) {
3423 MG_SET_PTRPTR(opts.error_string, err_msg);
3424 mg_destroy_conn(nc, 1 /* destroy_if */);
3425 return NULL;
3426 }
3427 nc->flags |= MG_F_SSL;
3428 }
3429#endif /* MG_ENABLE_SSL */
3430
3431 if (nc->flags & MG_F_UDP) {
3432 rc = nc->iface->vtable->listen_udp(nc, &nc->sa);
3433 } else {
3434 rc = nc->iface->vtable->listen_tcp(nc, &nc->sa);
3435 }
3436 if (rc != 0) {
3437 DBG(("Failed to open listener: %d", rc));
3438 MG_SET_PTRPTR(opts.error_string, "failed to open listener");
3439 mg_destroy_conn(nc, 1 /* destroy_if */);
3440 return NULL;
3441 }
3442 mg_add_conn(nc->mgr, nc);
3443
3444 return nc;
3445}
3446
3447struct mg_connection *mg_next(struct mg_mgr *s, struct mg_connection *conn) {
3448 return conn == NULL ? s->active_connections : conn->next;
3449}
3450
3451#if MG_ENABLE_BROADCAST
3452void mg_broadcast(struct mg_mgr *mgr, mg_event_handler_t cb, void *data,
3453 size_t len) {
3454 struct ctl_msg ctl_msg;
3455
3456 /*
3457 * Mongoose manager has a socketpair, `struct mg_mgr::ctl`,
3458 * where `mg_broadcast()` pushes the message.
3459 * `mg_mgr_poll()` wakes up, reads a message from the socket pair, and calls
3460 * specified callback for each connection. Thus the callback function executes
3461 * in event manager thread.
3462 */
3463 if (mgr->ctl[0] != INVALID_SOCKET && data != NULL &&
3464 len < sizeof(ctl_msg.message)) {
3465 size_t dummy;
3466
3467 ctl_msg.callback = cb;
3468 memcpy(ctl_msg.message, data, len);
3469 dummy = MG_SEND_FUNC(mgr->ctl[0], (char *) &ctl_msg,
3470 offsetof(struct ctl_msg, message) + len, 0);
3471 dummy = MG_RECV_FUNC(mgr->ctl[0], (char *) &len, 1, 0);
3472 (void) dummy; /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25509 */
3473 }
3474}
3475#endif /* MG_ENABLE_BROADCAST */
3476
3477static int isbyte(int n) {
3478 return n >= 0 && n <= 255;
3479}
3480
3481static int parse_net(const char *spec, uint32_t *net, uint32_t *mask) {
3482 int n, a, b, c, d, slash = 32, len = 0;
3483
3484 if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5 ||
3485 sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) &&
3486 isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) && slash >= 0 &&
3487 slash < 33) {
3488 len = n;
3489 *net =
3490 ((uint32_t) a << 24) | ((uint32_t) b << 16) | ((uint32_t) c << 8) | d;
3491 *mask = slash ? 0xffffffffU << (32 - slash) : 0;
3492 }
3493
3494 return len;
3495}
3496
3497int mg_check_ip_acl(const char *acl, uint32_t remote_ip) {
3498 int allowed, flag;
3499 uint32_t net, mask;
3500 struct mg_str vec;
3501
3502 /* If any ACL is set, deny by default */
3503 allowed = (acl == NULL || *acl == '\0') ? '+' : '-';
3504
3505 while ((acl = mg_next_comma_list_entry(acl, &vec, NULL)) != NULL) {
3506 flag = vec.p[0];
3507 if ((flag != '+' && flag != '-') ||
3508 parse_net(&vec.p[1], &net, &mask) == 0) {
3509 return -1;
3510 }
3511
3512 if (net == (remote_ip & mask)) {
3513 allowed = flag;
3514 }
3515 }
3516
3517 DBG(("%08x %c", (unsigned int) remote_ip, allowed));
3518 return allowed == '+';
3519}
3520
3521/* Move data from one connection to another */
3522void mg_forward(struct mg_connection *from, struct mg_connection *to) {
3523 mg_send(to, from->recv_mbuf.buf, from->recv_mbuf.len);
3524 mbuf_remove(&from->recv_mbuf, from->recv_mbuf.len);
3525}
3526
3527double mg_set_timer(struct mg_connection *c, double timestamp) {
3528 double result = c->ev_timer_time;
3529 c->ev_timer_time = timestamp;
3530 /*
3531 * If this connection is resolving, it's not in the list of active
3532 * connections, so not processed yet. It has a DNS resolver connection
3533 * linked to it. Set up a timer for the DNS connection.
3534 */
3535 DBG(("%p %p %d -> %lu", c, c->priv_2, (c->flags & MG_F_RESOLVING ? 1 : 0),
3536 (unsigned long) timestamp));
3537 if ((c->flags & MG_F_RESOLVING) && c->priv_2 != NULL) {
3538 mg_set_timer((struct mg_connection *) c->priv_2, timestamp);
3539 }
3540 return result;
3541}
3542
3543void mg_sock_set(struct mg_connection *nc, sock_t sock) {
3544 if (sock != INVALID_SOCKET) {
3545 nc->iface->vtable->sock_set(nc, sock);
3546 }
3547}
3548
3549void mg_if_get_conn_addr(struct mg_connection *nc, int remote,
3550 union socket_address *sa) {
3551 nc->iface->vtable->get_conn_addr(nc, remote, sa);
3552}
3553
3556 void *user_data),
3557 struct mg_add_sock_opts opts) {
3558#if MG_ENABLE_CALLBACK_USERDATA
3560#endif
3561
3563 if (nc != NULL) {
3564 mg_sock_set(nc, sock);
3565 mg_add_conn(nc->mgr, nc);
3566 }
3567 return nc;
3568}
3569
3570struct mg_connection *mg_add_sock(struct mg_mgr *s, sock_t sock,
3572 void *user_data)) {
3573 struct mg_add_sock_opts opts;
3574 memset(&opts, 0, sizeof(opts));
3575 return mg_add_sock_opt(s, sock, MG_CB(callback, user_data), opts);
3576}
3577
3578double mg_time(void) {
3579 return cs_time();
3580}
3581#ifdef MG_MODULE_LINES
3582#line 1 "mongoose/src/mg_net_if_socket.h"
3583#endif
3584/*
3585 * Copyright (c) 2014-2016 Cesanta Software Limited
3586 * All rights reserved
3587 */
3588
3589#ifndef CS_MONGOOSE_SRC_NET_IF_SOCKET_H_
3590#define CS_MONGOOSE_SRC_NET_IF_SOCKET_H_
3591
3592/* Amalgamated: #include "mg_net_if.h" */
3593
3594#ifdef __cplusplus
3595extern "C" {
3596#endif /* __cplusplus */
3597
3598#ifndef MG_ENABLE_NET_IF_SOCKET
3599#define MG_ENABLE_NET_IF_SOCKET MG_NET_IF == MG_NET_IF_SOCKET
3600#endif
3601
3602extern const struct mg_iface_vtable mg_socket_iface_vtable;
3603
3604#ifdef __cplusplus
3605}
3606#endif /* __cplusplus */
3607
3608#endif /* CS_MONGOOSE_SRC_NET_IF_SOCKET_H_ */
3609#ifdef MG_MODULE_LINES
3610#line 1 "mongoose/src/mg_net_if_socks.h"
3611#endif
3612/*
3613* Copyright (c) 2014-2017 Cesanta Software Limited
3614* All rights reserved
3615*/
3616
3617#ifndef CS_MONGOOSE_SRC_NET_IF_SOCKS_H_
3618#define CS_MONGOOSE_SRC_NET_IF_SOCKS_H_
3619
3620#if MG_ENABLE_SOCKS
3621/* Amalgamated: #include "mg_net_if.h" */
3622
3623#ifdef __cplusplus
3624extern "C" {
3625#endif /* __cplusplus */
3626
3627extern const struct mg_iface_vtable mg_socks_iface_vtable;
3628
3629#ifdef __cplusplus
3630}
3631#endif /* __cplusplus */
3632#endif /* MG_ENABLE_SOCKS */
3633#endif /* CS_MONGOOSE_SRC_NET_IF_SOCKS_H_ */
3634#ifdef MG_MODULE_LINES
3635#line 1 "mongoose/src/mg_net_if.c"
3636#endif
3637/* Amalgamated: #include "mg_net_if.h" */
3638/* Amalgamated: #include "mg_internal.h" */
3639/* Amalgamated: #include "mg_net_if_socket.h" */
3640
3641extern const struct mg_iface_vtable mg_default_iface_vtable;
3642
3643const struct mg_iface_vtable *mg_ifaces[] = {
3645};
3646
3647int mg_num_ifaces = (int) (sizeof(mg_ifaces) / sizeof(mg_ifaces[0]));
3648
3650 struct mg_mgr *mgr) {
3651 struct mg_iface *iface = (struct mg_iface *) MG_CALLOC(1, sizeof(*iface));
3652 iface->mgr = mgr;
3653 iface->data = NULL;
3654 iface->vtable = vtable;
3655 return iface;
3656}
3657
3658struct mg_iface *mg_find_iface(struct mg_mgr *mgr,
3659 const struct mg_iface_vtable *vtable,
3660 struct mg_iface *from) {
3661 int i = 0;
3662 if (from != NULL) {
3663 for (i = 0; i < mgr->num_ifaces; i++) {
3664 if (mgr->ifaces[i] == from) {
3665 i++;
3666 break;
3667 }
3668 }
3669 }
3670
3671 for (; i < mgr->num_ifaces; i++) {
3672 if (mgr->ifaces[i]->vtable == vtable) {
3673 return mgr->ifaces[i];
3674 }
3675 }
3676 return NULL;
3677}
3678
3679double mg_mgr_min_timer(const struct mg_mgr *mgr) {
3680 double min_timer = 0;
3681 struct mg_connection *nc;
3682 for (nc = mgr->active_connections; nc != NULL; nc = nc->next) {
3683 if (nc->ev_timer_time <= 0) continue;
3684 if (min_timer == 0 || nc->ev_timer_time < min_timer) {
3686 }
3687 }
3688 return min_timer;
3689}
3690#ifdef MG_MODULE_LINES
3691#line 1 "mongoose/src/mg_net_if_null.c"
3692#endif
3693/*
3694 * Copyright (c) 2018 Cesanta Software Limited
3695 * All rights reserved
3696 *
3697 * This software is dual-licensed: you can redistribute it and/or modify
3698 * it under the terms of the GNU General Public License version 2 as
3699 * published by the Free Software Foundation. For the terms of this
3700 * license, see <http://www.gnu.org/licenses/>.
3701 *
3702 * You are free to use this software under the terms of the GNU General
3703 * Public License, but WITHOUT ANY WARRANTY; without even the implied
3704 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
3705 * See the GNU General Public License for more details.
3706 *
3707 * Alternatively, you can license this software under a commercial
3708 * license, as set out in <https://www.cesanta.com/license>.
3709 */
3710
3711static void mg_null_if_connect_tcp(struct mg_connection *c,
3712 const union socket_address *sa) {
3713 c->flags |= MG_F_CLOSE_IMMEDIATELY;
3714 (void) sa;
3715}
3716
3717static void mg_null_if_connect_udp(struct mg_connection *c) {
3718 c->flags |= MG_F_CLOSE_IMMEDIATELY;
3719}
3720
3721static int mg_null_if_listen_tcp(struct mg_connection *c,
3722 union socket_address *sa) {
3723 (void) c;
3724 (void) sa;
3725 return -1;
3726}
3727
3728static int mg_null_if_listen_udp(struct mg_connection *c,
3729 union socket_address *sa) {
3730 (void) c;
3731 (void) sa;
3732 return -1;
3733}
3734
3735static int mg_null_if_tcp_send(struct mg_connection *c, const void *buf,
3736 size_t len) {
3737 (void) c;
3738 (void) buf;
3739 (void) len;
3740 return -1;
3741}
3742
3743static int mg_null_if_udp_send(struct mg_connection *c, const void *buf,
3744 size_t len) {
3745 (void) c;
3746 (void) buf;
3747 (void) len;
3748 return -1;
3749}
3750
3751int mg_null_if_tcp_recv(struct mg_connection *c, void *buf, size_t len) {
3752 (void) c;
3753 (void) buf;
3754 (void) len;
3755 return -1;
3756}
3757
3758int mg_null_if_udp_recv(struct mg_connection *c, void *buf, size_t len,
3759 union socket_address *sa, size_t *sa_len) {
3760 (void) c;
3761 (void) buf;
3762 (void) len;
3763 (void) sa;
3764 (void) sa_len;
3765 return -1;
3766}
3767
3768static int mg_null_if_create_conn(struct mg_connection *c) {
3769 (void) c;
3770 return 1;
3771}
3772
3773static void mg_null_if_destroy_conn(struct mg_connection *c) {
3774 (void) c;
3775}
3776
3777static void mg_null_if_sock_set(struct mg_connection *c, sock_t sock) {
3778 (void) c;
3779 (void) sock;
3780}
3781
3782static void mg_null_if_init(struct mg_iface *iface) {
3783 (void) iface;
3784}
3785
3786static void mg_null_if_free(struct mg_iface *iface) {
3787 (void) iface;
3788}
3789
3790static void mg_null_if_add_conn(struct mg_connection *c) {
3791 c->sock = INVALID_SOCKET;
3792 c->flags |= MG_F_CLOSE_IMMEDIATELY;
3793}
3794
3795static void mg_null_if_remove_conn(struct mg_connection *c) {
3796 (void) c;
3797}
3798
3799static time_t mg_null_if_poll(struct mg_iface *iface, int timeout_ms) {
3800 struct mg_mgr *mgr = iface->mgr;
3801 struct mg_connection *nc, *tmp;
3802 double now = mg_time();
3803 /* We basically just run timers and poll. */
3804 for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
3805 tmp = nc->next;
3806 mg_if_poll(nc, now);
3807 }
3808 (void) timeout_ms;
3809 return (time_t) now;
3810}
3811
3812static void mg_null_if_get_conn_addr(struct mg_connection *c, int remote,
3813 union socket_address *sa) {
3814 (void) c;
3815 (void) remote;
3816 (void) sa;
3817}
3818
3819#define MG_NULL_IFACE_VTABLE \
3820 { \
3821 mg_null_if_init, mg_null_if_free, mg_null_if_add_conn, \
3822 mg_null_if_remove_conn, mg_null_if_poll, mg_null_if_listen_tcp, \
3823 mg_null_if_listen_udp, mg_null_if_connect_tcp, mg_null_if_connect_udp, \
3824 mg_null_if_tcp_send, mg_null_if_udp_send, mg_null_if_tcp_recv, \
3825 mg_null_if_udp_recv, mg_null_if_create_conn, mg_null_if_destroy_conn, \
3826 mg_null_if_sock_set, mg_null_if_get_conn_addr, \
3827 }
3828
3829//const struct mg_iface_vtable mg_null_iface_vtable = MG_NULL_IFACE_VTABLE;
3830
3831#if MG_NET_IF == MG_NET_IF_NULL
3833#endif /* MG_NET_IF == MG_NET_IF_NULL */
3834#ifdef MG_MODULE_LINES
3835#line 1 "mongoose/src/mg_net_if_socket.c"
3836#endif
3837/*
3838 * Copyright (c) 2014-2016 Cesanta Software Limited
3839 * All rights reserved
3840 */
3841
3842#if MG_ENABLE_NET_IF_SOCKET
3843
3844/* Amalgamated: #include "mg_net_if_socket.h" */
3845/* Amalgamated: #include "mg_internal.h" */
3846/* Amalgamated: #include "mg_util.h" */
3847
3849 int proto);
3850
3852#ifdef _WIN32
3853 unsigned long on = 1;
3854 ioctlsocket(sock, FIONBIO, &on);
3855#else
3856 int flags = fcntl(sock, F_GETFL, 0);
3857 fcntl(sock, F_SETFL, flags | O_NONBLOCK);
3858#endif
3859}
3860
3861static int mg_is_error(void) {
3862 int err = mg_get_errno();
3863 return err != EINPROGRESS && err != EWOULDBLOCK
3864#ifndef WINCE
3865 && err != EAGAIN && err != EINTR
3866#endif
3867#ifdef _WIN32
3869#endif
3870 ;
3871}
3872
3874 const union socket_address *sa) {
3875 int rc, proto = 0;
3876 nc->sock = socket(AF_INET, SOCK_STREAM, proto);
3877 if (nc->sock == INVALID_SOCKET) {
3878 nc->err = mg_get_errno() ? mg_get_errno() : 1;
3879 return;
3880 }
3881#if !defined(MG_ESP8266)
3883#endif
3884 rc = connect(nc->sock, &sa->sa, sizeof(sa->sin));
3885 nc->err = rc < 0 && mg_is_error() ? mg_get_errno() : 0;
3886 DBG(("%p sock %d rc %d errno %d err %d", nc, nc->sock, rc, mg_get_errno(),
3887 nc->err));
3888}
3889
3890void mg_socket_if_connect_udp(struct mg_connection *nc) {
3891 nc->sock = socket(AF_INET, SOCK_DGRAM, 0);
3892 if (nc->sock == INVALID_SOCKET) {
3893 nc->err = mg_get_errno() ? mg_get_errno() : 1;
3894 return;
3895 }
3896 if (nc->flags & MG_F_ENABLE_BROADCAST) {
3897 int optval = 1;
3898 if (setsockopt(nc->sock, SOL_SOCKET, SO_BROADCAST, (const char *) &optval,
3899 sizeof(optval)) < 0) {
3900 nc->err = mg_get_errno() ? mg_get_errno() : 1;
3901 return;
3902 }
3903 }
3904 nc->err = 0;
3905}
3906
3908 union socket_address *sa) {
3909 int proto = 0;
3910 sock_t sock = mg_open_listening_socket(sa, SOCK_STREAM, proto);
3911 if (sock == INVALID_SOCKET) {
3912 return (mg_get_errno() ? mg_get_errno() : 1);
3913 }
3914 mg_sock_set(nc, sock);
3915 return 0;
3916}
3917
3918static int mg_socket_if_listen_udp(struct mg_connection *nc,
3919 union socket_address *sa) {
3921 if (sock == INVALID_SOCKET) return (mg_get_errno() ? mg_get_errno() : 1);
3922 mg_sock_set(nc, sock);
3923 return 0;
3924}
3925
3926static int mg_socket_if_tcp_send(struct mg_connection *nc, const void *buf,
3927 size_t len) {
3928 int n = (int) MG_SEND_FUNC(nc->sock, buf, len, 0);
3929 if (n < 0 && !mg_is_error()) n = 0;
3930 return n;
3931}
3932
3933static int mg_socket_if_udp_send(struct mg_connection *nc, const void *buf,
3934 size_t len) {
3935 int n = sendto(nc->sock, buf, len, 0, &nc->sa.sa, sizeof(nc->sa.sin));
3936 if (n < 0 && !mg_is_error()) n = 0;
3937 return n;
3938}
3939
3940static int mg_socket_if_tcp_recv(struct mg_connection *nc, void *buf,
3941 size_t len) {
3942 int n = (int) MG_RECV_FUNC(nc->sock, buf, len, 0);
3943 if (n == 0) {
3944 /* Orderly shutdown of the socket, try flushing output. */
3946 } else if (n < 0 && !mg_is_error()) {
3947 n = 0;
3948 }
3949 return n;
3950}
3951
3952static int mg_socket_if_udp_recv(struct mg_connection *nc, void *buf,
3953 size_t len, union socket_address *sa,
3954 size_t *sa_len) {
3956 int n = recvfrom(nc->sock, buf, len, 0, &sa->sa, &sa_len_st);
3957 *sa_len = sa_len_st;
3958 if (n < 0 && !mg_is_error()) n = 0;
3959 return n;
3960}
3961
3963 (void) nc;
3964 return 1;
3965}
3966
3968 if (nc->sock == INVALID_SOCKET) return;
3969 if (!(nc->flags & MG_F_UDP)) {
3970 closesocket(nc->sock);
3971 } else {
3972 /* Only close outgoing UDP sockets or listeners. */
3973 if (nc->listener == NULL) closesocket(nc->sock);
3974 }
3975 nc->sock = INVALID_SOCKET;
3976}
3977
3978static int mg_accept_conn(struct mg_connection *lc) {
3979 struct mg_connection *nc;
3980 union socket_address sa;
3981 socklen_t sa_len = sizeof(sa);
3982 /* NOTE(lsm): on Windows, sock is always > FD_SETSIZE */
3983 sock_t sock = accept(lc->sock, &sa.sa, &sa_len);
3984 if (sock == INVALID_SOCKET) {
3985 if (mg_is_error()) {
3986 DBG(("%p: failed to accept: %d", lc, mg_get_errno()));
3987 }
3988 return 0;
3989 }
3990 nc = mg_if_accept_new_conn(lc);
3991 if (nc == NULL) {
3992 closesocket(sock);
3993 return 0;
3994 }
3995 DBG(("%p conn from %s:%d", nc, inet_ntoa(sa.sin.sin_addr),
3996 ntohs(sa.sin.sin_port)));
3997 mg_sock_set(nc, sock);
3999 return 1;
4000}
4001
4002/* 'sa' must be an initialized address to bind to */
4004 int proto) {
4006 (sa->sa.sa_family == AF_INET) ? sizeof(sa->sin) : sizeof(sa->sin6);
4007 sock_t sock = INVALID_SOCKET;
4008#if !MG_LWIP
4009 int on = 1;
4010#endif
4011
4012 if ((sock = socket(sa->sa.sa_family, type, proto)) != INVALID_SOCKET &&
4013#if !MG_LWIP /* LWIP doesn't support either */
4015 /* "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE" http://goo.gl/RmrFTm */
4016 !setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &on,
4017 sizeof(on)) &&
4018#endif
4019
4020#if !defined(_WIN32) || !defined(SO_EXCLUSIVEADDRUSE)
4021 /*
4022 * SO_RESUSEADDR is not enabled on Windows because the semantics of
4023 * SO_REUSEADDR on UNIX and Windows is different. On Windows,
4024 * SO_REUSEADDR allows to bind a socket to a port without error even if
4025 * the port is already open by another program. This is not the behavior
4026 * SO_REUSEADDR was designed for, and leads to hard-to-track failure
4027 * scenarios. Therefore, SO_REUSEADDR was disabled on Windows unless
4028 * SO_EXCLUSIVEADDRUSE is supported and set on a socket.
4029 */
4030 !setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) &&
4031#endif
4032#endif /* !MG_LWIP */
4033
4034 !bind(sock, &sa->sa, sa_len) &&
4035 (type == SOCK_DGRAM || listen(sock, SOMAXCONN) == 0)) {
4036#if !MG_LWIP
4038 /* In case port was set to 0, get the real port number */
4039 (void) getsockname(sock, &sa->sa, &sa_len);
4040#endif
4041 } else if (sock != INVALID_SOCKET) {
4042 closesocket(sock);
4043 sock = INVALID_SOCKET;
4044 }
4045
4046 return sock;
4047}
4048
4049#define _MG_F_FD_CAN_READ 1
4050#define _MG_F_FD_CAN_WRITE 1 << 1
4051#define _MG_F_FD_ERROR 1 << 2
4052
4053void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
4054 int worth_logging =
4055 fd_flags != 0 || (nc->flags & (MG_F_WANT_READ | MG_F_WANT_WRITE));
4056 if (worth_logging) {
4057 DBG(("%p fd=%d fd_flags=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock,
4058 fd_flags, nc->flags, (int) nc->recv_mbuf.len,
4059 (int) nc->send_mbuf.len));
4060 }
4061
4062 if (!mg_if_poll(nc, now)) return;
4063
4064 if (nc->flags & MG_F_CONNECTING) {
4065 if (fd_flags != 0) {
4066 int err = 0;
4067#if !defined(MG_ESP8266)
4068 if (!(nc->flags & MG_F_UDP)) {
4069 socklen_t len = sizeof(err);
4070 int ret =
4071 getsockopt(nc->sock, SOL_SOCKET, SO_ERROR, (char *) &err, &len);
4072 if (ret != 0) {
4073 err = 1;
4074 } else if (err == EAGAIN || err == EWOULDBLOCK) {
4075 err = 0;
4076 }
4077 }
4078#else
4079 /*
4080 * On ESP8266 we use blocking connect.
4081 */
4082 err = nc->err;
4083#endif
4084 mg_if_connect_cb(nc, err);
4085 } else if (nc->err != 0) {
4086 mg_if_connect_cb(nc, nc->err);
4087 }
4088 }
4089
4091 if (nc->flags & MG_F_UDP) {
4093 } else {
4094 if (nc->flags & MG_F_LISTENING) {
4095 /*
4096 * We're not looping here, and accepting just one connection at
4097 * a time. The reason is that eCos does not respect non-blocking
4098 * flag on a listening socket and hangs in a loop.
4099 */
4100 mg_accept_conn(nc);
4101 } else {
4103 }
4104 }
4105 }
4106
4108
4109 if (worth_logging) {
4110 DBG(("%p after fd=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock,
4111 nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
4112 }
4113}
4114
4115#if MG_ENABLE_BROADCAST
4116static void mg_mgr_handle_ctl_sock(struct mg_mgr *mgr) {
4117 struct ctl_msg ctl_msg;
4118 int len =
4119 (int) MG_RECV_FUNC(mgr->ctl[1], (char *) &ctl_msg, sizeof(ctl_msg), 0);
4120 DBG(("read %d from ctl socket", len));
4121 if (len >= (int) sizeof(ctl_msg.callback) && ctl_msg.callback != NULL) {
4122 struct mg_connection *nc;
4123 for (nc = mg_next(mgr, NULL); nc != NULL; nc = mg_next(mgr, nc)) {
4126 }
4127 }
4128 // change from original mongoose code: send the reply message
4129 // after we finished processing the broadcast message. K.O.
4130 size_t dummy = MG_SEND_FUNC(mgr->ctl[1], ctl_msg.message, 1, 0);
4131 (void) dummy; /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25509 */
4132}
4133#endif
4134
4135/* Associate a socket to a connection. */
4139 nc->sock = sock;
4140 DBG(("%p %d", nc, sock));
4141}
4142
4143void mg_socket_if_init(struct mg_iface *iface) {
4144 (void) iface;
4145 DBG(("%p using select()", iface->mgr));
4146#if MG_ENABLE_BROADCAST
4148#endif
4149}
4150
4151void mg_socket_if_free(struct mg_iface *iface) {
4152 (void) iface;
4153}
4154
4155void mg_socket_if_add_conn(struct mg_connection *nc) {
4156 (void) nc;
4157}
4158
4159void mg_socket_if_remove_conn(struct mg_connection *nc) {
4160 (void) nc;
4161}
4162
4164 if (sock != INVALID_SOCKET
4166 && sock < (sock_t) FD_SETSIZE
4167#endif
4168 ) {
4169 FD_SET(sock, set);
4170 if (*max_fd == INVALID_SOCKET || sock > *max_fd) {
4171 *max_fd = sock;
4172 }
4173 }
4174}
4175
4177 struct mg_mgr *mgr = iface->mgr;
4178 double now = mg_time();
4179 double min_timer;
4180 struct mg_connection *nc, *tmp;
4181 struct timeval tv;
4184 int num_fds, num_ev, num_timers = 0;
4185#ifdef __unix__
4186 int try_dup = 1;
4187#endif
4188
4189 FD_ZERO(&read_set);
4191 FD_ZERO(&err_set);
4192#if MG_ENABLE_BROADCAST
4193 mg_add_to_set(mgr->ctl[1], &read_set, &max_fd);
4194#endif
4195
4196 /*
4197 * Note: it is ok to have connections with sock == INVALID_SOCKET in the list,
4198 * e.g. timer-only "connections".
4199 */
4200 min_timer = 0;
4201 for (nc = mgr->active_connections, num_fds = 0; nc != NULL; nc = tmp) {
4202 tmp = nc->next;
4203
4204 if (nc->sock != INVALID_SOCKET) {
4205 num_fds++;
4206
4207#ifdef __unix__
4208 /* A hack to make sure all our file descriptos fit into FD_SETSIZE. */
4209 if (nc->sock >= (sock_t) FD_SETSIZE && try_dup) {
4210 int new_sock = dup(nc->sock);
4211 if (new_sock >= 0) {
4212 if (new_sock < (sock_t) FD_SETSIZE) {
4213 closesocket(nc->sock);
4214 DBG(("new sock %d -> %d", nc->sock, new_sock));
4215 nc->sock = new_sock;
4216 } else {
4218 DBG(("new sock is still larger than FD_SETSIZE, disregard"));
4219 try_dup = 0;
4220 }
4221 } else {
4222 try_dup = 0;
4223 }
4224 }
4225#endif
4226
4227 if (nc->recv_mbuf.len < nc->recv_mbuf_limit &&
4228 (!(nc->flags & MG_F_UDP) || nc->listener == NULL)) {
4230 }
4231
4232 if (((nc->flags & MG_F_CONNECTING) && !(nc->flags & MG_F_WANT_READ)) ||
4233 (nc->send_mbuf.len > 0 && !(nc->flags & MG_F_CONNECTING))) {
4236 }
4237 }
4238
4239 if (nc->ev_timer_time > 0) {
4240 if (num_timers == 0 || nc->ev_timer_time < min_timer) {
4242 }
4243 num_timers++;
4244 }
4245 }
4246
4247 /*
4248 * If there is a timer to be fired earlier than the requested timeout,
4249 * adjust the timeout.
4250 */
4251 if (num_timers > 0) {
4252 double timer_timeout_ms = (min_timer - mg_time()) * 1000 + 1 /* rounding */;
4255 }
4256 }
4257 if (timeout_ms < 0) timeout_ms = 0;
4258
4259 tv.tv_sec = timeout_ms / 1000;
4260 tv.tv_usec = (timeout_ms % 1000) * 1000;
4261
4262 num_ev = select((int) max_fd + 1, &read_set, &write_set, &err_set, &tv);
4263 now = mg_time();
4264#if 0
4265 DBG(("select @ %ld num_ev=%d of %d, timeout=%d", (long) now, num_ev, num_fds,
4266 timeout_ms));
4267#endif
4268
4269#if MG_ENABLE_BROADCAST
4270 if (num_ev > 0 && mgr->ctl[1] != INVALID_SOCKET &&
4271 FD_ISSET(mgr->ctl[1], &read_set)) {
4273 }
4274#endif
4275
4276 for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
4277 int fd_flags = 0;
4278 if (nc->sock != INVALID_SOCKET) {
4279 if (num_ev > 0) {
4280 fd_flags = (FD_ISSET(nc->sock, &read_set) &&
4281 (!(nc->flags & MG_F_UDP) || nc->listener == NULL)
4283 : 0) |
4284 (FD_ISSET(nc->sock, &write_set) ? _MG_F_FD_CAN_WRITE : 0) |
4285 (FD_ISSET(nc->sock, &err_set) ? _MG_F_FD_ERROR : 0);
4286 }
4287#if MG_LWIP
4288 /* With LWIP socket emulation layer, we don't get write events for UDP */
4289 if ((nc->flags & MG_F_UDP) && nc->listener == NULL) {
4291 }
4292#endif
4293 }
4294 tmp = nc->next;
4296 }
4297
4298 return (time_t) now;
4299}
4300
4301#if MG_ENABLE_BROADCAST
4303 while (1) {
4304 if (closesocket(*sock) == -1 && errno == EINTR) continue;
4305 break;
4306 }
4307 *sock = INVALID_SOCKET;
4308}
4309
4312 sock_t rc;
4313 while (1) {
4314 if ((rc = accept(sock, &sa->sa, &sa_len)) == INVALID_SOCKET &&
4315 errno == EINTR)
4316 continue;
4317 break;
4318 }
4319 return rc;
4320}
4321
4322int mg_socketpair(sock_t sp[2], int sock_type) {
4323 union socket_address sa, sa2;
4324 sock_t sock;
4325 socklen_t len = sizeof(sa.sin);
4326 int ret = 0;
4327
4328 sock = sp[0] = sp[1] = INVALID_SOCKET;
4329
4330 (void) memset(&sa, 0, sizeof(sa));
4331 sa.sin.sin_family = AF_INET;
4332 sa.sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
4333 sa2 = sa;
4334
4335 if ((sock = socket(AF_INET, sock_type, 0)) == INVALID_SOCKET) {
4336 } else if (bind(sock, &sa.sa, len) != 0) {
4337 } else if (sock_type == SOCK_STREAM && listen(sock, 1) != 0) {
4338 } else if (getsockname(sock, &sa.sa, &len) != 0) {
4339 } else if ((sp[0] = socket(AF_INET, sock_type, 0)) == INVALID_SOCKET) {
4340 } else if (sock_type == SOCK_STREAM && connect(sp[0], &sa.sa, len) != 0) {
4341 } else if (sock_type == SOCK_DGRAM &&
4342 (bind(sp[0], &sa2.sa, len) != 0 ||
4343 getsockname(sp[0], &sa2.sa, &len) != 0 ||
4344 connect(sp[0], &sa.sa, len) != 0 ||
4345 connect(sock, &sa2.sa, len) != 0)) {
4346 } else if ((sp[1] = (sock_type == SOCK_DGRAM ? sock : mg_socketpair_accept(
4347 sock, &sa, len))) ==
4349 } else {
4353 ret = 1;
4354 }
4355
4356 if (!ret) {
4357 if (sp[0] != INVALID_SOCKET) mg_socketpair_close(&sp[0]);
4358 if (sp[1] != INVALID_SOCKET) mg_socketpair_close(&sp[1]);
4359 if (sock != INVALID_SOCKET) mg_socketpair_close(&sock);
4360 }
4361
4362 return ret;
4363}
4364#endif /* MG_ENABLE_BROADCAST */
4365
4366static void mg_sock_get_addr(sock_t sock, int remote,
4367 union socket_address *sa) {
4368 socklen_t slen = sizeof(*sa);
4369 memset(sa, 0, slen);
4370 if (remote) {
4371 getpeername(sock, &sa->sa, &slen);
4372 } else {
4373 getsockname(sock, &sa->sa, &slen);
4374 }
4375}
4376
4377void mg_sock_to_str(sock_t sock, char *buf, size_t len, int flags) {
4378 union socket_address sa;
4380 mg_sock_addr_to_str(&sa, buf, len, flags);
4381}
4382
4384 union socket_address *sa) {
4385 if ((nc->flags & MG_F_UDP) && remote) {
4386 memcpy(sa, &nc->sa, sizeof(*sa));
4387 return;
4388 }
4390}
4391
4392/* clang-format off */
4393#define MG_SOCKET_IFACE_VTABLE \
4394 { \
4395 mg_socket_if_init, \
4396 mg_socket_if_free, \
4397 mg_socket_if_add_conn, \
4398 mg_socket_if_remove_conn, \
4399 mg_socket_if_poll, \
4400 mg_socket_if_listen_tcp, \
4401 mg_socket_if_listen_udp, \
4402 mg_socket_if_connect_tcp, \
4403 mg_socket_if_connect_udp, \
4404 mg_socket_if_tcp_send, \
4405 mg_socket_if_udp_send, \
4406 mg_socket_if_tcp_recv, \
4407 mg_socket_if_udp_recv, \
4408 mg_socket_if_create_conn, \
4409 mg_socket_if_destroy_conn, \
4410 mg_socket_if_sock_set, \
4411 mg_socket_if_get_conn_addr, \
4412 }
4413/* clang-format on */
4414
4416#if MG_NET_IF == MG_NET_IF_SOCKET
4418#endif
4419
4420#endif /* MG_ENABLE_NET_IF_SOCKET */
4421#ifdef MG_MODULE_LINES
4422#line 1 "mongoose/src/mg_net_if_socks.c"
4423#endif
4424/*
4425 * Copyright (c) 2014-2016 Cesanta Software Limited
4426 * All rights reserved
4427 */
4428
4429#if MG_ENABLE_SOCKS
4430
4431struct socksdata {
4432 char *proxy_addr; /* HOST:PORT of the socks5 proxy server */
4433 struct mg_connection *s; /* Respective connection to the server */
4434 struct mg_connection *c; /* Connection to the client */
4435};
4436
4437static void socks_if_disband(struct socksdata *d) {
4438 LOG(LL_DEBUG, ("disbanding proxy %p %p", d->c, d->s));
4439 if (d->c) {
4440 d->c->flags |= MG_F_SEND_AND_CLOSE;
4441 d->c->user_data = NULL;
4442 d->c = NULL;
4443 }
4444 if (d->s) {
4445 d->s->flags |= MG_F_SEND_AND_CLOSE;
4446 d->s->user_data = NULL;
4447 d->s = NULL;
4448 }
4449}
4450
4451static void socks_if_relay(struct mg_connection *s) {
4452 struct socksdata *d = (struct socksdata *) s->user_data;
4453 if (d == NULL || d->c == NULL || !(s->flags & MG_SOCKS_CONNECT_DONE) ||
4454 d->s == NULL) {
4455 return;
4456 }
4457 if (s->recv_mbuf.len > 0) mg_if_can_recv_cb(d->c);
4458 if (d->c->send_mbuf.len > 0 && s->send_mbuf.len == 0) mg_if_can_send_cb(d->c);
4459}
4460
4461static void socks_if_handler(struct mg_connection *c, int ev, void *ev_data) {
4462 struct socksdata *d = (struct socksdata *) c->user_data;
4463 if (d == NULL) return;
4464 if (ev == MG_EV_CONNECT) {
4465 int res = *(int *) ev_data;
4466 if (res == 0) {
4467 /* Send handshake to the proxy server */
4468 unsigned char buf[] = {MG_SOCKS_VERSION, 1, MG_SOCKS_HANDSHAKE_NOAUTH};
4469 mg_send(d->s, buf, sizeof(buf));
4470 LOG(LL_DEBUG, ("Sent handshake to %s", d->proxy_addr));
4471 } else {
4472 LOG(LL_ERROR, ("Cannot connect to %s: %d", d->proxy_addr, res));
4473 d->c->flags |= MG_F_CLOSE_IMMEDIATELY;
4474 }
4475 } else if (ev == MG_EV_CLOSE) {
4477 } else if (ev == MG_EV_RECV) {
4478 /* Handle handshake reply */
4479 if (!(c->flags & MG_SOCKS_HANDSHAKE_DONE)) {
4480 /* TODO(lsm): process IPv6 too */
4481 unsigned char buf[10] = {MG_SOCKS_VERSION, MG_SOCKS_CMD_CONNECT, 0,
4483 if (c->recv_mbuf.len < 2) return;
4484 if ((unsigned char) c->recv_mbuf.buf[1] == MG_SOCKS_HANDSHAKE_FAILURE) {
4485 LOG(LL_ERROR, ("Server kicked us out"));
4487 return;
4488 }
4489 mbuf_remove(&c->recv_mbuf, 2);
4490 c->flags |= MG_SOCKS_HANDSHAKE_DONE;
4491
4492 /* Send connect request */
4493 memcpy(buf + 4, &d->c->sa.sin.sin_addr, 4);
4494 memcpy(buf + 8, &d->c->sa.sin.sin_port, 2);
4495 mg_send(c, buf, sizeof(buf));
4496 LOG(LL_DEBUG, ("%p Sent connect request", c));
4497 }
4498 /* Process connect request */
4499 if ((c->flags & MG_SOCKS_HANDSHAKE_DONE) &&
4500 !(c->flags & MG_SOCKS_CONNECT_DONE)) {
4501 if (c->recv_mbuf.len < 10) return;
4502 if (c->recv_mbuf.buf[1] != MG_SOCKS_SUCCESS) {
4503 LOG(LL_ERROR, ("Socks connection error: %d", c->recv_mbuf.buf[1]));
4505 return;
4506 }
4507 mbuf_remove(&c->recv_mbuf, 10);
4508 c->flags |= MG_SOCKS_CONNECT_DONE;
4509 LOG(LL_DEBUG, ("%p Connect done %p", c, d->c));
4510 mg_if_connect_cb(d->c, 0);
4511 }
4513 } else if (ev == MG_EV_SEND || ev == MG_EV_POLL) {
4515 }
4516}
4517
4518static void mg_socks_if_connect_tcp(struct mg_connection *c,
4519 const union socket_address *sa) {
4520 struct socksdata *d = (struct socksdata *) c->iface->data;
4521 d->c = c;
4522 d->s = mg_connect(c->mgr, d->proxy_addr, socks_if_handler);
4523 d->s->user_data = d;
4524 LOG(LL_DEBUG, ("%p %s %p %p", c, d->proxy_addr, d, d->s));
4525 (void) sa;
4526}
4527
4528static void mg_socks_if_connect_udp(struct mg_connection *c) {
4529 (void) c;
4530}
4531
4532static int mg_socks_if_listen_tcp(struct mg_connection *c,
4533 union socket_address *sa) {
4534 (void) c;
4535 (void) sa;
4536 return 0;
4537}
4538
4539static int mg_socks_if_listen_udp(struct mg_connection *c,
4540 union socket_address *sa) {
4541 (void) c;
4542 (void) sa;
4543 return -1;
4544}
4545
4546static int mg_socks_if_tcp_send(struct mg_connection *c, const void *buf,
4547 size_t len) {
4548 int res;
4549 struct socksdata *d = (struct socksdata *) c->iface->data;
4550 if (d->s == NULL) return -1;
4551 res = (int) mbuf_append(&d->s->send_mbuf, buf, len);
4552 DBG(("%p -> %d -> %p", c, res, d->s));
4553 return res;
4554}
4555
4556static int mg_socks_if_udp_send(struct mg_connection *c, const void *buf,
4557 size_t len) {
4558 (void) c;
4559 (void) buf;
4560 (void) len;
4561 return -1;
4562}
4563
4564int mg_socks_if_tcp_recv(struct mg_connection *c, void *buf, size_t len) {
4565 struct socksdata *d = (struct socksdata *) c->iface->data;
4566 if (d->s == NULL) return -1;
4567 if (len > d->s->recv_mbuf.len) len = d->s->recv_mbuf.len;
4568 if (len > 0) {
4569 memcpy(buf, d->s->recv_mbuf.buf, len);
4570 mbuf_remove(&d->s->recv_mbuf, len);
4571 }
4572 DBG(("%p <- %d <- %p", c, (int) len, d->s));
4573 return len;
4574}
4575
4576int mg_socks_if_udp_recv(struct mg_connection *c, void *buf, size_t len,
4577 union socket_address *sa, size_t *sa_len) {
4578 (void) c;
4579 (void) buf;
4580 (void) len;
4581 (void) sa;
4582 (void) sa_len;
4583 return -1;
4584}
4585
4586static int mg_socks_if_create_conn(struct mg_connection *c) {
4587 (void) c;
4588 return 1;
4589}
4590
4591static void mg_socks_if_destroy_conn(struct mg_connection *c) {
4592 c->iface->vtable->free(c->iface);
4593 MG_FREE(c->iface);
4594 c->iface = NULL;
4595 LOG(LL_DEBUG, ("%p", c));
4596}
4597
4598static void mg_socks_if_sock_set(struct mg_connection *c, sock_t sock) {
4599 (void) c;
4600 (void) sock;
4601}
4602
4603static void mg_socks_if_init(struct mg_iface *iface) {
4604 (void) iface;
4605}
4606
4607static void mg_socks_if_free(struct mg_iface *iface) {
4608 struct socksdata *d = (struct socksdata *) iface->data;
4609 LOG(LL_DEBUG, ("%p", iface));
4610 if (d != NULL) {
4612 MG_FREE(d->proxy_addr);
4613 MG_FREE(d);
4614 iface->data = NULL;
4615 }
4616}
4617
4618static void mg_socks_if_add_conn(struct mg_connection *c) {
4619 c->sock = INVALID_SOCKET;
4620}
4621
4622static void mg_socks_if_remove_conn(struct mg_connection *c) {
4623 (void) c;
4624}
4625
4626static time_t mg_socks_if_poll(struct mg_iface *iface, int timeout_ms) {
4627 LOG(LL_DEBUG, ("%p", iface));
4628 (void) iface;
4629 (void) timeout_ms;
4630 return (time_t) cs_time();
4631}
4632
4633static void mg_socks_if_get_conn_addr(struct mg_connection *c, int remote,
4634 union socket_address *sa) {
4635 LOG(LL_DEBUG, ("%p", c));
4636 (void) c;
4637 (void) remote;
4638 (void) sa;
4639}
4640
4651};
4652
4653struct mg_iface *mg_socks_mk_iface(struct mg_mgr *mgr, const char *proxy_addr) {
4655 iface->data = MG_CALLOC(1, sizeof(struct socksdata));
4656 ((struct socksdata *) iface->data)->proxy_addr = strdup(proxy_addr);
4657 return iface;
4658}
4659
4660#endif
4661#ifdef MG_MODULE_LINES
4662#line 1 "mongoose/src/mg_ssl_if_openssl.c"
4663#endif
4664/*
4665 * Copyright (c) 2014-2016 Cesanta Software Limited
4666 * All rights reserved
4667 */
4668
4669#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_OPENSSL
4670
4671#ifdef __APPLE__
4672#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
4673#endif
4674
4675#include <openssl/ssl.h>
4676#ifndef KR_VERSION
4677#include <openssl/tls1.h>
4678#endif
4679
4680struct mg_ssl_if_ctx {
4681 SSL *ssl;
4682 SSL_CTX *ssl_ctx;
4683 struct mbuf psk;
4684 size_t identity_len;
4685};
4686
4687void mg_ssl_if_init() {
4689}
4690
4692 struct mg_connection *lc) {
4693 struct mg_ssl_if_ctx *ctx =
4694 (struct mg_ssl_if_ctx *) MG_CALLOC(1, sizeof(*ctx));
4695 struct mg_ssl_if_ctx *lc_ctx = (struct mg_ssl_if_ctx *) lc->ssl_if_data;
4696 nc->ssl_if_data = ctx;
4697 if (ctx == NULL || lc_ctx == NULL) return MG_SSL_ERROR;
4698 ctx->ssl_ctx = lc_ctx->ssl_ctx;
4699 if ((ctx->ssl = SSL_new(ctx->ssl_ctx)) == NULL) {
4700 return MG_SSL_ERROR;
4701 }
4702 return MG_SSL_OK;
4703}
4704
4705static enum mg_ssl_if_result mg_use_cert(SSL_CTX *ctx, const char *cert,
4706 const char *key, const char **err_msg);
4707static enum mg_ssl_if_result mg_use_ca_cert(SSL_CTX *ctx, const char *cert);
4708static enum mg_ssl_if_result mg_set_cipher_list(SSL_CTX *ctx, const char *cl);
4710 const char *identity,
4711 const char *key_str);
4712
4714 struct mg_connection *nc, const struct mg_ssl_if_conn_params *params,
4715 const char **err_msg) {
4716 struct mg_ssl_if_ctx *ctx =
4717 (struct mg_ssl_if_ctx *) MG_CALLOC(1, sizeof(*ctx));
4718 DBG(("%p %s,%s,%s", nc, (params->cert ? params->cert : ""),
4719 (params->key ? params->key : ""),
4720 (params->ca_cert ? params->ca_cert : "")));
4721 if (ctx == NULL) {
4722 MG_SET_PTRPTR(err_msg, "Out of memory");
4723 return MG_SSL_ERROR;
4724 }
4725 nc->ssl_if_data = ctx;
4726 if (nc->flags & MG_F_LISTENING) {
4727 ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
4728 } else {
4729 ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
4730 }
4731 if (ctx->ssl_ctx == NULL) {
4732 MG_SET_PTRPTR(err_msg, "Failed to create SSL context");
4733 return MG_SSL_ERROR;
4734 }
4735
4736#ifndef KR_VERSION
4737 /* Disable deprecated protocols. */
4738 SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2);
4739 SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv3);
4740 SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1);
4741#ifdef MG_SSL_OPENSSL_NO_COMPRESSION
4743#endif
4744#ifdef MG_SSL_OPENSSL_CIPHER_SERVER_PREFERENCE
4746#endif
4747#else
4748/* Krypton only supports TLSv1.2 anyway. */
4749#endif
4750
4751 if (params->cert != NULL &&
4752 mg_use_cert(ctx->ssl_ctx, params->cert, params->key, err_msg) !=
4753 MG_SSL_OK) {
4754 return MG_SSL_ERROR;
4755 }
4756
4757 if (params->ca_cert != NULL &&
4758 mg_use_ca_cert(ctx->ssl_ctx, params->ca_cert) != MG_SSL_OK) {
4759 MG_SET_PTRPTR(err_msg, "Invalid SSL CA cert");
4760 return MG_SSL_ERROR;
4761 }
4762
4763 if (mg_set_cipher_list(ctx->ssl_ctx, params->cipher_suites) != MG_SSL_OK) {
4764 MG_SET_PTRPTR(err_msg, "Invalid cipher suite list");
4765 return MG_SSL_ERROR;
4766 }
4767
4768 mbuf_init(&ctx->psk, 0);
4769 if (mg_ssl_if_ossl_set_psk(ctx, params->psk_identity, params->psk_key) !=
4770 MG_SSL_OK) {
4771 MG_SET_PTRPTR(err_msg, "Invalid PSK settings");
4772 return MG_SSL_ERROR;
4773 }
4774
4775 if (!(nc->flags & MG_F_LISTENING) &&
4776 (ctx->ssl = SSL_new(ctx->ssl_ctx)) == NULL) {
4777 MG_SET_PTRPTR(err_msg, "Failed to create SSL session");
4778 return MG_SSL_ERROR;
4779 }
4780
4781 if (params->server_name != NULL) {
4782#ifdef KR_VERSION
4783 SSL_CTX_kr_set_verify_name(ctx->ssl_ctx, params->server_name);
4784#else
4785 SSL_set_tlsext_host_name(ctx->ssl, params->server_name);
4786#endif
4787 }
4788
4789 nc->flags |= MG_F_SSL;
4790
4791 return MG_SSL_OK;
4792}
4793
4794static enum mg_ssl_if_result mg_ssl_if_ssl_err(struct mg_connection *nc,
4795 int res) {
4796 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
4797 int err = SSL_get_error(ctx->ssl, res);
4798 if (err == SSL_ERROR_WANT_READ) return MG_SSL_WANT_READ;
4799 if (err == SSL_ERROR_WANT_WRITE) return MG_SSL_WANT_WRITE;
4800 DBG(("%p %p SSL error: %d %d", nc, ctx->ssl_ctx, res, err));
4801 nc->err = err;
4802 return MG_SSL_ERROR;
4803}
4804
4806 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
4807 int server_side = (nc->listener != NULL);
4808 int res;
4809 /* If descriptor is not yet set, do it now. */
4810 if (SSL_get_fd(ctx->ssl) < 0) {
4811 if (SSL_set_fd(ctx->ssl, nc->sock) != 1) return MG_SSL_ERROR;
4812 }
4813 res = server_side ? SSL_accept(ctx->ssl) : SSL_connect(ctx->ssl);
4814 if (res != 1) return mg_ssl_if_ssl_err(nc, res);
4815 return MG_SSL_OK;
4816}
4817
4818int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t buf_size) {
4819 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
4820 int n = SSL_read(ctx->ssl, buf, buf_size);
4821 DBG(("%p %d -> %d", nc, (int) buf_size, n));
4822 if (n < 0) return mg_ssl_if_ssl_err(nc, n);
4823 if (n == 0) nc->flags |= MG_F_CLOSE_IMMEDIATELY;
4824 return n;
4825}
4826
4827int mg_ssl_if_write(struct mg_connection *nc, const void *data, size_t len) {
4828 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
4829 int n = SSL_write(ctx->ssl, data, len);
4830 DBG(("%p %d -> %d", nc, (int) len, n));
4831 if (n <= 0) return mg_ssl_if_ssl_err(nc, n);
4832 return n;
4833}
4834
4836 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
4837 if (ctx == NULL) return;
4838 SSL_shutdown(ctx->ssl);
4839}
4840
4841void mg_ssl_if_conn_free(struct mg_connection *nc) {
4842 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
4843 if (ctx == NULL) return;
4844 nc->ssl_if_data = NULL;
4845 if (ctx->ssl != NULL) SSL_free(ctx->ssl);
4846 if (ctx->ssl_ctx != NULL && nc->listener == NULL) SSL_CTX_free(ctx->ssl_ctx);
4847 mbuf_free(&ctx->psk);
4848 memset(ctx, 0, sizeof(*ctx));
4849 MG_FREE(ctx);
4850}
4851
4852/*
4853 * Cipher suite options used for TLS negotiation.
4854 * https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations
4855 */
4856static const char mg_s_cipher_list[] =
4857#if defined(MG_SSL_CRYPTO_MODERN)
4858 "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:"
4859 "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:"
4860 "DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:"
4861 "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:"
4862 "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:"
4863 "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:"
4864 "DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:"
4865 "DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:"
4866 "!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK"
4867#elif defined(MG_SSL_CRYPTO_OLD)
4868 "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:"
4869 "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:"
4870 "DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:"
4871 "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:"
4872 "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:"
4873 "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:"
4874 "DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:"
4875 "DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:"
4876 "ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:"
4877 "AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:"
4878 "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:"
4879 "!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"
4880#else /* Default - intermediate. */
4881 "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:"
4882 "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:"
4883 "DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:"
4884 "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:"
4885 "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:"
4886 "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:"
4887 "DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:"
4888 "DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:"
4889 "AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:"
4890 "DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:"
4891 "!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:"
4892 "!CAMELLIA:"
4893 "!RSA:"
4894 "!DES:"
4895 "!3DES"
4896 //TLS_RSA_WITH_AES_128_CBC_SHA256
4897#endif
4898 ;
4899
4900/*
4901 * Default DH params for PFS cipher negotiation. This is a 2048-bit group.
4902 * Will be used if none are provided by the user in the certificate file.
4903 */
4904#if !MG_DISABLE_PFS && !defined(KR_VERSION)
4905static const char mg_s_default_dh_params[] =
4906 "\
4907-----BEGIN DH PARAMETERS-----\n\
4908MIIBCAKCAQEAlvbgD/qh9znWIlGFcV0zdltD7rq8FeShIqIhkQ0C7hYFThrBvF2E\n\
4909Z9bmgaP+sfQwGpVlv9mtaWjvERbu6mEG7JTkgmVUJrUt/wiRzwTaCXBqZkdUO8Tq\n\
4910+E6VOEQAilstG90ikN1Tfo+K6+X68XkRUIlgawBTKuvKVwBhuvlqTGerOtnXWnrt\n\
4911ym//hd3cd5PBYGBix0i7oR4xdghvfR2WLVu0LgdThTBb6XP7gLd19cQ1JuBtAajZ\n\
4912wMuPn7qlUkEFDIkAZy59/Hue/H2Q2vU/JsvVhHWCQBL4F1ofEAt50il6ZxR1QfFK\n\
49139VGKDC4oOgm9DlxwwBoC2FjqmvQlqVV3kwIBAg==\n\
4914-----END DH PARAMETERS-----\n";
4915#endif
4916
4917static enum mg_ssl_if_result mg_use_ca_cert(SSL_CTX *ctx, const char *cert) {
4918 if (cert == NULL || strcmp(cert, "*") == 0) {
4919 return MG_SSL_OK;
4920 }
4923 : MG_SSL_ERROR;
4924}
4925
4926static enum mg_ssl_if_result mg_use_cert(SSL_CTX *ctx, const char *cert,
4927 const char *key,
4928 const char **err_msg) {
4929 if (key == NULL) key = cert;
4930 if (cert == NULL || cert[0] == '\0' || key == NULL || key[0] == '\0') {
4931 return MG_SSL_OK;
4932 } else if (SSL_CTX_use_certificate_file(ctx, cert, 1) == 0) {
4933 MG_SET_PTRPTR(err_msg, "Invalid SSL cert");
4934 return MG_SSL_ERROR;
4935 } else if (SSL_CTX_use_PrivateKey_file(ctx, key, 1) == 0) {
4936 MG_SET_PTRPTR(err_msg, "Invalid SSL key");
4937 return MG_SSL_ERROR;
4938 } else if (SSL_CTX_use_certificate_chain_file(ctx, cert) == 0) {
4939 MG_SET_PTRPTR(err_msg, "Invalid CA bundle");
4940 return MG_SSL_ERROR;
4941 } else {
4943#if !MG_DISABLE_PFS && !defined(KR_VERSION)
4944 BIO *bio = NULL;
4945 DH *dh = NULL;
4946
4947 /* Try to read DH parameters from the cert/key file. */
4948 bio = BIO_new_file(cert, "r");
4949 if (bio != NULL) {
4951 BIO_free(bio);
4952 }
4953 /*
4954 * If there are no DH params in the file, fall back to hard-coded ones.
4955 * Not ideal, but better than nothing.
4956 */
4957 if (dh == NULL) {
4960 BIO_free(bio);
4961 }
4962 if (dh != NULL) {
4963 SSL_CTX_set_tmp_dh(ctx, dh);
4965 DH_free(dh);
4966 }
4967#if OPENSSL_VERSION_NUMBER > 0x10002000L
4968 SSL_CTX_set_ecdh_auto(ctx, 1);
4969#endif
4970#endif
4971 }
4972 return MG_SSL_OK;
4973}
4974
4975static enum mg_ssl_if_result mg_set_cipher_list(SSL_CTX *ctx, const char *cl) {
4976 return (SSL_CTX_set_cipher_list(ctx, cl ? cl : mg_s_cipher_list) == 1
4977 ? MG_SSL_OK
4978 : MG_SSL_ERROR);
4979}
4980
4981#if !defined(KR_VERSION) && !defined(LIBRESSL_VERSION_NUMBER)
4982static unsigned int mg_ssl_if_ossl_psk_cb(SSL *ssl, const char *hint,
4983 char *identity,
4984 unsigned int max_identity_len,
4985 unsigned char *psk,
4986 unsigned int max_psk_len) {
4987 struct mg_ssl_if_ctx *ctx =
4989 size_t key_len = ctx->psk.len - ctx->identity_len - 1;
4990 DBG(("hint: '%s'", (hint ? hint : "")));
4991 if (ctx->identity_len + 1 > max_identity_len) {
4992 DBG(("identity too long"));
4993 return 0;
4994 }
4995 if (key_len > max_psk_len) {
4996 DBG(("key too long"));
4997 return 0;
4998 }
4999 memcpy(identity, ctx->psk.buf, ctx->identity_len + 1);
5000 memcpy(psk, ctx->psk.buf + ctx->identity_len + 1, key_len);
5001 (void) ssl;
5002 return key_len;
5003}
5004
5006 const char *identity,
5007 const char *key_str) {
5008 unsigned char key[32];
5009 size_t key_len;
5010 size_t i = 0;
5011 if (identity == NULL && key_str == NULL) return MG_SSL_OK;
5012 if (identity == NULL || key_str == NULL) return MG_SSL_ERROR;
5014 if (key_len != 32 && key_len != 64) return MG_SSL_ERROR;
5015 memset(key, 0, sizeof(key));
5016 key_len = 0;
5017 for (i = 0; key_str[i] != '\0'; i++) {
5018 unsigned char c;
5019 char hc = tolower((int) key_str[i]);
5020 if (hc >= '0' && hc <= '9') {
5021 c = hc - '0';
5022 } else if (hc >= 'a' && hc <= 'f') {
5023 c = hc - 'a' + 0xa;
5024 } else {
5025 return MG_SSL_ERROR;
5026 }
5027 key_len = i / 2;
5028 key[key_len] <<= 4;
5029 key[key_len] |= c;
5030 }
5031 key_len++;
5032 DBG(("identity = '%s', key = (%u)", identity, (unsigned int) key_len));
5033 ctx->identity_len = strlen(identity);
5034 mbuf_append(&ctx->psk, identity, ctx->identity_len + 1);
5035 mbuf_append(&ctx->psk, key, key_len);
5037 SSL_CTX_set_app_data(ctx->ssl_ctx, ctx);
5038 return MG_SSL_OK;
5039}
5040#else
5042 const char *identity,
5043 const char *key_str) {
5044 (void) ctx;
5045 (void) identity;
5046 (void) key_str;
5047 /* Krypton / LibreSSL does not support PSK. */
5048 return MG_SSL_ERROR;
5049}
5050#endif /* !defined(KR_VERSION) && !defined(LIBRESSL_VERSION_NUMBER) */
5051
5052const char *mg_set_ssl(struct mg_connection *nc, const char *cert,
5053 const char *ca_cert) {
5054 const char *err_msg = NULL;
5055 struct mg_ssl_if_conn_params params;
5056 memset(&params, 0, sizeof(params));
5057 params.cert = cert;
5058 params.ca_cert = ca_cert;
5059 if (mg_ssl_if_conn_init(nc, &params, &err_msg) != MG_SSL_OK) {
5060 return err_msg;
5061 }
5062 return NULL;
5063}
5064
5065#endif /* MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_OPENSSL */
5066#ifdef MG_MODULE_LINES
5067#line 1 "mongoose/src/mg_ssl_if_mbedtls.c"
5068#endif
5069/*
5070 * Copyright (c) 2014-2016 Cesanta Software Limited
5071 * All rights reserved
5072 */
5073
5074#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_MBEDTLS
5075
5076#include <mbedtls/debug.h>
5077#include <mbedtls/ecp.h>
5078#include <mbedtls/net.h>
5079#include <mbedtls/platform.h>
5080#include <mbedtls/ssl.h>
5081#include <mbedtls/ssl_internal.h>
5082#include <mbedtls/x509_crt.h>
5083#include <mbedtls/version.h>
5084
5085static void mg_ssl_mbed_log(void *ctx, int level, const char *file, int line,
5086 const char *str) {
5088 switch (level) {
5089 case 1:
5091 break;
5092 case 2:
5093 cs_level = LL_INFO;
5094 break;
5095 case 3:
5097 break;
5098 default:
5100 }
5101 /* mbedTLS passes strings with \n at the end, strip it. */
5102 LOG(cs_level, ("%p %.*s", ctx, (int) (strlen(str) - 1), str));
5103 (void) ctx;
5104 (void) str;
5105 (void) file;
5106 (void) line;
5107 (void) cs_level;
5108}
5109
5110struct mg_ssl_if_ctx {
5116 struct mbuf cipher_suites;
5117 size_t saved_len;
5118};
5119
5120/* Must be provided by the platform. ctx is struct mg_connection. */
5121extern int mg_ssl_if_mbed_random(void *ctx, unsigned char *buf, size_t len);
5122
5123void mg_ssl_if_init() {
5125}
5126
5128 struct mg_connection *lc) {
5129 struct mg_ssl_if_ctx *ctx =
5130 (struct mg_ssl_if_ctx *) MG_CALLOC(1, sizeof(*ctx));
5131 struct mg_ssl_if_ctx *lc_ctx = (struct mg_ssl_if_ctx *) lc->ssl_if_data;
5132 nc->ssl_if_data = ctx;
5133 if (ctx == NULL || lc_ctx == NULL) return MG_SSL_ERROR;
5134 ctx->ssl = (mbedtls_ssl_context *) MG_CALLOC(1, sizeof(*ctx->ssl));
5135 if (mbedtls_ssl_setup(ctx->ssl, lc_ctx->conf) != 0) {
5136 return MG_SSL_ERROR;
5137 }
5138 return MG_SSL_OK;
5139}
5140
5141static enum mg_ssl_if_result mg_use_cert(struct mg_ssl_if_ctx *ctx,
5142 const char *cert, const char *key,
5143 const char **err_msg);
5144static enum mg_ssl_if_result mg_use_ca_cert(struct mg_ssl_if_ctx *ctx,
5145 const char *cert);
5146static enum mg_ssl_if_result mg_set_cipher_list(struct mg_ssl_if_ctx *ctx,
5147 const char *ciphers);
5148#ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED
5150 const char *identity,
5151 const char *key);
5152#endif
5153
5155 struct mg_connection *nc, const struct mg_ssl_if_conn_params *params,
5156 const char **err_msg) {
5157 struct mg_ssl_if_ctx *ctx =
5158 (struct mg_ssl_if_ctx *) MG_CALLOC(1, sizeof(*ctx));
5159 DBG(("%p %s,%s,%s", nc, (params->cert ? params->cert : ""),
5160 (params->key ? params->key : ""),
5161 (params->ca_cert ? params->ca_cert : "")));
5162
5163 if (ctx == NULL) {
5164 MG_SET_PTRPTR(err_msg, "Out of memory");
5165 return MG_SSL_ERROR;
5166 }
5167 nc->ssl_if_data = ctx;
5168 ctx->conf = (mbedtls_ssl_config *) MG_CALLOC(1, sizeof(*ctx->conf));
5169 mbuf_init(&ctx->cipher_suites, 0);
5170 mbedtls_ssl_config_init(ctx->conf);
5171 mbedtls_ssl_conf_dbg(ctx->conf, mg_ssl_mbed_log, nc);
5173 ctx->conf, (nc->flags & MG_F_LISTENING ? MBEDTLS_SSL_IS_SERVER
5176 MG_SET_PTRPTR(err_msg, "Failed to init SSL config");
5177 return MG_SSL_ERROR;
5178 }
5179
5180 /* TLS 1.2 and up */
5184
5185 if (params->cert != NULL &&
5186 mg_use_cert(ctx, params->cert, params->key, err_msg) != MG_SSL_OK) {
5187 return MG_SSL_ERROR;
5188 }
5189
5190 if (params->ca_cert != NULL &&
5191 mg_use_ca_cert(ctx, params->ca_cert) != MG_SSL_OK) {
5192 MG_SET_PTRPTR(err_msg, "Invalid SSL CA cert");
5193 return MG_SSL_ERROR;
5194 }
5195
5196 if (mg_set_cipher_list(ctx, params->cipher_suites) != MG_SSL_OK) {
5197 MG_SET_PTRPTR(err_msg, "Invalid cipher suite list");
5198 return MG_SSL_ERROR;
5199 }
5200
5201#ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED
5202 if (mg_ssl_if_mbed_set_psk(ctx, params->psk_identity, params->psk_key) !=
5203 MG_SSL_OK) {
5204 MG_SET_PTRPTR(err_msg, "Invalid PSK settings");
5205 return MG_SSL_ERROR;
5206 }
5207#endif
5208
5209 if (!(nc->flags & MG_F_LISTENING)) {
5210 ctx->ssl = (mbedtls_ssl_context *) MG_CALLOC(1, sizeof(*ctx->ssl));
5211 mbedtls_ssl_init(ctx->ssl);
5212 if (mbedtls_ssl_setup(ctx->ssl, ctx->conf) != 0) {
5213 MG_SET_PTRPTR(err_msg, "Failed to create SSL session");
5214 return MG_SSL_ERROR;
5215 }
5216 if (params->server_name != NULL &&
5217 mbedtls_ssl_set_hostname(ctx->ssl, params->server_name) != 0) {
5218 return MG_SSL_ERROR;
5219 }
5220 }
5221
5222#ifdef MG_SSL_IF_MBEDTLS_MAX_FRAG_LEN
5223 if (mbedtls_ssl_conf_max_frag_len(ctx->conf,
5232#else
5234#endif
5235 ) != 0) {
5236 return MG_SSL_ERROR;
5237 }
5238#endif
5239
5240 nc->flags |= MG_F_SSL;
5241
5242 return MG_SSL_OK;
5243}
5244
5245static int mg_ssl_if_mbed_send(void *ctx, const unsigned char *buf,
5246 size_t len) {
5247 struct mg_connection *nc = (struct mg_connection *) ctx;
5248 int n = nc->iface->vtable->tcp_send(nc, buf, len);
5249 if (n > 0) return n;
5250 if (n == 0) return MBEDTLS_ERR_SSL_WANT_WRITE;
5252}
5253
5254static int mg_ssl_if_mbed_recv(void *ctx, unsigned char *buf, size_t len) {
5255 struct mg_connection *nc = (struct mg_connection *) ctx;
5256 int n = nc->iface->vtable->tcp_recv(nc, buf, len);
5257 if (n > 0) return n;
5258 if (n == 0) return MBEDTLS_ERR_SSL_WANT_READ;
5260}
5261
5263 int ret) {
5265 if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
5267 } else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
5269 } else if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
5270 LOG(LL_DEBUG, ("%p TLS connection closed by peer", nc));
5272 res = MG_SSL_OK;
5273 } else if (ret == MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE) {
5275 res = MG_SSL_ERROR;
5276 } else if (ret == MBEDTLS_ERR_SSL_INVALID_MAC) {
5278 res = MG_SSL_ERROR;
5279 } else if (ret == MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION) {
5281 res = MG_SSL_ERROR;
5284 res = MG_SSL_ERROR;
5285 } else if (ret == MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN) {
5287 res = MG_SSL_ERROR;
5288 } else if (ret == MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE) {
5290 res = MG_SSL_ERROR;
5291 } else if (ret == MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO) {
5293 res = MG_SSL_ERROR;
5294 } else if (ret == MBEDTLS_ERR_NET_RECV_FAILED) {
5296 res = MG_SSL_ERROR;
5297 } else {
5298 LOG(LL_ERROR, ("%p mbedTLS error: -0x%04x", nc, -ret));
5300 res = MG_SSL_ERROR;
5301 }
5302 nc->err = ret;
5303 return res;
5304}
5305
5307 if (ctx->cert != NULL) {
5309 MG_FREE(ctx->cert);
5310 ctx->cert = NULL;
5311 mbedtls_pk_free(ctx->key);
5312 MG_FREE(ctx->key);
5313 ctx->key = NULL;
5314 }
5315 if (ctx->ca_cert != NULL) {
5317#ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK
5318 if (ctx->conf->ca_chain_file != NULL) {
5319 MG_FREE((void *) ctx->conf->ca_chain_file);
5320 ctx->conf->ca_chain_file = NULL;
5321 }
5322#endif
5323 mbedtls_x509_crt_free(ctx->ca_cert);
5324 MG_FREE(ctx->ca_cert);
5325 ctx->ca_cert = NULL;
5326 }
5327}
5328
5330 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
5331 int err;
5332 /* If bio is not yet set, do it now. */
5333 if (ctx->ssl->p_bio == NULL) {
5335 NULL);
5336 }
5337 err = mbedtls_ssl_handshake(ctx->ssl);
5338 if (err != 0) return mg_ssl_if_mbed_err(nc, err);
5339#ifdef MG_SSL_IF_MBEDTLS_FREE_CERTS
5340 /*
5341 * Free the peer certificate, we don't need it after handshake.
5342 * Note that this effectively disables renegotiation.
5343 */
5344 mbedtls_x509_crt_free(ctx->ssl->session->peer_cert);
5345 mbedtls_free(ctx->ssl->session->peer_cert);
5346 ctx->ssl->session->peer_cert = NULL;
5347 /* On a client connection we can also free our own and CA certs. */
5348 if (nc->listener == NULL) {
5349 if (ctx->conf->key_cert != NULL) {
5350 /* Note that this assumes one key_cert entry, which matches our init. */
5351 MG_FREE(ctx->conf->key_cert);
5352 ctx->conf->key_cert = NULL;
5353 }
5354 mbedtls_ssl_conf_ca_chain(ctx->conf, NULL, NULL);
5356 }
5357#endif
5358 return MG_SSL_OK;
5359}
5360
5361int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t len) {
5362 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
5363 int n = mbedtls_ssl_read(ctx->ssl, (unsigned char *) buf, len);
5364 DBG(("%p %d -> %d", nc, (int) len, n));
5365 if (n < 0) return mg_ssl_if_mbed_err(nc, n);
5366 if (n == 0) nc->flags |= MG_F_CLOSE_IMMEDIATELY;
5367 return n;
5368}
5369
5370int mg_ssl_if_write(struct mg_connection *nc, const void *buf, size_t len) {
5371 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
5372 /* Per mbedTLS docs, if write returns WANT_READ or WANT_WRITE, the operation
5373 * should be retried with the same data and length.
5374 * Here we assume that the data being pushed will remain the same but the
5375 * amount may grow between calls so we save the length that was used and
5376 * retry. The assumption being that the data itself won't change and won't
5377 * be removed. */
5378 size_t l = len;
5379 if (ctx->saved_len > 0 && ctx->saved_len < l) l = ctx->saved_len;
5380 int n = mbedtls_ssl_write(ctx->ssl, (const unsigned char *) buf, l);
5381 DBG(("%p %d,%d,%d -> %d", nc, (int) len, (int) ctx->saved_len, (int) l, n));
5382 if (n < 0) {
5384 ctx->saved_len = len;
5385 }
5386 return mg_ssl_if_mbed_err(nc, n);
5387 } else if (n > 0) {
5388 ctx->saved_len = 0;
5389 }
5390 return n;
5391}
5392
5394 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
5395 if (ctx == NULL) return;
5396 mbedtls_ssl_close_notify(ctx->ssl);
5397}
5398
5399void mg_ssl_if_conn_free(struct mg_connection *nc) {
5400 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
5401 if (ctx == NULL) return;
5402 nc->ssl_if_data = NULL;
5403 if (ctx->ssl != NULL) {
5404 mbedtls_ssl_free(ctx->ssl);
5405 MG_FREE(ctx->ssl);
5406 }
5408 if (ctx->conf != NULL) {
5409 mbedtls_ssl_config_free(ctx->conf);
5410 MG_FREE(ctx->conf);
5411 }
5412 mbuf_free(&ctx->cipher_suites);
5413 memset(ctx, 0, sizeof(*ctx));
5414 MG_FREE(ctx);
5415}
5416
5417static enum mg_ssl_if_result mg_use_ca_cert(struct mg_ssl_if_ctx *ctx,
5418 const char *ca_cert) {
5419 if (ca_cert == NULL || strcmp(ca_cert, "*") == 0) {
5421 return MG_SSL_OK;
5422 }
5423 ctx->ca_cert = (mbedtls_x509_crt *) MG_CALLOC(1, sizeof(*ctx->ca_cert));
5424 mbedtls_x509_crt_init(ctx->ca_cert);
5425#ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK
5428#else
5429 if (mbedtls_x509_crt_parse_file(ctx->ca_cert, ca_cert) != 0) {
5430 return MG_SSL_ERROR;
5431 }
5432 mbedtls_ssl_conf_ca_chain(ctx->conf, ctx->ca_cert, NULL);
5433#endif
5435 return MG_SSL_OK;
5436}
5437
5438static enum mg_ssl_if_result mg_use_cert(struct mg_ssl_if_ctx *ctx,
5439 const char *cert, const char *key,
5440 const char **err_msg) {
5441 if (key == NULL) key = cert;
5442 if (cert == NULL || cert[0] == '\0' || key == NULL || key[0] == '\0') {
5443 return MG_SSL_OK;
5444 }
5445 ctx->cert = (mbedtls_x509_crt *) MG_CALLOC(1, sizeof(*ctx->cert));
5446 mbedtls_x509_crt_init(ctx->cert);
5447 ctx->key = (mbedtls_pk_context *) MG_CALLOC(1, sizeof(*ctx->key));
5448 mbedtls_pk_init(ctx->key);
5449 if (mbedtls_x509_crt_parse_file(ctx->cert, cert) != 0) {
5450 MG_SET_PTRPTR(err_msg, "Invalid SSL cert");
5451 return MG_SSL_ERROR;
5452 }
5453 if (mbedtls_pk_parse_keyfile(ctx->key, key, NULL) != 0) {
5454 MG_SET_PTRPTR(err_msg, "Invalid SSL key");
5455 return MG_SSL_ERROR;
5456 }
5457 if (mbedtls_ssl_conf_own_cert(ctx->conf, ctx->cert, ctx->key) != 0) {
5458 MG_SET_PTRPTR(err_msg, "Invalid SSL key or cert");
5459 return MG_SSL_ERROR;
5460 }
5461 return MG_SSL_OK;
5462}
5463
5464static const int mg_s_cipher_list[] = {
5465#if CS_PLATFORM != CS_P_ESP8266
5481#else
5482 /*
5483 * ECDHE is way too slow on ESP8266 w/o cryptochip, this sometimes results
5484 * in WiFi STA deauths. Use weaker but faster cipher suites. Sad but true.
5485 * Disable DHE completely because it's just hopelessly slow.
5486 */
5500#endif /* CS_PLATFORM != CS_P_ESP8266 */
5501 0,
5502};
5503
5504/*
5505 * Ciphers can be specified as a colon-separated list of cipher suite names.
5506 * These can be found in
5507 * https://github.com/ARMmbed/mbedtls/blob/development/library/ssl_ciphersuites.c#L267
5508 * E.g.: TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-CCM
5509 */
5510static enum mg_ssl_if_result mg_set_cipher_list(struct mg_ssl_if_ctx *ctx,
5511 const char *ciphers) {
5512 if (ciphers != NULL) {
5513 int l, id;
5514 const char *s = ciphers, *e;
5515 char tmp[50];
5516 while (s != NULL) {
5517 e = strchr(s, ':');
5518 l = (e != NULL ? (e - s) : (int) strlen(s));
5519 strncpy(tmp, s, l);
5520 tmp[l] = '\0';
5522 DBG(("%s -> %04x", tmp, id));
5523 if (id != 0) {
5524 mbuf_append(&ctx->cipher_suites, &id, sizeof(id));
5525 }
5526 s = (e != NULL ? e + 1 : NULL);
5527 }
5528 if (ctx->cipher_suites.len == 0) return MG_SSL_ERROR;
5529 id = 0;
5530 mbuf_append(&ctx->cipher_suites, &id, sizeof(id));
5531 mbuf_trim(&ctx->cipher_suites);
5533 (const int *) ctx->cipher_suites.buf);
5534 } else {
5536 }
5537 return MG_SSL_OK;
5538}
5539
5540#ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED
5542 const char *identity,
5543 const char *key_str) {
5544 unsigned char key[32];
5545 size_t key_len;
5546 if (identity == NULL && key_str == NULL) return MG_SSL_OK;
5547 if (identity == NULL || key_str == NULL) return MG_SSL_ERROR;
5549 if (key_len != 32 && key_len != 64) return MG_SSL_ERROR;
5550 size_t i = 0;
5551 memset(key, 0, sizeof(key));
5552 key_len = 0;
5553 for (i = 0; key_str[i] != '\0'; i++) {
5554 unsigned char c;
5555 char hc = tolower((int) key_str[i]);
5556 if (hc >= '0' && hc <= '9') {
5557 c = hc - '0';
5558 } else if (hc >= 'a' && hc <= 'f') {
5559 c = hc - 'a' + 0xa;
5560 } else {
5561 return MG_SSL_ERROR;
5562 }
5563 key_len = i / 2;
5564 key[key_len] <<= 4;
5565 key[key_len] |= c;
5566 }
5567 key_len++;
5568 DBG(("identity = '%s', key = (%u)", identity, (unsigned int) key_len));
5569 /* mbedTLS makes copies of psk and identity. */
5570 if (mbedtls_ssl_conf_psk(ctx->conf, (const unsigned char *) key, key_len,
5571 (const unsigned char *) identity,
5572 strlen(identity)) != 0) {
5573 return MG_SSL_ERROR;
5574 }
5575 return MG_SSL_OK;
5576}
5577#endif
5578
5579const char *mg_set_ssl(struct mg_connection *nc, const char *cert,
5580 const char *ca_cert) {
5581 const char *err_msg = NULL;
5582 struct mg_ssl_if_conn_params params;
5583 memset(&params, 0, sizeof(params));
5584 params.cert = cert;
5585 params.ca_cert = ca_cert;
5586 if (mg_ssl_if_conn_init(nc, &params, &err_msg) != MG_SSL_OK) {
5587 return err_msg;
5588 }
5589 return NULL;
5590}
5591
5592/* Lazy RNG. Warning: it would be a bad idea to do this in production! */
5593#ifdef MG_SSL_MBED_DUMMY_RANDOM
5594int mg_ssl_if_mbed_random(void *ctx, unsigned char *buf, size_t len) {
5595 (void) ctx;
5596 while (len--) *buf++ = rand();
5597 return 0;
5598}
5599#endif
5600
5601#endif /* MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_MBEDTLS */
5602#ifdef MG_MODULE_LINES
5603#line 1 "mongoose/src/mg_uri.c"
5604#endif
5605/*
5606 * Copyright (c) 2014 Cesanta Software Limited
5607 * All rights reserved
5608 */
5609
5610/* Amalgamated: #include "mg_internal.h" */
5611/* Amalgamated: #include "mg_uri.h" */
5612
5613/*
5614 * scan string until encountering one of `seps`, keeping track of component
5615 * boundaries in `res`.
5616 *
5617 * `p` will point to the char after the separator or it will be `end`.
5618 */
5619static void parse_uri_component(const char **p, const char *end,
5620 const char *seps, struct mg_str *res) {
5621 const char *q;
5622 res->p = *p;
5623 for (; *p < end; (*p)++) {
5624 for (q = seps; *q != '\0'; q++) {
5625 if (**p == *q) break;
5626 }
5627 if (*q != '\0') break;
5628 }
5629 res->len = (*p) - res->p;
5630 if (*p < end) (*p)++;
5631}
5632
5633int mg_parse_uri(const struct mg_str uri, struct mg_str *scheme,
5634 struct mg_str *user_info, struct mg_str *host,
5635 unsigned int *port, struct mg_str *path, struct mg_str *query,
5636 struct mg_str *fragment) {
5637 struct mg_str rscheme = {0, 0}, ruser_info = {0, 0}, rhost = {0, 0},
5638 rpath = {0, 0}, rquery = {0, 0}, rfragment = {0, 0};
5639 unsigned int rport = 0;
5640 enum {
5641 P_START,
5644 P_HOST,
5645 P_PORT,
5646 P_REST
5647 } state = P_START;
5648
5649 const char *p = uri.p, *end = p + uri.len;
5650 while (p < end) {
5651 switch (state) {
5652 case P_START:
5653 /*
5654 * expecting on of:
5655 * - `scheme://xxxx`
5656 * - `xxxx:port`
5657 * - `[a:b:c]:port`
5658 * - `xxxx/path`
5659 */
5660 if (*p == '[') {
5661 state = P_HOST;
5662 break;
5663 }
5664 for (; p < end; p++) {
5665 if (*p == ':') {
5667 break;
5668 } else if (*p == '/') {
5669 state = P_REST;
5670 break;
5671 }
5672 }
5673 if (state == P_START || state == P_REST) {
5674 rhost.p = uri.p;
5675 rhost.len = p - uri.p;
5676 }
5677 break;
5678 case P_SCHEME_OR_PORT:
5679 if (end - p >= 3 && strncmp(p, "://", 3) == 0) {
5680 rscheme.p = uri.p;
5681 rscheme.len = p - uri.p;
5683 p += 3;
5684 } else {
5685 rhost.p = uri.p;
5686 rhost.len = p - uri.p;
5687 state = P_PORT;
5688 }
5689 break;
5690 case P_USER_INFO:
5691 ruser_info.p = p;
5692 for (; p < end; p++) {
5693 if (*p == '@' || *p == '[' || *p == '/') {
5694 break;
5695 }
5696 }
5697 if (p == end || *p == '/' || *p == '[') {
5698 /* backtrack and parse as host */
5699 p = ruser_info.p;
5700 }
5701 ruser_info.len = p - ruser_info.p;
5702 state = P_HOST;
5703 break;
5704 case P_HOST:
5705 if (*p == '@') p++;
5706 rhost.p = p;
5707 if (*p == '[') {
5708 int found = 0;
5709 for (; !found && p < end; p++) {
5710 found = (*p == ']');
5711 }
5712 if (!found) return -1;
5713 } else {
5714 for (; p < end; p++) {
5715 if (*p == ':' || *p == '/') break;
5716 }
5717 }
5718 rhost.len = p - rhost.p;
5719 if (p < end) {
5720 if (*p == ':') {
5721 state = P_PORT;
5722 break;
5723 } else if (*p == '/') {
5724 state = P_REST;
5725 break;
5726 }
5727 }
5728 break;
5729 case P_PORT:
5730 p++;
5731 for (; p < end; p++) {
5732 if (*p == '/') {
5733 state = P_REST;
5734 break;
5735 }
5736 rport *= 10;
5737 rport += *p - '0';
5738 }
5739 break;
5740 case P_REST:
5741 /* `p` points to separator. `path` includes the separator */
5742 parse_uri_component(&p, end, "?#", &rpath);
5743 if (p < end && *(p - 1) == '?') {
5744 parse_uri_component(&p, end, "#", &rquery);
5745 }
5747 break;
5748 }
5749 }
5750
5751 if (scheme != 0) *scheme = rscheme;
5752 if (user_info != 0) *user_info = ruser_info;
5753 if (host != 0) *host = rhost;
5754 if (port != 0) *port = rport;
5755 if (path != 0) *path = rpath;
5756 if (query != 0) *query = rquery;
5757 if (fragment != 0) *fragment = rfragment;
5758
5759 return 0;
5760}
5761
5762/* Normalize the URI path. Remove/resolve "." and "..". */
5763int mg_normalize_uri_path(const struct mg_str *in, struct mg_str *out) {
5764 const char *s = in->p, *se = s + in->len;
5765 char *cp = (char *) out->p, *d;
5766
5767 if (in->len == 0 || *s != '/') {
5768 out->len = 0;
5769 return 0;
5770 }
5771
5772 d = cp;
5773
5774 while (s < se) {
5775 const char *next = s;
5776 struct mg_str component;
5777 parse_uri_component(&next, se, "/", &component);
5778 if (mg_vcmp(&component, ".") == 0) {
5779 /* Yum. */
5780 } else if (mg_vcmp(&component, "..") == 0) {
5781 /* Backtrack to previous slash. */
5782 if (d > cp + 1 && *(d - 1) == '/') d--;
5783 while (d > cp && *(d - 1) != '/') d--;
5784 } else {
5785 memmove(d, s, next - s);
5786 d += next - s;
5787 }
5788 s = next;
5789 }
5790 if (d == cp) *d++ = '/';
5791
5792 out->p = cp;
5793 out->len = d - cp;
5794 return 1;
5795}
5796
5797int mg_assemble_uri(const struct mg_str *scheme, const struct mg_str *user_info,
5798 const struct mg_str *host, unsigned int port,
5799 const struct mg_str *path, const struct mg_str *query,
5800 const struct mg_str *fragment, int normalize_path,
5801 struct mg_str *uri) {
5802 int result = -1;
5803 struct mbuf out;
5804 mbuf_init(&out, 0);
5805
5806 if (scheme != NULL && scheme->len > 0) {
5807 mbuf_append(&out, scheme->p, scheme->len);
5808 mbuf_append(&out, "://", 3);
5809 }
5810
5811 if (user_info != NULL && user_info->len > 0) {
5812 mbuf_append(&out, user_info->p, user_info->len);
5813 mbuf_append(&out, "@", 1);
5814 }
5815
5816 if (host != NULL && host->len > 0) {
5817 mbuf_append(&out, host->p, host->len);
5818 }
5819
5820 if (port != 0) {
5821 char port_str[20];
5822 int port_str_len = sprintf(port_str, ":%u", port);
5824 }
5825
5826 if (path != NULL && path->len > 0) {
5827 if (normalize_path) {
5828 struct mg_str npath = mg_strdup(*path);
5829 if (npath.len != path->len) goto out;
5830 if (!mg_normalize_uri_path(path, &npath)) {
5831 free((void *) npath.p);
5832 goto out;
5833 }
5834 mbuf_append(&out, npath.p, npath.len);
5835 free((void *) npath.p);
5836 } else {
5837 mbuf_append(&out, path->p, path->len);
5838 }
5839 } else if (normalize_path) {
5840 mbuf_append(&out, "/", 1);
5841 }
5842
5843 if (query != NULL && query->len > 0) {
5844 mbuf_append(&out, "?", 1);
5845 mbuf_append(&out, query->p, query->len);
5846 }
5847
5848 if (fragment != NULL && fragment->len > 0) {
5849 mbuf_append(&out, "#", 1);
5850 mbuf_append(&out, fragment->p, fragment->len);
5851 }
5852
5853 result = 0;
5854
5855out:
5856 if (result == 0) {
5857 uri->p = out.buf;
5858 uri->len = out.len;
5859 } else {
5860 mbuf_free(&out);
5861 uri->p = NULL;
5862 uri->len = 0;
5863 }
5864 return result;
5865}
5866#ifdef MG_MODULE_LINES
5867#line 1 "mongoose/src/mg_http.c"
5868#endif
5869/*
5870 * Copyright (c) 2014 Cesanta Software Limited
5871 * All rights reserved
5872 */
5873
5874#if MG_ENABLE_HTTP
5875
5876/* Amalgamated: #include "common/cs_md5.h" */
5877/* Amalgamated: #include "mg_internal.h" */
5878/* Amalgamated: #include "mg_util.h" */
5879
5880/* altbuf {{{ */
5881
5882/*
5883 * Alternate buffer: fills the client-provided buffer with data; and if it's
5884 * not large enough, allocates another buffer (via mbuf), similar to asprintf.
5885 */
5886struct altbuf {
5887 struct mbuf m;
5888 char *user_buf;
5889 size_t len;
5890 size_t user_buf_size;
5891};
5892
5893/*
5894 * Initializes altbuf; `buf`, `buf_size` is the client-provided buffer.
5895 */
5896MG_INTERNAL void altbuf_init(struct altbuf *ab, char *buf, size_t buf_size) {
5897 mbuf_init(&ab->m, 0);
5898 ab->user_buf = buf;
5899 ab->user_buf_size = buf_size;
5900 ab->len = 0;
5901}
5902
5903/*
5904 * Appends a single char to the altbuf.
5905 */
5906MG_INTERNAL void altbuf_append(struct altbuf *ab, char c) {
5907 if (ab->len < ab->user_buf_size) {
5908 /* The data fits into the original buffer */
5909 ab->user_buf[ab->len++] = c;
5910 } else {
5911 /* The data can't fit into the original buffer, so write it to mbuf. */
5912
5913 /*
5914 * First of all, see if that's the first byte which overflows the original
5915 * buffer: if so, copy the existing data from there to a newly allocated
5916 * mbuf.
5917 */
5918 if (ab->len > 0 && ab->m.len == 0) {
5919 mbuf_append(&ab->m, ab->user_buf, ab->len);
5920 }
5921
5922 mbuf_append(&ab->m, &c, 1);
5923 ab->len = ab->m.len;
5924 }
5925}
5926
5927/*
5928 * Resets any data previously appended to altbuf.
5929 */
5930MG_INTERNAL void altbuf_reset(struct altbuf *ab) {
5931 mbuf_free(&ab->m);
5932 ab->len = 0;
5933}
5934
5935/*
5936 * Returns whether the additional buffer was allocated (and thus the data
5937 * is in the mbuf, not the client-provided buffer)
5938 */
5940 return ab->len > ab->user_buf_size;
5941}
5942
5943/*
5944 * Returns the actual buffer with data, either the client-provided or a newly
5945 * allocated one. If `trim` is non-zero, mbuf-backed buffer is trimmed first.
5946 */
5947MG_INTERNAL char *altbuf_get_buf(struct altbuf *ab, int trim) {
5948 if (altbuf_reallocated(ab)) {
5949 if (trim) {
5950 mbuf_trim(&ab->m);
5951 }
5952 return ab->m.buf;
5953 } else {
5954 return ab->user_buf;
5955 }
5956}
5957
5958/* }}} */
5959
5960static const char *mg_version_header = "Mongoose/" MG_VERSION;
5961
5963
5965 FILE *fp; /* Opened file. */
5966 int64_t cl; /* Content-Length. How many bytes to send. */
5967 int64_t sent; /* How many bytes have been already sent. */
5968 int keepalive; /* Keep connection open after sending. */
5970};
5971
5972#if MG_ENABLE_HTTP_CGI
5974 struct mg_connection *cgi_nc;
5975};
5976#endif
5977
5979 int64_t body_len; /* How many bytes of chunked body was reassembled. */
5980};
5981
5982struct mg_http_endpoint {
5983 struct mg_http_endpoint *next;
5984 struct mg_str uri_pattern; /* owned */
5985 char *auth_domain; /* owned */
5986 char *auth_file; /* owned */
5987
5989#if MG_ENABLE_CALLBACK_USERDATA
5990 void *user_data;
5991#endif
5992};
5993
5995 MPS_BEGIN,
6001};
6002
6004 const char *boundary;
6005 int boundary_len;
6006 const char *var_name;
6007 const char *file_name;
6008 void *user_data;
6010 int processing_part;
6011 int data_avail;
6012};
6013
6014struct mg_reverse_proxy_data {
6015 struct mg_connection *linked_conn;
6016};
6017
6018struct mg_ws_proto_data {
6019 /*
6020 * Defragmented size of the frame so far.
6021 *
6022 * First byte of nc->recv_mbuf.buf is an op, the rest of the data is
6023 * defragmented data.
6024 */
6025 size_t reass_len;
6026};
6027
6028struct mg_http_proto_data {
6029#if MG_ENABLE_FILESYSTEM
6031#endif
6032#if MG_ENABLE_HTTP_CGI
6034#endif
6035#if MG_ENABLE_HTTP_STREAMING_MULTIPART
6037#endif
6038#if MG_ENABLE_HTTP_WEBSOCKET
6040#endif
6045 size_t rcvd; /* How many bytes we have received. */
6046};
6047
6048static void mg_http_proto_data_destructor(void *proto_data);
6049
6052 struct mg_connect_opts opts, const char *scheme1, const char *scheme2,
6053 const char *scheme_ssl1, const char *scheme_ssl2, const char *url,
6054 struct mg_str *path, struct mg_str *user_info, struct mg_str *host);
6055
6057 struct mg_connection *c) {
6058 /* If we have proto data from previous connection, flush it. */
6059 if (c->proto_data != NULL) {
6060 void *pd = c->proto_data;
6061 c->proto_data = NULL;
6063 }
6064 c->proto_data = MG_CALLOC(1, sizeof(struct mg_http_proto_data));
6065 c->proto_data_destructor = mg_http_proto_data_destructor;
6066 return (struct mg_http_proto_data *) c->proto_data;
6067}
6068
6070 struct mg_connection *c) {
6071 return (struct mg_http_proto_data *) c->proto_data;
6072}
6073
6074#if MG_ENABLE_HTTP_STREAMING_MULTIPART
6076 struct mg_http_multipart_stream *mp) {
6077 MG_FREE((void *) mp->boundary);
6078 MG_FREE((void *) mp->var_name);
6079 MG_FREE((void *) mp->file_name);
6080 memset(mp, 0, sizeof(*mp));
6081}
6082#endif
6083
6084#if MG_ENABLE_FILESYSTEM
6086 if (d != NULL) {
6087 if (d->fp != NULL) {
6088 fclose(d->fp);
6089 }
6090 memset(d, 0, sizeof(struct mg_http_proto_data_file));
6091 }
6092}
6093#endif
6094
6095static void mg_http_free_proto_data_endpoints(struct mg_http_endpoint **ep) {
6096 struct mg_http_endpoint *current = *ep;
6097
6098 while (current != NULL) {
6099 struct mg_http_endpoint *tmp = current->next;
6100 MG_FREE((void *) current->uri_pattern.p);
6101 MG_FREE((void *) current->auth_domain);
6102 MG_FREE((void *) current->auth_file);
6104 current = tmp;
6105 }
6106
6107 ep = NULL;
6108}
6109
6111 if (rpd->linked_conn != NULL) {
6112 /*
6113 * Connection has linked one, we have to unlink & close it
6114 * since _this_ connection is going to die and
6115 * it doesn't make sense to keep another one
6116 */
6117 struct mg_http_proto_data *pd = mg_http_get_proto_data(rpd->linked_conn);
6118 if (pd->reverse_proxy_data.linked_conn != NULL) {
6119 pd->reverse_proxy_data.linked_conn->flags |= MG_F_SEND_AND_CLOSE;
6120 pd->reverse_proxy_data.linked_conn = NULL;
6121 }
6122 rpd->linked_conn = NULL;
6123 }
6124}
6125
6126static void mg_http_proto_data_destructor(void *proto_data) {
6127 struct mg_http_proto_data *pd = (struct mg_http_proto_data *) proto_data;
6128#if MG_ENABLE_FILESYSTEM
6130#endif
6131#if MG_ENABLE_HTTP_CGI
6133#endif
6134#if MG_ENABLE_HTTP_STREAMING_MULTIPART
6136#endif
6138 mg_http_free_reverse_proxy_data(&pd->reverse_proxy_data);
6139 MG_FREE(proto_data);
6140}
6141
6142#if MG_ENABLE_FILESYSTEM
6143
6144#define MIME_ENTRY(_ext, _type) \
6145 { _ext, sizeof(_ext) - 1, _type }
6146static const struct {
6147 const char *extension;
6148 size_t ext_len;
6149 const char *mime_type;
6151 MIME_ENTRY("html", "text/html"),
6152 MIME_ENTRY("html", "text/html"),
6153 MIME_ENTRY("htm", "text/html"),
6154 MIME_ENTRY("shtm", "text/html"),
6155 MIME_ENTRY("shtml", "text/html"),
6156 MIME_ENTRY("css", "text/css"),
6157 MIME_ENTRY("js", "application/x-javascript"),
6158 MIME_ENTRY("ico", "image/x-icon"),
6159 MIME_ENTRY("gif", "image/gif"),
6160 MIME_ENTRY("jpg", "image/jpeg"),
6161 MIME_ENTRY("jpeg", "image/jpeg"),
6162 MIME_ENTRY("png", "image/png"),
6163 MIME_ENTRY("svg", "image/svg+xml"),
6164 MIME_ENTRY("txt", "text/plain"),
6165 MIME_ENTRY("torrent", "application/x-bittorrent"),
6166 MIME_ENTRY("wav", "audio/x-wav"),
6167 MIME_ENTRY("mp3", "audio/x-mp3"),
6168 MIME_ENTRY("mid", "audio/mid"),
6169 MIME_ENTRY("m3u", "audio/x-mpegurl"),
6170 MIME_ENTRY("ogg", "application/ogg"),
6171 MIME_ENTRY("ram", "audio/x-pn-realaudio"),
6172 MIME_ENTRY("xml", "text/xml"),
6173 MIME_ENTRY("ttf", "application/x-font-ttf"),
6174 MIME_ENTRY("json", "application/json"),
6175 MIME_ENTRY("xslt", "application/xml"),
6176 MIME_ENTRY("xsl", "application/xml"),
6177 MIME_ENTRY("ra", "audio/x-pn-realaudio"),
6178 MIME_ENTRY("doc", "application/msword"),
6179 MIME_ENTRY("exe", "application/octet-stream"),
6180 MIME_ENTRY("zip", "application/x-zip-compressed"),
6181 MIME_ENTRY("xls", "application/excel"),
6182 MIME_ENTRY("tgz", "application/x-tar-gz"),
6183 MIME_ENTRY("tar", "application/x-tar"),
6184 MIME_ENTRY("gz", "application/x-gunzip"),
6185 MIME_ENTRY("arj", "application/x-arj-compressed"),
6186 MIME_ENTRY("rar", "application/x-rar-compressed"),
6187 MIME_ENTRY("rtf", "application/rtf"),
6188 MIME_ENTRY("pdf", "application/pdf"),
6189 MIME_ENTRY("swf", "application/x-shockwave-flash"),
6190 MIME_ENTRY("mpg", "video/mpeg"),
6191 MIME_ENTRY("webm", "video/webm"),
6192 MIME_ENTRY("mpeg", "video/mpeg"),
6193 MIME_ENTRY("mov", "video/quicktime"),
6194 MIME_ENTRY("mp4", "video/mp4"),
6195 MIME_ENTRY("m4v", "video/x-m4v"),
6196 MIME_ENTRY("asf", "video/x-ms-asf"),
6197 MIME_ENTRY("avi", "video/x-msvideo"),
6198 MIME_ENTRY("bmp", "image/bmp"),
6199 {NULL, 0, NULL}};
6200
6201static struct mg_str mg_get_mime_type(const char *path, const char *dflt,
6202 const struct mg_serve_http_opts *opts) {
6203 const char *ext, *overrides;
6204 size_t i, path_len;
6205 struct mg_str r, k, v;
6206
6207 path_len = strlen(path);
6208
6209 overrides = opts->custom_mime_types;
6210 while ((overrides = mg_next_comma_list_entry(overrides, &k, &v)) != NULL) {
6211 ext = path + (path_len - k.len);
6212 if (path_len > k.len && mg_vcasecmp(&k, ext) == 0) {
6213 return v;
6214 }
6215 }
6216
6217 for (i = 0; mg_static_builtin_mime_types[i].extension != NULL; i++) {
6218 ext = path + (path_len - mg_static_builtin_mime_types[i].ext_len);
6219 if (path_len > mg_static_builtin_mime_types[i].ext_len && ext[-1] == '.' &&
6221 r.p = mg_static_builtin_mime_types[i].mime_type;
6222 r.len = strlen(r.p);
6223 return r;
6224 }
6225 }
6226
6227 r.p = dflt;
6228 r.len = strlen(r.p);
6229 return r;
6230}
6231#endif
6232
6233/*
6234 * Check whether full request is buffered. Return:
6235 * -1 if request is malformed
6236 * 0 if request is not yet fully buffered
6237 * >0 actual request length, including last \r\n\r\n
6238 */
6239static int mg_http_get_request_len(const char *s, int buf_len) {
6240 const unsigned char *buf = (unsigned char *) s;
6241 int i;
6242
6243 for (i = 0; i < buf_len; i++) {
6244 if (!isprint(buf[i]) && buf[i] != '\r' && buf[i] != '\n' && buf[i] < 128) {
6245 return -1;
6246 } else if (buf[i] == '\n' && i + 1 < buf_len && buf[i + 1] == '\n') {
6247 return i + 2;
6248 } else if (buf[i] == '\n' && i + 2 < buf_len && buf[i + 1] == '\r' &&
6249 buf[i + 2] == '\n') {
6250 return i + 3;
6251 }
6252 }
6253
6254 return 0;
6255}
6256
6257static const char *mg_http_parse_headers(const char *s, const char *end,
6258 int len, struct http_message *req) {
6259 int i = 0;
6260 while (i < (int) ARRAY_SIZE(req->header_names) - 1) {
6261 struct mg_str *k = &req->header_names[i], *v = &req->header_values[i];
6262
6263 s = mg_skip(s, end, ": ", k);
6264 s = mg_skip(s, end, "\r\n", v);
6265
6266 while (v->len > 0 && v->p[v->len - 1] == ' ') {
6267 v->len--; /* Trim trailing spaces in header value */
6268 }
6269
6270 /*
6271 * If header value is empty - skip it and go to next (if any).
6272 * NOTE: Do not add it to headers_values because such addition changes API
6273 * behaviour
6274 */
6275 if (k->len != 0 && v->len == 0) {
6276 continue;
6277 }
6278
6279 if (k->len == 0 || v->len == 0) {
6280 k->p = v->p = NULL;
6281 k->len = v->len = 0;
6282 break;
6283 }
6284
6285 if (!mg_ncasecmp(k->p, "Content-Length", 14)) {
6286 req->body.len = (size_t) to64(v->p);
6287 req->message.len = len + req->body.len;
6288 }
6289
6290 i++;
6291 }
6292
6293 return s;
6294}
6295
6296int mg_parse_http(const char *s, int n, struct http_message *hm, int is_req) {
6297 const char *end, *qs;
6298 int len = mg_http_get_request_len(s, n);
6299
6300 if (len <= 0) return len;
6301
6302 memset(hm, 0, sizeof(*hm));
6303 hm->message.p = s;
6304 hm->body.p = s + len;
6305 hm->message.len = hm->body.len = (size_t) ~0;
6306 end = s + len;
6307
6308 /* Request is fully buffered. Skip leading whitespaces. */
6309 while (s < end && isspace(*(unsigned char *) s)) s++;
6310
6311 if (is_req) {
6312 /* Parse request line: method, URI, proto */
6313 s = mg_skip(s, end, " ", &hm->method);
6314 s = mg_skip(s, end, " ", &hm->uri);
6315 s = mg_skip(s, end, "\r\n", &hm->proto);
6316 if (hm->uri.p <= hm->method.p || hm->proto.p <= hm->uri.p) return -1;
6317
6318 /* If URI contains '?' character, initialize query_string */
6319 if ((qs = (char *) memchr(hm->uri.p, '?', hm->uri.len)) != NULL) {
6320 hm->query_string.p = qs + 1;
6321 hm->query_string.len = &hm->uri.p[hm->uri.len] - (qs + 1);
6322 hm->uri.len = qs - hm->uri.p;
6323 }
6324 } else {
6325 s = mg_skip(s, end, " ", &hm->proto);
6326 if (end - s < 4 || s[0] < '0' || s[0] > '9' || s[3] != ' ') return -1;
6327 hm->resp_code = atoi(s);
6328 if (hm->resp_code < 100 || hm->resp_code >= 600) return -1;
6329 s += 4;
6330 s = mg_skip(s, end, "\r\n", &hm->resp_status_msg);
6331 }
6332
6333 s = mg_http_parse_headers(s, end, len, hm);
6334
6335 /*
6336 * mg_parse_http() is used to parse both HTTP requests and HTTP
6337 * responses. If HTTP response does not have Content-Length set, then
6338 * body is read until socket is closed, i.e. body.len is infinite (~0).
6339 *
6340 * For HTTP requests though, according to
6341 * http://tools.ietf.org/html/rfc7231#section-8.1.3,
6342 * only POST and PUT methods have defined body semantics.
6343 * Therefore, if Content-Length is not specified and methods are
6344 * not one of PUT or POST, set body length to 0.
6345 *
6346 * So,
6347 * if it is HTTP request, and Content-Length is not set,
6348 * and method is not (PUT or POST) then reset body length to zero.
6349 */
6350 if (hm->body.len == (size_t) ~0 && is_req &&
6351 mg_vcasecmp(&hm->method, "PUT") != 0 &&
6352 mg_vcasecmp(&hm->method, "POST") != 0) {
6353 hm->body.len = 0;
6354 hm->message.len = len;
6355 }
6356
6357 return len;
6358}
6359
6360struct mg_str *mg_get_http_header(struct http_message *hm, const char *name) {
6361 size_t i, len = strlen(name);
6362
6363 for (i = 0; hm->header_names[i].len > 0; i++) {
6364 struct mg_str *h = &hm->header_names[i], *v = &hm->header_values[i];
6365 if (h->p != NULL && h->len == len && !mg_ncasecmp(h->p, name, len))
6366 return v;
6367 }
6368
6369 return NULL;
6370}
6371
6372#if MG_ENABLE_FILESYSTEM
6373static void mg_http_transfer_file_data(struct mg_connection *nc) {
6375 char buf[MG_MAX_HTTP_SEND_MBUF];
6376 size_t n = 0, to_read = 0, left = (size_t)(pd->file.cl - pd->file.sent);
6377
6378 if (pd->file.type == DATA_FILE) {
6379 struct mbuf *io = &nc->send_mbuf;
6380 if (io->len >= MG_MAX_HTTP_SEND_MBUF) {
6381 to_read = 0;
6382 } else {
6384 }
6385 if (to_read > left) {
6386 to_read = left;
6387 }
6388 if (to_read > 0) {
6389 n = mg_fread(buf, 1, to_read, pd->file.fp);
6390 if (n > 0) {
6391 mg_send(nc, buf, n);
6392 pd->file.sent += n;
6393 DBG(("%p sent %d (total %d)", nc, (int) n, (int) pd->file.sent));
6394 }
6395 } else {
6396 /* Rate-limited */
6397 }
6398 if (pd->file.sent >= pd->file.cl) {
6399 LOG(LL_DEBUG, ("%p done, %d bytes, ka %d", nc, (int) pd->file.sent,
6400 pd->file.keepalive));
6401 if (!pd->file.keepalive) nc->flags |= MG_F_SEND_AND_CLOSE;
6403 }
6404 } else if (pd->file.type == DATA_PUT) {
6405 struct mbuf *io = &nc->recv_mbuf;
6406 size_t to_write = left <= 0 ? 0 : left < io->len ? (size_t) left : io->len;
6407 size_t n = mg_fwrite(io->buf, 1, to_write, pd->file.fp);
6408 if (n > 0) {
6409 mbuf_remove(io, n);
6410 pd->file.sent += n;
6411 }
6412 if (n == 0 || pd->file.sent >= pd->file.cl) {
6413 if (!pd->file.keepalive) nc->flags |= MG_F_SEND_AND_CLOSE;
6415 }
6416 }
6417#if MG_ENABLE_HTTP_CGI
6418 else if (pd->cgi.cgi_nc != NULL) {
6419 /* This is POST data that needs to be forwarded to the CGI process */
6420 if (pd->cgi.cgi_nc != NULL) {
6421 mg_forward(nc, pd->cgi.cgi_nc);
6422 } else {
6424 }
6425 }
6426#endif
6427}
6428#endif /* MG_ENABLE_FILESYSTEM */
6429
6430/*
6431 * Parse chunked-encoded buffer. Return 0 if the buffer is not encoded, or
6432 * if it's incomplete. If the chunk is fully buffered, return total number of
6433 * bytes in a chunk, and store data in `data`, `data_len`.
6434 */
6435static size_t mg_http_parse_chunk(char *buf, size_t len, char **chunk_data,
6436 size_t *chunk_len) {
6437 unsigned char *s = (unsigned char *) buf;
6438 size_t n = 0; /* scanned chunk length */
6439 size_t i = 0; /* index in s */
6440
6441 /* Scan chunk length. That should be a hexadecimal number. */
6442 while (i < len && isxdigit(s[i])) {
6443 n *= 16;
6444 n += (s[i] >= '0' && s[i] <= '9') ? s[i] - '0' : tolower(s[i]) - 'a' + 10;
6445 i++;
6446 if (i > 6) {
6447 /* Chunk size is unreasonable. */
6448 return 0;
6449 }
6450 }
6451
6452 /* Skip new line */
6453 if (i == 0 || i + 2 > len || s[i] != '\r' || s[i + 1] != '\n') {
6454 return 0;
6455 }
6456 i += 2;
6457
6458 /* Record where the data is */
6459 *chunk_data = (char *) s + i;
6460 *chunk_len = n;
6461
6462 /* Skip data */
6463 i += n;
6464
6465 /* Skip new line */
6466 if (i == 0 || i + 2 > len || s[i] != '\r' || s[i + 1] != '\n') {
6467 return 0;
6468 }
6469 return i + 2;
6470}
6471
6473 struct http_message *hm, char *buf,
6474 size_t blen) {
6476 char *data;
6477 size_t i, n, data_len, body_len, zero_chunk_received = 0;
6478 /* Find out piece of received data that is not yet reassembled */
6479 body_len = (size_t) pd->chunk.body_len;
6480 assert(blen >= body_len);
6481
6482 /* Traverse all fully buffered chunks */
6483 for (i = body_len;
6484 (n = mg_http_parse_chunk(buf + i, blen - i, &data, &data_len)) > 0;
6485 i += n) {
6486 /* Collapse chunk data to the rest of HTTP body */
6487 memmove(buf + body_len, data, data_len);
6488 body_len += data_len;
6489 hm->body.len = body_len;
6490
6491 if (data_len == 0) {
6493 i += n;
6494 break;
6495 }
6496 }
6497
6498 if (i > body_len) {
6499 /* Shift unparsed content to the parsed body */
6500 assert(i <= blen);
6501 memmove(buf + body_len, buf + i, blen - i);
6502 memset(buf + body_len + blen - i, 0, i - body_len);
6503 nc->recv_mbuf.len -= i - body_len;
6504 pd->chunk.body_len = body_len;
6505
6506 /* Send MG_EV_HTTP_CHUNK event */
6509
6510 /* Delete processed data if user set MG_F_DELETE_CHUNK flag */
6511 if (nc->flags & MG_F_DELETE_CHUNK) {
6512 memset(buf, 0, body_len);
6513 memmove(buf, buf + body_len, blen - i);
6514 nc->recv_mbuf.len -= body_len;
6515 hm->body.len = 0;
6516 pd->chunk.body_len = 0;
6517 }
6518
6519 if (zero_chunk_received) {
6520 /* Total message size is len(body) + len(headers) */
6521 hm->message.len =
6522 (size_t) pd->chunk.body_len + blen - i + (hm->body.p - hm->message.p);
6523 }
6524 }
6525
6526 return body_len;
6527}
6528
6530 struct mg_str *uri_path) {
6531 struct mg_http_proto_data *pd;
6532 struct mg_http_endpoint *ret = NULL;
6533 int matched, matched_max = 0;
6534 struct mg_http_endpoint *ep;
6535
6536 if (nc == NULL) return NULL;
6537
6539
6540 if (pd == NULL) return NULL;
6541
6542 ep = pd->endpoints;
6543 while (ep != NULL) {
6544 if ((matched = mg_match_prefix_n(ep->uri_pattern, *uri_path)) > 0) {
6545 if (matched > matched_max) {
6546 /* Looking for the longest suitable handler */
6547 ret = ep;
6549 }
6550 }
6551
6552 ep = ep->next;
6553 }
6554
6555 return ret;
6556}
6557
6558#if MG_ENABLE_HTTP_STREAMING_MULTIPART
6559static void mg_http_multipart_continue(struct mg_connection *nc);
6560
6561static void mg_http_multipart_begin(struct mg_connection *nc,
6562 struct http_message *hm, int req_len);
6563
6564#endif
6565
6566static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev,
6567 struct http_message *hm);
6568
6569static void deliver_chunk(struct mg_connection *c, struct http_message *hm,
6570 int req_len) {
6571 /* Incomplete message received. Send MG_EV_HTTP_CHUNK event */
6572 hm->body.len = c->recv_mbuf.len - req_len;
6573 c->flags &= ~MG_F_DELETE_CHUNK;
6574 mg_call(c, c->handler, c->user_data, MG_EV_HTTP_CHUNK, hm);
6575 /* Delete processed data if user set MG_F_DELETE_CHUNK flag */
6576 if (c->flags & MG_F_DELETE_CHUNK) c->recv_mbuf.len = req_len;
6577}
6578
6579/*
6580 * lx106 compiler has a bug (TODO(mkm) report and insert tracking bug here)
6581 * If a big structure is declared in a big function, lx106 gcc will make it
6582 * even bigger (round up to 4k, from 700 bytes of actual size).
6583 */
6584#ifdef __xtensa__
6585static void mg_http_handler2(struct mg_connection *nc, int ev,
6586 void *ev_data MG_UD_ARG(void *user_data),
6588
6589void mg_http_handler(struct mg_connection *nc, int ev,
6590 void *ev_data MG_UD_ARG(void *user_data)) {
6591 struct http_message hm;
6592 mg_http_handler2(nc, ev, ev_data MG_UD_ARG(user_data), &hm);
6593}
6594
6595static void mg_http_handler2(struct mg_connection *nc, int ev,
6596 void *ev_data MG_UD_ARG(void *user_data),
6597 struct http_message *hm) {
6598#else /* !__XTENSA__ */
6599void mg_http_handler(struct mg_connection *nc, int ev,
6600 void *ev_data MG_UD_ARG(void *user_data)) {
6601 struct http_message shm, *hm = &shm;
6602#endif /* __XTENSA__ */
6604 struct mbuf *io = &nc->recv_mbuf;
6605 int req_len;
6606 const int is_req = (nc->listener != NULL);
6607#if MG_ENABLE_HTTP_WEBSOCKET
6608 struct mg_str *vec;
6609#endif
6610 if (ev == MG_EV_CLOSE) {
6611#if MG_ENABLE_HTTP_CGI
6612 /* Close associated CGI forwarder connection */
6613 if (pd != NULL && pd->cgi.cgi_nc != NULL) {
6614 pd->cgi.cgi_nc->user_data = NULL;
6615 pd->cgi.cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY;
6616 }
6617#endif
6618#if MG_ENABLE_HTTP_STREAMING_MULTIPART
6619 if (pd != NULL && pd->mp_stream.boundary != NULL) {
6620 /*
6621 * Multipart message is in progress, but connection is closed.
6622 * Finish part and request with an error flag.
6623 */
6625 memset(&mp, 0, sizeof(mp));
6626 mp.status = -1;
6627 mp.user_data = pd->mp_stream.user_data;
6628 mp.var_name = pd->mp_stream.var_name;
6629 mp.file_name = pd->mp_stream.file_name;
6630 mg_call(nc, (pd->endpoint_handler ? pd->endpoint_handler : nc->handler),
6632 mp.var_name = NULL;
6633 mp.file_name = NULL;
6634 mg_call(nc, (pd->endpoint_handler ? pd->endpoint_handler : nc->handler),
6636 } else
6637#endif
6638 if (io->len > 0 &&
6639 (req_len = mg_parse_http(io->buf, io->len, hm, is_req)) > 0) {
6640 /*
6641 * For HTTP messages without Content-Length, always send HTTP message
6642 * before MG_EV_CLOSE message.
6643 */
6645 hm->message.len = io->len;
6646 hm->body.len = io->buf + io->len - hm->body.p;
6647 deliver_chunk(nc, hm, req_len);
6649 }
6650 if (pd != NULL && pd->endpoint_handler != NULL &&
6651 pd->endpoint_handler != nc->handler) {
6652 mg_call(nc, pd->endpoint_handler, nc->user_data, ev, NULL);
6653 }
6654 }
6655
6656#if MG_ENABLE_FILESYSTEM
6657 if (pd != NULL && pd->file.fp != NULL) {
6659 }
6660#endif
6661
6662 mg_call(nc, nc->handler, nc->user_data, ev, ev_data);
6663
6664#if MG_ENABLE_HTTP_STREAMING_MULTIPART
6665 if (pd != NULL && pd->mp_stream.boundary != NULL &&
6666 (ev == MG_EV_RECV || ev == MG_EV_POLL)) {
6667 if (ev == MG_EV_RECV) {
6668 pd->rcvd += *(int *) ev_data;
6670 } else if (pd->mp_stream.data_avail) {
6671 /* Try re-delivering the data. */
6673 }
6674 return;
6675 }
6676#endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
6677
6678 if (ev == MG_EV_RECV) {
6679 struct mg_str *s;
6680
6681 again:
6682 req_len = mg_parse_http(io->buf, io->len, hm, is_req);
6683
6684 if (req_len > 0) {
6685 /* New request - new proto data */
6686 if (!pd) {
6688 }
6689 pd->rcvd = io->len;
6690 }
6691
6692 if (req_len > 0 &&
6693 (s = mg_get_http_header(hm, "Transfer-Encoding")) != NULL &&
6694 mg_vcasecmp(s, "chunked") == 0) {
6695 mg_handle_chunked(nc, hm, io->buf + req_len, io->len - req_len);
6696 }
6697
6698#if MG_ENABLE_HTTP_STREAMING_MULTIPART
6699 if (req_len > 0 && (s = mg_get_http_header(hm, "Content-Type")) != NULL &&
6700 s->len >= 9 && strncmp(s->p, "multipart", 9) == 0) {
6703 return;
6704 }
6705#endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
6706
6707 /* TODO(alashkin): refactor this ifelseifelseifelseifelse */
6708 if ((req_len < 0 ||
6709 (req_len == 0 && io->len >= MG_MAX_HTTP_REQUEST_SIZE))) {
6710 DBG(("invalid request"));
6712 } else if (req_len == 0) {
6713 /* Do nothing, request is not yet fully buffered */
6714 }
6715#if MG_ENABLE_HTTP_WEBSOCKET
6716 else if (nc->listener == NULL && (nc->flags & MG_F_IS_WEBSOCKET)) {
6717 /* We're websocket client, got handshake response from server. */
6718 DBG(("%p WebSocket upgrade code %d", nc, hm->resp_code));
6719 if (hm->resp_code == 101 &&
6720 mg_get_http_header(hm, "Sec-WebSocket-Accept")) {
6721 /* TODO(lsm): check the validity of accept Sec-WebSocket-Accept */
6723 hm);
6726 mg_ws_handler(nc, MG_EV_RECV, ev_data MG_UD_ARG(user_data));
6727 } else {
6729 hm);
6732 }
6733 } else if (nc->listener != NULL &&
6734 (vec = mg_get_http_header(hm, "Sec-WebSocket-Key")) != NULL) {
6735 struct mg_http_endpoint *ep;
6736
6737 /* This is a websocket request. Switch protocol handlers. */
6740 nc->flags |= MG_F_IS_WEBSOCKET;
6741
6742 /*
6743 * If we have a handler set up with mg_register_http_endpoint(),
6744 * deliver subsequent websocket events to this handler after the
6745 * protocol switch.
6746 */
6747 ep = mg_http_get_endpoint_handler(nc->listener, &hm->uri);
6748 if (ep != NULL) {
6749 nc->handler = ep->handler;
6750#if MG_ENABLE_CALLBACK_USERDATA
6751 nc->user_data = ep->user_data;
6752#endif
6753 }
6754
6755 /* Send handshake */
6757 hm);
6759 if (nc->send_mbuf.len == 0) {
6760 mg_ws_handshake(nc, vec, hm);
6761 }
6763 hm);
6764 mg_ws_handler(nc, MG_EV_RECV, ev_data MG_UD_ARG(user_data));
6765 }
6766 }
6767#endif /* MG_ENABLE_HTTP_WEBSOCKET */
6768 else if (hm->message.len > pd->rcvd) {
6769 /* Not yet received all HTTP body, deliver MG_EV_HTTP_CHUNK */
6770 deliver_chunk(nc, hm, req_len);
6771 if (nc->recv_mbuf_limit > 0 && nc->recv_mbuf.len >= nc->recv_mbuf_limit) {
6772 LOG(LL_ERROR, ("%p recv buffer (%lu bytes) exceeds the limit "
6773 "%lu bytes, and not drained, closing",
6774 nc, (unsigned long) nc->recv_mbuf.len,
6775 (unsigned long) nc->recv_mbuf_limit));
6777 }
6778 } else {
6779 /* We did receive all HTTP body. */
6780 int request_done = 1;
6782 char addr[32];
6783 mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr),
6785 DBG(("%p %s %.*s %.*s", nc, addr, (int) hm->method.len, hm->method.p,
6786 (int) hm->uri.len, hm->uri.p));
6787 deliver_chunk(nc, hm, req_len);
6788 /* Whole HTTP message is fully buffered, call event handler */
6790 mbuf_remove(io, hm->message.len);
6791 pd->rcvd -= hm->message.len;
6792#if MG_ENABLE_FILESYSTEM
6793 /* We don't have a generic mechanism of communicating that we are done
6794 * responding to a request (should probably add one). But if we are
6795 * serving
6796 * a file, we are definitely not done. */
6797 if (pd->file.fp != NULL) request_done = 0;
6798#endif
6799#if MG_ENABLE_HTTP_CGI
6800 /* If this is a CGI request, we are not done either. */
6801 if (pd->cgi.cgi_nc != NULL) request_done = 0;
6802#endif
6803 if (request_done && io->len > 0) goto again;
6804 }
6805 }
6806}
6807
6808static size_t mg_get_line_len(const char *buf, size_t buf_len) {
6809 size_t len = 0;
6810 while (len < buf_len && buf[len] != '\n') len++;
6811 return len == buf_len ? 0 : len + 1;
6812}
6813
6814#if MG_ENABLE_HTTP_STREAMING_MULTIPART
6815static void mg_http_multipart_begin(struct mg_connection *nc,
6816 struct http_message *hm, int req_len) {
6818 struct mg_str *ct;
6819 struct mbuf *io = &nc->recv_mbuf;
6820
6821 char boundary_buf[100];
6822 char *boundary = boundary_buf;
6823 int boundary_len;
6824
6825 ct = mg_get_http_header(hm, "Content-Type");
6826 if (ct == NULL) {
6827 /* We need more data - or it isn't multipart mesage */
6828 goto exit_mp;
6829 }
6830
6831 /* Content-type should start with "multipart" */
6832 if (ct->len < 9 || strncmp(ct->p, "multipart", 9) != 0) {
6833 goto exit_mp;
6834 }
6835
6836 boundary_len =
6837 mg_http_parse_header2(ct, "boundary", &boundary, sizeof(boundary_buf));
6838 if (boundary_len == 0) {
6839 /*
6840 * Content type is multipart, but there is no boundary,
6841 * probably malformed request
6842 */
6844 DBG(("invalid request"));
6845 goto exit_mp;
6846 }
6847
6848 /* If we reach this place - that is multipart request */
6849
6850 if (pd->mp_stream.boundary != NULL) {
6851 /*
6852 * Another streaming request was in progress,
6853 * looks like protocol error
6854 */
6856 } else {
6857 struct mg_http_endpoint *ep = NULL;
6858 pd->mp_stream.state = MPS_BEGIN;
6859 pd->mp_stream.boundary = strdup(boundary);
6860 pd->mp_stream.boundary_len = strlen(boundary);
6861 pd->mp_stream.var_name = pd->mp_stream.file_name = NULL;
6862 pd->endpoint_handler = nc->handler;
6863
6864 ep = mg_http_get_endpoint_handler(nc->listener, &hm->uri);
6865 if (ep != NULL) {
6866 pd->endpoint_handler = ep->handler;
6867 }
6868
6870
6872 }
6873exit_mp:
6874 if (boundary != boundary_buf) MG_FREE(boundary);
6875}
6876
6877#define CONTENT_DISPOSITION "Content-Disposition: "
6878
6879static size_t mg_http_multipart_call_handler(struct mg_connection *c, int ev,
6880 const char *data,
6881 size_t data_len) {
6884 memset(&mp, 0, sizeof(mp));
6885
6886 mp.var_name = pd->mp_stream.var_name;
6887 mp.file_name = pd->mp_stream.file_name;
6888 mp.user_data = pd->mp_stream.user_data;
6889 mp.data.p = data;
6890 mp.data.len = data_len;
6891 mp.num_data_consumed = data_len;
6892 mg_call(c, pd->endpoint_handler, c->user_data, ev, &mp);
6893 pd->mp_stream.user_data = mp.user_data;
6894 pd->mp_stream.data_avail = (mp.num_data_consumed != data_len);
6895 return mp.num_data_consumed;
6896}
6897
6898static int mg_http_multipart_finalize(struct mg_connection *c) {
6900
6902 MG_FREE((void *) pd->mp_stream.file_name);
6903 pd->mp_stream.file_name = NULL;
6904 MG_FREE((void *) pd->mp_stream.var_name);
6905 pd->mp_stream.var_name = NULL;
6908 pd->mp_stream.state = MPS_FINISHED;
6909
6910 return 1;
6911}
6912
6914 const char *boundary;
6915 struct mbuf *io = &c->recv_mbuf;
6917
6918 if (pd->mp_stream.boundary == NULL) {
6919 pd->mp_stream.state = MPS_FINALIZE;
6920 DBG(("Invalid request: boundary not initialized"));
6921 return 0;
6922 }
6923
6924 if ((int) io->len < pd->mp_stream.boundary_len + 2) {
6925 return 0;
6926 }
6927
6928 boundary = c_strnstr(io->buf, pd->mp_stream.boundary, io->len);
6929 if (boundary != NULL) {
6930 const char *boundary_end = (boundary + pd->mp_stream.boundary_len);
6931 if (io->len - (boundary_end - io->buf) < 4) {
6932 return 0;
6933 }
6934 if (strncmp(boundary_end, "--\r\n", 4) == 0) {
6935 pd->mp_stream.state = MPS_FINALIZE;
6936 mbuf_remove(io, (boundary_end - io->buf) + 4);
6937 } else {
6938 pd->mp_stream.state = MPS_GOT_BOUNDARY;
6939 }
6940 } else {
6941 return 0;
6942 }
6943
6944 return 1;
6945}
6946
6947static void mg_http_parse_header_internal(struct mg_str *hdr,
6948 const char *var_name,
6949 struct altbuf *ab);
6950
6952 int data_size;
6953 const char *boundary, *block_begin;
6954 struct mbuf *io = &c->recv_mbuf;
6957 int line_len;
6958 boundary = c_strnstr(io->buf, pd->mp_stream.boundary, io->len);
6959 block_begin = boundary + pd->mp_stream.boundary_len + 2;
6960 data_size = io->len - (block_begin - io->buf);
6961
6964
6965 while (data_size > 0 &&
6966 (line_len = mg_get_line_len(block_begin, data_size)) != 0) {
6967 if (line_len > (int) sizeof(CONTENT_DISPOSITION) &&
6969 sizeof(CONTENT_DISPOSITION) - 1) == 0) {
6970 struct mg_str header;
6971
6972 header.p = block_begin + sizeof(CONTENT_DISPOSITION) - 1;
6973 header.len = line_len - sizeof(CONTENT_DISPOSITION) - 1;
6974
6976 mg_http_parse_header_internal(&header, "name", &ab_var_name);
6977
6979 mg_http_parse_header_internal(&header, "filename", &ab_file_name);
6980
6982 data_size -= line_len;
6983
6984 continue;
6985 }
6986
6987 if (line_len == 2 && mg_ncasecmp(block_begin, "\r\n", 2) == 0) {
6988 mbuf_remove(io, block_begin - io->buf + 2);
6989
6990 if (pd->mp_stream.processing_part != 0) {
6992 }
6993
6994 /* Reserve 2 bytes for "\r\n" in file_name and var_name */
6997 altbuf_append(&ab_var_name, '\0');
6998 altbuf_append(&ab_var_name, '\0');
6999
7000 MG_FREE((void *) pd->mp_stream.file_name);
7001 pd->mp_stream.file_name = altbuf_get_buf(&ab_file_name, 1 /* trim */);
7002 MG_FREE((void *) pd->mp_stream.var_name);
7003 pd->mp_stream.var_name = altbuf_get_buf(&ab_var_name, 1 /* trim */);
7004
7006 pd->mp_stream.state = MPS_WAITING_FOR_CHUNK;
7007 pd->mp_stream.processing_part++;
7008 return 1;
7009 }
7010
7012 }
7013
7014 pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY;
7015
7018
7019 return 0;
7020}
7021
7024 struct mbuf *io = &c->recv_mbuf;
7025
7026 const char *boundary;
7027 if ((int) io->len < pd->mp_stream.boundary_len + 6 /* \r\n, --, -- */) {
7028 return 0;
7029 }
7030
7031 boundary = c_strnstr(io->buf, pd->mp_stream.boundary, io->len);
7032 if (boundary == NULL) {
7033 int data_len = (io->len - (pd->mp_stream.boundary_len + 6));
7034 if (data_len > 0) {
7036 c, MG_EV_HTTP_PART_DATA, io->buf, (size_t) data_len);
7038 }
7039 return 0;
7040 } else if (boundary != NULL) {
7041 size_t data_len = ((size_t)(boundary - io->buf) - 4);
7043 io->buf, data_len);
7045 if (consumed == data_len) {
7046 mbuf_remove(io, 4);
7047 pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY;
7048 return 1;
7049 } else {
7050 return 0;
7051 }
7052 } else {
7053 return 0;
7054 }
7055}
7056
7057static void mg_http_multipart_continue(struct mg_connection *c) {
7059 while (1) {
7060 switch (pd->mp_stream.state) {
7061 case MPS_BEGIN: {
7062 pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY;
7063 break;
7064 }
7067 return;
7068 }
7069 break;
7070 }
7071 case MPS_GOT_BOUNDARY: {
7073 return;
7074 }
7075 break;
7076 }
7077 case MPS_WAITING_FOR_CHUNK: {
7079 return;
7080 }
7081 break;
7082 }
7083 case MPS_FINALIZE: {
7084 if (mg_http_multipart_finalize(c) == 0) {
7085 return;
7086 }
7087 break;
7088 }
7089 case MPS_FINISHED: {
7090 return;
7091 }
7092 }
7093 }
7094}
7095
7096struct file_upload_state {
7097 char *lfn;
7098 size_t num_recd;
7099 FILE *fp;
7100};
7101
7102#endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
7103
7106}
7107
7108const char *mg_status_message(int status_code) {
7109 switch (status_code) {
7110 case 206:
7111 return "Partial Content";
7112 case 301:
7113 return "Moved";
7114 case 302:
7115 return "Found";
7116 case 400:
7117 return "Bad Request";
7118 case 401:
7119 return "Unauthorized";
7120 case 403:
7121 return "Forbidden";
7122 case 404:
7123 return "Not Found";
7124 case 416:
7125 return "Requested Range Not Satisfiable";
7126 case 418:
7127 return "I'm a teapot";
7128 case 500:
7129 return "Internal Server Error";
7130 case 502:
7131 return "Bad Gateway";
7132 case 503:
7133 return "Service Unavailable";
7134
7135#if MG_ENABLE_EXTRA_ERRORS_DESC
7136 case 100:
7137 return "Continue";
7138 case 101:
7139 return "Switching Protocols";
7140 case 102:
7141 return "Processing";
7142 case 200:
7143 return "OK";
7144 case 201:
7145 return "Created";
7146 case 202:
7147 return "Accepted";
7148 case 203:
7149 return "Non-Authoritative Information";
7150 case 204:
7151 return "No Content";
7152 case 205:
7153 return "Reset Content";
7154 case 207:
7155 return "Multi-Status";
7156 case 208:
7157 return "Already Reported";
7158 case 226:
7159 return "IM Used";
7160 case 300:
7161 return "Multiple Choices";
7162 case 303:
7163 return "See Other";
7164 case 304:
7165 return "Not Modified";
7166 case 305:
7167 return "Use Proxy";
7168 case 306:
7169 return "Switch Proxy";
7170 case 307:
7171 return "Temporary Redirect";
7172 case 308:
7173 return "Permanent Redirect";
7174 case 402:
7175 return "Payment Required";
7176 case 405:
7177 return "Method Not Allowed";
7178 case 406:
7179 return "Not Acceptable";
7180 case 407:
7181 return "Proxy Authentication Required";
7182 case 408:
7183 return "Request Timeout";
7184 case 409:
7185 return "Conflict";
7186 case 410:
7187 return "Gone";
7188 case 411:
7189 return "Length Required";
7190 case 412:
7191 return "Precondition Failed";
7192 case 413:
7193 return "Payload Too Large";
7194 case 414:
7195 return "URI Too Long";
7196 case 415:
7197 return "Unsupported Media Type";
7198 case 417:
7199 return "Expectation Failed";
7200 case 422:
7201 return "Unprocessable Entity";
7202 case 423:
7203 return "Locked";
7204 case 424:
7205 return "Failed Dependency";
7206 case 426:
7207 return "Upgrade Required";
7208 case 428:
7209 return "Precondition Required";
7210 case 429:
7211 return "Too Many Requests";
7212 case 431:
7213 return "Request Header Fields Too Large";
7214 case 451:
7215 return "Unavailable For Legal Reasons";
7216 case 501:
7217 return "Not Implemented";
7218 case 504:
7219 return "Gateway Timeout";
7220 case 505:
7221 return "HTTP Version Not Supported";
7222 case 506:
7223 return "Variant Also Negotiates";
7224 case 507:
7225 return "Insufficient Storage";
7226 case 508:
7227 return "Loop Detected";
7228 case 510:
7229 return "Not Extended";
7230 case 511:
7231 return "Network Authentication Required";
7232#endif /* MG_ENABLE_EXTRA_ERRORS_DESC */
7233
7234 default:
7235 return "OK";
7236 }
7237}
7238
7239void mg_send_response_line_s(struct mg_connection *nc, int status_code,
7240 const struct mg_str extra_headers) {
7241 mg_printf(nc, "HTTP/1.1 %d %s\r\n", status_code,
7242 mg_status_message(status_code));
7243#ifndef MG_HIDE_SERVER_INFO
7244 mg_printf(nc, "Server: %s\r\n", mg_version_header);
7245#endif
7246 if (extra_headers.len > 0) {
7247 mg_printf(nc, "%.*s\r\n", (int) extra_headers.len, extra_headers.p);
7248 }
7249}
7250
7251void mg_send_response_line(struct mg_connection *nc, int status_code,
7252 const char *extra_headers) {
7253 mg_send_response_line_s(nc, status_code, mg_mk_str(extra_headers));
7254}
7255
7256void mg_http_send_redirect(struct mg_connection *nc, int status_code,
7257 const struct mg_str location,
7258 const struct mg_str extra_headers) {
7259 char bbody[100], *pbody = bbody;
7260 int bl = mg_asprintf(&pbody, sizeof(bbody),
7261 "<p>Moved <a href='%.*s'>here</a>.\r\n",
7262 (int) location.len, location.p);
7263 char bhead[150], *phead = bhead;
7264 mg_asprintf(&phead, sizeof(bhead),
7265 "Location: %.*s\r\n"
7266 "Content-Type: text/html\r\n"
7267 "Content-Length: %d\r\n"
7268 "Cache-Control: no-cache\r\n"
7269 "%.*s%s",
7270 (int) location.len, location.p, bl, (int) extra_headers.len,
7271 extra_headers.p, (extra_headers.len > 0 ? "\r\n" : ""));
7272 mg_send_response_line(nc, status_code, phead);
7273 if (phead != bhead) MG_FREE(phead);
7274 mg_send(nc, pbody, bl);
7275 if (pbody != bbody) MG_FREE(pbody);
7276}
7277
7278void mg_send_head(struct mg_connection *c, int status_code,
7279 int64_t content_length, const char *extra_headers) {
7280 mg_send_response_line(c, status_code, extra_headers);
7281 if (content_length < 0) {
7282 mg_printf(c, "%s", "Transfer-Encoding: chunked\r\n");
7283 } else {
7284 mg_printf(c, "Content-Length: %" INT64_FMT "\r\n", content_length);
7285 }
7286 mg_send(c, "\r\n", 2);
7287}
7288
7289void mg_http_send_error(struct mg_connection *nc, int code,
7290 const char *reason) {
7291 if (!reason) reason = mg_status_message(code);
7292 LOG(LL_DEBUG, ("%p %d %s", nc, code, reason));
7293 mg_send_head(nc, code, strlen(reason),
7294 "Content-Type: text/plain\r\nConnection: close");
7295 mg_send(nc, reason, strlen(reason));
7297}
7298
7299#if MG_ENABLE_FILESYSTEM
7300static void mg_http_construct_etag(char *buf, size_t buf_len,
7301 const cs_stat_t *st) {
7302 snprintf(buf, buf_len, "\"%lx.%" INT64_FMT "\"", (unsigned long) st->st_mtime,
7303 (int64_t) st->st_size);
7304}
7305
7306#ifndef WINCE
7307static void mg_gmt_time_string(char *buf, size_t buf_len, time_t *t) {
7308 strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(t));
7309}
7310#else
7311/* Look wince_lib.c for WindowsCE implementation */
7312static void mg_gmt_time_string(char *buf, size_t buf_len, time_t *t);
7313#endif
7314
7315static int mg_http_parse_range_header(const struct mg_str *header, int64_t *a,
7316 int64_t *b) {
7317 /*
7318 * There is no snscanf. Headers are not guaranteed to be NUL-terminated,
7319 * so we have this. Ugh.
7320 */
7321 int result;
7322 char *p = (char *) MG_MALLOC(header->len + 1);
7323 if (p == NULL) return 0;
7324 memcpy(p, header->p, header->len);
7325 p[header->len] = '\0';
7326 result = sscanf(p, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
7327 MG_FREE(p);
7328 return result;
7329}
7330
7331void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm,
7332 const char *path, const struct mg_str mime_type,
7333 const struct mg_str extra_headers) {
7335 cs_stat_t st;
7336 LOG(LL_DEBUG, ("%p [%s] %.*s", nc, path, (int) mime_type.len, mime_type.p));
7337 if (mg_stat(path, &st) != 0 || (pd->file.fp = mg_fopen(path, "rb")) == NULL) {
7338 int code, err = mg_get_errno();
7339 switch (err) {
7340 case EACCES:
7341 code = 403;
7342 break;
7343 case ENOENT:
7344 code = 404;
7345 break;
7346 default:
7347 code = 500;
7348 };
7349 mg_http_send_error(nc, code, "Open failed");
7350 } else {
7351 char etag[50], current_time[50], last_modified[50], range[70];
7352 time_t t = (time_t) mg_time();
7353 int64_t r1 = 0, r2 = 0, cl = st.st_size;
7354 struct mg_str *range_hdr = mg_get_http_header(hm, "Range");
7355 int n, status_code = 200;
7356
7357 /* Handle Range header */
7358 range[0] = '\0';
7359 if (range_hdr != NULL &&
7360 (n = mg_http_parse_range_header(range_hdr, &r1, &r2)) > 0 && r1 >= 0 &&
7361 r2 >= 0) {
7362 /* If range is specified like "400-", set second limit to content len */
7363 if (n == 1) {
7364 r2 = cl - 1;
7365 }
7366 if (r1 > r2 || r2 >= cl) {
7367 status_code = 416;
7368 cl = 0;
7369 snprintf(range, sizeof(range),
7370 "Content-Range: bytes */%" INT64_FMT "\r\n",
7371 (int64_t) st.st_size);
7372 } else {
7373 status_code = 206;
7374 cl = r2 - r1 + 1;
7375 snprintf(range, sizeof(range), "Content-Range: bytes %" INT64_FMT
7376 "-%" INT64_FMT "/%" INT64_FMT "\r\n",
7377 r1, r1 + cl - 1, (int64_t) st.st_size);
7378#if _FILE_OFFSET_BITS == 64 || _POSIX_C_SOURCE >= 200112L || \
7379 _XOPEN_SOURCE >= 600
7380 fseeko(pd->file.fp, r1, SEEK_SET);
7381#else
7382 fseek(pd->file.fp, (long) r1, SEEK_SET);
7383#endif
7384 }
7385 }
7386
7387#if !MG_DISABLE_HTTP_KEEP_ALIVE
7388 {
7389 struct mg_str *conn_hdr = mg_get_http_header(hm, "Connection");
7390 if (conn_hdr != NULL) {
7391 pd->file.keepalive = (mg_vcasecmp(conn_hdr, "keep-alive") == 0);
7392 } else {
7393 pd->file.keepalive = (mg_vcmp(&hm->proto, "HTTP/1.1") == 0);
7394 }
7395 }
7396#endif
7397
7398 mg_http_construct_etag(etag, sizeof(etag), &st);
7400 mg_gmt_time_string(last_modified, sizeof(last_modified), &st.st_mtime);
7401 /*
7402 * Content length casted to size_t because:
7403 * 1) that's the maximum buffer size anyway
7404 * 2) ESP8266 RTOS SDK newlib vprintf cannot contain a 64bit arg at non-last
7405 * position
7406 * TODO(mkm): fix ESP8266 RTOS SDK
7407 */
7408 mg_send_response_line_s(nc, status_code, extra_headers);
7409 mg_printf(nc,
7410 "Date: %s\r\n"
7411 "Last-Modified: %s\r\n"
7412 "Accept-Ranges: bytes\r\n"
7413 "Content-Type: %.*s\r\n"
7414 "Connection: %s\r\n"
7415 "Content-Length: %" SIZE_T_FMT
7416 "\r\n"
7417 "%sEtag: %s\r\n\r\n",
7419 (pd->file.keepalive ? "keep-alive" : "close"), (size_t) cl, range,
7420 etag);
7421
7422 pd->file.cl = cl;
7423 pd->file.type = DATA_FILE;
7425 }
7426}
7427
7428static void mg_http_serve_file2(struct mg_connection *nc, const char *path,
7429 struct http_message *hm,
7430 struct mg_serve_http_opts *opts) {
7431#if MG_ENABLE_HTTP_SSI
7432 if (mg_match_prefix(opts->ssi_pattern, strlen(opts->ssi_pattern), path) > 0) {
7433 mg_handle_ssi_request(nc, hm, path, opts);
7434 return;
7435 }
7436#endif
7437 mg_http_serve_file(nc, hm, path, mg_get_mime_type(path, "text/plain", opts),
7438 mg_mk_str(opts->extra_headers));
7439}
7440
7441#endif
7442
7443int mg_url_decode(const char *src, int src_len, char *dst, int dst_len,
7444 int is_form_url_encoded) {
7445 int i, j, a, b;
7446#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
7447
7448 for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
7449 if (src[i] == '%') {
7450 if (i < src_len - 2 && isxdigit(*(const unsigned char *) (src + i + 1)) &&
7451 isxdigit(*(const unsigned char *) (src + i + 2))) {
7452 a = tolower(*(const unsigned char *) (src + i + 1));
7453 b = tolower(*(const unsigned char *) (src + i + 2));
7454 dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b));
7455 i += 2;
7456 } else {
7457 return -1;
7458 }
7459 } else if (is_form_url_encoded && src[i] == '+') {
7460 dst[j] = ' ';
7461 } else {
7462 dst[j] = src[i];
7463 }
7464 }
7465
7466 dst[j] = '\0'; /* Null-terminate the destination */
7467
7468 return i >= src_len ? j : -1;
7469}
7470
7471int mg_get_http_var(const struct mg_str *buf, const char *name, char *dst,
7472 size_t dst_len) {
7473 const char *p, *e, *s;
7474 size_t name_len;
7475 int len;
7476
7477 /*
7478 * According to the documentation function returns negative
7479 * value in case of error. For debug purposes it returns:
7480 * -1 - src is wrong (NUUL)
7481 * -2 - dst is wrong (NULL)
7482 * -3 - failed to decode url or dst is to small
7483 * -4 - name does not exist
7484 */
7485 if (dst == NULL || dst_len == 0) {
7486 len = -2;
7487 } else if (buf->p == NULL || name == NULL || buf->len == 0) {
7488 len = -1;
7489 dst[0] = '\0';
7490 } else {
7491 name_len = strlen(name);
7492 e = buf->p + buf->len;
7493 len = -4;
7494 dst[0] = '\0';
7495
7496 for (p = buf->p; p + name_len < e; p++) {
7497 if ((p == buf->p || p[-1] == '&') && p[name_len] == '=' &&
7498 !mg_ncasecmp(name, p, name_len)) {
7499 p += name_len + 1;
7500 s = (const char *) memchr(p, '&', (size_t)(e - p));
7501 if (s == NULL) {
7502 s = e;
7503 }
7504 len = mg_url_decode(p, (size_t)(s - p), dst, dst_len, 1);
7505 /* -1 means: failed to decode or dst is too small */
7506 if (len == -1) {
7507 len = -3;
7508 }
7509 break;
7510 }
7511 }
7512 }
7513
7514 return len;
7515}
7516
7517void mg_send_http_chunk(struct mg_connection *nc, const char *buf, size_t len) {
7518 char chunk_size[50];
7519 int n;
7520
7521 n = snprintf(chunk_size, sizeof(chunk_size), "%lX\r\n", (unsigned long) len);
7522 mg_send(nc, chunk_size, n);
7523 mg_send(nc, buf, len);
7524 mg_send(nc, "\r\n", 2);
7525}
7526
7527void mg_printf_http_chunk(struct mg_connection *nc, const char *fmt, ...) {
7528 char mem[MG_VPRINTF_BUFFER_SIZE], *buf = mem;
7529 int len;
7530 va_list ap;
7531
7532 va_start(ap, fmt);
7533 len = mg_avprintf(&buf, sizeof(mem), fmt, ap);
7534 va_end(ap);
7535
7536 if (len >= 0) {
7537 mg_send_http_chunk(nc, buf, len);
7538 }
7539
7540 /* LCOV_EXCL_START */
7541 if (buf != mem && buf != NULL) {
7542 MG_FREE(buf);
7543 }
7544 /* LCOV_EXCL_STOP */
7545}
7546
7547void mg_printf_html_escape(struct mg_connection *nc, const char *fmt, ...) {
7548 char mem[MG_VPRINTF_BUFFER_SIZE], *buf = mem;
7549 int i, j, len;
7550 va_list ap;
7551
7552 va_start(ap, fmt);
7553 len = mg_avprintf(&buf, sizeof(mem), fmt, ap);
7554 va_end(ap);
7555
7556 if (len >= 0) {
7557 for (i = j = 0; i < len; i++) {
7558 if (buf[i] == '<' || buf[i] == '>') {
7559 mg_send(nc, buf + j, i - j);
7560 mg_send(nc, buf[i] == '<' ? "&lt;" : "&gt;", 4);
7561 j = i + 1;
7562 }
7563 }
7564 mg_send(nc, buf + j, i - j);
7565 }
7566
7567 /* LCOV_EXCL_START */
7568 if (buf != mem && buf != NULL) {
7569 MG_FREE(buf);
7570 }
7571 /* LCOV_EXCL_STOP */
7572}
7573
7574static void mg_http_parse_header_internal(struct mg_str *hdr,
7575 const char *var_name,
7576 struct altbuf *ab) {
7577 int ch = ' ', ch1 = ',', ch2 = ';', n = strlen(var_name);
7578 const char *p, *end = hdr ? hdr->p + hdr->len : NULL, *s = NULL;
7579
7580 /* Find where variable starts */
7581 for (s = hdr->p; s != NULL && s + n < end; s++) {
7582 if ((s == hdr->p || s[-1] == ch || s[-1] == ch1 || s[-1] == ';') &&
7583 s[n] == '=' && !strncmp(s, var_name, n))
7584 break;
7585 }
7586
7587 if (s != NULL && &s[n + 1] < end) {
7588 s += n + 1;
7589 if (*s == '"' || *s == '\'') {
7590 ch = ch1 = ch2 = *s++;
7591 }
7592 p = s;
7593 while (p < end && p[0] != ch && p[0] != ch1 && p[0] != ch2) {
7594 if (ch != ' ' && p[0] == '\\' && p[1] == ch) p++;
7595 altbuf_append(ab, *p++);
7596 }
7597
7598 if (ch != ' ' && *p != ch) {
7600 }
7601 }
7602
7603 /* If there is some data, append a NUL. */
7604 if (ab->len > 0) {
7605 altbuf_append(ab, '\0');
7606 }
7607}
7608
7609int mg_http_parse_header2(struct mg_str *hdr, const char *var_name, char **buf,
7610 size_t buf_size) {
7611 struct altbuf ab;
7612 altbuf_init(&ab, *buf, buf_size);
7613 if (hdr == NULL) return 0;
7614 if (*buf != NULL && buf_size > 0) *buf[0] = '\0';
7615
7617
7618 /*
7619 * Get a (trimmed) buffer, and return a len without a NUL byte which might
7620 * have been added.
7621 */
7622 *buf = altbuf_get_buf(&ab, 1 /* trim */);
7623 return ab.len > 0 ? ab.len - 1 : 0;
7624}
7625
7626int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf,
7627 size_t buf_size) {
7628 char *buf2 = buf;
7629
7630 int len = mg_http_parse_header2(hdr, var_name, &buf2, buf_size);
7631
7632 if (buf2 != buf) {
7633 /* Buffer was not enough and was reallocated: free it and just return 0 */
7634 MG_FREE(buf2);
7635 return 0;
7636 }
7637
7638 return len;
7639}
7640
7641int mg_get_http_basic_auth(struct http_message *hm, char *user, size_t user_len,
7642 char *pass, size_t pass_len) {
7643 struct mg_str *hdr = mg_get_http_header(hm, "Authorization");
7644 if (hdr == NULL) return -1;
7646}
7647
7648int mg_parse_http_basic_auth(struct mg_str *hdr, char *user, size_t user_len,
7649 char *pass, size_t pass_len) {
7650 char *buf = NULL;
7651 char fmt[64];
7652 int res = 0;
7653
7654 if (mg_strncmp(*hdr, mg_mk_str("Basic "), 6) != 0) return -1;
7655
7656 buf = (char *) MG_MALLOC(hdr->len);
7657 cs_base64_decode((unsigned char *) hdr->p + 6, hdr->len, buf, NULL);
7658
7659 /* e.g. "%123[^:]:%321[^\n]" */
7660 snprintf(fmt, sizeof(fmt), "%%%" SIZE_T_FMT "[^:]:%%%" SIZE_T_FMT "[^\n]",
7661 user_len - 1, pass_len - 1);
7662 if (sscanf(buf, fmt, user, pass) == 0) {
7663 res = -1;
7664 }
7665
7666 MG_FREE(buf);
7667 return res;
7668}
7669
7670#if MG_ENABLE_FILESYSTEM
7671static int mg_is_file_hidden(const char *path,
7672 const struct mg_serve_http_opts *opts,
7673 int exclude_specials) {
7674 const char *p1 = opts->per_directory_auth_file;
7675 const char *p2 = opts->hidden_file_pattern;
7676
7677 /* Strip directory path from the file name */
7678 const char *pdir = strrchr(path, DIRSEP);
7679 if (pdir != NULL) {
7680 path = pdir + 1;
7681 }
7682
7683 return (exclude_specials && (!strcmp(path, ".") || !strcmp(path, ".."))) ||
7684 (p1 != NULL && mg_match_prefix(p1, strlen(p1), path) == strlen(p1)) ||
7685 (p2 != NULL && mg_match_prefix(p2, strlen(p2), path) > 0);
7686}
7687
7688#if !MG_DISABLE_HTTP_DIGEST_AUTH
7689
7690#ifndef MG_EXT_MD5
7691void mg_hash_md5_v(size_t num_msgs, const uint8_t *msgs[],
7692 const size_t *msg_lens, uint8_t *digest) {
7693 size_t i;
7696 for (i = 0; i < num_msgs; i++) {
7698 }
7700}
7701#else
7702extern void mg_hash_md5_v(size_t num_msgs, const uint8_t *msgs[],
7703 const size_t *msg_lens, uint8_t *digest);
7704#endif
7705
7706void cs_md5(char buf[33], ...) {
7707 unsigned char hash[16];
7708 const uint8_t *msgs[20], *p;
7709 size_t msg_lens[20];
7710 size_t num_msgs = 0;
7711 va_list ap;
7712
7713 va_start(ap, buf);
7714 while ((p = va_arg(ap, const unsigned char *) ) != NULL) {
7715 msgs[num_msgs] = p;
7716 msg_lens[num_msgs] = va_arg(ap, size_t);
7717 num_msgs++;
7718 }
7719 va_end(ap);
7720
7722 cs_to_hex(buf, hash, sizeof(hash));
7723}
7724
7725static void mg_mkmd5resp(const char *method, size_t method_len, const char *uri,
7726 size_t uri_len, const char *ha1, size_t ha1_len,
7727 const char *nonce, size_t nonce_len, const char *nc,
7728 size_t nc_len, const char *cnonce, size_t cnonce_len,
7729 const char *qop, size_t qop_len, char *resp) {
7730 static const char colon[] = ":";
7731 static const size_t one = 1;
7732 char ha2[33];
7733 cs_md5(ha2, method, method_len, colon, one, uri, uri_len, NULL);
7734 cs_md5(resp, ha1, ha1_len, colon, one, nonce, nonce_len, colon, one, nc,
7735 nc_len, colon, one, cnonce, cnonce_len, colon, one, qop, qop_len,
7736 colon, one, ha2, sizeof(ha2) - 1, NULL);
7737}
7738
7739int mg_http_create_digest_auth_header(char *buf, size_t buf_len,
7740 const char *method, const char *uri,
7741 const char *auth_domain, const char *user,
7742 const char *passwd, const char *nonce) {
7743 static const char colon[] = ":", qop[] = "auth";
7744 static const size_t one = 1;
7745 char ha1[33], resp[33], cnonce[40];
7746
7747 snprintf(cnonce, sizeof(cnonce), "%lx", (unsigned long) mg_time());
7748 cs_md5(ha1, user, (size_t) strlen(user), colon, one, auth_domain,
7749 (size_t) strlen(auth_domain), colon, one, passwd,
7750 (size_t) strlen(passwd), NULL);
7751 mg_mkmd5resp(method, strlen(method), uri, strlen(uri), ha1, sizeof(ha1) - 1,
7752 nonce, strlen(nonce), "1", one, cnonce, strlen(cnonce), qop,
7753 sizeof(qop) - 1, resp);
7754 return snprintf(buf, buf_len,
7755 "Authorization: Digest username=\"%s\","
7756 "realm=\"%s\",uri=\"%s\",qop=%s,nc=1,cnonce=%s,"
7757 "nonce=%s,response=%s\r\n",
7758 user, auth_domain, uri, qop, cnonce, nonce, resp);
7759}
7760
7761/*
7762 * Check for authentication timeout.
7763 * Clients send time stamp encoded in nonce. Make sure it is not too old,
7764 * to prevent replay attacks.
7765 * Assumption: nonce is a hexadecimal number of seconds since 1970.
7766 */
7767static int mg_check_nonce(const char *nonce) {
7768 unsigned long now = (unsigned long) mg_time();
7769 unsigned long val = (unsigned long) strtoul(nonce, NULL, 16);
7770 return (now >= val) && (now - val < 60 * 60);
7771}
7772
7773int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain,
7774 FILE *fp) {
7775 int ret = 0;
7776 struct mg_str *hdr;
7777 char username_buf[50], cnonce_buf[64], response_buf[40], uri_buf[200],
7778 qop_buf[20], nc_buf[20], nonce_buf[16];
7779
7780 char *username = username_buf, *cnonce = cnonce_buf, *response = response_buf,
7781 *uri = uri_buf, *qop = qop_buf, *nc = nc_buf, *nonce = nonce_buf;
7782
7783 /* Parse "Authorization:" header, fail fast on parse error */
7784 if (hm == NULL || fp == NULL ||
7785 (hdr = mg_get_http_header(hm, "Authorization")) == NULL ||
7786 mg_http_parse_header2(hdr, "username", &username, sizeof(username_buf)) ==
7787 0 ||
7788 mg_http_parse_header2(hdr, "cnonce", &cnonce, sizeof(cnonce_buf)) == 0 ||
7789 mg_http_parse_header2(hdr, "response", &response, sizeof(response_buf)) ==
7790 0 ||
7791 mg_http_parse_header2(hdr, "uri", &uri, sizeof(uri_buf)) == 0 ||
7792 mg_http_parse_header2(hdr, "qop", &qop, sizeof(qop_buf)) == 0 ||
7793 mg_http_parse_header2(hdr, "nc", &nc, sizeof(nc_buf)) == 0 ||
7794 mg_http_parse_header2(hdr, "nonce", &nonce, sizeof(nonce_buf)) == 0 ||
7795 mg_check_nonce(nonce) == 0) {
7796 ret = 0;
7797 goto clean;
7798 }
7799
7800 /* NOTE(lsm): due to a bug in MSIE, we do not compare URIs */
7801
7803 hm->method,
7805 hm->uri.p,
7806 hm->uri.len + (hm->query_string.len ? hm->query_string.len + 1 : 0)),
7807 mg_mk_str(username), mg_mk_str(cnonce), mg_mk_str(response),
7808 mg_mk_str(qop), mg_mk_str(nc), mg_mk_str(nonce), mg_mk_str(auth_domain),
7809 fp);
7810
7811clean:
7812 if (username != username_buf) MG_FREE(username);
7813 if (cnonce != cnonce_buf) MG_FREE(cnonce);
7815 if (uri != uri_buf) MG_FREE(uri);
7816 if (qop != qop_buf) MG_FREE(qop);
7817 if (nc != nc_buf) MG_FREE(nc);
7818 if (nonce != nonce_buf) MG_FREE(nonce);
7819
7820 return ret;
7821}
7822
7823int mg_check_digest_auth(struct mg_str method, struct mg_str uri,
7824 struct mg_str username, struct mg_str cnonce,
7825 struct mg_str response, struct mg_str qop,
7826 struct mg_str nc, struct mg_str nonce,
7827 struct mg_str auth_domain, FILE *fp) {
7828 char buf[128], f_user[sizeof(buf)], f_ha1[sizeof(buf)], f_domain[sizeof(buf)];
7829 char exp_resp[33];
7830
7831 /*
7832 * Read passwords file line by line. If should have htdigest format,
7833 * i.e. each line should be a colon-separated sequence:
7834 * USER_NAME:DOMAIN_NAME:HA1_HASH_OF_USER_DOMAIN_AND_PASSWORD
7835 */
7836 while (fgets(buf, sizeof(buf), fp) != NULL) {
7837 if (sscanf(buf, "%[^:]:%[^:]:%s", f_user, f_domain, f_ha1) == 3 &&
7838 mg_vcmp(&username, f_user) == 0 &&
7839 mg_vcmp(&auth_domain, f_domain) == 0) {
7840 /* Username and domain matched, check the password */
7841 mg_mkmd5resp(method.p, method.len, uri.p, uri.len, f_ha1, strlen(f_ha1),
7842 nonce.p, nonce.len, nc.p, nc.len, cnonce.p, cnonce.len,
7843 qop.p, qop.len, exp_resp);
7844 LOG(LL_DEBUG, ("%.*s %s %.*s %s", (int) username.len, username.p,
7845 f_domain, (int) response.len, response.p, exp_resp));
7846 return mg_ncasecmp(response.p, exp_resp, strlen(exp_resp)) == 0;
7847 }
7848 }
7849
7850 /* None of the entries in the passwords file matched - return failure */
7851 return 0;
7852}
7853
7854int mg_http_is_authorized(struct http_message *hm, struct mg_str path,
7855 const char *domain, const char *passwords_file,
7856 int flags) {
7857 char buf[MG_MAX_PATH];
7858 const char *p;
7859 FILE *fp;
7860 int authorized = 1;
7861
7862 if (domain != NULL && passwords_file != NULL) {
7864 fp = mg_fopen(passwords_file, "r");
7865 } else if (flags & MG_AUTH_FLAG_IS_DIRECTORY) {
7866 snprintf(buf, sizeof(buf), "%.*s%c%s", (int) path.len, path.p, DIRSEP,
7868 fp = mg_fopen(buf, "r");
7869 } else {
7870 p = strrchr(path.p, DIRSEP);
7871 if (p == NULL) p = path.p;
7872 snprintf(buf, sizeof(buf), "%.*s%c%s", (int) (p - path.p), path.p, DIRSEP,
7874 fp = mg_fopen(buf, "r");
7875 }
7876
7877 if (fp != NULL) {
7879 fclose(fp);
7880 } else if (!(flags & MG_AUTH_FLAG_ALLOW_MISSING_FILE)) {
7881 authorized = 0;
7882 }
7883 }
7884
7885 LOG(LL_DEBUG, ("%.*s %s %x %d", (int) path.len, path.p,
7886 passwords_file ? passwords_file : "", flags, authorized));
7887 return authorized;
7888}
7889#else
7890int mg_http_is_authorized(struct http_message *hm, const struct mg_str path,
7891 const char *domain, const char *passwords_file,
7892 int flags) {
7893 (void) hm;
7894 (void) path;
7895 (void) domain;
7897 (void) flags;
7898 return 1;
7899}
7900#endif
7901
7902#if MG_ENABLE_DIRECTORY_LISTING
7903static void mg_escape(const char *src, char *dst, size_t dst_len) {
7904 size_t n = 0;
7905 while (*src != '\0' && n + 5 < dst_len) {
7906 unsigned char ch = *(unsigned char *) src++;
7907 if (ch == '<') {
7908 n += snprintf(dst + n, dst_len - n, "%s", "&lt;");
7909 } else {
7910 dst[n++] = ch;
7911 }
7912 }
7913 dst[n] = '\0';
7914}
7915
7916static void mg_print_dir_entry(struct mg_connection *nc, const char *file_name,
7917 cs_stat_t *stp) {
7918 char size[64], mod[64], path[MG_MAX_PATH];
7919 int64_t fsize = stp->st_size;
7920 int is_dir = S_ISDIR(stp->st_mode);
7921 const char *slash = is_dir ? "/" : "";
7922 struct mg_str href;
7923
7924 if (is_dir) {
7925 snprintf(size, sizeof(size), "%s", "[DIRECTORY]");
7926 } else {
7927 /*
7928 * We use (double) cast below because MSVC 6 compiler cannot
7929 * convert unsigned __int64 to double.
7930 */
7931 if (fsize < 1024) {
7932 snprintf(size, sizeof(size), "%d", (int) fsize);
7933 } else if (fsize < 0x100000) {
7934 snprintf(size, sizeof(size), "%.1fk", (double) fsize / 1024.0);
7935 } else if (fsize < 0x40000000) {
7936 snprintf(size, sizeof(size), "%.1fM", (double) fsize / 1048576);
7937 } else {
7938 snprintf(size, sizeof(size), "%.1fG", (double) fsize / 1073741824);
7939 }
7940 }
7941 strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&stp->st_mtime));
7942 mg_escape(file_name, path, sizeof(path));
7945 "<tr><td><a href=\"%s%s\">%s%s</a></td>"
7946 "<td>%s</td><td name=%" INT64_FMT ">%s</td></tr>\n",
7947 href.p, slash, path, slash, mod, is_dir ? -1 : fsize,
7948 size);
7949 free((void *) href.p);
7950}
7951
7952static void mg_scan_directory(struct mg_connection *nc, const char *dir,
7953 const struct mg_serve_http_opts *opts,
7954 void (*func)(struct mg_connection *, const char *,
7955 cs_stat_t *)) {
7956 char path[MG_MAX_PATH + 1];
7957 cs_stat_t st;
7958 struct dirent *dp;
7959 DIR *dirp;
7960
7961 LOG(LL_DEBUG, ("%p [%s]", nc, dir));
7962 if ((dirp = (opendir(dir))) != NULL) {
7963 while ((dp = readdir(dirp)) != NULL) {
7964 /* Do not show current dir and hidden files */
7965 if (mg_is_file_hidden((const char *) dp->d_name, opts, 1)) {
7966 continue;
7967 }
7968 snprintf(path, sizeof(path), "%s/%s", dir, dp->d_name);
7969 if (mg_stat(path, &st) == 0) {
7970 func(nc, (const char *) dp->d_name, &st);
7971 }
7972 }
7973 closedir(dirp);
7974 } else {
7975 LOG(LL_DEBUG, ("%p opendir(%s) -> %d", nc, dir, mg_get_errno()));
7976 }
7977}
7978
7979static void mg_send_directory_listing(struct mg_connection *nc, const char *dir,
7980 struct http_message *hm,
7981 struct mg_serve_http_opts *opts) {
7982 static const char *sort_js_code =
7983 "<script>function srt(tb, sc, so, d) {"
7984 "var tr = Array.prototype.slice.call(tb.rows, 0),"
7985 "tr = tr.sort(function (a, b) { var c1 = a.cells[sc], c2 = b.cells[sc],"
7986 "n1 = c1.getAttribute('name'), n2 = c2.getAttribute('name'), "
7987 "t1 = a.cells[2].getAttribute('name'), "
7988 "t2 = b.cells[2].getAttribute('name'); "
7989 "return so * (t1 < 0 && t2 >= 0 ? -1 : t2 < 0 && t1 >= 0 ? 1 : "
7990 "n1 ? parseInt(n2) - parseInt(n1) : "
7991 "c1.textContent.trim().localeCompare(c2.textContent.trim())); });";
7992 static const char *sort_js_code2 =
7993 "for (var i = 0; i < tr.length; i++) tb.appendChild(tr[i]); "
7994 "if (!d) window.location.hash = ('sc=' + sc + '&so=' + so); "
7995 "};"
7996 "window.onload = function() {"
7997 "var tb = document.getElementById('tb');"
7998 "var m = /sc=([012]).so=(1|-1)/.exec(window.location.hash) || [0, 2, 1];"
7999 "var sc = m[1], so = m[2]; document.onclick = function(ev) { "
8000 "var c = ev.target.rel; if (c) {if (c == sc) so *= -1; srt(tb, c, so); "
8001 "sc = c; ev.preventDefault();}};"
8002 "srt(tb, sc, so, true);"
8003 "}"
8004 "</script>";
8005
8006 mg_send_response_line(nc, 200, opts->extra_headers);
8007 mg_printf(nc, "%s: %s\r\n%s: %s\r\n\r\n", "Transfer-Encoding", "chunked",
8008 "Content-Type", "text/html; charset=utf-8");
8009
8011 nc,
8012 "<html><head><title>Index of %.*s</title>%s%s"
8013 "<style>th,td {text-align: left; padding-right: 1em; "
8014 "font-family: monospace; }</style></head>\n"
8015 "<body><h1>Index of %.*s</h1>\n<table cellpadding=0><thead>"
8016 "<tr><th><a href=# rel=0>Name</a></th><th>"
8017 "<a href=# rel=1>Modified</a</th>"
8018 "<th><a href=# rel=2>Size</a></th></tr>"
8019 "<tr><td colspan=3><hr></td></tr>\n"
8020 "</thead>\n"
8021 "<tbody id=tb>",
8022 (int) hm->uri.len, hm->uri.p, sort_js_code, sort_js_code2,
8023 (int) hm->uri.len, hm->uri.p);
8026 "</tbody><tr><td colspan=3><hr></td></tr>\n"
8027 "</table>\n"
8028 "<address>%s</address>\n"
8029 "</body></html>",
8031 mg_send_http_chunk(nc, "", 0);
8032 /* TODO(rojer): Remove when cesanta/dev/issues/197 is fixed. */
8034}
8035#endif /* MG_ENABLE_DIRECTORY_LISTING */
8036
8037/*
8038 * Given a directory path, find one of the files specified in the
8039 * comma-separated list of index files `list`.
8040 * First found index file wins. If an index file is found, then gets
8041 * appended to the `path`, stat-ed, and result of `stat()` passed to `stp`.
8042 * If index file is not found, then `path` and `stp` remain unchanged.
8043 */
8044MG_INTERNAL void mg_find_index_file(const char *path, const char *list,
8045 char **index_file, cs_stat_t *stp) {
8046 struct mg_str vec;
8047 size_t path_len = strlen(path);
8048 int found = 0;
8049 *index_file = NULL;
8050
8051 /* Traverse index files list. For each entry, append it to the given */
8052 /* path and see if the file exists. If it exists, break the loop */
8053 while ((list = mg_next_comma_list_entry(list, &vec, NULL)) != NULL) {
8054 cs_stat_t st;
8055 size_t len = path_len + 1 + vec.len + 1;
8056 *index_file = (char *) MG_REALLOC(*index_file, len);
8057 if (*index_file == NULL) break;
8058 snprintf(*index_file, len, "%s%c%.*s", path, DIRSEP, (int) vec.len, vec.p);
8059
8060 /* Does it exist? Is it a file? */
8061 if (mg_stat(*index_file, &st) == 0 && S_ISREG(st.st_mode)) {
8062 /* Yes it does, break the loop */
8063 *stp = st;
8064 found = 1;
8065 break;
8066 }
8067 }
8068 if (!found) {
8070 *index_file = NULL;
8071 }
8072 LOG(LL_DEBUG, ("[%s] [%s]", path, (*index_file ? *index_file : "")));
8073}
8074
8075#if MG_ENABLE_HTTP_URL_REWRITES
8077 struct mg_connection *c, struct http_message *hm,
8078 const struct mg_serve_http_opts *opts) {
8079 const char *rewrites = opts->url_rewrites;
8080 struct mg_str a, b;
8081 char local_port[20] = {'%'};
8082
8083 mg_conn_addr_to_str(c, local_port + 1, sizeof(local_port) - 1,
8085
8086 while ((rewrites = mg_next_comma_list_entry(rewrites, &a, &b)) != NULL) {
8087 if (mg_vcmp(&a, local_port) == 0) {
8089 mg_printf(c, "Content-Length: 0\r\nLocation: %.*s%.*s\r\n\r\n",
8090 (int) b.len, b.p, (int) (hm->proto.p - hm->uri.p - 1),
8091 hm->uri.p);
8092 return 1;
8093 }
8094 }
8095
8096 return 0;
8097}
8098
8099static uint64_t ContentLength(const std::string& msg)
8100{
8101 const char* CRLFCRLF = "\r\n\r\n";
8102 size_t pos = msg.find(CRLFCRLF);
8103 if (pos == std::string::npos) {
8104 return 0;
8105 }
8106 //printf("msg.length %d, pos %d\n", (int)msg.length(), (int)pos);
8107 return msg.length() - pos - 4;
8108}
8109
8110static void SetContentLength(std::string& msg, uint64_t len)
8111{
8112 const char* CRLF = "\r\n";
8113 const char* CL = "Content-Length: ";
8114 size_t pos = msg.find(CL);
8115 if (pos == std::string::npos) {
8116 return;
8117 }
8118 pos += strlen(CL);
8119 size_t pos2 = msg.find(CRLF, pos);
8120 if (pos2 == std::string::npos) {
8121 return;
8122 }
8123 char buf[256];
8124 sprintf(buf, "%llu", (long long unsigned)len);
8125 msg.replace(pos, pos2-pos, buf);
8126 //printf("content-length %d, pos %d, pos2 %d\n", (int)len, (int)pos, (int)pos2);
8127}
8128
8129bool Rewrite(std::string& message, const char* re, const char* rs)
8130{
8131 bool changed = false;
8132 size_t pos = 0;
8133 size_t len = strlen(re);
8134 while (1) {
8135 pos = message.find(re, pos);
8136 if (pos == std::string::npos) {
8137 break;
8138 }
8139 message.replace(pos, len, rs);
8140 changed = true;
8141 }
8142 return changed;
8143}
8144
8145static void mg_reverse_proxy_handler(struct mg_connection *nc, int ev,
8146 void *ev_data MG_UD_ARG(void *user_data)) {
8147 struct http_message *hm = (struct http_message *) ev_data;
8149
8150 if (pd == NULL || pd->reverse_proxy_data.linked_conn == NULL) {
8151 DBG(("%p: upstream closed", nc));
8152 return;
8153 }
8154
8155 //if (ev != 0) {
8156 // printf("proxy event %d\n", ev);
8157 //}
8158
8159 switch (ev) {
8160 case MG_EV_CONNECT:
8161 if (*(int *) ev_data != 0) {
8162 mg_http_send_error(pd->reverse_proxy_data.linked_conn, 502, NULL);
8163 }
8164 break;
8165 /* TODO(mkm): handle streaming */
8166 case MG_EV_RECV: {
8167 //struct mbuf *io = &nc->recv_mbuf;
8168 //printf("proxy read: %d bytes [%s]\n", (int)io->len, io->buf);
8169 break;
8170 }
8171 case MG_EV_HTTP_REPLY: {
8172 // HTTP header "Transfer-Encoding: chunked" has to be removed:
8173 // proxy data is chunked, after mongoose reads it, chunking is removed,
8174 // it is sent to requestor all in one go (not chunked), but
8175 // Transfer-Encoding header is still there and confuses the web browser.
8176 // We hack the message to hide this header and everything works. K.O.
8177 mg_str xstr;
8178 xstr.p = "Transfer-Encoding: chunked";
8179 xstr.len = strlen(xstr.p);
8180 const char* s = mg_strstr(hm->message, xstr);
8181 if (s) {
8182 *(char*)s = 'X';
8183 }
8184 //printf("proxy reply: [%s]\n", hm->message.p);
8185 if (0) {
8186 std::string message_in(hm->message.p, hm->message.len);
8187 // <link rel="icon" type="image/png" href="/static/favicons/favicon-16px-a64986.png" sizes="16x16">
8188 // <script type="text/javascript" src="/static/scripts/bundle-9e842c.js"></script></body>
8189 //std::regex re("href=\"/");
8190 //std::string rs("href=\"");
8191 //std::regex re("h");
8192 //std::string rs("XXX");
8193 //std::regex re ("\\b(sub)([^ ]*)");
8194 //std::string message = std::regex_replace(message_in.c_str(), re, "sub-$2");
8195 bool changed = false;
8196 std::string message = message_in;
8197 changed |= Rewrite(message, "href=\"/", "href=\"");
8198 changed |= Rewrite(message, "src=\"/", "src=\"");
8199 // ...post("/api/...
8200 changed |= Rewrite(message, "post(\"/api/", "post(\"api/");
8201 if (changed) {
8202 // need to doctor ContentLength!
8204 //printf("proxy rewrite:\n[%s] content-length %d\n[%s] content-length %d\n", message_in.c_str(), (int)ContentLength(message_in), message.c_str(), (int)ContentLength(message));
8205 mg_send(pd->reverse_proxy_data.linked_conn, message.c_str(), message.length());
8206 } else {
8207 mg_send(pd->reverse_proxy_data.linked_conn, hm->message.p, hm->message.len);
8208 }
8209 } else {
8210 mg_send(pd->reverse_proxy_data.linked_conn, hm->message.p, hm->message.len);
8211 }
8212 pd->reverse_proxy_data.linked_conn->flags |= MG_F_SEND_AND_CLOSE;
8214 break;
8215 }
8216 case MG_EV_CLOSE: {
8217 struct mbuf *io = &nc->recv_mbuf;
8218 //printf("proxy close: mbuf %p, bytes %d\n", io, (int)io->len); //, io->buf);
8219 if (io->len > 0) {
8220 mg_send(pd->reverse_proxy_data.linked_conn, io->buf, io->len);
8221 }
8222 pd->reverse_proxy_data.linked_conn->flags |= MG_F_SEND_AND_CLOSE;
8223 break;
8224 }
8225 }
8226
8227#if MG_ENABLE_CALLBACK_USERDATA
8228 (void) user_data;
8229#endif
8230}
8231
8232void mg_http_reverse_proxy(struct mg_connection *nc,
8233 const struct http_message *hm, struct mg_str mount,
8234 struct mg_str upstream) {
8235 struct mg_connection *be;
8236 char burl[256], *purl = burl;
8237 int i;
8238 const char *error;
8239 struct mg_connect_opts opts;
8240 struct mg_str path = MG_NULL_STR, user_info = MG_NULL_STR, host = MG_NULL_STR;
8241 memset(&opts, 0, sizeof(opts));
8242 opts.error_string = &error;
8243
8244 mg_asprintf(&purl, sizeof(burl), "%.*s%.*s%s%.*s", (int) upstream.len, upstream.p,
8245 (int) (hm->uri.len - mount.len), hm->uri.p + mount.len, (hm->query_string.len > 0 ? "?" : ""), (int) hm->query_string.len, hm->query_string.p);
8246
8247 //printf("proxy url: [%s]\n", purl);
8248
8250 opts, "http", NULL, "https", NULL, purl, &path,
8251 &user_info, &host);
8252 LOG(LL_DEBUG, ("Proxying %.*s to %s (rule: %.*s)", (int) hm->uri.len,
8253 hm->uri.p, purl, (int) mount.len, mount.p));
8254
8255 if (be == NULL) {
8256 LOG(LL_ERROR, ("Error connecting to %s: %s", purl, error));
8257 mg_http_send_error(nc, 502, NULL);
8258 goto cleanup;
8259 }
8260
8262
8263 /* link connections to each other, they must live and die together */
8264 mg_http_get_proto_data(be)->reverse_proxy_data.linked_conn = nc;
8265 mg_http_get_proto_data(nc)->reverse_proxy_data.linked_conn = be;
8266
8267 /* send request upstream */
8268 mg_printf(be, "%.*s %.*s HTTP/1.1\r\n", (int) hm->method.len, hm->method.p,
8269 (int) path.len, path.p);
8270
8271 mg_printf(be, "Host: %.*s\r\n", (int) host.len, host.p);
8272 for (i = 0; i < MG_MAX_HTTP_HEADERS && hm->header_names[i].len > 0; i++) {
8273 struct mg_str hn = hm->header_names[i];
8274 struct mg_str hv = hm->header_values[i];
8275
8276 /* we rewrite the host header */
8277 if (mg_vcasecmp(&hn, "Host") == 0) continue;
8278 /*
8279 * Don't pass chunked transfer encoding to the client because hm->body is
8280 * already dechunked when we arrive here.
8281 */
8282 if (mg_vcasecmp(&hn, "Transfer-encoding") == 0 &&
8283 mg_vcasecmp(&hv, "chunked") == 0) {
8284 mg_printf(be, "Content-Length: %" SIZE_T_FMT "\r\n", hm->body.len);
8285 continue;
8286 }
8287 /* We don't support proxying Expect: 100-continue. */
8288 if (mg_vcasecmp(&hn, "Expect") == 0 &&
8289 mg_vcasecmp(&hv, "100-continue") == 0) {
8290 continue;
8291 }
8292
8293 mg_printf(be, "%.*s: %.*s\r\n", (int) hn.len, hn.p, (int) hv.len, hv.p);
8294 }
8295
8296 mg_send(be, "\r\n", 2);
8297 mg_send(be, hm->body.p, hm->body.len);
8298
8299cleanup:
8300 if (purl != burl) MG_FREE(purl);
8301}
8302
8303static int mg_http_handle_forwarding(struct mg_connection *nc,
8304 struct http_message *hm,
8305 const struct mg_serve_http_opts *opts) {
8306 const char *rewrites = opts->url_rewrites;
8307 struct mg_str a, b;
8308 struct mg_str p1 = MG_MK_STR("http://"), p2 = MG_MK_STR("https://");
8309
8310 while ((rewrites = mg_next_comma_list_entry(rewrites, &a, &b)) != NULL) {
8311 if (mg_strncmp(a, hm->uri, a.len) == 0) {
8312 if (mg_strncmp(b, p1, p1.len) == 0 || mg_strncmp(b, p2, p2.len) == 0) {
8313 mg_http_reverse_proxy(nc, hm, a, b);
8314 return 1;
8315 }
8316 }
8317 }
8318
8319 return 0;
8320}
8321#endif /* MG_ENABLE_FILESYSTEM */
8322
8323#if 0
8325 const struct mg_serve_http_opts *opts,
8326 char **local_path,
8327 struct mg_str *remainder) {
8328 int ok = 1;
8329 const char *cp = hm->uri.p, *cp_end = hm->uri.p + hm->uri.len;
8330 struct mg_str root = {NULL, 0};
8331 const char *file_uri_start = cp;
8332 *local_path = NULL;
8333 remainder->p = NULL;
8334 remainder->len = 0;
8335
8336 { /* 1. Determine which root to use. */
8337
8338#if MG_ENABLE_HTTP_URL_REWRITES
8339 const char *rewrites = opts->url_rewrites;
8340#else
8341 const char *rewrites = "";
8342#endif
8343 struct mg_str *hh = mg_get_http_header(hm, "Host");
8344 struct mg_str a, b;
8345 /* Check rewrites first. */
8346 while ((rewrites = mg_next_comma_list_entry(rewrites, &a, &b)) != NULL) {
8347 if (a.len > 1 && a.p[0] == '@') {
8348 /* Host rewrite. */
8349 if (hh != NULL && hh->len == a.len - 1 &&
8350 mg_ncasecmp(a.p + 1, hh->p, a.len - 1) == 0) {
8351 root = b;
8352 break;
8353 }
8354 } else {
8355 /* Regular rewrite, URI=directory */
8356 size_t match_len = mg_match_prefix_n(a, hm->uri);
8357 if (match_len > 0) {
8358 file_uri_start = hm->uri.p + match_len;
8359 if (*file_uri_start == '/' || file_uri_start == cp_end) {
8360 /* Match ended at component boundary, ok. */
8361 } else if (*(file_uri_start - 1) == '/') {
8362 /* Pattern ends with '/', backtrack. */
8364 } else {
8365 /* No match: must fall on the component boundary. */
8366 continue;
8367 }
8368 root = b;
8369 break;
8370 }
8371 }
8372 }
8373 /* If no rewrite rules matched, use DAV or regular document root. */
8374 if (root.p == NULL) {
8375#if MG_ENABLE_HTTP_WEBDAV
8376 if (opts->dav_document_root != NULL && mg_is_dav_request(&hm->method)) {
8377 root.p = opts->dav_document_root;
8378 root.len = strlen(opts->dav_document_root);
8379 } else
8380#endif
8381 {
8382 root.p = opts->document_root;
8383 root.len = strlen(opts->document_root);
8384 }
8385 }
8386 assert(root.p != NULL && root.len > 0);
8387 }
8388
8389 { /* 2. Find where in the canonical URI path the local path ends. */
8390 const char *u = file_uri_start + 1;
8391 char *lp = (char *) MG_MALLOC(root.len + hm->uri.len + 1);
8392 char *lp_end = lp + root.len + hm->uri.len + 1;
8393 char *p = lp, *ps;
8394 int exists = 1;
8395 if (lp == NULL) {
8396 ok = 0;
8397 goto out;
8398 }
8399 memcpy(p, root.p, root.len);
8400 p += root.len;
8401 if (*(p - 1) == DIRSEP) p--;
8402 *p = '\0';
8403 ps = p;
8404
8405 /* Chop off URI path components one by one and build local path. */
8406 while (u <= cp_end) {
8407 const char *next = u;
8408 struct mg_str component;
8409 if (exists) {
8410 cs_stat_t st;
8411 exists = (mg_stat(lp, &st) == 0);
8412 if (exists && S_ISREG(st.st_mode)) {
8413 /* We found the terminal, the rest of the URI (if any) is path_info.
8414 */
8415 if (*(u - 1) == '/') u--;
8416 break;
8417 }
8418 }
8419 if (u >= cp_end) break;
8420 parse_uri_component((const char **) &next, cp_end, "/", &component);
8421 if (component.len > 0) {
8422 int len;
8423 memmove(p + 1, component.p, component.len);
8424 len = mg_url_decode(p + 1, component.len, p + 1, lp_end - p - 1, 0);
8425 if (len <= 0) {
8426 ok = 0;
8427 break;
8428 }
8429 component.p = p + 1;
8430 component.len = len;
8431 if (mg_vcmp(&component, ".") == 0) {
8432 /* Yum. */
8433 } else if (mg_vcmp(&component, "..") == 0) {
8434 while (p > ps && *p != DIRSEP) p--;
8435 *p = '\0';
8436 } else {
8437 size_t i;
8438#ifdef _WIN32
8439 /* On Windows, make sure it's valid Unicode (no funny stuff). */
8440 wchar_t buf[MG_MAX_PATH * 2];
8441 if (to_wchar(component.p, buf, MG_MAX_PATH) == 0) {
8442 DBG(("[%.*s] smells funny", (int) component.len, component.p));
8443 ok = 0;
8444 break;
8445 }
8446#endif
8447 *p++ = DIRSEP;
8448 /* No NULs and DIRSEPs in the component (percent-encoded). */
8449 for (i = 0; i < component.len; i++, p++) {
8450 if (*p == '\0' || *p == DIRSEP
8452 /* On Windows, "/" is also accepted, so check for that too. */
8453 ||
8454 *p == '/'
8455#endif
8456 ) {
8457 ok = 0;
8458 break;
8459 }
8460 }
8461 }
8462 }
8463 u = next;
8464 }
8465 if (ok) {
8466 *local_path = lp;
8467 if (u > cp_end) u = cp_end;
8468 remainder->p = u;
8469 remainder->len = cp_end - u;
8470 } else {
8471 MG_FREE(lp);
8472 }
8473 }
8474
8475out:
8476 LOG(LL_DEBUG,
8477 ("'%.*s' -> '%s' + '%.*s'", (int) hm->uri.len, hm->uri.p,
8478 *local_path ? *local_path : "", (int) remainder->len, remainder->p));
8479 return ok;
8480}
8481#endif
8482
8483static int mg_get_month_index(const char *s) {
8484 static const char *month_names[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
8485 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
8486 size_t i;
8487
8488 for (i = 0; i < ARRAY_SIZE(month_names); i++)
8489 if (!strcmp(s, month_names[i])) return (int) i;
8490
8491 return -1;
8492}
8493
8494static int mg_num_leap_years(int year) {
8495 return year / 4 - year / 100 + year / 400;
8496}
8497
8498/* Parse UTC date-time string, and return the corresponding time_t value. */
8500 static const unsigned short days_before_month[] = {
8501 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
8502 char month_str[32];
8504 time_t result = (time_t) 0;
8505
8506 if (((sscanf(datetime, "%d/%3s/%d %d:%d:%d", &day, month_str, &year, &hour,
8507 &minute, &second) == 6) ||
8508 (sscanf(datetime, "%d %3s %d %d:%d:%d", &day, month_str, &year, &hour,
8509 &minute, &second) == 6) ||
8510 (sscanf(datetime, "%*3s, %d %3s %d %d:%d:%d", &day, month_str, &year,
8511 &hour, &minute, &second) == 6) ||
8512 (sscanf(datetime, "%d-%3s-%d %d:%d:%d", &day, month_str, &year, &hour,
8513 &minute, &second) == 6)) &&
8514 year > 1970 && (month = mg_get_month_index(month_str)) != -1) {
8516 year -= 1970;
8517 days = year * 365 + days_before_month[month] + (day - 1) + leap_days;
8518 result = days * 24 * 3600 + hour * 3600 + minute * 60 + second;
8519 }
8520
8521 return result;
8522}
8523
8525 struct mg_str *hdr;
8526 if ((hdr = mg_get_http_header(hm, "If-None-Match")) != NULL) {
8527 char etag[64];
8529 return mg_vcasecmp(hdr, etag) == 0;
8530 } else if ((hdr = mg_get_http_header(hm, "If-Modified-Since")) != NULL) {
8531 return st->st_mtime <= mg_parse_date_string(hdr->p);
8532 } else {
8533 return 0;
8534 }
8535}
8536
8538 const char *domain) {
8539 mg_printf(c,
8540 "HTTP/1.1 401 Unauthorized\r\n"
8541 "WWW-Authenticate: Digest qop=\"auth\", "
8542 "realm=\"%s\", nonce=\"%lx\"\r\n"
8543 "Content-Length: 0\r\n\r\n",
8544 domain, (unsigned long) mg_time());
8545}
8546
8547static void mg_http_send_options(struct mg_connection *nc,
8548 struct mg_serve_http_opts *opts) {
8549 mg_send_response_line(nc, 200, opts->extra_headers);
8550 mg_printf(nc, "%s",
8551 "Allow: GET, POST, HEAD, CONNECT, OPTIONS"
8553 ", MKCOL, PUT, DELETE, PROPFIND, MOVE\r\nDAV: 1,2"
8554#endif
8555 "\r\n\r\n");
8557}
8558
8559static int mg_is_creation_request(const struct http_message *hm) {
8560 return mg_vcmp(&hm->method, "MKCOL") == 0 || mg_vcmp(&hm->method, "PUT") == 0;
8561}
8562
8563MG_INTERNAL void mg_send_http_file(struct mg_connection *nc, char *path,
8564 const struct mg_str *path_info,
8565 struct http_message *hm,
8566 struct mg_serve_http_opts *opts) {
8567 int exists, is_directory, is_cgi;
8568#if MG_ENABLE_HTTP_WEBDAV
8569 int is_dav = mg_is_dav_request(&hm->method);
8570#else
8571 int is_dav = 0;
8572#endif
8573 char *index_file = NULL;
8574 cs_stat_t st;
8575
8576 exists = (mg_stat(path, &st) == 0);
8577 is_directory = exists && S_ISDIR(st.st_mode);
8578
8579 if (is_directory)
8580 mg_find_index_file(path, opts->index_files, &index_file, &st);
8581
8582 is_cgi =
8583 (mg_match_prefix(opts->cgi_file_pattern, strlen(opts->cgi_file_pattern),
8584 index_file ? index_file : path) > 0);
8585
8586 LOG(LL_DEBUG,
8587 ("%p %.*s [%s] exists=%d is_dir=%d is_dav=%d is_cgi=%d index=%s", nc,
8588 (int) hm->method.len, hm->method.p, path, exists, is_directory, is_dav,
8589 is_cgi, index_file ? index_file : ""));
8590
8591 if (is_directory && hm->uri.p[hm->uri.len - 1] != '/' && !is_dav) {
8592 mg_printf(nc,
8593 "HTTP/1.1 301 Moved\r\nLocation: %.*s/\r\n"
8594 "Content-Length: 0\r\n\r\n",
8595 (int) hm->uri.len, hm->uri.p);
8597 return;
8598 }
8599
8600 /* If we have path_info, the only way to handle it is CGI. */
8601 if (path_info->len > 0 && !is_cgi) {
8602 mg_http_send_error(nc, 501, NULL);
8604 return;
8605 }
8606
8607 if (is_dav && opts->dav_document_root == NULL) {
8608 mg_http_send_error(nc, 501, NULL);
8609 } else if (!mg_http_is_authorized(
8610 hm, mg_mk_str(path), opts->auth_domain, opts->global_auth_file,
8611 ((is_directory ? MG_AUTH_FLAG_IS_DIRECTORY : 0) |
8615 hm, mg_mk_str(path), opts->auth_domain,
8616 opts->per_directory_auth_file,
8617 ((is_directory ? MG_AUTH_FLAG_IS_DIRECTORY : 0) |
8619 mg_http_send_digest_auth_request(nc, opts->auth_domain);
8620 } else if (is_cgi) {
8621#if MG_ENABLE_HTTP_CGI
8622 mg_handle_cgi(nc, index_file ? index_file : path, path_info, hm, opts);
8623#else
8624 mg_http_send_error(nc, 501, NULL);
8625#endif /* MG_ENABLE_HTTP_CGI */
8626 } else if ((!exists ||
8627 mg_is_file_hidden(path, opts, 0 /* specials are ok */)) &&
8629 mg_http_send_error(nc, 404, NULL);
8630#if MG_ENABLE_HTTP_WEBDAV
8631 } else if (!mg_vcmp(&hm->method, "PROPFIND")) {
8632 mg_handle_propfind(nc, path, &st, hm, opts);
8633#if !MG_DISABLE_DAV_AUTH
8634 } else if (is_dav &&
8635 (opts->dav_auth_file == NULL ||
8636 (strcmp(opts->dav_auth_file, "-") != 0 &&
8638 hm, mg_mk_str(path), opts->auth_domain, opts->dav_auth_file,
8639 ((is_directory ? MG_AUTH_FLAG_IS_DIRECTORY : 0) |
8642 mg_http_send_digest_auth_request(nc, opts->auth_domain);
8643#endif
8644 } else if (!mg_vcmp(&hm->method, "MKCOL")) {
8645 mg_handle_mkcol(nc, path, hm);
8646 } else if (!mg_vcmp(&hm->method, "DELETE")) {
8647 mg_handle_delete(nc, opts, path);
8648 } else if (!mg_vcmp(&hm->method, "PUT")) {
8649 mg_handle_put(nc, path, hm);
8650 } else if (!mg_vcmp(&hm->method, "MOVE")) {
8651 mg_handle_move(nc, opts, path, hm);
8652#if MG_ENABLE_FAKE_DAVLOCK
8653 } else if (!mg_vcmp(&hm->method, "LOCK")) {
8654 mg_handle_lock(nc, path);
8655#endif
8656#endif /* MG_ENABLE_HTTP_WEBDAV */
8657 } else if (!mg_vcmp(&hm->method, "OPTIONS")) {
8659 } else if (is_directory && index_file == NULL) {
8660#if MG_ENABLE_DIRECTORY_LISTING
8661 if (strcmp(opts->enable_directory_listing, "yes") == 0) {
8662 mg_send_directory_listing(nc, path, hm, opts);
8663 } else {
8664 mg_http_send_error(nc, 403, NULL);
8665 }
8666#else
8667 mg_http_send_error(nc, 501, NULL);
8668#endif
8669 } else if (mg_is_not_modified(hm, &st)) {
8670 mg_http_send_error(nc, 304, "Not Modified");
8671 } else {
8673 }
8675}
8676
8677#if 0
8678void mg_serve_http(struct mg_connection *nc, struct http_message *hm,
8679 struct mg_serve_http_opts opts) {
8680 char *path = NULL;
8681 struct mg_str *hdr, path_info;
8682 uint32_t remote_ip = ntohl(*(uint32_t *) &nc->sa.sin.sin_addr);
8683
8684 if (mg_check_ip_acl(opts.ip_acl, remote_ip) != 1) {
8685 /* Not allowed to connect */
8686 mg_http_send_error(nc, 403, NULL);
8688 return;
8689 }
8690
8691#if MG_ENABLE_HTTP_URL_REWRITES
8692 if (mg_http_handle_forwarding(nc, hm, &opts)) {
8693 return;
8694 }
8695
8697 return;
8698 }
8699#endif
8700
8701 if (opts.document_root == NULL) {
8702 opts.document_root = ".";
8703 }
8704 if (opts.per_directory_auth_file == NULL) {
8705 opts.per_directory_auth_file = ".htpasswd";
8706 }
8707 if (opts.enable_directory_listing == NULL) {
8708 opts.enable_directory_listing = "yes";
8709 }
8710 if (opts.cgi_file_pattern == NULL) {
8711 opts.cgi_file_pattern = "**.cgi$|**.php$";
8712 }
8713 if (opts.ssi_pattern == NULL) {
8714 opts.ssi_pattern = "**.shtml$|**.shtm$";
8715 }
8716 if (opts.index_files == NULL) {
8717 opts.index_files = "index.html,index.htm,index.shtml,index.cgi,index.php";
8718 }
8719 /* Normalize path - resolve "." and ".." (in-place). */
8720 if (!mg_normalize_uri_path(&hm->uri, &hm->uri)) {
8721 mg_http_send_error(nc, 400, NULL);
8722 return;
8723 }
8724 if (mg_uri_to_local_path(hm, &opts, &path, &path_info) == 0) {
8725 mg_http_send_error(nc, 404, NULL);
8726 return;
8727 }
8728 mg_send_http_file(nc, path, &path_info, hm, &opts);
8729
8730 MG_FREE(path);
8731 path = NULL;
8732
8733 /* Close connection for non-keep-alive requests */
8734 if (mg_vcmp(&hm->proto, "HTTP/1.1") != 0 ||
8735 ((hdr = mg_get_http_header(hm, "Connection")) != NULL &&
8736 mg_vcmp(hdr, "keep-alive") != 0)) {
8737#if 0
8739#endif
8740 }
8741}
8742#endif
8743
8744#if MG_ENABLE_HTTP_STREAMING_MULTIPART
8745void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data,
8747 MG_UD_ARG(void *user_data)) {
8748 switch (ev) {
8749 case MG_EV_HTTP_PART_BEGIN: {
8750 struct mg_http_multipart_part *mp =
8752 struct file_upload_state *fus;
8753 struct mg_str lfn = local_name_fn(nc, mg_mk_str(mp->file_name));
8754 mp->user_data = NULL;
8755 if (lfn.p == NULL || lfn.len == 0) {
8756 LOG(LL_ERROR, ("%p Not allowed to upload %s", nc, mp->file_name));
8757 mg_printf(nc,
8758 "HTTP/1.1 403 Not Allowed\r\n"
8759 "Content-Type: text/plain\r\n"
8760 "Connection: close\r\n\r\n"
8761 "Not allowed to upload %s\r\n",
8762 mp->file_name);
8764 return;
8765 }
8766 fus = (struct file_upload_state *) MG_CALLOC(1, sizeof(*fus));
8767 if (fus == NULL) {
8769 return;
8770 }
8771 fus->lfn = (char *) MG_MALLOC(lfn.len + 1);
8772 memcpy(fus->lfn, lfn.p, lfn.len);
8773 fus->lfn[lfn.len] = '\0';
8774 if (lfn.p != mp->file_name) MG_FREE((char *) lfn.p);
8775 LOG(LL_DEBUG,
8776 ("%p Receiving file %s -> %s", nc, mp->file_name, fus->lfn));
8777 fus->fp = mg_fopen(fus->lfn, "wb");
8778 if (fus->fp == NULL) {
8779 mg_printf(nc,
8780 "HTTP/1.1 500 Internal Server Error\r\n"
8781 "Content-Type: text/plain\r\n"
8782 "Connection: close\r\n\r\n");
8783 LOG(LL_ERROR, ("Failed to open %s: %d\n", fus->lfn, mg_get_errno()));
8784 mg_printf(nc, "Failed to open %s: %d\n", fus->lfn, mg_get_errno());
8785 /* Do not close the connection just yet, discard remainder of the data.
8786 * This is because at the time of writing some browsers (Chrome) fail to
8787 * render response before all the data is sent. */
8788 }
8789 mp->user_data = (void *) fus;
8790 break;
8791 }
8792 case MG_EV_HTTP_PART_DATA: {
8793 struct mg_http_multipart_part *mp =
8795 struct file_upload_state *fus =
8796 (struct file_upload_state *) mp->user_data;
8797 if (fus == NULL || fus->fp == NULL) break;
8798 if (mg_fwrite(mp->data.p, 1, mp->data.len, fus->fp) != mp->data.len) {
8799 LOG(LL_ERROR, ("Failed to write to %s: %d, wrote %d", fus->lfn,
8800 mg_get_errno(), (int) fus->num_recd));
8801 if (mg_get_errno() == ENOSPC
8804#endif
8805 ) {
8806 mg_printf(nc,
8807 "HTTP/1.1 413 Payload Too Large\r\n"
8808 "Content-Type: text/plain\r\n"
8809 "Connection: close\r\n\r\n");
8810 mg_printf(nc, "Failed to write to %s: no space left; wrote %d\r\n",
8811 fus->lfn, (int) fus->num_recd);
8812 } else {
8813 mg_printf(nc,
8814 "HTTP/1.1 500 Internal Server Error\r\n"
8815 "Content-Type: text/plain\r\n"
8816 "Connection: close\r\n\r\n");
8817 mg_printf(nc, "Failed to write to %s: %d, wrote %d", mp->file_name,
8818 mg_get_errno(), (int) fus->num_recd);
8819 }
8820 fclose(fus->fp);
8821 remove(fus->lfn);
8822 fus->fp = NULL;
8823 /* Do not close the connection just yet, discard remainder of the data.
8824 * This is because at the time of writing some browsers (Chrome) fail to
8825 * render response before all the data is sent. */
8826 return;
8827 }
8828 fus->num_recd += mp->data.len;
8829 LOG(LL_DEBUG, ("%p rec'd %d bytes, %d total", nc, (int) mp->data.len,
8830 (int) fus->num_recd));
8831 break;
8832 }
8833 case MG_EV_HTTP_PART_END: {
8834 struct mg_http_multipart_part *mp =
8836 struct file_upload_state *fus =
8837 (struct file_upload_state *) mp->user_data;
8838 if (fus == NULL) break;
8839 if (mp->status >= 0 && fus->fp != NULL) {
8840 LOG(LL_DEBUG, ("%p Uploaded %s (%s), %d bytes", nc, mp->file_name,
8841 fus->lfn, (int) fus->num_recd));
8842 } else {
8843 LOG(LL_ERROR, ("Failed to store %s (%s)", mp->file_name, fus->lfn));
8844 /*
8845 * mp->status < 0 means connection was terminated, so no reason to send
8846 * HTTP reply
8847 */
8848 }
8849 if (fus->fp != NULL) fclose(fus->fp);
8850 MG_FREE(fus->lfn);
8851 MG_FREE(fus);
8852 mp->user_data = NULL;
8853 /* Don't close the connection yet, there may be more files to come. */
8854 break;
8855 }
8857 mg_printf(nc,
8858 "HTTP/1.1 200 OK\r\n"
8859 "Content-Type: text/plain\r\n"
8860 "Connection: close\r\n\r\n"
8861 "Ok.\r\n");
8863 break;
8864 }
8865 }
8866
8867#if MG_ENABLE_CALLBACK_USERDATA
8868 (void) user_data;
8869#endif
8870}
8871
8872#endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
8873#endif /* MG_ENABLE_FILESYSTEM */
8874
8877 struct mg_connect_opts opts, const char *scheme1, const char *scheme2,
8878 const char *scheme_ssl1, const char *scheme_ssl2, const char *url,
8879 struct mg_str *path, struct mg_str *user_info, struct mg_str *host) {
8880 struct mg_connection *nc = NULL;
8881 unsigned int port_i = 0;
8882 int use_ssl = 0;
8883 struct mg_str scheme, query, fragment;
8884 char conn_addr_buf[2];
8885 char *conn_addr = conn_addr_buf;
8886
8887 if (mg_parse_uri(mg_mk_str(url), &scheme, user_info, host, &port_i, path,
8888 &query, &fragment) != 0) {
8889 MG_SET_PTRPTR(opts.error_string, "cannot parse url");
8890 goto out;
8891 }
8892
8893 /* If query is present, do not strip it. Pass to the caller. */
8894 if (query.len > 0) path->len += query.len + 1;
8895
8896 if (scheme.len == 0 || mg_vcmp(&scheme, scheme1) == 0 ||
8897 (scheme2 != NULL && mg_vcmp(&scheme, scheme2) == 0)) {
8898 use_ssl = 0;
8899 if (port_i == 0) port_i = 80;
8900 } else if (mg_vcmp(&scheme, scheme_ssl1) == 0 ||
8901 (scheme2 != NULL && mg_vcmp(&scheme, scheme_ssl2) == 0)) {
8902 use_ssl = 1;
8903 if (port_i == 0) port_i = 443;
8904 } else {
8905 goto out;
8906 }
8907
8908 mg_asprintf(&conn_addr, sizeof(conn_addr_buf), "tcp://%.*s:%u",
8909 (int) host->len, host->p, port_i);
8910 if (conn_addr == NULL) goto out;
8911
8912 LOG(LL_DEBUG, ("%s use_ssl? %d %s", url, use_ssl, conn_addr));
8913 if (use_ssl) {
8914#if MG_ENABLE_SSL
8915 /*
8916 * Schema requires SSL, but no SSL parameters were provided in opts.
8917 * In order to maintain backward compatibility, use a faux-SSL with no
8918 * verification.
8919 */
8920 if (opts.ssl_ca_cert == NULL) {
8921 opts.ssl_ca_cert = "*";
8922 }
8923#else
8924 MG_SET_PTRPTR(opts.error_string, "ssl is disabled");
8925 goto out;
8926#endif
8927 }
8928
8929 if ((nc = mg_connect_opt(mgr, conn_addr, MG_CB(ev_handler, user_data),
8930 opts)) != NULL) {
8932 }
8933
8934out:
8936 return nc;
8937}
8938
8941 struct mg_connect_opts opts, const char *url, const char *extra_headers,
8942 const char *post_data) {
8943 struct mg_str user = MG_NULL_STR, null_str = MG_NULL_STR;
8944 struct mg_str host = MG_NULL_STR, path = MG_NULL_STR;
8945 struct mbuf auth;
8946 struct mg_connection *nc =
8948 NULL, "https", NULL, url, &path, &user, &host);
8949
8950 if (nc == NULL) {
8951 return NULL;
8952 }
8953
8954 mbuf_init(&auth, 0);
8955 if (user.len > 0) {
8957 }
8958
8959 if (post_data == NULL) post_data = "";
8960 if (extra_headers == NULL) extra_headers = "";
8961 if (path.len == 0) path = mg_mk_str("/");
8962 if (host.len == 0) host = mg_mk_str("");
8963
8964 mg_printf(nc, "%s %.*s HTTP/1.1\r\nHost: %.*s\r\nContent-Length: %" SIZE_T_FMT
8965 "\r\n%.*s%s\r\n%s",
8966 (post_data[0] == '\0' ? "GET" : "POST"), (int) path.len, path.p,
8967 (int) (path.p - host.p), host.p, strlen(post_data), (int) auth.len,
8968 (auth.buf == NULL ? "" : auth.buf), extra_headers, post_data);
8969
8970 mbuf_free(&auth);
8971 return nc;
8972}
8973
8976 const char *url, const char *extra_headers, const char *post_data) {
8977 struct mg_connect_opts opts;
8978 memset(&opts, 0, sizeof(opts));
8980 extra_headers, post_data);
8981}
8982
8983size_t mg_parse_multipart(const char *buf, size_t buf_len, char *var_name,
8984 size_t var_name_len, char *file_name,
8985 size_t file_name_len, const char **data,
8986 size_t *data_len) {
8987 static const char cd[] = "Content-Disposition: ";
8988 size_t hl, bl, n, ll, pos, cdl = sizeof(cd) - 1;
8989 int shl;
8990
8991 if (buf == NULL || buf_len <= 0) return 0;
8992 if ((shl = mg_http_get_request_len(buf, buf_len)) <= 0) return 0;
8993 hl = shl;
8994 if (buf[0] != '-' || buf[1] != '-' || buf[2] == '\n') return 0;
8995
8996 /* Get boundary length */
8997 bl = mg_get_line_len(buf, buf_len);
8998
8999 /* Loop through headers, fetch variable name and file name */
9000 var_name[0] = file_name[0] = '\0';
9001 for (n = bl; (ll = mg_get_line_len(buf + n, hl - n)) > 0; n += ll) {
9002 if (mg_ncasecmp(cd, buf + n, cdl) == 0) {
9003 struct mg_str header;
9004 header.p = buf + n + cdl;
9005 header.len = ll - (cdl + 2);
9006 {
9007 char *var_name2 = var_name;
9008 mg_http_parse_header2(&header, "name", &var_name2, var_name_len);
9009 /* TODO: handle reallocated buffer correctly */
9010 if (var_name2 != var_name) {
9012 var_name[0] = '\0';
9013 }
9014 }
9015 {
9016 char *file_name2 = file_name;
9017 mg_http_parse_header2(&header, "filename", &file_name2, file_name_len);
9018 /* TODO: handle reallocated buffer correctly */
9019 if (file_name2 != file_name) {
9021 file_name[0] = '\0';
9022 }
9023 }
9024 }
9025 }
9026
9027 /* Scan through the body, search for terminating boundary */
9028 for (pos = hl; pos + (bl - 2) < buf_len; pos++) {
9029 if (buf[pos] == '-' && !strncmp(buf, &buf[pos], bl - 2)) {
9030 if (data_len != NULL) *data_len = (pos - 2) - hl;
9031 if (data != NULL) *data = buf + hl;
9032 return pos;
9033 }
9034 }
9035
9036 return 0;
9037}
9038
9040 const char *uri_path,
9041 mg_event_handler_t handler,
9042 struct mg_http_endpoint_opts opts) {
9043 struct mg_http_proto_data *pd = NULL;
9044 struct mg_http_endpoint *new_ep = NULL;
9045
9046 if (nc == NULL) return;
9047 new_ep = (struct mg_http_endpoint *) MG_CALLOC(1, sizeof(*new_ep));
9048 if (new_ep == NULL) return;
9049
9051 if (pd == NULL) pd = mg_http_create_proto_data(nc);
9052 new_ep->uri_pattern = mg_strdup(mg_mk_str(uri_path));
9053 if (opts.auth_domain != NULL && opts.auth_file != NULL) {
9054 new_ep->auth_domain = strdup(opts.auth_domain);
9055 new_ep->auth_file = strdup(opts.auth_file);
9056 }
9057 new_ep->handler = handler;
9058#if MG_ENABLE_CALLBACK_USERDATA
9059 new_ep->user_data = opts.user_data;
9060#endif
9061 new_ep->next = pd->endpoints;
9062 pd->endpoints = new_ep;
9063}
9064
9065static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev,
9066 struct http_message *hm) {
9068 void *user_data = nc->user_data;
9069
9070 if (ev == MG_EV_HTTP_REQUEST
9073#endif
9074 ) {
9075 struct mg_http_endpoint *ep =
9077 if (ep != NULL) {
9078#if MG_ENABLE_FILESYSTEM && !MG_DISABLE_HTTP_DIGEST_AUTH
9079 if (!mg_http_is_authorized(hm, hm->uri, ep->auth_domain, ep->auth_file,
9081 mg_http_send_digest_auth_request(nc, ep->auth_domain);
9082 return;
9083 }
9084#endif
9085 pd->endpoint_handler = ep->handler;
9086#if MG_ENABLE_CALLBACK_USERDATA
9087 user_data = ep->user_data;
9088#endif
9089 }
9090 }
9091 mg_call(nc, pd->endpoint_handler ? pd->endpoint_handler : nc->handler,
9092 user_data, ev, hm);
9093}
9094
9095void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path,
9097 void *user_data)) {
9099 memset(&opts, 0, sizeof(opts));
9100#if MG_ENABLE_CALLBACK_USERDATA
9101 opts.user_data = user_data;
9102#endif
9104}
9105
9106#endif /* MG_ENABLE_HTTP */
9107#ifdef MG_MODULE_LINES
9108#line 1 "mongoose/src/mg_http_cgi.c"
9109#endif
9110/*
9111 * Copyright (c) 2014-2016 Cesanta Software Limited
9112 * All rights reserved
9113 */
9114
9115#ifndef _WIN32
9116#include <signal.h>
9117#endif
9118
9119#if MG_ENABLE_HTTP && MG_ENABLE_HTTP_CGI
9120
9121#ifndef MG_MAX_CGI_ENVIR_VARS
9122#define MG_MAX_CGI_ENVIR_VARS 64
9123#endif
9124
9125#ifndef MG_ENV_EXPORT_TO_CGI
9126#define MG_ENV_EXPORT_TO_CGI "MONGOOSE_CGI"
9127#endif
9128
9129#define MG_F_HTTP_CGI_PARSE_HEADERS MG_F_USER_1
9130
9131/*
9132 * This structure helps to create an environment for the spawned CGI program.
9133 * Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
9134 * last element must be NULL.
9135 * However, on Windows there is a requirement that all these VARIABLE=VALUE\0
9136 * strings must reside in a contiguous buffer. The end of the buffer is
9137 * marked by two '\0' characters.
9138 * We satisfy both worlds: we create an envp array (which is vars), all
9139 * entries are actually pointers inside buf.
9140 */
9141struct mg_cgi_env_block {
9142 struct mg_connection *nc;
9143 char buf[MG_CGI_ENVIRONMENT_SIZE]; /* Environment buffer */
9144 const char *vars[MG_MAX_CGI_ENVIR_VARS]; /* char *envp[] */
9145 int len; /* Space taken */
9146 int nvars; /* Number of variables in envp[] */
9147};
9148
9149#ifdef _WIN32
9150struct mg_threadparam {
9151 sock_t s;
9152 HANDLE hPipe;
9153};
9154
9155static int mg_wait_until_ready(sock_t sock, int for_read) {
9156 fd_set set;
9157 FD_ZERO(&set);
9158 FD_SET(sock, &set);
9159 return select(sock + 1, for_read ? &set : 0, for_read ? 0 : &set, 0, 0) == 1;
9160}
9161
9162static void *mg_push_to_stdin(void *arg) {
9163 struct mg_threadparam *tp = (struct mg_threadparam *) arg;
9164 int n, sent, stop = 0;
9165 DWORD k;
9166 char buf[BUFSIZ];
9167
9168 while (!stop && mg_wait_until_ready(tp->s, 1) &&
9169 (n = recv(tp->s, buf, sizeof(buf), 0)) > 0) {
9170 if (n == -1 && GetLastError() == WSAEWOULDBLOCK) continue;
9171 for (sent = 0; !stop && sent < n; sent += k) {
9172 if (!WriteFile(tp->hPipe, buf + sent, n - sent, &k, 0)) stop = 1;
9173 }
9174 }
9175 DBG(("%s", "FORWARED EVERYTHING TO CGI"));
9176 CloseHandle(tp->hPipe);
9177 MG_FREE(tp);
9178 return NULL;
9179}
9180
9181static void *mg_pull_from_stdout(void *arg) {
9182 struct mg_threadparam *tp = (struct mg_threadparam *) arg;
9183 int k = 0, stop = 0;
9184 DWORD n, sent;
9185 char buf[BUFSIZ];
9186
9187 while (!stop && ReadFile(tp->hPipe, buf, sizeof(buf), &n, NULL)) {
9188 for (sent = 0; !stop && sent < n; sent += k) {
9189 if (mg_wait_until_ready(tp->s, 0) &&
9190 (k = send(tp->s, buf + sent, n - sent, 0)) <= 0)
9191 stop = 1;
9192 }
9193 }
9194 DBG(("%s", "EOF FROM CGI"));
9195 CloseHandle(tp->hPipe);
9196 shutdown(tp->s, 2); // Without this, IO thread may get truncated data
9197 closesocket(tp->s);
9198 MG_FREE(tp);
9199 return NULL;
9200}
9201
9202static void mg_spawn_stdio_thread(sock_t sock, HANDLE hPipe,
9203 void *(*func)(void *)) {
9204 struct mg_threadparam *tp = (struct mg_threadparam *) MG_MALLOC(sizeof(*tp));
9205 if (tp != NULL) {
9206 tp->s = sock;
9207 tp->hPipe = hPipe;
9208 mg_start_thread(func, tp);
9209 }
9210}
9211
9212static void mg_abs_path(const char *utf8_path, char *abs_path, size_t len) {
9213 wchar_t buf[MG_MAX_PATH], buf2[MG_MAX_PATH];
9214 to_wchar(utf8_path, buf, ARRAY_SIZE(buf));
9216 WideCharToMultiByte(CP_UTF8, 0, buf2, wcslen(buf2) + 1, abs_path, len, 0, 0);
9217}
9218
9219static int mg_start_process(const char *interp, const char *cmd,
9220 const char *env, const char *envp[],
9221 const char *dir, sock_t sock) {
9224 HANDLE a[2], b[2], me = GetCurrentProcess();
9229 FILE *fp;
9230
9231 memset(&si, 0, sizeof(si));
9232 memset(&pi, 0, sizeof(pi));
9233
9234 si.cb = sizeof(si);
9236 si.wShowWindow = SW_HIDE;
9237 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
9238
9239 CreatePipe(&a[0], &a[1], NULL, 0);
9240 CreatePipe(&b[0], &b[1], NULL, 0);
9241 DuplicateHandle(me, a[0], me, &si.hStdInput, 0, TRUE, flags);
9242 DuplicateHandle(me, b[1], me, &si.hStdOutput, 0, TRUE, flags);
9243
9244 if (interp == NULL && (fp = mg_fopen(cmd, "r")) != NULL) {
9245 buf[0] = buf[1] = '\0';
9246 fgets(buf, sizeof(buf), fp);
9247 buf[sizeof(buf) - 1] = '\0';
9248 if (buf[0] == '#' && buf[1] == '!') {
9249 interp = buf + 2;
9250 /* Trim leading spaces: https://github.com/cesanta/mongoose/issues/489 */
9251 while (*interp != '\0' && isspace(*(unsigned char *) interp)) {
9252 interp++;
9253 }
9254 }
9255 fclose(fp);
9256 }
9257
9258 snprintf(buf, sizeof(buf), "%s/%s", dir, cmd);
9260
9263
9264 if (interp != NULL) {
9266 snprintf(cmdline, sizeof(cmdline), "%s \"%s\"", buf4, buf2);
9267 } else {
9268 snprintf(cmdline, sizeof(cmdline), "\"%s\"", buf2);
9269 }
9271
9273 (void *) env, full_dir, &si, &pi) != 0) {
9276
9277 CloseHandle(si.hStdOutput);
9278 CloseHandle(si.hStdInput);
9279
9280 CloseHandle(pi.hThread);
9281 CloseHandle(pi.hProcess);
9282 } else {
9283 CloseHandle(a[1]);
9284 CloseHandle(b[0]);
9285 closesocket(sock);
9286 }
9287 DBG(("CGI command: [%ls] -> %p", wcmd, pi.hProcess));
9288
9289 /* Not closing a[0] and b[1] because we've used DUPLICATE_CLOSE_SOURCE */
9290 (void) envp;
9291 return (pi.hProcess != NULL);
9292}
9293#else
9294static int mg_start_process(const char *interp, const char *cmd,
9295 const char *env, const char *envp[],
9296 const char *dir, sock_t sock) {
9297 char buf[500];
9298 pid_t pid = fork();
9299 (void) env;
9300
9301 if (pid == 0) {
9302 /*
9303 * In Linux `chdir` declared with `warn_unused_result` attribute
9304 * To shutup compiler we have yo use result in some way
9305 */
9306 int tmp = chdir(dir);
9307 (void) tmp;
9308 (void) dup2(sock, 0);
9309 (void) dup2(sock, 1);
9310 closesocket(sock);
9311
9312 /*
9313 * After exec, all signal handlers are restored to their default values,
9314 * with one exception of SIGCHLD. According to POSIX.1-2001 and Linux's
9315 * implementation, SIGCHLD's handler will leave unchanged after exec
9316 * if it was set to be ignored. Restore it to default action.
9317 */
9319
9320 if (interp == NULL) {
9321 execle(cmd, cmd, (char *) 0, envp); /* (char *) 0 to squash warning */
9322 } else {
9323 execle(interp, interp, cmd, (char *) 0, envp);
9324 }
9325 snprintf(buf, sizeof(buf),
9326 "Status: 500\r\n\r\n"
9327 "500 Server Error: %s%s%s: %s",
9328 interp == NULL ? "" : interp, interp == NULL ? "" : " ", cmd,
9329 strerror(errno));
9330 send(1, buf, strlen(buf), 0);
9331 _exit(EXIT_FAILURE); /* exec call failed */
9332 }
9333
9334 return (pid != 0);
9335}
9336#endif /* _WIN32 */
9337
9338/*
9339 * Append VARIABLE=VALUE\0 string to the buffer, and add a respective
9340 * pointer into the vars array.
9341 */
9342static char *mg_addenv(struct mg_cgi_env_block *block, const char *fmt, ...) {
9343 int n, space;
9344 char *added = block->buf + block->len;
9345 va_list ap;
9346
9347 /* Calculate how much space is left in the buffer */
9348 space = sizeof(block->buf) - (block->len + 2);
9349 if (space > 0) {
9350 /* Copy VARIABLE=VALUE\0 string into the free space */
9351 va_start(ap, fmt);
9352 n = vsnprintf(added, (size_t) space, fmt, ap);
9353 va_end(ap);
9354
9355 /* Make sure we do not overflow buffer and the envp array */
9356 if (n > 0 && n + 1 < space &&
9357 block->nvars < (int) ARRAY_SIZE(block->vars) - 2) {
9358 /* Append a pointer to the added string into the envp array */
9359 block->vars[block->nvars++] = added;
9360 /* Bump up used length counter. Include \0 terminator */
9361 block->len += n + 1;
9362 }
9363 }
9364
9365 return added;
9366}
9367
9368static void mg_addenv2(struct mg_cgi_env_block *blk, const char *name) {
9369 const char *s;
9370 if ((s = getenv(name)) != NULL) mg_addenv(blk, "%s=%s", name, s);
9371}
9372
9373static void mg_prepare_cgi_environment(struct mg_connection *nc,
9374 const char *prog,
9375 const struct mg_str *path_info,
9376 const struct http_message *hm,
9377 const struct mg_serve_http_opts *opts,
9378 struct mg_cgi_env_block *blk) {
9379 const char *s;
9380 struct mg_str *h;
9381 char *p;
9382 size_t i;
9383 char buf[100];
9384 size_t path_info_len = path_info != NULL ? path_info->len : 0;
9385
9386 blk->len = blk->nvars = 0;
9387 blk->nc = nc;
9388
9389 if ((s = getenv("SERVER_NAME")) != NULL) {
9390 mg_addenv(blk, "SERVER_NAME=%s", s);
9391 } else {
9392 mg_sock_to_str(nc->sock, buf, sizeof(buf), 3);
9393 mg_addenv(blk, "SERVER_NAME=%s", buf);
9394 }
9395 mg_addenv(blk, "SERVER_ROOT=%s", opts->document_root);
9396 mg_addenv(blk, "DOCUMENT_ROOT=%s", opts->document_root);
9397 mg_addenv(blk, "SERVER_SOFTWARE=%s/%s", "Mongoose", MG_VERSION);
9398
9399 /* Prepare the environment block */
9400 mg_addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
9401 mg_addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
9402 mg_addenv(blk, "%s", "REDIRECT_STATUS=200"); /* For PHP */
9403
9404 mg_addenv(blk, "REQUEST_METHOD=%.*s", (int) hm->method.len, hm->method.p);
9405
9406 mg_addenv(blk, "REQUEST_URI=%.*s%s%.*s", (int) hm->uri.len, hm->uri.p,
9407 hm->query_string.len == 0 ? "" : "?", (int) hm->query_string.len,
9408 hm->query_string.p);
9409
9410 mg_conn_addr_to_str(nc, buf, sizeof(buf),
9412 mg_addenv(blk, "REMOTE_ADDR=%s", buf);
9413 mg_conn_addr_to_str(nc, buf, sizeof(buf), MG_SOCK_STRINGIFY_PORT);
9414 mg_addenv(blk, "SERVER_PORT=%s", buf);
9415
9416 s = hm->uri.p + hm->uri.len - path_info_len - 1;
9417 if (*s == '/') {
9418 const char *base_name = strrchr(prog, DIRSEP);
9419 mg_addenv(blk, "SCRIPT_NAME=%.*s/%s", (int) (s - hm->uri.p), hm->uri.p,
9420 (base_name != NULL ? base_name + 1 : prog));
9421 } else {
9422 mg_addenv(blk, "SCRIPT_NAME=%.*s", (int) (s - hm->uri.p + 1), hm->uri.p);
9423 }
9424 mg_addenv(blk, "SCRIPT_FILENAME=%s", prog);
9425
9426 if (path_info != NULL && path_info->len > 0) {
9427 mg_addenv(blk, "PATH_INFO=%.*s", (int) path_info->len, path_info->p);
9428 /* Not really translated... */
9429 mg_addenv(blk, "PATH_TRANSLATED=%.*s", (int) path_info->len, path_info->p);
9430 }
9431
9432#if MG_ENABLE_SSL
9433 mg_addenv(blk, "HTTPS=%s", (nc->flags & MG_F_SSL ? "on" : "off"));
9434#else
9435 mg_addenv(blk, "HTTPS=off");
9436#endif
9437
9438 if ((h = mg_get_http_header((struct http_message *) hm, "Content-Type")) !=
9439 NULL) {
9440 mg_addenv(blk, "CONTENT_TYPE=%.*s", (int) h->len, h->p);
9441 }
9442
9443 if (hm->query_string.len > 0) {
9444 mg_addenv(blk, "QUERY_STRING=%.*s", (int) hm->query_string.len,
9445 hm->query_string.p);
9446 }
9447
9448 if ((h = mg_get_http_header((struct http_message *) hm, "Content-Length")) !=
9449 NULL) {
9450 mg_addenv(blk, "CONTENT_LENGTH=%.*s", (int) h->len, h->p);
9451 }
9452
9453 mg_addenv2(blk, "PATH");
9454 mg_addenv2(blk, "TMP");
9455 mg_addenv2(blk, "TEMP");
9456 mg_addenv2(blk, "TMPDIR");
9457 mg_addenv2(blk, "PERLLIB");
9459
9460#ifdef _WIN32
9461 mg_addenv2(blk, "COMSPEC");
9462 mg_addenv2(blk, "SYSTEMROOT");
9463 mg_addenv2(blk, "SystemDrive");
9464 mg_addenv2(blk, "ProgramFiles");
9465 mg_addenv2(blk, "ProgramFiles(x86)");
9466 mg_addenv2(blk, "CommonProgramFiles(x86)");
9467#else
9468 mg_addenv2(blk, "LD_LIBRARY_PATH");
9469#endif /* _WIN32 */
9470
9471 /* Add all headers as HTTP_* variables */
9472 for (i = 0; hm->header_names[i].len > 0; i++) {
9473 p = mg_addenv(blk, "HTTP_%.*s=%.*s", (int) hm->header_names[i].len,
9474 hm->header_names[i].p, (int) hm->header_values[i].len,
9475 hm->header_values[i].p);
9476
9477 /* Convert variable name into uppercase, and change - to _ */
9478 for (; *p != '=' && *p != '\0'; p++) {
9479 if (*p == '-') *p = '_';
9480 *p = (char) toupper(*(unsigned char *) p);
9481 }
9482 }
9483
9484 blk->vars[blk->nvars++] = NULL;
9485 blk->buf[blk->len++] = '\0';
9486}
9487
9488static void mg_cgi_ev_handler(struct mg_connection *cgi_nc, int ev,
9489 void *ev_data MG_UD_ARG(void *user_data)) {
9490#if !MG_ENABLE_CALLBACK_USERDATA
9491 void *user_data = cgi_nc->user_data;
9492#endif
9493 struct mg_connection *nc = (struct mg_connection *) user_data;
9494 (void) ev_data;
9495
9496 if (nc == NULL) {
9497 /* The corresponding network connection was closed. */
9498 cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY;
9499 return;
9500 }
9501
9502 switch (ev) {
9503 case MG_EV_RECV:
9504 /*
9505 * CGI script does not output reply line, like "HTTP/1.1 CODE XXXXX\n"
9506 * It outputs headers, then body. Headers might include "Status"
9507 * header, which changes CODE, and it might include "Location" header
9508 * which changes CODE to 302.
9509 *
9510 * Therefore we do not send the output from the CGI script to the user
9511 * until all CGI headers are received.
9512 *
9513 * Here we parse the output from the CGI script, and if all headers has
9514 * been received, send appropriate reply line, and forward all
9515 * received headers to the client.
9516 */
9518 struct mbuf *io = &cgi_nc->recv_mbuf;
9519 int len = mg_http_get_request_len(io->buf, io->len);
9520
9521 if (len == 0) break;
9523 cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY;
9524 mg_http_send_error(nc, 500, "Bad headers");
9525 } else {
9526 struct http_message hm;
9527 struct mg_str *h;
9528 mg_http_parse_headers(io->buf, io->buf + io->len, io->len, &hm);
9529 if (mg_get_http_header(&hm, "Location") != NULL) {
9530 mg_printf(nc, "%s", "HTTP/1.1 302 Moved\r\n");
9531 } else if ((h = mg_get_http_header(&hm, "Status")) != NULL) {
9532 mg_printf(nc, "HTTP/1.1 %.*s\r\n", (int) h->len, h->p);
9533 } else {
9534 mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\n");
9535 }
9536 }
9538 }
9539 if (!(nc->flags & MG_F_HTTP_CGI_PARSE_HEADERS)) {
9540 mg_forward(cgi_nc, nc);
9541 }
9542 break;
9543 case MG_EV_CLOSE:
9544 DBG(("%p CLOSE", cgi_nc));
9547 break;
9548 }
9549}
9550
9551MG_INTERNAL void mg_handle_cgi(struct mg_connection *nc, const char *prog,
9552 const struct mg_str *path_info,
9553 const struct http_message *hm,
9554 const struct mg_serve_http_opts *opts) {
9555 struct mg_cgi_env_block blk;
9556 char dir[MG_MAX_PATH];
9557 const char *p;
9558 sock_t fds[2];
9559
9560 DBG(("%p [%s]", nc, prog));
9561 mg_prepare_cgi_environment(nc, prog, path_info, hm, opts, &blk);
9562 /*
9563 * CGI must be executed in its own directory. 'dir' must point to the
9564 * directory containing executable program, 'p' must point to the
9565 * executable program name relative to 'dir'.
9566 */
9567 if ((p = strrchr(prog, DIRSEP)) == NULL) {
9568 snprintf(dir, sizeof(dir), "%s", ".");
9569 } else {
9570 snprintf(dir, sizeof(dir), "%.*s", (int) (p - prog), prog);
9571 prog = p + 1;
9572 }
9573
9574 if (!mg_socketpair(fds, SOCK_STREAM)) {
9576 return;
9577 }
9578
9579#ifndef _WIN32
9580 struct sigaction sa;
9581
9582 sigemptyset(&sa.sa_mask);
9583 sa.sa_handler = SIG_IGN;
9584 sa.sa_flags = 0;
9585 sigaction(SIGCHLD, &sa, NULL);
9586#endif
9587
9588 if (mg_start_process(opts->cgi_interpreter, prog, blk.buf, blk.vars, dir,
9589 fds[1]) != 0) {
9590 struct mg_connection *cgi_nc =
9593 cgi_pd->cgi.cgi_nc = cgi_nc;
9594#if !MG_ENABLE_CALLBACK_USERDATA
9595 cgi_pd->cgi.cgi_nc->user_data = nc;
9596#endif
9598 /* Push POST data to the CGI */
9599 if (hm->body.len > 0) {
9600 mg_send(cgi_pd->cgi.cgi_nc, hm->body.p, hm->body.len);
9601 }
9603 } else {
9604 closesocket(fds[0]);
9605 mg_http_send_error(nc, 500, "CGI failure");
9606 }
9607
9608#ifndef _WIN32
9609 closesocket(fds[1]); /* On Windows, CGI stdio thread closes that socket */
9610#endif
9611}
9612
9614 if (d == NULL) return;
9615 if (d->cgi_nc != NULL) {
9616 d->cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY;
9617 d->cgi_nc->user_data = NULL;
9618 }
9619 memset(d, 0, sizeof(*d));
9620}
9621
9622#endif /* MG_ENABLE_HTTP && MG_ENABLE_HTTP_CGI */
9623#ifdef MG_MODULE_LINES
9624#line 1 "mongoose/src/mg_http_ssi.c"
9625#endif
9626/*
9627 * Copyright (c) 2014-2016 Cesanta Software Limited
9628 * All rights reserved
9629 */
9630
9631#if MG_ENABLE_HTTP && MG_ENABLE_HTTP_SSI && MG_ENABLE_FILESYSTEM
9632
9633static void mg_send_ssi_file(struct mg_connection *nc, struct http_message *hm,
9634 const char *path, FILE *fp, int include_level,
9635 const struct mg_serve_http_opts *opts);
9636
9637static void mg_send_file_data(struct mg_connection *nc, FILE *fp) {
9638 char buf[BUFSIZ];
9639 size_t n;
9640 while ((n = mg_fread(buf, 1, sizeof(buf), fp)) > 0) {
9641 mg_send(nc, buf, n);
9642 }
9643}
9644
9645#if 0
9646static void mg_do_ssi_include(struct mg_connection *nc, struct http_message *hm,
9647 const char *ssi, char *tag, int include_level,
9648 const struct mg_serve_http_opts *opts) {
9649 char file_name[MG_MAX_PATH], path[MG_MAX_PATH], *p;
9650 FILE *fp;
9651
9652 /*
9653 * sscanf() is safe here, since send_ssi_file() also uses buffer
9654 * of size MG_BUF_LEN to get the tag. So strlen(tag) is always < MG_BUF_LEN.
9655 */
9656 if (sscanf(tag, " virtual=\"%[^\"]\"", file_name) == 1) {
9657 /* File name is relative to the webserver root */
9658 snprintf(path, sizeof(path), "%s/%s", opts->document_root, file_name);
9659 } else if (sscanf(tag, " abspath=\"%[^\"]\"", file_name) == 1) {
9660 /*
9661 * File name is relative to the webserver working directory
9662 * or it is absolute system path
9663 */
9664 snprintf(path, sizeof(path), "%s", file_name);
9665 } else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1 ||
9666 sscanf(tag, " \"%[^\"]\"", file_name) == 1) {
9667 /* File name is relative to the currect document */
9668 snprintf(path, sizeof(path), "%s", ssi);
9669 if ((p = strrchr(path, DIRSEP)) != NULL) {
9670 p[1] = '\0';
9671 }
9672 snprintf(path + strlen(path), sizeof(path) - strlen(path), "%s", file_name);
9673 } else {
9674 mg_printf(nc, "Bad SSI #include: [%s]", tag);
9675 return;
9676 }
9677
9678 if ((fp = mg_fopen(path, "rb")) == NULL) {
9679 mg_printf(nc, "SSI include error: mg_fopen(%s): %s", path,
9681 } else {
9683 if (mg_match_prefix(opts->ssi_pattern, strlen(opts->ssi_pattern), path) >
9684 0) {
9685 mg_send_ssi_file(nc, hm, path, fp, include_level + 1, opts);
9686 } else {
9687 mg_send_file_data(nc, fp);
9688 }
9689 fclose(fp);
9690 }
9691}
9692#endif
9693
9694#if MG_ENABLE_HTTP_SSI_EXEC
9695static void do_ssi_exec(struct mg_connection *nc, char *tag) {
9696 char cmd[BUFSIZ];
9697 FILE *fp;
9698
9699 if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) {
9700 mg_printf(nc, "Bad SSI #exec: [%s]", tag);
9701 } else if ((fp = popen(cmd, "r")) == NULL) {
9702 mg_printf(nc, "Cannot SSI #exec: [%s]: %s", cmd, strerror(mg_get_errno()));
9703 } else {
9704 mg_send_file_data(nc, fp);
9705 pclose(fp);
9706 }
9707}
9708#endif /* MG_ENABLE_HTTP_SSI_EXEC */
9709
9710/*
9711 * SSI directive has the following format:
9712 * <!--#directive parameter=value parameter=value -->
9713 */
9714#if 0
9715static void mg_send_ssi_file(struct mg_connection *nc, struct http_message *hm,
9716 const char *path, FILE *fp, int include_level,
9717 const struct mg_serve_http_opts *opts) {
9718 static const struct mg_str btag = MG_MK_STR("<!--#");
9719 static const struct mg_str d_include = MG_MK_STR("include");
9720 static const struct mg_str d_call = MG_MK_STR("call");
9721#if MG_ENABLE_HTTP_SSI_EXEC
9722 static const struct mg_str d_exec = MG_MK_STR("exec");
9723#endif
9724 char buf[BUFSIZ], *p = buf + btag.len; /* p points to SSI directive */
9725 int ch, len, in_ssi_tag;
9726
9727 if (include_level > 10) {
9728 mg_printf(nc, "SSI #include level is too deep (%s)", path);
9729 return;
9730 }
9731
9732 in_ssi_tag = len = 0;
9733 while ((ch = fgetc(fp)) != EOF) {
9734 if (in_ssi_tag && ch == '>' && buf[len - 1] == '-' && buf[len - 2] == '-') {
9735 size_t i = len - 2;
9736 in_ssi_tag = 0;
9737
9738 /* Trim closing --> */
9739 buf[i--] = '\0';
9740 while (i > 0 && buf[i] == ' ') {
9741 buf[i--] = '\0';
9742 }
9743
9744 /* Handle known SSI directives */
9745 if (strncmp(p, d_include.p, d_include.len) == 0) {
9746 mg_do_ssi_include(nc, hm, path, p + d_include.len + 1, include_level,
9747 opts);
9748 } else if (strncmp(p, d_call.p, d_call.len) == 0) {
9749 struct mg_ssi_call_ctx cctx;
9750 memset(&cctx, 0, sizeof(cctx));
9751 cctx.req = hm;
9752 cctx.file = mg_mk_str(path);
9753 cctx.arg = mg_mk_str(p + d_call.len + 1);
9755 (void *) cctx.arg.p); /* NUL added above */
9757#if MG_ENABLE_HTTP_SSI_EXEC
9758 } else if (strncmp(p, d_exec.p, d_exec.len) == 0) {
9759 do_ssi_exec(nc, p + d_exec.len + 1);
9760#endif
9761 } else {
9762 /* Silently ignore unknown SSI directive. */
9763 }
9764 len = 0;
9765 } else if (ch == '<') {
9766 in_ssi_tag = 1;
9767 if (len > 0) {
9768 mg_send(nc, buf, (size_t) len);
9769 }
9770 len = 0;
9771 buf[len++] = ch & 0xff;
9772 } else if (in_ssi_tag) {
9773 if (len == (int) btag.len && strncmp(buf, btag.p, btag.len) != 0) {
9774 /* Not an SSI tag */
9775 in_ssi_tag = 0;
9776 } else if (len == (int) sizeof(buf) - 2) {
9777 mg_printf(nc, "%s: SSI tag is too large", path);
9778 len = 0;
9779 }
9780 buf[len++] = ch & 0xff;
9781 } else {
9782 buf[len++] = ch & 0xff;
9783 if (len == (int) sizeof(buf)) {
9784 mg_send(nc, buf, (size_t) len);
9785 len = 0;
9786 }
9787 }
9788 }
9789
9790 /* Send the rest of buffered data */
9791 if (len > 0) {
9792 mg_send(nc, buf, (size_t) len);
9793 }
9794}
9795
9797 struct http_message *hm,
9798 const char *path,
9799 const struct mg_serve_http_opts *opts) {
9800 FILE *fp;
9801 struct mg_str mime_type;
9802 DBG(("%p %s", nc, path));
9803
9804 if ((fp = mg_fopen(path, "rb")) == NULL) {
9805 mg_http_send_error(nc, 404, NULL);
9806 } else {
9808
9809 mime_type = mg_get_mime_type(path, "text/plain", opts);
9810 mg_send_response_line(nc, 200, opts->extra_headers);
9811 mg_printf(nc,
9812 "Content-Type: %.*s\r\n"
9813 "Connection: close\r\n\r\n",
9814 (int) mime_type.len, mime_type.p);
9815 mg_send_ssi_file(nc, hm, path, fp, 0, opts);
9816 fclose(fp);
9818 }
9819}
9820#endif
9821
9822#endif /* MG_ENABLE_HTTP_SSI && MG_ENABLE_HTTP && MG_ENABLE_FILESYSTEM */
9823#ifdef MG_MODULE_LINES
9824#line 1 "mongoose/src/mg_http_webdav.c"
9825#endif
9826/*
9827 * Copyright (c) 2014-2016 Cesanta Software Limited
9828 * All rights reserved
9829 */
9830
9831#if MG_ENABLE_HTTP && MG_ENABLE_HTTP_WEBDAV
9832
9833MG_INTERNAL int mg_is_dav_request(const struct mg_str *s) {
9834 static const char *methods[] = {
9835 "PUT",
9836 "DELETE",
9837 "MKCOL",
9838 "PROPFIND",
9839 "MOVE"
9840#if MG_ENABLE_FAKE_DAVLOCK
9841 ,
9842 "LOCK",
9843 "UNLOCK"
9844#endif
9845 };
9846 size_t i;
9847
9848 for (i = 0; i < ARRAY_SIZE(methods); i++) {
9849 if (mg_vcmp(s, methods[i]) == 0) {
9850 return 1;
9851 }
9852 }
9853
9854 return 0;
9855}
9856
9857static int mg_mkdir(const char *path, uint32_t mode) {
9858#ifndef _WIN32
9859 return mkdir(path, mode);
9860#else
9861 (void) mode;
9862 return _mkdir(path);
9863#endif
9864}
9865
9866static void mg_print_props(struct mg_connection *nc, const char *name,
9867 cs_stat_t *stp) {
9868 char mtime[64];
9869 time_t t = stp->st_mtime; /* store in local variable for NDK compile */
9871 mg_gmt_time_string(mtime, sizeof(mtime), &t);
9872 mg_printf(nc,
9873 "<d:response>"
9874 "<d:href>%s</d:href>"
9875 "<d:propstat>"
9876 "<d:prop>"
9877 "<d:resourcetype>%s</d:resourcetype>"
9878 "<d:getcontentlength>%" INT64_FMT
9879 "</d:getcontentlength>"
9880 "<d:getlastmodified>%s</d:getlastmodified>"
9881 "</d:prop>"
9882 "<d:status>HTTP/1.1 200 OK</d:status>"
9883 "</d:propstat>"
9884 "</d:response>\n",
9885 name_esc.p, S_ISDIR(stp->st_mode) ? "<d:collection/>" : "",
9886 (int64_t) stp->st_size, mtime);
9887 free((void *) name_esc.p);
9888}
9889
9890MG_INTERNAL void mg_handle_propfind(struct mg_connection *nc, const char *path,
9891 cs_stat_t *stp, struct http_message *hm,
9892 struct mg_serve_http_opts *opts) {
9893 static const char header[] =
9894 "HTTP/1.1 207 Multi-Status\r\n"
9895 "Connection: close\r\n"
9896 "Content-Type: text/xml; charset=utf-8\r\n\r\n"
9897 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
9898 "<d:multistatus xmlns:d='DAV:'>\n";
9899 static const char footer[] = "</d:multistatus>\n";
9900 const struct mg_str *depth = mg_get_http_header(hm, "Depth");
9901
9902 /* Print properties for the requested resource itself */
9903 if (S_ISDIR(stp->st_mode) &&
9904 strcmp(opts->enable_directory_listing, "yes") != 0) {
9905 mg_printf(nc, "%s", "HTTP/1.1 403 Directory Listing Denied\r\n\r\n");
9906 } else {
9907 char uri[MG_MAX_PATH];
9908 mg_send(nc, header, sizeof(header) - 1);
9909 snprintf(uri, sizeof(uri), "%.*s", (int) hm->uri.len, hm->uri.p);
9910 mg_print_props(nc, uri, stp);
9911 if (S_ISDIR(stp->st_mode) && (depth == NULL || mg_vcmp(depth, "0") != 0)) {
9913 }
9914 mg_send(nc, footer, sizeof(footer) - 1);
9916 }
9917}
9918
9919#if MG_ENABLE_FAKE_DAVLOCK
9920/*
9921 * Windows explorer (probably there are another WebDav clients like it)
9922 * requires LOCK support in webdav. W/out this, it still works, but fails
9923 * to save file: shows error message and offers "Save As".
9924 * "Save as" works, but this message is very annoying.
9925 * This is fake lock, which doesn't lock something, just returns LOCK token,
9926 * UNLOCK always answers "OK".
9927 * With this fake LOCK Windows Explorer looks happy and saves file.
9928 * NOTE: that is not DAV LOCK imlementation, it is just a way to shut up
9929 * Windows native DAV client. This is why FAKE LOCK is not enabed by default
9930 */
9931MG_INTERNAL void mg_handle_lock(struct mg_connection *nc, const char *path) {
9932 static const char *reply =
9933 "HTTP/1.1 207 Multi-Status\r\n"
9934 "Connection: close\r\n"
9935 "Content-Type: text/xml; charset=utf-8\r\n\r\n"
9936 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
9937 "<d:multistatus xmlns:d='DAV:'>\n"
9938 "<D:lockdiscovery>\n"
9939 "<D:activelock>\n"
9940 "<D:locktoken>\n"
9941 "<D:href>\n"
9942 "opaquelocktoken:%s%u"
9943 "</D:href>"
9944 "</D:locktoken>"
9945 "</D:activelock>\n"
9946 "</D:lockdiscovery>"
9947 "</d:multistatus>\n";
9948 mg_printf(nc, reply, path, (unsigned int) mg_time());
9950}
9951#endif
9952
9953MG_INTERNAL void mg_handle_mkcol(struct mg_connection *nc, const char *path,
9954 struct http_message *hm) {
9955 int status_code = 500;
9956 if (hm->body.len != (size_t) ~0 && hm->body.len > 0) {
9957 status_code = 415;
9958 } else if (!mg_mkdir(path, 0755)) {
9959 status_code = 201;
9960 } else if (errno == EEXIST) {
9961 status_code = 405;
9962 } else if (errno == EACCES) {
9963 status_code = 403;
9964 } else if (errno == ENOENT) {
9965 status_code = 409;
9966 } else {
9967 status_code = 500;
9968 }
9969 mg_http_send_error(nc, status_code, NULL);
9970}
9971
9972static int mg_remove_directory(const struct mg_serve_http_opts *opts,
9973 const char *dir) {
9974 char path[MG_MAX_PATH];
9975 struct dirent *dp;
9976 cs_stat_t st;
9977 DIR *dirp;
9978
9979 if ((dirp = opendir(dir)) == NULL) return 0;
9980
9981 while ((dp = readdir(dirp)) != NULL) {
9982 if (mg_is_file_hidden((const char *) dp->d_name, opts, 1)) {
9983 continue;
9984 }
9985 snprintf(path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
9986 mg_stat(path, &st);
9987 if (S_ISDIR(st.st_mode)) {
9989 } else {
9990 remove(path);
9991 }
9992 }
9993 closedir(dirp);
9994 rmdir(dir);
9995
9996 return 1;
9997}
9998
10000 const struct mg_serve_http_opts *opts,
10001 const char *path, struct http_message *hm) {
10002 const struct mg_str *dest = mg_get_http_header(hm, "Destination");
10003 if (dest == NULL) {
10004 mg_http_send_error(c, 411, NULL);
10005 } else {
10006 const char *p = (char *) memchr(dest->p, '/', dest->len);
10007 if (p != NULL && p[1] == '/' &&
10008 (p = (char *) memchr(p + 2, '/', dest->p + dest->len - p)) != NULL) {
10009 char buf[MG_MAX_PATH];
10010 snprintf(buf, sizeof(buf), "%s%.*s", opts->dav_document_root,
10011 (int) (dest->p + dest->len - p), p);
10012 if (rename(path, buf) == 0) {
10013 mg_http_send_error(c, 200, NULL);
10014 } else {
10015 mg_http_send_error(c, 418, NULL);
10016 }
10017 } else {
10018 mg_http_send_error(c, 500, NULL);
10019 }
10020 }
10021}
10022
10024 const struct mg_serve_http_opts *opts,
10025 const char *path) {
10026 cs_stat_t st;
10027 if (mg_stat(path, &st) != 0) {
10028 mg_http_send_error(nc, 404, NULL);
10029 } else if (S_ISDIR(st.st_mode)) {
10031 mg_http_send_error(nc, 204, NULL);
10032 } else if (remove(path) == 0) {
10033 mg_http_send_error(nc, 204, NULL);
10034 } else {
10035 mg_http_send_error(nc, 423, NULL);
10036 }
10037}
10038
10039/* Return -1 on error, 1 on success. */
10040static int mg_create_itermediate_directories(const char *path) {
10041 const char *s;
10042
10043 /* Create intermediate directories if they do not exist */
10044 for (s = path + 1; *s != '\0'; s++) {
10045 if (*s == '/') {
10046 char buf[MG_MAX_PATH];
10047 cs_stat_t st;
10048 snprintf(buf, sizeof(buf), "%.*s", (int) (s - path), path);
10049 buf[sizeof(buf) - 1] = '\0';
10050 if (mg_stat(buf, &st) != 0 && mg_mkdir(buf, 0755) != 0) {
10051 return -1;
10052 }
10053 }
10054 }
10055
10056 return 1;
10057}
10058
10059MG_INTERNAL void mg_handle_put(struct mg_connection *nc, const char *path,
10060 struct http_message *hm) {
10062 cs_stat_t st;
10063 const struct mg_str *cl_hdr = mg_get_http_header(hm, "Content-Length");
10064 int rc, status_code = mg_stat(path, &st) == 0 ? 200 : 201;
10065
10067 if ((rc = mg_create_itermediate_directories(path)) == 0) {
10068 mg_printf(nc, "HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n", status_code);
10069 } else if (rc == -1) {
10070 mg_http_send_error(nc, 500, NULL);
10071 } else if (cl_hdr == NULL) {
10072 mg_http_send_error(nc, 411, NULL);
10073 } else if ((pd->file.fp = mg_fopen(path, "w+b")) == NULL) {
10074 mg_http_send_error(nc, 500, NULL);
10075 } else {
10076 const struct mg_str *range_hdr = mg_get_http_header(hm, "Content-Range");
10077 int64_t r1 = 0, r2 = 0;
10078 pd->file.type = DATA_PUT;
10079 mg_set_close_on_exec((sock_t) fileno(pd->file.fp));
10080 pd->file.cl = to64(cl_hdr->p);
10081 if (range_hdr != NULL &&
10083 status_code = 206;
10084 fseeko(pd->file.fp, r1, SEEK_SET);
10085 pd->file.cl = r2 > r1 ? r2 - r1 + 1 : pd->file.cl - r1;
10086 }
10087 mg_printf(nc, "HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n", status_code);
10088 /* Remove HTTP request from the mbuf, leave only payload */
10089 mbuf_remove(&nc->recv_mbuf, hm->message.len - hm->body.len);
10091 }
10092}
10093
10094#endif /* MG_ENABLE_HTTP && MG_ENABLE_HTTP_WEBDAV */
10095#ifdef MG_MODULE_LINES
10096#line 1 "mongoose/src/mg_http_websocket.c"
10097#endif
10098/*
10099 * Copyright (c) 2014 Cesanta Software Limited
10100 * All rights reserved
10101 */
10102
10103#if MG_ENABLE_HTTP && MG_ENABLE_HTTP_WEBSOCKET
10104
10105/* Amalgamated: #include "common/cs_sha1.h" */
10106
10107#ifndef MG_WEBSOCKET_PING_INTERVAL_SECONDS
10108#define MG_WEBSOCKET_PING_INTERVAL_SECONDS 5
10109#endif
10110
10111#define FLAGS_MASK_FIN (1 << 7)
10112#define FLAGS_MASK_OP 0x0f
10113
10114static int mg_is_ws_fragment(unsigned char flags) {
10115 return (flags & FLAGS_MASK_FIN) == 0 ||
10117}
10118
10119static int mg_is_ws_first_fragment(unsigned char flags) {
10120 return (flags & FLAGS_MASK_FIN) == 0 &&
10122}
10123
10124static int mg_is_ws_control_frame(unsigned char flags) {
10125 unsigned char op = (flags & FLAGS_MASK_OP);
10126 return op == WEBSOCKET_OP_CLOSE || op == WEBSOCKET_OP_PING ||
10128}
10129
10131 struct websocket_message *wsm) {
10132 if (wsm->flags & 0x8) {
10134 } else {
10136 }
10137}
10138
10139static struct mg_ws_proto_data *mg_ws_get_proto_data(struct mg_connection *nc) {
10141 return (htd != NULL ? &htd->ws_data : NULL);
10142}
10143
10144/*
10145 * Sends a Close websocket frame with the given data, and closes the underlying
10146 * connection. If `len` is ~0, strlen(data) is used.
10147 */
10148static void mg_ws_close(struct mg_connection *nc, const void *data,
10149 size_t len) {
10150 if ((int) len == ~0) {
10151 len = strlen((const char *) data);
10152 }
10155}
10156
10157static int mg_deliver_websocket_data(struct mg_connection *nc) {
10158 /* Using unsigned char *, cause of integer arithmetic below */
10159 uint64_t i, data_len = 0, frame_len = 0, new_data_len = nc->recv_mbuf.len,
10160 len, mask_len = 0, header_len = 0;
10162 unsigned char *new_data = (unsigned char *) nc->recv_mbuf.buf,
10163 *e = (unsigned char *) nc->recv_mbuf.buf + nc->recv_mbuf.len;
10164 uint8_t flags;
10165 int ok, reass;
10166
10167 if (wsd->reass_len > 0) {
10168 /*
10169 * We already have some previously received data which we need to
10170 * reassemble and deliver to the client code when we get the final
10171 * fragment.
10172 *
10173 * NOTE: it doesn't mean that the current message must be a continuation:
10174 * it might be a control frame (Close, Ping or Pong), which should be
10175 * handled without breaking the fragmented message.
10176 */
10177
10178 size_t existing_len = wsd->reass_len;
10179 assert(new_data_len >= existing_len);
10180
10183 }
10184
10185 flags = new_data[0];
10186
10187 reass = new_data_len > 0 && mg_is_ws_fragment(flags) &&
10189
10190 if (reass && mg_is_ws_control_frame(flags)) {
10191 /*
10192 * Control frames can't be fragmented, so if we encounter fragmented
10193 * control frame, close connection immediately.
10194 */
10195 mg_ws_close(nc, "fragmented control frames are illegal", ~0);
10196 return 0;
10197 } else if (new_data_len > 0 && !reass && !mg_is_ws_control_frame(flags) &&
10198 wsd->reass_len > 0) {
10199 /*
10200 * When in the middle of a fragmented message, only the continuations
10201 * and control frames are allowed.
10202 */
10203 mg_ws_close(nc, "non-continuation in the middle of a fragmented message",
10204 ~0);
10205 return 0;
10206 }
10207
10208 if (new_data_len >= 2) {
10209 len = new_data[1] & 0x7f;
10210 mask_len = new_data[1] & FLAGS_MASK_FIN ? 4 : 0;
10212 data_len = len;
10213 header_len = 2 + mask_len;
10214 } else if (len == 126 && new_data_len >= 4 + mask_len) {
10215 header_len = 4 + mask_len;
10216 data_len = ntohs(*(uint16_t *) &new_data[2]);
10217 } else if (new_data_len >= 10 + mask_len) {
10218 header_len = 10 + mask_len;
10219 data_len = (((uint64_t) ntohl(*(uint32_t *) &new_data[2])) << 32) +
10220 ntohl(*(uint32_t *) &new_data[6]);
10221 }
10222 }
10223
10224 frame_len = header_len + data_len;
10225 ok = (frame_len > 0 && frame_len <= new_data_len);
10226
10227 /* Check for overflow */
10228 if (frame_len < header_len || frame_len < data_len) {
10229 ok = 0;
10230 mg_ws_close(nc, "overflowed message", ~0);
10231 }
10232
10233 if (ok) {
10234 size_t cleanup_len = 0;
10235 struct websocket_message wsm;
10236
10237 wsm.size = (size_t) data_len;
10238 wsm.data = new_data + header_len;
10239 wsm.flags = flags;
10240
10241 /* Apply mask if necessary */
10242 if (mask_len > 0) {
10243 for (i = 0; i < data_len; i++) {
10245 }
10246 }
10247
10248 if (reass) {
10249 /* This is a message fragment */
10250
10252 /*
10253 * On the first fragmented frame, skip the first byte (op) and also
10254 * reset size to 1 (op), it'll be incremented with the data len below.
10255 */
10256 new_data += 1;
10257 wsd->reass_len = 1 /* op */;
10258 }
10259
10260 /* Append this frame to the reassembled buffer */
10261 memmove(new_data, wsm.data, e - wsm.data);
10262 wsd->reass_len += wsm.size;
10263 nc->recv_mbuf.len -= wsm.data - new_data;
10264
10265 if (flags & FLAGS_MASK_FIN) {
10266 /* On last fragmented frame - call user handler and remove data */
10267 wsm.flags = FLAGS_MASK_FIN | nc->recv_mbuf.buf[0];
10268 wsm.data = (unsigned char *) nc->recv_mbuf.buf + 1 /* op */;
10269 wsm.size = wsd->reass_len - 1 /* op */;
10270 cleanup_len = wsd->reass_len;
10271 wsd->reass_len = 0;
10272
10273 /* Pass reassembled message to the client code. */
10275 mbuf_remove(&nc->recv_mbuf, cleanup_len); /* Cleanup frame */
10276 }
10277 } else {
10278 /*
10279 * This is a complete message, not a fragment. It might happen in between
10280 * of a fragmented message (in this case, WebSocket protocol requires
10281 * current message to be a control frame).
10282 */
10284
10285 /* First of all, check if we need to react on a control frame. */
10286 switch (flags & FLAGS_MASK_OP) {
10287 case WEBSOCKET_OP_PING:
10289 break;
10290
10291 case WEBSOCKET_OP_CLOSE:
10292 mg_ws_close(nc, wsm.data, wsm.size);
10293 break;
10294 }
10295
10296 /* Pass received message to the client code. */
10298
10299 /* Cleanup frame */
10300 memmove(nc->recv_mbuf.buf + wsd->reass_len,
10301 nc->recv_mbuf.buf + wsd->reass_len + cleanup_len,
10302 nc->recv_mbuf.len - wsd->reass_len - cleanup_len);
10303 nc->recv_mbuf.len -= cleanup_len;
10304 }
10305 }
10306
10307 return ok;
10308}
10309
10310struct ws_mask_ctx {
10311 size_t pos; /* zero means unmasked */
10312 uint32_t mask;
10313};
10314
10315static uint32_t mg_ws_random_mask(void) {
10316 uint32_t mask;
10317/*
10318 * The spec requires WS client to generate hard to
10319 * guess mask keys. From RFC6455, Section 5.3:
10320 *
10321 * The unpredictability of the masking key is essential to prevent
10322 * authors of malicious applications from selecting the bytes that appear on
10323 * the wire.
10324 *
10325 * Hence this feature is essential when the actual end user of this API
10326 * is untrusted code that wouldn't have access to a lower level net API
10327 * anyway (e.g. web browsers). Hence this feature is low prio for most
10328 * mongoose use cases and thus can be disabled, e.g. when porting to a platform
10329 * that lacks rand().
10330 */
10331#if MG_DISABLE_WS_RANDOM_MASK
10332 mask = 0xefbeadde; /* generated with a random number generator, I swear */
10333#else
10334 if (sizeof(long) >= 4) {
10335 mask = (uint32_t) rand();
10336 } else if (sizeof(long) == 2) {
10337 mask = (uint32_t) rand() << 16 | (uint32_t) rand();
10338 }
10339#endif
10340 return mask;
10341}
10342
10343static void mg_send_ws_header(struct mg_connection *nc, int op, size_t len,
10344 struct ws_mask_ctx *ctx) {
10345 int header_len;
10346 unsigned char header[10];
10347
10348 header[0] =
10350 if (len < 126) {
10351 header[1] = (unsigned char) len;
10352 header_len = 2;
10353 } else if (len < 65535) {
10354 uint16_t tmp = htons((uint16_t) len);
10355 header[1] = 126;
10356 memcpy(&header[2], &tmp, sizeof(tmp));
10357 header_len = 4;
10358 } else {
10359 uint32_t tmp;
10360 header[1] = 127;
10361 tmp = htonl((uint32_t)((uint64_t) len >> 32));
10362 memcpy(&header[2], &tmp, sizeof(tmp));
10363 tmp = htonl((uint32_t)(len & 0xffffffff));
10364 memcpy(&header[6], &tmp, sizeof(tmp));
10365 header_len = 10;
10366 }
10367
10368 /* client connections enable masking */
10369 if (nc->listener == NULL) {
10370 header[1] |= 1 << 7; /* set masking flag */
10371 mg_send(nc, header, header_len);
10372 ctx->mask = mg_ws_random_mask();
10373 mg_send(nc, &ctx->mask, sizeof(ctx->mask));
10374 ctx->pos = nc->send_mbuf.len;
10375 } else {
10376 mg_send(nc, header, header_len);
10377 ctx->pos = 0;
10378 }
10379}
10380
10381static void mg_ws_mask_frame(struct mbuf *mbuf, struct ws_mask_ctx *ctx) {
10382 size_t i;
10383 if (ctx->pos == 0) return;
10384 for (i = 0; i < (mbuf->len - ctx->pos); i++) {
10385 mbuf->buf[ctx->pos + i] ^= ((char *) &ctx->mask)[i % 4];
10386 }
10387}
10388
10389void mg_send_websocket_frame(struct mg_connection *nc, int op, const void *data,
10390 size_t len) {
10391 struct ws_mask_ctx ctx;
10392 DBG(("%p %d %d", nc, op, (int) len));
10393 mg_send_ws_header(nc, op, len, &ctx);
10394 mg_send(nc, data, len);
10395
10396 mg_ws_mask_frame(&nc->send_mbuf, &ctx);
10397
10398 if (op == WEBSOCKET_OP_CLOSE) {
10400 }
10401}
10402
10403void mg_send_websocket_framev(struct mg_connection *nc, int op,
10404 const struct mg_str *strv, int strvcnt) {
10405 struct ws_mask_ctx ctx;
10406 int i;
10407 int len = 0;
10408 for (i = 0; i < strvcnt; i++) {
10409 len += strv[i].len;
10410 }
10411
10412 mg_send_ws_header(nc, op, len, &ctx);
10413
10414 for (i = 0; i < strvcnt; i++) {
10415 mg_send(nc, strv[i].p, strv[i].len);
10416 }
10417
10418 mg_ws_mask_frame(&nc->send_mbuf, &ctx);
10419
10420 if (op == WEBSOCKET_OP_CLOSE) {
10422 }
10423}
10424
10425void mg_printf_websocket_frame(struct mg_connection *nc, int op,
10426 const char *fmt, ...) {
10427 char mem[MG_VPRINTF_BUFFER_SIZE], *buf = mem;
10428 va_list ap;
10429 int len;
10430
10431 va_start(ap, fmt);
10432 if ((len = mg_avprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
10433 mg_send_websocket_frame(nc, op, buf, len);
10434 }
10435 va_end(ap);
10436
10437 if (buf != mem && buf != NULL) {
10438 MG_FREE(buf);
10439 }
10440}
10441
10442MG_INTERNAL void mg_ws_handler(struct mg_connection *nc, int ev,
10443 void *ev_data MG_UD_ARG(void *user_data)) {
10444 mg_call(nc, nc->handler, nc->user_data, ev, ev_data);
10445
10446 switch (ev) {
10447 case MG_EV_RECV:
10448 do {
10449 } while (mg_deliver_websocket_data(nc));
10450 break;
10451 case MG_EV_POLL:
10452 /* Ping idle websocket connections */
10453 {
10454 time_t now = *(time_t *) ev_data;
10455 if (nc->flags & MG_F_IS_WEBSOCKET &&
10458 }
10459 }
10460 break;
10461 default:
10462 break;
10463 }
10464#if MG_ENABLE_CALLBACK_USERDATA
10465 (void) user_data;
10466#endif
10467}
10468
10469#ifndef MG_EXT_SHA1
10470void mg_hash_sha1_v(size_t num_msgs, const uint8_t *msgs[],
10471 const size_t *msg_lens, uint8_t *digest) {
10472 size_t i;
10475 for (i = 0; i < num_msgs; i++) {
10477 }
10479}
10480#else
10481extern void mg_hash_sha1_v(size_t num_msgs, const uint8_t *msgs[],
10482 const size_t *msg_lens, uint8_t *digest);
10483#endif
10484
10486 const struct mg_str *key,
10487 struct http_message *hm) {
10488 static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
10489 const uint8_t *msgs[2] = {(const uint8_t *) key->p, (const uint8_t *) magic};
10490 const size_t msg_lens[2] = {key->len, 36};
10491 unsigned char sha[20];
10492 char b64_sha[30];
10493 struct mg_str *s;
10494
10496 mg_base64_encode(sha, sizeof(sha), b64_sha);
10497 mg_printf(nc, "%s",
10498 "HTTP/1.1 101 Switching Protocols\r\n"
10499 "Upgrade: websocket\r\n"
10500 "Connection: Upgrade\r\n");
10501
10502 s = mg_get_http_header(hm, "Sec-WebSocket-Protocol");
10503 if (s != NULL) {
10504 mg_printf(nc, "Sec-WebSocket-Protocol: %.*s\r\n", (int) s->len, s->p);
10505 }
10506 mg_printf(nc, "Sec-WebSocket-Accept: %s%s", b64_sha, "\r\n\r\n");
10507
10508 DBG(("%p %.*s %s", nc, (int) key->len, key->p, b64_sha));
10509}
10510
10511void mg_send_websocket_handshake2(struct mg_connection *nc, const char *path,
10512 const char *host, const char *protocol,
10513 const char *extra_headers) {
10514 mg_send_websocket_handshake3(nc, path, host, protocol, extra_headers, NULL,
10515 NULL);
10516}
10517
10518void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path,
10519 const char *host, const char *protocol,
10520 const char *extra_headers, const char *user,
10521 const char *pass) {
10523 mg_mk_str(protocol), mg_mk_str(extra_headers),
10524 mg_mk_str(user), mg_mk_str(pass));
10525}
10526
10528 const struct mg_str path,
10529 const struct mg_str host,
10530 const struct mg_str protocol,
10531 const struct mg_str extra_headers,
10532 const struct mg_str user,
10533 const struct mg_str pass) {
10534 struct mbuf auth;
10535 char key[25];
10536 uint32_t nonce[4];
10537 nonce[0] = mg_ws_random_mask();
10538 nonce[1] = mg_ws_random_mask();
10539 nonce[2] = mg_ws_random_mask();
10540 nonce[3] = mg_ws_random_mask();
10541 mg_base64_encode((unsigned char *) &nonce, sizeof(nonce), key);
10542
10543 mbuf_init(&auth, 0);
10544 if (user.len > 0) {
10546 }
10547
10548 /*
10549 * NOTE: the (auth.buf == NULL ? "" : auth.buf) is because cc3200 libc is
10550 * broken: it doesn't like zero length to be passed to %.*s
10551 * i.e. sprintf("f%.*so", (int)0, NULL), yields `f\0o`.
10552 * because it handles NULL specially (and incorrectly).
10553 */
10554 mg_printf(nc,
10555 "GET %.*s HTTP/1.1\r\n"
10556 "Upgrade: websocket\r\n"
10557 "Connection: Upgrade\r\n"
10558 "%.*s"
10559 "Sec-WebSocket-Version: 13\r\n"
10560 "Sec-WebSocket-Key: %s\r\n",
10561 (int) path.len, path.p, (int) auth.len,
10562 (auth.buf == NULL ? "" : auth.buf), key);
10563
10564 /* TODO(mkm): take default hostname from http proto data if host == NULL */
10565 if (host.len > 0) {
10566 int host_len = (int) (path.p - host.p); /* Account for possible :PORT */
10567 mg_printf(nc, "Host: %.*s\r\n", host_len, host.p);
10568 }
10569 if (protocol.len > 0) {
10570 mg_printf(nc, "Sec-WebSocket-Protocol: %.*s\r\n", (int) protocol.len,
10571 protocol.p);
10572 }
10573 if (extra_headers.len > 0) {
10574 mg_printf(nc, "%.*s", (int) extra_headers.len, extra_headers.p);
10575 }
10576 mg_printf(nc, "\r\n");
10577
10578 nc->flags |= MG_F_IS_WEBSOCKET;
10579
10580 mbuf_free(&auth);
10581}
10582
10583void mg_send_websocket_handshake(struct mg_connection *nc, const char *path,
10584 const char *extra_headers) {
10585 struct mg_str null_str = MG_NULL_STR;
10587 nc, mg_mk_str(path), null_str /* host */, null_str /* protocol */,
10588 mg_mk_str(extra_headers), null_str /* user */, null_str /* pass */);
10589}
10590
10593 struct mg_connect_opts opts, const char *url, const char *protocol,
10594 const char *extra_headers) {
10595 struct mg_str null_str = MG_NULL_STR;
10596 struct mg_str host = MG_NULL_STR, path = MG_NULL_STR, user_info = MG_NULL_STR;
10597 struct mg_connection *nc =
10599 "ws", "https", "wss", url, &path, &user_info, &host);
10600 if (nc != NULL) {
10602 mg_mk_str(extra_headers), user_info,
10603 null_str);
10604 }
10605 return nc;
10606}
10607
10610 const char *url, const char *protocol, const char *extra_headers) {
10611 struct mg_connect_opts opts;
10612 memset(&opts, 0, sizeof(opts));
10614 protocol, extra_headers);
10615}
10616#endif /* MG_ENABLE_HTTP && MG_ENABLE_HTTP_WEBSOCKET */
10617#ifdef MG_MODULE_LINES
10618#line 1 "mongoose/src/mg_util.c"
10619#endif
10620/*
10621 * Copyright (c) 2014 Cesanta Software Limited
10622 * All rights reserved
10623 */
10624
10625/* Amalgamated: #include "common/cs_base64.h" */
10626/* Amalgamated: #include "mg_internal.h" */
10627/* Amalgamated: #include "mg_util.h" */
10628
10629/* For platforms with limited libc */
10630#ifndef MAX
10631#define MAX(a, b) ((a) > (b) ? (a) : (b))
10632#endif
10633
10634const char *mg_skip(const char *s, const char *end, const char *delims,
10635 struct mg_str *v) {
10636 v->p = s;
10637 while (s < end && strchr(delims, *(unsigned char *) s) == NULL) s++;
10638 v->len = s - v->p;
10639 while (s < end && strchr(delims, *(unsigned char *) s) != NULL) s++;
10640 return s;
10641}
10642
10643#if MG_ENABLE_FILESYSTEM && !defined(MG_USER_FILE_FUNCTIONS)
10644int mg_stat(const char *path, cs_stat_t *st) {
10645#ifdef _WIN32
10646 wchar_t wpath[MG_MAX_PATH];
10647 to_wchar(path, wpath, ARRAY_SIZE(wpath));
10648 DBG(("[%ls] -> %d", wpath, _wstati64(wpath, st)));
10649 return _wstati64(wpath, st);
10650#else
10651 return stat(path, st);
10652#endif
10653}
10654
10655FILE *mg_fopen(const char *path, const char *mode) {
10656#ifdef _WIN32
10657 wchar_t wpath[MG_MAX_PATH], wmode[10];
10658 to_wchar(path, wpath, ARRAY_SIZE(wpath));
10660 return _wfopen(wpath, wmode);
10661#else
10662 return fopen(path, mode);
10663#endif
10664}
10665
10666int mg_open(const char *path, int flag, int mode) { /* LCOV_EXCL_LINE */
10667#if defined(_WIN32) && !defined(WINCE)
10668 wchar_t wpath[MG_MAX_PATH];
10669 to_wchar(path, wpath, ARRAY_SIZE(wpath));
10670 return _wopen(wpath, flag, mode);
10671#else
10672 return open(path, flag, mode); /* LCOV_EXCL_LINE */
10673#endif
10674}
10675
10676size_t mg_fread(void *ptr, size_t size, size_t count, FILE *f) {
10677 return fread(ptr, size, count, f);
10678}
10679
10680size_t mg_fwrite(const void *ptr, size_t size, size_t count, FILE *f) {
10681 return fwrite(ptr, size, count, f);
10682}
10683#endif
10684
10685void mg_base64_encode(const unsigned char *src, int src_len, char *dst) {
10686 cs_base64_encode(src, src_len, dst);
10687}
10688
10689int mg_base64_decode(const unsigned char *s, int len, char *dst) {
10690 return cs_base64_decode(s, len, dst, NULL);
10691}
10692
10693#if MG_ENABLE_THREADS
10694void *mg_start_thread(void *(*f)(void *), void *p) {
10695#ifdef WINCE
10696 return (void *) CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) f, p, 0, NULL);
10697#elif defined(_WIN32)
10698 return (void *) _beginthread((void(__cdecl *) (void *) ) f, 0, p);
10699#else
10700 pthread_t thread_id = (pthread_t) 0;
10702
10705
10706#if defined(MG_STACK_SIZE) && MG_STACK_SIZE > 1
10708#endif
10709
10710 pthread_create(&thread_id, &attr, f, p);
10712
10713 return (void *) thread_id;
10714#endif
10715}
10716#endif /* MG_ENABLE_THREADS */
10717
10718/* Set close-on-exec bit for a given socket. */
10719void mg_set_close_on_exec(sock_t sock) {
10720#if defined(_WIN32) && !defined(WINCE)
10722#elif defined(__unix__)
10723 fcntl(sock, F_SETFD, FD_CLOEXEC);
10724#else
10725 (void) sock;
10726#endif
10727}
10728
10729int mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len,
10730 int flags) {
10731 int is_v6;
10732 if (buf == NULL || len <= 0) return 0;
10733 memset(buf, 0, len);
10734#if MG_ENABLE_IPV6
10735 is_v6 = sa->sa.sa_family == AF_INET6;
10736#else
10737 is_v6 = 0;
10738#endif
10740#if MG_ENABLE_IPV6
10741 const void *addr = NULL;
10742 char *start = buf;
10743 socklen_t capacity = len;
10744 if (!is_v6) {
10745 addr = &sa->sin.sin_addr;
10746 } else {
10747 addr = (void *) &sa->sin6.sin6_addr;
10749 *buf = '[';
10750 start++;
10751 capacity--;
10752 }
10753 }
10754 if (inet_ntop(sa->sa.sa_family, addr, start, capacity) == NULL) {
10755 goto cleanup;
10756 }
10757#elif defined(_WIN32) || MG_LWIP || (MG_NET_IF == MG_NET_IF_PIC32)
10758 /* Only Windoze Vista (and newer) have inet_ntop() */
10759 char *addr_str = inet_ntoa(sa->sin.sin_addr);
10760 if (addr_str != NULL) {
10761 strncpy(buf, inet_ntoa(sa->sin.sin_addr), len - 1);
10762 } else {
10763 goto cleanup;
10764 }
10765#else
10766 if (inet_ntop(AF_INET, (void *) &sa->sin.sin_addr, buf, len) == NULL) {
10767 goto cleanup;
10768 }
10769#endif
10770 }
10772 int port = ntohs(sa->sin.sin_port);
10774 int buf_len = strlen(buf);
10775 snprintf(buf + buf_len, len - (buf_len + 1), "%s:%d", (is_v6 ? "]" : ""),
10776 port);
10777 } else {
10778 snprintf(buf, len, "%d", port);
10779 }
10780 }
10781
10782 return strlen(buf);
10783
10784cleanup:
10785 *buf = '\0';
10786 return 0;
10787}
10788
10789int mg_conn_addr_to_str(struct mg_connection *nc, char *buf, size_t len,
10790 int flags) {
10791 union socket_address sa;
10792 memset(&sa, 0, sizeof(sa));
10794 return mg_sock_addr_to_str(&sa, buf, len, flags);
10795}
10796
10797#if MG_ENABLE_HEXDUMP
10798static int mg_hexdump_n(const void *buf, int len, char *dst, int dst_len,
10799 int offset) {
10800 const unsigned char *p = (const unsigned char *) buf;
10801 char ascii[17] = "";
10802 int i, idx, n = 0;
10803
10804 for (i = 0; i < len; i++) {
10805 idx = i % 16;
10806 if (idx == 0) {
10807 if (i > 0) n += snprintf(dst + n, MAX(dst_len - n, 0), " %s\n", ascii);
10808 n += snprintf(dst + n, MAX(dst_len - n, 0), "%04x ", i + offset);
10809 }
10810 if (dst_len - n < 0) {
10811 return n;
10812 }
10813 n += snprintf(dst + n, MAX(dst_len - n, 0), " %02x", p[i]);
10814 ascii[idx] = p[i] < 0x20 || p[i] > 0x7e ? '.' : p[i];
10815 ascii[idx + 1] = '\0';
10816 }
10817
10818 while (i++ % 16) n += snprintf(dst + n, MAX(dst_len - n, 0), "%s", " ");
10819 n += snprintf(dst + n, MAX(dst_len - n, 0), " %s\n", ascii);
10820
10821 return n;
10822}
10823
10824int mg_hexdump(const void *buf, int len, char *dst, int dst_len) {
10825 return mg_hexdump_n(buf, len, dst, dst_len, 0);
10826}
10827
10828void mg_hexdumpf(FILE *fp, const void *buf, int len) {
10829 char tmp[80];
10830 int offset = 0, n;
10831 while (len > 0) {
10832 n = (len < 16 ? len : 16);
10833 mg_hexdump_n(((const char *) buf) + offset, n, tmp, sizeof(tmp), offset);
10834 fputs(tmp, fp);
10835 offset += n;
10836 len -= n;
10837 }
10838}
10839
10840void mg_hexdump_connection(struct mg_connection *nc, const char *path,
10841 const void *buf, int num_bytes, int ev) {
10842 FILE *fp = NULL;
10843 char src[60], dst[60];
10844 const char *tag = NULL;
10845 switch (ev) {
10846 case MG_EV_RECV:
10847 tag = "<-";
10848 break;
10849 case MG_EV_SEND:
10850 tag = "->";
10851 break;
10852 case MG_EV_ACCEPT:
10853 tag = "<A";
10854 break;
10855 case MG_EV_CONNECT:
10856 tag = "C>";
10857 break;
10858 case MG_EV_CLOSE:
10859 tag = "XX";
10860 break;
10861 }
10862 if (tag == NULL) return; /* Don't log MG_EV_TIMER, etc */
10863
10864 if (strcmp(path, "-") == 0) {
10865 fp = stdout;
10866 } else if (strcmp(path, "--") == 0) {
10867 fp = stderr;
10868#if MG_ENABLE_FILESYSTEM
10869 } else {
10870 fp = mg_fopen(path, "a");
10871#endif
10872 }
10873 if (fp == NULL) return;
10874
10875 mg_conn_addr_to_str(nc, src, sizeof(src),
10877 mg_conn_addr_to_str(nc, dst, sizeof(dst), MG_SOCK_STRINGIFY_IP |
10880 fprintf(fp, "%lu %p %s %s %s %d\n", (unsigned long) mg_time(), (void *) nc,
10881 src, tag, dst, (int) num_bytes);
10882 if (num_bytes > 0) {
10883 mg_hexdumpf(fp, buf, num_bytes);
10884 }
10885 if (fp != stdout && fp != stderr) fclose(fp);
10886}
10887#endif
10888
10889int mg_is_big_endian(void) {
10890 static const int n = 1;
10891 /* TODO(mkm) use compiletime check with 4-byte char literal */
10892 return ((char *) &n)[0] == 0;
10893}
10894
10896#ifndef WINCE
10897 return errno;
10898#else
10899 /* TODO(alashkin): translate error codes? */
10900 return GetLastError();
10901#endif
10902}
10903
10904void mg_mbuf_append_base64_putc(char ch, void *user_data) {
10905 struct mbuf *mbuf = (struct mbuf *) user_data;
10906 mbuf_append(mbuf, &ch, sizeof(ch));
10907}
10908
10909void mg_mbuf_append_base64(struct mbuf *mbuf, const void *data, size_t len) {
10910 struct cs_base64_ctx ctx;
10912 cs_base64_update(&ctx, (const char *) data, len);
10913 cs_base64_finish(&ctx);
10914}
10915
10916void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass,
10917 struct mbuf *buf) {
10918 const char *header_prefix = "Authorization: Basic ";
10919 const char *header_suffix = "\r\n";
10920
10921 struct cs_base64_ctx ctx;
10923
10925
10926 cs_base64_update(&ctx, user.p, user.len);
10927 if (pass.len > 0) {
10928 cs_base64_update(&ctx, ":", 1);
10929 cs_base64_update(&ctx, pass.p, pass.len);
10930 }
10931 cs_base64_finish(&ctx);
10933}
10934
10937 const char *hex =
10938 (flags & MG_URL_ENCODE_F_UPPERCASE_HEX ? "0123456789ABCDEF"
10939 : "0123456789abcdef");
10940 size_t i = 0;
10941 struct mbuf mb;
10942 mbuf_init(&mb, src.len);
10943
10944 for (i = 0; i < src.len; i++) {
10945 const unsigned char c = *((const unsigned char *) src.p + i);
10946 if (isalnum(c) || mg_strchr(safe, c) != NULL) {
10947 mbuf_append(&mb, &c, 1);
10948 } else if (c == ' ' && (flags & MG_URL_ENCODE_F_SPACE_AS_PLUS)) {
10949 mbuf_append(&mb, "+", 1);
10950 } else {
10951 mbuf_append(&mb, "%", 1);
10952 mbuf_append(&mb, &hex[c >> 4], 1);
10953 mbuf_append(&mb, &hex[c & 15], 1);
10954 }
10955 }
10956 mbuf_append(&mb, "", 1);
10957 mbuf_trim(&mb);
10958 return mg_mk_str_n(mb.buf, mb.len - 1);
10959}
10960
10962 return mg_url_encode_opt(src, mg_mk_str("._-$,;~()/"), 0);
10963}
10964#ifdef MG_MODULE_LINES
10965#line 1 "mongoose/src/mg_mqtt.c"
10966#endif
10967/*
10968 * Copyright (c) 2014 Cesanta Software Limited
10969 * All rights reserved
10970 */
10971
10972#if MG_ENABLE_MQTT
10973
10974#include <string.h>
10975
10976/* Amalgamated: #include "mg_internal.h" */
10977/* Amalgamated: #include "mg_mqtt.h" */
10978
10979static uint16_t getu16(const char *p) {
10980 const uint8_t *up = (const uint8_t *) p;
10981 return (up[0] << 8) + up[1];
10982}
10983
10984static const char *scanto(const char *p, struct mg_str *s) {
10985 s->len = getu16(p);
10986 s->p = p + 2;
10987 return s->p + s->len;
10988}
10989
10990MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm) {
10991 uint8_t header;
10992 size_t len = 0, len_len = 0;
10993 const char *p, *end, *eop = &io->buf[io->len];
10994 unsigned char lc = 0;
10995 int cmd;
10996
10997 if (io->len < 2) return MG_MQTT_ERROR_INCOMPLETE_MSG;
10998 header = io->buf[0];
10999 cmd = header >> 4;
11000
11001 /* decode mqtt variable length */
11002 len = len_len = 0;
11003 p = io->buf + 1;
11004 while (p < eop) {
11005 lc = *((const unsigned char *) p++);
11006 len += (lc & 0x7f) << 7 * len_len;
11007 len_len++;
11008 if (!(lc & 0x80)) break;
11009 if (len_len > 4) return MG_MQTT_ERROR_MALFORMED_MSG;
11010 }
11011
11012 end = p + len;
11013 if (lc & 0x80 || end > eop) return MG_MQTT_ERROR_INCOMPLETE_MSG;
11014
11015 mm->cmd = cmd;
11016 mm->qos = MG_MQTT_GET_QOS(header);
11017
11018 switch (cmd) {
11019 case MG_MQTT_CMD_CONNECT: {
11020 p = scanto(p, &mm->protocol_name);
11021 if (p > end - 4) return MG_MQTT_ERROR_MALFORMED_MSG;
11022 mm->protocol_version = *(uint8_t *) p++;
11023 mm->connect_flags = *(uint8_t *) p++;
11024 mm->keep_alive_timer = getu16(p);
11025 p += 2;
11026 if (p >= end) return MG_MQTT_ERROR_MALFORMED_MSG;
11027 p = scanto(p, &mm->client_id);
11028 if (p > end) return MG_MQTT_ERROR_MALFORMED_MSG;
11029 if (mm->connect_flags & MG_MQTT_HAS_WILL) {
11030 if (p >= end) return MG_MQTT_ERROR_MALFORMED_MSG;
11031 p = scanto(p, &mm->will_topic);
11032 }
11033 if (mm->connect_flags & MG_MQTT_HAS_WILL) {
11034 if (p >= end) return MG_MQTT_ERROR_MALFORMED_MSG;
11035 p = scanto(p, &mm->will_message);
11036 }
11037 if (mm->connect_flags & MG_MQTT_HAS_USER_NAME) {
11038 if (p >= end) return MG_MQTT_ERROR_MALFORMED_MSG;
11039 p = scanto(p, &mm->user_name);
11040 }
11041 if (mm->connect_flags & MG_MQTT_HAS_PASSWORD) {
11042 if (p >= end) return MG_MQTT_ERROR_MALFORMED_MSG;
11043 p = scanto(p, &mm->password);
11044 }
11045 if (p != end) return MG_MQTT_ERROR_MALFORMED_MSG;
11046
11047 LOG(LL_DEBUG,
11048 ("%d %2x %d proto [%.*s] client_id [%.*s] will_topic [%.*s] "
11049 "will_msg [%.*s] user_name [%.*s] password [%.*s]",
11050 (int) len, (int) mm->connect_flags, (int) mm->keep_alive_timer,
11051 (int) mm->protocol_name.len, mm->protocol_name.p,
11052 (int) mm->client_id.len, mm->client_id.p, (int) mm->will_topic.len,
11053 mm->will_topic.p, (int) mm->will_message.len, mm->will_message.p,
11054 (int) mm->user_name.len, mm->user_name.p, (int) mm->password.len,
11055 mm->password.p));
11056 break;
11057 }
11059 if (end - p < 2) return MG_MQTT_ERROR_MALFORMED_MSG;
11060 mm->connack_ret_code = p[1];
11061 break;
11062 case MG_MQTT_CMD_PUBACK:
11063 case MG_MQTT_CMD_PUBREC:
11064 case MG_MQTT_CMD_PUBREL:
11066 case MG_MQTT_CMD_SUBACK:
11067 if (end - p < 2) return MG_MQTT_ERROR_MALFORMED_MSG;
11068 mm->message_id = getu16(p);
11069 p += 2;
11070 break;
11071 case MG_MQTT_CMD_PUBLISH: {
11072 p = scanto(p, &mm->topic);
11073 if (p > end) return MG_MQTT_ERROR_MALFORMED_MSG;
11074 if (mm->qos > 0) {
11075 if (end - p < 2) return MG_MQTT_ERROR_MALFORMED_MSG;
11076 mm->message_id = getu16(p);
11077 p += 2;
11078 }
11079 mm->payload.p = p;
11080 mm->payload.len = end - p;
11081 break;
11082 }
11084 if (end - p < 2) return MG_MQTT_ERROR_MALFORMED_MSG;
11085 mm->message_id = getu16(p);
11086 p += 2;
11087 /*
11088 * topic expressions are left in the payload and can be parsed with
11089 * `mg_mqtt_next_subscribe_topic`
11090 */
11091 mm->payload.p = p;
11092 mm->payload.len = end - p;
11093 break;
11094 default:
11095 /* Unhandled command */
11096 break;
11097 }
11098
11099 mm->len = end - io->buf;
11100 return mm->len;
11101}
11102
11103static void mqtt_handler(struct mg_connection *nc, int ev,
11104 void *ev_data MG_UD_ARG(void *user_data)) {
11105 struct mbuf *io = &nc->recv_mbuf;
11106 struct mg_mqtt_message mm;
11107 memset(&mm, 0, sizeof(mm));
11108
11109 nc->handler(nc, ev, ev_data MG_UD_ARG(user_data));
11110
11111 switch (ev) {
11112 case MG_EV_ACCEPT:
11113 if (nc->proto_data == NULL) mg_set_protocol_mqtt(nc);
11114 break;
11115 case MG_EV_RECV: {
11116 /* There can be multiple messages in the buffer, process them all. */
11117 while (1) {
11118 int len = parse_mqtt(io, &mm);
11119 if (len < 0) {
11121 /* Protocol error. */
11123 } else if (len == MG_MQTT_ERROR_INCOMPLETE_MSG) {
11124 /* Not fully buffered, let's check if we have a chance to get more
11125 * data later */
11126 if (nc->recv_mbuf_limit > 0 &&
11127 nc->recv_mbuf.len >= nc->recv_mbuf_limit) {
11128 LOG(LL_ERROR, ("%p recv buffer (%lu bytes) exceeds the limit "
11129 "%lu bytes, and not drained, closing",
11130 nc, (unsigned long) nc->recv_mbuf.len,
11131 (unsigned long) nc->recv_mbuf_limit));
11133 }
11134 } else {
11135 /* Should never be here */
11136 LOG(LL_ERROR, ("%p invalid len: %d, closing", nc, len));
11138 }
11139 break;
11140 }
11141
11142 nc->handler(nc, MG_MQTT_EVENT_BASE + mm.cmd, &mm MG_UD_ARG(user_data));
11143 mbuf_remove(io, len);
11144 }
11145 break;
11146 }
11147 case MG_EV_POLL: {
11148 struct mg_mqtt_proto_data *pd =
11149 (struct mg_mqtt_proto_data *) nc->proto_data;
11150 double now = mg_time();
11151 if (pd->keep_alive > 0 && pd->last_control_time > 0 &&
11152 (now - pd->last_control_time) > pd->keep_alive) {
11153 LOG(LL_DEBUG, ("Send PINGREQ"));
11154 mg_mqtt_ping(nc);
11155 }
11156 break;
11157 }
11158 }
11159}
11160
11161static void mg_mqtt_proto_data_destructor(void *proto_data) {
11162 MG_FREE(proto_data);
11163}
11164
11165static struct mg_str mg_mqtt_next_topic_component(struct mg_str *topic) {
11166 struct mg_str res = *topic;
11167 const char *c = mg_strchr(*topic, '/');
11168 if (c != NULL) {
11169 res.len = (c - topic->p);
11170 topic->len -= (res.len + 1);
11171 topic->p += (res.len + 1);
11172 } else {
11173 topic->len = 0;
11174 }
11175 return res;
11176}
11177
11178/* Refernce: https://mosquitto.org/man/mqtt-7.html */
11179int mg_mqtt_match_topic_expression(struct mg_str exp, struct mg_str topic) {
11180 struct mg_str ec, tc;
11181 if (exp.len == 0) return 0;
11182 while (1) {
11185 if (ec.len == 0) {
11186 if (tc.len != 0) return 0;
11187 if (exp.len == 0) break;
11188 continue;
11189 }
11190 if (mg_vcmp(&ec, "+") == 0) {
11191 if (tc.len == 0 && topic.len == 0) return 0;
11192 continue;
11193 }
11194 if (mg_vcmp(&ec, "#") == 0) {
11195 /* Must be the last component in the expression or it's invalid. */
11196 return (exp.len == 0);
11197 }
11198 if (mg_strcmp(ec, tc) != 0) {
11199 return 0;
11200 }
11201 }
11202 return (tc.len == 0 && topic.len == 0);
11203}
11204
11205int mg_mqtt_vmatch_topic_expression(const char *exp, struct mg_str topic) {
11207}
11208
11209void mg_set_protocol_mqtt(struct mg_connection *nc) {
11211 nc->proto_data = MG_CALLOC(1, sizeof(struct mg_mqtt_proto_data));
11213}
11214
11215static void mg_send_mqtt_header(struct mg_connection *nc, uint8_t cmd,
11216 uint8_t flags, size_t len) {
11217 struct mg_mqtt_proto_data *pd = (struct mg_mqtt_proto_data *) nc->proto_data;
11218 uint8_t buf[1 + sizeof(size_t)];
11219 uint8_t *vlen = &buf[1];
11220
11221 buf[0] = (cmd << 4) | flags;
11222
11223 /* mqtt variable length encoding */
11224 do {
11225 *vlen = len % 0x80;
11226 len /= 0x80;
11227 if (len > 0) *vlen |= 0x80;
11228 vlen++;
11229 } while (len > 0);
11230
11231 mg_send(nc, buf, vlen - buf);
11232 pd->last_control_time = mg_time();
11233}
11234
11235void mg_send_mqtt_handshake(struct mg_connection *nc, const char *client_id) {
11236 static struct mg_send_mqtt_handshake_opts opts;
11237 mg_send_mqtt_handshake_opt(nc, client_id, opts);
11238}
11239
11240void mg_send_mqtt_handshake_opt(struct mg_connection *nc, const char *client_id,
11242 struct mg_mqtt_proto_data *pd = (struct mg_mqtt_proto_data *) nc->proto_data;
11243 uint16_t id_len = 0, wt_len = 0, wm_len = 0, user_len = 0, pw_len = 0;
11245 size_t total_len;
11246
11247 if (client_id != NULL) {
11248 id_len = strlen(client_id);
11249 }
11250
11251 total_len = 7 + 1 + 2 + 2 + id_len;
11252
11253 if (opts.user_name != NULL) {
11254 opts.flags |= MG_MQTT_HAS_USER_NAME;
11255 }
11256 if (opts.password != NULL) {
11257 opts.flags |= MG_MQTT_HAS_PASSWORD;
11258 }
11259 if (opts.will_topic != NULL && opts.will_message != NULL) {
11260 wt_len = strlen(opts.will_topic);
11261 wm_len = strlen(opts.will_message);
11262 opts.flags |= MG_MQTT_HAS_WILL;
11263 }
11264 if (opts.keep_alive == 0) {
11265 opts.keep_alive = 60;
11266 }
11267
11268 if (opts.flags & MG_MQTT_HAS_WILL) {
11269 total_len += 2 + wt_len + 2 + wm_len;
11270 }
11271 if (opts.flags & MG_MQTT_HAS_USER_NAME) {
11272 user_len = strlen(opts.user_name);
11273 total_len += 2 + user_len;
11274 }
11275 if (opts.flags & MG_MQTT_HAS_PASSWORD) {
11276 pw_len = strlen(opts.password);
11277 total_len += 2 + pw_len;
11278 }
11279
11281 mg_send(nc, "\00\04MQTT\04", 7);
11282 mg_send(nc, &opts.flags, 1);
11283
11284 netbytes = htons(opts.keep_alive);
11285 mg_send(nc, &netbytes, 2);
11286
11288 mg_send(nc, &netbytes, 2);
11289 mg_send(nc, client_id, id_len);
11290
11291 if (opts.flags & MG_MQTT_HAS_WILL) {
11293 mg_send(nc, &netbytes, 2);
11294 mg_send(nc, opts.will_topic, wt_len);
11295
11297 mg_send(nc, &netbytes, 2);
11298 mg_send(nc, opts.will_message, wm_len);
11299 }
11300
11301 if (opts.flags & MG_MQTT_HAS_USER_NAME) {
11303 mg_send(nc, &netbytes, 2);
11304 mg_send(nc, opts.user_name, user_len);
11305 }
11306 if (opts.flags & MG_MQTT_HAS_PASSWORD) {
11308 mg_send(nc, &netbytes, 2);
11309 mg_send(nc, opts.password, pw_len);
11310 }
11311
11312 if (pd != NULL) {
11313 pd->keep_alive = opts.keep_alive;
11314 }
11315}
11316
11317void mg_mqtt_publish(struct mg_connection *nc, const char *topic,
11318 uint16_t message_id, int flags, const void *data,
11319 size_t len) {
11321 uint16_t topic_len = strlen(topic);
11322
11323 size_t total_len = 2 + topic_len + len;
11324 if (MG_MQTT_GET_QOS(flags) > 0) {
11325 total_len += 2;
11326 }
11327
11329
11331 mg_send(nc, &netbytes, 2);
11332 mg_send(nc, topic, topic_len);
11333
11334 if (MG_MQTT_GET_QOS(flags) > 0) {
11335 netbytes = htons(message_id);
11336 mg_send(nc, &netbytes, 2);
11337 }
11338
11339 mg_send(nc, data, len);
11340}
11341
11342void mg_mqtt_subscribe(struct mg_connection *nc,
11343 const struct mg_mqtt_topic_expression *topics,
11344 size_t topics_len, uint16_t message_id) {
11346 size_t i;
11348 size_t total_len = 2;
11349
11350 for (i = 0; i < topics_len; i++) {
11351 total_len += 2 + strlen(topics[i].topic) + 1;
11352 }
11353
11355
11356 netbytes = htons(message_id);
11357 mg_send(nc, (char *) &netbytes, 2);
11358
11359 for (i = 0; i < topics_len; i++) {
11360 topic_len = strlen(topics[i].topic);
11362 mg_send(nc, &netbytes, 2);
11363 mg_send(nc, topics[i].topic, topic_len);
11364 mg_send(nc, &topics[i].qos, 1);
11365 }
11366}
11367
11369 struct mg_str *topic, uint8_t *qos, int pos) {
11370 unsigned char *buf = (unsigned char *) msg->payload.p + pos;
11371 int new_pos;
11372
11373 if ((size_t) pos >= msg->payload.len) return -1;
11374
11375 topic->len = buf[0] << 8 | buf[1];
11376 topic->p = (char *) buf + 2;
11377 new_pos = pos + 2 + topic->len + 1;
11378 if ((size_t) new_pos > msg->payload.len) return -1;
11379 *qos = buf[2 + topic->len];
11380 return new_pos;
11381}
11382
11383void mg_mqtt_unsubscribe(struct mg_connection *nc, char **topics,
11384 size_t topics_len, uint16_t message_id) {
11386 size_t i;
11388 size_t total_len = 2;
11389
11390 for (i = 0; i < topics_len; i++) {
11391 total_len += 2 + strlen(topics[i]);
11392 }
11393
11395
11396 netbytes = htons(message_id);
11397 mg_send(nc, (char *) &netbytes, 2);
11398
11399 for (i = 0; i < topics_len; i++) {
11402 mg_send(nc, &netbytes, 2);
11403 mg_send(nc, topics[i], topic_len);
11404 }
11405}
11406
11408 uint8_t unused = 0;
11410 mg_send(nc, &unused, 1);
11411 mg_send(nc, &return_code, 1);
11412}
11413
11414/*
11415 * Sends a command which contains only a `message_id` and a QoS level of 1.
11416 *
11417 * Helper function.
11418 */
11419static void mg_send_mqtt_short_command(struct mg_connection *nc, uint8_t cmd,
11420 uint16_t message_id) {
11422 uint8_t flags = (cmd == MG_MQTT_CMD_PUBREL ? 2 : 0);
11423
11424 mg_send_mqtt_header(nc, cmd, flags, 2 /* len */);
11425
11426 netbytes = htons(message_id);
11427 mg_send(nc, &netbytes, 2);
11428}
11429
11430void mg_mqtt_puback(struct mg_connection *nc, uint16_t message_id) {
11432}
11433
11434void mg_mqtt_pubrec(struct mg_connection *nc, uint16_t message_id) {
11436}
11437
11438void mg_mqtt_pubrel(struct mg_connection *nc, uint16_t message_id) {
11440}
11441
11442void mg_mqtt_pubcomp(struct mg_connection *nc, uint16_t message_id) {
11444}
11445
11446void mg_mqtt_suback(struct mg_connection *nc, uint8_t *qoss, size_t qoss_len,
11447 uint16_t message_id) {
11448 size_t i;
11450
11452
11453 netbytes = htons(message_id);
11454 mg_send(nc, &netbytes, 2);
11455
11456 for (i = 0; i < qoss_len; i++) {
11457 mg_send(nc, &qoss[i], 1);
11458 }
11459}
11460
11461void mg_mqtt_unsuback(struct mg_connection *nc, uint16_t message_id) {
11463}
11464
11465void mg_mqtt_ping(struct mg_connection *nc) {
11467}
11468
11469void mg_mqtt_pong(struct mg_connection *nc) {
11471}
11472
11473void mg_mqtt_disconnect(struct mg_connection *nc) {
11475}
11476
11477#endif /* MG_ENABLE_MQTT */
11478#ifdef MG_MODULE_LINES
11479#line 1 "mongoose/src/mg_mqtt_server.c"
11480#endif
11481/*
11482 * Copyright (c) 2014 Cesanta Software Limited
11483 * All rights reserved
11484 */
11485
11486/* Amalgamated: #include "mg_internal.h" */
11487/* Amalgamated: #include "mg_mqtt_server.h" */
11488
11489#if MG_ENABLE_MQTT_BROKER
11490
11491static void mg_mqtt_session_init(struct mg_mqtt_broker *brk,
11492 struct mg_mqtt_session *s,
11493 struct mg_connection *nc) {
11494 s->brk = brk;
11495 s->subscriptions = NULL;
11496 s->num_subscriptions = 0;
11497 s->nc = nc;
11498}
11499
11500static void mg_mqtt_add_session(struct mg_mqtt_session *s) {
11501 LIST_INSERT_HEAD(&s->brk->sessions, s, link);
11502}
11503
11504static void mg_mqtt_remove_session(struct mg_mqtt_session *s) {
11505 LIST_REMOVE(s, link);
11506}
11507
11508static void mg_mqtt_destroy_session(struct mg_mqtt_session *s) {
11509 size_t i;
11510 for (i = 0; i < s->num_subscriptions; i++) {
11511 MG_FREE((void *) s->subscriptions[i].topic);
11512 }
11513 MG_FREE(s->subscriptions);
11514 MG_FREE(s);
11515}
11516
11517static void mg_mqtt_close_session(struct mg_mqtt_session *s) {
11520}
11521
11522void mg_mqtt_broker_init(struct mg_mqtt_broker *brk, void *user_data) {
11523 LIST_INIT(&brk->sessions);
11524 brk->user_data = user_data;
11525}
11526
11528 struct mg_connection *nc) {
11529 struct mg_mqtt_session *s =
11530 (struct mg_mqtt_session *) MG_CALLOC(1, sizeof *s);
11531 if (s == NULL) {
11532 /* LCOV_EXCL_START */
11534 return;
11535 /* LCOV_EXCL_STOP */
11536 }
11537
11538 /* TODO(mkm): check header (magic and version) */
11539
11540 mg_mqtt_session_init(brk, s, nc);
11541 nc->priv_2 = s;
11543
11545}
11546
11547static void mg_mqtt_broker_handle_subscribe(struct mg_connection *nc,
11548 struct mg_mqtt_message *msg) {
11549 struct mg_mqtt_session *ss = (struct mg_mqtt_session *) nc->priv_2;
11551 size_t num_subs = 0;
11552 struct mg_str topic;
11553 uint8_t qos;
11554 int pos;
11556
11557 for (pos = 0;
11558 (pos = mg_mqtt_next_subscribe_topic(msg, &topic, &qos, pos)) != -1;) {
11560 (ss->num_subscriptions + num_subs >=
11563 return;
11564 }
11565 qoss[num_subs++] = qos;
11566 }
11567
11568 if (num_subs > 0) {
11570 ss->subscriptions,
11571 sizeof(*ss->subscriptions) * (ss->num_subscriptions + num_subs));
11572 if (te == NULL) {
11574 return;
11575 }
11576 ss->subscriptions = te;
11577 for (pos = 0;
11578 pos < (int) msg->payload.len &&
11579 (pos = mg_mqtt_next_subscribe_topic(msg, &topic, &qos, pos)) != -1;
11580 ss->num_subscriptions++) {
11581 te = &ss->subscriptions[ss->num_subscriptions];
11582 te->topic = (char *) MG_MALLOC(topic.len + 1);
11583 te->qos = qos;
11584 memcpy((char *) te->topic, topic.p, topic.len);
11585 ((char *) te->topic)[topic.len] = '\0';
11586 }
11587 }
11588
11589 if (pos == (int) msg->payload.len) {
11590 mg_mqtt_suback(nc, qoss, num_subs, msg->message_id);
11591 } else {
11592 /* We did not fully parse the payload, something must be wrong. */
11594 }
11595}
11596
11598 struct mg_mqtt_message *msg) {
11599 struct mg_mqtt_session *s;
11600 size_t i;
11601
11602 for (s = mg_mqtt_next(brk, NULL); s != NULL; s = mg_mqtt_next(brk, s)) {
11603 for (i = 0; i < s->num_subscriptions; i++) {
11604 if (mg_mqtt_vmatch_topic_expression(s->subscriptions[i].topic,
11605 msg->topic)) {
11606 char buf[100], *p = buf;
11607 mg_asprintf(&p, sizeof(buf), "%.*s", (int) msg->topic.len,
11608 msg->topic.p);
11609 if (p == NULL) {
11610 return;
11611 }
11612 mg_mqtt_publish(s->nc, p, 0, 0, msg->payload.p, msg->payload.len);
11613 if (p != buf) {
11614 MG_FREE(p);
11615 }
11616 break;
11617 }
11618 }
11619 }
11620}
11621
11622void mg_mqtt_broker(struct mg_connection *nc, int ev, void *data) {
11623 struct mg_mqtt_message *msg = (struct mg_mqtt_message *) data;
11624 struct mg_mqtt_broker *brk;
11625
11626 if (nc->listener) {
11627 brk = (struct mg_mqtt_broker *) nc->listener->priv_2;
11628 } else {
11629 brk = (struct mg_mqtt_broker *) nc->priv_2;
11630 }
11631
11632 switch (ev) {
11633 case MG_EV_ACCEPT:
11634 if (nc->proto_data == NULL) mg_set_protocol_mqtt(nc);
11635 nc->priv_2 = NULL; /* Clear up the inherited pointer to broker */
11636 break;
11637 case MG_EV_MQTT_CONNECT:
11638 if (nc->priv_2 == NULL) {
11640 } else {
11641 /* Repeated CONNECT */
11643 }
11644 break;
11646 if (nc->priv_2 != NULL) {
11648 } else {
11649 /* Subscribe before CONNECT */
11651 }
11652 break;
11653 case MG_EV_MQTT_PUBLISH:
11654 if (nc->priv_2 != NULL) {
11656 } else {
11657 /* Publish before CONNECT */
11659 }
11660 break;
11661 case MG_EV_CLOSE:
11662 if (nc->listener && nc->priv_2 != NULL) {
11664 }
11665 break;
11666 }
11667}
11668
11670 struct mg_mqtt_session *s) {
11671 return s == NULL ? LIST_FIRST(&brk->sessions) : LIST_NEXT(s, link);
11672}
11673
11674#endif /* MG_ENABLE_MQTT_BROKER */
11675#ifdef MG_MODULE_LINES
11676#line 1 "mongoose/src/mg_dns.c"
11677#endif
11678/*
11679 * Copyright (c) 2014 Cesanta Software Limited
11680 * All rights reserved
11681 */
11682
11683#if MG_ENABLE_DNS
11684
11685/* Amalgamated: #include "mg_internal.h" */
11686/* Amalgamated: #include "mg_dns.h" */
11687
11688static int mg_dns_tid = 0xa0;
11689
11690struct mg_dns_header {
11697};
11698
11700 struct mg_dns_message *msg, int query,
11701 struct mg_dns_resource_record *prev) {
11702 struct mg_dns_resource_record *rr;
11703
11704 for (rr = (prev == NULL ? msg->answers : prev + 1);
11705 rr - msg->answers < msg->num_answers; rr++) {
11706 if (rr->rtype == query) {
11707 return rr;
11708 }
11709 }
11710 return NULL;
11711}
11712
11714 struct mg_dns_resource_record *rr, void *data,
11715 size_t data_len) {
11716 switch (rr->rtype) {
11717 case MG_DNS_A_RECORD:
11718 if (data_len < sizeof(struct in_addr)) {
11719 return -1;
11720 }
11721 if (rr->rdata.p + data_len > msg->pkt.p + msg->pkt.len) {
11722 return -1;
11723 }
11724 memcpy(data, rr->rdata.p, data_len);
11725 return 0;
11726#if MG_ENABLE_IPV6
11727 case MG_DNS_AAAA_RECORD:
11728 if (data_len < sizeof(struct in6_addr)) {
11729 return -1; /* LCOV_EXCL_LINE */
11730 }
11731 memcpy(data, rr->rdata.p, data_len);
11732 return 0;
11733#endif
11735 mg_dns_uncompress_name(msg, &rr->rdata, (char *) data, data_len);
11736 return 0;
11737 }
11738
11739 return -1;
11740}
11741
11742int mg_dns_insert_header(struct mbuf *io, size_t pos,
11743 struct mg_dns_message *msg) {
11744 struct mg_dns_header header;
11745
11746 memset(&header, 0, sizeof(header));
11747 header.transaction_id = msg->transaction_id;
11748 header.flags = htons(msg->flags);
11749 header.num_questions = htons(msg->num_questions);
11750 header.num_answers = htons(msg->num_answers);
11751
11752 return mbuf_insert(io, pos, &header, sizeof(header));
11753}
11754
11755int mg_dns_copy_questions(struct mbuf *io, struct mg_dns_message *msg) {
11756 unsigned char *begin, *end;
11758 if (msg->num_questions <= 0) return 0;
11759 begin = (unsigned char *) msg->pkt.p + sizeof(struct mg_dns_header);
11760 last_q = &msg->questions[msg->num_questions - 1];
11761 end = (unsigned char *) last_q->name.p + last_q->name.len + 4;
11762 return mbuf_append(io, begin, end - begin);
11763}
11764
11765int mg_dns_encode_name(struct mbuf *io, const char *name, size_t len) {
11766 const char *s;
11767 unsigned char n;
11768 size_t pos = io->len;
11769
11770 do {
11771 if ((s = strchr(name, '.')) == NULL) {
11772 s = name + len;
11773 }
11774
11775 if (s - name > 127) {
11776 return -1; /* TODO(mkm) cover */
11777 }
11778 n = s - name; /* chunk length */
11779 mbuf_append(io, &n, 1); /* send length */
11780 mbuf_append(io, name, n);
11781
11782 if (*s == '.') {
11783 n++;
11784 }
11785
11786 name += n;
11787 len -= n;
11788 } while (*s != '\0');
11789 mbuf_append(io, "\0", 1); /* Mark end of host name */
11790
11791 return io->len - pos;
11792}
11793
11795 const char *name, size_t nlen, const void *rdata,
11796 size_t rlen) {
11797 size_t pos = io->len;
11798 uint16_t u16;
11799 uint32_t u32;
11800
11801 if (rr->kind == MG_DNS_INVALID_RECORD) {
11802 return -1; /* LCOV_EXCL_LINE */
11803 }
11804
11805 if (mg_dns_encode_name(io, name, nlen) == -1) {
11806 return -1;
11807 }
11808
11809 u16 = htons(rr->rtype);
11810 mbuf_append(io, &u16, 2);
11811 u16 = htons(rr->rclass);
11812 mbuf_append(io, &u16, 2);
11813
11814 if (rr->kind == MG_DNS_ANSWER) {
11815 u32 = htonl(rr->ttl);
11816 mbuf_append(io, &u32, 4);
11817
11818 if (rr->rtype == MG_DNS_CNAME_RECORD) {
11819 int clen;
11820 /* fill size after encoding */
11821 size_t off = io->len;
11822 mbuf_append(io, &u16, 2);
11823 if ((clen = mg_dns_encode_name(io, (const char *) rdata, rlen)) == -1) {
11824 return -1;
11825 }
11826 u16 = clen;
11827 io->buf[off] = u16 >> 8;
11828 io->buf[off + 1] = u16 & 0xff;
11829 } else {
11830 u16 = htons((uint16_t) rlen);
11831 mbuf_append(io, &u16, 2);
11833 }
11834 }
11835
11836 return io->len - pos;
11837}
11838
11839void mg_send_dns_query(struct mg_connection *nc, const char *name,
11840 int query_type) {
11841 struct mg_dns_message *msg =
11842 (struct mg_dns_message *) MG_CALLOC(1, sizeof(*msg));
11843 struct mbuf pkt;
11844 struct mg_dns_resource_record *rr = &msg->questions[0];
11845
11846 DBG(("%s %d", name, query_type));
11847
11848 mbuf_init(&pkt, 64 /* Start small, it'll grow as needed. */);
11849
11850 msg->transaction_id = ++mg_dns_tid;
11851 msg->flags = 0x100;
11852 msg->num_questions = 1;
11853
11854 mg_dns_insert_header(&pkt, 0, msg);
11855
11856 rr->rtype = query_type;
11857 rr->rclass = 1; /* Class: inet */
11858 rr->kind = MG_DNS_QUESTION;
11859
11860 if (mg_dns_encode_record(&pkt, rr, name, strlen(name), NULL, 0) == -1) {
11861 /* TODO(mkm): return an error code */
11862 goto cleanup; /* LCOV_EXCL_LINE */
11863 }
11864
11865 /* TCP DNS requires messages to be prefixed with len */
11866 if (!(nc->flags & MG_F_UDP)) {
11867 uint16_t len = htons((uint16_t) pkt.len);
11868 mbuf_insert(&pkt, 0, &len, 2);
11869 }
11870
11871 mg_send(nc, pkt.buf, pkt.len);
11872 mbuf_free(&pkt);
11873
11874cleanup:
11875 MG_FREE(msg);
11876}
11877
11878static unsigned char *mg_parse_dns_resource_record(
11879 unsigned char *data, unsigned char *end, struct mg_dns_resource_record *rr,
11880 int reply) {
11881 unsigned char *name = data;
11882 int chunk_len, data_len;
11883
11884 while (data < end && (chunk_len = *data)) {
11885 if (((unsigned char *) data)[0] & 0xc0) {
11886 data += 1;
11887 break;
11888 }
11889 data += chunk_len + 1;
11890 }
11891
11892 if (data > end - 5) {
11893 return NULL;
11894 }
11895
11896 rr->name.p = (char *) name;
11897 rr->name.len = data - name + 1;
11898 data++;
11899
11900 rr->rtype = data[0] << 8 | data[1];
11901 data += 2;
11902
11903 rr->rclass = data[0] << 8 | data[1];
11904 data += 2;
11905
11907 if (reply) {
11908 if (data >= end - 6) {
11909 return NULL;
11910 }
11911
11912 rr->ttl = (uint32_t) data[0] << 24 | (uint32_t) data[1] << 16 |
11913 data[2] << 8 | data[3];
11914 data += 4;
11915
11916 data_len = *data << 8 | *(data + 1);
11917 data += 2;
11918
11919 rr->rdata.p = (char *) data;
11920 rr->rdata.len = data_len;
11921 data += data_len;
11922 }
11923 return data;
11924}
11925
11926int mg_parse_dns(const char *buf, int len, struct mg_dns_message *msg) {
11927 struct mg_dns_header *header = (struct mg_dns_header *) buf;
11928 unsigned char *data = (unsigned char *) buf + sizeof(*header);
11929 unsigned char *end = (unsigned char *) buf + len;
11930 int i;
11931
11932 memset(msg, 0, sizeof(*msg));
11933 msg->pkt.p = buf;
11934 msg->pkt.len = len;
11935
11936 if (len < (int) sizeof(*header)) return -1;
11937
11938 msg->transaction_id = header->transaction_id;
11939 msg->flags = ntohs(header->flags);
11940 msg->num_questions = ntohs(header->num_questions);
11941 if (msg->num_questions > (int) ARRAY_SIZE(msg->questions)) {
11942 msg->num_questions = (int) ARRAY_SIZE(msg->questions);
11943 }
11944 msg->num_answers = ntohs(header->num_answers);
11945 if (msg->num_answers > (int) ARRAY_SIZE(msg->answers)) {
11946 msg->num_answers = (int) ARRAY_SIZE(msg->answers);
11947 }
11948
11949 for (i = 0; i < msg->num_questions; i++) {
11951 if (data == NULL) return -1;
11952 }
11953
11954 for (i = 0; i < msg->num_answers; i++) {
11956 if (data == NULL) return -1;
11957 }
11958
11959 return 0;
11960}
11961
11962size_t mg_dns_uncompress_name(struct mg_dns_message *msg, struct mg_str *name,
11963 char *dst, int dst_len) {
11964 int chunk_len, num_ptrs = 0;
11965 char *old_dst = dst;
11966 const unsigned char *data = (unsigned char *) name->p;
11967 const unsigned char *end = (unsigned char *) msg->pkt.p + msg->pkt.len;
11968
11969 if (data >= end) {
11970 return 0;
11971 }
11972
11973 while ((chunk_len = *data++)) {
11974 int leeway = dst_len - (dst - old_dst);
11975 if (data >= end) {
11976 return 0;
11977 }
11978
11979 if ((chunk_len & 0xc0) == 0xc0) {
11980 uint16_t off = (data[-1] & (~0xc0)) << 8 | data[0];
11981 if (off >= msg->pkt.len) {
11982 return 0;
11983 }
11984 /* Basic circular loop avoidance: allow up to 16 pointer hops. */
11985 if (++num_ptrs > 15) {
11986 return 0;
11987 }
11988 data = (unsigned char *) msg->pkt.p + off;
11989 continue;
11990 }
11991 if (chunk_len > 63) {
11992 return 0;
11993 }
11994 if (chunk_len > leeway) {
11995 chunk_len = leeway;
11996 }
11997
11998 if (data + chunk_len >= end) {
11999 return 0;
12000 }
12001
12002 memcpy(dst, data, chunk_len);
12003 data += chunk_len;
12004 dst += chunk_len;
12005 leeway -= chunk_len;
12006 if (leeway == 0) {
12007 return dst - old_dst;
12008 }
12009 *dst++ = '.';
12010 }
12011
12012 if (dst != old_dst) {
12013 *--dst = 0;
12014 }
12015 return dst - old_dst;
12016}
12017
12018static void dns_handler(struct mg_connection *nc, int ev,
12019 void *ev_data MG_UD_ARG(void *user_data)) {
12020 struct mbuf *io = &nc->recv_mbuf;
12021 struct mg_dns_message msg;
12022
12023 /* Pass low-level events to the user handler */
12024 nc->handler(nc, ev, ev_data MG_UD_ARG(user_data));
12025
12026 switch (ev) {
12027 case MG_EV_RECV:
12028 if (!(nc->flags & MG_F_UDP)) {
12029 mbuf_remove(&nc->recv_mbuf, 2);
12030 }
12031 if (mg_parse_dns(nc->recv_mbuf.buf, nc->recv_mbuf.len, &msg) == -1) {
12032 /* reply + recursion allowed + format error */
12033 memset(&msg, 0, sizeof(msg));
12034 msg.flags = 0x8081;
12035 mg_dns_insert_header(io, 0, &msg);
12036 if (!(nc->flags & MG_F_UDP)) {
12037 uint16_t len = htons((uint16_t) io->len);
12038 mbuf_insert(io, 0, &len, 2);
12039 }
12040 mg_send(nc, io->buf, io->len);
12041 } else {
12042 /* Call user handler with parsed message */
12043 nc->handler(nc, MG_DNS_MESSAGE, &msg MG_UD_ARG(user_data));
12044 }
12045 mbuf_remove(io, io->len);
12046 break;
12047 }
12048}
12049
12050void mg_set_protocol_dns(struct mg_connection *nc) {
12052}
12053
12054#endif /* MG_ENABLE_DNS */
12055#ifdef MG_MODULE_LINES
12056#line 1 "mongoose/src/mg_dns_server.c"
12057#endif
12058/*
12059 * Copyright (c) 2014 Cesanta Software Limited
12060 * All rights reserved
12061 */
12062
12063#if MG_ENABLE_DNS_SERVER
12064
12065/* Amalgamated: #include "mg_internal.h" */
12066/* Amalgamated: #include "dns-server.h" */
12067
12069 struct mg_dns_message *msg) {
12070 struct mg_dns_reply rep;
12071 rep.msg = msg;
12072 rep.io = io;
12073 rep.start = io->len;
12074
12075 /* reply + recursion allowed */
12076 msg->flags |= 0x8080;
12078
12079 msg->num_answers = 0;
12080 return rep;
12081}
12082
12083void mg_dns_send_reply(struct mg_connection *nc, struct mg_dns_reply *r) {
12084 size_t sent = r->io->len - r->start;
12085 mg_dns_insert_header(r->io, r->start, r->msg);
12086 if (!(nc->flags & MG_F_UDP)) {
12087 uint16_t len = htons((uint16_t) sent);
12088 mbuf_insert(r->io, r->start, &len, 2);
12089 }
12090
12091 if (&nc->send_mbuf != r->io) {
12092 mg_send(nc, r->io->buf + r->start, r->io->len - r->start);
12093 r->io->len = r->start;
12094 }
12095}
12096
12099 const char *name, int rtype, int ttl, const void *rdata,
12100 size_t rdata_len) {
12101 struct mg_dns_message *msg = (struct mg_dns_message *) reply->msg;
12102 char rname[512];
12103 struct mg_dns_resource_record *ans = &msg->answers[msg->num_answers];
12104 if (msg->num_answers >= MG_MAX_DNS_ANSWERS) {
12105 return -1; /* LCOV_EXCL_LINE */
12106 }
12107
12108 if (name == NULL) {
12109 name = rname;
12110 rname[511] = 0;
12111 mg_dns_uncompress_name(msg, &question->name, rname, sizeof(rname) - 1);
12112 }
12113
12114 *ans = *question;
12115 ans->kind = MG_DNS_ANSWER;
12116 ans->rtype = rtype;
12117 ans->ttl = ttl;
12118
12120 rdata_len) == -1) {
12121 return -1; /* LCOV_EXCL_LINE */
12122 };
12123
12124 msg->num_answers++;
12125 return 0;
12126}
12127
12128#endif /* MG_ENABLE_DNS_SERVER */
12129#ifdef MG_MODULE_LINES
12130#line 1 "mongoose/src/mg_resolv.c"
12131#endif
12132/*
12133 * Copyright (c) 2014 Cesanta Software Limited
12134 * All rights reserved
12135 */
12136
12137#if MG_ENABLE_ASYNC_RESOLVER
12138
12139/* Amalgamated: #include "mg_internal.h" */
12140/* Amalgamated: #include "mg_resolv.h" */
12141
12142#ifndef MG_DEFAULT_NAMESERVER
12143#define MG_DEFAULT_NAMESERVER "8.8.8.8"
12144#endif
12145
12147 char name[1024];
12148 int query;
12150 void *data;
12152 int max_retries;
12153 enum mg_resolve_err err;
12154
12155 /* state */
12157 int retries;
12158};
12159
12160/*
12161 * Find what nameserver to use.
12162 *
12163 * Return 0 if OK, -1 if error
12164 */
12165static int mg_get_ip_address_of_nameserver(char *name, size_t name_len) {
12166 int ret = -1;
12167
12168#ifdef _WIN32
12169 int i;
12170 LONG err;
12171 HKEY hKey, hSub;
12172 wchar_t subkey[512], value[128],
12173 *key = L"SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters\\Interfaces";
12174
12175 if ((err = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hKey)) !=
12176 ERROR_SUCCESS) {
12177 fprintf(stderr, "cannot open reg key %S: %ld\n", key, err);
12178 ret = -1;
12179 } else {
12180 for (ret = -1, i = 0; 1; i++) {
12181 DWORD subkey_size = sizeof(subkey), type, len = sizeof(value);
12183 NULL) != ERROR_SUCCESS) {
12184 break;
12185 }
12187 ((RegQueryValueExW(hSub, L"NameServer", 0, &type, (void *) value,
12188 &len) == ERROR_SUCCESS &&
12189 value[0] != '\0') ||
12190 (RegQueryValueExW(hSub, L"DhcpNameServer", 0, &type, (void *) value,
12191 &len) == ERROR_SUCCESS &&
12192 value[0] != '\0'))) {
12193 /*
12194 * See https://github.com/cesanta/mongoose/issues/176
12195 * The value taken from the registry can be empty, a single
12196 * IP address, or multiple IP addresses separated by comma.
12197 * If it's empty, check the next interface.
12198 * If it's multiple IP addresses, take the first one.
12199 */
12200 wchar_t *comma = wcschr(value, ',');
12201 if (comma != NULL) {
12202 *comma = '\0';
12203 }
12204 /* %S will convert wchar_t -> char */
12205 snprintf(name, name_len, "%S", value);
12206 ret = 0;
12208 break;
12209 }
12210 }
12212 }
12213#elif MG_ENABLE_FILESYSTEM && defined(MG_RESOLV_CONF_FILE_NAME)
12214 FILE *fp;
12215 char line[512];
12216
12217 if ((fp = mg_fopen(MG_RESOLV_CONF_FILE_NAME, "r")) == NULL) {
12218 ret = -1;
12219 } else {
12220 /* Try to figure out what nameserver to use */
12221 for (ret = -1; fgets(line, sizeof(line), fp) != NULL;) {
12222 unsigned int a, b, c, d;
12223 if (sscanf(line, "nameserver %u.%u.%u.%u", &a, &b, &c, &d) == 4) {
12224 snprintf(name, name_len, "%u.%u.%u.%u", a, b, c, d);
12225 ret = 0;
12226 break;
12227 }
12228 }
12229 (void) fclose(fp);
12230 }
12231#else
12232 snprintf(name, name_len, "%s", MG_DEFAULT_NAMESERVER);
12233#endif /* _WIN32 */
12234
12235 return ret;
12236}
12237
12238int mg_resolve_from_hosts_file(const char *name, union socket_address *usa) {
12239#if MG_ENABLE_FILESYSTEM && defined(MG_HOSTS_FILE_NAME)
12240 /* TODO(mkm) cache /etc/hosts */
12241 FILE *fp;
12242 char line[1024];
12243 char *p;
12244 char alias[256];
12245 unsigned int a, b, c, d;
12246 int len = 0;
12247
12248 if ((fp = mg_fopen(MG_HOSTS_FILE_NAME, "r")) == NULL) {
12249 return -1;
12250 }
12251
12252 for (; fgets(line, sizeof(line), fp) != NULL;) {
12253 if (line[0] == '#') continue;
12254
12255 if (sscanf(line, "%u.%u.%u.%u%n", &a, &b, &c, &d, &len) == 0) {
12256 /* TODO(mkm): handle ipv6 */
12257 continue;
12258 }
12259 for (p = line + len; sscanf(p, "%s%n", alias, &len) == 1; p += len) {
12260 if (strcmp(alias, name) == 0) {
12261 usa->sin.sin_addr.s_addr = htonl(a << 24 | b << 16 | c << 8 | d);
12262 fclose(fp);
12263 return 0;
12264 }
12265 }
12266 }
12267
12268 fclose(fp);
12269#else
12270 (void) name;
12271 (void) usa;
12272#endif
12273
12274 return -1;
12275}
12276
12277static void mg_resolve_async_eh(struct mg_connection *nc, int ev,
12278 void *data MG_UD_ARG(void *user_data)) {
12279 time_t now = (time_t) mg_time();
12280 struct mg_resolve_async_request *req;
12281 struct mg_dns_message *msg;
12282#if !MG_ENABLE_CALLBACK_USERDATA
12283 void *user_data = nc->user_data;
12284#endif
12285
12286 if (ev != MG_EV_POLL) {
12287 DBG(("ev=%d user_data=%p", ev, user_data));
12288 }
12289
12290 req = (struct mg_resolve_async_request *) user_data;
12291
12292 if (req == NULL) {
12293 return;
12294 }
12295
12296 switch (ev) {
12297 case MG_EV_POLL:
12298 if (req->retries > req->max_retries) {
12301 break;
12302 }
12303 if (nc->flags & MG_F_CONNECTING) break;
12304 /* fallthrough */
12305 case MG_EV_CONNECT:
12306 if (req->retries == 0 || now - req->last_time >= req->timeout) {
12307 mg_send_dns_query(nc, req->name, req->query);
12308 req->last_time = now;
12309 req->retries++;
12310 }
12311 break;
12312 case MG_EV_RECV:
12313 msg = (struct mg_dns_message *) MG_MALLOC(sizeof(*msg));
12314 if (mg_parse_dns(nc->recv_mbuf.buf, *(int *) data, msg) == 0 &&
12315 msg->num_answers > 0) {
12316 req->callback(msg, req->data, MG_RESOLVE_OK);
12317 nc->user_data = NULL;
12318 MG_FREE(req);
12319 } else {
12321 }
12322 MG_FREE(msg);
12324 break;
12325 case MG_EV_SEND:
12326 /*
12327 * If a send error occurs, prevent closing of the connection by the core.
12328 * We will retry after timeout.
12329 */
12332 break;
12333 case MG_EV_TIMER:
12334 req->err = MG_RESOLVE_TIMEOUT;
12336 break;
12337 case MG_EV_CLOSE:
12338 /* If we got here with request still not done, fire an error callback. */
12339 if (req != NULL) {
12340 char addr[32];
12342#ifdef MG_LOG_DNS_FAILURES
12343 LOG(LL_ERROR, ("Failed to resolve '%s', server %s", req->name, addr));
12344#endif
12345 req->callback(NULL, req->data, req->err);
12346 nc->user_data = NULL;
12347 MG_FREE(req);
12348 }
12349 break;
12350 }
12351}
12352
12353int mg_resolve_async(struct mg_mgr *mgr, const char *name, int query,
12354 mg_resolve_callback_t cb, void *data) {
12356 memset(&opts, 0, sizeof(opts));
12357 return mg_resolve_async_opt(mgr, name, query, cb, data, opts);
12358}
12359
12360int mg_resolve_async_opt(struct mg_mgr *mgr, const char *name, int query,
12361 mg_resolve_callback_t cb, void *data,
12362 struct mg_resolve_async_opts opts) {
12363 struct mg_resolve_async_request *req;
12364 struct mg_connection *dns_nc;
12365 const char *nameserver = opts.nameserver;
12366 char dns_server_buff[17], nameserver_url[26];
12367
12368 if (nameserver == NULL) {
12369 nameserver = mgr->nameserver;
12370 }
12371
12372 DBG(("%s %d %p", name, query, opts.dns_conn));
12373
12374 /* resolve with DNS */
12375 req = (struct mg_resolve_async_request *) MG_CALLOC(1, sizeof(*req));
12376 if (req == NULL) {
12377 return -1;
12378 }
12379
12380 strncpy(req->name, name, sizeof(req->name));
12381 req->name[sizeof(req->name) - 1] = '\0';
12382
12383 req->query = query;
12384 req->callback = cb;
12385 req->data = data;
12386 /* TODO(mkm): parse defaults out of resolve.conf */
12387 req->max_retries = opts.max_retries ? opts.max_retries : 2;
12388 req->timeout = opts.timeout ? opts.timeout : 5;
12389
12390 /* Lazily initialize dns server */
12391 if (nameserver == NULL) {
12393 sizeof(dns_server_buff)) != -1) {
12394 nameserver = dns_server_buff;
12395 } else {
12396 nameserver = MG_DEFAULT_NAMESERVER;
12397 }
12398 }
12399
12400 snprintf(nameserver_url, sizeof(nameserver_url), "udp://%s:53", nameserver);
12401
12402 dns_nc = mg_connect(mgr, nameserver_url, MG_CB(mg_resolve_async_eh, NULL));
12403 if (dns_nc == NULL) {
12404 MG_FREE(req);
12405 return -1;
12406 }
12407 dns_nc->user_data = req;
12408 if (opts.dns_conn != NULL) {
12409 *opts.dns_conn = dns_nc;
12410 }
12411
12412 return 0;
12413}
12414
12415void mg_set_nameserver(struct mg_mgr *mgr, const char *nameserver) {
12416 MG_FREE((char *) mgr->nameserver);
12417 mgr->nameserver = NULL;
12418 if (nameserver != NULL) {
12419 mgr->nameserver = strdup(nameserver);
12420 }
12421}
12422
12423#endif /* MG_ENABLE_ASYNC_RESOLVER */
12424#ifdef MG_MODULE_LINES
12425#line 1 "mongoose/src/mg_coap.c"
12426#endif
12427/*
12428 * Copyright (c) 2015 Cesanta Software Limited
12429 * All rights reserved
12430 * This software is dual-licensed: you can redistribute it and/or modify
12431 * it under the terms of the GNU General Public License version 2 as
12432 * published by the Free Software Foundation. For the terms of this
12433 * license, see <http://www.gnu.org/licenses/>.
12434 *
12435 * You are free to use this software under the terms of the GNU General
12436 * Public License, but WITHOUT ANY WARRANTY; without even the implied
12437 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12438 * See the GNU General Public License for more details.
12439 *
12440 * Alternatively, you can license this software under a commercial
12441 * license, as set out in <https://www.cesanta.com/license>.
12442 */
12443
12444/* Amalgamated: #include "mg_internal.h" */
12445/* Amalgamated: #include "mg_coap.h" */
12446
12447#if MG_ENABLE_COAP
12448
12450 while (cm->options != NULL) {
12451 struct mg_coap_option *next = cm->options->next;
12452 MG_FREE(cm->options);
12453 cm->options = next;
12454 }
12455}
12456
12458 uint32_t number, char *value,
12459 size_t len) {
12460 struct mg_coap_option *new_option =
12461 (struct mg_coap_option *) MG_CALLOC(1, sizeof(*new_option));
12462
12463 new_option->number = number;
12464 new_option->value.p = value;
12465 new_option->value.len = len;
12466
12467 if (cm->options == NULL) {
12468 cm->options = cm->optiomg_tail = new_option;
12469 } else {
12470 /*
12471 * A very simple attention to help clients to compose options:
12472 * CoAP wants to see options ASC ordered.
12473 * Could be change by using sort in coap_compose
12474 */
12475 if (cm->optiomg_tail->number <= new_option->number) {
12476 /* if option is already ordered just add it */
12477 cm->optiomg_tail = cm->optiomg_tail->next = new_option;
12478 } else {
12479 /* looking for appropriate position */
12480 struct mg_coap_option *current_opt = cm->options;
12481 struct mg_coap_option *prev_opt = 0;
12482
12483 while (current_opt != NULL) {
12484 if (current_opt->number > new_option->number) {
12485 break;
12486 }
12488 current_opt = current_opt->next;
12489 }
12490
12491 if (prev_opt != NULL) {
12492 prev_opt->next = new_option;
12493 new_option->next = current_opt;
12494 } else {
12495 /* insert new_option to the beginning */
12496 new_option->next = cm->options;
12497 cm->options = new_option;
12498 }
12499 }
12500 }
12501
12502 return new_option;
12503}
12504
12505/*
12506 * Fills CoAP header in mg_coap_message.
12507 *
12508 * Helper function.
12509 */
12510static char *coap_parse_header(char *ptr, struct mbuf *io,
12511 struct mg_coap_message *cm) {
12512 if (io->len < sizeof(uint32_t)) {
12513 cm->flags |= MG_COAP_NOT_ENOUGH_DATA;
12514 return NULL;
12515 }
12516
12517 /*
12518 * Version (Ver): 2-bit unsigned integer. Indicates the CoAP version
12519 * number. Implementations of this specification MUST set this field
12520 * to 1 (01 binary). Other values are reserved for future versions.
12521 * Messages with unknown version numbers MUST be silently ignored.
12522 */
12523 if (((uint8_t) *ptr >> 6) != 1) {
12524 cm->flags |= MG_COAP_IGNORE;
12525 return NULL;
12526 }
12527
12528 /*
12529 * Type (T): 2-bit unsigned integer. Indicates if this message is of
12530 * type Confirmable (0), Non-confirmable (1), Acknowledgement (2), or
12531 * Reset (3).
12532 */
12533 cm->msg_type = ((uint8_t) *ptr & 0x30) >> 4;
12534 cm->flags |= MG_COAP_MSG_TYPE_FIELD;
12535
12536 /*
12537 * Token Length (TKL): 4-bit unsigned integer. Indicates the length of
12538 * the variable-length Token field (0-8 bytes). Lengths 9-15 are
12539 * reserved, MUST NOT be sent, and MUST be processed as a message
12540 * format error.
12541 */
12542 cm->token.len = *ptr & 0x0F;
12543 if (cm->token.len > 8) {
12544 cm->flags |= MG_COAP_FORMAT_ERROR;
12545 return NULL;
12546 }
12547
12548 ptr++;
12549
12550 /*
12551 * Code: 8-bit unsigned integer, split into a 3-bit class (most
12552 * significant bits) and a 5-bit detail (least significant bits)
12553 */
12554 cm->code_class = (uint8_t) *ptr >> 5;
12555 cm->code_detail = *ptr & 0x1F;
12557
12558 ptr++;
12559
12560 /* Message ID: 16-bit unsigned integer in network byte order. */
12561 cm->msg_id = (uint8_t) *ptr << 8 | (uint8_t) * (ptr + 1);
12562 cm->flags |= MG_COAP_MSG_ID_FIELD;
12563
12564 ptr += 2;
12565
12566 return ptr;
12567}
12568
12569/*
12570 * Fills token information in mg_coap_message.
12571 *
12572 * Helper function.
12573 */
12574static char *coap_get_token(char *ptr, struct mbuf *io,
12575 struct mg_coap_message *cm) {
12576 if (cm->token.len != 0) {
12577 if (ptr + cm->token.len > io->buf + io->len) {
12578 cm->flags |= MG_COAP_NOT_ENOUGH_DATA;
12579 return NULL;
12580 } else {
12581 cm->token.p = ptr;
12582 ptr += cm->token.len;
12583 cm->flags |= MG_COAP_TOKEN_FIELD;
12584 }
12585 }
12586
12587 return ptr;
12588}
12589
12590/*
12591 * Returns Option Delta or Length.
12592 *
12593 * Helper function.
12594 */
12595static int coap_get_ext_opt(char *ptr, struct mbuf *io, uint16_t *opt_info) {
12596 int ret = 0;
12597
12598 if (*opt_info == 13) {
12599 /*
12600 * 13: An 8-bit unsigned integer follows the initial byte and
12601 * indicates the Option Delta/Length minus 13.
12602 */
12603 if (ptr < io->buf + io->len) {
12604 *opt_info = (uint8_t) *ptr + 13;
12605 ret = sizeof(uint8_t);
12606 } else {
12607 ret = -1; /* LCOV_EXCL_LINE */
12608 }
12609 } else if (*opt_info == 14) {
12610 /*
12611 * 14: A 16-bit unsigned integer in network byte order follows the
12612 * initial byte and indicates the Option Delta/Length minus 269.
12613 */
12614 if (ptr + sizeof(uint8_t) < io->buf + io->len) {
12615 *opt_info = ((uint8_t) *ptr << 8 | (uint8_t) * (ptr + 1)) + 269;
12616 ret = sizeof(uint16_t);
12617 } else {
12618 ret = -1; /* LCOV_EXCL_LINE */
12619 }
12620 }
12621
12622 return ret;
12623}
12624
12625/*
12626 * Fills options in mg_coap_message.
12627 *
12628 * Helper function.
12629 *
12630 * General options format:
12631 * +---------------+---------------+
12632 * | Option Delta | Option Length | 1 byte
12633 * +---------------+---------------+
12634 * \ Option Delta (extended) \ 0-2 bytes
12635 * +-------------------------------+
12636 * / Option Length (extended) \ 0-2 bytes
12637 * +-------------------------------+
12638 * \ Option Value \ 0 or more bytes
12639 * +-------------------------------+
12640 */
12641static char *coap_get_options(char *ptr, struct mbuf *io,
12642 struct mg_coap_message *cm) {
12643 uint16_t prev_opt = 0;
12644
12645 if (ptr == io->buf + io->len) {
12646 /* end of packet, ok */
12647 return NULL;
12648 }
12649
12650 /* 0xFF is payload marker */
12651 while (ptr < io->buf + io->len && (uint8_t) *ptr != 0xFF) {
12653 int optinfo_len;
12654
12655 /* Option Delta: 4-bit unsigned integer */
12656 option_delta = ((uint8_t) *ptr & 0xF0) >> 4;
12657 /* Option Length: 4-bit unsigned integer */
12658 option_lenght = *ptr & 0x0F;
12659
12660 if (option_delta == 15 || option_lenght == 15) {
12661 /*
12662 * 15: Reserved for future use. If the field is set to this value,
12663 * it MUST be processed as a message format error
12664 */
12665 cm->flags |= MG_COAP_FORMAT_ERROR;
12666 break;
12667 }
12668
12669 ptr++;
12670
12671 /* check for extended option delta */
12673 if (optinfo_len == -1) {
12674 cm->flags |= MG_COAP_NOT_ENOUGH_DATA; /* LCOV_EXCL_LINE */
12675 break; /* LCOV_EXCL_LINE */
12676 }
12677
12678 ptr += optinfo_len;
12679
12680 /* check or extended option lenght */
12682 if (optinfo_len == -1) {
12683 cm->flags |= MG_COAP_NOT_ENOUGH_DATA; /* LCOV_EXCL_LINE */
12684 break; /* LCOV_EXCL_LINE */
12685 }
12686
12687 ptr += optinfo_len;
12688
12689 /*
12690 * Instead of specifying the Option Number directly, the instances MUST
12691 * appear in order of their Option Numbers and a delta encoding is used
12692 * between them.
12693 */
12695
12697
12699
12700 if (ptr + option_lenght > io->buf + io->len) {
12701 cm->flags |= MG_COAP_NOT_ENOUGH_DATA; /* LCOV_EXCL_LINE */
12702 break; /* LCOV_EXCL_LINE */
12703 }
12704
12705 ptr += option_lenght;
12706 }
12707
12708 if ((cm->flags & MG_COAP_ERROR) != 0) {
12710 return NULL;
12711 }
12712
12713 cm->flags |= MG_COAP_OPTIOMG_FIELD;
12714
12715 if (ptr == io->buf + io->len) {
12716 /* end of packet, ok */
12717 return NULL;
12718 }
12719
12720 ptr++;
12721
12722 return ptr;
12723}
12724
12725uint32_t mg_coap_parse(struct mbuf *io, struct mg_coap_message *cm) {
12726 char *ptr;
12727
12728 memset(cm, 0, sizeof(*cm));
12729
12730 if ((ptr = coap_parse_header(io->buf, io, cm)) == NULL) {
12731 return cm->flags;
12732 }
12733
12734 if ((ptr = coap_get_token(ptr, io, cm)) == NULL) {
12735 return cm->flags;
12736 }
12737
12738 if ((ptr = coap_get_options(ptr, io, cm)) == NULL) {
12739 return cm->flags;
12740 }
12741
12742 /* the rest is payload */
12743 cm->payload.len = io->len - (ptr - io->buf);
12744 if (cm->payload.len != 0) {
12745 cm->payload.p = ptr;
12746 cm->flags |= MG_COAP_PAYLOAD_FIELD;
12747 }
12748
12749 return cm->flags;
12750}
12751
12752/*
12753 * Calculates extended size of given Opt Number/Length in coap message.
12754 *
12755 * Helper function.
12756 */
12757static size_t coap_get_ext_opt_size(uint32_t value) {
12758 int ret = 0;
12759
12760 if (value >= 13 && value <= 0xFF + 13) {
12761 ret = sizeof(uint8_t);
12762 } else if (value > 0xFF + 13 && value <= 0xFFFF + 269) {
12763 ret = sizeof(uint16_t);
12764 }
12765
12766 return ret;
12767}
12768
12769/*
12770 * Splits given Opt Number/Length into base and ext values.
12771 *
12772 * Helper function.
12773 */
12774static int coap_split_opt(uint32_t value, uint8_t *base, uint16_t *ext) {
12775 int ret = 0;
12776
12777 if (value < 13) {
12778 *base = value;
12779 } else if (value >= 13 && value <= 0xFF + 13) {
12780 *base = 13;
12781 *ext = value - 13;
12782 ret = sizeof(uint8_t);
12783 } else if (value > 0xFF + 13 && value <= 0xFFFF + 269) {
12784 *base = 14;
12785 *ext = value - 269;
12786 ret = sizeof(uint16_t);
12787 }
12788
12789 return ret;
12790}
12791
12792/*
12793 * Puts uint16_t (in network order) into given char stream.
12794 *
12795 * Helper function.
12796 */
12797static char *coap_add_uint16(char *ptr, uint16_t val) {
12798 *ptr = val >> 8;
12799 ptr++;
12800 *ptr = val & 0x00FF;
12801 ptr++;
12802 return ptr;
12803}
12804
12805/*
12806 * Puts extended value of Opt Number/Length into given char stream.
12807 *
12808 * Helper function.
12809 */
12810static char *coap_add_opt_info(char *ptr, uint16_t val, size_t len) {
12811 if (len == sizeof(uint8_t)) {
12812 *ptr = (char) val;
12813 ptr++;
12814 } else if (len == sizeof(uint16_t)) {
12815 ptr = coap_add_uint16(ptr, val);
12816 }
12817
12818 return ptr;
12819}
12820
12821/*
12822 * Verifies given mg_coap_message and calculates message size for it.
12823 *
12824 * Helper function.
12825 */
12827 size_t *len) {
12828 struct mg_coap_option *opt;
12830
12831 *len = 4; /* header */
12832 if (cm->msg_type > MG_COAP_MSG_MAX) {
12834 }
12835 if (cm->token.len > 8) {
12837 }
12838 if (cm->code_class > 7) {
12840 }
12841 if (cm->code_detail > 31) {
12843 }
12844
12845 *len += cm->token.len;
12846 if (cm->payload.len != 0) {
12847 *len += cm->payload.len + 1; /* ... + 1; add payload marker */
12848 }
12849
12850 opt = cm->options;
12851 prev_opt_number = 0;
12852 while (opt != NULL) {
12853 *len += 1; /* basic delta/length */
12854 *len += coap_get_ext_opt_size(opt->number - prev_opt_number);
12855 *len += coap_get_ext_opt_size((uint32_t) opt->value.len);
12856 /*
12857 * Current implementation performs check if
12858 * option_number > previous option_number and produces an error
12859 * TODO(alashkin): write design doc with limitations
12860 * May be resorting is more suitable solution.
12861 */
12862 if ((opt->next != NULL && opt->number > opt->next->number) ||
12863 opt->value.len > 0xFFFF + 269 ||
12864 opt->number - prev_opt_number > 0xFFFF + 269) {
12866 }
12867 *len += opt->value.len;
12868 prev_opt_number = opt->number;
12869 opt = opt->next;
12870 }
12871
12872 return 0;
12873}
12874
12876 struct mg_coap_option *opt;
12878 size_t prev_io_len, packet_size;
12879 char *ptr;
12880
12882 if (res != 0) {
12883 return res;
12884 }
12885
12886 /* saving previous lenght to handle non-empty mbuf */
12887 prev_io_len = io->len;
12888 if (mbuf_append(io, NULL, packet_size) == 0) return MG_COAP_ERROR;
12889 ptr = io->buf + prev_io_len;
12890
12891 /*
12892 * since cm is verified, it is possible to use bits shift operator
12893 * without additional zeroing of unused bits
12894 */
12895
12896 /* ver: 2 bits, msg_type: 2 bits, toklen: 4 bits */
12897 *ptr = (1 << 6) | (cm->msg_type << 4) | (uint8_t)(cm->token.len);
12898 ptr++;
12899
12900 /* code class: 3 bits, code detail: 5 bits */
12901 *ptr = (cm->code_class << 5) | (cm->code_detail);
12902 ptr++;
12903
12904 ptr = coap_add_uint16(ptr, cm->msg_id);
12905
12906 if (cm->token.len != 0) {
12907 memcpy(ptr, cm->token.p, cm->token.len);
12908 ptr += cm->token.len;
12909 }
12910
12911 opt = cm->options;
12912 prev_opt_number = 0;
12913 while (opt != NULL) {
12915 uint16_t delta_ext = 0, length_ext = 0;
12916
12917 size_t opt_delta_len =
12919 size_t opt_lenght_len =
12921
12922 *ptr = (delta_base << 4) | length_base;
12923 ptr++;
12924
12927
12928 if (opt->value.len != 0) {
12929 memcpy(ptr, opt->value.p, opt->value.len);
12930 ptr += opt->value.len;
12931 }
12932
12933 prev_opt_number = opt->number;
12934 opt = opt->next;
12935 }
12936
12937 if (cm->payload.len != 0) {
12938 *ptr = (char) -1;
12939 ptr++;
12940 memcpy(ptr, cm->payload.p, cm->payload.len);
12941 }
12942
12943 return 0;
12944}
12945
12947 struct mg_coap_message *cm) {
12948 struct mbuf packet_out;
12950
12951 mbuf_init(&packet_out, 0);
12953 if (compose_res != 0) {
12954 return compose_res; /* LCOV_EXCL_LINE */
12955 }
12956
12957 mg_send(nc, packet_out.buf, (int) packet_out.len);
12959
12960 return 0;
12961}
12962
12964 struct mg_coap_message cm;
12965 memset(&cm, 0, sizeof(cm));
12966 cm.msg_type = MG_COAP_MSG_ACK;
12967 cm.msg_id = msg_id;
12968
12969 return mg_coap_send_message(nc, &cm);
12970}
12971
12972static void coap_handler(struct mg_connection *nc, int ev,
12973 void *ev_data MG_UD_ARG(void *user_data)) {
12974 struct mbuf *io = &nc->recv_mbuf;
12975 struct mg_coap_message cm;
12977
12978 memset(&cm, 0, sizeof(cm));
12979
12980 nc->handler(nc, ev, ev_data MG_UD_ARG(user_data));
12981
12982 switch (ev) {
12983 case MG_EV_RECV:
12985 if ((parse_res & MG_COAP_IGNORE) == 0) {
12986 if ((cm.flags & MG_COAP_NOT_ENOUGH_DATA) != 0) {
12987 /*
12988 * Since we support UDP only
12989 * MG_COAP_NOT_ENOUGH_DATA == MG_COAP_FORMAT_ERROR
12990 */
12991 cm.flags |= MG_COAP_FORMAT_ERROR; /* LCOV_EXCL_LINE */
12992 } /* LCOV_EXCL_LINE */
12993 nc->handler(nc, MG_COAP_EVENT_BASE + cm.msg_type,
12994 &cm MG_UD_ARG(user_data));
12995 }
12996
12998 mbuf_remove(io, io->len);
12999 break;
13000 }
13001}
13002/*
13003 * Attach built-in CoAP event handler to the given connection.
13004 *
13005 * The user-defined event handler will receive following extra events:
13006 *
13007 * - MG_EV_COAP_CON
13008 * - MG_EV_COAP_NOC
13009 * - MG_EV_COAP_ACK
13010 * - MG_EV_COAP_RST
13011 */
13012int mg_set_protocol_coap(struct mg_connection *nc) {
13013 /* supports UDP only */
13014 if ((nc->flags & MG_F_UDP) == 0) {
13015 return -1;
13016 }
13017
13019
13020 return 0;
13021}
13022
13023#endif /* MG_ENABLE_COAP */
13024#ifdef MG_MODULE_LINES
13025#line 1 "mongoose/src/mg_sntp.c"
13026#endif
13027/*
13028 * Copyright (c) 2016 Cesanta Software Limited
13029 * All rights reserved
13030 */
13031
13032/* Amalgamated: #include "mg_internal.h" */
13033/* Amalgamated: #include "mg_sntp.h" */
13034/* Amalgamated: #include "mg_util.h" */
13035
13036#if MG_ENABLE_SNTP
13037
13038#define SNTP_TIME_OFFSET 2208988800
13039
13040#ifndef SNTP_TIMEOUT
13041#define SNTP_TIMEOUT 10
13042#endif
13043
13044#ifndef SNTP_ATTEMPTS
13045#define SNTP_ATTEMPTS 3
13046#endif
13047
13049 return (val & 0xFFFFFFFF00000000) >> 32;
13050}
13051
13053 uint64_t tmp = (val & 0x00000000FFFFFFFF);
13054 tmp *= 1000000;
13055 tmp >>= 32;
13056 return tmp;
13057}
13058
13059static void mg_ntp_to_tv(uint64_t val, struct timeval *tv) {
13060 uint64_t tmp;
13061 tmp = mg_get_sec(val);
13063 tv->tv_sec = tmp;
13064 tv->tv_usec = mg_get_usec(val);
13065}
13066
13067static void mg_get_ntp_ts(const char *ntp, uint64_t *val) {
13068 uint32_t tmp;
13069 memcpy(&tmp, ntp, sizeof(tmp));
13070 tmp = ntohl(tmp);
13071 *val = (uint64_t) tmp << 32;
13072 memcpy(&tmp, ntp + 4, sizeof(tmp));
13073 tmp = ntohl(tmp);
13074 *val |= tmp;
13075}
13076
13077void mg_sntp_send_request(struct mg_connection *c) {
13078 uint8_t buf[48] = {0};
13079 /*
13080 * header - 8 bit:
13081 * LI (2 bit) - 3 (not in sync), VN (3 bit) - 4 (version),
13082 * mode (3 bit) - 3 (client)
13083 */
13084 buf[0] = (3 << 6) | (4 << 3) | 3;
13085
13086/*
13087 * Next fields should be empty in client request
13088 * stratum, 8 bit
13089 * poll interval, 8 bit
13090 * rrecision, 8 bit
13091 * root delay, 32 bit
13092 * root dispersion, 32 bit
13093 * ref id, 32 bit
13094 * ref timestamp, 64 bit
13095 * originate Timestamp, 64 bit
13096 * receive Timestamp, 64 bit
13097*/
13098
13099/*
13100 * convert time to sntp format (sntp starts from 00:00:00 01.01.1900)
13101 * according to rfc868 it is 2208988800L sec
13102 * this information is used to correct roundtrip delay
13103 * but if local clock is absolutely broken (and doesn't work even
13104 * as simple timer), it is better to disable it
13105*/
13106#ifndef MG_SNTP_NO_DELAY_CORRECTION
13107 uint32_t sec;
13109 memcpy(&buf[40], &sec, sizeof(sec));
13110#endif
13111
13112 mg_send(c, buf, sizeof(buf));
13113}
13114
13115#ifndef MG_SNTP_NO_DELAY_CORRECTION
13117 /* roundloop delay = (T4 - T1) - (T3 - T2) */
13118 uint64_t d1 = ((mg_time() + SNTP_TIME_OFFSET) * 1000000) -
13119 (mg_get_sec(t1) * 1000000 + mg_get_usec(t1));
13120 uint64_t d2 = (mg_get_sec(t3) * 1000000 + mg_get_usec(t3)) -
13121 (mg_get_sec(t2) * 1000000 + mg_get_usec(t2));
13122
13123 return (d1 > d2) ? d1 - d2 : 0;
13124}
13125#endif
13126
13127MG_INTERNAL int mg_sntp_parse_reply(const char *buf, int len,
13128 struct mg_sntp_message *msg) {
13129 uint8_t hdr;
13130 uint64_t trsm_ts_T3, delay = 0;
13131 int mode;
13132 struct timeval tv;
13133
13134 if (len < 48) {
13135 return -1;
13136 }
13137
13138 hdr = buf[0];
13139
13140 if ((hdr & 0x38) >> 3 != 4) {
13141 /* Wrong version */
13142 return -1;
13143 }
13144
13145 mode = hdr & 0x7;
13146 if (mode != 4 && mode != 5) {
13147 /* Not a server reply */
13148 return -1;
13149 }
13150
13151 memset(msg, 0, sizeof(*msg));
13152
13153 msg->kiss_of_death = (buf[1] == 0); /* Server asks to not send requests */
13154
13155 mg_get_ntp_ts(&buf[40], &trsm_ts_T3);
13156
13157#ifndef MG_SNTP_NO_DELAY_CORRECTION
13158 {
13160 mg_get_ntp_ts(&buf[24], &orig_ts_T1);
13161 mg_get_ntp_ts(&buf[32], &recv_ts_T2);
13163 }
13164#endif
13165
13167
13168 msg->time = (double) tv.tv_sec + (((double) tv.tv_usec + delay) / 1000000.0);
13169
13170 return 0;
13171}
13172
13173static void mg_sntp_handler(struct mg_connection *c, int ev,
13174 void *ev_data MG_UD_ARG(void *user_data)) {
13175 struct mbuf *io = &c->recv_mbuf;
13176 struct mg_sntp_message msg;
13177
13178 c->handler(c, ev, ev_data MG_UD_ARG(user_data));
13179
13180 switch (ev) {
13181 case MG_EV_RECV: {
13182 if (mg_sntp_parse_reply(io->buf, io->len, &msg) < 0) {
13183 DBG(("Invalid SNTP packet received (%d)", (int) io->len));
13184 c->handler(c, MG_SNTP_MALFORMED_REPLY, NULL MG_UD_ARG(user_data));
13185 } else {
13186 c->handler(c, MG_SNTP_REPLY, (void *) &msg MG_UD_ARG(user_data));
13187 }
13188
13189 mbuf_remove(io, io->len);
13190 break;
13191 }
13192 }
13193}
13194
13196 if ((c->flags & MG_F_UDP) == 0) {
13197 return -1;
13198 }
13199
13200 c->proto_handler = mg_sntp_handler;
13201
13202 return 0;
13203}
13204
13205struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr,
13206 MG_CB(mg_event_handler_t event_handler,
13207 void *user_data),
13208 const char *sntp_server_name) {
13209 struct mg_connection *c = NULL;
13210 char url[100], *p_url = url;
13211 const char *proto = "", *port = "", *tmp;
13212
13213 /* If port is not specified, use default (123) */
13214 tmp = strchr(sntp_server_name, ':');
13215 if (tmp != NULL && *(tmp + 1) == '/') {
13216 tmp = strchr(tmp + 1, ':');
13217 }
13218
13219 if (tmp == NULL) {
13220 port = ":123";
13221 }
13222
13223 /* Add udp:// if needed */
13224 if (strncmp(sntp_server_name, "udp://", 6) != 0) {
13225 proto = "udp://";
13226 }
13227
13228 mg_asprintf(&p_url, sizeof(url), "%s%s%s", proto, sntp_server_name, port);
13229
13230 c = mg_connect(mgr, p_url, event_handler MG_UD_ARG(user_data));
13231
13232 if (c == NULL) {
13233 goto cleanup;
13234 }
13235
13237
13238cleanup:
13239 if (p_url != url) {
13240 MG_FREE(p_url);
13241 }
13242
13243 return c;
13244}
13245
13246struct sntp_data {
13248 int count;
13249};
13250
13251static void mg_sntp_util_ev_handler(struct mg_connection *c, int ev,
13252 void *ev_data MG_UD_ARG(void *user_data)) {
13253#if !MG_ENABLE_CALLBACK_USERDATA
13254 void *user_data = c->user_data;
13255#endif
13256 struct sntp_data *sd = (struct sntp_data *) user_data;
13257
13258 switch (ev) {
13259 case MG_EV_CONNECT:
13260 if (*(int *) ev_data != 0) {
13261 mg_call(c, sd->hander, c->user_data, MG_SNTP_FAILED, NULL);
13262 break;
13263 }
13264 /* fallthrough */
13265 case MG_EV_TIMER:
13266 if (sd->count <= SNTP_ATTEMPTS) {
13268 mg_set_timer(c, mg_time() + 10);
13269 sd->count++;
13270 } else {
13271 mg_call(c, sd->hander, c->user_data, MG_SNTP_FAILED, NULL);
13272 c->flags |= MG_F_CLOSE_IMMEDIATELY;
13273 }
13274 break;
13276 mg_call(c, sd->hander, c->user_data, MG_SNTP_FAILED, NULL);
13277 c->flags |= MG_F_CLOSE_IMMEDIATELY;
13278 break;
13279 case MG_SNTP_REPLY:
13280 mg_call(c, sd->hander, c->user_data, MG_SNTP_REPLY, ev_data);
13281 c->flags |= MG_F_CLOSE_IMMEDIATELY;
13282 break;
13283 case MG_EV_CLOSE:
13284 MG_FREE(user_data);
13285 c->user_data = NULL;
13286 break;
13287 }
13288}
13289
13291 mg_event_handler_t event_handler,
13292 const char *sntp_server_name) {
13293 struct mg_connection *c;
13294 struct sntp_data *sd = (struct sntp_data *) MG_CALLOC(1, sizeof(*sd));
13295 if (sd == NULL) {
13296 return NULL;
13297 }
13298
13301 if (c == NULL) {
13302 MG_FREE(sd);
13303 return NULL;
13304 }
13305
13306 sd->hander = event_handler;
13307#if !MG_ENABLE_CALLBACK_USERDATA
13308 c->user_data = sd;
13309#endif
13310
13311 return c;
13312}
13313
13314#endif /* MG_ENABLE_SNTP */
13315#ifdef MG_MODULE_LINES
13316#line 1 "mongoose/src/mg_socks.c"
13317#endif
13318/*
13319 * Copyright (c) 2017 Cesanta Software Limited
13320 * All rights reserved
13321 */
13322
13323#if MG_ENABLE_SOCKS
13324
13325/* Amalgamated: #include "mg_socks.h" */
13326/* Amalgamated: #include "mg_internal.h" */
13327
13328/*
13329 * https://www.ietf.org/rfc/rfc1928.txt paragraph 3, handle client handshake
13330 *
13331 * +----+----------+----------+
13332 * |VER | NMETHODS | METHODS |
13333 * +----+----------+----------+
13334 * | 1 | 1 | 1 to 255 |
13335 * +----+----------+----------+
13336 */
13337static void mg_socks5_handshake(struct mg_connection *c) {
13338 struct mbuf *r = &c->recv_mbuf;
13339 if (r->buf[0] != MG_SOCKS_VERSION) {
13340 c->flags |= MG_F_CLOSE_IMMEDIATELY;
13341 } else if (r->len > 2 && (size_t) r->buf[1] + 2 <= r->len) {
13342 /* https://www.ietf.org/rfc/rfc1928.txt paragraph 3 */
13344 int i;
13345 for (i = 2; i < r->buf[1] + 2; i++) {
13346 /* TODO(lsm): support other auth methods */
13347 if (r->buf[i] == MG_SOCKS_HANDSHAKE_NOAUTH) reply[1] = r->buf[i];
13348 }
13349 mbuf_remove(r, 2 + r->buf[1]);
13350 mg_send(c, reply, sizeof(reply));
13351 c->flags |= MG_SOCKS_HANDSHAKE_DONE; /* Mark handshake done */
13352 }
13353}
13354
13355static void disband(struct mg_connection *c) {
13356 struct mg_connection *c2 = (struct mg_connection *) c->user_data;
13357 if (c2 != NULL) {
13358 c2->flags |= MG_F_SEND_AND_CLOSE;
13359 c2->user_data = NULL;
13360 }
13361 c->flags |= MG_F_SEND_AND_CLOSE;
13362 c->user_data = NULL;
13363}
13364
13365static void relay_data(struct mg_connection *c) {
13366 struct mg_connection *c2 = (struct mg_connection *) c->user_data;
13367 if (c2 != NULL) {
13368 mg_send(c2, c->recv_mbuf.buf, c->recv_mbuf.len);
13369 mbuf_remove(&c->recv_mbuf, c->recv_mbuf.len);
13370 } else {
13371 c->flags |= MG_F_SEND_AND_CLOSE;
13372 }
13373}
13374
13375static void serv_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
13376 if (ev == MG_EV_CLOSE) {
13377 disband(c);
13378 } else if (ev == MG_EV_RECV) {
13379 relay_data(c);
13380 } else if (ev == MG_EV_CONNECT) {
13381 int res = *(int *) ev_data;
13382 if (res != 0) LOG(LL_ERROR, ("connect error: %d", res));
13383 }
13384}
13385
13386static void mg_socks5_connect(struct mg_connection *c, const char *addr) {
13388 serv->user_data = c;
13389 c->user_data = serv;
13390}
13391
13392/*
13393 * Request, https://www.ietf.org/rfc/rfc1928.txt paragraph 4
13394 *
13395 * +----+-----+-------+------+----------+----------+
13396 * |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
13397 * +----+-----+-------+------+----------+----------+
13398 * | 1 | 1 | X'00' | 1 | Variable | 2 |
13399 * +----+-----+-------+------+----------+----------+
13400 */
13401static void mg_socks5_handle_request(struct mg_connection *c) {
13402 struct mbuf *r = &c->recv_mbuf;
13403 unsigned char *p = (unsigned char *) r->buf;
13404 unsigned char addr_len = 4, reply = MG_SOCKS_SUCCESS;
13405 int ver, cmd, atyp;
13406 char addr[300];
13407
13408 if (r->len < 8) return; /* return if not fully buffered. min DST.ADDR is 2 */
13409 ver = p[0];
13410 cmd = p[1];
13411 atyp = p[3];
13412
13413 /* TODO(lsm): support other commands */
13414 if (ver != MG_SOCKS_VERSION || cmd != MG_SOCKS_CMD_CONNECT) {
13416 } else if (atyp == MG_SOCKS_ADDR_IPV4) {
13417 addr_len = 4;
13418 if (r->len < (size_t) addr_len + 6) return; /* return if not buffered */
13419 snprintf(addr, sizeof(addr), "%d.%d.%d.%d:%d", p[4], p[5], p[6], p[7],
13420 p[8] << 8 | p[9]);
13422 } else if (atyp == MG_SOCKS_ADDR_IPV6) {
13423 addr_len = 16;
13424 if (r->len < (size_t) addr_len + 6) return; /* return if not buffered */
13425 snprintf(addr, sizeof(addr), "[%x:%x:%x:%x:%x:%x:%x:%x]:%d",
13426 p[4] << 8 | p[5], p[6] << 8 | p[7], p[8] << 8 | p[9],
13427 p[10] << 8 | p[11], p[12] << 8 | p[13], p[14] << 8 | p[15],
13428 p[16] << 8 | p[17], p[18] << 8 | p[19], p[20] << 8 | p[21]);
13430 } else if (atyp == MG_SOCKS_ADDR_DOMAIN) {
13431 addr_len = p[4] + 1;
13432 if (r->len < (size_t) addr_len + 6) return; /* return if not buffered */
13433 snprintf(addr, sizeof(addr), "%.*s:%d", p[4], p + 5,
13434 p[4 + addr_len] << 8 | p[4 + addr_len + 1]);
13436 } else {
13438 }
13439
13440 /*
13441 * Reply, https://www.ietf.org/rfc/rfc1928.txt paragraph 5
13442 *
13443 * +----+-----+-------+------+----------+----------+
13444 * |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
13445 * +----+-----+-------+------+----------+----------+
13446 * | 1 | 1 | X'00' | 1 | Variable | 2 |
13447 * +----+-----+-------+------+----------+----------+
13448 */
13449 {
13450 unsigned char buf[] = {MG_SOCKS_VERSION, reply, 0};
13451 mg_send(c, buf, sizeof(buf));
13452 }
13453 mg_send(c, r->buf + 3, addr_len + 1 + 2);
13454
13455 mbuf_remove(r, 6 + addr_len); /* Remove request from the input stream */
13456 c->flags |= MG_SOCKS_CONNECT_DONE; /* Mark ourselves as connected */
13457}
13458
13459static void socks_handler(struct mg_connection *c, int ev, void *ev_data) {
13460 if (ev == MG_EV_RECV) {
13462 if (c->flags & MG_SOCKS_HANDSHAKE_DONE &&
13463 !(c->flags & MG_SOCKS_CONNECT_DONE)) {
13465 }
13466 if (c->flags & MG_SOCKS_CONNECT_DONE) relay_data(c);
13467 } else if (ev == MG_EV_CLOSE) {
13468 disband(c);
13469 }
13470 (void) ev_data;
13471}
13472
13474 c->proto_handler = socks_handler;
13475}
13476#endif
13477#ifdef MG_MODULE_LINES
13478#line 1 "common/platforms/cc3200/cc3200_libc.c"
13479#endif
13480/*
13481 * Copyright (c) 2014-2018 Cesanta Software Limited
13482 * All rights reserved
13483 *
13484 * Licensed under the Apache License, Version 2.0 (the ""License"");
13485 * you may not use this file except in compliance with the License.
13486 * You may obtain a copy of the License at
13487 *
13488 * http://www.apache.org/licenses/LICENSE-2.0
13489 *
13490 * Unless required by applicable law or agreed to in writing, software
13491 * distributed under the License is distributed on an ""AS IS"" BASIS,
13492 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13493 * See the License for the specific language governing permissions and
13494 * limitations under the License.
13495 */
13496
13497#if CS_PLATFORM == CS_P_CC3200
13498
13499/* Amalgamated: #include "common/mg_mem.h" */
13500#include <stdio.h>
13501#include <string.h>
13502
13503#ifndef __TI_COMPILER_VERSION__
13504#include <reent.h>
13505#include <sys/stat.h>
13506#include <sys/time.h>
13507#include <unistd.h>
13508#endif
13509
13510#include <inc/hw_types.h>
13511#include <inc/hw_memmap.h>
13512#include <driverlib/prcm.h>
13513#include <driverlib/rom.h>
13514#include <driverlib/rom_map.h>
13515#include <driverlib/uart.h>
13516#include <driverlib/utils.h>
13517
13518#define CONSOLE_UART UARTA0_BASE
13519
13520#ifdef __TI_COMPILER_VERSION__
13521int asprintf(char **strp, const char *fmt, ...) {
13522 va_list ap;
13523 int len;
13524
13525 *strp = MG_MALLOC(BUFSIZ);
13526 if (*strp == NULL) return -1;
13527
13528 va_start(ap, fmt);
13529 len = vsnprintf(*strp, BUFSIZ, fmt, ap);
13530 va_end(ap);
13531
13532 if (len > 0) {
13533 *strp = MG_REALLOC(*strp, len + 1);
13534 if (*strp == NULL) return -1;
13535 }
13536
13537 if (len >= BUFSIZ) {
13538 va_start(ap, fmt);
13539 len = vsnprintf(*strp, len + 1, fmt, ap);
13540 va_end(ap);
13541 }
13542
13543 return len;
13544}
13545
13546#if MG_TI_NO_HOST_INTERFACE
13547time_t HOSTtime() {
13548 struct timeval tp;
13549 gettimeofday(&tp, NULL);
13550 return tp.tv_sec;
13551}
13552#endif
13553
13554#endif /* __TI_COMPILER_VERSION__ */
13555
13556void fprint_str(FILE *fp, const char *str) {
13557 while (*str != '\0') {
13558 if (*str == '\n') MAP_UARTCharPut(CONSOLE_UART, '\r');
13560 }
13561}
13562
13563void _exit(int status) {
13564 fprint_str(stderr, "_exit\n");
13565 /* cause an unaligned access exception, that will drop you into gdb */
13566 *(int *) 1 = status;
13567 while (1)
13568 ; /* avoid gcc warning because stdlib abort() has noreturn attribute */
13569}
13570
13571void _not_implemented(const char *what) {
13572 fprint_str(stderr, what);
13573 fprint_str(stderr, " is not implemented\n");
13574 _exit(42);
13575}
13576
13577int _kill(int pid, int sig) {
13578 (void) pid;
13579 (void) sig;
13580 _not_implemented("_kill");
13581 return -1;
13582}
13583
13584int _getpid() {
13585 fprint_str(stderr, "_getpid is not implemented\n");
13586 return 42;
13587}
13588
13589int _isatty(int fd) {
13590 /* 0, 1 and 2 are TTYs. */
13591 return fd < 2;
13592}
13593
13594#endif /* CS_PLATFORM == CS_P_CC3200 */
13595#ifdef MG_MODULE_LINES
13596#line 1 "common/platforms/msp432/msp432_libc.c"
13597#endif
13598/*
13599 * Copyright (c) 2014-2018 Cesanta Software Limited
13600 * All rights reserved
13601 *
13602 * Licensed under the Apache License, Version 2.0 (the ""License"");
13603 * you may not use this file except in compliance with the License.
13604 * You may obtain a copy of the License at
13605 *
13606 * http://www.apache.org/licenses/LICENSE-2.0
13607 *
13608 * Unless required by applicable law or agreed to in writing, software
13609 * distributed under the License is distributed on an ""AS IS"" BASIS,
13610 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13611 * See the License for the specific language governing permissions and
13612 * limitations under the License.
13613 */
13614
13615#if CS_PLATFORM == CS_P_MSP432
13616
13617#include <ti/sysbios/BIOS.h>
13618#include <ti/sysbios/knl/Clock.h>
13619
13620int gettimeofday(struct timeval *tp, void *tzp) {
13622 tp->tv_sec = ticks / 1000;
13623 tp->tv_usec = (ticks % 1000) * 1000;
13624 return 0;
13625}
13626
13627#endif /* CS_PLATFORM == CS_P_MSP432 */
13628#ifdef MG_MODULE_LINES
13629#line 1 "common/platforms/nrf5/nrf5_libc.c"
13630#endif
13631/*
13632 * Copyright (c) 2014-2018 Cesanta Software Limited
13633 * All rights reserved
13634 *
13635 * Licensed under the Apache License, Version 2.0 (the ""License"");
13636 * you may not use this file except in compliance with the License.
13637 * You may obtain a copy of the License at
13638 *
13639 * http://www.apache.org/licenses/LICENSE-2.0
13640 *
13641 * Unless required by applicable law or agreed to in writing, software
13642 * distributed under the License is distributed on an ""AS IS"" BASIS,
13643 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13644 * See the License for the specific language governing permissions and
13645 * limitations under the License.
13646 */
13647
13648#if (CS_PLATFORM == CS_P_NRF51 || CS_PLATFORM == CS_P_NRF52) && \
13649 defined(__ARMCC_VERSION)
13650int gettimeofday(struct timeval *tp, void *tzp) {
13651 /* TODO */
13652 tp->tv_sec = 0;
13653 tp->tv_usec = 0;
13654 return 0;
13655}
13656#endif
13657#ifdef MG_MODULE_LINES
13658#line 1 "common/platforms/simplelink/sl_fs_slfs.h"
13659#endif
13660/*
13661 * Copyright (c) 2014-2018 Cesanta Software Limited
13662 * All rights reserved
13663 *
13664 * Licensed under the Apache License, Version 2.0 (the ""License"");
13665 * you may not use this file except in compliance with the License.
13666 * You may obtain a copy of the License at
13667 *
13668 * http://www.apache.org/licenses/LICENSE-2.0
13669 *
13670 * Unless required by applicable law or agreed to in writing, software
13671 * distributed under the License is distributed on an ""AS IS"" BASIS,
13672 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13673 * See the License for the specific language governing permissions and
13674 * limitations under the License.
13675 */
13676
13677#ifndef CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_
13678#define CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_
13679
13680#if defined(MG_FS_SLFS)
13681
13682#include <stdio.h>
13683#ifndef __TI_COMPILER_VERSION__
13684#include <unistd.h>
13685#include <sys/stat.h>
13686#endif
13687
13688#define MAX_OPEN_SLFS_FILES 8
13689
13690/* Indirect libc interface - same functions, different names. */
13691int fs_slfs_open(const char *pathname, int flags, mode_t mode);
13692int fs_slfs_close(int fd);
13693ssize_t fs_slfs_read(int fd, void *buf, size_t count);
13694ssize_t fs_slfs_write(int fd, const void *buf, size_t count);
13695int fs_slfs_stat(const char *pathname, struct stat *s);
13696int fs_slfs_fstat(int fd, struct stat *s);
13697off_t fs_slfs_lseek(int fd, off_t offset, int whence);
13698int fs_slfs_unlink(const char *filename);
13699int fs_slfs_rename(const char *from, const char *to);
13700
13701void fs_slfs_set_file_size(const char *name, size_t size);
13702void fs_slfs_set_file_flags(const char *name, uint32_t flags, uint32_t *token);
13703void fs_slfs_unset_file_flags(const char *name);
13704
13705#endif /* defined(MG_FS_SLFS) */
13706
13707#endif /* CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_ */
13708#ifdef MG_MODULE_LINES
13709#line 1 "common/platforms/simplelink/sl_fs_slfs.c"
13710#endif
13711/*
13712 * Copyright (c) 2014-2018 Cesanta Software Limited
13713 * All rights reserved
13714 *
13715 * Licensed under the Apache License, Version 2.0 (the ""License"");
13716 * you may not use this file except in compliance with the License.
13717 * You may obtain a copy of the License at
13718 *
13719 * http://www.apache.org/licenses/LICENSE-2.0
13720 *
13721 * Unless required by applicable law or agreed to in writing, software
13722 * distributed under the License is distributed on an ""AS IS"" BASIS,
13723 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13724 * See the License for the specific language governing permissions and
13725 * limitations under the License.
13726 */
13727
13728/* Standard libc interface to TI SimpleLink FS. */
13729
13730#if defined(MG_FS_SLFS) || defined(CC3200_FS_SLFS)
13731
13732/* Amalgamated: #include "common/platforms/simplelink/sl_fs_slfs.h" */
13733
13734#include <errno.h>
13735
13736#if CS_PLATFORM == CS_P_CC3200
13737#include <inc/hw_types.h>
13738#endif
13739
13740/* Amalgamated: #include "common/cs_dbg.h" */
13741/* Amalgamated: #include "common/mg_mem.h" */
13742
13743#if SL_MAJOR_VERSION_NUM < 2
13744int slfs_open(const unsigned char *fname, uint32_t flags, uint32_t *token) {
13745 _i32 fh;
13746 _i32 r = sl_FsOpen(fname, flags, (unsigned long *) token, &fh);
13747 return (r < 0 ? r : fh);
13748}
13749#else /* SL_MAJOR_VERSION_NUM >= 2 */
13750int slfs_open(const unsigned char *fname, uint32_t flags, uint32_t *token) {
13751 return sl_FsOpen(fname, flags, (unsigned long *) token);
13752}
13753#endif
13754
13755/* From sl_fs.c */
13756int set_errno(int e);
13757const char *drop_dir(const char *fname, bool *is_slfs);
13758
13759/*
13760 * With SLFS, you have to pre-declare max file size. Yes. Really.
13761 * 64K should be enough for everyone. Right?
13762 */
13763#ifndef FS_SLFS_MAX_FILE_SIZE
13764#define FS_SLFS_MAX_FILE_SIZE (64 * 1024)
13765#endif
13766
13767struct sl_file_open_info {
13768 char *name;
13769 size_t size;
13770 uint32_t flags;
13771 uint32_t *token;
13772};
13773
13774struct sl_fd_info {
13775 _i32 fh;
13776 _off_t pos;
13777 size_t size;
13778};
13779
13782
13783static struct sl_file_open_info *fs_slfs_find_foi(const char *name,
13784 bool create);
13785
13786static int sl_fs_to_errno(_i32 r) {
13787 DBG(("SL error: %d", (int) r));
13788 switch (r) {
13789 case SL_FS_OK:
13790 return 0;
13792 return EEXIST;
13794 return EINVAL;
13797 return ENOSPC;
13799 return ENOMEM;
13801 return ENOENT;
13803 return ENOTSUP;
13804 }
13805 return ENXIO;
13806}
13807
13808int fs_slfs_open(const char *pathname, int flags, mode_t mode) {
13809 int fd;
13810 for (fd = 0; fd < MAX_OPEN_SLFS_FILES; fd++) {
13811 if (s_sl_fds[fd].fh <= 0) break;
13812 }
13813 if (fd >= MAX_OPEN_SLFS_FILES) return set_errno(ENOMEM);
13814 struct sl_fd_info *fi = &s_sl_fds[fd];
13815
13816 /*
13817 * Apply path manipulations again, in case we got here directly
13818 * (via TI libc's "add_device").
13819 */
13821
13822 _u32 am = 0;
13823 fi->size = (size_t) -1;
13824 int rw = (flags & 3);
13825 size_t new_size = 0;
13826 struct sl_file_open_info *foi =
13827 fs_slfs_find_foi(pathname, false /* create */);
13828 if (foi != NULL) {
13829 LOG(LL_DEBUG, ("FOI for %s: %d 0x%x %p", pathname, (int) foi->size,
13830 (unsigned int) foi->flags, foi->token));
13831 }
13832 if (rw == O_RDONLY) {
13834 _i32 r = sl_FsGetInfo((const _u8 *) pathname, 0, &sl_fi);
13835 if (r == SL_FS_OK) {
13836 fi->size = SL_FI_FILE_SIZE(sl_fi);
13837 }
13838 am = SL_FS_READ;
13839 } else {
13840 if (!(flags & O_TRUNC) || (flags & O_APPEND)) {
13841 // FailFS files cannot be opened for append and will be truncated
13842 // when opened for write.
13843 return set_errno(ENOTSUP);
13844 }
13845 if (flags & O_CREAT) {
13846 if (foi->size > 0) {
13847 new_size = foi->size;
13848 } else {
13850 }
13852 } else {
13853 am = SL_FS_WRITE;
13854 }
13855#if SL_MAJOR_VERSION_NUM >= 2
13856 am |= SL_FS_OVERWRITE;
13857#endif
13858 }
13859 uint32_t *token = NULL;
13860 if (foi != NULL) {
13861 am |= foi->flags;
13862 token = foi->token;
13863 }
13864 fi->fh = slfs_open((_u8 *) pathname, am, token);
13865 LOG(LL_DEBUG, ("sl_FsOpen(%s, 0x%x, %p) sz %u = %d", pathname, (int) am,
13866 token, (unsigned int) new_size, (int) fi->fh));
13867 int r;
13868 if (fi->fh >= 0) {
13869 fi->pos = 0;
13870 r = fd;
13871 } else {
13872 r = set_errno(sl_fs_to_errno(fi->fh));
13873 }
13874 return r;
13875}
13876
13877int fs_slfs_close(int fd) {
13878 struct sl_fd_info *fi = &s_sl_fds[fd];
13879 if (fi->fh <= 0) return set_errno(EBADF);
13880 _i32 r = sl_FsClose(fi->fh, NULL, NULL, 0);
13881 LOG(LL_DEBUG, ("sl_FsClose(%d) = %d", (int) fi->fh, (int) r));
13882 s_sl_fds[fd].fh = -1;
13883 return set_errno(sl_fs_to_errno(r));
13884}
13885
13886ssize_t fs_slfs_read(int fd, void *buf, size_t count) {
13887 struct sl_fd_info *fi = &s_sl_fds[fd];
13888 if (fi->fh <= 0) return set_errno(EBADF);
13889 /* Simulate EOF. sl_FsRead @ file_size return SL_FS_ERR_OFFSET_OUT_OF_RANGE.
13890 */
13891 if (fi->pos == fi->size) return 0;
13892 _i32 r = sl_FsRead(fi->fh, fi->pos, buf, count);
13893 DBG(("sl_FsRead(%d, %d, %d) = %d", (int) fi->fh, (int) fi->pos, (int) count,
13894 (int) r));
13895 if (r >= 0) {
13896 fi->pos += r;
13897 return r;
13898 }
13899 return set_errno(sl_fs_to_errno(r));
13900}
13901
13902ssize_t fs_slfs_write(int fd, const void *buf, size_t count) {
13903 struct sl_fd_info *fi = &s_sl_fds[fd];
13904 if (fi->fh <= 0) return set_errno(EBADF);
13905 _i32 r = sl_FsWrite(fi->fh, fi->pos, (_u8 *) buf, count);
13906 DBG(("sl_FsWrite(%d, %d, %d) = %d", (int) fi->fh, (int) fi->pos, (int) count,
13907 (int) r));
13908 if (r >= 0) {
13909 fi->pos += r;
13910 return r;
13911 }
13912 return set_errno(sl_fs_to_errno(r));
13913}
13914
13915int fs_slfs_stat(const char *pathname, struct stat *s) {
13917 /*
13918 * Apply path manipulations again, in case we got here directly
13919 * (via TI libc's "add_device").
13920 */
13922 _i32 r = sl_FsGetInfo((const _u8 *) pathname, 0, &sl_fi);
13923 if (r == SL_FS_OK) {
13924 s->st_mode = S_IFREG | 0666;
13925 s->st_nlink = 1;
13926 s->st_size = SL_FI_FILE_SIZE(sl_fi);
13927 return 0;
13928 }
13929 return set_errno(sl_fs_to_errno(r));
13930}
13931
13932int fs_slfs_fstat(int fd, struct stat *s) {
13933 struct sl_fd_info *fi = &s_sl_fds[fd];
13934 if (fi->fh <= 0) return set_errno(EBADF);
13935 s->st_mode = 0666;
13936 s->st_mode = S_IFREG | 0666;
13937 s->st_nlink = 1;
13938 s->st_size = fi->size;
13939 return 0;
13940}
13941
13942off_t fs_slfs_lseek(int fd, off_t offset, int whence) {
13943 if (s_sl_fds[fd].fh <= 0) return set_errno(EBADF);
13944 switch (whence) {
13945 case SEEK_SET:
13946 s_sl_fds[fd].pos = offset;
13947 break;
13948 case SEEK_CUR:
13949 s_sl_fds[fd].pos += offset;
13950 break;
13951 case SEEK_END:
13952 return set_errno(ENOTSUP);
13953 }
13954 return 0;
13955}
13956
13957int fs_slfs_unlink(const char *pathname) {
13958 /*
13959 * Apply path manipulations again, in case we got here directly
13960 * (via TI libc's "add_device").
13961 */
13963 return set_errno(sl_fs_to_errno(sl_FsDel((const _u8 *) pathname, 0)));
13964}
13965
13966int fs_slfs_rename(const char *from, const char *to) {
13967 return set_errno(ENOTSUP);
13968}
13969
13970static struct sl_file_open_info *fs_slfs_find_foi(const char *name,
13971 bool create) {
13972 int i = 0;
13973 for (i = 0; i < MAX_OPEN_SLFS_FILES; i++) {
13974 if (s_sl_file_open_infos[i].name != NULL &&
13976 break;
13977 }
13978 }
13980 if (!create) return NULL;
13981 for (i = 0; i < MAX_OPEN_SLFS_FILES; i++) {
13982 if (s_sl_file_open_infos[i].name == NULL) break;
13983 }
13984 if (i == MAX_OPEN_SLFS_FILES) {
13985 i = 0; /* Evict a random slot. */
13986 }
13987 if (s_sl_file_open_infos[i].name != NULL) {
13989 }
13991 return &s_sl_file_open_infos[i];
13992}
13993
13994void fs_slfs_set_file_size(const char *name, size_t size) {
13995 struct sl_file_open_info *foi = fs_slfs_find_foi(name, true /* create */);
13996 foi->size = size;
13997}
13998
13999void fs_slfs_set_file_flags(const char *name, uint32_t flags, uint32_t *token) {
14000 struct sl_file_open_info *foi = fs_slfs_find_foi(name, true /* create */);
14001 foi->flags = flags;
14002 foi->token = token;
14003}
14004
14005void fs_slfs_unset_file_flags(const char *name) {
14006 struct sl_file_open_info *foi = fs_slfs_find_foi(name, false /* create */);
14007 if (foi == NULL) return;
14008 free(foi->name);
14009 memset(foi, 0, sizeof(*foi));
14010}
14011
14012#endif /* defined(MG_FS_SLFS) || defined(CC3200_FS_SLFS) */
14013#ifdef MG_MODULE_LINES
14014#line 1 "common/platforms/simplelink/sl_fs.c"
14015#endif
14016/*
14017 * Copyright (c) 2014-2018 Cesanta Software Limited
14018 * All rights reserved
14019 *
14020 * Licensed under the Apache License, Version 2.0 (the ""License"");
14021 * you may not use this file except in compliance with the License.
14022 * You may obtain a copy of the License at
14023 *
14024 * http://www.apache.org/licenses/LICENSE-2.0
14025 *
14026 * Unless required by applicable law or agreed to in writing, software
14027 * distributed under the License is distributed on an ""AS IS"" BASIS,
14028 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14029 * See the License for the specific language governing permissions and
14030 * limitations under the License.
14031 */
14032
14033#if MG_NET_IF == MG_NET_IF_SIMPLELINK && \
14034 (defined(MG_FS_SLFS) || defined(MG_FS_SPIFFS))
14035
14036int set_errno(int e) {
14037 errno = e;
14038 return (e == 0 ? 0 : -1);
14039}
14040
14041const char *drop_dir(const char *fname, bool *is_slfs) {
14042 if (is_slfs != NULL) {
14043 *is_slfs = (strncmp(fname, "SL:", 3) == 0);
14044 if (*is_slfs) fname += 3;
14045 }
14046 /* Drop "./", if any */
14047 if (fname[0] == '.' && fname[1] == '/') {
14048 fname += 2;
14049 }
14050 /*
14051 * Drop / if it is the only one in the path.
14052 * This allows use of /pretend/directories but serves /file.txt as normal.
14053 */
14054 if (fname[0] == '/' && strchr(fname + 1, '/') == NULL) {
14055 fname++;
14056 }
14057 return fname;
14058}
14059
14060#if !defined(MG_FS_NO_VFS)
14061
14062#include <errno.h>
14063#include <stdbool.h>
14064#include <stdio.h>
14065#include <stdlib.h>
14066#include <string.h>
14067#ifdef __TI_COMPILER_VERSION__
14068#include <file.h>
14069#endif
14070
14071/* Amalgamated: #include "common/cs_dbg.h" */
14072/* Amalgamated: #include "common/platform.h" */
14073
14074#ifdef CC3200_FS_SPIFFS
14075/* Amalgamated: #include "cc3200_fs_spiffs.h" */
14076#endif
14077
14078#ifdef MG_FS_SLFS
14079/* Amalgamated: #include "sl_fs_slfs.h" */
14080#endif
14081
14082#define NUM_SYS_FDS 3
14083#define SPIFFS_FD_BASE 10
14084#define SLFS_FD_BASE 100
14085
14086#if !defined(MG_UART_CHAR_PUT) && !defined(MG_UART_WRITE)
14087#if CS_PLATFORM == CS_P_CC3200
14088#include <inc/hw_types.h>
14089#include <inc/hw_memmap.h>
14090#include <driverlib/rom.h>
14091#include <driverlib/rom_map.h>
14092#include <driverlib/uart.h>
14093#define MG_UART_CHAR_PUT(fd, c) MAP_UARTCharPut(UARTA0_BASE, c);
14094#else
14095#define MG_UART_WRITE(fd, buf, len)
14096#endif /* CS_PLATFORM == CS_P_CC3200 */
14097#endif /* !MG_UART_CHAR_PUT */
14098
14099enum fd_type {
14100 FD_INVALID,
14101 FD_SYS,
14102#ifdef CC3200_FS_SPIFFS
14103 FD_SPIFFS,
14104#endif
14105#ifdef MG_FS_SLFS
14106 FD_SLFS
14107#endif
14108};
14109static int fd_type(int fd) {
14110 if (fd >= 0 && fd < NUM_SYS_FDS) return FD_SYS;
14111#ifdef CC3200_FS_SPIFFS
14113 return FD_SPIFFS;
14114 }
14115#endif
14116#ifdef MG_FS_SLFS
14117 if (fd >= SLFS_FD_BASE && fd < SLFS_FD_BASE + MAX_OPEN_SLFS_FILES) {
14118 return FD_SLFS;
14119 }
14120#endif
14121 return FD_INVALID;
14122}
14123
14124#if MG_TI_NO_HOST_INTERFACE
14125int open(const char *pathname, unsigned flags, int mode) {
14126#else
14127int _open(const char *pathname, int flags, mode_t mode) {
14128#endif
14129 int fd = -1;
14130 bool is_sl;
14131 const char *fname = drop_dir(pathname, &is_sl);
14132 if (is_sl) {
14133#ifdef MG_FS_SLFS
14134 fd = fs_slfs_open(fname, flags, mode);
14135 if (fd >= 0) fd += SLFS_FD_BASE;
14136#endif
14137 } else {
14138#ifdef CC3200_FS_SPIFFS
14139 fd = fs_spiffs_open(fname, flags, mode);
14140 if (fd >= 0) fd += SPIFFS_FD_BASE;
14141#endif
14142 }
14143 LOG(LL_DEBUG,
14144 ("open(%s, 0x%x) = %d, fname = %s", pathname, flags, fd, fname));
14145 return fd;
14146}
14147
14148int _stat(const char *pathname, struct stat *st) {
14149 int res = -1;
14150 bool is_sl;
14151 const char *fname = drop_dir(pathname, &is_sl);
14152 memset(st, 0, sizeof(*st));
14153 /* Simulate statting the root directory. */
14154 if (fname[0] == '\0' || strcmp(fname, ".") == 0) {
14155 st->st_ino = 0;
14156 st->st_mode = S_IFDIR | 0777;
14157 st->st_nlink = 1;
14158 st->st_size = 0;
14159 return 0;
14160 }
14161 if (is_sl) {
14162#ifdef MG_FS_SLFS
14164#endif
14165 } else {
14166#ifdef CC3200_FS_SPIFFS
14168#endif
14169 }
14170 LOG(LL_DEBUG, ("stat(%s) = %d; fname = %s", pathname, res, fname));
14171 return res;
14172}
14173
14174#if MG_TI_NO_HOST_INTERFACE
14175int close(int fd) {
14176#else
14177int _close(int fd) {
14178#endif
14179 int r = -1;
14180 switch (fd_type(fd)) {
14181 case FD_INVALID:
14182 r = set_errno(EBADF);
14183 break;
14184 case FD_SYS:
14185 r = set_errno(EACCES);
14186 break;
14187#ifdef CC3200_FS_SPIFFS
14188 case FD_SPIFFS:
14190 break;
14191#endif
14192#ifdef MG_FS_SLFS
14193 case FD_SLFS:
14194 r = fs_slfs_close(fd - SLFS_FD_BASE);
14195 break;
14196#endif
14197 }
14198 DBG(("close(%d) = %d", fd, r));
14199 return r;
14200}
14201
14202#if MG_TI_NO_HOST_INTERFACE
14203off_t lseek(int fd, off_t offset, int whence) {
14204#else
14205off_t _lseek(int fd, off_t offset, int whence) {
14206#endif
14207 int r = -1;
14208 switch (fd_type(fd)) {
14209 case FD_INVALID:
14210 r = set_errno(EBADF);
14211 break;
14212 case FD_SYS:
14213 r = set_errno(ESPIPE);
14214 break;
14215#ifdef CC3200_FS_SPIFFS
14216 case FD_SPIFFS:
14218 break;
14219#endif
14220#ifdef MG_FS_SLFS
14221 case FD_SLFS:
14223 break;
14224#endif
14225 }
14226 DBG(("lseek(%d, %d, %d) = %d", fd, (int) offset, whence, r));
14227 return r;
14228}
14229
14230int _fstat(int fd, struct stat *s) {
14231 int r = -1;
14232 memset(s, 0, sizeof(*s));
14233 switch (fd_type(fd)) {
14234 case FD_INVALID:
14235 r = set_errno(EBADF);
14236 break;
14237 case FD_SYS: {
14238 /* Create barely passable stats for STD{IN,OUT,ERR}. */
14239 memset(s, 0, sizeof(*s));
14240 s->st_ino = fd;
14241 s->st_mode = S_IFCHR | 0666;
14242 r = 0;
14243 break;
14244 }
14245#ifdef CC3200_FS_SPIFFS
14246 case FD_SPIFFS:
14247 r = fs_spiffs_fstat(fd - SPIFFS_FD_BASE, s);
14248 break;
14249#endif
14250#ifdef MG_FS_SLFS
14251 case FD_SLFS:
14252 r = fs_slfs_fstat(fd - SLFS_FD_BASE, s);
14253 break;
14254#endif
14255 }
14256 DBG(("fstat(%d) = %d", fd, r));
14257 return r;
14258}
14259
14260#if MG_TI_NO_HOST_INTERFACE
14261int read(int fd, char *buf, unsigned count) {
14262#else
14263ssize_t _read(int fd, void *buf, size_t count) {
14264#endif
14265 int r = -1;
14266 switch (fd_type(fd)) {
14267 case FD_INVALID:
14268 r = set_errno(EBADF);
14269 break;
14270 case FD_SYS: {
14271 if (fd != 0) {
14272 r = set_errno(EACCES);
14273 break;
14274 }
14275 /* Should we allow reading from stdin = uart? */
14276 r = set_errno(ENOTSUP);
14277 break;
14278 }
14279#ifdef CC3200_FS_SPIFFS
14280 case FD_SPIFFS:
14281 r = fs_spiffs_read(fd - SPIFFS_FD_BASE, buf, count);
14282 break;
14283#endif
14284#ifdef MG_FS_SLFS
14285 case FD_SLFS:
14286 r = fs_slfs_read(fd - SLFS_FD_BASE, buf, count);
14287 break;
14288#endif
14289 }
14290 DBG(("read(%d, %u) = %d", fd, count, r));
14291 return r;
14292}
14293
14294#if MG_TI_NO_HOST_INTERFACE
14295int write(int fd, const char *buf, unsigned count) {
14296#else
14297ssize_t _write(int fd, const void *buf, size_t count) {
14298#endif
14299 int r = -1;
14300 switch (fd_type(fd)) {
14301 case FD_INVALID:
14302 r = set_errno(EBADF);
14303 break;
14304 case FD_SYS: {
14305 if (fd == 0) {
14306 r = set_errno(EACCES);
14307 break;
14308 }
14309#ifdef MG_UART_WRITE
14310 MG_UART_WRITE(fd, buf, count);
14311#elif defined(MG_UART_CHAR_PUT)
14312 {
14313 size_t i;
14314 for (i = 0; i < count; i++) {
14315 const char c = ((const char *) buf)[i];
14316 if (c == '\n') MG_UART_CHAR_PUT(fd, '\r');
14317 MG_UART_CHAR_PUT(fd, c);
14318 }
14319 }
14320#endif
14321 r = count;
14322 break;
14323 }
14324#ifdef CC3200_FS_SPIFFS
14325 case FD_SPIFFS:
14326 r = fs_spiffs_write(fd - SPIFFS_FD_BASE, buf, count);
14327 break;
14328#endif
14329#ifdef MG_FS_SLFS
14330 case FD_SLFS:
14331 r = fs_slfs_write(fd - SLFS_FD_BASE, buf, count);
14332 break;
14333#endif
14334 }
14335 return r;
14336}
14337
14338/*
14339 * On Newlib we override rename directly too, because the default
14340 * implementation using _link and _unlink doesn't work for us.
14341 */
14342#if MG_TI_NO_HOST_INTERFACE || defined(_NEWLIB_VERSION)
14343int rename(const char *frompath, const char *topath) {
14344 int r = -1;
14345 bool is_sl_from, is_sl_to;
14346 const char *from = drop_dir(frompath, &is_sl_from);
14347 const char *to = drop_dir(topath, &is_sl_to);
14348 if (is_sl_from || is_sl_to) {
14350 } else {
14351#ifdef CC3200_FS_SPIFFS
14352 r = fs_spiffs_rename(from, to);
14353#endif
14354 }
14355 DBG(("rename(%s, %s) = %d", from, to, r));
14356 return r;
14357}
14358#endif /* MG_TI_NO_HOST_INTERFACE || defined(_NEWLIB_VERSION) */
14359
14360#if MG_TI_NO_HOST_INTERFACE
14361int unlink(const char *pathname) {
14362#else
14363int _unlink(const char *pathname) {
14364#endif
14365 int r = -1;
14366 bool is_sl;
14367 const char *fname = drop_dir(pathname, &is_sl);
14368 if (is_sl) {
14369#ifdef MG_FS_SLFS
14370 r = fs_slfs_unlink(fname);
14371#endif
14372 } else {
14373#ifdef CC3200_FS_SPIFFS
14375#endif
14376 }
14377 DBG(("unlink(%s) = %d, fname = %s", pathname, r, fname));
14378 return r;
14379}
14380
14381#ifdef CC3200_FS_SPIFFS /* FailFS does not support listing files. */
14382DIR *opendir(const char *dir_name) {
14383 DIR *r = NULL;
14384 bool is_sl;
14386 if (is_sl) {
14387 r = NULL;
14389 } else {
14391 }
14392 DBG(("opendir(%s) = %p", dir_name, r));
14393 return r;
14394}
14395
14396struct dirent *readdir(DIR *dir) {
14397 struct dirent *res = fs_spiffs_readdir(dir);
14398 DBG(("readdir(%p) = %p", dir, res));
14399 return res;
14400}
14401
14402int closedir(DIR *dir) {
14403 int res = fs_spiffs_closedir(dir);
14404 DBG(("closedir(%p) = %d", dir, res));
14405 return res;
14406}
14407
14408int rmdir(const char *path) {
14409 return fs_spiffs_rmdir(path);
14410}
14411
14412int mkdir(const char *path, mode_t mode) {
14413 (void) path;
14414 (void) mode;
14415 /* for spiffs supports only root dir, which comes from mongoose as '.' */
14416 return (strlen(path) == 1 && *path == '.') ? 0 : ENOTDIR;
14417}
14418#endif
14419
14420int sl_fs_init(void) {
14421 int ret = 1;
14422#ifdef __TI_COMPILER_VERSION__
14423#ifdef MG_FS_SLFS
14424#pragma diag_push
14425#pragma diag_suppress 169 /* Nothing we can do about the prototype mismatch. \
14426 */
14429 fs_slfs_rename) == 0);
14430#pragma diag_pop
14431#endif
14432#endif
14433 return ret;
14434}
14435
14436#endif /* !defined(MG_FS_NO_VFS) */
14437#endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK && (defined(MG_FS_SLFS) || \
14438 defined(MG_FS_SPIFFS)) */
14439#ifdef MG_MODULE_LINES
14440#line 1 "common/platforms/simplelink/sl_socket.c"
14441#endif
14442/*
14443 * Copyright (c) 2014-2018 Cesanta Software Limited
14444 * All rights reserved
14445 *
14446 * Licensed under the Apache License, Version 2.0 (the ""License"");
14447 * you may not use this file except in compliance with the License.
14448 * You may obtain a copy of the License at
14449 *
14450 * http://www.apache.org/licenses/LICENSE-2.0
14451 *
14452 * Unless required by applicable law or agreed to in writing, software
14453 * distributed under the License is distributed on an ""AS IS"" BASIS,
14454 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14455 * See the License for the specific language governing permissions and
14456 * limitations under the License.
14457 */
14458
14459#if MG_NET_IF == MG_NET_IF_SIMPLELINK
14460
14461#include <errno.h>
14462#include <stdio.h>
14463
14464/* Amalgamated: #include "common/platform.h" */
14465
14466const char *inet_ntop(int af, const void *src, char *dst, socklen_t size) {
14467 int res;
14468 struct in_addr *in = (struct in_addr *) src;
14469 if (af != AF_INET) {
14470 errno = ENOTSUP;
14471 return NULL;
14472 }
14473 res = snprintf(dst, size, "%lu.%lu.%lu.%lu", SL_IPV4_BYTE(in->s_addr, 0),
14474 SL_IPV4_BYTE(in->s_addr, 1), SL_IPV4_BYTE(in->s_addr, 2),
14475 SL_IPV4_BYTE(in->s_addr, 3));
14476 return res > 0 ? dst : NULL;
14477}
14478
14479char *inet_ntoa(struct in_addr n) {
14480 static char a[16];
14481 return (char *) inet_ntop(AF_INET, &n, a, sizeof(a));
14482}
14483
14484int inet_pton(int af, const char *src, void *dst) {
14485 uint32_t a0, a1, a2, a3;
14486 uint8_t *db = (uint8_t *) dst;
14487 if (af != AF_INET) {
14488 errno = ENOTSUP;
14489 return 0;
14490 }
14491 if (sscanf(src, "%lu.%lu.%lu.%lu", &a0, &a1, &a2, &a3) != 4) {
14492 return 0;
14493 }
14494 *db = a3;
14495 *(db + 1) = a2;
14496 *(db + 2) = a1;
14497 *(db + 3) = a0;
14498 return 1;
14499}
14500
14501#endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */
14502#ifdef MG_MODULE_LINES
14503#line 1 "common/platforms/simplelink/sl_mg_task.c"
14504#endif
14505#if MG_NET_IF == MG_NET_IF_SIMPLELINK && !defined(MG_SIMPLELINK_NO_OSI)
14506
14507/* Amalgamated: #include "mg_task.h" */
14508
14509#include <oslib/osi.h>
14510
14511enum mg_q_msg_type {
14513};
14514struct mg_q_msg {
14515 enum mg_q_msg_type type;
14516 void (*cb)(struct mg_mgr *mgr, void *arg);
14517 void *arg;
14518};
14519static OsiMsgQ_t s_mg_q;
14520static void mg_task(void *arg);
14521
14523 if (osi_MsgQCreate(&s_mg_q, "MG", sizeof(struct mg_q_msg), 16) != OSI_OK) {
14524 return false;
14525 }
14526 if (osi_TaskCreate(mg_task, (const signed char *) "MG", stack_size,
14527 (void *) mg_init, priority, NULL) != OSI_OK) {
14528 return false;
14529 }
14530 return true;
14531}
14532
14533static void mg_task(void *arg) {
14534 struct mg_mgr mgr;
14536 mg_mgr_init(&mgr, NULL);
14537 mg_init(&mgr);
14538 while (1) {
14539 struct mg_q_msg msg;
14540 mg_mgr_poll(&mgr, 1);
14541 if (osi_MsgQRead(&s_mg_q, &msg, 1) != OSI_OK) continue;
14542 switch (msg.type) {
14543 case MG_Q_MSG_CB: {
14544 msg.cb(&mgr, msg.arg);
14545 }
14546 }
14547 }
14548}
14549
14550void mg_run_in_task(void (*cb)(struct mg_mgr *mgr, void *arg), void *cb_arg) {
14551 struct mg_q_msg msg = {MG_Q_MSG_CB, cb, cb_arg};
14553}
14554
14555#endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK && !defined(MG_SIMPLELINK_NO_OSI) \
14556 */
14557#ifdef MG_MODULE_LINES
14558#line 1 "common/platforms/simplelink/sl_net_if.h"
14559#endif
14560/*
14561 * Copyright (c) 2014-2018 Cesanta Software Limited
14562 * All rights reserved
14563 *
14564 * Licensed under the Apache License, Version 2.0 (the ""License"");
14565 * you may not use this file except in compliance with the License.
14566 * You may obtain a copy of the License at
14567 *
14568 * http://www.apache.org/licenses/LICENSE-2.0
14569 *
14570 * Unless required by applicable law or agreed to in writing, software
14571 * distributed under the License is distributed on an ""AS IS"" BASIS,
14572 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14573 * See the License for the specific language governing permissions and
14574 * limitations under the License.
14575 */
14576
14577#ifndef CS_COMMON_PLATFORMS_SIMPLELINK_SL_NET_IF_H_
14578#define CS_COMMON_PLATFORMS_SIMPLELINK_SL_NET_IF_H_
14579
14580/* Amalgamated: #include "mongoose/src/net_if.h" */
14581
14582#ifdef __cplusplus
14583extern "C" {
14584#endif /* __cplusplus */
14585
14586#ifndef MG_ENABLE_NET_IF_SIMPLELINK
14587#define MG_ENABLE_NET_IF_SIMPLELINK MG_NET_IF == MG_NET_IF_SIMPLELINK
14588#endif
14589
14591
14592#ifdef __cplusplus
14593}
14594#endif /* __cplusplus */
14595
14596#endif /* CS_COMMON_PLATFORMS_SIMPLELINK_SL_NET_IF_H_ */
14597#ifdef MG_MODULE_LINES
14598#line 1 "common/platforms/simplelink/sl_net_if.c"
14599#endif
14600/*
14601 * Copyright (c) 2014-2018 Cesanta Software Limited
14602 * All rights reserved
14603 *
14604 * Licensed under the Apache License, Version 2.0 (the ""License"");
14605 * you may not use this file except in compliance with the License.
14606 * You may obtain a copy of the License at
14607 *
14608 * http://www.apache.org/licenses/LICENSE-2.0
14609 *
14610 * Unless required by applicable law or agreed to in writing, software
14611 * distributed under the License is distributed on an ""AS IS"" BASIS,
14612 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14613 * See the License for the specific language governing permissions and
14614 * limitations under the License.
14615 */
14616
14617/* Amalgamated: #include "common/platforms/simplelink/sl_net_if.h" */
14618
14619#if MG_ENABLE_NET_IF_SIMPLELINK
14620
14621/* Amalgamated: #include "mongoose/src/internal.h" */
14622/* Amalgamated: #include "mongoose/src/util.h" */
14623
14624#define MG_TCP_RECV_BUFFER_SIZE 1024
14625#define MG_UDP_RECV_BUFFER_SIZE 1500
14626
14628 union socket_address *sa, int type,
14629 int proto);
14630
14631static void mg_set_non_blocking_mode(sock_t sock) {
14633#if SL_MAJOR_VERSION_NUM < 2
14634 opt.NonblockingEnabled = 1;
14635#else
14636 opt.NonBlockingEnabled = 1;
14637#endif
14639}
14640
14641static int mg_is_error(int n) {
14642 return (n < 0 && n != SL_ERROR_BSD_EALREADY && n != SL_ERROR_BSD_EAGAIN);
14643}
14644
14645static void mg_sl_if_connect_tcp(struct mg_connection *nc,
14646 const union socket_address *sa) {
14647 int proto = 0;
14648#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
14649 if (nc->flags & MG_F_SSL) proto = SL_SEC_SOCKET;
14650#endif
14651 sock_t sock = sl_Socket(AF_INET, SOCK_STREAM, proto);
14652 if (sock < 0) {
14653 nc->err = sock;
14654 goto out;
14655 }
14656 mg_sock_set(nc, sock);
14657#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
14658 nc->err = sl_set_ssl_opts(sock, nc);
14659 if (nc->err != 0) goto out;
14660#endif
14661 nc->err = sl_Connect(sock, &sa->sa, sizeof(sa->sin));
14662out:
14663 DBG(("%p to %s:%d sock %d %d err %d", nc, inet_ntoa(sa->sin.sin_addr),
14664 ntohs(sa->sin.sin_port), nc->sock, proto, nc->err));
14665}
14666
14667static void mg_sl_if_connect_udp(struct mg_connection *nc) {
14668 sock_t sock = sl_Socket(AF_INET, SOCK_DGRAM, 0);
14669 if (sock < 0) {
14670 nc->err = sock;
14671 return;
14672 }
14673 mg_sock_set(nc, sock);
14674 nc->err = 0;
14675}
14676
14677static int mg_sl_if_listen_tcp(struct mg_connection *nc,
14678 union socket_address *sa) {
14679 int proto = 0;
14680 if (nc->flags & MG_F_SSL) proto = SL_SEC_SOCKET;
14681 sock_t sock = mg_open_listening_socket(nc, sa, SOCK_STREAM, proto);
14682 if (sock < 0) return sock;
14683 mg_sock_set(nc, sock);
14684 return 0;
14685}
14686
14687static int mg_sl_if_listen_udp(struct mg_connection *nc,
14688 union socket_address *sa) {
14689 sock_t sock = mg_open_listening_socket(nc, sa, SOCK_DGRAM, 0);
14690 if (sock == INVALID_SOCKET) return (errno ? errno : 1);
14691 mg_sock_set(nc, sock);
14692 return 0;
14693}
14694
14695static int mg_sl_if_tcp_send(struct mg_connection *nc, const void *buf,
14696 size_t len) {
14697 int n = (int) sl_Send(nc->sock, buf, len, 0);
14698 if (n < 0 && !mg_is_error(n)) n = 0;
14699 return n;
14700}
14701
14702static int mg_sl_if_udp_send(struct mg_connection *nc, const void *buf,
14703 size_t len) {
14704 int n = sl_SendTo(nc->sock, buf, len, 0, &nc->sa.sa, sizeof(nc->sa.sin));
14705 if (n < 0 && !mg_is_error(n)) n = 0;
14706 return n;
14707}
14708
14709static int mg_sl_if_tcp_recv(struct mg_connection *nc, void *buf, size_t len) {
14710 int n = sl_Recv(nc->sock, buf, len, 0);
14711 if (n == 0) {
14712 /* Orderly shutdown of the socket, try flushing output. */
14714 } else if (n < 0 && !mg_is_error(n)) {
14715 n = 0;
14716 }
14717 return n;
14718}
14719
14720static int mg_sl_if_udp_recv(struct mg_connection *nc, void *buf, size_t len,
14721 union socket_address *sa, size_t *sa_len) {
14723 int n = sl_RecvFrom(nc->sock, buf, MG_UDP_RECV_BUFFER_SIZE, 0,
14724 (SlSockAddr_t *) sa, &sa_len_t);
14725 *sa_len = sa_len_t;
14726 if (n < 0 && !mg_is_error(n)) n = 0;
14727 return n;
14728}
14729
14730static int mg_sl_if_create_conn(struct mg_connection *nc) {
14731 (void) nc;
14732 return 1;
14733}
14734
14735void mg_sl_if_destroy_conn(struct mg_connection *nc) {
14736 if (nc->sock == INVALID_SOCKET) return;
14737 /* For UDP, only close outgoing sockets or listeners. */
14738 if (!(nc->flags & MG_F_UDP) || nc->listener == NULL) {
14739 sl_Close(nc->sock);
14740 }
14741 nc->sock = INVALID_SOCKET;
14742}
14743
14744static int mg_accept_conn(struct mg_connection *lc) {
14745 struct mg_connection *nc;
14746 union socket_address sa;
14747 socklen_t sa_len = sizeof(sa);
14748 sock_t sock = sl_Accept(lc->sock, &sa.sa, &sa_len);
14749 if (sock < 0) {
14750 DBG(("%p: failed to accept: %d", lc, sock));
14751 return 0;
14752 }
14753 nc = mg_if_accept_new_conn(lc);
14754 if (nc == NULL) {
14755 sl_Close(sock);
14756 return 0;
14757 }
14758 DBG(("%p conn from %s:%d", nc, inet_ntoa(sa.sin.sin_addr),
14759 ntohs(sa.sin.sin_port)));
14760 mg_sock_set(nc, sock);
14762 return 1;
14763}
14764
14765/* 'sa' must be an initialized address to bind to */
14767 union socket_address *sa, int type,
14768 int proto) {
14769 int r;
14771 (sa->sa.sa_family == AF_INET) ? sizeof(sa->sin) : sizeof(sa->sin6);
14772 sock_t sock = sl_Socket(sa->sa.sa_family, type, proto);
14773 if (sock < 0) return sock;
14774#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
14775 if ((r = sl_set_ssl_opts(sock, nc)) < 0) goto clean;
14776#endif
14777 if ((r = sl_Bind(sock, &sa->sa, sa_len)) < 0) goto clean;
14778 if (type != SOCK_DGRAM) {
14779 if ((r = sl_Listen(sock, SOMAXCONN)) < 0) goto clean;
14780 }
14782clean:
14783 if (r < 0) {
14784 sl_Close(sock);
14785 sock = r;
14786 }
14787 return sock;
14788}
14789
14790#define _MG_F_FD_CAN_READ 1
14791#define _MG_F_FD_CAN_WRITE 1 << 1
14792#define _MG_F_FD_ERROR 1 << 2
14793
14794void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
14795 DBG(("%p fd=%d fd_flags=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock,
14796 fd_flags, nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
14797
14798 if (!mg_if_poll(nc, now)) return;
14799
14800 if (nc->flags & MG_F_CONNECTING) {
14801 if ((nc->flags & MG_F_UDP) || nc->err != SL_ERROR_BSD_EALREADY) {
14802 mg_if_connect_cb(nc, nc->err);
14803 } else {
14804 /* In SimpleLink, to get status of non-blocking connect() we need to wait
14805 * until socket is writable and repeat the call to sl_Connect again,
14806 * which will now return the real status. */
14808 nc->err = sl_Connect(nc->sock, &nc->sa.sa, sizeof(nc->sa.sin));
14809 DBG(("%p conn res=%d", nc, nc->err));
14810 if (nc->err == SL_ERROR_BSD_ESECSNOVERIFY ||
14811 /* TODO(rojer): Provide API to set the date for verification. */
14813#if SL_MAJOR_VERSION_NUM >= 2
14814 /* Per SWRU455, this error does not mean verification failed,
14815 * it only means that the cert used is not present in the trusted
14816 * root CA catalog. Which is perfectly fine. */
14817 ||
14819#endif
14820 ) {
14821 nc->err = 0;
14822 }
14823 mg_if_connect_cb(nc, nc->err);
14824 }
14825 }
14826 /* Ignore read/write in further processing, we've handled it. */
14828 }
14829
14831 if (nc->flags & MG_F_UDP) {
14833 } else {
14834 if (nc->flags & MG_F_LISTENING) {
14835 mg_accept_conn(nc);
14836 } else {
14838 }
14839 }
14840 }
14841
14844 }
14845
14846 DBG(("%p after fd=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock, nc->flags,
14847 (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
14848}
14849
14850/* Associate a socket to a connection. */
14851void mg_sl_if_sock_set(struct mg_connection *nc, sock_t sock) {
14853 nc->sock = sock;
14854 DBG(("%p %d", nc, sock));
14855}
14856
14857void mg_sl_if_init(struct mg_iface *iface) {
14858 (void) iface;
14859 DBG(("%p using sl_Select()", iface->mgr));
14860}
14861
14862void mg_sl_if_free(struct mg_iface *iface) {
14863 (void) iface;
14864}
14865
14866void mg_sl_if_add_conn(struct mg_connection *nc) {
14867 (void) nc;
14868}
14869
14870void mg_sl_if_remove_conn(struct mg_connection *nc) {
14871 (void) nc;
14872}
14873
14874time_t mg_sl_if_poll(struct mg_iface *iface, int timeout_ms) {
14875 struct mg_mgr *mgr = iface->mgr;
14876 double now = mg_time();
14877 double min_timer;
14878 struct mg_connection *nc, *tmp;
14879 struct SlTimeval_t tv;
14882 int num_fds, num_ev = 0, num_timers = 0;
14883
14887
14888 /*
14889 * Note: it is ok to have connections with sock == INVALID_SOCKET in the list,
14890 * e.g. timer-only "connections".
14891 */
14892 min_timer = 0;
14893 for (nc = mgr->active_connections, num_fds = 0; nc != NULL; nc = tmp) {
14894 tmp = nc->next;
14895
14896 if (nc->sock != INVALID_SOCKET) {
14897 num_fds++;
14898
14899 if (!(nc->flags & MG_F_WANT_WRITE) &&
14900 nc->recv_mbuf.len < nc->recv_mbuf_limit &&
14901 (!(nc->flags & MG_F_UDP) || nc->listener == NULL)) {
14903 if (max_fd == INVALID_SOCKET || nc->sock > max_fd) max_fd = nc->sock;
14904 }
14905
14906 if (((nc->flags & MG_F_CONNECTING) && !(nc->flags & MG_F_WANT_READ)) ||
14907 (nc->send_mbuf.len > 0 && !(nc->flags & MG_F_CONNECTING))) {
14910 if (max_fd == INVALID_SOCKET || nc->sock > max_fd) max_fd = nc->sock;
14911 }
14912 }
14913
14914 if (nc->ev_timer_time > 0) {
14915 if (num_timers == 0 || nc->ev_timer_time < min_timer) {
14917 }
14918 num_timers++;
14919 }
14920 }
14921
14922 /*
14923 * If there is a timer to be fired earlier than the requested timeout,
14924 * adjust the timeout.
14925 */
14926 if (num_timers > 0) {
14927 double timer_timeout_ms = (min_timer - mg_time()) * 1000 + 1 /* rounding */;
14930 }
14931 }
14932 if (timeout_ms < 0) timeout_ms = 0;
14933
14934 tv.tv_sec = timeout_ms / 1000;
14935 tv.tv_usec = (timeout_ms % 1000) * 1000;
14936
14937 if (num_fds > 0) {
14938 num_ev = sl_Select((int) max_fd + 1, &read_set, &write_set, &err_set, &tv);
14939 }
14940
14941 now = mg_time();
14942 DBG(("sl_Select @ %ld num_ev=%d of %d, timeout=%d", (long) now, num_ev,
14944
14945 for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
14946 int fd_flags = 0;
14947 if (nc->sock != INVALID_SOCKET) {
14948 if (num_ev > 0) {
14949 fd_flags =
14951 (!(nc->flags & MG_F_UDP) || nc->listener == NULL)
14953 : 0) |
14955 : 0) |
14957 }
14958 /* SimpleLink does not report UDP sockets as writable. */
14959 if (nc->flags & MG_F_UDP && nc->send_mbuf.len > 0) {
14961 }
14962 }
14963 tmp = nc->next;
14965 }
14966
14967 return now;
14968}
14969
14970void mg_sl_if_get_conn_addr(struct mg_connection *nc, int remote,
14971 union socket_address *sa) {
14972 /* SimpleLink does not provide a way to get socket's peer address after
14973 * accept or connect. Address should have been preserved in the connection,
14974 * so we do our best here by using it. */
14975 if (remote) memcpy(sa, &nc->sa, sizeof(*sa));
14976}
14977
14978void sl_restart_cb(struct mg_mgr *mgr) {
14979 /*
14980 * SimpleLink has been restarted, meaning all sockets have been invalidated.
14981 * We try our best - we'll restart the listeners, but for outgoing
14982 * connections we have no option but to terminate.
14983 */
14984 struct mg_connection *nc;
14985 for (nc = mg_next(mgr, NULL); nc != NULL; nc = mg_next(mgr, nc)) {
14986 if (nc->sock == INVALID_SOCKET) continue; /* Could be a timer */
14987 if (nc->flags & MG_F_LISTENING) {
14988 DBG(("restarting %p %s:%d", nc, inet_ntoa(nc->sa.sin.sin_addr),
14989 ntohs(nc->sa.sin.sin_port)));
14990 int res = (nc->flags & MG_F_UDP ? mg_sl_if_listen_udp(nc, &nc->sa)
14991 : mg_sl_if_listen_tcp(nc, &nc->sa));
14992 if (res == 0) continue;
14993 /* Well, we tried and failed. Fall through to closing. */
14994 }
14995 nc->sock = INVALID_SOCKET;
14996 DBG(("terminating %p %s:%d", nc, inet_ntoa(nc->sa.sin.sin_addr),
14997 ntohs(nc->sa.sin.sin_port)));
14998 /* TODO(rojer): Outgoing UDP? */
15000 }
15001}
15002
15003/* clang-format off */
15004#define MG_SL_IFACE_VTABLE \
15005 { \
15006 mg_sl_if_init, \
15007 mg_sl_if_free, \
15008 mg_sl_if_add_conn, \
15009 mg_sl_if_remove_conn, \
15010 mg_sl_if_poll, \
15011 mg_sl_if_listen_tcp, \
15012 mg_sl_if_listen_udp, \
15013 mg_sl_if_connect_tcp, \
15014 mg_sl_if_connect_udp, \
15015 mg_sl_if_tcp_send, \
15016 mg_sl_if_udp_send, \
15017 mg_sl_if_tcp_recv, \
15018 mg_sl_if_udp_recv, \
15019 mg_sl_if_create_conn, \
15020 mg_sl_if_destroy_conn, \
15021 mg_sl_if_sock_set, \
15022 mg_sl_if_get_conn_addr, \
15023 }
15024/* clang-format on */
15025
15027#if MG_NET_IF == MG_NET_IF_SIMPLELINK
15029#endif
15030
15031#endif /* MG_ENABLE_NET_IF_SIMPLELINK */
15032#ifdef MG_MODULE_LINES
15033#line 1 "common/platforms/simplelink/sl_ssl_if.c"
15034#endif
15035/*
15036 * Copyright (c) 2014-2018 Cesanta Software Limited
15037 * All rights reserved
15038 *
15039 * Licensed under the Apache License, Version 2.0 (the ""License"");
15040 * you may not use this file except in compliance with the License.
15041 * You may obtain a copy of the License at
15042 *
15043 * http://www.apache.org/licenses/LICENSE-2.0
15044 *
15045 * Unless required by applicable law or agreed to in writing, software
15046 * distributed under the License is distributed on an ""AS IS"" BASIS,
15047 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15048 * See the License for the specific language governing permissions and
15049 * limitations under the License.
15050 */
15051
15052#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
15053
15054/* Amalgamated: #include "common/mg_mem.h" */
15055
15056#ifndef MG_SSL_IF_SIMPLELINK_SLFS_PREFIX
15057#define MG_SSL_IF_SIMPLELINK_SLFS_PREFIX "SL:"
15058#endif
15059
15060#define MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN \
15061 (sizeof(MG_SSL_IF_SIMPLELINK_SLFS_PREFIX) - 1)
15062
15063struct mg_ssl_if_ctx {
15064 char *ssl_cert;
15065 char *ssl_key;
15066 char *ssl_ca_cert;
15067 char *ssl_server_name;
15068};
15069
15070void mg_ssl_if_init() {
15071}
15072
15074 struct mg_connection *nc, const struct mg_ssl_if_conn_params *params,
15075 const char **err_msg) {
15076 struct mg_ssl_if_ctx *ctx =
15077 (struct mg_ssl_if_ctx *) MG_CALLOC(1, sizeof(*ctx));
15078 if (ctx == NULL) {
15079 MG_SET_PTRPTR(err_msg, "Out of memory");
15080 return MG_SSL_ERROR;
15081 }
15082 nc->ssl_if_data = ctx;
15083
15084 if (params->cert != NULL || params->key != NULL) {
15085 if (params->cert != NULL && params->key != NULL) {
15086 ctx->ssl_cert = strdup(params->cert);
15087 ctx->ssl_key = strdup(params->key);
15088 } else {
15089 MG_SET_PTRPTR(err_msg, "Both cert and key are required.");
15090 return MG_SSL_ERROR;
15091 }
15092 }
15093 if (params->ca_cert != NULL && strcmp(params->ca_cert, "*") != 0) {
15094 ctx->ssl_ca_cert = strdup(params->ca_cert);
15095 }
15096 /* TODO(rojer): cipher_suites. */
15097 if (params->server_name != NULL) {
15098 ctx->ssl_server_name = strdup(params->server_name);
15099 }
15100 return MG_SSL_OK;
15101}
15102
15104 struct mg_connection *lc) {
15105 /* SimpleLink does everything for us, nothing for us to do. */
15106 (void) nc;
15107 (void) lc;
15108 return MG_SSL_OK;
15109}
15110
15112 /* SimpleLink has already performed the handshake, nothing to do. */
15113 return MG_SSL_OK;
15114}
15115
15116int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t len) {
15117 /* SimpelLink handles TLS, so this is just a pass-through. */
15118 int n = nc->iface->vtable->tcp_recv(nc, buf, len);
15119 if (n == 0) nc->flags |= MG_F_WANT_READ;
15120 return n;
15121}
15122
15123int mg_ssl_if_write(struct mg_connection *nc, const void *buf, size_t len) {
15124 /* SimpelLink handles TLS, so this is just a pass-through. */
15125 return nc->iface->vtable->tcp_send(nc, buf, len);
15126}
15127
15129 /* Nothing to do */
15130 (void) nc;
15131}
15132
15133void mg_ssl_if_conn_free(struct mg_connection *nc) {
15134 struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
15135 if (ctx == NULL) return;
15136 nc->ssl_if_data = NULL;
15137 MG_FREE(ctx->ssl_cert);
15138 MG_FREE(ctx->ssl_key);
15139 MG_FREE(ctx->ssl_ca_cert);
15140 MG_FREE(ctx->ssl_server_name);
15141 memset(ctx, 0, sizeof(*ctx));
15142 MG_FREE(ctx);
15143}
15144
15145bool pem_to_der(const char *pem_file, const char *der_file) {
15146 bool ret = false;
15147 FILE *pf = NULL, *df = NULL;
15148 bool writing = false;
15149 pf = fopen(pem_file, "r");
15150 if (pf == NULL) goto clean;
15151 remove(der_file);
15153 df = fopen(der_file, "w");
15155 if (df == NULL) goto clean;
15156 while (1) {
15157 char pem_buf[70];
15158 char der_buf[48];
15159 if (!fgets(pem_buf, sizeof(pem_buf), pf)) break;
15160 if (writing) {
15161 if (strstr(pem_buf, "-----END ") != NULL) {
15162 ret = true;
15163 break;
15164 }
15165 int l = 0;
15166 while (!isspace((unsigned int) pem_buf[l])) l++;
15167 int der_len = 0;
15168 cs_base64_decode((const unsigned char *) pem_buf, sizeof(pem_buf),
15169 der_buf, &der_len);
15170 if (der_len <= 0) break;
15171 if (fwrite(der_buf, 1, der_len, df) != der_len) break;
15172 } else if (strstr(pem_buf, "-----BEGIN ") != NULL) {
15173 writing = true;
15174 }
15175 }
15176
15177clean:
15178 if (pf != NULL) fclose(pf);
15179 if (df != NULL) {
15180 fclose(df);
15181 if (!ret) remove(der_file);
15182 }
15183 return ret;
15184}
15185
15186#if MG_ENABLE_FILESYSTEM && defined(MG_FS_SLFS)
15187/* If the file's extension is .pem, convert it to DER format and put on SLFS. */
15188static char *sl_pem2der(const char *pem_file) {
15189 const char *pem_ext = strstr(pem_file, ".pem");
15190 if (pem_ext == NULL || *(pem_ext + 4) != '\0') {
15191 return strdup(pem_file);
15192 }
15193 char *der_file = NULL;
15194 /* DER file must be located on SLFS, add prefix. */
15196 (int) (pem_ext - pem_file), pem_file);
15197 if (der_file == NULL) return NULL;
15198 bool result = false;
15199 cs_stat_t st;
15200 if (mg_stat(der_file, &st) != 0) {
15201 result = pem_to_der(pem_file, der_file);
15202 LOG(LL_DEBUG, ("%s -> %s = %d", pem_file, der_file, result));
15203 } else {
15204 /* File exists, assume it's already been converted. */
15205 result = true;
15206 }
15207 if (result) {
15208 /* Strip the SL: prefix we added since NWP does not expect it. */
15210 l - 2 /* including \0 */);
15211 } else {
15213 der_file = NULL;
15214 }
15215 return der_file;
15216}
15217#else
15218static char *sl_pem2der(const char *pem_file) {
15219 return strdup(pem_file);
15220}
15221#endif
15222
15223int sl_set_ssl_opts(int sock, struct mg_connection *nc) {
15224 int err;
15225 const struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
15226 DBG(("%p ssl ctx: %p", nc, ctx));
15227
15228 if (ctx == NULL) return 0;
15229 DBG(("%p %s,%s,%s,%s", nc, (ctx->ssl_cert ? ctx->ssl_cert : "-"),
15230 (ctx->ssl_key ? ctx->ssl_cert : "-"),
15231 (ctx->ssl_ca_cert ? ctx->ssl_ca_cert : "-"),
15232 (ctx->ssl_server_name ? ctx->ssl_server_name : "-")));
15233 if (ctx->ssl_cert != NULL && ctx->ssl_key != NULL) {
15234 char *ssl_cert = sl_pem2der(ctx->ssl_cert), *ssl_key = NULL;
15235 if (ssl_cert != NULL) {
15236 err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
15238 strlen(ssl_cert));
15240 LOG(LL_DEBUG, ("CERTIFICATE_FILE_NAME %s -> %d", ssl_cert, err));
15241 ssl_key = sl_pem2der(ctx->ssl_key);
15242 if (ssl_key != NULL) {
15243 err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
15245 strlen(ssl_key));
15247 LOG(LL_DEBUG, ("PRIVATE_KEY_FILE_NAME %s -> %d", ssl_key, err));
15248 } else {
15249 err = -1;
15250 }
15251 } else {
15252 err = -1;
15253 }
15254 if (err != 0) return err;
15255 }
15256 if (ctx->ssl_ca_cert != NULL) {
15257 if (ctx->ssl_ca_cert[0] != '\0') {
15258 char *ssl_ca_cert = sl_pem2der(ctx->ssl_ca_cert);
15259 if (ssl_ca_cert != NULL) {
15260 err =
15263 LOG(LL_DEBUG, ("CA_FILE_NAME %s -> %d", ssl_ca_cert, err));
15264 } else {
15265 err = -1;
15266 }
15268 if (err != 0) return err;
15269 }
15270 }
15271 if (ctx->ssl_server_name != NULL) {
15272 err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
15274 ctx->ssl_server_name, strlen(ctx->ssl_server_name));
15275 DBG(("DOMAIN_NAME_VERIFICATION %s -> %d", ctx->ssl_server_name, err));
15276 /* Domain name verificationw as added in a NWP service pack, older
15277 * versions return SL_ERROR_BSD_ENOPROTOOPT. There isn't much we can do
15278 * about it,
15279 * so we ignore the error. */
15280 if (err != 0 && err != SL_ERROR_BSD_ENOPROTOOPT) return err;
15281 }
15282 return 0;
15283}
15284
15285#endif /* MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK */
15286#ifdef MG_MODULE_LINES
15287#line 1 "common/platforms/lwip/mg_lwip_net_if.h"
15288#endif
15289/*
15290 * Copyright (c) 2014-2018 Cesanta Software Limited
15291 * All rights reserved
15292 *
15293 * Licensed under the Apache License, Version 2.0 (the ""License"");
15294 * you may not use this file except in compliance with the License.
15295 * You may obtain a copy of the License at
15296 *
15297 * http://www.apache.org/licenses/LICENSE-2.0
15298 *
15299 * Unless required by applicable law or agreed to in writing, software
15300 * distributed under the License is distributed on an ""AS IS"" BASIS,
15301 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15302 * See the License for the specific language governing permissions and
15303 * limitations under the License.
15304 */
15305
15306#ifndef CS_COMMON_PLATFORMS_LWIP_MG_NET_IF_LWIP_H_
15307#define CS_COMMON_PLATFORMS_LWIP_MG_NET_IF_LWIP_H_
15308
15309#ifndef MG_ENABLE_NET_IF_LWIP_LOW_LEVEL
15310#define MG_ENABLE_NET_IF_LWIP_LOW_LEVEL MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL
15311#endif
15312
15313#if MG_ENABLE_NET_IF_LWIP_LOW_LEVEL
15314
15315#include <stdint.h>
15316
15317extern const struct mg_iface_vtable mg_lwip_iface_vtable;
15318
15319struct mg_lwip_conn_state {
15320 struct mg_connection *nc;
15321 struct mg_connection *lc;
15322 union {
15323 struct tcp_pcb *tcp;
15324 struct udp_pcb *udp;
15325 } pcb;
15326 err_t err;
15327 size_t num_sent; /* Number of acknowledged bytes to be reported to the core */
15328 struct pbuf *rx_chain; /* Chain of incoming data segments. */
15329 size_t rx_offset; /* Offset within the first pbuf (if partially consumed) */
15330 /* Last SSL write size, for retries. */
15332 /* Whether MG_SIG_RECV is already pending for this connection */
15333 int recv_pending;
15334 /* Whether the connection is about to close, just `rx_chain` needs to drain */
15336};
15337
15338enum mg_sig_type {
15340 MG_SIG_RECV = 2,
15342 MG_SIG_TOMBSTONE = 4,
15343 MG_SIG_ACCEPT = 5,
15344};
15345
15346void mg_lwip_post_signal(enum mg_sig_type sig, struct mg_connection *nc);
15347
15348/* To be implemented by the platform. */
15349void mg_lwip_mgr_schedule_poll(struct mg_mgr *mgr);
15350
15351#endif /* MG_ENABLE_NET_IF_LWIP_LOW_LEVEL */
15352
15353#endif /* CS_COMMON_PLATFORMS_LWIP_MG_NET_IF_LWIP_H_ */
15354#ifdef MG_MODULE_LINES
15355#line 1 "common/platforms/lwip/mg_lwip_net_if.c"
15356#endif
15357/*
15358 * Copyright (c) 2014-2018 Cesanta Software Limited
15359 * All rights reserved
15360 *
15361 * Licensed under the Apache License, Version 2.0 (the ""License"");
15362 * you may not use this file except in compliance with the License.
15363 * You may obtain a copy of the License at
15364 *
15365 * http://www.apache.org/licenses/LICENSE-2.0
15366 *
15367 * Unless required by applicable law or agreed to in writing, software
15368 * distributed under the License is distributed on an ""AS IS"" BASIS,
15369 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15370 * See the License for the specific language governing permissions and
15371 * limitations under the License.
15372 */
15373
15374#if MG_ENABLE_NET_IF_LWIP_LOW_LEVEL
15375
15376/* Amalgamated: #include "common/mg_mem.h" */
15377
15378#include <lwip/init.h>
15379#include <lwip/pbuf.h>
15380#include <lwip/tcp.h>
15381#include <lwip/tcpip.h>
15382#if ((LWIP_VERSION_MAJOR << 8) | LWIP_VERSION_MINOR) >= 0x0105
15383#include <lwip/priv/tcp_priv.h> /* For tcp_seg */
15384#include <lwip/priv/tcpip_priv.h> /* For tcpip_api_call */
15385#else
15386#include <lwip/tcp_impl.h>
15387#endif
15388#include <lwip/udp.h>
15389
15390/* Amalgamated: #include "common/cs_dbg.h" */
15391
15392/*
15393 * Newest versions of LWIP have ip_2_ip4, older have ipX_2_ip,
15394 * even older have nothing.
15395 */
15396#ifndef ip_2_ip4
15397#ifdef ipX_2_ip
15398#define ip_2_ip4(addr) ipX_2_ip(addr)
15399#else
15400#define ip_2_ip4(addr) (addr)
15401#endif
15402#endif
15403
15404/*
15405 * Depending on whether Mongoose is compiled with ipv6 support, use right
15406 * lwip functions
15407 */
15408#if MG_ENABLE_IPV6
15409#define TCP_NEW tcp_new_ip6
15410#define TCP_BIND tcp_bind_ip6
15411#define UDP_BIND udp_bind_ip6
15412#define IPADDR_NTOA(x) ip6addr_ntoa((const ip6_addr_t *)(x))
15413#define SET_ADDR(dst, src) \
15414 memcpy((dst)->sin6.sin6_addr.s6_addr, (src)->ip6.addr, \
15415 sizeof((dst)->sin6.sin6_addr.s6_addr))
15416#else
15417#define TCP_NEW tcp_new
15418#define TCP_BIND tcp_bind
15419#define UDP_BIND udp_bind
15420#define IPADDR_NTOA ipaddr_ntoa
15421#define SET_ADDR(dst, src) (dst)->sin.sin_addr.s_addr = ip_2_ip4(src)->addr
15422#endif
15423
15424#if !NO_SYS
15425#if LWIP_TCPIP_CORE_LOCKING
15426/* With locking tcpip_api_call is just a function call wrapped in lock/unlock,
15427 * so we can get away with just casting. */
15428void mg_lwip_netif_run_on_tcpip(void (*fn)(void *), void *arg) {
15430}
15431#else
15435 void (*fn)(void *);
15436 void *arg;
15437};
15438static void xxx_tcpip(void *arg) {
15439 struct mg_lwip_netif_tcpip_call_ctx *ctx =
15441 ctx->fn(ctx->arg);
15443}
15444void mg_lwip_netif_run_on_tcpip(void (*fn)(void *), void *arg) {
15445 struct mg_lwip_netif_tcpip_call_ctx ctx = {.fn = fn, .arg = arg};
15449}
15450#endif
15451#else
15452#define mg_lwip_netif_run_on_tcpip(fn, arg) (fn)(arg)
15453#endif
15454
15455void mg_lwip_if_init(struct mg_iface *iface);
15456void mg_lwip_if_free(struct mg_iface *iface);
15457void mg_lwip_if_add_conn(struct mg_connection *nc);
15458void mg_lwip_if_remove_conn(struct mg_connection *nc);
15459time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms);
15460
15461// If compiling for Mongoose OS.
15462#ifdef MGOS
15463extern void mgos_lock();
15464extern void mgos_unlock();
15465#else
15466#define mgos_lock()
15467#define mgos_unlock()
15468#endif
15469
15470static void mg_lwip_recv_common(struct mg_connection *nc, struct pbuf *p);
15471
15472#if LWIP_TCP_KEEPALIVE
15474 int interval, int count) {
15475 if (nc->sock == INVALID_SOCKET || nc->flags & MG_F_UDP) {
15476 return;
15477 }
15478 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15479 struct tcp_pcb *tpcb = cs->pcb.tcp;
15480 if (idle > 0 && interval > 0 && count > 0) {
15481 tpcb->keep_idle = idle * 1000;
15482 tpcb->keep_intvl = interval * 1000;
15483 tpcb->keep_cnt = count;
15484 tpcb->so_options |= SOF_KEEPALIVE;
15485 } else {
15486 tpcb->so_options &= ~SOF_KEEPALIVE;
15487 }
15488}
15489#elif !defined(MG_NO_LWIP_TCP_KEEPALIVE)
15490#warning LWIP TCP keepalive is disabled. Please consider enabling it.
15491#endif /* LWIP_TCP_KEEPALIVE */
15492
15493static err_t mg_lwip_tcp_conn_cb(void *arg, struct tcp_pcb *tpcb, err_t err) {
15494 struct mg_connection *nc = (struct mg_connection *) arg;
15495 DBG(("%p connect to %s:%u = %d", nc, IPADDR_NTOA(ipX_2_ip(&tpcb->remote_ip)),
15496 tpcb->remote_port, err));
15497 if (nc == NULL) {
15498 tcp_abort(tpcb);
15499 return ERR_ARG;
15500 }
15501 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15502 cs->err = err;
15503#if LWIP_TCP_KEEPALIVE
15504 if (err == 0) mg_lwip_set_keepalive_params(nc, 60, 10, 6);
15505#endif
15507 return ERR_OK;
15508}
15509
15510static void mg_lwip_tcp_error_cb(void *arg, err_t err) {
15511 struct mg_connection *nc = (struct mg_connection *) arg;
15512 DBG(("%p conn error %d", nc, err));
15513 if (nc == NULL || (nc->flags & MG_F_CLOSE_IMMEDIATELY)) return;
15514 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15515 cs->pcb.tcp = NULL; /* Has already been deallocated */
15516 if (nc->flags & MG_F_CONNECTING) {
15517 cs->err = err;
15519 } else {
15521 }
15522}
15523
15524static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb,
15525 struct pbuf *p, err_t err) {
15526 struct mg_connection *nc = (struct mg_connection *) arg;
15527 struct mg_lwip_conn_state *cs =
15528 (nc ? (struct mg_lwip_conn_state *) nc->sock : NULL);
15529 DBG(("%p %p %p %p %u %d", nc, cs, tpcb, p, (p != NULL ? p->tot_len : 0),
15530 err));
15531 if (p == NULL) {
15532 if (nc != NULL && !(nc->flags & MG_F_CLOSE_IMMEDIATELY)) {
15533 if (cs->rx_chain != NULL) {
15534 /*
15535 * rx_chain still contains non-consumed data, don't close the
15536 * connection
15537 */
15538 cs->draining_rx_chain = 1;
15539 } else {
15541 }
15542 } else {
15543 /* Tombstoned connection, do nothing. */
15544 }
15545 return ERR_OK;
15546 } else if (nc == NULL) {
15547 tcp_abort(tpcb);
15548 return ERR_ARG;
15549 }
15550 /*
15551 * If we get a chain of more than one segment at once, we need to bump
15552 * refcount on the subsequent bufs to make them independent.
15553 */
15554 if (p->next != NULL) {
15555 struct pbuf *q = p->next;
15556 for (; q != NULL; q = q->next) pbuf_ref(q);
15557 }
15558 mgos_lock();
15559 if (cs->rx_chain == NULL) {
15560 cs->rx_offset = 0;
15561 } else if (pbuf_clen(cs->rx_chain) >= 4) {
15562 /* ESP SDK has a limited pool of 5 pbufs. We must not hog them all or RX
15563 * will be completely blocked. We already have at least 4 in the chain,
15564 * this one is the last, so we have to make a copy and release this one. */
15565 struct pbuf *np = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
15566 if (np != NULL) {
15567 pbuf_copy(np, p);
15568 pbuf_free(p);
15569 p = np;
15570 }
15571 }
15572 mg_lwip_recv_common(nc, p);
15573 mgos_unlock();
15574 (void) err;
15575 return ERR_OK;
15576}
15577
15578static err_t mg_lwip_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb,
15579 u16_t num_sent) {
15580 struct mg_connection *nc = (struct mg_connection *) arg;
15581 DBG(("%p %p %u %p %p", nc, tpcb, num_sent, tpcb->unsent, tpcb->unacked));
15582 if (nc == NULL) return ERR_OK;
15583 if ((nc->flags & MG_F_SEND_AND_CLOSE) && !(nc->flags & MG_F_WANT_WRITE) &&
15584 nc->send_mbuf.len == 0 && tpcb->unsent == NULL && tpcb->unacked == NULL) {
15586 }
15587 if (nc->send_mbuf.len > 0 || (nc->flags & MG_F_WANT_WRITE)) {
15589 }
15590 (void) num_sent;
15591 return ERR_OK;
15592}
15593
15595 struct mg_connection *nc;
15596 const union socket_address *sa;
15597};
15598
15599static void mg_lwip_if_connect_tcp_tcpip(void *arg) {
15600 struct mg_lwip_if_connect_tcp_ctx *ctx =
15601 (struct mg_lwip_if_connect_tcp_ctx *) arg;
15602 struct mg_connection *nc = ctx->nc;
15603 const union socket_address *sa = ctx->sa;
15604
15605 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15606 struct tcp_pcb *tpcb = TCP_NEW();
15607 cs->pcb.tcp = tpcb;
15608 ip_addr_t *ip = (ip_addr_t *) &sa->sin.sin_addr.s_addr;
15609 u16_t port = ntohs(sa->sin.sin_port);
15610 tcp_arg(tpcb, nc);
15613 tcp_recv(tpcb, mg_lwip_tcp_recv_cb);
15614 cs->err = TCP_BIND(tpcb, IP_ADDR_ANY, 0 /* any port */);
15615 DBG(("%p tcp_bind = %d", nc, cs->err));
15616 if (cs->err != ERR_OK) {
15618 return;
15619 }
15620 cs->err = tcp_connect(tpcb, ip, port, mg_lwip_tcp_conn_cb);
15621 DBG(("%p tcp_connect %p = %d", nc, tpcb, cs->err));
15622 if (cs->err != ERR_OK) {
15624 return;
15625 }
15626}
15627
15629 const union socket_address *sa) {
15630 struct mg_lwip_if_connect_tcp_ctx ctx = {.nc = nc, .sa = sa};
15632}
15633
15634/*
15635 * Lwip included in the SDKs for nRF5x chips has different type for the
15636 * callback of `udp_recv()`
15637 */
15638#if ((LWIP_VERSION_MAJOR << 8) | LWIP_VERSION_MINOR) >= 0x0105
15639static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p,
15640 const ip_addr_t *addr, u16_t port)
15641#else
15642static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p,
15643 ip_addr_t *addr, u16_t port)
15644#endif
15645{
15646 struct mg_connection *nc = (struct mg_connection *) arg;
15647 DBG(("%p %s:%u %p %u %u", nc, IPADDR_NTOA(addr), port, p, p->ref, p->len));
15648 /* Put address in a separate pbuf and tack it onto the packet. */
15649 struct pbuf *sap =
15650 pbuf_alloc(PBUF_RAW, sizeof(union socket_address), PBUF_RAM);
15651 if (sap == NULL) {
15652 pbuf_free(p);
15653 return;
15654 }
15655 union socket_address *sa = (union socket_address *) sap->payload;
15656#if ((LWIP_VERSION_MAJOR << 8) | LWIP_VERSION_MINOR) >= 0x0105
15657 sa->sin.sin_addr.s_addr = ip_2_ip4(addr)->addr;
15658#else
15659 sa->sin.sin_addr.s_addr = addr->addr;
15660#endif
15661 sa->sin.sin_port = htons(port);
15662 /* Logic in the recv handler requires that there be exactly one data pbuf. */
15663 p = pbuf_coalesce(p, PBUF_RAW);
15664 pbuf_chain(sap, p);
15665 mgos_lock();
15667 mgos_unlock();
15668 (void) pcb;
15669}
15670
15671static void mg_lwip_recv_common(struct mg_connection *nc, struct pbuf *p) {
15672 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15673 if (cs->rx_chain == NULL) {
15674 cs->rx_chain = p;
15675 } else {
15676 pbuf_chain(cs->rx_chain, p);
15677 }
15678 if (!cs->recv_pending) {
15679 cs->recv_pending = 1;
15681 }
15682}
15683
15684static int mg_lwip_if_udp_recv(struct mg_connection *nc, void *buf, size_t len,
15685 union socket_address *sa, size_t *sa_len) {
15686 /*
15687 * For UDP, RX chain consists of interleaved address and packet bufs:
15688 * Address pbuf followed by exactly one data pbuf (recv_cb took care of that).
15689 */
15690 int res = 0;
15691 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15692 if (nc->sock == INVALID_SOCKET) return -1;
15693 mgos_lock();
15694 if (cs->rx_chain != NULL) {
15695 struct pbuf *ap = cs->rx_chain;
15696 struct pbuf *dp = ap->next;
15697 cs->rx_chain = pbuf_dechain(dp);
15698 res = MIN(dp->len, len);
15699 pbuf_copy_partial(dp, buf, res, 0);
15700 pbuf_free(dp);
15701 pbuf_copy_partial(ap, sa, MIN(*sa_len, ap->len), 0);
15702 pbuf_free(ap);
15703 }
15704 mgos_unlock();
15705 return res;
15706}
15707
15708static void mg_lwip_if_connect_udp_tcpip(void *arg) {
15709 struct mg_connection *nc = (struct mg_connection *) arg;
15710 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15711 struct udp_pcb *upcb = udp_new();
15712 cs->err = UDP_BIND(upcb, IP_ADDR_ANY, 0 /* any port */);
15713 DBG(("%p udp_bind %p = %d", nc, upcb, cs->err));
15714 if (cs->err == ERR_OK) {
15715 udp_recv(upcb, mg_lwip_udp_recv_cb, nc);
15716 cs->pcb.udp = upcb;
15717 } else {
15718 udp_remove(upcb);
15719 }
15721}
15722
15723void mg_lwip_if_connect_udp(struct mg_connection *nc) {
15725}
15726
15727static void tcp_close_tcpip(void *arg) {
15728 tcp_close((struct tcp_pcb *) arg);
15729}
15730
15731void mg_lwip_handle_accept(struct mg_connection *nc) {
15732 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15733 if (cs->pcb.tcp == NULL) return;
15734 union socket_address sa;
15735 struct tcp_pcb *tpcb = cs->pcb.tcp;
15736 SET_ADDR(&sa, &tpcb->remote_ip);
15737 sa.sin.sin_port = htons(tpcb->remote_port);
15738 mg_if_accept_tcp_cb(nc, &sa, sizeof(sa.sin));
15739}
15740
15741static err_t mg_lwip_accept_cb(void *arg, struct tcp_pcb *newtpcb, err_t err) {
15742 struct mg_connection *lc = (struct mg_connection *) arg, *nc;
15743 struct mg_lwip_conn_state *lcs, *cs;
15744 struct tcp_pcb_listen *lpcb;
15745 LOG(LL_DEBUG,
15746 ("%p conn %p from %s:%u", lc, newtpcb,
15747 IPADDR_NTOA(ipX_2_ip(&newtpcb->remote_ip)), newtpcb->remote_port));
15748 if (lc == NULL) {
15750 return ERR_ABRT;
15751 }
15752 lcs = (struct mg_lwip_conn_state *) lc->sock;
15753 lpcb = (struct tcp_pcb_listen *) lcs->pcb.tcp;
15754#if TCP_LISTEN_BACKLOG
15756#endif
15757 nc = mg_if_accept_new_conn(lc);
15758 if (nc == NULL) {
15760 return ERR_ABRT;
15761 }
15762 cs = (struct mg_lwip_conn_state *) nc->sock;
15763 cs->lc = lc;
15764 cs->pcb.tcp = newtpcb;
15765 /* We need to set up callbacks before returning because data may start
15766 * arriving immediately. */
15767 tcp_arg(newtpcb, nc);
15770 tcp_recv(newtpcb, mg_lwip_tcp_recv_cb);
15771#if LWIP_TCP_KEEPALIVE
15772 mg_lwip_set_keepalive_params(nc, 60, 10, 6);
15773#endif
15775 (void) err;
15776 (void) lpcb;
15777 return ERR_OK;
15778}
15779
15780struct mg_lwip_if_listen_ctx {
15781 struct mg_connection *nc;
15782 union socket_address *sa;
15783 int ret;
15784};
15785
15786static void mg_lwip_if_listen_tcp_tcpip(void *arg) {
15787 struct mg_lwip_if_listen_ctx *ctx = (struct mg_lwip_if_listen_ctx *) arg;
15788 struct mg_connection *nc = ctx->nc;
15789 union socket_address *sa = ctx->sa;
15790 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15791 struct tcp_pcb *tpcb = TCP_NEW();
15792 ip_addr_t *ip = (ip_addr_t *) &sa->sin.sin_addr.s_addr;
15793 u16_t port = ntohs(sa->sin.sin_port);
15794 cs->err = TCP_BIND(tpcb, ip, port);
15795 DBG(("%p tcp_bind(%s:%u) = %d", nc, IPADDR_NTOA(ip), port, cs->err));
15796 if (cs->err != ERR_OK) {
15797 tcp_close(tpcb);
15798 ctx->ret = -1;
15799 return;
15800 }
15801 tcp_arg(tpcb, nc);
15802 tpcb = tcp_listen(tpcb);
15803 cs->pcb.tcp = tpcb;
15805 ctx->ret = 0;
15806}
15807
15808int mg_lwip_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) {
15809 struct mg_lwip_if_listen_ctx ctx = {.nc = nc, .sa = sa};
15811 return ctx.ret;
15812}
15813
15814static void mg_lwip_if_listen_udp_tcpip(void *arg) {
15815 struct mg_lwip_if_listen_ctx *ctx = (struct mg_lwip_if_listen_ctx *) arg;
15816 struct mg_connection *nc = ctx->nc;
15817 union socket_address *sa = ctx->sa;
15818 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15819 struct udp_pcb *upcb = udp_new();
15820 ip_addr_t *ip = (ip_addr_t *) &sa->sin.sin_addr.s_addr;
15821 u16_t port = ntohs(sa->sin.sin_port);
15822 cs->err = UDP_BIND(upcb, ip, port);
15823 DBG(("%p udb_bind(%s:%u) = %d", nc, IPADDR_NTOA(ip), port, cs->err));
15824 if (cs->err != ERR_OK) {
15825 udp_remove(upcb);
15826 ctx->ret = -1;
15827 } else {
15828 udp_recv(upcb, mg_lwip_udp_recv_cb, nc);
15829 cs->pcb.udp = upcb;
15830 ctx->ret = 0;
15831 }
15832}
15833
15834int mg_lwip_if_listen_udp(struct mg_connection *nc, union socket_address *sa) {
15835 struct mg_lwip_if_listen_ctx ctx = {.nc = nc, .sa = sa};
15837 return ctx.ret;
15838}
15839
15840struct mg_lwip_tcp_write_ctx {
15841 struct mg_connection *nc;
15842 const void *data;
15843 uint16_t len;
15844 int ret;
15845};
15846
15847static void tcp_output_tcpip(void *arg) {
15848 tcp_output((struct tcp_pcb *) arg);
15849}
15850
15851static void mg_lwip_tcp_write_tcpip(void *arg) {
15852 struct mg_lwip_tcp_write_ctx *ctx = (struct mg_lwip_tcp_write_ctx *) arg;
15853 struct mg_connection *nc = ctx->nc;
15854 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15855 struct tcp_pcb *tpcb = cs->pcb.tcp;
15856 size_t len = MIN(tpcb->mss, MIN(ctx->len, tpcb->snd_buf));
15857 size_t unsent, unacked;
15858 if (len == 0) {
15859 DBG(("%p no buf avail %u %u %p %p", tpcb, tpcb->snd_buf, tpcb->snd_queuelen,
15860 tpcb->unsent, tpcb->unacked));
15862 ctx->ret = 0;
15863 return;
15864 }
15865 unsent = (tpcb->unsent != NULL ? tpcb->unsent->len : 0);
15866 unacked = (tpcb->unacked != NULL ? tpcb->unacked->len : 0);
15867/*
15868 * On ESP8266 we only allow one TCP segment in flight at any given time.
15869 * This may increase latency and reduce efficiency of tcp windowing,
15870 * but memory is scarce and precious on that platform so we do this to
15871 * reduce footprint.
15872 */
15873#if CS_PLATFORM == CS_P_ESP8266
15874 if (unacked > 0) {
15875 ctx->ret = 0;
15876 return;
15877 }
15878 len = MIN(len, (TCP_MSS - unsent));
15879#endif
15880 cs->err = tcp_write(tpcb, ctx->data, len, TCP_WRITE_FLAG_COPY);
15881 unsent = (tpcb->unsent != NULL ? tpcb->unsent->len : 0);
15882 unacked = (tpcb->unacked != NULL ? tpcb->unacked->len : 0);
15883 DBG(("%p tcp_write %u = %d, %u %u", tpcb, len, cs->err, unsent, unacked));
15884 if (cs->err != ERR_OK) {
15885 /*
15886 * We ignore ERR_MEM because memory will be freed up when the data is sent
15887 * and we'll retry.
15888 */
15889 ctx->ret = (cs->err == ERR_MEM ? 0 : -1);
15890 return;
15891 }
15892 ctx->ret = len;
15893 (void) unsent;
15894 (void) unacked;
15895}
15896
15897int mg_lwip_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len) {
15898 struct mg_lwip_tcp_write_ctx ctx = {.nc = nc, .data = buf, .len = len};
15899 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15900 if (nc->sock == INVALID_SOCKET) return -1;
15901 struct tcp_pcb *tpcb = cs->pcb.tcp;
15902 if (tpcb == NULL) return -1;
15903 if (tpcb->snd_buf <= 0) return 0;
15905 return ctx.ret;
15906}
15907
15908struct udp_sendto_ctx {
15909 struct udp_pcb *upcb;
15910 struct pbuf *p;
15911 ip_addr_t *ip;
15912 uint16_t port;
15913 int ret;
15914};
15915
15916static void udp_sendto_tcpip(void *arg) {
15917 struct udp_sendto_ctx *ctx = (struct udp_sendto_ctx *) arg;
15918 ctx->ret = udp_sendto(ctx->upcb, ctx->p, ctx->ip, ctx->port);
15919}
15920
15921static int mg_lwip_if_udp_send(struct mg_connection *nc, const void *data,
15922 size_t len) {
15923 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15924 if (nc->sock == INVALID_SOCKET || cs->pcb.udp == NULL) return -1;
15925 struct udp_pcb *upcb = cs->pcb.udp;
15926 struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
15927#if defined(LWIP_IPV4) && LWIP_IPV4 && defined(LWIP_IPV6) && LWIP_IPV6
15928 ip_addr_t ip = {.u_addr.ip4.addr = nc->sa.sin.sin_addr.s_addr, .type = 0};
15929#else
15930 ip_addr_t ip = {.addr = nc->sa.sin.sin_addr.s_addr};
15931#endif
15932 u16_t port = ntohs(nc->sa.sin.sin_port);
15933 if (p == NULL) return 0;
15934 memcpy(p->payload, data, len);
15935 struct udp_sendto_ctx ctx = {.upcb = upcb, .p = p, .ip = &ip, .port = port};
15937 cs->err = ctx.ret;
15938 pbuf_free(p);
15939 return (cs->err == ERR_OK ? (int) len : -2);
15940}
15941
15942static int mg_lwip_if_can_send(struct mg_connection *nc,
15943 struct mg_lwip_conn_state *cs) {
15944 int can_send = 0;
15945 if (nc->send_mbuf.len > 0 || (nc->flags & MG_F_WANT_WRITE)) {
15946 /* We have stuff to send, but can we? */
15947 if (nc->flags & MG_F_UDP) {
15948 /* UDP is always ready for sending. */
15949 can_send = (cs->pcb.udp != NULL);
15950 } else {
15951 can_send = (cs->pcb.tcp != NULL && cs->pcb.tcp->snd_buf > 0);
15952/* See comment above. */
15953#if CS_PLATFORM == CS_P_ESP8266
15954 if (cs->pcb.tcp->unacked != NULL) can_send = 0;
15955#endif
15956 }
15957 }
15958 return can_send;
15959}
15960
15961struct tcp_recved_ctx {
15962 struct tcp_pcb *tpcb;
15963 size_t len;
15964};
15965
15966void tcp_recved_tcpip(void *arg) {
15967 struct tcp_recved_ctx *ctx = (struct tcp_recved_ctx *) arg;
15968 if (ctx->tpcb != NULL) tcp_recved(ctx->tpcb, ctx->len);
15969}
15970
15971static int mg_lwip_if_tcp_recv(struct mg_connection *nc, void *buf,
15972 size_t len) {
15973 int res = 0;
15974 char *bufp = buf;
15975 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15976 if (nc->sock == INVALID_SOCKET) return -1;
15977 mgos_lock();
15978 while (cs->rx_chain != NULL && len > 0) {
15979 struct pbuf *seg = cs->rx_chain;
15980 size_t seg_len = (seg->len - cs->rx_offset);
15981 size_t copy_len = MIN(len, seg_len);
15982
15983 pbuf_copy_partial(seg, bufp, copy_len, cs->rx_offset);
15984 len -= copy_len;
15985 res += copy_len;
15986 bufp += copy_len;
15987 cs->rx_offset += copy_len;
15988 if (cs->rx_offset == cs->rx_chain->len) {
15989 cs->rx_chain = pbuf_dechain(cs->rx_chain);
15990 pbuf_free(seg);
15991 cs->rx_offset = 0;
15992 }
15993 }
15994 mgos_unlock();
15995 if (res > 0) {
15996 struct tcp_recved_ctx ctx = {.tpcb = cs->pcb.tcp, .len = res};
15998 }
15999 return res;
16000}
16001
16002int mg_lwip_if_create_conn(struct mg_connection *nc) {
16003 struct mg_lwip_conn_state *cs =
16004 (struct mg_lwip_conn_state *) MG_CALLOC(1, sizeof(*cs));
16005 if (cs == NULL) return 0;
16006 cs->nc = nc;
16007 nc->sock = (intptr_t) cs;
16008 return 1;
16009}
16010
16011static void udp_remove_tcpip(void *arg) {
16012 udp_remove((struct udp_pcb *) arg);
16013}
16014
16016 if (nc->sock == INVALID_SOCKET) return;
16017 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
16018 if (!(nc->flags & MG_F_UDP)) {
16019 struct tcp_pcb *tpcb = cs->pcb.tcp;
16020 if (tpcb != NULL) {
16021 tcp_arg(tpcb, NULL);
16022 DBG(("%p tcp_close %p", nc, tpcb));
16023 tcp_arg(tpcb, NULL);
16025 }
16026 while (cs->rx_chain != NULL) {
16027 struct pbuf *seg = cs->rx_chain;
16028 cs->rx_chain = pbuf_dechain(cs->rx_chain);
16029 pbuf_free(seg);
16030 }
16031 memset(cs, 0, sizeof(*cs));
16032 MG_FREE(cs);
16033 } else if (nc->listener == NULL) {
16034 /* Only close outgoing UDP pcb or listeners. */
16035 struct udp_pcb *upcb = cs->pcb.udp;
16036 if (upcb != NULL) {
16037 DBG(("%p udp_remove %p", nc, upcb));
16039 }
16040 memset(cs, 0, sizeof(*cs));
16041 MG_FREE(cs);
16042 }
16043 nc->sock = INVALID_SOCKET;
16044}
16045
16046void mg_lwip_if_get_conn_addr(struct mg_connection *nc, int remote,
16047 union socket_address *sa) {
16048 memset(sa, 0, sizeof(*sa));
16049 if (nc == NULL || nc->sock == INVALID_SOCKET) return;
16050 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
16051 if (nc->flags & MG_F_UDP) {
16052 struct udp_pcb *upcb = cs->pcb.udp;
16053 if (remote) {
16054 memcpy(sa, &nc->sa, sizeof(*sa));
16055 } else if (upcb != NULL) {
16056 sa->sin.sin_port = htons(upcb->local_port);
16057 SET_ADDR(sa, &upcb->local_ip);
16058 }
16059 } else {
16060 struct tcp_pcb *tpcb = cs->pcb.tcp;
16061 if (remote) {
16062 memcpy(sa, &nc->sa, sizeof(*sa));
16063 } else if (tpcb != NULL) {
16064 sa->sin.sin_port = htons(tpcb->local_port);
16065 SET_ADDR(sa, &tpcb->local_ip);
16066 }
16067 }
16068}
16069
16070void mg_lwip_if_sock_set(struct mg_connection *nc, sock_t sock) {
16071 nc->sock = sock;
16072}
16073
16074/* clang-format off */
16075#define MG_LWIP_IFACE_VTABLE \
16076 { \
16077 mg_lwip_if_init, \
16078 mg_lwip_if_free, \
16079 mg_lwip_if_add_conn, \
16080 mg_lwip_if_remove_conn, \
16081 mg_lwip_if_poll, \
16082 mg_lwip_if_listen_tcp, \
16083 mg_lwip_if_listen_udp, \
16084 mg_lwip_if_connect_tcp, \
16085 mg_lwip_if_connect_udp, \
16086 mg_lwip_if_tcp_send, \
16087 mg_lwip_if_udp_send, \
16088 mg_lwip_if_tcp_recv, \
16089 mg_lwip_if_udp_recv, \
16090 mg_lwip_if_create_conn, \
16091 mg_lwip_if_destroy_conn, \
16092 mg_lwip_if_sock_set, \
16093 mg_lwip_if_get_conn_addr, \
16094 }
16095/* clang-format on */
16096
16098#if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL
16100#endif
16101
16102#endif /* MG_ENABLE_NET_IF_LWIP_LOW_LEVEL */
16103#ifdef MG_MODULE_LINES
16104#line 1 "common/platforms/lwip/mg_lwip_ev_mgr.c"
16105#endif
16106/*
16107 * Copyright (c) 2014-2018 Cesanta Software Limited
16108 * All rights reserved
16109 *
16110 * Licensed under the Apache License, Version 2.0 (the ""License"");
16111 * you may not use this file except in compliance with the License.
16112 * You may obtain a copy of the License at
16113 *
16114 * http://www.apache.org/licenses/LICENSE-2.0
16115 *
16116 * Unless required by applicable law or agreed to in writing, software
16117 * distributed under the License is distributed on an ""AS IS"" BASIS,
16118 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16119 * See the License for the specific language governing permissions and
16120 * limitations under the License.
16121 */
16122
16123#if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL
16124
16125#ifndef MG_SIG_QUEUE_LEN
16126#define MG_SIG_QUEUE_LEN 32
16127#endif
16128
16129struct mg_ev_mgr_lwip_signal {
16130 int sig;
16131 struct mg_connection *nc;
16132};
16133
16134struct mg_ev_mgr_lwip_data {
16136 int sig_queue_len;
16137 int start_index;
16138};
16139
16141 struct mg_ev_mgr_lwip_data *md =
16142 (struct mg_ev_mgr_lwip_data *) nc->iface->data;
16143 mgos_lock();
16144 if (md->sig_queue_len >= MG_SIG_QUEUE_LEN) {
16145 mgos_unlock();
16146 return;
16147 }
16148 int end_index = (md->start_index + md->sig_queue_len) % MG_SIG_QUEUE_LEN;
16149 md->sig_queue[end_index].sig = sig;
16150 md->sig_queue[end_index].nc = nc;
16151 md->sig_queue_len++;
16153 mgos_unlock();
16154}
16155
16156void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) {
16157 struct mg_ev_mgr_lwip_data *md =
16158 (struct mg_ev_mgr_lwip_data *) mgr->ifaces[MG_MAIN_IFACE]->data;
16159 while (md->sig_queue_len > 0) {
16160 mgos_lock();
16161 int i = md->start_index;
16162 int sig = md->sig_queue[i].sig;
16163 struct mg_connection *nc = md->sig_queue[i].nc;
16164 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
16165 md->start_index = (i + 1) % MG_SIG_QUEUE_LEN;
16166 md->sig_queue_len--;
16167 mgos_unlock();
16168 if (nc->iface == NULL || nc->mgr == NULL) continue;
16169 switch (sig) {
16170 case MG_SIG_CONNECT_RESULT: {
16172 break;
16173 }
16174 case MG_SIG_CLOSE_CONN: {
16176 break;
16177 }
16178 case MG_SIG_RECV: {
16179 cs->recv_pending = 0;
16182 break;
16183 }
16184 case MG_SIG_TOMBSTONE: {
16185 break;
16186 }
16187 case MG_SIG_ACCEPT: {
16189 break;
16190 }
16191 }
16192 }
16193}
16194
16195void mg_lwip_if_init(struct mg_iface *iface) {
16196 LOG(LL_INFO, ("Mongoose %s, LwIP %u.%u.%u", MG_VERSION, LWIP_VERSION_MAJOR,
16198 iface->data = MG_CALLOC(1, sizeof(struct mg_ev_mgr_lwip_data));
16199#if !NO_SYS && !LWIP_TCPIP_CORE_LOCKING
16202#endif
16203}
16204
16205void mg_lwip_if_free(struct mg_iface *iface) {
16206 MG_FREE(iface->data);
16207 iface->data = NULL;
16208}
16209
16210void mg_lwip_if_add_conn(struct mg_connection *nc) {
16211 (void) nc;
16212}
16213
16215 struct mg_ev_mgr_lwip_data *md =
16216 (struct mg_ev_mgr_lwip_data *) nc->iface->data;
16217 /* Walk the queue and null-out further signals for this conn. */
16218 for (int i = 0; i < MG_SIG_QUEUE_LEN; i++) {
16219 if (md->sig_queue[i].nc == nc) {
16220 md->sig_queue[i].sig = MG_SIG_TOMBSTONE;
16221 }
16222 }
16223}
16224
16225time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms) {
16226 struct mg_mgr *mgr = iface->mgr;
16227 int n = 0;
16228 double now = mg_time();
16229 struct mg_connection *nc, *tmp;
16230 double min_timer = 0;
16231 int num_timers = 0;
16232#if 0
16233 DBG(("begin poll @%u", (unsigned int) (now * 1000)));
16234#endif
16236 for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
16237 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
16238 tmp = nc->next;
16239 n++;
16240 if (!mg_if_poll(nc, now)) continue;
16241 if (nc->sock != INVALID_SOCKET &&
16242 !(nc->flags & (MG_F_UDP | MG_F_LISTENING)) && cs->pcb.tcp != NULL &&
16243 cs->pcb.tcp->unsent != NULL) {
16245 }
16246 if (nc->ev_timer_time > 0) {
16247 if (num_timers == 0 || nc->ev_timer_time < min_timer) {
16249 }
16250 num_timers++;
16251 }
16252
16253 if (nc->sock != INVALID_SOCKET) {
16254 if (mg_lwip_if_can_send(nc, cs)) {
16257 }
16258 if (cs->rx_chain != NULL) {
16260 } else if (cs->draining_rx_chain) {
16261 /*
16262 * If the connection is about to close, and rx_chain is finally empty,
16263 * send the MG_SIG_CLOSE_CONN signal
16264 */
16266 }
16267 }
16268 }
16269#if 0
16270 DBG(("end poll @%u, %d conns, %d timers (min %u), next in %d ms",
16271 (unsigned int) (now * 1000), n, num_timers,
16272 (unsigned int) (min_timer * 1000), timeout_ms));
16273#endif
16274 (void) timeout_ms;
16275 return now;
16276}
16277
16278#endif /* MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL */
16279#ifdef MG_MODULE_LINES
16280#line 1 "common/platforms/wince/wince_libc.c"
16281#endif
16282/*
16283 * Copyright (c) 2014-2018 Cesanta Software Limited
16284 * All rights reserved
16285 *
16286 * Licensed under the Apache License, Version 2.0 (the ""License"");
16287 * you may not use this file except in compliance with the License.
16288 * You may obtain a copy of the License at
16289 *
16290 * http://www.apache.org/licenses/LICENSE-2.0
16291 *
16292 * Unless required by applicable law or agreed to in writing, software
16293 * distributed under the License is distributed on an ""AS IS"" BASIS,
16294 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16295 * See the License for the specific language governing permissions and
16296 * limitations under the License.
16297 */
16298
16299#ifdef WINCE
16300
16301const char *strerror(int err) {
16302 /*
16303 * TODO(alashkin): there is no strerror on WinCE;
16304 * look for similar wce_xxxx function
16305 */
16306 static char buf[10];
16307 snprintf(buf, sizeof(buf), "%d", err);
16308 return buf;
16309}
16310
16311int open(const char *filename, int oflag, int pmode) {
16312 /*
16313 * TODO(alashkin): mg_open function is not used in mongoose
16314 * but exists in documentation as utility function
16315 * Shall we delete it at all or implement for WinCE as well?
16316 */
16317 DebugBreak();
16318 return 0; /* for compiler */
16319}
16320
16321int _wstati64(const wchar_t *path, cs_stat_t *st) {
16322 DWORD fa = GetFileAttributesW(path);
16323 if (fa == INVALID_FILE_ATTRIBUTES) {
16324 return -1;
16325 }
16326 memset(st, 0, sizeof(*st));
16327 if ((fa & FILE_ATTRIBUTE_DIRECTORY) == 0) {
16328 HANDLE h;
16330 st->st_mode |= _S_IFREG;
16333 if (h == INVALID_HANDLE_VALUE) {
16334 return -1;
16335 }
16336 st->st_size = GetFileSize(h, NULL);
16337 GetFileTime(h, NULL, NULL, &ftime);
16338 st->st_mtime = (uint32_t)((((uint64_t) ftime.dwLowDateTime +
16339 ((uint64_t) ftime.dwHighDateTime << 32)) /
16340 10000000.0) -
16341 11644473600);
16342 CloseHandle(h);
16343 } else {
16344 st->st_mode |= _S_IFDIR;
16345 }
16346 return 0;
16347}
16348
16349/* Windows CE doesn't have neither gmtime nor strftime */
16350static void mg_gmt_time_string(char *buf, size_t buf_len, time_t *t) {
16351 FILETIME ft;
16353 if (t != NULL) {
16354 uint64_t filetime = (*t + 11644473600) * 10000000;
16355 ft.dwLowDateTime = filetime & 0xFFFFFFFF;
16356 ft.dwHighDateTime = (filetime & 0xFFFFFFFF00000000) >> 32;
16358 } else {
16360 }
16361 /* There is no PRIu16 in WinCE SDK */
16362 snprintf(buf, buf_len, "%d.%d.%d %d:%d:%d GMT", (int) systime.wYear,
16363 (int) systime.wMonth, (int) systime.wDay, (int) systime.wHour,
16364 (int) systime.wMinute, (int) systime.wSecond);
16365}
16366
16367#endif
16368#ifdef MG_MODULE_LINES
16369#line 1 "common/platforms/pic32/pic32_net_if.h"
16370#endif
16371/*
16372 * Copyright (c) 2014-2018 Cesanta Software Limited
16373 * All rights reserved
16374 *
16375 * Licensed under the Apache License, Version 2.0 (the ""License"");
16376 * you may not use this file except in compliance with the License.
16377 * You may obtain a copy of the License at
16378 *
16379 * http://www.apache.org/licenses/LICENSE-2.0
16380 *
16381 * Unless required by applicable law or agreed to in writing, software
16382 * distributed under the License is distributed on an ""AS IS"" BASIS,
16383 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16384 * See the License for the specific language governing permissions and
16385 * limitations under the License.
16386 */
16387
16388#ifndef CS_COMMON_PLATFORMS_PIC32_NET_IF_H_
16389#define CS_COMMON_PLATFORMS_PIC32_NET_IF_H_
16390
16391/* Amalgamated: #include "mongoose/src/net_if.h" */
16392
16393#ifdef __cplusplus
16394extern "C" {
16395#endif /* __cplusplus */
16396
16397#ifndef MG_ENABLE_NET_IF_PIC32
16398#define MG_ENABLE_NET_IF_PIC32 MG_NET_IF == MG_NET_IF_PIC32
16399#endif
16400
16401extern const struct mg_iface_vtable mg_pic32_iface_vtable;
16402
16403#ifdef __cplusplus
16404}
16405#endif /* __cplusplus */
16406
16407#endif /* CS_COMMON_PLATFORMS_PIC32_NET_IF_H_ */
16408#ifdef MG_MODULE_LINES
16409#line 1 "common/platforms/pic32/pic32_net_if.c"
16410#endif
16411/*
16412 * Copyright (c) 2014-2018 Cesanta Software Limited
16413 * All rights reserved
16414 *
16415 * Licensed under the Apache License, Version 2.0 (the ""License"");
16416 * you may not use this file except in compliance with the License.
16417 * You may obtain a copy of the License at
16418 *
16419 * http://www.apache.org/licenses/LICENSE-2.0
16420 *
16421 * Unless required by applicable law or agreed to in writing, software
16422 * distributed under the License is distributed on an ""AS IS"" BASIS,
16423 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16424 * See the License for the specific language governing permissions and
16425 * limitations under the License.
16426 */
16427
16428#if MG_ENABLE_NET_IF_PIC32
16429
16430int mg_pic32_if_create_conn(struct mg_connection *nc) {
16431 (void) nc;
16432 return 1;
16433}
16434
16435void mg_pic32_if_recved(struct mg_connection *nc, size_t len) {
16436 (void) nc;
16437 (void) len;
16438}
16439
16440void mg_pic32_if_add_conn(struct mg_connection *nc) {
16441 (void) nc;
16442}
16443
16444void mg_pic32_if_init(struct mg_iface *iface) {
16445 (void) iface;
16446 (void) mg_get_errno(); /* Shutup compiler */
16447}
16448
16449void mg_pic32_if_free(struct mg_iface *iface) {
16450 (void) iface;
16451}
16452
16453void mg_pic32_if_remove_conn(struct mg_connection *nc) {
16454 (void) nc;
16455}
16456
16457void mg_pic32_if_destroy_conn(struct mg_connection *nc) {
16458 if (nc->sock == INVALID_SOCKET) return;
16459 /* For UDP, only close outgoing sockets or listeners. */
16460 if (!(nc->flags & MG_F_UDP)) {
16461 /* Close TCP */
16463 } else if (nc->listener == NULL) {
16464 /* Only close outgoing UDP or listeners. */
16466 }
16467
16468 nc->sock = INVALID_SOCKET;
16469}
16470
16471int mg_pic32_if_listen_udp(struct mg_connection *nc, union socket_address *sa) {
16473 sa->sin.sin_family == AF_INET ? IP_ADDRESS_TYPE_IPV4
16475 ntohs(sa->sin.sin_port),
16476 sa->sin.sin_addr.s_addr == 0 ? 0 : (IP_MULTI_ADDRESS *) &sa->sin);
16477 if (nc->sock == INVALID_SOCKET) {
16478 return -1;
16479 }
16480 return 0;
16481}
16482
16483void mg_pic32_if_udp_send(struct mg_connection *nc, const void *buf,
16484 size_t len) {
16485 mbuf_append(&nc->send_mbuf, buf, len);
16486}
16487
16488void mg_pic32_if_tcp_send(struct mg_connection *nc, const void *buf,
16489 size_t len) {
16490 mbuf_append(&nc->send_mbuf, buf, len);
16491}
16492
16493int mg_pic32_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) {
16495 sa->sin.sin_family == AF_INET ? IP_ADDRESS_TYPE_IPV4
16497 ntohs(sa->sin.sin_port),
16498 sa->sin.sin_addr.s_addr == 0 ? 0 : (IP_MULTI_ADDRESS *) &sa->sin);
16499 memcpy(&nc->sa, sa, sizeof(*sa));
16500 if (nc->sock == INVALID_SOCKET) {
16501 return -1;
16502 }
16503 return 0;
16504}
16505
16506static int mg_accept_conn(struct mg_connection *lc) {
16507 struct mg_connection *nc;
16509 union socket_address sa;
16510
16511 nc = mg_if_accept_new_conn(lc);
16512
16513 if (nc == NULL) {
16514 return 0;
16515 }
16516
16517 nc->sock = lc->sock;
16518 nc->flags &= ~MG_F_LISTENING;
16519
16520 if (!TCPIP_TCP_SocketInfoGet((TCP_SOCKET) nc->sock, &si)) {
16521 return 0;
16522 }
16523
16524 if (si.addressType == IP_ADDRESS_TYPE_IPV4) {
16525 sa.sin.sin_family = AF_INET;
16526 sa.sin.sin_port = htons(si.remotePort);
16527 sa.sin.sin_addr.s_addr = si.remoteIPaddress.v4Add.Val;
16528 } else {
16529 /* TODO(alashkin): do something with _potential_ IPv6 */
16530 memset(&sa, 0, sizeof(sa));
16531 }
16532
16533 mg_if_accept_tcp_cb(nc, (union socket_address *) &sa, sizeof(sa));
16534
16535 return mg_pic32_if_listen_tcp(lc, &lc->sa) >= 0;
16536}
16537
16538char *inet_ntoa(struct in_addr in) {
16539 static char addr[17];
16540 snprintf(addr, sizeof(addr), "%d.%d.%d.%d", (int) in.S_un.S_un_b.s_b1,
16541 (int) in.S_un.S_un_b.s_b2, (int) in.S_un.S_un_b.s_b3,
16542 (int) in.S_un.S_un_b.s_b4);
16543 return addr;
16544}
16545
16546static void mg_handle_send(struct mg_connection *nc) {
16547 uint16_t bytes_written = 0;
16548 if (nc->flags & MG_F_UDP) {
16550 (UDP_SOCKET) nc->sock,
16551 nc->sa.sin.sin_family == AF_INET ? IP_ADDRESS_TYPE_IPV4
16553 ntohs(nc->sa.sin.sin_port), (IP_MULTI_ADDRESS *) &nc->sa.sin)) {
16555 return;
16556 }
16557 bytes_written = TCPIP_UDP_TxPutIsReady((UDP_SOCKET) nc->sock, 0);
16558 if (bytes_written >= nc->send_mbuf.len) {
16560 (uint8_t *) nc->send_mbuf.buf,
16561 nc->send_mbuf.len) != nc->send_mbuf.len) {
16563 bytes_written = 0;
16564 }
16565 }
16566 } else {
16567 bytes_written = TCPIP_TCP_FifoTxFreeGet((TCP_SOCKET) nc->sock);
16568 if (bytes_written != 0) {
16569 if (bytes_written > nc->send_mbuf.len) {
16570 bytes_written = nc->send_mbuf.len;
16571 }
16573 (uint8_t *) nc->send_mbuf.buf,
16574 bytes_written) != bytes_written) {
16576 bytes_written = 0;
16577 }
16578 }
16579 }
16580
16581 mg_if_sent_cb(nc, bytes_written);
16582}
16583
16584static void mg_handle_recv(struct mg_connection *nc) {
16585 uint16_t bytes_read = 0;
16586 uint8_t *buf = NULL;
16587 if (nc->flags & MG_F_UDP) {
16588 bytes_read = TCPIP_UDP_GetIsReady((UDP_SOCKET) nc->sock);
16589 if (bytes_read != 0 &&
16590 (nc->recv_mbuf_limit == -1 ||
16591 nc->recv_mbuf.len + bytes_read < nc->recv_mbuf_limit)) {
16592 buf = (uint8_t *) MG_MALLOC(bytes_read);
16593 if (TCPIP_UDP_ArrayGet((UDP_SOCKET) nc->sock, buf, bytes_read) !=
16594 bytes_read) {
16596 bytes_read = 0;
16597 MG_FREE(buf);
16598 }
16599 }
16600 } else {
16601 bytes_read = TCPIP_TCP_GetIsReady((TCP_SOCKET) nc->sock);
16602 if (bytes_read != 0) {
16603 if (nc->recv_mbuf_limit != -1 &&
16604 nc->recv_mbuf_limit - nc->recv_mbuf.len > bytes_read) {
16605 bytes_read = nc->recv_mbuf_limit - nc->recv_mbuf.len;
16606 }
16607 buf = (uint8_t *) MG_MALLOC(bytes_read);
16608 if (TCPIP_TCP_ArrayGet((TCP_SOCKET) nc->sock, buf, bytes_read) !=
16609 bytes_read) {
16611 MG_FREE(buf);
16612 bytes_read = 0;
16613 }
16614 }
16615 }
16616
16617 if (bytes_read != 0) {
16618 mg_if_recv_tcp_cb(nc, buf, bytes_read, 1 /* own */);
16619 }
16620}
16621
16622time_t mg_pic32_if_poll(struct mg_iface *iface, int timeout_ms) {
16623 struct mg_mgr *mgr = iface->mgr;
16624 double now = mg_time();
16625 struct mg_connection *nc, *tmp;
16626
16627 for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
16628 tmp = nc->next;
16629
16630 if (nc->flags & MG_F_CONNECTING) {
16631 /* processing connections */
16632 if (nc->flags & MG_F_UDP ||
16634 mg_if_connect_cb(nc, 0);
16635 }
16636 } else if (nc->flags & MG_F_LISTENING) {
16638 /* accept new connections */
16639 mg_accept_conn(nc);
16640 }
16641 } else {
16642 if (nc->send_mbuf.len != 0) {
16643 mg_handle_send(nc);
16644 }
16645
16646 if (nc->recv_mbuf_limit == -1 ||
16647 nc->recv_mbuf.len < nc->recv_mbuf_limit) {
16648 mg_handle_recv(nc);
16649 }
16650 }
16651 }
16652
16653 for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
16654 tmp = nc->next;
16655 if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) ||
16656 (nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE))) {
16657 mg_close_conn(nc);
16658 }
16659 }
16660
16661 return now;
16662}
16663
16665 nc->sock = sock;
16666}
16667
16669 union socket_address *sa) {
16670 /* TODO(alaskin): not implemented yet */
16671}
16672
16674 const union socket_address *sa) {
16676 sa->sin.sin_family == AF_INET ? IP_ADDRESS_TYPE_IPV4
16678 ntohs(sa->sin.sin_port), (IP_MULTI_ADDRESS *) &sa->sin);
16679 nc->err = (nc->sock == INVALID_SOCKET) ? -1 : 0;
16680}
16681
16682void mg_pic32_if_connect_udp(struct mg_connection *nc) {
16684 nc->err = (nc->sock == INVALID_SOCKET) ? -1 : 0;
16685}
16686
16687/* clang-format off */
16688#define MG_PIC32_IFACE_VTABLE \
16689 { \
16690 mg_pic32_if_init, \
16691 mg_pic32_if_free, \
16692 mg_pic32_if_add_conn, \
16693 mg_pic32_if_remove_conn, \
16694 mg_pic32_if_poll, \
16695 mg_pic32_if_listen_tcp, \
16696 mg_pic32_if_listen_udp, \
16697 mg_pic32_if_connect_tcp, \
16698 mg_pic32_if_connect_udp, \
16699 mg_pic32_if_tcp_send, \
16700 mg_pic32_if_udp_send, \
16701 mg_pic32_if_recved, \
16702 mg_pic32_if_create_conn, \
16703 mg_pic32_if_destroy_conn, \
16704 mg_pic32_if_sock_set, \
16705 mg_pic32_if_get_conn_addr, \
16706 }
16707/* clang-format on */
16708
16710#if MG_NET_IF == MG_NET_IF_PIC32
16712#endif
16713
16714#endif /* MG_ENABLE_NET_IF_PIC32 */
16715#ifdef MG_MODULE_LINES
16716#line 1 "common/platforms/windows/windows_direct.c"
16717#endif
16718/*
16719 * Copyright (c) 2014-2018 Cesanta Software Limited
16720 * All rights reserved
16721 *
16722 * Licensed under the Apache License, Version 2.0 (the ""License"");
16723 * you may not use this file except in compliance with the License.
16724 * You may obtain a copy of the License at
16725 *
16726 * http://www.apache.org/licenses/LICENSE-2.0
16727 *
16728 * Unless required by applicable law or agreed to in writing, software
16729 * distributed under the License is distributed on an ""AS IS"" BASIS,
16730 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16731 * See the License for the specific language governing permissions and
16732 * limitations under the License.
16733 */
16734
16735#ifdef _WIN32
16736
16737int rmdir(const char *dirname) {
16738 return _rmdir(dirname);
16739}
16740
16741unsigned int sleep(unsigned int seconds) {
16742 Sleep(seconds * 1000);
16743 return 0;
16744}
16745
16746#endif /* _WIN32 */
#define LONG
Definition crc32c.cxx:230
unsigned int DWORD
Definition mcstd.h:51
int mg_start_thread(mg_thread_func_t f, void *p)
int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, int is_form_url_encoded)
int(* mg_event_handler_t)(struct mg_event *event)
Definition mongoose4.h:70
int mg_mgr_poll(struct mg_mgr *m, int timeout_ms)
struct mg_str message
Definition mongoose6.h:2068
void mg_mqtt_ping(struct mg_connection *nc)
void mg_set_protocol_mqtt(struct mg_connection *nc)
void * user_data
Definition mongoose6.h:1396
void mg_mgr_free(struct mg_mgr *m)
const char * hexdump_file
Definition mongoose6.h:1232
int mg_resolve_from_hosts_file(const char *host, union socket_address *usa)
void cs_base64_update(struct cs_base64_ctx *ctx, const char *str, size_t len)
void cs_to_hex(char *to, const unsigned char *p, size_t len) WEAK
#define WEBSOCKET_DONT_FIN
Definition mongoose6.h:2365
#define MG_MK_STR(str_literal)
Definition mongoose6.h:2006
void mg_send_dns_query(struct mg_connection *nc, const char *name, int query_type)
#define WEBSOCKET_OP_PING
Definition mongoose6.h:2350
char * cs_md5(char buf[33],...)
void mg_mqtt_disconnect(struct mg_connection *nc)
#define MG_MQTT_HAS_USER_NAME
Definition mongoose6.h:2944
#define MG_MQTT_CMD_PUBREC
Definition mongoose6.h:2904
void mg_mqtt_publish(struct mg_connection *nc, const char *topic, uint16_t message_id, int flags, const void *data, size_t len)
void mg_if_get_conn_addr(struct mg_connection *nc, int remote, union socket_address *sa)
#define MG_MQTT_CMD_UNSUBACK
Definition mongoose6.h:2910
void * user_data
Definition mongoose6.h:1265
struct mg_str header_names[MG_MAX_HTTP_HEADERS]
Definition mongoose6.h:2090
int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap) WEAK
struct mg_str payload
Definition mongoose6.h:2878
#define MG_MAX_HTTP_HEADERS
Definition mongoose6.h:2031
#define MG_MAX_HTTP_SEND_MBUF
Definition mongoose6.h:2047
#define MG_MAX_DNS_ANSWERS
Definition mongoose6.h:3169
#define MG_EV_WEBSOCKET_FRAME
Definition mongoose6.h:2121
int mg_stat(const char *path, cs_stat_t *st)
struct mg_connection * mg_connect_http(struct mg_mgr *mgr, mg_event_handler_t event_handler, const char *url, const char *extra_headers, const char *post_data)
#define MG_EV_WEBSOCKET_HANDSHAKE_DONE
Definition mongoose6.h:2120
int mg_resolve_async_opt(struct mg_mgr *mgr, const char *name, int query, mg_resolve_callback_t cb, void *data, struct mg_resolve_async_opts opts)
mg_event_handler_t handler
Definition mongoose6.h:1264
struct mg_connection * active_connections
Definition mongoose6.h:1231
void mg_mqtt_connack(struct mg_connection *nc, uint8_t return_code)
cs_log_level
Definition mongoose6.h:741
#define MG_MQTT_CMD_PUBACK
Definition mongoose6.h:2903
int mg_dns_encode_record(struct mbuf *io, struct mg_dns_resource_record *rr, const char *name, size_t nlen, const void *rdata, size_t rlen)
void mg_mqtt_pong(struct mg_connection *nc)
struct mg_connection ** dns_conn
Definition mongoose6.h:3426
int mg_is_big_endian(void)
#define MG_F_CLOSE_IMMEDIATELY
Definition mongoose6.h:1289
size_t mbuf_insert(struct mbuf *a, size_t off, const void *buf, size_t) WEAK
size_t mg_parse_multipart(const char *buf, size_t buf_len, char *var_name, size_t var_name_len, char *file_name, size_t file_name_len, const char **chunk, size_t *chunk_len)
#define MG_SOCK_STRINGIFY_PORT
Definition mongoose6.h:1905
void mbuf_remove(struct mbuf *mb, size_t n) WEAK
void mg_mgr_init(struct mg_mgr *m, void *user_data)
int mg_dns_insert_header(struct mbuf *io, size_t pos, struct mg_dns_message *msg)
void mg_send_head(struct mg_connection *n, int status_code, int64_t content_length, const char *extra_headers)
void mg_mqtt_pubcomp(struct mg_connection *nc, uint16_t message_id)
void(* proto_data_destructor)(void *proto_data)
Definition mongoose6.h:1263
struct mg_connection * mg_next(struct mg_mgr *s, struct mg_connection *conn)
int mg_resolve_async(struct mg_mgr *mgr, const char *name, int query, mg_resolve_callback_t cb, void *data)
#define MG_EV_RECV
Definition mongoose6.h:1222
void mg_if_accept_tcp_cb(struct mg_connection *nc, union socket_address *sa, size_t sa_len)
int mg_normalize_uri_path(const struct mg_str *in, struct mg_str *out)
#define WEBSOCKET_OP_CLOSE
Definition mongoose6.h:2349
const char * c_strnstr(const char *s, const char *find, size_t slen) WEAK
int mg_vprintf(struct mg_connection *nc, const char *fmt, va_list ap)
const char * mg_set_ssl(struct mg_connection *nc, const char *cert, const char *ca_cert)
void mg_broadcast(struct mg_mgr *, mg_event_handler_t func, void *, size_t)
#define MG_DNS_AAAA_RECORD
Definition mongoose6.h:3165
void mg_send_response_line(struct mg_connection *c, int status_code, const char *extra_headers)
#define MG_MQTT_CMD_CONNACK
Definition mongoose6.h:2901
void mg_send_mqtt_handshake(struct mg_connection *nc, const char *client_id)
#define MG_VPRINTF_BUFFER_SIZE
Definition mongoose6.h:1179
struct mg_str header_values[MG_MAX_HTTP_HEADERS]
Definition mongoose6.h:2091
void mbuf_free(struct mbuf *mbuf) WEAK
union socket_address sa
Definition mongoose6.h:1253
#define MG_EV_WEBSOCKET_CONTROL_FRAME
Definition mongoose6.h:2122
void mg_serve_http(struct mg_connection *nc, struct http_message *hm, struct mg_serve_http_opts opts)
#define MG_F_WANT_READ
Definition mongoose6.h:1283
#define MG_MAX_CGI_ENVIR_VARS
Definition mongoose6.h:2059
#define MG_SOCK_STRINGIFY_REMOTE
Definition mongoose6.h:1906
int mg_open(const char *path, int flag, int mode)
double mg_set_timer(struct mg_connection *c, double timestamp)
int mg_conn_addr_to_str(struct mg_connection *nc, char *buf, size_t len, int flags)
#define MG_MQTT_GET_QOS(flags)
Definition mongoose6.h:2936
#define MG_EV_CONNECT
Definition mongoose6.h:1221
int mg_parse_http(const char *s, int n, struct http_message *hm, int is_req)
size_t mg_match_prefix_n(const struct mg_str, const struct mg_str) WEAK
#define MG_EV_SSI_CALL
Definition mongoose6.h:2117
mg_resolve_err
Definition mongoose6.h:3409
#define MG_SEND_FUNC(s, b, l, f)
Definition mongoose6.h:1187
size_t len
Definition mongoose6.h:835
void * proto_data
Definition mongoose6.h:1262
#define MG_MAX_PATH
Definition mongoose6.h:2042
void mbuf_resize(struct mbuf *a, size_t new_size) WEAK
size_t len
Definition mongoose6.h:1207
void mg_if_recv_tcp_cb(struct mg_connection *nc, void *buf, int len)
void mg_printf_html_escape(struct mg_connection *nc, const char *fmt,...)
#define MG_F_LISTENING
Definition mongoose6.h:1278
void mg_if_sent_cb(struct mg_connection *nc, int num_sent)
#define MG_MQTT_HAS_WILL
Definition mongoose6.h:2941
#define MG_DNS_CNAME_RECORD
Definition mongoose6.h:3164
struct mg_connection * mg_if_accept_new_conn(struct mg_connection *lc)
#define MG_CGI_ENVIRONMENT_SIZE
Definition mongoose6.h:2055
int mg_casecmp(const char *s1, const char *s2) WEAK
void mg_send(struct mg_connection *nc, const void *buf, int len)
int mg_socketpair(sock_t[2], int sock_type)
#define WEBSOCKET_OP_PONG
Definition mongoose6.h:2351
#define MG_MQTT_CMD_PUBREL
Definition mongoose6.h:2905
struct mg_connection * next
Definition mongoose6.h:1247
void mg_send_http_chunk(struct mg_connection *nc, const char *buf, size_t len)
#define MG_MQTT_CMD_PINGREQ
Definition mongoose6.h:2911
#define MG_EV_MQTT_CONNACK_SERVER_UNAVAILABLE
Definition mongoose6.h:2953
#define MG_ENV_EXPORT_TO_CGI
Definition mongoose6.h:2063
void mg_hexdump_connection(struct mg_connection *nc, const char *path, const void *buf, int num_bytes, int ev)
struct mbuf send_mbuf
Definition mongoose6.h:1256
#define MG_DNS_A_RECORD
Definition mongoose6.h:3163
#define ARRAY_SIZE(array)
Definition mongoose6.h:119
struct mbuf recv_mbuf
Definition mongoose6.h:1255
unsigned char flags
Definition mongoose6.h:2101
void mg_if_connect_cb(struct mg_connection *nc, int err)
int mg_http_create_digest_auth_header(char *buf, size_t buf_len, const char *method, const char *uri, const char *auth_domain, const char *user, const char *passwd)
#define MG_EV_MQTT_CONNECT
Definition mongoose6.h:2917
#define MG_EV_POLL
Definition mongoose6.h:1219
unsigned int flags
Definition mongoose6.h:1437
void mg_sock_set(struct mg_connection *nc, sock_t sock)
#define MG_MQTT_QOS(qos)
Definition mongoose6.h:2935
#define MG_F_UDP
Definition mongoose6.h:1279
void mg_send_websocket_handshake2(struct mg_connection *nc, const char *path, const char *host, const char *protocol, const char *extra_headers)
void cs_base64_finish(struct cs_base64_ctx *ctx)
sock_t ctl[2]
Definition mongoose6.h:1234
double mg_time(void)
double ev_timer_time
Definition mongoose6.h:1260
void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path, mg_event_handler_t handler)
void mg_sock_to_str(sock_t sock, char *buf, size_t len, int flags)
#define MG_MQTT_CMD_PUBCOMP
Definition mongoose6.h:2906
void mg_mqtt_puback(struct mg_connection *nc, uint16_t message_id)
uint16_t flags
Definition mongoose6.h:3192
void mg_printf_websocket_frame(struct mg_connection *nc, int op_and_flags, const char *fmt,...)
void * SSL_CTX
Definition mongoose6.h:1175
#define MG_MQTT_EVENT_BASE
Definition mongoose6.h:2916
#define MG_MQTT_CMD_PUBLISH
Definition mongoose6.h:2902
struct mg_dns_resource_record questions[MG_MAX_DNS_QUESTIONS]
Definition mongoose6.h:3196
#define MG_EV_HTTP_CHUNK
Definition mongoose6.h:2116
struct sockaddr sin6
Definition mongoose6.h:1200
#define MG_SOCK_STRINGIFY_IP
Definition mongoose6.h:1904
size_t mg_match_prefix(const char *, int, const char *) WEAK
#define MG_MQTT_CMD_PINGRESP
Definition mongoose6.h:2912
#define MG_EV_TIMER
Definition mongoose6.h:1225
#define MG_MQTT_CMD_CONNECT
Definition mongoose6.h:2900
void mg_set_protocol_http_websocket(struct mg_connection *nc)
void mg_send_websocket_framev(struct mg_connection *nc, int op_and_flags, const struct mg_str *strings, int num_strings)
int mg_hexdump(const void *buf, int len, char *dst, int dst_len)
#define MG_DNS_MESSAGE
Definition mongoose6.h:3171
int mg_vcasecmp(const struct mg_str *str1, const char *str2) WEAK
#define MG_WEBSOCKET_PING_INTERVAL_SECONDS
Definition mongoose6.h:2051
#define MG_EV_SEND
Definition mongoose6.h:1223
unsigned long flags
Definition mongoose6.h:1276
int mg_base64_decode(const unsigned char *s, int len, char *dst)
struct mg_connection * mg_connect_ws(struct mg_mgr *mgr, mg_event_handler_t event_handler, const char *url, const char *protocol, const char *extra_headers)
struct mg_connection * listener
Definition mongoose6.h:1248
struct mg_connection * prev
Definition mongoose6.h:1247
#define MG_VERSION
Definition mongoose6.h:26
#define MG_MQTT_HAS_PASSWORD
Definition mongoose6.h:2943
void mg_mqtt_pubrec(struct mg_connection *nc, uint16_t message_id)
void * user_data
Definition mongoose6.h:1236
time_t last_io_time
Definition mongoose6.h:1259
void mg_set_close_on_exec(sock_t sock)
size_t recv_mbuf_limit
Definition mongoose6.h:1254
double cs_time(void) WEAK
struct mg_connection * mg_connect_ws_opt(struct mg_mgr *mgr, mg_event_handler_t ev_handler, struct mg_connect_opts opts, const char *url, const char *protocol, const char *extra_headers)
#define MG_F_DELETE_CHUNK
Definition mongoose6.h:1291
struct mg_str body
Definition mongoose6.h:2094
int mg_resolve(const char *domain_name, char *ip_addr_buf, size_t buf_len)
#define MG_EV_HTTP_REPLY
Definition mongoose6.h:2115
void mg_set_protocol_dns(struct mg_connection *nc)
const char * mg_skip(const char *s, const char *end, const char *delims, struct mg_str *v)
void mg_mqtt_suback(struct mg_connection *nc, uint8_t *qoss, size_t qoss_len, uint16_t message_id)
struct sockaddr sa
Definition mongoose6.h:1195
#define MG_MAX_HTTP_REQUEST_SIZE
Definition mongoose6.h:2035
#define MG_MQTT_CMD_UNSUBSCRIBE
Definition mongoose6.h:2909
struct mg_mgr * mgr
Definition mongoose6.h:1249
int mg_parse_dns(const char *buf, int len, struct mg_dns_message *msg)
char * buf
Definition mongoose6.h:834
void mg_mqtt_unsuback(struct mg_connection *nc, uint16_t message_id)
void cs_base64_init(struct cs_base64_ctx *ctx, cs_base64_putc_t b64_putc, void *user_data)
struct mg_dns_resource_record * mg_dns_next_record(struct mg_dns_message *msg, int query, struct mg_dns_resource_record *prev)
#define MG_F_RESOLVING
Definition mongoose6.h:1280
void mbuf_init(struct mbuf *mbuf, size_t initial_size) WEAK
struct mg_str rdata
Definition mongoose6.h:3186
void mg_send_mqtt_handshake_opt(struct mg_connection *nc, const char *client_id, struct mg_send_mqtt_handshake_opts)
size_t mbuf_append(struct mbuf *a, const void *buf, size_t len) WEAK
#define MG_F_SSL_HANDSHAKE_DONE
Definition mongoose6.h:1282
int mg_sock_addr_to_str(const union socket_address *sa, char *buf, size_t len, int flags)
void mg_base64_encode(const unsigned char *src, int src_len, char *dst)
void mg_send_websocket_frame(struct mg_connection *nc, int op_and_flags, const void *data, size_t data_len)
#define MG_EV_MQTT_PUBLISH
Definition mongoose6.h:2919
void(* mg_resolve_callback_t)(struct mg_dns_message *dns_message, void *user_data, enum mg_resolve_err)
Definition mongoose6.h:3416
#define MG_F_IS_WEBSOCKET
Definition mongoose6.h:1285
#define MG_RECV_FUNC(s, b, l, f)
Definition mongoose6.h:1186
void cs_sha1_final(unsigned char digest[20], cs_sha1_ctx *context)
int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf, size_t buf_size)
struct mg_str mg_mk_str(const char *s) WEAK
void cs_base64_encode(const unsigned char *src, int src_len, char *dst)
int mg_get_http_var(const struct mg_str *buf, const char *name, char *dst, size_t dst_len)
void mg_send_websocket_handshake(struct mg_connection *nc, const char *uri, const char *extra_headers)
void mg_printf_http_chunk(struct mg_connection *nc, const char *fmt,...)
#define MG_EV_MQTT_SUBSCRIBE
Definition mongoose6.h:2924
const char * mg_next_comma_list_entry(const char *, struct mg_str *, struct mg_str *) WEAK
#define MG_EV_CLOSE
Definition mongoose6.h:1224
size_t mg_dns_uncompress_name(struct mg_dns_message *msg, struct mg_str *name, char *dst, int dst_len)
struct mg_connection * mg_connect_http_opt(struct mg_mgr *mgr, mg_event_handler_t ev_handler, struct mg_connect_opts opts, const char *url, const char *extra_headers, const char *post_data)
void mbuf_trim(struct mbuf *mbuf) WEAK
#define MG_MQTT_CMD_DISCONNECT
Definition mongoose6.h:2913
FILE * mg_fopen(const char *path, const char *mode)
struct mg_str * mg_get_http_header(struct http_message *hm, const char *name)
void cs_sha1_update(cs_sha1_ctx *context, const unsigned char *data, uint32_t len)
#define MG_MQTT_CMD_SUBSCRIBE
Definition mongoose6.h:2907
#define MG_MQTT_CMD_SUBACK
Definition mongoose6.h:2908
int mg_vcmp(const struct mg_str *str1, const char *str2) WEAK
int mg_parse_uri(const struct mg_str uri, struct mg_str *scheme, struct mg_str *user_info, struct mg_str *host, unsigned int *port, struct mg_str *path, struct mg_str *query, struct mg_str *fragment)
#define MG_F_WANT_WRITE
Definition mongoose6.h:1284
size_t size
Definition mongoose6.h:836
int mg_check_ip_acl(const char *acl, uint32_t remote_ip)
struct mg_dns_resource_record answers[MG_MAX_DNS_ANSWERS]
Definition mongoose6.h:3197
#define MG_F_CONNECTING
Definition mongoose6.h:1281
mg_event_handler_t proto_handler
Definition mongoose6.h:1261
MG_INTERNAL void mg_close_conn(struct mg_connection *conn)
void * SSL
Definition mongoose6.h:1174
struct mg_str pkt
Definition mongoose6.h:3191
const char * p
Definition mongoose6.h:1206
void cs_sha1_init(cs_sha1_ctx *context)
int mg_ncasecmp(const char *s1, const char *s2, size_t len) WEAK
int mg_dns_parse_record_data(struct mg_dns_message *msg, struct mg_dns_resource_record *rr, void *data, size_t data_len)
#define MG_EV_ACCEPT
Definition mongoose6.h:1220
#define MG_EV_MQTT_CONNACK_ACCEPTED
Definition mongoose6.h:2950
void mg_mqtt_unsubscribe(struct mg_connection *nc, char **topics, size_t topics_len, uint16_t message_id)
#define MG_EV_WEBSOCKET_HANDSHAKE_REQUEST
Definition mongoose6.h:2119
struct sockaddr_in sin
Definition mongoose6.h:1196
int mg_printf(struct mg_connection *conn, const char *fmt,...)
void mg_mqtt_subscribe(struct mg_connection *nc, const struct mg_mqtt_topic_expression *topics, size_t topics_len, uint16_t message_id)
void mg_mqtt_pubrel(struct mg_connection *nc, uint16_t message_id)
#define WEBSOCKET_OP_CONTINUE
Definition mongoose6.h:2346
int mg_mqtt_next_subscribe_topic(struct mg_mqtt_message *msg, struct mg_str *topic, uint8_t *qos, int pos)
#define MG_F_SEND_AND_CLOSE
Definition mongoose6.h:1288
uint16_t transaction_id
Definition mongoose6.h:3193
#define MG_EV_HTTP_REQUEST
Definition mongoose6.h:2114
@ MG_RESOLVE_TIMEOUT
Definition mongoose6.h:3413
@ MG_RESOLVE_EXCEEDED_RETRY_COUNT
Definition mongoose6.h:3412
@ MG_RESOLVE_OK
Definition mongoose6.h:3410
@ MG_RESOLVE_NO_ANSWERS
Definition mongoose6.h:3411
@ MG_DNS_INVALID_RECORD
Definition mongoose6.h:3174
@ MG_DNS_ANSWER
Definition mongoose6.h:3176
@ MG_DNS_QUESTION
Definition mongoose6.h:3175
#define FD_SETSIZE
Definition msystem.h:199
static std::string q(const char *s)
HNDLE hKey
DWORD n[4]
Definition mana.cxx:247
void * data
Definition mana.cxx:268
INT type
Definition mana.cxx:269
BOOL create
Definition mchart.cxx:39
char addr[128]
Definition mcnaf.cxx:104
double count
Definition mdump.cxx:33
KEY key
Definition mdump.cxx:34
INT i
Definition mdump.cxx:32
INT bl
Definition mdump.cxx:29
char response[10000]
Definition melog.cxx:90
#define closesocket(s)
Definition melog.cxx:29
static int offset
Definition mgd.cxx:1500
#define TRUE
Definition midas.h:182
#define end
#define message(type, str)
#define read(n, a, f)
#define sleep(ms)
#define write(n, a, f, d)
#define mask(slot)
Definition midas_macro.h:54
#define begin
#define name(x)
Definition midas_macro.h:24
#define set(var, value)
static FILE * fp
#define mg_mkdir(x, y)
#define SOMAXCONN
#define HEXTOI(x)
const char * mime_type
static void do_ssi_exec(struct mg_connection *conn, char *tag)
#define INVALID_SOCKET
size_t ext_len
const char * extension
#define INT64_FMT
static const char * month_names[]
mg_sig_type
mg_q_msg_type
void mg_set_nameserver(struct mg_mgr *mgr, const char *nameserver)
#define MG_NULL_STR
#define MG_AUTH_FLAG_IS_GLOBAL_PASS_FILE
#define DO_NOT_WARN_UNUSED
void mg_http_send_error(struct mg_connection *nc, int code, const char *reason)
#define LIST_INIT(head)
int mg_get_http_basic_auth(struct http_message *hm, char *user, size_t user_len, char *pass, size_t pass_len)
int mg_parse_http_basic_auth(struct mg_str *hdr, char *user, size_t user_len, char *pass, size_t pass_len)
#define MG_UD_ARG(ud)
#define MG_AUTH_FLAG_IS_DIRECTORY
void mg_hash_sha1_v(size_t num_msgs, const uint8_t *msgs[], const size_t *msg_lens, uint8_t *digest)
void mg_send_websocket_handshake3v(struct mg_connection *nc, const struct mg_str path, const struct mg_str host, const struct mg_str protocol, const struct mg_str extra_headers, const struct mg_str user, const struct mg_str pass)
#define MG_ENABLE_HTTP_WEBDAV
#define LIST_REMOVE(elm, field)
#define MG_EV_SSI_CALL_CTX
#define MG_CB(cb, ud)
void mg_http_send_digest_auth_request(struct mg_connection *c, const char *domain)
#define MG_F_SSL
#define MG_AUTH_FLAG_ALLOW_MISSING_FILE
#define LIST_FIRST(head)
#define MG_F_RECV_AND_CLOSE
void mg_http_send_redirect(struct mg_connection *nc, int status_code, const struct mg_str location, const struct mg_str extra_headers)
int mg_check_digest_auth(struct mg_str method, struct mg_str uri, struct mg_str username, struct mg_str cnonce, struct mg_str response, struct mg_str qop, struct mg_str nc, struct mg_str nonce, struct mg_str auth_domain, FILE *fp)
#define MG_MAIN_IFACE
int mg_mqtt_match_topic_expression(struct mg_str exp, struct mg_str topic)
int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain, FILE *fp)
int mg_http_parse_header2(struct mg_str *hdr, const char *var_name, char **buf, size_t buf_size)
void mg_hash_md5_v(size_t num_msgs, const uint8_t *msgs[], const size_t *msg_lens, uint8_t *digest)
#define MG_LWIP
int mg_dns_encode_name(struct mbuf *io, const char *name, size_t len)
#define MG_ENABLE_HTTP_STREAMING_MULTIPART
int mg_mqtt_vmatch_topic_expression(const char *exp, struct mg_str topic)
#define LIST_NEXT(elm, field)
void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path, const char *host, const char *protocol, const char *extra_headers, const char *user, const char *pass)
#define LIST_INSERT_HEAD(head, elm, field)
int mg_dns_copy_questions(struct mbuf *io, struct mg_dns_message *msg)
int mg_http_is_authorized(struct http_message *hm, struct mg_str path, const char *domain, const char *passwords_file, int flags)
void mg_register_http_endpoint_opt(struct mg_connection *nc, const char *uri_path, mg_event_handler_t handler, struct mg_http_endpoint_opts opts)
#define TCP_NEW
#define MG_COPY_COMMON_CONNECTION_OPTIONS(dst, src)
int mg_pic32_if_listen_udp(struct mg_connection *nc, union socket_address *sa)
#define LOG(l, x)
void mg_pic32_if_udp_send(struct mg_connection *nc, const void *buf, size_t len)
void mg_socket_if_sock_set(struct mg_connection *nc, sock_t sock)
#define IPADDR_NTOA
int _kill(int pid, int sig)
void cs_md5_final(unsigned char digest[16], cs_md5_ctx *ctx)
void mg_lwip_if_connect_udp(struct mg_connection *nc)
struct mg_connection * mg_bind(struct mg_mgr *srv, const char *address, MG_CB(mg_event_handler_t event_handler, void *user_data))
static OsiMsgQ_t s_mg_q
int mg_pic32_if_listen_tcp(struct mg_connection *nc, union socket_address *sa)
int _getpid()
static int mg_accept_conn(struct mg_connection *lc)
#define MG_MALLOC
static int mg_sl_if_listen_tcp(struct mg_connection *nc, union socket_address *sa)
void mg_socket_if_connect_udp(struct mg_connection *nc)
void mg_sl_if_sock_set(struct mg_connection *nc, sock_t sock)
static sock_t mg_open_listening_socket(union socket_address *sa, int type, int proto)
int mg_strcmp(const struct mg_str str1, const struct mg_str str2) WEAK
MG_INTERNAL void mg_remove_conn(struct mg_connection *c)
void sl_restart_cb(struct mg_mgr *mgr)
void cs_md5_init(cs_md5_ctx *ctx)
struct mg_connection * mg_add_sock_opt(struct mg_mgr *s, sock_t sock, MG_CB(mg_event_handler_t callback, void *user_data), struct mg_add_sock_opts opts)
static int mg_sl_if_udp_recv(struct mg_connection *nc, void *buf, size_t len, union socket_address *sa, size_t *sa_len)
const struct mg_iface_vtable * mg_ifaces[]
static void mg_lwip_if_connect_tcp_tcpip(void *arg)
MG_INTERNAL struct mg_connection * mg_create_connection_base(struct mg_mgr *mgr, mg_event_handler_t callback, struct mg_add_sock_opts opts)
static int mg_socket_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len)
@ LL_INFO
@ LL_DEBUG
@ LL_ERROR
@ LL_VERBOSE_DEBUG
#define MG_UDP_IO_SIZE
#define MG_LWIP_IFACE_VTABLE
static int mg_do_recv(struct mg_connection *nc)
MG_INTERNAL struct mg_connection * mg_create_connection(struct mg_mgr *mgr, mg_event_handler_t callback, struct mg_add_sock_opts opts)
void mg_lwip_if_destroy_conn(struct mg_connection *nc)
static int mg_socket_if_udp_recv(struct mg_connection *nc, void *buf, size_t len, union socket_address *sa, size_t *sa_len)
void mg_pic32_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len)
time_t mg_pic32_if_poll(struct mg_iface *iface, int timeout_ms)
static void mg_null_if_add_conn(struct mg_connection *c)
int mg_null_if_tcp_recv(struct mg_connection *c, void *buf, size_t len)
void mg_lwip_if_add_conn(struct mg_connection *nc)
static void mg_lwip_tcp_error_cb(void *arg, err_t err)
void mg_mbuf_append_base64_putc(char ch, void *user_data)
#define _MG_CALLBACK_MODIFIABLE_FLAGS_MASK
void mg_basic_auth_header(const struct mg_str user, const struct mg_str pass, struct mbuf *buf)
static void tcp_output_tcpip(void *arg)
bool mg_start_task(int priority, int stack_size, mg_init_cb mg_init)
#define DBG(x)
@ MG_SIG_CLOSE_CONN
@ MG_SIG_RECV
@ MG_SIG_TOMBSTONE
@ MG_SIG_ACCEPT
@ MG_SIG_CONNECT_RESULT
#define _MG_F_FD_ERROR
double mg_mgr_min_timer(const struct mg_mgr *mgr)
static void mg_lwip_if_connect_udp_tcpip(void *arg)
static void mg_null_if_get_conn_addr(struct mg_connection *c, int remote, union socket_address *sa)
#define MG_UDP_RECV_BUFFER_SIZE
static int parse_net(const char *spec, uint32_t *net, uint32_t *mask)
#define MIN(a, b)
#define ip_2_ip4(addr)
int mg_lwip_if_create_conn(struct mg_connection *nc)
time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms)
void mg_pic32_if_recved(struct mg_connection *nc, size_t len)
static void mg_null_if_free(struct mg_iface *iface)
void mg_pic32_if_add_conn(struct mg_connection *nc)
void mg_lwip_handle_accept(struct mg_connection *nc)
struct mg_str mg_url_encode(const struct mg_str src)
static int mg_sl_if_create_conn(struct mg_connection *nc)
int mg_asprintf(char **buf, size_t size, const char *fmt,...) WEAK
int _isatty(int fd)
MG_INTERNAL size_t recv_avail_size(struct mg_connection *conn, size_t max)
static void mg_sl_if_connect_tcp(struct mg_connection *nc, const union socket_address *sa)
void mg_lwip_if_get_conn_addr(struct mg_connection *nc, int remote, union socket_address *sa)
void _not_implemented(const char *what)
int mg_num_ifaces
static err_t mg_lwip_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb, u16_t num_sent)
void mg_lwip_if_free(struct mg_iface *iface)
struct mg_str mg_url_encode_opt(const struct mg_str src, const struct mg_str safe, unsigned int flags)
int mg_strncmp(const struct mg_str, const struct mg_str, size_t n) WEAK
@ MG_Q_MSG_CB
int mg_if_poll(struct mg_connection *nc, double now)
static err_t mg_lwip_accept_cb(void *arg, struct tcp_pcb *newtpcb, err_t err)
static int mg_lwip_if_can_send(struct mg_connection *nc, struct mg_lwip_conn_state *cs)
void mg_socket_if_add_conn(struct mg_connection *nc)
void mg_sl_if_add_conn(struct mg_connection *nc)
void mg_sl_if_remove_conn(struct mg_connection *nc)
static void mg_handle_recv(struct mg_connection *nc)
static err_t mg_lwip_tcp_conn_cb(void *arg, struct tcp_pcb *tpcb, err_t err)
static int mg_lwip_if_udp_send(struct mg_connection *nc, const void *data, size_t len)
void mg_lwip_if_remove_conn(struct mg_connection *nc)
void mg_socket_if_get_conn_addr(struct mg_connection *nc, int remote, union socket_address *sa)
static time_t mg_null_if_poll(struct mg_iface *iface, int timeout_ms)
void mg_mgr_init_opt(struct mg_mgr *m, void *user_data, struct mg_mgr_init_opts opts)
static void udp_sendto_tcpip(void *arg)
void mg_socket_if_init(struct mg_iface *iface)
struct mg_connection * mg_connect(struct mg_mgr *mgr, const char *address, MG_CB(mg_event_handler_t callback, void *user_data))
#define MG_CALLOC
#define MG_PIC32_IFACE_VTABLE
#define _MG_ALLOWED_CONNECT_FLAGS_MASK
static int mg_recv_tcp(struct mg_connection *nc, char *buf, size_t len)
void mg_pic32_if_init(struct mg_iface *iface)
static void mg_null_if_init(struct mg_iface *iface)
static void mg_null_if_destroy_conn(struct mg_connection *c)
struct mg_str mg_strdup(const struct mg_str s) WEAK
#define TCP_BIND
static int mg_null_if_create_conn(struct mg_connection *c)
void mg_set_non_blocking_mode(sock_t sock)
#define MG_MAX_HOST_LEN
static void mg_null_if_sock_set(struct mg_connection *c, sock_t sock)
void mg_socket_if_connect_tcp(struct mg_connection *nc, const union socket_address *sa)
static int isbyte(int n)
#define UDP_BIND
void mg_socket_if_remove_conn(struct mg_connection *nc)
void mg_pic32_if_connect_udp(struct mg_connection *nc)
void mg_lwip_if_init(struct mg_iface *iface)
const struct mg_iface_vtable mg_default_iface_vtable
void mg_pic32_if_free(struct mg_iface *iface)
static void mg_lwip_recv_common(struct mg_connection *nc, struct pbuf *p)
void mg_if_can_recv_cb(struct mg_connection *nc)
static int mg_lwip_if_udp_recv(struct mg_connection *nc, void *buf, size_t len, union socket_address *sa, size_t *sa_len)
static int mg_socket_if_udp_send(struct mg_connection *nc, const void *buf, size_t len)
static void mg_sock_get_addr(sock_t sock, int remote, union socket_address *sa)
MG_INTERNAL int mg_parse_address(const char *str, union socket_address *sa, int *proto, char *host, size_t host_len)
static int mg_sl_if_listen_udp(struct mg_connection *nc, union socket_address *sa)
void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr)
void mg_mbuf_append_base64(struct mbuf *mbuf, const void *data, size_t len)
void mg_lwip_netif_run_on_tcpip(void(*fn)(void *), void *arg)
#define _MG_F_FD_CAN_READ
#define MG_SL_IFACE_VTABLE
static void mg_null_if_connect_udp(struct mg_connection *c)
static void mg_sl_if_connect_udp(struct mg_connection *nc)
static int mg_sl_if_tcp_recv(struct mg_connection *nc, void *buf, size_t len)
static void parse_uri_component(const char **p, const char *end, const char *seps, struct mg_str *res)
#define MG_SET_PTRPTR(_ptr, _v)
int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len)
static void tcp_close_tcpip(void *arg)
const struct mg_iface_vtable mg_simplelink_iface_vtable
static int mg_null_if_listen_tcp(struct mg_connection *c, union socket_address *sa)
int mg_assemble_uri(const struct mg_str *scheme, const struct mg_str *user_info, const struct mg_str *host, unsigned int port, const struct mg_str *path, const struct mg_str *query, const struct mg_str *fragment, int normalize_path, struct mg_str *uri)
void mg_pic32_if_destroy_conn(struct mg_connection *nc)
void mg_lwip_if_sock_set(struct mg_connection *nc, sock_t sock)
struct mg_iface * mg_if_create_iface(const struct mg_iface_vtable *vtable, struct mg_mgr *mgr)
static sys_sem_t s_tcpip_call_lock_sem
static int mg_socket_if_listen_udp(struct mg_connection *nc, union socket_address *sa)
static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
struct mg_connection * mg_bind_opt(struct mg_mgr *mgr, const char *address, MG_CB(mg_event_handler_t callback, void *user_data), struct mg_bind_opts opts)
const char * mg_strstr(const struct mg_str haystack, const struct mg_str needle) WEAK
void mg_lwip_post_signal(enum mg_sig_type sig, struct mg_connection *nc)
const struct mg_iface_vtable mg_pic32_iface_vtable
#define CONSOLE_UART
static int mg_socket_if_tcp_recv(struct mg_connection *nc, void *buf, size_t len)
static sys_sem_t s_tcpip_call_sync_sem
static void mg_lwip_tcp_write_tcpip(void *arg)
char * inet_ntoa(struct in_addr n)
void mg_forward(struct mg_connection *from, struct mg_connection *to)
#define intptr_t
static int mg_null_if_tcp_send(struct mg_connection *c, const void *buf, size_t len)
static int mg_lwip_if_tcp_recv(struct mg_connection *nc, void *buf, size_t len)
static int mg_null_if_udp_send(struct mg_connection *c, const void *buf, size_t len)
#define MG_TCP_IO_SIZE
static void mg_task(void *arg)
void mg_sl_if_get_conn_addr(struct mg_connection *nc, int remote, union socket_address *sa)
void mg_sl_if_destroy_conn(struct mg_connection *nc)
const char * mg_strchr(const struct mg_str s, int c) WEAK
static void mg_lwip_if_listen_tcp_tcpip(void *arg)
void _exit(int status)
int mg_null_if_udp_recv(struct mg_connection *c, void *buf, size_t len, union socket_address *sa, size_t *sa_len)
int mg_pic32_if_create_conn(struct mg_connection *nc)
#define blk(i)
void mg_pic32_if_get_conn_addr(struct mg_connection *nc, int remote, union socket_address *sa)
#define MG_REALLOC
struct mg_str mg_mk_str_n(const char *s, size_t len) WEAK
void mg_pic32_if_sock_set(struct mg_connection *nc, sock_t sock)
int mg_lwip_if_listen_tcp(struct mg_connection *nc, union socket_address *sa)
#define MG_SOCKET_IFACE_VTABLE
#define MG_INTERNAL
int mg_socket_if_listen_tcp(struct mg_connection *nc, union socket_address *sa)
void mg_sl_if_init(struct mg_iface *iface)
static void mg_null_if_remove_conn(struct mg_connection *c)
const struct mg_iface_vtable mg_socket_iface_vtable
const char * inet_ntop(int af, const void *src, char *dst, socklen_t size)
int gettimeofday(struct timeval *tp, void *tzp)
void cs_md5_update(cs_md5_ctx *ctx, const unsigned char *buf, size_t len)
struct mg_iface * mg_find_iface(struct mg_mgr *mgr, const struct mg_iface_vtable *vtable, struct mg_iface *from)
static void mg_handle_send(struct mg_connection *nc)
#define SET_ADDR(dst, src)
static void udp_remove_tcpip(void *arg)
static void mg_lwip_if_listen_udp_tcpip(void *arg)
void mg_sl_if_free(struct mg_iface *iface)
MG_INTERNAL void mg_add_conn(struct mg_mgr *mgr, struct mg_connection *c)
int inet_pton(int af, const char *src, void *dst)
int mg_lwip_if_listen_udp(struct mg_connection *nc, union socket_address *sa)
#define _MG_F_FD_CAN_WRITE
static int mg_sl_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len)
#define MG_FREE
MG_INTERNAL struct mg_connection * mg_do_connect(struct mg_connection *nc, int proto, union socket_address *sa)
void mg_ev_handler_empty(struct mg_connection *c, int ev, void *ev_data MG_UD_ARG(void *user_data))
void mg_socket_if_free(struct mg_iface *iface)
void mg_if_can_send_cb(struct mg_connection *nc)
#define MG_SIG_QUEUE_LEN
static int mg_sl_if_udp_send(struct mg_connection *nc, const void *buf, size_t len)
static void mg_null_if_connect_tcp(struct mg_connection *c, const union socket_address *sa)
static void xxx_tcpip(void *arg)
void mg_pic32_if_connect_tcp(struct mg_connection *nc, const union socket_address *sa)
void mg_lwip_mgr_schedule_poll(struct mg_mgr *mgr)
#define mgos_lock()
static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
#define mgos_unlock()
void mg_add_to_set(sock_t sock, fd_set *set, sock_t *max_fd)
const struct mg_iface_vtable mg_lwip_iface_vtable
void fprint_str(FILE *fp, const char *str)
struct mg_connection * mg_connect_opt(struct mg_mgr *mgr, const char *address, MG_CB(mg_event_handler_t callback, void *user_data), struct mg_connect_opts opts)
int mg_lwip_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len)
void mg_destroy_conn(struct mg_connection *conn, int destroy_if)
void mg_lwip_if_connect_tcp(struct mg_connection *nc, const union socket_address *sa)
time_t mg_sl_if_poll(struct mg_iface *iface, int timeout_ms)
MG_INTERNAL int mg_get_errno(void)
int mg_socket_if_create_conn(struct mg_connection *nc)
static int mg_is_error(void)
MG_INTERNAL void mg_call(struct mg_connection *nc, mg_event_handler_t ev_handler, void *user_data, int ev, void *ev_data)
static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len)
void mg_socket_if_destroy_conn(struct mg_connection *nc)
void mg_run_in_task(void(*cb)(struct mg_mgr *mgr, void *arg), void *cb_arg)
static int mg_null_if_listen_udp(struct mg_connection *c, union socket_address *sa)
void mg_pic32_if_remove_conn(struct mg_connection *nc)
#define MG_NULL_IFACE_VTABLE
void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now)
time_t mg_socket_if_poll(struct mg_iface *iface, int timeout_ms)
#define MAX(a, b)
struct mg_connection * mg_add_sock(struct mg_mgr *s, sock_t sock, MG_CB(mg_event_handler_t callback, void *user_data))
MG_INTERNAL void mg_timer(struct mg_connection *c, double now)
void tcp_recved_tcpip(void *arg)
struct mg_str mg_url_encode_opt(const struct mg_str src, const struct mg_str safe, unsigned int flags)
const char * mg_strchr(const struct mg_str s, int c)
struct mg_str mg_mk_str_n(const char *s, size_t len)
#define MG_URL_ENCODE_F_UPPERCASE_HEX
#define MG_URL_ENCODE_F_SPACE_AS_PLUS
static size_t mg_http_parse_chunk(char *buf, size_t len, char **chunk_data, size_t *chunk_len)
mg_http_multipart_stream_state
@ MPS_WAITING_FOR_CHUNK
@ MPS_FINISHED
@ MPS_FINALIZE
@ MPS_GOT_BOUNDARY
@ MPS_WAITING_FOR_BOUNDARY
@ MPS_BEGIN
MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm)
static void mg_send_directory_listing(struct mg_connection *nc, const char *dir, struct http_message *hm, struct mg_serve_http_opts *opts)
MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm, const struct mg_serve_http_opts *opts, char **local_path, struct mg_str *remainder)
static void mg_http_free_proto_data_cgi(struct mg_http_proto_data_cgi *d)
static void mqtt_handler(struct mg_connection *nc, int ev, void *ev_data)
const char * mime_type
static int mg_resolve2(const char *host, struct in_addr *ina)
static void mg_handle_cgi(struct mg_connection *nc, const char *prog, const struct mg_str *path_info, const struct http_message *hm, const struct mg_serve_http_opts *opts)
static struct mg_http_proto_data * mg_http_get_proto_data(struct mg_connection *c)
static void mg_send_file_data(struct mg_connection *nc, FILE *fp)
static void mg_resolve_async_eh(struct mg_connection *nc, int ev, void *data)
static const struct @23 mg_static_builtin_mime_types[]
#define MIME_ENTRY(_ext, _type)
size_t ext_len
static int mg_create_itermediate_directories(const char *path)
MG_INTERNAL void mg_send_http_file(struct mg_connection *nc, char *path, const struct mg_str *path_info, struct http_message *hm, struct mg_serve_http_opts *opts)
static void dns_handler(struct mg_connection *nc, int ev, void *ev_data)
const char * extension
static void mg_http_construct_etag(char *buf, size_t buf_len, const cs_stat_t *st)
static int mg_dns_tid
MG_INTERNAL time_t mg_parse_date_string(const char *datetime)
static void resolve_cb(struct mg_dns_message *msg, void *data, enum mg_resolve_err e)
static mg_event_handler_t mg_http_get_endpoint_handler(struct mg_connection *nc, struct mg_str *uri_path)
static int mg_is_ws_first_fragment(unsigned char flags)
static int mg_remove_directory(const struct mg_serve_http_opts *opts, const char *dir)
static int mg_check_nonce(const char *nonce)
static void mg_scan_directory(struct mg_connection *nc, const char *dir, const struct mg_serve_http_opts *opts, void(*func)(struct mg_connection *, const char *, cs_stat_t *))
static void mg_print_dir_entry(struct mg_connection *nc, const char *file_name, cs_stat_t *stp)
struct mg_connection * mg_connect_http_base(struct mg_mgr *mgr, mg_event_handler_t ev_handler, struct mg_connect_opts opts, const char *schema, const char *schema_ssl, const char *url, const char **path, char **addr)
static int left(const struct frozen *f)
static void mg_handle_put(struct mg_connection *nc, const char *path, struct http_message *hm)
static const char * mg_http_parse_headers(const char *s, const char *end, int len, struct http_message *req)
static void mg_escape(const char *src, char *dst, size_t dst_len)
static void mg_send_ssi_file(struct mg_connection *, const char *, FILE *, int, const struct mg_serve_http_opts *)
MG_INTERNAL int mg_is_not_modified(struct http_message *hm, cs_stat_t *st)
static int mg_get_month_index(const char *s)
static uint32_t mg_ws_random_mask(void)
static void mg_http_free_proto_data_file(struct mg_http_proto_data_file *d)
static int mg_get_ip_address_of_nameserver(char *name, size_t name_len)
static int mg_is_dav_request(const struct mg_str *s)
static unsigned char * mg_parse_dns_resource_record(unsigned char *data, unsigned char *end, struct mg_dns_resource_record *rr, int reply)
static void mg_mgr_handle_ctl_sock(struct mg_mgr *mgr)
static char * mg_addenv(struct mg_cgi_env_block *block, const char *fmt,...)
static void mg_ws_mask_frame(struct mbuf *mbuf, struct ws_mask_ctx *ctx)
static void mg_prepare_cgi_environment(struct mg_connection *nc, const char *prog, const struct mg_str *path_info, const struct http_message *hm, const struct mg_serve_http_opts *opts, struct mg_cgi_env_block *blk)
static void mg_handle_incoming_websocket_frame(struct mg_connection *nc, struct websocket_message *wsm)
static int mg_is_file_hidden(const char *path, const struct mg_serve_http_opts *opts, int exclude_specials)
static void mg_handle_ssi_request(struct mg_connection *nc, const char *path, const struct mg_serve_http_opts *opts)
static int mg_http_get_request_len(const char *s, int buf_len)
MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc, struct http_message *hm, char *buf, size_t blen)
static void mg_addenv2(struct mg_cgi_env_block *blk, const char *name)
static void mg_send_ws_header(struct mg_connection *nc, int op, size_t len, struct ws_mask_ctx *ctx)
static int mg_http_parse_range_header(const struct mg_str *header, int64_t *a, int64_t *b)
static void mg_print_props(struct mg_connection *nc, const char *name, cs_stat_t *stp)
static pid_t mg_start_process(const char *interp, const char *cmd, const char *env, const char *envp[], const char *dir, sock_t sock)
static int mg_is_ws_fragment(unsigned char flags)
MG_INTERNAL void mg_find_index_file(const char *path, const char *list, char **index_file, cs_stat_t *stp)
static int mg_deliver_websocket_data(struct mg_connection *nc)
static void mg_http_free_proto_data_endpoints(struct mg_http_endpoint **ep)
static void mg_cgi_ev_handler(struct mg_connection *cgi_nc, int ev, void *ev_data)
static size_t mg_get_line_len(const char *buf, size_t buf_len)
static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev, struct http_message *hm)
static void mg_handle_mkcol(struct mg_connection *nc, const char *path, struct http_message *hm)
static void mg_http_transfer_file_data(struct mg_connection *nc)
static void mg_mkmd5resp(const char *method, size_t method_len, const char *uri, size_t uri_len, const char *ha1, size_t ha1_len, const char *nonce, size_t nonce_len, const char *nc, size_t nc_len, const char *cnonce, size_t cnonce_len, const char *qop, size_t qop_len, char *resp)
mg_http_proto_data_type
@ DATA_FILE
@ DATA_NONE
@ DATA_PUT
void mg_http_handler(struct mg_connection *nc, int ev, void *ev_data)
static int mg_http_send_port_based_redirect(struct mg_connection *c, struct http_message *hm, const struct mg_serve_http_opts *opts)
static void mg_handle_delete(struct mg_connection *nc, const struct mg_serve_http_opts *opts, const char *path)
static void mg_handle_move(struct mg_connection *c, const struct mg_serve_http_opts *opts, const char *path, struct http_message *hm)
static void mg_handle_propfind(struct mg_connection *nc, const char *path, cs_stat_t *stp, struct http_message *hm, struct mg_serve_http_opts *opts)
static void mg_gmt_time_string(char *buf, size_t buf_len, time_t *t)
static void mg_http_send_options(struct mg_connection *nc)
#define MG_DEFAULT_NAMESERVER
static void mg_ws_handshake(struct mg_connection *nc, const struct mg_str *key)
static int mg_is_creation_request(const struct http_message *hm)
static int mg_num_leap_years(int year)
static struct mg_str mg_get_mime_type(const char *path, const char *dflt, const struct mg_serve_http_opts *opts)
static void mg_send_mqtt_short_command(struct mg_connection *nc, uint8_t cmd, uint16_t message_id)
struct callback_addr callback
Definition mserver.cxx:22
timeval tv
Definition msysmon.cxx:1095
#define gmtime
Definition msystem.h:266
#define localtime
Definition msystem.h:265
INT j
Definition odbhist.cxx:40
double value[100]
Definition odbhist.cxx:42
INT k
Definition odbhist.cxx:40
char str[256]
Definition odbhist.cxx:33
char file_name[256]
Definition odbhist.cxx:41
DWORD status
Definition odbhist.cxx:39
char var_name[256]
Definition odbhist.cxx:41
TH1X EXPRT * h1_book(const char *name, const char *title, int bins, double min, double max)
Definition rmidas.h:24
char message[MG_CTL_MSG_MESSAGE_SIZE]
mg_event_handler_t callback
const char * vars[MG_MAX_CGI_ENVIR_VARS]
struct mg_connection * nc
char buf[MG_CGI_ENVIRONMENT_SIZE]
struct mg_iface * iface
struct mg_context * ctx
uint16_t transaction_id
uint16_t num_questions
uint16_t num_answers
uint16_t num_authority_prs
uint16_t num_other_prs
struct mg_ev_mgr_lwip_signal sig_queue[MG_SIG_QUEUE_LEN]
struct mg_connection * nc
mg_event_handler_t handler
struct mg_http_endpoint * next
enum mg_http_multipart_stream_state state
struct mg_connection * cgi_nc
enum mg_http_proto_data_type type
struct mg_http_proto_data_chuncked chunk
struct mg_http_endpoint * endpoints
struct mg_http_proto_data_cgi cgi
mg_event_handler_t endpoint_handler
time_t(* poll)(struct mg_iface *iface, int timeout_ms)
void(* destroy_conn)(struct mg_connection *nc)
int(* listen_tcp)(struct mg_connection *nc, union socket_address *sa)
void(* remove_conn)(struct mg_connection *nc)
void(* connect_tcp)(struct mg_connection *nc, const union socket_address *sa)
void(* free)(struct mg_iface *iface)
void(* init)(struct mg_iface *iface)
void(* get_conn_addr)(struct mg_connection *nc, int remote, union socket_address *sa)
void(* connect_udp)(struct mg_connection *nc)
int(* udp_send)(struct mg_connection *nc, const void *buf, size_t len)
int(* create_conn)(struct mg_connection *nc)
int(* listen_udp)(struct mg_connection *nc, union socket_address *sa)
void(* sock_set)(struct mg_connection *nc, sock_t sock)
int(* udp_recv)(struct mg_connection *nc, void *buf, size_t len, union socket_address *sa, size_t *sa_len)
int(* tcp_send)(struct mg_connection *nc, const void *buf, size_t len)
int(* tcp_recv)(struct mg_connection *nc, void *buf, size_t len)
struct mg_mgr * mgr
const struct mg_iface_vtable * vtable
void * data
struct mg_connection * lc
union mg_lwip_conn_state::@24 pcb
struct pbuf * rx_chain
struct mg_connection * nc
const union socket_address * sa
struct mg_connection * nc
struct mg_connection * nc
union socket_address * sa
struct mg_connection * nc
int num_ifaces
struct mg_iface ** ifaces
int num_calls
const char * nameserver
enum mg_q_msg_type type
void(* cb)(struct mg_mgr *mgr, void *arg)
enum mg_resolve_err err
mg_resolve_callback_t callback
struct tcp_pcb * tpcb
struct pbuf * p
struct udp_pcb * upcb
size_t len
uint32_t mask
double d
Definition system.cxx:1311
char c
Definition system.cxx:1310
@ DIR
Definition test_init.cxx:7
static double comma(double a, double b)
Definition tinyexpr.c:248
static double e(void)
Definition tinyexpr.c:136
static te_expr * base(state *s)
Definition tinyexpr.c:357
static double pi(void)
Definition tinyexpr.c:135
static te_expr * list(state *s)
Definition tinyexpr.c:567
struct sockaddr_in sin

◆ _MG_CALLBACK_MODIFIABLE_FLAGS_MASK

◆ _MG_F_FD_CAN_READ [1/2]

#define _MG_F_FD_CAN_READ   1

Definition at line 4049 of file mongoose616.cxx.

◆ _MG_F_FD_CAN_READ [2/2]

#define _MG_F_FD_CAN_READ   1

Definition at line 4049 of file mongoose616.cxx.

◆ _MG_F_FD_CAN_WRITE [1/2]

#define _MG_F_FD_CAN_WRITE   1 << 1

Definition at line 4050 of file mongoose616.cxx.

◆ _MG_F_FD_CAN_WRITE [2/2]

#define _MG_F_FD_CAN_WRITE   1 << 1

Definition at line 4050 of file mongoose616.cxx.

◆ _MG_F_FD_ERROR [1/2]

#define _MG_F_FD_ERROR   1 << 2

Definition at line 4051 of file mongoose616.cxx.

◆ _MG_F_FD_ERROR [2/2]

#define _MG_F_FD_ERROR   1 << 2

Definition at line 4051 of file mongoose616.cxx.

◆ BASE64_ENCODE_BODY

#define BASE64_ENCODE_BODY
Value:
static const char *b64 = \
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; \
int i, j, a, b, c; \
for (i = j = 0; i < src_len; i += 3) { \
a = src[i]; \
b = i + 1 >= src_len ? 0 : src[i + 1]; \
c = i + 2 >= src_len ? 0 : src[i + 2]; \
BASE64_OUT(b64[a >> 2]); \
BASE64_OUT(b64[((a & 3) << 4) | (b >> 4)]); \
if (i + 1 < src_len) { \
BASE64_OUT(b64[(b & 15) << 2 | (c >> 6)]); \
} \
if (i + 2 < src_len) { \
BASE64_OUT(b64[c & 63]); \
} \
} \
while (j % 4 != 0) { \
BASE64_OUT('='); \
} \

Definition at line 316 of file mongoose616.cxx.

321 { \
322 a = src[i]; \
323 b = i + 1 >= src_len ? 0 : src[i + 1]; \
324 c = i + 2 >= src_len ? 0 : src[i + 2]; \
325 \
326 BASE64_OUT(b64[a >> 2]); \
327 BASE64_OUT(b64[((a & 3) << 4) | (b >> 4)]); \
328 if (i + 1 < src_len) { \
329 BASE64_OUT(b64[(b & 15) << 2 | (c >> 6)]); \
330 } \
331 if (i + 2 < src_len) { \
332 BASE64_OUT(b64[c & 63]); \
333 } \
334 } \
335 \
336 while (j % 4 != 0) { \
337 BASE64_OUT('='); \
338 } \

◆ BASE64_FLUSH

#define BASE64_FLUSH ( )
Value:
do { \
dst[j++] = '\0'; \
} while (0)

Definition at line 346 of file mongoose616.cxx.

347 { \
348 dst[j++] = '\0'; \
349 } while (0)

◆ BASE64_OUT

#define BASE64_OUT (   ch)
Value:
do { \
dst[j++] = (ch); \
} while (0)

Definition at line 341 of file mongoose616.cxx.

342 { \
343 dst[j++] = (ch); \
344 } while (0)

◆ blk

#define blk (   i)
Value:
(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 rol(value, bits)

Definition at line 1299 of file mongoose616.cxx.

◆ C_DISABLE_BUILTIN_SNPRINTF

#define C_DISABLE_BUILTIN_SNPRINTF   0

Definition at line 1859 of file mongoose616.cxx.

◆ C_SNPRINTF_APPEND_CHAR

#define C_SNPRINTF_APPEND_CHAR (   ch)
Value:
do { \
if (i < (int) buf_size) buf[i] = ch; \
i++; \
} while (0)

Definition at line 1872 of file mongoose616.cxx.

1873 { \
1874 if (i < (int) buf_size) buf[i] = ch; \
1875 i++; \
1876 } while (0)

◆ C_SNPRINTF_FLAG_ZERO

#define C_SNPRINTF_FLAG_ZERO   1

Definition at line 1878 of file mongoose616.cxx.

◆ CONSOLE_UART

#define CONSOLE_UART   UARTA0_BASE

Definition at line 13518 of file mongoose616.cxx.

◆ CS_COMMON_CS_DBG_H_

#define CS_COMMON_CS_DBG_H_

Definition at line 458 of file mongoose616.cxx.

◆ CS_COMMON_CS_DIRENT_H_

#define CS_COMMON_CS_DIRENT_H_

Definition at line 755 of file mongoose616.cxx.

◆ CS_COMMON_CS_ENDIAN_H_

#define CS_COMMON_CS_ENDIAN_H_

Definition at line 1018 of file mongoose616.cxx.

◆ CS_COMMON_MG_MEM_H_

#define CS_COMMON_MG_MEM_H_

Definition at line 190 of file mongoose616.cxx.

◆ CS_COMMON_PLATFORMS_LWIP_MG_NET_IF_LWIP_H_

#define CS_COMMON_PLATFORMS_LWIP_MG_NET_IF_LWIP_H_

Definition at line 15307 of file mongoose616.cxx.

◆ CS_COMMON_PLATFORMS_PIC32_NET_IF_H_

#define CS_COMMON_PLATFORMS_PIC32_NET_IF_H_

Definition at line 16389 of file mongoose616.cxx.

◆ CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_

#define CS_COMMON_PLATFORMS_SIMPLELINK_SL_FS_SLFS_H_

Definition at line 13678 of file mongoose616.cxx.

◆ CS_COMMON_PLATFORMS_SIMPLELINK_SL_NET_IF_H_

#define CS_COMMON_PLATFORMS_SIMPLELINK_SL_NET_IF_H_

Definition at line 14578 of file mongoose616.cxx.

◆ CS_ENABLE_DEBUG

#define CS_ENABLE_DEBUG   0

Definition at line 467 of file mongoose616.cxx.

◆ CS_LOG_ENABLE_TS_DIFF

#define CS_LOG_ENABLE_TS_DIFF   0

Definition at line 475 of file mongoose616.cxx.

◆ CS_LOG_PREFIX_LEN

#define CS_LOG_PREFIX_LEN   24

Definition at line 471 of file mongoose616.cxx.

◆ CS_MONGOOSE_SRC_INTERNAL_H_

#define CS_MONGOOSE_SRC_INTERNAL_H_

Definition at line 13 of file mongoose616.cxx.

◆ CS_MONGOOSE_SRC_NET_IF_SOCKET_H_

#define CS_MONGOOSE_SRC_NET_IF_SOCKET_H_

Definition at line 3590 of file mongoose616.cxx.

◆ CS_MONGOOSE_SRC_NET_IF_SOCKS_H_

#define CS_MONGOOSE_SRC_NET_IF_SOCKS_H_

Definition at line 3618 of file mongoose616.cxx.

◆ DBG

#define DBG (   x)

Definition at line 579 of file mongoose616.cxx.

◆ F1

#define F1 (   x,
  y,
  z 
)    (z ^ (x & (y ^ z)))

Definition at line 1087 of file mongoose616.cxx.

◆ F2

#define F2 (   x,
  y,
  z 
)    F1(z, x, y)

Definition at line 1088 of file mongoose616.cxx.

◆ F3

#define F3 (   x,
  y,
  z 
)    (x ^ y ^ z)

Definition at line 1089 of file mongoose616.cxx.

◆ F4

#define F4 (   x,
  y,
  z 
)    (y ^ (x | ~z))

Definition at line 1090 of file mongoose616.cxx.

◆ intptr_t

#define intptr_t   long

Definition at line 2418 of file mongoose616.cxx.

◆ ip_2_ip4

#define ip_2_ip4 (   addr)    (addr)

Definition at line 15400 of file mongoose616.cxx.

◆ IPADDR_NTOA

#define IPADDR_NTOA   ipaddr_ntoa

Definition at line 15420 of file mongoose616.cxx.

◆ LOG

#define LOG (   l,
 
)

Definition at line 578 of file mongoose616.cxx.

◆ MAX

#define MAX (   a,
 
)    ((a) > (b) ? (a) : (b))

Definition at line 10631 of file mongoose616.cxx.

◆ MBUF_FREE

#define MBUF_FREE   MG_FREE

Definition at line 22 of file mongoose616.cxx.

◆ MBUF_REALLOC

#define MBUF_REALLOC   MG_REALLOC

Definition at line 18 of file mongoose616.cxx.

◆ MD5STEP

#define MD5STEP (   f,
  w,
  x,
  y,
  z,
  data,
 
)     (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x)

Definition at line 1092 of file mongoose616.cxx.

◆ MG_CALLOC

#define MG_CALLOC   calloc

Definition at line 201 of file mongoose616.cxx.

◆ MG_COPY_COMMON_CONNECTION_OPTIONS

#define MG_COPY_COMMON_CONNECTION_OPTIONS (   dst,
  src 
)     memcpy(dst, src, sizeof(*dst));

Definition at line 2404 of file mongoose616.cxx.

◆ MG_CTL_MSG_MESSAGE_SIZE

#define MG_CTL_MSG_MESSAGE_SIZE   8192

Definition at line 44 of file mongoose616.cxx.

◆ MG_ENABLE_NET_IF_LWIP_LOW_LEVEL

#define MG_ENABLE_NET_IF_LWIP_LOW_LEVEL   MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL

Definition at line 15310 of file mongoose616.cxx.

◆ MG_ENABLE_NET_IF_PIC32

#define MG_ENABLE_NET_IF_PIC32   MG_NET_IF == MG_NET_IF_PIC32

Definition at line 16398 of file mongoose616.cxx.

◆ MG_ENABLE_NET_IF_SIMPLELINK

#define MG_ENABLE_NET_IF_SIMPLELINK   MG_NET_IF == MG_NET_IF_SIMPLELINK

Definition at line 14587 of file mongoose616.cxx.

◆ MG_ENABLE_NET_IF_SOCKET

#define MG_ENABLE_NET_IF_SOCKET   MG_NET_IF == MG_NET_IF_SOCKET

Definition at line 3599 of file mongoose616.cxx.

◆ MG_FREE

#define MG_FREE   free

Definition at line 209 of file mongoose616.cxx.

◆ MG_INTERNAL

#define MG_INTERNAL   static

Definition at line 31 of file mongoose616.cxx.

◆ MG_LWIP_IFACE_VTABLE

◆ MG_MALLOC

#define MG_MALLOC   malloc

Definition at line 197 of file mongoose616.cxx.

◆ MG_MAX_HOST_LEN

#define MG_MAX_HOST_LEN   200

Definition at line 2394 of file mongoose616.cxx.

◆ MG_NULL_IFACE_VTABLE

◆ MG_PIC32_IFACE_VTABLE

◆ MG_REALLOC

#define MG_REALLOC   realloc

Definition at line 205 of file mongoose616.cxx.

◆ MG_SET_PTRPTR

#define MG_SET_PTRPTR (   _ptr,
  _v 
)
Value:
do { \
if (_ptr) *(_ptr) = _v; \
} while (0)

Definition at line 25 of file mongoose616.cxx.

26 { \
27 if (_ptr) *(_ptr) = _v; \
28 } while (0)

◆ MG_SIG_QUEUE_LEN

#define MG_SIG_QUEUE_LEN   32

Definition at line 16126 of file mongoose616.cxx.

◆ MG_SL_IFACE_VTABLE

◆ MG_SOCKET_IFACE_VTABLE

◆ MG_TCP_IO_SIZE

#define MG_TCP_IO_SIZE   1460000

Definition at line 2398 of file mongoose616.cxx.

◆ MG_TCP_RECV_BUFFER_SIZE

#define MG_TCP_RECV_BUFFER_SIZE   1024

Definition at line 14624 of file mongoose616.cxx.

◆ MG_UDP_IO_SIZE

#define MG_UDP_IO_SIZE   1460

Definition at line 2401 of file mongoose616.cxx.

◆ MG_UDP_RECV_BUFFER_SIZE

#define MG_UDP_RECV_BUFFER_SIZE   1500

Definition at line 14625 of file mongoose616.cxx.

◆ mgos_lock

#define mgos_lock ( )

Definition at line 15466 of file mongoose616.cxx.

◆ mgos_unlock

#define mgos_unlock ( )

Definition at line 15467 of file mongoose616.cxx.

◆ MIN

#define MIN (   a,
 
)    ((a) < (b) ? (a) : (b))

Definition at line 87 of file mongoose616.cxx.

◆ NUM_DIGITS

#define NUM_DIGITS   ('9' - '0' + 1)

Definition at line 249 of file mongoose616.cxx.

◆ NUM_LETTERS

#define NUM_LETTERS   (NUM_UPPERCASES * 2)

Definition at line 248 of file mongoose616.cxx.

◆ NUM_UPPERCASES

#define NUM_UPPERCASES   ('Z' - 'A' + 1)

Definition at line 247 of file mongoose616.cxx.

◆ R0

#define R0 (   v,
  w,
  x,
  y,
  z,
  i 
)
Value:
z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \
w = rol(w, 30);
static uint32_t blk0(union char64long16 *block, int i)

Definition at line 1303 of file mongoose616.cxx.

◆ R1

#define R1 (   v,
  w,
  x,
  y,
  z,
  i 
)
Value:
z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
w = rol(w, 30);

Definition at line 1306 of file mongoose616.cxx.

◆ R2

#define R2 (   v,
  w,
  x,
  y,
  z,
  i 
)
Value:
z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
w = rol(w, 30);

Definition at line 1309 of file mongoose616.cxx.

◆ R3

#define R3 (   v,
  w,
  x,
  y,
  z,
  i 
)
Value:
z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
w = rol(w, 30);

Definition at line 1312 of file mongoose616.cxx.

◆ R4

#define R4 (   v,
  w,
  x,
  y,
  z,
  i 
)
Value:
z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
w = rol(w, 30);

Definition at line 1315 of file mongoose616.cxx.

◆ rol

#define rol (   value,
  bits 
)    (((value) << (bits)) | ((value) >> (32 - (bits))))

Definition at line 1280 of file mongoose616.cxx.

◆ SET_ADDR

#define SET_ADDR (   dst,
  src 
)    (dst)->sin.sin_addr.s_addr = ip_2_ip4(src)->addr

Definition at line 15421 of file mongoose616.cxx.

◆ SHA1HANDSOFF

#define SHA1HANDSOFF

Definition at line 1270 of file mongoose616.cxx.

◆ TCP_BIND

#define TCP_BIND   tcp_bind

Definition at line 15418 of file mongoose616.cxx.

◆ TCP_NEW

#define TCP_NEW   tcp_new

Definition at line 15417 of file mongoose616.cxx.

◆ UDP_BIND

#define UDP_BIND   udp_bind

Definition at line 15419 of file mongoose616.cxx.

Typedef Documentation

◆ cs_dirent_dummy

Definition at line 898 of file mongoose616.cxx.

Enumeration Type Documentation

◆ cs_log_level

Enumerator
LL_NONE 
LL_ERROR 
LL_WARN 
LL_INFO 
LL_DEBUG 
LL_VERBOSE_DEBUG 
_LL_MIN 
_LL_MAX 

Definition at line 485 of file mongoose616.cxx.

485 {
486 LL_NONE = -1,
487 LL_ERROR = 0,
488 LL_WARN = 1,
489 LL_INFO = 2,
490 LL_DEBUG = 3,
492
493 _LL_MIN = -2,
494 _LL_MAX = 5,
495};
@ LL_NONE
@ _LL_MAX
@ LL_WARN
@ _LL_MIN

◆ mg_q_msg_type

Enumerator
MG_Q_MSG_CB 

Definition at line 14511 of file mongoose616.cxx.

14511 {
14513};

◆ mg_sig_type

Enumerator
MG_SIG_CONNECT_RESULT 
MG_SIG_RECV 
MG_SIG_CLOSE_CONN 
MG_SIG_TOMBSTONE 
MG_SIG_ACCEPT 

Definition at line 15338 of file mongoose616.cxx.

15338 {
15340 MG_SIG_RECV = 2,
15342 MG_SIG_TOMBSTONE = 4,
15343 MG_SIG_ACCEPT = 5,
15344};

Function Documentation

◆ _exit()

void _exit ( int  status)

Definition at line 13563 of file mongoose616.cxx.

13563 {
13564 fprint_str(stderr, "_exit\n");
13565 /* cause an unaligned access exception, that will drop you into gdb */
13566 *(int *) 1 = status;
13567 while (1)
13568 ; /* avoid gcc warning because stdlib abort() has noreturn attribute */
13569}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ _getpid()

int _getpid ( )

Definition at line 13584 of file mongoose616.cxx.

13584 {
13585 fprint_str(stderr, "_getpid is not implemented\n");
13586 return 42;
13587}
Here is the call graph for this function:

◆ _isatty()

int _isatty ( int  fd)

Definition at line 13589 of file mongoose616.cxx.

13589 {
13590 /* 0, 1 and 2 are TTYs. */
13591 return fd < 2;
13592}

◆ _kill()

int _kill ( int  pid,
int  sig 
)

Definition at line 13577 of file mongoose616.cxx.

13577 {
13578 (void) pid;
13579 (void) sig;
13580 _not_implemented("_kill");
13581 return -1;
13582}
Here is the call graph for this function:

◆ _not_implemented()

void _not_implemented ( const char what)

Definition at line 13571 of file mongoose616.cxx.

13571 {
13572 fprint_str(stderr, what);
13573 fprint_str(stderr, " is not implemented\n");
13574 _exit(42);
13575}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ blk0()

static uint32_t blk0 ( union char64long16 block,
int  i 
)
static

Definition at line 1282 of file mongoose616.cxx.

1282 {
1283/* Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN */
1284#if BYTE_ORDER == LITTLE_ENDIAN
1285 block->l[i] =
1286 (rol(block->l[i], 24) & 0xFF00FF00) | (rol(block->l[i], 8) & 0x00FF00FF);
1287#endif
1288 return block->l[i];
1289}
Here is the call graph for this function:

◆ byteReverse()

static void byteReverse ( unsigned char buf,
unsigned  longs 
)
static

Definition at line 1072 of file mongoose616.cxx.

1072 {
1073/* Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN */
1074#if BYTE_ORDER == BIG_ENDIAN
1075 do {
1076 uint32_t t = (uint32_t)((unsigned) buf[3] << 8 | buf[2]) << 16 |
1077 ((unsigned) buf[1] << 8 | buf[0]);
1078 *(uint32_t *) buf = t;
1079 buf += 4;
1080 } while (--longs);
1081#else
1082 (void) buf;
1083 (void) longs;
1084#endif
1085}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ c_itoa()

static int c_itoa ( char buf,
size_t  buf_size,
int64_t  num,
int  base,
int  flags,
int  field_width 
)
static

Definition at line 1886 of file mongoose616.cxx.

1887 {
1888 char tmp[40];
1889 int i = 0, k = 0, neg = 0;
1890
1891 if (num < 0) {
1892 neg++;
1893 num = -num;
1894 }
1895
1896 /* Print into temporary buffer - in reverse order */
1897 do {
1898 int rem = num % base;
1899 if (rem < 10) {
1900 tmp[k++] = '0' + rem;
1901 } else {
1902 tmp[k++] = 'a' + (rem - 10);
1903 }
1904 num /= base;
1905 } while (num > 0);
1906
1907 /* Zero padding */
1908 if (flags && C_SNPRINTF_FLAG_ZERO) {
1909 while (k < field_width && k < (int) sizeof(tmp) - 1) {
1910 tmp[k++] = '0';
1911 }
1912 }
1913
1914 /* And sign */
1915 if (neg) {
1916 tmp[k++] = '-';
1917 }
1918
1919 /* Now output */
1920 while (--k >= 0) {
1922 }
1923
1924 return i;
1925}
#define C_SNPRINTF_FLAG_ZERO
#define C_SNPRINTF_APPEND_CHAR(ch)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cs_base64_decode()

int cs_base64_decode ( const unsigned char s,
int  len,
char dst,
int dec_len 
)

Definition at line 415 of file mongoose616.cxx.

415 {
416 unsigned char a, b, c, d;
417 int orig_len = len;
418 char *orig_dst = dst;
419 while (len >= 4 && (a = from_b64(s[0])) != 255 &&
420 (b = from_b64(s[1])) != 255 && (c = from_b64(s[2])) != 255 &&
421 (d = from_b64(s[3])) != 255) {
422 s += 4;
423 len -= 4;
424 if (a == 200 || b == 200) break; /* '=' can't be there */
425 *dst++ = a << 2 | b >> 4;
426 if (c == 200) break;
427 *dst++ = b << 4 | c >> 2;
428 if (d == 200) break;
429 *dst++ = c << 6 | d;
430 }
431 *dst = 0;
432 if (dec_len != NULL) *dec_len = (dst - orig_dst);
433 return orig_len - len;
434}
static unsigned char from_b64(unsigned char ch)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cs_base64_emit_chunk()

static void cs_base64_emit_chunk ( struct cs_base64_ctx ctx)
static

Definition at line 269 of file mongoose616.cxx.

269 {
270 int a, b, c;
271
272 a = ctx->chunk[0];
273 b = ctx->chunk[1];
274 c = ctx->chunk[2];
275
276 cs_base64_emit_code(ctx, a >> 2);
277 cs_base64_emit_code(ctx, ((a & 3) << 4) | (b >> 4));
278 if (ctx->chunk_size > 1) {
279 cs_base64_emit_code(ctx, (b & 15) << 2 | (c >> 6));
280 }
281 if (ctx->chunk_size > 2) {
282 cs_base64_emit_code(ctx, c & 63);
283 }
284}
unsigned char chunk[3]
Definition mongoose6.h:982
static void cs_base64_emit_code(struct cs_base64_ctx *ctx, int v)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cs_base64_emit_code()

static void cs_base64_emit_code ( struct cs_base64_ctx ctx,
int  v 
)
static

Definition at line 256 of file mongoose616.cxx.

256 {
257 if (v < NUM_UPPERCASES) {
258 ctx->b64_putc(v + 'A', ctx->user_data);
259 } else if (v < (NUM_LETTERS)) {
260 ctx->b64_putc(v - NUM_UPPERCASES + 'a', ctx->user_data);
261 } else if (v < (NUM_LETTERS + NUM_DIGITS)) {
262 ctx->b64_putc(v - NUM_LETTERS + '0', ctx->user_data);
263 } else {
264 ctx->b64_putc(v - NUM_LETTERS - NUM_DIGITS == 0 ? '+' : '/',
265 ctx->user_data);
266 }
267}
void * user_data
Definition mongoose6.h:984
cs_base64_putc_t b64_putc
Definition mongoose6.h:981
#define NUM_DIGITS
#define NUM_UPPERCASES
#define NUM_LETTERS
Here is the caller graph for this function:

◆ cs_from_hex()

void cs_from_hex ( char to,
const char p,
size_t  len 
)

Definition at line 2159 of file mongoose616.cxx.

2159 {
2160 size_t i;
2161
2162 for (i = 0; i < len; i += 2) {
2163 *to++ = (fourbit(p[i]) << 4) + fourbit(p[i + 1]);
2164 }
2165 *to = '\0';
2166}
static int fourbit(int ch)
Here is the call graph for this function:

◆ cs_log_print_prefix()

int cs_log_print_prefix ( enum cs_log_level  level,
const char fname,
int  line 
)

◆ cs_log_set_file_level()

void cs_log_set_file_level ( const char file_level)

Definition at line 721 of file mongoose616.cxx.

721 {
723}
Here is the call graph for this function:

◆ cs_md5_final()

void cs_md5_final ( unsigned char  digest[16],
cs_md5_ctx ctx 
)

Definition at line 1226 of file mongoose616.cxx.

1226 {
1227 unsigned count;
1228 unsigned char *p;
1229 uint32_t *a;
1230
1231 count = (ctx->bits[0] >> 3) & 0x3F;
1232
1233 p = ctx->in + count;
1234 *p++ = 0x80;
1235 count = 64 - 1 - count;
1236 if (count < 8) {
1237 memset(p, 0, count);
1238 byteReverse(ctx->in, 16);
1239 cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
1240 memset(ctx->in, 0, 56);
1241 } else {
1242 memset(p, 0, count - 8);
1243 }
1244 byteReverse(ctx->in, 14);
1245
1246 a = (uint32_t *) ctx->in;
1247 a[14] = ctx->bits[0];
1248 a[15] = ctx->bits[1];
1249
1250 cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
1251 byteReverse((unsigned char *) ctx->buf, 4);
1252 memcpy(digest, ctx->buf, 16);
1253 memset((char *) ctx, 0, sizeof(*ctx));
1254}
static void cs_md5_transform(uint32_t buf[4], uint32_t const in[16])
static void byteReverse(unsigned char *buf, unsigned longs)
unsigned char in[64]
uint32_t bits[2]
uint32_t buf[4]
Here is the call graph for this function:

◆ cs_md5_init()

void cs_md5_init ( cs_md5_ctx ctx)

Definition at line 1099 of file mongoose616.cxx.

1099 {
1100 ctx->buf[0] = 0x67452301;
1101 ctx->buf[1] = 0xefcdab89;
1102 ctx->buf[2] = 0x98badcfe;
1103 ctx->buf[3] = 0x10325476;
1104
1105 ctx->bits[0] = 0;
1106 ctx->bits[1] = 0;
1107}

◆ cs_md5_transform()

static void cs_md5_transform ( uint32_t  buf[4],
uint32_t const  in[16] 
)
static

Definition at line 1109 of file mongoose616.cxx.

1109 {
1110 uint32_t a, b, c, d;
1111
1112 a = buf[0];
1113 b = buf[1];
1114 c = buf[2];
1115 d = buf[3];
1116
1117 MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
1118 MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
1119 MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
1120 MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
1121 MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
1122 MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
1123 MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
1124 MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
1125 MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
1126 MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
1127 MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
1128 MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
1129 MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
1130 MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
1131 MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
1132 MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
1133
1134 MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
1135 MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
1136 MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
1137 MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
1138 MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
1139 MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
1140 MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
1141 MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
1142 MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
1143 MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
1144 MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
1145 MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
1146 MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
1147 MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
1148 MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
1149 MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
1150
1151 MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
1152 MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
1153 MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
1154 MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
1155 MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
1156 MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
1157 MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
1158 MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
1159 MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
1160 MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
1161 MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
1162 MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
1163 MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
1164 MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
1165 MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
1166 MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
1167
1168 MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
1169 MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
1170 MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
1171 MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
1172 MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
1173 MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
1174 MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
1175 MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
1176 MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
1177 MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
1178 MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
1179 MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
1180 MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
1181 MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
1182 MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
1183 MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
1184
1185 buf[0] += a;
1186 buf[1] += b;
1187 buf[2] += c;
1188 buf[3] += d;
1189}
#define MD5STEP(f, w, x, y, z, data, s)
#define F1(x, y, z)
#define F4(x, y, z)
#define F3(x, y, z)
#define F2(x, y, z)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cs_md5_update()

void cs_md5_update ( cs_md5_ctx ctx,
const unsigned char buf,
size_t  len 
)

Definition at line 1191 of file mongoose616.cxx.

1191 {
1192 uint32_t t;
1193
1194 t = ctx->bits[0];
1195 if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) ctx->bits[1]++;
1196 ctx->bits[1] += (uint32_t) len >> 29;
1197
1198 t = (t >> 3) & 0x3f;
1199
1200 if (t) {
1201 unsigned char *p = (unsigned char *) ctx->in + t;
1202
1203 t = 64 - t;
1204 if (len < t) {
1205 memcpy(p, buf, len);
1206 return;
1207 }
1208 memcpy(p, buf, t);
1209 byteReverse(ctx->in, 16);
1210 cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
1211 buf += t;
1212 len -= t;
1213 }
1214
1215 while (len >= 64) {
1216 memcpy(ctx->in, buf, 64);
1217 byteReverse(ctx->in, 16);
1218 cs_md5_transform(ctx->buf, (uint32_t *) ctx->in);
1219 buf += 64;
1220 len -= 64;
1221 }
1222
1223 memcpy(ctx->in, buf, len);
1224}
Here is the call graph for this function:

◆ cs_sha1_transform()

void cs_sha1_transform ( uint32_t  state[5],
const unsigned char  buffer[64] 
)

Definition at line 1319 of file mongoose616.cxx.

1319 {
1320 uint32_t a, b, c, d, e;
1321 union char64long16 block[1];
1322
1323 memcpy(block, buffer, 64);
1324 a = state[0];
1325 b = state[1];
1326 c = state[2];
1327 d = state[3];
1328 e = state[4];
1329 R0(a, b, c, d, e, 0);
1330 R0(e, a, b, c, d, 1);
1331 R0(d, e, a, b, c, 2);
1332 R0(c, d, e, a, b, 3);
1333 R0(b, c, d, e, a, 4);
1334 R0(a, b, c, d, e, 5);
1335 R0(e, a, b, c, d, 6);
1336 R0(d, e, a, b, c, 7);
1337 R0(c, d, e, a, b, 8);
1338 R0(b, c, d, e, a, 9);
1339 R0(a, b, c, d, e, 10);
1340 R0(e, a, b, c, d, 11);
1341 R0(d, e, a, b, c, 12);
1342 R0(c, d, e, a, b, 13);
1343 R0(b, c, d, e, a, 14);
1344 R0(a, b, c, d, e, 15);
1345 R1(e, a, b, c, d, 16);
1346 R1(d, e, a, b, c, 17);
1347 R1(c, d, e, a, b, 18);
1348 R1(b, c, d, e, a, 19);
1349 R2(a, b, c, d, e, 20);
1350 R2(e, a, b, c, d, 21);
1351 R2(d, e, a, b, c, 22);
1352 R2(c, d, e, a, b, 23);
1353 R2(b, c, d, e, a, 24);
1354 R2(a, b, c, d, e, 25);
1355 R2(e, a, b, c, d, 26);
1356 R2(d, e, a, b, c, 27);
1357 R2(c, d, e, a, b, 28);
1358 R2(b, c, d, e, a, 29);
1359 R2(a, b, c, d, e, 30);
1360 R2(e, a, b, c, d, 31);
1361 R2(d, e, a, b, c, 32);
1362 R2(c, d, e, a, b, 33);
1363 R2(b, c, d, e, a, 34);
1364 R2(a, b, c, d, e, 35);
1365 R2(e, a, b, c, d, 36);
1366 R2(d, e, a, b, c, 37);
1367 R2(c, d, e, a, b, 38);
1368 R2(b, c, d, e, a, 39);
1369 R3(a, b, c, d, e, 40);
1370 R3(e, a, b, c, d, 41);
1371 R3(d, e, a, b, c, 42);
1372 R3(c, d, e, a, b, 43);
1373 R3(b, c, d, e, a, 44);
1374 R3(a, b, c, d, e, 45);
1375 R3(e, a, b, c, d, 46);
1376 R3(d, e, a, b, c, 47);
1377 R3(c, d, e, a, b, 48);
1378 R3(b, c, d, e, a, 49);
1379 R3(a, b, c, d, e, 50);
1380 R3(e, a, b, c, d, 51);
1381 R3(d, e, a, b, c, 52);
1382 R3(c, d, e, a, b, 53);
1383 R3(b, c, d, e, a, 54);
1384 R3(a, b, c, d, e, 55);
1385 R3(e, a, b, c, d, 56);
1386 R3(d, e, a, b, c, 57);
1387 R3(c, d, e, a, b, 58);
1388 R3(b, c, d, e, a, 59);
1389 R4(a, b, c, d, e, 60);
1390 R4(e, a, b, c, d, 61);
1391 R4(d, e, a, b, c, 62);
1392 R4(c, d, e, a, b, 63);
1393 R4(b, c, d, e, a, 64);
1394 R4(a, b, c, d, e, 65);
1395 R4(e, a, b, c, d, 66);
1396 R4(d, e, a, b, c, 67);
1397 R4(c, d, e, a, b, 68);
1398 R4(b, c, d, e, a, 69);
1399 R4(a, b, c, d, e, 70);
1400 R4(e, a, b, c, d, 71);
1401 R4(d, e, a, b, c, 72);
1402 R4(c, d, e, a, b, 73);
1403 R4(b, c, d, e, a, 74);
1404 R4(a, b, c, d, e, 75);
1405 R4(e, a, b, c, d, 76);
1406 R4(d, e, a, b, c, 77);
1407 R4(c, d, e, a, b, 78);
1408 R4(b, c, d, e, a, 79);
1409 state[0] += a;
1410 state[1] += b;
1411 state[2] += c;
1412 state[3] += d;
1413 state[4] += e;
1414 /* Erase working structures. The order of operations is important,
1415 * used to ensure that compiler doesn't optimize those out. */
1416 memset(block, 0, sizeof(block));
1417 a = b = c = d = e = 0;
1418 (void) a;
1419 (void) b;
1420 (void) c;
1421 (void) d;
1422 (void) e;
1423}
#define R1(v, w, x, y, z, i)
#define R2(v, w, x, y, z, i)
#define R0(v, w, x, y, z, i)
#define R3(v, w, x, y, z, i)
#define R4(v, w, x, y, z, i)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cs_timegm()

double cs_timegm ( const struct tm tm)

Definition at line 963 of file mongoose616.cxx.

963 {
964 /* Month-to-day offset for non-leap-years. */
965 static const int month_day[12] = {0, 31, 59, 90, 120, 151,
966 181, 212, 243, 273, 304, 334};
967
968 /* Most of the calculation is easy; leap years are the main difficulty. */
969 int month = tm->tm_mon % 12;
970 int year = tm->tm_year + tm->tm_mon / 12;
971 int year_for_leap;
972 int64_t rt;
973
974 if (month < 0) { /* Negative values % 12 are still negative. */
975 month += 12;
976 --year;
977 }
978
979 /* This is the number of Februaries since 1900. */
980 year_for_leap = (month > 1) ? year + 1 : year;
981
982 rt =
983 tm->tm_sec /* Seconds */
984 +
985 60 *
986 (tm->tm_min /* Minute = 60 seconds */
987 +
988 60 * (tm->tm_hour /* Hour = 60 minutes */
989 +
990 24 * (month_day[month] + tm->tm_mday - 1 /* Day = 24 hours */
991 + 365 * (year - 70) /* Year = 365 days */
992 + (year_for_leap - 69) / 4 /* Every 4 years is leap... */
993 - (year_for_leap - 1) / 100 /* Except centuries... */
994 + (year_for_leap + 299) / 400))); /* Except 400s. */
995 return rt < 0 ? -1 : (double) rt;
996}
MUTEX_T * tm
Definition odbedit.cxx:39
Here is the call graph for this function:

◆ fourbit()

static int fourbit ( int  ch)
static

Definition at line 2147 of file mongoose616.cxx.

2147 {
2148 if (ch >= '0' && ch <= '9') {
2149 return ch - '0';
2150 } else if (ch >= 'a' && ch <= 'f') {
2151 return ch - 'a' + 10;
2152 } else if (ch >= 'A' && ch <= 'F') {
2153 return ch - 'A' + 10;
2154 }
2155 return 0;
2156}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fprint_str()

void fprint_str ( FILE fp,
const char str 
)

Definition at line 13556 of file mongoose616.cxx.

13556 {
13557 while (*str != '\0') {
13558 if (*str == '\n') MAP_UARTCharPut(CONSOLE_UART, '\r');
13560 }
13561}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ from_b64()

static unsigned char from_b64 ( unsigned char  ch)
static

Definition at line 376 of file mongoose616.cxx.

376 {
377 /* Inverse lookup map */
378 static const unsigned char tab[128] = {
379 255, 255, 255, 255,
380 255, 255, 255, 255, /* 0 */
381 255, 255, 255, 255,
382 255, 255, 255, 255, /* 8 */
383 255, 255, 255, 255,
384 255, 255, 255, 255, /* 16 */
385 255, 255, 255, 255,
386 255, 255, 255, 255, /* 24 */
387 255, 255, 255, 255,
388 255, 255, 255, 255, /* 32 */
389 255, 255, 255, 62,
390 255, 255, 255, 63, /* 40 */
391 52, 53, 54, 55,
392 56, 57, 58, 59, /* 48 */
393 60, 61, 255, 255,
394 255, 200, 255, 255, /* 56 '=' is 200, on index 61 */
395 255, 0, 1, 2,
396 3, 4, 5, 6, /* 64 */
397 7, 8, 9, 10,
398 11, 12, 13, 14, /* 72 */
399 15, 16, 17, 18,
400 19, 20, 21, 22, /* 80 */
401 23, 24, 25, 255,
402 255, 255, 255, 255, /* 88 */
403 255, 26, 27, 28,
404 29, 30, 31, 32, /* 96 */
405 33, 34, 35, 36,
406 37, 38, 39, 40, /* 104 */
407 41, 42, 43, 44,
408 45, 46, 47, 48, /* 112 */
409 49, 50, 51, 255,
410 255, 255, 255, 255, /* 120 */
411 };
412 return tab[ch & 127];
413}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ gettimeofday()

int gettimeofday ( struct timeval tp,
void tzp 
)

Definition at line 13620 of file mongoose616.cxx.

13620 {
13622 tp->tv_sec = ticks / 1000;
13623 tp->tv_usec = (ticks % 1000) * 1000;
13624 return 0;
13625}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ inet_ntoa()

char * inet_ntoa ( struct in_addr  n)

Definition at line 14479 of file mongoose616.cxx.

14479 {
14480 static char a[16];
14481 return (char *) inet_ntop(AF_INET, &n, a, sizeof(a));
14482}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ inet_ntop()

const char * inet_ntop ( int  af,
const void src,
char dst,
socklen_t  size 
)

Definition at line 14466 of file mongoose616.cxx.

14466 {
14467 int res;
14468 struct in_addr *in = (struct in_addr *) src;
14469 if (af != AF_INET) {
14470 errno = ENOTSUP;
14471 return NULL;
14472 }
14473 res = snprintf(dst, size, "%lu.%lu.%lu.%lu", SL_IPV4_BYTE(in->s_addr, 0),
14474 SL_IPV4_BYTE(in->s_addr, 1), SL_IPV4_BYTE(in->s_addr, 2),
14475 SL_IPV4_BYTE(in->s_addr, 3));
14476 return res > 0 ? dst : NULL;
14477}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ inet_pton()

int inet_pton ( int  af,
const char src,
void dst 
)

Definition at line 14484 of file mongoose616.cxx.

14484 {
14485 uint32_t a0, a1, a2, a3;
14486 uint8_t *db = (uint8_t *) dst;
14487 if (af != AF_INET) {
14488 errno = ENOTSUP;
14489 return 0;
14490 }
14491 if (sscanf(src, "%lu.%lu.%lu.%lu", &a0, &a1, &a2, &a3) != 4) {
14492 return 0;
14493 }
14494 *db = a3;
14495 *(db + 1) = a2;
14496 *(db + 2) = a1;
14497 *(db + 3) = a0;
14498 return 1;
14499}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ isbyte()

static int isbyte ( int  n)
static

Definition at line 3477 of file mongoose616.cxx.

3477 {
3478 return n >= 0 && n <= 255;
3479}
Here is the caller graph for this function:

◆ mbuf_append_and_free()

size_t mbuf_append_and_free ( struct mbuf a,
void buf,
size_t  len 
)

Definition at line 1633 of file mongoose616.cxx.

1633 {
1634 size_t ret;
1635 /* Optimization: if the buffer is currently empty,
1636 * take over the user-provided buffer. */
1637 if (a->len == 0) {
1638 if (a->buf != NULL) free(a->buf);
1639 a->buf = (char *) data;
1640 a->len = a->size = len;
1641 return len;
1642 }
1643 ret = mbuf_insert(a, a->len, data, len);
1644 free(data);
1645 return ret;
1646}
Here is the call graph for this function:

◆ mbuf_clear()

void mbuf_clear ( struct mbuf mb)

Definition at line 1657 of file mongoose616.cxx.

1657 {
1658 mb->len = 0;
1659}
Here is the call graph for this function:

◆ mbuf_move()

void mbuf_move ( struct mbuf from,
struct mbuf to 
)

Definition at line 1662 of file mongoose616.cxx.

1662 {
1663 memcpy(to, from, sizeof(*to));
1664 memset(from, 0, sizeof(*from));
1665}
Here is the call graph for this function:

◆ mg_accept_conn()

static int mg_accept_conn ( struct mg_connection lc)
static

Definition at line 3978 of file mongoose616.cxx.

3978 {
3979 struct mg_connection *nc;
3980 union socket_address sa;
3981 socklen_t sa_len = sizeof(sa);
3982 /* NOTE(lsm): on Windows, sock is always > FD_SETSIZE */
3983 sock_t sock = accept(lc->sock, &sa.sa, &sa_len);
3984 if (sock == INVALID_SOCKET) {
3985 if (mg_is_error()) {
3986 DBG(("%p: failed to accept: %d", lc, mg_get_errno()));
3987 }
3988 return 0;
3989 }
3990 nc = mg_if_accept_new_conn(lc);
3991 if (nc == NULL) {
3992 closesocket(sock);
3993 return 0;
3994 }
3995 DBG(("%p conn from %s:%d", nc, inet_ntoa(sa.sin.sin_addr),
3996 ntohs(sa.sin.sin_port)));
3997 mg_sock_set(nc, sock);
3999 return 1;
4000}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_add_conn()

MG_INTERNAL void mg_add_conn ( struct mg_mgr mgr,
struct mg_connection c 
)

Definition at line 2421 of file mongoose616.cxx.

2421 {
2422 DBG(("%p %p", mgr, c));
2423 c->mgr = mgr;
2424 c->next = mgr->active_connections;
2425 mgr->active_connections = c;
2426 c->prev = NULL;
2427 if (c->next != NULL) c->next->prev = c;
2428 if (c->sock != INVALID_SOCKET) {
2429 c->iface->vtable->add_conn(c);
2430 }
2431}
void(* add_conn)(struct mg_connection *nc)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_add_sock()

struct mg_connection * mg_add_sock ( struct mg_mgr s,
sock_t  sock,
MG_CB(mg_event_handler_t callback, void *user_data)   
)

Definition at line 3570 of file mongoose616.cxx.

3572 {
3573 struct mg_add_sock_opts opts;
3574 memset(&opts, 0, sizeof(opts));
3575 return mg_add_sock_opt(s, sock, MG_CB(callback, user_data), opts);
3576}
Here is the call graph for this function:

◆ mg_add_sock_opt()

struct mg_connection * mg_add_sock_opt ( struct mg_mgr s,
sock_t  sock,
MG_CB(mg_event_handler_t callback, void *user_data)  ,
struct mg_add_sock_opts  opts 
)

Definition at line 3554 of file mongoose616.cxx.

3557 {
3558#if MG_ENABLE_CALLBACK_USERDATA
3559 opts.user_data = user_data;
3560#endif
3561
3563 if (nc != NULL) {
3564 mg_sock_set(nc, sock);
3565 mg_add_conn(nc->mgr, nc);
3566 }
3567 return nc;
3568}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_add_to_set()

void mg_add_to_set ( sock_t  sock,
fd_set set,
sock_t max_fd 
)

Definition at line 4163 of file mongoose616.cxx.

4163 {
4164 if (sock != INVALID_SOCKET
4166 && sock < (sock_t) FD_SETSIZE
4167#endif
4168 ) {
4169 FD_SET(sock, set);
4170 if (*max_fd == INVALID_SOCKET || sock > *max_fd) {
4171 *max_fd = sock;
4172 }
4173 }
4174}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_asprintf()

int mg_asprintf ( char **  buf,
size_t  size,
const char fmt,
  ... 
)

Definition at line 2208 of file mongoose616.cxx.

2208 {
2209 int ret;
2210 va_list ap;
2211 va_start(ap, fmt);
2212 ret = mg_avprintf(buf, size, fmt, ap);
2213 va_end(ap);
2214 return ret;
2215}
Here is the call graph for this function:

◆ mg_assemble_uri()

int mg_assemble_uri ( const struct mg_str scheme,
const struct mg_str user_info,
const struct mg_str host,
unsigned int  port,
const struct mg_str path,
const struct mg_str query,
const struct mg_str fragment,
int  normalize_path,
struct mg_str uri 
)

Definition at line 5797 of file mongoose616.cxx.

5801 {
5802 int result = -1;
5803 struct mbuf out;
5804 mbuf_init(&out, 0);
5805
5806 if (scheme != NULL && scheme->len > 0) {
5807 mbuf_append(&out, scheme->p, scheme->len);
5808 mbuf_append(&out, "://", 3);
5809 }
5810
5811 if (user_info != NULL && user_info->len > 0) {
5812 mbuf_append(&out, user_info->p, user_info->len);
5813 mbuf_append(&out, "@", 1);
5814 }
5815
5816 if (host != NULL && host->len > 0) {
5817 mbuf_append(&out, host->p, host->len);
5818 }
5819
5820 if (port != 0) {
5821 char port_str[20];
5822 int port_str_len = sprintf(port_str, ":%u", port);
5824 }
5825
5826 if (path != NULL && path->len > 0) {
5827 if (normalize_path) {
5828 struct mg_str npath = mg_strdup(*path);
5829 if (npath.len != path->len) goto out;
5830 if (!mg_normalize_uri_path(path, &npath)) {
5831 free((void *) npath.p);
5832 goto out;
5833 }
5834 mbuf_append(&out, npath.p, npath.len);
5835 free((void *) npath.p);
5836 } else {
5837 mbuf_append(&out, path->p, path->len);
5838 }
5839 } else if (normalize_path) {
5840 mbuf_append(&out, "/", 1);
5841 }
5842
5843 if (query != NULL && query->len > 0) {
5844 mbuf_append(&out, "?", 1);
5845 mbuf_append(&out, query->p, query->len);
5846 }
5847
5848 if (fragment != NULL && fragment->len > 0) {
5849 mbuf_append(&out, "#", 1);
5850 mbuf_append(&out, fragment->p, fragment->len);
5851 }
5852
5853 result = 0;
5854
5855out:
5856 if (result == 0) {
5857 uri->p = out.buf;
5858 uri->len = out.len;
5859 } else {
5860 mbuf_free(&out);
5861 uri->p = NULL;
5862 uri->len = 0;
5863 }
5864 return result;
5865}
Here is the call graph for this function:

◆ mg_basic_auth_header()

void mg_basic_auth_header ( const struct mg_str  user,
const struct mg_str  pass,
struct mbuf buf 
)

Definition at line 10916 of file mongoose616.cxx.

10917 {
10918 const char *header_prefix = "Authorization: Basic ";
10919 const char *header_suffix = "\r\n";
10920
10921 struct cs_base64_ctx ctx;
10923
10925
10926 cs_base64_update(&ctx, user.p, user.len);
10927 if (pass.len > 0) {
10928 cs_base64_update(&ctx, ":", 1);
10929 cs_base64_update(&ctx, pass.p, pass.len);
10930 }
10931 cs_base64_finish(&ctx);
10933}
Here is the call graph for this function:

◆ mg_bind()

struct mg_connection * mg_bind ( struct mg_mgr srv,
const char address,
MG_CB(mg_event_handler_t event_handler, void *user_data)   
)

Definition at line 3364 of file mongoose616.cxx.

3366 {
3367 struct mg_bind_opts opts;
3368 memset(&opts, 0, sizeof(opts));
3369 return mg_bind_opt(srv, address, MG_CB(event_handler, user_data), opts);
3370}
Here is the call graph for this function:

◆ mg_bind_opt()

struct mg_connection * mg_bind_opt ( struct mg_mgr mgr,
const char address,
MG_CB(mg_event_handler_t callback, void *user_data)  ,
struct mg_bind_opts  opts 
)

Definition at line 3372 of file mongoose616.cxx.

3375 {
3376 union socket_address sa;
3377 struct mg_connection *nc = NULL;
3378 int proto, rc;
3380 char host[MG_MAX_HOST_LEN];
3381
3382#if MG_ENABLE_CALLBACK_USERDATA
3384#endif
3385
3387
3389
3390 if (mg_parse_address(address, &sa, &proto, host, sizeof(host)) <= 0) {
3391 MG_SET_PTRPTR(opts.error_string, "cannot parse address");
3392 return NULL;
3393 }
3394
3396 if (nc == NULL) {
3397 return NULL;
3398 }
3399
3400 nc->sa = sa;
3401 nc->flags |= MG_F_LISTENING;
3402 if (proto == SOCK_DGRAM) nc->flags |= MG_F_UDP;
3403
3404#if MG_ENABLE_SSL
3405 DBG(("%p %s %s,%s,%s", nc, address, (opts.ssl_cert ? opts.ssl_cert : "-"),
3406 (opts.ssl_key ? opts.ssl_key : "-"),
3407 (opts.ssl_ca_cert ? opts.ssl_ca_cert : "-")));
3408
3409 if (opts.ssl_cert != NULL || opts.ssl_ca_cert != NULL) {
3410 const char *err_msg = NULL;
3411 struct mg_ssl_if_conn_params params;
3412 if (nc->flags & MG_F_UDP) {
3413 MG_SET_PTRPTR(opts.error_string, "SSL for UDP is not supported");
3414 mg_destroy_conn(nc, 1 /* destroy_if */);
3415 return NULL;
3416 }
3417 memset(&params, 0, sizeof(params));
3418 params.cert = opts.ssl_cert;
3419 params.key = opts.ssl_key;
3420 params.ca_cert = opts.ssl_ca_cert;
3421 params.cipher_suites = opts.ssl_cipher_suites;
3422 if (mg_ssl_if_conn_init(nc, &params, &err_msg) != MG_SSL_OK) {
3423 MG_SET_PTRPTR(opts.error_string, err_msg);
3424 mg_destroy_conn(nc, 1 /* destroy_if */);
3425 return NULL;
3426 }
3427 nc->flags |= MG_F_SSL;
3428 }
3429#endif /* MG_ENABLE_SSL */
3430
3431 if (nc->flags & MG_F_UDP) {
3432 rc = nc->iface->vtable->listen_udp(nc, &nc->sa);
3433 } else {
3434 rc = nc->iface->vtable->listen_tcp(nc, &nc->sa);
3435 }
3436 if (rc != 0) {
3437 DBG(("Failed to open listener: %d", rc));
3438 MG_SET_PTRPTR(opts.error_string, "failed to open listener");
3439 mg_destroy_conn(nc, 1 /* destroy_if */);
3440 return NULL;
3441 }
3442 mg_add_conn(nc->mgr, nc);
3443
3444 return nc;
3445}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_call()

MG_INTERNAL void mg_call ( struct mg_connection nc,
mg_event_handler_t  ev_handler,
void user_data,
int  ev,
void ev_data 
)

Definition at line 2441 of file mongoose616.cxx.

2443 {
2444 if (ev_handler == NULL) {
2445 /*
2446 * If protocol handler is specified, call it. Otherwise, call user-specified
2447 * event handler.
2448 */
2450 }
2451 if (ev != MG_EV_POLL) {
2452 DBG(("%p %s ev=%d ev_data=%p flags=0x%lx rmbl=%d smbl=%d", nc,
2453 ev_handler == nc->handler ? "user" : "proto", ev, ev_data, nc->flags,
2454 (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
2455 }
2456
2457#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
2458 if (nc->mgr->hexdump_file != NULL && ev != MG_EV_POLL && ev != MG_EV_RECV &&
2459 ev != MG_EV_SEND /* handled separately */) {
2461 }
2462#endif
2463 if (ev_handler != NULL) {
2464 unsigned long flags_before = nc->flags;
2465 ev_handler(nc, ev, ev_data MG_UD_ARG(user_data));
2466 /* Prevent user handler from fiddling with system flags. */
2467 if (ev_handler == nc->handler && nc->flags != flags_before) {
2470 }
2471 }
2472 if (ev != MG_EV_POLL) nc->mgr->num_calls++;
2473 if (ev != MG_EV_POLL) {
2474 DBG(("%p after %s flags=0x%lx rmbl=%d smbl=%d", nc,
2475 ev_handler == nc->handler ? "user" : "proto", nc->flags,
2476 (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
2477 }
2478#if !MG_ENABLE_CALLBACK_USERDATA
2479 (void) user_data;
2480#endif
2481}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_connect()

struct mg_connection * mg_connect ( struct mg_mgr mgr,
const char address,
MG_CB(mg_event_handler_t callback, void *user_data)   
)

Definition at line 3242 of file mongoose616.cxx.

3244 {
3245 struct mg_connect_opts opts;
3246 memset(&opts, 0, sizeof(opts));
3247 return mg_connect_opt(mgr, address, MG_CB(callback, user_data), opts);
3248}
Here is the call graph for this function:

◆ mg_connect_opt()

struct mg_connection * mg_connect_opt ( struct mg_mgr mgr,
const char address,
MG_CB(mg_event_handler_t callback, void *user_data)  ,
struct mg_connect_opts  opts 
)

Definition at line 3260 of file mongoose616.cxx.

3263 {
3264 struct mg_connection *nc = NULL;
3265 int proto, rc;
3267 char host[MG_MAX_HOST_LEN];
3268
3270
3272
3273 if ((nc = mg_create_connection(mgr, callback, add_sock_opts)) == NULL) {
3274 return NULL;
3275 }
3276
3277 if ((rc = mg_parse_address(address, &nc->sa, &proto, host, sizeof(host))) <
3278 0) {
3279 /* Address is malformed */
3280 MG_SET_PTRPTR(opts.error_string, "cannot parse address");
3281 mg_destroy_conn(nc, 1 /* destroy_if */);
3282 return NULL;
3283 }
3284
3286 nc->flags |= (proto == SOCK_DGRAM) ? MG_F_UDP : 0;
3287#if MG_ENABLE_CALLBACK_USERDATA
3288 nc->user_data = user_data;
3289#else
3290 nc->user_data = opts.user_data;
3291#endif
3292
3293#if MG_ENABLE_SSL
3294 LOG(LL_DEBUG,
3295 ("%p %s %s,%s,%s", nc, address, (opts.ssl_cert ? opts.ssl_cert : "-"),
3296 (opts.ssl_key ? opts.ssl_key : "-"),
3297 (opts.ssl_ca_cert ? opts.ssl_ca_cert : "-")));
3298
3299 if (opts.ssl_cert != NULL || opts.ssl_ca_cert != NULL ||
3300 opts.ssl_psk_identity != NULL) {
3301 const char *err_msg = NULL;
3302 struct mg_ssl_if_conn_params params;
3303 if (nc->flags & MG_F_UDP) {
3304 MG_SET_PTRPTR(opts.error_string, "SSL for UDP is not supported");
3305 mg_destroy_conn(nc, 1 /* destroy_if */);
3306 return NULL;
3307 }
3308 memset(&params, 0, sizeof(params));
3309 params.cert = opts.ssl_cert;
3310 params.key = opts.ssl_key;
3311 params.ca_cert = opts.ssl_ca_cert;
3312 params.cipher_suites = opts.ssl_cipher_suites;
3313 params.psk_identity = opts.ssl_psk_identity;
3314 params.psk_key = opts.ssl_psk_key;
3315 if (opts.ssl_ca_cert != NULL) {
3316 if (opts.ssl_server_name != NULL) {
3317 if (strcmp(opts.ssl_server_name, "*") != 0) {
3318 params.server_name = opts.ssl_server_name;
3319 }
3320 } else if (rc == 0) { /* If it's a DNS name, use host. */
3321 params.server_name = host;
3322 }
3323 }
3324 if (mg_ssl_if_conn_init(nc, &params, &err_msg) != MG_SSL_OK) {
3325 MG_SET_PTRPTR(opts.error_string, err_msg);
3326 mg_destroy_conn(nc, 1 /* destroy_if */);
3327 return NULL;
3328 }
3329 nc->flags |= MG_F_SSL;
3330 }
3331#endif /* MG_ENABLE_SSL */
3332
3333 if (rc == 0) {
3334#if MG_ENABLE_ASYNC_RESOLVER
3335 /*
3336 * DNS resolution is required for host.
3337 * mg_parse_address() fills port in nc->sa, which we pass to resolve_cb()
3338 */
3339 struct mg_connection *dns_conn = NULL;
3340 struct mg_resolve_async_opts o;
3341 memset(&o, 0, sizeof(o));
3342 o.dns_conn = &dns_conn;
3343 o.nameserver = opts.nameserver;
3345 o) != 0) {
3346 MG_SET_PTRPTR(opts.error_string, "cannot schedule DNS lookup");
3347 mg_destroy_conn(nc, 1 /* destroy_if */);
3348 return NULL;
3349 }
3350 nc->priv_2 = dns_conn;
3351 nc->flags |= MG_F_RESOLVING;
3352 return nc;
3353#else
3354 MG_SET_PTRPTR(opts.error_string, "Resolver is disabled");
3355 mg_destroy_conn(nc, 1 /* destroy_if */);
3356 return NULL;
3357#endif
3358 } else {
3359 /* Address is parsed and resolved to IP. proceed with connect() */
3360 return mg_do_connect(nc, proto, &nc->sa);
3361 }
3362}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_create_connection()

MG_INTERNAL struct mg_connection * mg_create_connection ( struct mg_mgr mgr,
mg_event_handler_t  callback,
struct mg_add_sock_opts  opts 
)

Definition at line 2764 of file mongoose616.cxx.

2766 {
2768
2769 if (conn != NULL && !conn->iface->vtable->create_conn(conn)) {
2770 MG_FREE(conn);
2771 conn = NULL;
2772 }
2773 if (conn == NULL) {
2774 MG_SET_PTRPTR(opts.error_string, "failed to init connection");
2775 }
2776
2777 return conn;
2778}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_create_connection_base()

MG_INTERNAL struct mg_connection * mg_create_connection_base ( struct mg_mgr mgr,
mg_event_handler_t  callback,
struct mg_add_sock_opts  opts 
)

Definition at line 2737 of file mongoose616.cxx.

2739 {
2740 struct mg_connection *conn;
2741
2742 if ((conn = (struct mg_connection *) MG_CALLOC(1, sizeof(*conn))) != NULL) {
2743 conn->sock = INVALID_SOCKET;
2744 conn->handler = callback;
2745 conn->mgr = mgr;
2746 conn->last_io_time = (time_t) mg_time();
2747 conn->iface =
2748 (opts.iface != NULL ? opts.iface : mgr->ifaces[MG_MAIN_IFACE]);
2750 conn->user_data = opts.user_data;
2751 /*
2752 * SIZE_MAX is defined as a long long constant in
2753 * system headers on some platforms and so it
2754 * doesn't compile with pedantic ansi flags.
2755 */
2756 conn->recv_mbuf_limit = ~0;
2757 } else {
2758 MG_SET_PTRPTR(opts.error_string, "failed to create connection");
2759 }
2760
2761 return conn;
2762}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_destroy_conn()

void mg_destroy_conn ( struct mg_connection conn,
int  destroy_if 
)

Definition at line 2534 of file mongoose616.cxx.

2534 {
2535 if (conn->sock != INVALID_SOCKET) { /* Don't print timer-only conns */
2536 LOG(LL_DEBUG, ("%p 0x%lx %d", conn, conn->flags, destroy_if));
2537 }
2538 if (destroy_if) conn->iface->vtable->destroy_conn(conn);
2539 if (conn->proto_data != NULL && conn->proto_data_destructor != NULL) {
2540 conn->proto_data_destructor(conn->proto_data);
2541 }
2542#if MG_ENABLE_SSL
2543 mg_ssl_if_conn_free(conn);
2544#endif
2545 mbuf_free(&conn->recv_mbuf);
2546 mbuf_free(&conn->send_mbuf);
2547
2548 memset(conn, 0, sizeof(*conn));
2549 MG_FREE(conn);
2550}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_do_connect()

MG_INTERNAL struct mg_connection * mg_do_connect ( struct mg_connection nc,
int  proto,
union socket_address sa 
)

Definition at line 3161 of file mongoose616.cxx.

3163 {
3164 LOG(LL_DEBUG, ("%p %s://%s:%hu", nc, proto == SOCK_DGRAM ? "udp" : "tcp",
3165 inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port)));
3166
3167 nc->flags |= MG_F_CONNECTING;
3168 if (proto == SOCK_DGRAM) {
3169 nc->iface->vtable->connect_udp(nc);
3170 } else {
3171 nc->iface->vtable->connect_tcp(nc, sa);
3172 }
3173 mg_add_conn(nc->mgr, nc);
3174 return nc;
3175}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_do_recv()

static int mg_do_recv ( struct mg_connection nc)
static

Definition at line 2946 of file mongoose616.cxx.

2946 {
2947 int res = 0;
2948 char *buf = NULL;
2949 size_t len = (nc->flags & MG_F_UDP ? MG_UDP_IO_SIZE : MG_TCP_IO_SIZE);
2951 ((nc->flags & MG_F_LISTENING) && !(nc->flags & MG_F_UDP))) {
2952 return -1;
2953 }
2954 do {
2955 len = recv_avail_size(nc, len);
2956 if (len == 0) {
2957 res = -2;
2958 break;
2959 }
2960 if (nc->recv_mbuf.size < nc->recv_mbuf.len + len) {
2961 mbuf_resize(&nc->recv_mbuf, nc->recv_mbuf.len + len);
2962 }
2963 buf = nc->recv_mbuf.buf + nc->recv_mbuf.len;
2964 len = nc->recv_mbuf.size - nc->recv_mbuf.len;
2965 if (nc->flags & MG_F_UDP) {
2966 res = mg_recv_udp(nc, buf, len);
2967 } else {
2968 res = mg_recv_tcp(nc, buf, len);
2969 }
2970 } while (res > 0 && !(nc->flags & (MG_F_CLOSE_IMMEDIATELY | MG_F_UDP)));
2971 return res;
2972}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_ev_handler_empty()

void mg_ev_handler_empty ( struct mg_connection c,
int  ev,
void *ev_data   MG_UD_ARGvoid *user_data 
)

Definition at line 3250 of file mongoose616.cxx.

3251 {
3252 (void) c;
3253 (void) ev;
3254 (void) ev_data;
3255#if MG_ENABLE_CALLBACK_USERDATA
3256 (void) user_data;
3257#endif
3258}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_ev_mgr_lwip_process_signals()

void mg_ev_mgr_lwip_process_signals ( struct mg_mgr mgr)

Definition at line 16156 of file mongoose616.cxx.

16156 {
16157 struct mg_ev_mgr_lwip_data *md =
16158 (struct mg_ev_mgr_lwip_data *) mgr->ifaces[MG_MAIN_IFACE]->data;
16159 while (md->sig_queue_len > 0) {
16160 mgos_lock();
16161 int i = md->start_index;
16162 int sig = md->sig_queue[i].sig;
16163 struct mg_connection *nc = md->sig_queue[i].nc;
16164 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
16165 md->start_index = (i + 1) % MG_SIG_QUEUE_LEN;
16166 md->sig_queue_len--;
16167 mgos_unlock();
16168 if (nc->iface == NULL || nc->mgr == NULL) continue;
16169 switch (sig) {
16170 case MG_SIG_CONNECT_RESULT: {
16172 break;
16173 }
16174 case MG_SIG_CLOSE_CONN: {
16176 break;
16177 }
16178 case MG_SIG_RECV: {
16179 cs->recv_pending = 0;
16182 break;
16183 }
16184 case MG_SIG_TOMBSTONE: {
16185 break;
16186 }
16187 case MG_SIG_ACCEPT: {
16189 break;
16190 }
16191 }
16192 }
16193}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_find_iface()

struct mg_iface * mg_find_iface ( struct mg_mgr mgr,
const struct mg_iface_vtable vtable,
struct mg_iface from 
)

Definition at line 3658 of file mongoose616.cxx.

3660 {
3661 int i = 0;
3662 if (from != NULL) {
3663 for (i = 0; i < mgr->num_ifaces; i++) {
3664 if (mgr->ifaces[i] == from) {
3665 i++;
3666 break;
3667 }
3668 }
3669 }
3670
3671 for (; i < mgr->num_ifaces; i++) {
3672 if (mgr->ifaces[i]->vtable == vtable) {
3673 return mgr->ifaces[i];
3674 }
3675 }
3676 return NULL;
3677}
Here is the call graph for this function:

◆ mg_forward()

void mg_forward ( struct mg_connection from,
struct mg_connection to 
)

Definition at line 3522 of file mongoose616.cxx.

3522 {
3523 mg_send(to, from->recv_mbuf.buf, from->recv_mbuf.len);
3524 mbuf_remove(&from->recv_mbuf, from->recv_mbuf.len);
3525}
Here is the call graph for this function:

◆ mg_get_errno()

MG_INTERNAL int mg_get_errno ( void  )

Definition at line 10895 of file mongoose616.cxx.

10895 {
10896#ifndef WINCE
10897 return errno;
10898#else
10899 /* TODO(alashkin): translate error codes? */
10900 return GetLastError();
10901#endif
10902}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_handle_recv()

static void mg_handle_recv ( struct mg_connection nc)
static

Definition at line 16584 of file mongoose616.cxx.

16584 {
16585 uint16_t bytes_read = 0;
16586 uint8_t *buf = NULL;
16587 if (nc->flags & MG_F_UDP) {
16588 bytes_read = TCPIP_UDP_GetIsReady((UDP_SOCKET) nc->sock);
16589 if (bytes_read != 0 &&
16590 (nc->recv_mbuf_limit == -1 ||
16591 nc->recv_mbuf.len + bytes_read < nc->recv_mbuf_limit)) {
16592 buf = (uint8_t *) MG_MALLOC(bytes_read);
16593 if (TCPIP_UDP_ArrayGet((UDP_SOCKET) nc->sock, buf, bytes_read) !=
16594 bytes_read) {
16596 bytes_read = 0;
16597 MG_FREE(buf);
16598 }
16599 }
16600 } else {
16601 bytes_read = TCPIP_TCP_GetIsReady((TCP_SOCKET) nc->sock);
16602 if (bytes_read != 0) {
16603 if (nc->recv_mbuf_limit != -1 &&
16604 nc->recv_mbuf_limit - nc->recv_mbuf.len > bytes_read) {
16605 bytes_read = nc->recv_mbuf_limit - nc->recv_mbuf.len;
16606 }
16607 buf = (uint8_t *) MG_MALLOC(bytes_read);
16608 if (TCPIP_TCP_ArrayGet((TCP_SOCKET) nc->sock, buf, bytes_read) !=
16609 bytes_read) {
16611 MG_FREE(buf);
16612 bytes_read = 0;
16613 }
16614 }
16615 }
16616
16617 if (bytes_read != 0) {
16618 mg_if_recv_tcp_cb(nc, buf, bytes_read, 1 /* own */);
16619 }
16620}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_handle_send()

static void mg_handle_send ( struct mg_connection nc)
static

Definition at line 16546 of file mongoose616.cxx.

16546 {
16547 uint16_t bytes_written = 0;
16548 if (nc->flags & MG_F_UDP) {
16550 (UDP_SOCKET) nc->sock,
16551 nc->sa.sin.sin_family == AF_INET ? IP_ADDRESS_TYPE_IPV4
16553 ntohs(nc->sa.sin.sin_port), (IP_MULTI_ADDRESS *) &nc->sa.sin)) {
16555 return;
16556 }
16557 bytes_written = TCPIP_UDP_TxPutIsReady((UDP_SOCKET) nc->sock, 0);
16558 if (bytes_written >= nc->send_mbuf.len) {
16560 (uint8_t *) nc->send_mbuf.buf,
16561 nc->send_mbuf.len) != nc->send_mbuf.len) {
16563 bytes_written = 0;
16564 }
16565 }
16566 } else {
16567 bytes_written = TCPIP_TCP_FifoTxFreeGet((TCP_SOCKET) nc->sock);
16568 if (bytes_written != 0) {
16569 if (bytes_written > nc->send_mbuf.len) {
16570 bytes_written = nc->send_mbuf.len;
16571 }
16573 (uint8_t *) nc->send_mbuf.buf,
16574 bytes_written) != bytes_written) {
16576 bytes_written = 0;
16577 }
16578 }
16579 }
16580
16581 mg_if_sent_cb(nc, bytes_written);
16582}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_if_can_recv_cb()

void mg_if_can_recv_cb ( struct mg_connection nc)

Definition at line 2974 of file mongoose616.cxx.

2974 {
2975 mg_do_recv(nc);
2976}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_if_can_send_cb()

void mg_if_can_send_cb ( struct mg_connection nc)

Definition at line 3097 of file mongoose616.cxx.

3097 {
3098 int n = 0;
3099 const char *buf = nc->send_mbuf.buf;
3100 size_t len = nc->send_mbuf.len;
3101
3103 return;
3104 }
3105 if (!(nc->flags & MG_F_UDP)) {
3106 if (nc->flags & MG_F_LISTENING) return;
3107 if (len > MG_TCP_IO_SIZE) len = MG_TCP_IO_SIZE;
3108 }
3109#if MG_ENABLE_SSL
3110 if (nc->flags & MG_F_SSL) {
3111 if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
3112 if (len > 0) {
3113 n = mg_ssl_if_write(nc, buf, len);
3114 DBG(("%p -> %d bytes (SSL)", nc, n));
3115 }
3116 if (n < 0) {
3117 if (n == MG_SSL_WANT_WRITE) {
3118 nc->flags |= MG_F_WANT_WRITE;
3119 n = 0;
3120 } else {
3122 }
3123 } else {
3124 nc->flags &= ~MG_F_WANT_WRITE;
3125 }
3126 } else {
3127 mg_ssl_handshake(nc);
3128 }
3129 } else
3130#endif
3131 if (len > 0) {
3132 if (nc->flags & MG_F_UDP) {
3133 n = nc->iface->vtable->udp_send(nc, buf, len);
3134 } else {
3135 n = nc->iface->vtable->tcp_send(nc, buf, len);
3136 }
3137 DBG(("%p -> %d bytes", nc, n));
3138 }
3139
3140#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
3141 if (n > 0 && nc->mgr && nc->mgr->hexdump_file != NULL) {
3143 }
3144#endif
3145 if (n < 0) {
3147 } else if (n > 0) {
3148 nc->last_io_time = (time_t) mg_time();
3149 mbuf_remove(&nc->send_mbuf, n);
3150 mbuf_trim(&nc->send_mbuf);
3151 }
3152 if (n != 0) mg_call(nc, NULL, nc->user_data, MG_EV_SEND, &n);
3153}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_if_create_iface()

struct mg_iface * mg_if_create_iface ( const struct mg_iface_vtable vtable,
struct mg_mgr mgr 
)

Definition at line 3649 of file mongoose616.cxx.

3650 {
3651 struct mg_iface *iface = (struct mg_iface *) MG_CALLOC(1, sizeof(*iface));
3652 iface->mgr = mgr;
3653 iface->data = NULL;
3654 iface->vtable = vtable;
3655 return iface;
3656}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_if_poll()

int mg_if_poll ( struct mg_connection nc,
double  now 
)

Definition at line 2500 of file mongoose616.cxx.

2500 {
2501 if (nc->flags & MG_F_CLOSE_IMMEDIATELY) {
2502 mg_close_conn(nc);
2503 return 0;
2504 } else if (nc->flags & MG_F_SEND_AND_CLOSE) {
2505 if (nc->send_mbuf.len == 0) {
2507 mg_close_conn(nc);
2508 return 0;
2509 }
2510 } else if (nc->flags & MG_F_RECV_AND_CLOSE) {
2511 mg_close_conn(nc);
2512 return 0;
2513 }
2514#if MG_ENABLE_SSL
2515 if ((nc->flags & (MG_F_SSL | MG_F_LISTENING | MG_F_CONNECTING)) == MG_F_SSL) {
2516 /* SSL library may have data to be delivered to the app in its buffers,
2517 * drain them. */
2518 int recved = 0;
2519 do {
2520 if (nc->flags & (MG_F_WANT_READ | MG_F_WANT_WRITE)) break;
2521 if (recv_avail_size(nc, MG_TCP_IO_SIZE) <= 0) break;
2522 recved = mg_do_recv(nc);
2523 } while (recved > 0);
2524 }
2525#endif /* MG_ENABLE_SSL */
2526 mg_timer(nc, now);
2527 {
2528 time_t now_t = (time_t) now;
2529 mg_call(nc, NULL, nc->user_data, MG_EV_POLL, &now_t);
2530 }
2531 return 1;
2532}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_is_error() [1/2]

static int mg_is_error ( int  n)
static

Definition at line 14641 of file mongoose616.cxx.

14641 {
14642 return (n < 0 && n != SL_ERROR_BSD_EALREADY && n != SL_ERROR_BSD_EAGAIN);
14643}
Here is the call graph for this function:

◆ mg_is_error() [2/2]

static int mg_is_error ( void  )
static

Definition at line 3861 of file mongoose616.cxx.

3861 {
3862 int err = mg_get_errno();
3863 return err != EINPROGRESS && err != EWOULDBLOCK
3864#ifndef WINCE
3865 && err != EAGAIN && err != EINTR
3866#endif
3867#ifdef _WIN32
3869#endif
3870 ;
3871}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_lwip_accept_cb()

static err_t mg_lwip_accept_cb ( void arg,
struct tcp_pcb newtpcb,
err_t  err 
)
static

Definition at line 15741 of file mongoose616.cxx.

15741 {
15742 struct mg_connection *lc = (struct mg_connection *) arg, *nc;
15743 struct mg_lwip_conn_state *lcs, *cs;
15744 struct tcp_pcb_listen *lpcb;
15745 LOG(LL_DEBUG,
15746 ("%p conn %p from %s:%u", lc, newtpcb,
15747 IPADDR_NTOA(ipX_2_ip(&newtpcb->remote_ip)), newtpcb->remote_port));
15748 if (lc == NULL) {
15750 return ERR_ABRT;
15751 }
15752 lcs = (struct mg_lwip_conn_state *) lc->sock;
15753 lpcb = (struct tcp_pcb_listen *) lcs->pcb.tcp;
15754#if TCP_LISTEN_BACKLOG
15756#endif
15757 nc = mg_if_accept_new_conn(lc);
15758 if (nc == NULL) {
15760 return ERR_ABRT;
15761 }
15762 cs = (struct mg_lwip_conn_state *) nc->sock;
15763 cs->lc = lc;
15764 cs->pcb.tcp = newtpcb;
15765 /* We need to set up callbacks before returning because data may start
15766 * arriving immediately. */
15767 tcp_arg(newtpcb, nc);
15770 tcp_recv(newtpcb, mg_lwip_tcp_recv_cb);
15771#if LWIP_TCP_KEEPALIVE
15772 mg_lwip_set_keepalive_params(nc, 60, 10, 6);
15773#endif
15775 (void) err;
15776 (void) lpcb;
15777 return ERR_OK;
15778}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_lwip_handle_accept()

void mg_lwip_handle_accept ( struct mg_connection nc)

Definition at line 15731 of file mongoose616.cxx.

15731 {
15732 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15733 if (cs->pcb.tcp == NULL) return;
15734 union socket_address sa;
15735 struct tcp_pcb *tpcb = cs->pcb.tcp;
15736 SET_ADDR(&sa, &tpcb->remote_ip);
15737 sa.sin.sin_port = htons(tpcb->remote_port);
15738 mg_if_accept_tcp_cb(nc, &sa, sizeof(sa.sin));
15739}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_lwip_if_add_conn()

void mg_lwip_if_add_conn ( struct mg_connection nc)

Definition at line 16210 of file mongoose616.cxx.

16210 {
16211 (void) nc;
16212}
Here is the call graph for this function:

◆ mg_lwip_if_can_send()

static int mg_lwip_if_can_send ( struct mg_connection nc,
struct mg_lwip_conn_state cs 
)
static

Definition at line 15942 of file mongoose616.cxx.

15943 {
15944 int can_send = 0;
15945 if (nc->send_mbuf.len > 0 || (nc->flags & MG_F_WANT_WRITE)) {
15946 /* We have stuff to send, but can we? */
15947 if (nc->flags & MG_F_UDP) {
15948 /* UDP is always ready for sending. */
15949 can_send = (cs->pcb.udp != NULL);
15950 } else {
15951 can_send = (cs->pcb.tcp != NULL && cs->pcb.tcp->snd_buf > 0);
15952/* See comment above. */
15953#if CS_PLATFORM == CS_P_ESP8266
15954 if (cs->pcb.tcp->unacked != NULL) can_send = 0;
15955#endif
15956 }
15957 }
15958 return can_send;
15959}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_lwip_if_connect_tcp()

void mg_lwip_if_connect_tcp ( struct mg_connection nc,
const union socket_address sa 
)

Definition at line 15628 of file mongoose616.cxx.

15629 {
15630 struct mg_lwip_if_connect_tcp_ctx ctx = {.nc = nc, .sa = sa};
15632}
Here is the call graph for this function:

◆ mg_lwip_if_connect_tcp_tcpip()

static void mg_lwip_if_connect_tcp_tcpip ( void arg)
static

Definition at line 15599 of file mongoose616.cxx.

15599 {
15600 struct mg_lwip_if_connect_tcp_ctx *ctx =
15601 (struct mg_lwip_if_connect_tcp_ctx *) arg;
15602 struct mg_connection *nc = ctx->nc;
15603 const union socket_address *sa = ctx->sa;
15604
15605 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15606 struct tcp_pcb *tpcb = TCP_NEW();
15607 cs->pcb.tcp = tpcb;
15608 ip_addr_t *ip = (ip_addr_t *) &sa->sin.sin_addr.s_addr;
15609 u16_t port = ntohs(sa->sin.sin_port);
15610 tcp_arg(tpcb, nc);
15613 tcp_recv(tpcb, mg_lwip_tcp_recv_cb);
15614 cs->err = TCP_BIND(tpcb, IP_ADDR_ANY, 0 /* any port */);
15615 DBG(("%p tcp_bind = %d", nc, cs->err));
15616 if (cs->err != ERR_OK) {
15618 return;
15619 }
15620 cs->err = tcp_connect(tpcb, ip, port, mg_lwip_tcp_conn_cb);
15621 DBG(("%p tcp_connect %p = %d", nc, tpcb, cs->err));
15622 if (cs->err != ERR_OK) {
15624 return;
15625 }
15626}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_lwip_if_connect_udp()

void mg_lwip_if_connect_udp ( struct mg_connection nc)

Definition at line 15723 of file mongoose616.cxx.

Here is the call graph for this function:

◆ mg_lwip_if_connect_udp_tcpip()

static void mg_lwip_if_connect_udp_tcpip ( void arg)
static

Definition at line 15708 of file mongoose616.cxx.

15708 {
15709 struct mg_connection *nc = (struct mg_connection *) arg;
15710 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15711 struct udp_pcb *upcb = udp_new();
15712 cs->err = UDP_BIND(upcb, IP_ADDR_ANY, 0 /* any port */);
15713 DBG(("%p udp_bind %p = %d", nc, upcb, cs->err));
15714 if (cs->err == ERR_OK) {
15715 udp_recv(upcb, mg_lwip_udp_recv_cb, nc);
15716 cs->pcb.udp = upcb;
15717 } else {
15718 udp_remove(upcb);
15719 }
15721}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_lwip_if_create_conn()

int mg_lwip_if_create_conn ( struct mg_connection nc)

Definition at line 16002 of file mongoose616.cxx.

16002 {
16003 struct mg_lwip_conn_state *cs =
16004 (struct mg_lwip_conn_state *) MG_CALLOC(1, sizeof(*cs));
16005 if (cs == NULL) return 0;
16006 cs->nc = nc;
16007 nc->sock = (intptr_t) cs;
16008 return 1;
16009}
Here is the call graph for this function:

◆ mg_lwip_if_destroy_conn()

void mg_lwip_if_destroy_conn ( struct mg_connection nc)

Definition at line 16015 of file mongoose616.cxx.

16015 {
16016 if (nc->sock == INVALID_SOCKET) return;
16017 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
16018 if (!(nc->flags & MG_F_UDP)) {
16019 struct tcp_pcb *tpcb = cs->pcb.tcp;
16020 if (tpcb != NULL) {
16021 tcp_arg(tpcb, NULL);
16022 DBG(("%p tcp_close %p", nc, tpcb));
16023 tcp_arg(tpcb, NULL);
16025 }
16026 while (cs->rx_chain != NULL) {
16027 struct pbuf *seg = cs->rx_chain;
16028 cs->rx_chain = pbuf_dechain(cs->rx_chain);
16029 pbuf_free(seg);
16030 }
16031 memset(cs, 0, sizeof(*cs));
16032 MG_FREE(cs);
16033 } else if (nc->listener == NULL) {
16034 /* Only close outgoing UDP pcb or listeners. */
16035 struct udp_pcb *upcb = cs->pcb.udp;
16036 if (upcb != NULL) {
16037 DBG(("%p udp_remove %p", nc, upcb));
16039 }
16040 memset(cs, 0, sizeof(*cs));
16041 MG_FREE(cs);
16042 }
16043 nc->sock = INVALID_SOCKET;
16044}
Here is the call graph for this function:

◆ mg_lwip_if_free()

void mg_lwip_if_free ( struct mg_iface iface)

Definition at line 16205 of file mongoose616.cxx.

16205 {
16206 MG_FREE(iface->data);
16207 iface->data = NULL;
16208}
Here is the call graph for this function:

◆ mg_lwip_if_get_conn_addr()

void mg_lwip_if_get_conn_addr ( struct mg_connection nc,
int  remote,
union socket_address sa 
)

Definition at line 16046 of file mongoose616.cxx.

16047 {
16048 memset(sa, 0, sizeof(*sa));
16049 if (nc == NULL || nc->sock == INVALID_SOCKET) return;
16050 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
16051 if (nc->flags & MG_F_UDP) {
16052 struct udp_pcb *upcb = cs->pcb.udp;
16053 if (remote) {
16054 memcpy(sa, &nc->sa, sizeof(*sa));
16055 } else if (upcb != NULL) {
16056 sa->sin.sin_port = htons(upcb->local_port);
16057 SET_ADDR(sa, &upcb->local_ip);
16058 }
16059 } else {
16060 struct tcp_pcb *tpcb = cs->pcb.tcp;
16061 if (remote) {
16062 memcpy(sa, &nc->sa, sizeof(*sa));
16063 } else if (tpcb != NULL) {
16064 sa->sin.sin_port = htons(tpcb->local_port);
16065 SET_ADDR(sa, &tpcb->local_ip);
16066 }
16067 }
16068}
Here is the call graph for this function:

◆ mg_lwip_if_init()

void mg_lwip_if_init ( struct mg_iface iface)

Definition at line 16195 of file mongoose616.cxx.

16195 {
16196 LOG(LL_INFO, ("Mongoose %s, LwIP %u.%u.%u", MG_VERSION, LWIP_VERSION_MAJOR,
16198 iface->data = MG_CALLOC(1, sizeof(struct mg_ev_mgr_lwip_data));
16199#if !NO_SYS && !LWIP_TCPIP_CORE_LOCKING
16202#endif
16203}
Here is the call graph for this function:

◆ mg_lwip_if_listen_tcp()

int mg_lwip_if_listen_tcp ( struct mg_connection nc,
union socket_address sa 
)

Definition at line 15808 of file mongoose616.cxx.

15808 {
15809 struct mg_lwip_if_listen_ctx ctx = {.nc = nc, .sa = sa};
15811 return ctx.ret;
15812}
Here is the call graph for this function:

◆ mg_lwip_if_listen_tcp_tcpip()

static void mg_lwip_if_listen_tcp_tcpip ( void arg)
static

Definition at line 15786 of file mongoose616.cxx.

15786 {
15787 struct mg_lwip_if_listen_ctx *ctx = (struct mg_lwip_if_listen_ctx *) arg;
15788 struct mg_connection *nc = ctx->nc;
15789 union socket_address *sa = ctx->sa;
15790 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15791 struct tcp_pcb *tpcb = TCP_NEW();
15792 ip_addr_t *ip = (ip_addr_t *) &sa->sin.sin_addr.s_addr;
15793 u16_t port = ntohs(sa->sin.sin_port);
15794 cs->err = TCP_BIND(tpcb, ip, port);
15795 DBG(("%p tcp_bind(%s:%u) = %d", nc, IPADDR_NTOA(ip), port, cs->err));
15796 if (cs->err != ERR_OK) {
15797 tcp_close(tpcb);
15798 ctx->ret = -1;
15799 return;
15800 }
15801 tcp_arg(tpcb, nc);
15802 tpcb = tcp_listen(tpcb);
15803 cs->pcb.tcp = tpcb;
15805 ctx->ret = 0;
15806}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_lwip_if_listen_udp()

int mg_lwip_if_listen_udp ( struct mg_connection nc,
union socket_address sa 
)

Definition at line 15834 of file mongoose616.cxx.

15834 {
15835 struct mg_lwip_if_listen_ctx ctx = {.nc = nc, .sa = sa};
15837 return ctx.ret;
15838}
Here is the call graph for this function:

◆ mg_lwip_if_listen_udp_tcpip()

static void mg_lwip_if_listen_udp_tcpip ( void arg)
static

Definition at line 15814 of file mongoose616.cxx.

15814 {
15815 struct mg_lwip_if_listen_ctx *ctx = (struct mg_lwip_if_listen_ctx *) arg;
15816 struct mg_connection *nc = ctx->nc;
15817 union socket_address *sa = ctx->sa;
15818 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15819 struct udp_pcb *upcb = udp_new();
15820 ip_addr_t *ip = (ip_addr_t *) &sa->sin.sin_addr.s_addr;
15821 u16_t port = ntohs(sa->sin.sin_port);
15822 cs->err = UDP_BIND(upcb, ip, port);
15823 DBG(("%p udb_bind(%s:%u) = %d", nc, IPADDR_NTOA(ip), port, cs->err));
15824 if (cs->err != ERR_OK) {
15825 udp_remove(upcb);
15826 ctx->ret = -1;
15827 } else {
15828 udp_recv(upcb, mg_lwip_udp_recv_cb, nc);
15829 cs->pcb.udp = upcb;
15830 ctx->ret = 0;
15831 }
15832}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_lwip_if_poll()

time_t mg_lwip_if_poll ( struct mg_iface iface,
int  timeout_ms 
)

Definition at line 16225 of file mongoose616.cxx.

16225 {
16226 struct mg_mgr *mgr = iface->mgr;
16227 int n = 0;
16228 double now = mg_time();
16229 struct mg_connection *nc, *tmp;
16230 double min_timer = 0;
16231 int num_timers = 0;
16232#if 0
16233 DBG(("begin poll @%u", (unsigned int) (now * 1000)));
16234#endif
16236 for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
16237 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
16238 tmp = nc->next;
16239 n++;
16240 if (!mg_if_poll(nc, now)) continue;
16241 if (nc->sock != INVALID_SOCKET &&
16242 !(nc->flags & (MG_F_UDP | MG_F_LISTENING)) && cs->pcb.tcp != NULL &&
16243 cs->pcb.tcp->unsent != NULL) {
16245 }
16246 if (nc->ev_timer_time > 0) {
16247 if (num_timers == 0 || nc->ev_timer_time < min_timer) {
16249 }
16250 num_timers++;
16251 }
16252
16253 if (nc->sock != INVALID_SOCKET) {
16254 if (mg_lwip_if_can_send(nc, cs)) {
16257 }
16258 if (cs->rx_chain != NULL) {
16260 } else if (cs->draining_rx_chain) {
16261 /*
16262 * If the connection is about to close, and rx_chain is finally empty,
16263 * send the MG_SIG_CLOSE_CONN signal
16264 */
16266 }
16267 }
16268 }
16269#if 0
16270 DBG(("end poll @%u, %d conns, %d timers (min %u), next in %d ms",
16271 (unsigned int) (now * 1000), n, num_timers,
16272 (unsigned int) (min_timer * 1000), timeout_ms));
16273#endif
16274 (void) timeout_ms;
16275 return now;
16276}
Here is the call graph for this function:

◆ mg_lwip_if_remove_conn()

void mg_lwip_if_remove_conn ( struct mg_connection nc)

Definition at line 16214 of file mongoose616.cxx.

16214 {
16215 struct mg_ev_mgr_lwip_data *md =
16216 (struct mg_ev_mgr_lwip_data *) nc->iface->data;
16217 /* Walk the queue and null-out further signals for this conn. */
16218 for (int i = 0; i < MG_SIG_QUEUE_LEN; i++) {
16219 if (md->sig_queue[i].nc == nc) {
16220 md->sig_queue[i].sig = MG_SIG_TOMBSTONE;
16221 }
16222 }
16223}
Here is the call graph for this function:

◆ mg_lwip_if_sock_set()

void mg_lwip_if_sock_set ( struct mg_connection nc,
sock_t  sock 
)

Definition at line 16070 of file mongoose616.cxx.

16070 {
16071 nc->sock = sock;
16072}

◆ mg_lwip_if_tcp_recv()

static int mg_lwip_if_tcp_recv ( struct mg_connection nc,
void buf,
size_t  len 
)
static

Definition at line 15971 of file mongoose616.cxx.

15972 {
15973 int res = 0;
15974 char *bufp = buf;
15975 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15976 if (nc->sock == INVALID_SOCKET) return -1;
15977 mgos_lock();
15978 while (cs->rx_chain != NULL && len > 0) {
15979 struct pbuf *seg = cs->rx_chain;
15980 size_t seg_len = (seg->len - cs->rx_offset);
15981 size_t copy_len = MIN(len, seg_len);
15982
15983 pbuf_copy_partial(seg, bufp, copy_len, cs->rx_offset);
15984 len -= copy_len;
15985 res += copy_len;
15986 bufp += copy_len;
15987 cs->rx_offset += copy_len;
15988 if (cs->rx_offset == cs->rx_chain->len) {
15989 cs->rx_chain = pbuf_dechain(cs->rx_chain);
15990 pbuf_free(seg);
15991 cs->rx_offset = 0;
15992 }
15993 }
15994 mgos_unlock();
15995 if (res > 0) {
15996 struct tcp_recved_ctx ctx = {.tpcb = cs->pcb.tcp, .len = res};
15998 }
15999 return res;
16000}
Here is the call graph for this function:

◆ mg_lwip_if_tcp_send()

int mg_lwip_if_tcp_send ( struct mg_connection nc,
const void buf,
size_t  len 
)

Definition at line 15897 of file mongoose616.cxx.

15897 {
15898 struct mg_lwip_tcp_write_ctx ctx = {.nc = nc, .data = buf, .len = len};
15899 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15900 if (nc->sock == INVALID_SOCKET) return -1;
15901 struct tcp_pcb *tpcb = cs->pcb.tcp;
15902 if (tpcb == NULL) return -1;
15903 if (tpcb->snd_buf <= 0) return 0;
15905 return ctx.ret;
15906}
Here is the call graph for this function:

◆ mg_lwip_if_udp_recv()

static int mg_lwip_if_udp_recv ( struct mg_connection nc,
void buf,
size_t  len,
union socket_address sa,
size_t sa_len 
)
static

Definition at line 15684 of file mongoose616.cxx.

15685 {
15686 /*
15687 * For UDP, RX chain consists of interleaved address and packet bufs:
15688 * Address pbuf followed by exactly one data pbuf (recv_cb took care of that).
15689 */
15690 int res = 0;
15691 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15692 if (nc->sock == INVALID_SOCKET) return -1;
15693 mgos_lock();
15694 if (cs->rx_chain != NULL) {
15695 struct pbuf *ap = cs->rx_chain;
15696 struct pbuf *dp = ap->next;
15697 cs->rx_chain = pbuf_dechain(dp);
15698 res = MIN(dp->len, len);
15699 pbuf_copy_partial(dp, buf, res, 0);
15700 pbuf_free(dp);
15701 pbuf_copy_partial(ap, sa, MIN(*sa_len, ap->len), 0);
15702 pbuf_free(ap);
15703 }
15704 mgos_unlock();
15705 return res;
15706}
Here is the call graph for this function:

◆ mg_lwip_if_udp_send()

static int mg_lwip_if_udp_send ( struct mg_connection nc,
const void data,
size_t  len 
)
static

Definition at line 15921 of file mongoose616.cxx.

15922 {
15923 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15924 if (nc->sock == INVALID_SOCKET || cs->pcb.udp == NULL) return -1;
15925 struct udp_pcb *upcb = cs->pcb.udp;
15926 struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
15927#if defined(LWIP_IPV4) && LWIP_IPV4 && defined(LWIP_IPV6) && LWIP_IPV6
15928 ip_addr_t ip = {.u_addr.ip4.addr = nc->sa.sin.sin_addr.s_addr, .type = 0};
15929#else
15930 ip_addr_t ip = {.addr = nc->sa.sin.sin_addr.s_addr};
15931#endif
15932 u16_t port = ntohs(nc->sa.sin.sin_port);
15933 if (p == NULL) return 0;
15934 memcpy(p->payload, data, len);
15935 struct udp_sendto_ctx ctx = {.upcb = upcb, .p = p, .ip = &ip, .port = port};
15937 cs->err = ctx.ret;
15938 pbuf_free(p);
15939 return (cs->err == ERR_OK ? (int) len : -2);
15940}
Here is the call graph for this function:

◆ mg_lwip_mgr_schedule_poll()

void mg_lwip_mgr_schedule_poll ( struct mg_mgr mgr)
Here is the caller graph for this function:

◆ mg_lwip_netif_run_on_tcpip()

void mg_lwip_netif_run_on_tcpip ( void(*)(void *)  fn,
void arg 
)

Definition at line 15444 of file mongoose616.cxx.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_lwip_post_signal()

void mg_lwip_post_signal ( enum mg_sig_type  sig,
struct mg_connection nc 
)

Definition at line 16140 of file mongoose616.cxx.

16140 {
16141 struct mg_ev_mgr_lwip_data *md =
16142 (struct mg_ev_mgr_lwip_data *) nc->iface->data;
16143 mgos_lock();
16144 if (md->sig_queue_len >= MG_SIG_QUEUE_LEN) {
16145 mgos_unlock();
16146 return;
16147 }
16148 int end_index = (md->start_index + md->sig_queue_len) % MG_SIG_QUEUE_LEN;
16149 md->sig_queue[end_index].sig = sig;
16150 md->sig_queue[end_index].nc = nc;
16151 md->sig_queue_len++;
16153 mgos_unlock();
16154}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_lwip_recv_common()

static void mg_lwip_recv_common ( struct mg_connection nc,
struct pbuf p 
)
static

Definition at line 15671 of file mongoose616.cxx.

15671 {
15672 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15673 if (cs->rx_chain == NULL) {
15674 cs->rx_chain = p;
15675 } else {
15676 pbuf_chain(cs->rx_chain, p);
15677 }
15678 if (!cs->recv_pending) {
15679 cs->recv_pending = 1;
15681 }
15682}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_lwip_tcp_conn_cb()

static err_t mg_lwip_tcp_conn_cb ( void arg,
struct tcp_pcb tpcb,
err_t  err 
)
static

Definition at line 15493 of file mongoose616.cxx.

15493 {
15494 struct mg_connection *nc = (struct mg_connection *) arg;
15495 DBG(("%p connect to %s:%u = %d", nc, IPADDR_NTOA(ipX_2_ip(&tpcb->remote_ip)),
15496 tpcb->remote_port, err));
15497 if (nc == NULL) {
15498 tcp_abort(tpcb);
15499 return ERR_ARG;
15500 }
15501 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15502 cs->err = err;
15503#if LWIP_TCP_KEEPALIVE
15504 if (err == 0) mg_lwip_set_keepalive_params(nc, 60, 10, 6);
15505#endif
15507 return ERR_OK;
15508}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_lwip_tcp_error_cb()

static void mg_lwip_tcp_error_cb ( void arg,
err_t  err 
)
static

Definition at line 15510 of file mongoose616.cxx.

15510 {
15511 struct mg_connection *nc = (struct mg_connection *) arg;
15512 DBG(("%p conn error %d", nc, err));
15513 if (nc == NULL || (nc->flags & MG_F_CLOSE_IMMEDIATELY)) return;
15514 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15515 cs->pcb.tcp = NULL; /* Has already been deallocated */
15516 if (nc->flags & MG_F_CONNECTING) {
15517 cs->err = err;
15519 } else {
15521 }
15522}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_lwip_tcp_recv_cb()

static err_t mg_lwip_tcp_recv_cb ( void arg,
struct tcp_pcb tpcb,
struct pbuf p,
err_t  err 
)
static

Definition at line 15524 of file mongoose616.cxx.

15525 {
15526 struct mg_connection *nc = (struct mg_connection *) arg;
15527 struct mg_lwip_conn_state *cs =
15528 (nc ? (struct mg_lwip_conn_state *) nc->sock : NULL);
15529 DBG(("%p %p %p %p %u %d", nc, cs, tpcb, p, (p != NULL ? p->tot_len : 0),
15530 err));
15531 if (p == NULL) {
15532 if (nc != NULL && !(nc->flags & MG_F_CLOSE_IMMEDIATELY)) {
15533 if (cs->rx_chain != NULL) {
15534 /*
15535 * rx_chain still contains non-consumed data, don't close the
15536 * connection
15537 */
15538 cs->draining_rx_chain = 1;
15539 } else {
15541 }
15542 } else {
15543 /* Tombstoned connection, do nothing. */
15544 }
15545 return ERR_OK;
15546 } else if (nc == NULL) {
15547 tcp_abort(tpcb);
15548 return ERR_ARG;
15549 }
15550 /*
15551 * If we get a chain of more than one segment at once, we need to bump
15552 * refcount on the subsequent bufs to make them independent.
15553 */
15554 if (p->next != NULL) {
15555 struct pbuf *q = p->next;
15556 for (; q != NULL; q = q->next) pbuf_ref(q);
15557 }
15558 mgos_lock();
15559 if (cs->rx_chain == NULL) {
15560 cs->rx_offset = 0;
15561 } else if (pbuf_clen(cs->rx_chain) >= 4) {
15562 /* ESP SDK has a limited pool of 5 pbufs. We must not hog them all or RX
15563 * will be completely blocked. We already have at least 4 in the chain,
15564 * this one is the last, so we have to make a copy and release this one. */
15565 struct pbuf *np = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
15566 if (np != NULL) {
15567 pbuf_copy(np, p);
15568 pbuf_free(p);
15569 p = np;
15570 }
15571 }
15572 mg_lwip_recv_common(nc, p);
15573 mgos_unlock();
15574 (void) err;
15575 return ERR_OK;
15576}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_lwip_tcp_sent_cb()

static err_t mg_lwip_tcp_sent_cb ( void arg,
struct tcp_pcb tpcb,
u16_t  num_sent 
)
static

Definition at line 15578 of file mongoose616.cxx.

15579 {
15580 struct mg_connection *nc = (struct mg_connection *) arg;
15581 DBG(("%p %p %u %p %p", nc, tpcb, num_sent, tpcb->unsent, tpcb->unacked));
15582 if (nc == NULL) return ERR_OK;
15583 if ((nc->flags & MG_F_SEND_AND_CLOSE) && !(nc->flags & MG_F_WANT_WRITE) &&
15584 nc->send_mbuf.len == 0 && tpcb->unsent == NULL && tpcb->unacked == NULL) {
15586 }
15587 if (nc->send_mbuf.len > 0 || (nc->flags & MG_F_WANT_WRITE)) {
15589 }
15590 (void) num_sent;
15591 return ERR_OK;
15592}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_lwip_tcp_write_tcpip()

static void mg_lwip_tcp_write_tcpip ( void arg)
static

Definition at line 15851 of file mongoose616.cxx.

15851 {
15852 struct mg_lwip_tcp_write_ctx *ctx = (struct mg_lwip_tcp_write_ctx *) arg;
15853 struct mg_connection *nc = ctx->nc;
15854 struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
15855 struct tcp_pcb *tpcb = cs->pcb.tcp;
15856 size_t len = MIN(tpcb->mss, MIN(ctx->len, tpcb->snd_buf));
15857 size_t unsent, unacked;
15858 if (len == 0) {
15859 DBG(("%p no buf avail %u %u %p %p", tpcb, tpcb->snd_buf, tpcb->snd_queuelen,
15860 tpcb->unsent, tpcb->unacked));
15862 ctx->ret = 0;
15863 return;
15864 }
15865 unsent = (tpcb->unsent != NULL ? tpcb->unsent->len : 0);
15866 unacked = (tpcb->unacked != NULL ? tpcb->unacked->len : 0);
15867/*
15868 * On ESP8266 we only allow one TCP segment in flight at any given time.
15869 * This may increase latency and reduce efficiency of tcp windowing,
15870 * but memory is scarce and precious on that platform so we do this to
15871 * reduce footprint.
15872 */
15873#if CS_PLATFORM == CS_P_ESP8266
15874 if (unacked > 0) {
15875 ctx->ret = 0;
15876 return;
15877 }
15878 len = MIN(len, (TCP_MSS - unsent));
15879#endif
15880 cs->err = tcp_write(tpcb, ctx->data, len, TCP_WRITE_FLAG_COPY);
15881 unsent = (tpcb->unsent != NULL ? tpcb->unsent->len : 0);
15882 unacked = (tpcb->unacked != NULL ? tpcb->unacked->len : 0);
15883 DBG(("%p tcp_write %u = %d, %u %u", tpcb, len, cs->err, unsent, unacked));
15884 if (cs->err != ERR_OK) {
15885 /*
15886 * We ignore ERR_MEM because memory will be freed up when the data is sent
15887 * and we'll retry.
15888 */
15889 ctx->ret = (cs->err == ERR_MEM ? 0 : -1);
15890 return;
15891 }
15892 ctx->ret = len;
15893 (void) unsent;
15894 (void) unacked;
15895}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_lwip_udp_recv_cb()

static void mg_lwip_udp_recv_cb ( void arg,
struct udp_pcb pcb,
struct pbuf p,
ip_addr_t addr,
u16_t  port 
)
static

Definition at line 15642 of file mongoose616.cxx.

15645{
15646 struct mg_connection *nc = (struct mg_connection *) arg;
15647 DBG(("%p %s:%u %p %u %u", nc, IPADDR_NTOA(addr), port, p, p->ref, p->len));
15648 /* Put address in a separate pbuf and tack it onto the packet. */
15649 struct pbuf *sap =
15650 pbuf_alloc(PBUF_RAW, sizeof(union socket_address), PBUF_RAM);
15651 if (sap == NULL) {
15652 pbuf_free(p);
15653 return;
15654 }
15655 union socket_address *sa = (union socket_address *) sap->payload;
15656#if ((LWIP_VERSION_MAJOR << 8) | LWIP_VERSION_MINOR) >= 0x0105
15657 sa->sin.sin_addr.s_addr = ip_2_ip4(addr)->addr;
15658#else
15659 sa->sin.sin_addr.s_addr = addr->addr;
15660#endif
15661 sa->sin.sin_port = htons(port);
15662 /* Logic in the recv handler requires that there be exactly one data pbuf. */
15663 p = pbuf_coalesce(p, PBUF_RAW);
15664 pbuf_chain(sap, p);
15665 mgos_lock();
15667 mgos_unlock();
15668 (void) pcb;
15669}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_mbuf_append_base64()

void mg_mbuf_append_base64 ( struct mbuf mbuf,
const void data,
size_t  len 
)

Definition at line 10909 of file mongoose616.cxx.

10909 {
10910 struct cs_base64_ctx ctx;
10912 cs_base64_update(&ctx, (const char *) data, len);
10913 cs_base64_finish(&ctx);
10914}
Here is the call graph for this function:

◆ mg_mbuf_append_base64_putc()

void mg_mbuf_append_base64_putc ( char  ch,
void user_data 
)

Definition at line 10904 of file mongoose616.cxx.

10904 {
10905 struct mbuf *mbuf = (struct mbuf *) user_data;
10906 mbuf_append(mbuf, &ch, sizeof(ch));
10907}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_mgr_handle_conn()

void mg_mgr_handle_conn ( struct mg_connection nc,
int  fd_flags,
double  now 
)

Definition at line 4053 of file mongoose616.cxx.

4053 {
4054 int worth_logging =
4055 fd_flags != 0 || (nc->flags & (MG_F_WANT_READ | MG_F_WANT_WRITE));
4056 if (worth_logging) {
4057 DBG(("%p fd=%d fd_flags=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock,
4058 fd_flags, nc->flags, (int) nc->recv_mbuf.len,
4059 (int) nc->send_mbuf.len));
4060 }
4061
4062 if (!mg_if_poll(nc, now)) return;
4063
4064 if (nc->flags & MG_F_CONNECTING) {
4065 if (fd_flags != 0) {
4066 int err = 0;
4067#if !defined(MG_ESP8266)
4068 if (!(nc->flags & MG_F_UDP)) {
4069 socklen_t len = sizeof(err);
4070 int ret =
4071 getsockopt(nc->sock, SOL_SOCKET, SO_ERROR, (char *) &err, &len);
4072 if (ret != 0) {
4073 err = 1;
4074 } else if (err == EAGAIN || err == EWOULDBLOCK) {
4075 err = 0;
4076 }
4077 }
4078#else
4079 /*
4080 * On ESP8266 we use blocking connect.
4081 */
4082 err = nc->err;
4083#endif
4084 mg_if_connect_cb(nc, err);
4085 } else if (nc->err != 0) {
4086 mg_if_connect_cb(nc, nc->err);
4087 }
4088 }
4089
4091 if (nc->flags & MG_F_UDP) {
4093 } else {
4094 if (nc->flags & MG_F_LISTENING) {
4095 /*
4096 * We're not looping here, and accepting just one connection at
4097 * a time. The reason is that eCos does not respect non-blocking
4098 * flag on a listening socket and hangs in a loop.
4099 */
4100 mg_accept_conn(nc);
4101 } else {
4103 }
4104 }
4105 }
4106
4108
4109 if (worth_logging) {
4110 DBG(("%p after fd=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock,
4111 nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
4112 }
4113}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_mgr_init_opt()

void mg_mgr_init_opt ( struct mg_mgr m,
void user_data,
struct mg_mgr_init_opts  opts 
)

Definition at line 2582 of file mongoose616.cxx.

2583 {
2584 memset(m, 0, sizeof(*m));
2585#if MG_ENABLE_BROADCAST
2586 m->ctl[0] = m->ctl[1] = INVALID_SOCKET;
2587#endif
2588 m->user_data = user_data;
2589
2590#ifdef _WIN32
2591 {
2592 WSADATA data;
2593 WSAStartup(MAKEWORD(2, 2), &data);
2594 }
2595#elif defined(__unix__)
2596 /* Ignore SIGPIPE signal, so if client cancels the request, it
2597 * won't kill the whole process. */
2599#endif
2600
2601 {
2602 int i;
2603 if (opts.num_ifaces == 0) {
2604 opts.num_ifaces = mg_num_ifaces;
2605 opts.ifaces = mg_ifaces;
2606 }
2607 if (opts.main_iface != NULL) {
2608 opts.ifaces[MG_MAIN_IFACE] = opts.main_iface;
2609 }
2610 m->num_ifaces = opts.num_ifaces;
2611 m->ifaces =
2612 (struct mg_iface **) MG_MALLOC(sizeof(*m->ifaces) * opts.num_ifaces);
2613 for (i = 0; i < opts.num_ifaces; i++) {
2614 m->ifaces[i] = mg_if_create_iface(opts.ifaces[i], m);
2615 m->ifaces[i]->vtable->init(m->ifaces[i]);
2616 }
2617 }
2618 if (opts.nameserver != NULL) {
2619 m->nameserver = strdup(opts.nameserver);
2620 }
2621 DBG(("=================================="));
2622 DBG(("init mgr=%p", m));
2623#if MG_ENABLE_SSL
2624 {
2625 static int init_done;
2626 if (!init_done) {
2628 init_done++;
2629 }
2630 }
2631#endif
2632}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_mgr_min_timer()

double mg_mgr_min_timer ( const struct mg_mgr mgr)

Definition at line 3679 of file mongoose616.cxx.

3679 {
3680 double min_timer = 0;
3681 struct mg_connection *nc;
3682 for (nc = mgr->active_connections; nc != NULL; nc = nc->next) {
3683 if (nc->ev_timer_time <= 0) continue;
3684 if (min_timer == 0 || nc->ev_timer_time < min_timer) {
3686 }
3687 }
3688 return min_timer;
3689}
Here is the call graph for this function:

◆ mg_mk_str_n()

struct mg_str mg_mk_str_n ( const char s,
size_t  len 
)

Definition at line 1706 of file mongoose616.cxx.

1706 {
1707 struct mg_str ret = {s, len};
1708 return ret;
1709}
Here is the caller graph for this function:

◆ mg_next_comma_list_entry_n()

struct mg_str mg_next_comma_list_entry_n ( struct mg_str  list,
struct mg_str val,
struct mg_str eq_val 
)

Definition at line 2276 of file mongoose616.cxx.

2277 {
2278 if (list.len == 0) {
2279 /* End of the list */
2280 list = mg_mk_str(NULL);
2281 } else {
2282 const char *chr = NULL;
2283 *val = list;
2284
2285 if ((chr = mg_strchr(*val, ',')) != NULL) {
2286 /* Comma found. Store length and shift the list ptr */
2287 val->len = chr - val->p;
2288 chr++;
2289 list.len -= (chr - list.p);
2290 list.p = chr;
2291 } else {
2292 /* This value is the last one */
2293 list = mg_mk_str_n(list.p + list.len, 0);
2294 }
2295
2296 if (eq_val != NULL) {
2297 /* Value has form "x=y", adjust pointers and lengths */
2298 /* so that val points to "x", and eq_val points to "y". */
2299 eq_val->len = 0;
2300 eq_val->p = (const char *) memchr(val->p, '=', val->len);
2301 if (eq_val->p != NULL) {
2302 eq_val->p++; /* Skip over '=' character */
2303 eq_val->len = val->p + val->len - eq_val->p;
2304 val->len = (eq_val->p - val->p) - 1;
2305 }
2306 }
2307 }
2308
2309 return list;
2310}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_null_if_add_conn()

static void mg_null_if_add_conn ( struct mg_connection c)
static

Definition at line 3790 of file mongoose616.cxx.

3790 {
3791 c->sock = INVALID_SOCKET;
3792 c->flags |= MG_F_CLOSE_IMMEDIATELY;
3793}

◆ mg_null_if_connect_tcp()

static void mg_null_if_connect_tcp ( struct mg_connection c,
const union socket_address sa 
)
static

Definition at line 3711 of file mongoose616.cxx.

3712 {
3713 c->flags |= MG_F_CLOSE_IMMEDIATELY;
3714 (void) sa;
3715}
Here is the call graph for this function:

◆ mg_null_if_connect_udp()

static void mg_null_if_connect_udp ( struct mg_connection c)
static

Definition at line 3717 of file mongoose616.cxx.

3717 {
3718 c->flags |= MG_F_CLOSE_IMMEDIATELY;
3719}

◆ mg_null_if_create_conn()

static int mg_null_if_create_conn ( struct mg_connection c)
static

Definition at line 3768 of file mongoose616.cxx.

3768 {
3769 (void) c;
3770 return 1;
3771}
Here is the call graph for this function:

◆ mg_null_if_destroy_conn()

static void mg_null_if_destroy_conn ( struct mg_connection c)
static

Definition at line 3773 of file mongoose616.cxx.

3773 {
3774 (void) c;
3775}
Here is the call graph for this function:

◆ mg_null_if_free()

static void mg_null_if_free ( struct mg_iface iface)
static

Definition at line 3786 of file mongoose616.cxx.

3786 {
3787 (void) iface;
3788}
Here is the call graph for this function:

◆ mg_null_if_get_conn_addr()

static void mg_null_if_get_conn_addr ( struct mg_connection c,
int  remote,
union socket_address sa 
)
static

Definition at line 3812 of file mongoose616.cxx.

3813 {
3814 (void) c;
3815 (void) remote;
3816 (void) sa;
3817}
Here is the call graph for this function:

◆ mg_null_if_init()

static void mg_null_if_init ( struct mg_iface iface)
static

Definition at line 3782 of file mongoose616.cxx.

3782 {
3783 (void) iface;
3784}
Here is the call graph for this function:

◆ mg_null_if_listen_tcp()

static int mg_null_if_listen_tcp ( struct mg_connection c,
union socket_address sa 
)
static

Definition at line 3721 of file mongoose616.cxx.

3722 {
3723 (void) c;
3724 (void) sa;
3725 return -1;
3726}
Here is the call graph for this function:

◆ mg_null_if_listen_udp()

static int mg_null_if_listen_udp ( struct mg_connection c,
union socket_address sa 
)
static

Definition at line 3728 of file mongoose616.cxx.

3729 {
3730 (void) c;
3731 (void) sa;
3732 return -1;
3733}
Here is the call graph for this function:

◆ mg_null_if_poll()

static time_t mg_null_if_poll ( struct mg_iface iface,
int  timeout_ms 
)
static

Definition at line 3799 of file mongoose616.cxx.

3799 {
3800 struct mg_mgr *mgr = iface->mgr;
3801 struct mg_connection *nc, *tmp;
3802 double now = mg_time();
3803 /* We basically just run timers and poll. */
3804 for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
3805 tmp = nc->next;
3806 mg_if_poll(nc, now);
3807 }
3808 (void) timeout_ms;
3809 return (time_t) now;
3810}
Here is the call graph for this function:

◆ mg_null_if_remove_conn()

static void mg_null_if_remove_conn ( struct mg_connection c)
static

Definition at line 3795 of file mongoose616.cxx.

3795 {
3796 (void) c;
3797}
Here is the call graph for this function:

◆ mg_null_if_sock_set()

static void mg_null_if_sock_set ( struct mg_connection c,
sock_t  sock 
)
static

Definition at line 3777 of file mongoose616.cxx.

3777 {
3778 (void) c;
3779 (void) sock;
3780}
Here is the call graph for this function:

◆ mg_null_if_tcp_recv()

int mg_null_if_tcp_recv ( struct mg_connection c,
void buf,
size_t  len 
)

Definition at line 3751 of file mongoose616.cxx.

3751 {
3752 (void) c;
3753 (void) buf;
3754 (void) len;
3755 return -1;
3756}
Here is the call graph for this function:

◆ mg_null_if_tcp_send()

static int mg_null_if_tcp_send ( struct mg_connection c,
const void buf,
size_t  len 
)
static

Definition at line 3735 of file mongoose616.cxx.

3736 {
3737 (void) c;
3738 (void) buf;
3739 (void) len;
3740 return -1;
3741}
Here is the call graph for this function:

◆ mg_null_if_udp_recv()

int mg_null_if_udp_recv ( struct mg_connection c,
void buf,
size_t  len,
union socket_address sa,
size_t sa_len 
)

Definition at line 3758 of file mongoose616.cxx.

3759 {
3760 (void) c;
3761 (void) buf;
3762 (void) len;
3763 (void) sa;
3764 (void) sa_len;
3765 return -1;
3766}
Here is the call graph for this function:

◆ mg_null_if_udp_send()

static int mg_null_if_udp_send ( struct mg_connection c,
const void buf,
size_t  len 
)
static

Definition at line 3743 of file mongoose616.cxx.

3744 {
3745 (void) c;
3746 (void) buf;
3747 (void) len;
3748 return -1;
3749}
Here is the call graph for this function:

◆ mg_open_listening_socket() [1/2]

static sock_t mg_open_listening_socket ( struct mg_connection nc,
union socket_address sa,
int  type,
int  proto 
)
static

Definition at line 14766 of file mongoose616.cxx.

14768 {
14769 int r;
14771 (sa->sa.sa_family == AF_INET) ? sizeof(sa->sin) : sizeof(sa->sin6);
14772 sock_t sock = sl_Socket(sa->sa.sa_family, type, proto);
14773 if (sock < 0) return sock;
14774#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
14775 if ((r = sl_set_ssl_opts(sock, nc)) < 0) goto clean;
14776#endif
14777 if ((r = sl_Bind(sock, &sa->sa, sa_len)) < 0) goto clean;
14778 if (type != SOCK_DGRAM) {
14779 if ((r = sl_Listen(sock, SOMAXCONN)) < 0) goto clean;
14780 }
14782clean:
14783 if (r < 0) {
14784 sl_Close(sock);
14785 sock = r;
14786 }
14787 return sock;
14788}
Here is the call graph for this function:

◆ mg_open_listening_socket() [2/2]

static sock_t mg_open_listening_socket ( union socket_address sa,
int  type,
int  proto 
)
static

Definition at line 4003 of file mongoose616.cxx.

4004 {
4006 (sa->sa.sa_family == AF_INET) ? sizeof(sa->sin) : sizeof(sa->sin6);
4007 sock_t sock = INVALID_SOCKET;
4008#if !MG_LWIP
4009 int on = 1;
4010#endif
4011
4012 if ((sock = socket(sa->sa.sa_family, type, proto)) != INVALID_SOCKET &&
4013#if !MG_LWIP /* LWIP doesn't support either */
4015 /* "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE" http://goo.gl/RmrFTm */
4016 !setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &on,
4017 sizeof(on)) &&
4018#endif
4019
4020#if !defined(_WIN32) || !defined(SO_EXCLUSIVEADDRUSE)
4021 /*
4022 * SO_RESUSEADDR is not enabled on Windows because the semantics of
4023 * SO_REUSEADDR on UNIX and Windows is different. On Windows,
4024 * SO_REUSEADDR allows to bind a socket to a port without error even if
4025 * the port is already open by another program. This is not the behavior
4026 * SO_REUSEADDR was designed for, and leads to hard-to-track failure
4027 * scenarios. Therefore, SO_REUSEADDR was disabled on Windows unless
4028 * SO_EXCLUSIVEADDRUSE is supported and set on a socket.
4029 */
4030 !setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) &&
4031#endif
4032#endif /* !MG_LWIP */
4033
4034 !bind(sock, &sa->sa, sa_len) &&
4035 (type == SOCK_DGRAM || listen(sock, SOMAXCONN) == 0)) {
4036#if !MG_LWIP
4038 /* In case port was set to 0, get the real port number */
4039 (void) getsockname(sock, &sa->sa, &sa_len);
4040#endif
4041 } else if (sock != INVALID_SOCKET) {
4042 closesocket(sock);
4043 sock = INVALID_SOCKET;
4044 }
4045
4046 return sock;
4047}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_parse_address()

MG_INTERNAL int mg_parse_address ( const char str,
union socket_address sa,
int proto,
char host,
size_t  host_len 
)

Definition at line 2793 of file mongoose616.cxx.

2794 {
2795 unsigned int a, b, c, d, port = 0;
2796 int ch, len = 0;
2797#if MG_ENABLE_IPV6
2798 char buf[100];
2799#endif
2800
2801 /*
2802 * MacOS needs that. If we do not zero it, subsequent bind() will fail.
2803 * Also, all-zeroes in the socket address means binding to all addresses
2804 * for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT).
2805 */
2806 memset(sa, 0, sizeof(*sa));
2807 sa->sin.sin_family = AF_INET;
2808
2809 *proto = SOCK_STREAM;
2810
2811 if (strncmp(str, "udp://", 6) == 0) {
2812 str += 6;
2813 *proto = SOCK_DGRAM;
2814 } else if (strncmp(str, "tcp://", 6) == 0) {
2815 str += 6;
2816 }
2817
2818 if (sscanf(str, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len) == 5) {
2819 /* Bind to a specific IPv4 address, e.g. 192.168.1.5:8080 */
2820 sa->sin.sin_addr.s_addr =
2821 htonl(((uint32_t) a << 24) | ((uint32_t) b << 16) | c << 8 | d);
2822 sa->sin.sin_port = htons((uint16_t) port);
2823#if MG_ENABLE_IPV6
2824 } else if (sscanf(str, "[%99[^]]]:%u%n", buf, &port, &len) == 2 &&
2825 inet_pton(AF_INET6, buf, &sa->sin6.sin6_addr)) {
2826 /* IPv6 address, e.g. [3ffe:2a00:100:7031::1]:8080 */
2827 sa->sin6.sin6_family = AF_INET6;
2828 sa->sin.sin_port = htons((uint16_t) port);
2829#endif
2830#if MG_ENABLE_ASYNC_RESOLVER
2831 } else if (strlen(str) < host_len &&
2832 sscanf(str, "%[^ :]:%u%n", host, &port, &len) == 2) {
2833 sa->sin.sin_port = htons((uint16_t) port);
2834 if (mg_resolve_from_hosts_file(host, sa) != 0) {
2835 /*
2836 * if resolving from hosts file failed and the host
2837 * we are trying to resolve is `localhost` - we should
2838 * try to resolve it using `gethostbyname` and do not try
2839 * to resolve it via DNS server if gethostbyname has failed too
2840 */
2841 if (mg_ncasecmp(host, "localhost", 9) != 0) {
2842 return 0;
2843 }
2844
2845#if MG_ENABLE_SYNC_RESOLVER
2846 if (!mg_resolve2(host, &sa->sin.sin_addr)) {
2847 return -1;
2848 }
2849#else
2850 return -1;
2851#endif
2852 }
2853#endif
2854 } else if (sscanf(str, ":%u%n", &port, &len) == 1 ||
2855 sscanf(str, "%u%n", &port, &len) == 1) {
2856 /* If only port is specified, bind to IPv4, INADDR_ANY */
2857 sa->sin.sin_port = htons((uint16_t) port);
2858 } else {
2859 return -1;
2860 }
2861
2862 /* Required for MG_ENABLE_ASYNC_RESOLVER=0 */
2863 (void) host;
2864 (void) host_len;
2865
2866 ch = str[len]; /* Character that follows the address */
2867 return port < 0xffffUL && (ch == '\0' || ch == ',' || isspace(ch)) ? len : -1;
2868}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_pic32_if_add_conn()

void mg_pic32_if_add_conn ( struct mg_connection nc)

Definition at line 16440 of file mongoose616.cxx.

16440 {
16441 (void) nc;
16442}
Here is the call graph for this function:

◆ mg_pic32_if_connect_tcp()

void mg_pic32_if_connect_tcp ( struct mg_connection nc,
const union socket_address sa 
)

Definition at line 16673 of file mongoose616.cxx.

16674 {
16676 sa->sin.sin_family == AF_INET ? IP_ADDRESS_TYPE_IPV4
16678 ntohs(sa->sin.sin_port), (IP_MULTI_ADDRESS *) &sa->sin);
16679 nc->err = (nc->sock == INVALID_SOCKET) ? -1 : 0;
16680}
Here is the call graph for this function:

◆ mg_pic32_if_connect_udp()

void mg_pic32_if_connect_udp ( struct mg_connection nc)

Definition at line 16682 of file mongoose616.cxx.

16682 {
16684 nc->err = (nc->sock == INVALID_SOCKET) ? -1 : 0;
16685}
Here is the call graph for this function:

◆ mg_pic32_if_create_conn()

int mg_pic32_if_create_conn ( struct mg_connection nc)

Definition at line 16430 of file mongoose616.cxx.

16430 {
16431 (void) nc;
16432 return 1;
16433}
Here is the call graph for this function:

◆ mg_pic32_if_destroy_conn()

void mg_pic32_if_destroy_conn ( struct mg_connection nc)

Definition at line 16457 of file mongoose616.cxx.

16457 {
16458 if (nc->sock == INVALID_SOCKET) return;
16459 /* For UDP, only close outgoing sockets or listeners. */
16460 if (!(nc->flags & MG_F_UDP)) {
16461 /* Close TCP */
16463 } else if (nc->listener == NULL) {
16464 /* Only close outgoing UDP or listeners. */
16466 }
16467
16468 nc->sock = INVALID_SOCKET;
16469}
Here is the call graph for this function:

◆ mg_pic32_if_free()

void mg_pic32_if_free ( struct mg_iface iface)

Definition at line 16449 of file mongoose616.cxx.

16449 {
16450 (void) iface;
16451}
Here is the call graph for this function:

◆ mg_pic32_if_get_conn_addr()

void mg_pic32_if_get_conn_addr ( struct mg_connection nc,
int  remote,
union socket_address sa 
)

Definition at line 16668 of file mongoose616.cxx.

16669 {
16670 /* TODO(alaskin): not implemented yet */
16671}

◆ mg_pic32_if_init()

void mg_pic32_if_init ( struct mg_iface iface)

Definition at line 16444 of file mongoose616.cxx.

16444 {
16445 (void) iface;
16446 (void) mg_get_errno(); /* Shutup compiler */
16447}
Here is the call graph for this function:

◆ mg_pic32_if_listen_tcp()

int mg_pic32_if_listen_tcp ( struct mg_connection nc,
union socket_address sa 
)

Definition at line 16493 of file mongoose616.cxx.

16493 {
16495 sa->sin.sin_family == AF_INET ? IP_ADDRESS_TYPE_IPV4
16497 ntohs(sa->sin.sin_port),
16498 sa->sin.sin_addr.s_addr == 0 ? 0 : (IP_MULTI_ADDRESS *) &sa->sin);
16499 memcpy(&nc->sa, sa, sizeof(*sa));
16500 if (nc->sock == INVALID_SOCKET) {
16501 return -1;
16502 }
16503 return 0;
16504}
Here is the call graph for this function:

◆ mg_pic32_if_listen_udp()

int mg_pic32_if_listen_udp ( struct mg_connection nc,
union socket_address sa 
)

Definition at line 16471 of file mongoose616.cxx.

16471 {
16473 sa->sin.sin_family == AF_INET ? IP_ADDRESS_TYPE_IPV4
16475 ntohs(sa->sin.sin_port),
16476 sa->sin.sin_addr.s_addr == 0 ? 0 : (IP_MULTI_ADDRESS *) &sa->sin);
16477 if (nc->sock == INVALID_SOCKET) {
16478 return -1;
16479 }
16480 return 0;
16481}
Here is the call graph for this function:

◆ mg_pic32_if_poll()

time_t mg_pic32_if_poll ( struct mg_iface iface,
int  timeout_ms 
)

Definition at line 16622 of file mongoose616.cxx.

16622 {
16623 struct mg_mgr *mgr = iface->mgr;
16624 double now = mg_time();
16625 struct mg_connection *nc, *tmp;
16626
16627 for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
16628 tmp = nc->next;
16629
16630 if (nc->flags & MG_F_CONNECTING) {
16631 /* processing connections */
16632 if (nc->flags & MG_F_UDP ||
16634 mg_if_connect_cb(nc, 0);
16635 }
16636 } else if (nc->flags & MG_F_LISTENING) {
16638 /* accept new connections */
16639 mg_accept_conn(nc);
16640 }
16641 } else {
16642 if (nc->send_mbuf.len != 0) {
16643 mg_handle_send(nc);
16644 }
16645
16646 if (nc->recv_mbuf_limit == -1 ||
16647 nc->recv_mbuf.len < nc->recv_mbuf_limit) {
16648 mg_handle_recv(nc);
16649 }
16650 }
16651 }
16652
16653 for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
16654 tmp = nc->next;
16655 if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) ||
16656 (nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE))) {
16657 mg_close_conn(nc);
16658 }
16659 }
16660
16661 return now;
16662}
Here is the call graph for this function:

◆ mg_pic32_if_recved()

void mg_pic32_if_recved ( struct mg_connection nc,
size_t  len 
)

Definition at line 16435 of file mongoose616.cxx.

16435 {
16436 (void) nc;
16437 (void) len;
16438}
Here is the call graph for this function:

◆ mg_pic32_if_remove_conn()

void mg_pic32_if_remove_conn ( struct mg_connection nc)

Definition at line 16453 of file mongoose616.cxx.

16453 {
16454 (void) nc;
16455}
Here is the call graph for this function:

◆ mg_pic32_if_sock_set()

void mg_pic32_if_sock_set ( struct mg_connection nc,
sock_t  sock 
)

Definition at line 16664 of file mongoose616.cxx.

16664 {
16665 nc->sock = sock;
16666}

◆ mg_pic32_if_tcp_send()

void mg_pic32_if_tcp_send ( struct mg_connection nc,
const void buf,
size_t  len 
)

Definition at line 16488 of file mongoose616.cxx.

16489 {
16490 mbuf_append(&nc->send_mbuf, buf, len);
16491}
Here is the call graph for this function:

◆ mg_pic32_if_udp_send()

void mg_pic32_if_udp_send ( struct mg_connection nc,
const void buf,
size_t  len 
)

Definition at line 16483 of file mongoose616.cxx.

16484 {
16485 mbuf_append(&nc->send_mbuf, buf, len);
16486}
Here is the call graph for this function:

◆ mg_recv_tcp()

static int mg_recv_tcp ( struct mg_connection nc,
char buf,
size_t  len 
)
static

Definition at line 2978 of file mongoose616.cxx.

2978 {
2979 int n = 0;
2980#if MG_ENABLE_SSL
2981 if (nc->flags & MG_F_SSL) {
2982 if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
2983 n = mg_ssl_if_read(nc, buf, len);
2984 DBG(("%p <- %d bytes (SSL)", nc, n));
2985 if (n < 0) {
2986 if (n == MG_SSL_WANT_READ) {
2987 nc->flags |= MG_F_WANT_READ;
2988 n = 0;
2989 } else {
2991 }
2992 } else if (n > 0) {
2993 nc->flags &= ~MG_F_WANT_READ;
2994 }
2995 } else {
2996 mg_ssl_handshake(nc);
2997 }
2998 } else
2999#endif
3000 {
3001 n = nc->iface->vtable->tcp_recv(nc, buf, len);
3002 DBG(("%p <- %d bytes", nc, n));
3003 }
3004 if (n > 0) {
3005 nc->recv_mbuf.len += n;
3006 nc->last_io_time = (time_t) mg_time();
3007#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
3008 if (nc->mgr && nc->mgr->hexdump_file != NULL) {
3010 }
3011#endif
3012 mbuf_trim(&nc->recv_mbuf);
3013 mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n);
3014 } else if (n < 0) {
3016 }
3017 mbuf_trim(&nc->recv_mbuf);
3018 return n;
3019}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_recv_udp()

static int mg_recv_udp ( struct mg_connection nc,
char buf,
size_t  len 
)
static

Definition at line 3021 of file mongoose616.cxx.

3021 {
3022 int n = 0;
3023 struct mg_connection *lc = nc;
3024 union socket_address sa;
3025 size_t sa_len = sizeof(sa);
3026 n = nc->iface->vtable->udp_recv(lc, buf, len, &sa, &sa_len);
3027 if (n < 0) {
3029 goto out;
3030 }
3031 if (nc->flags & MG_F_LISTENING) {
3032 /*
3033 * Do we have an existing connection for this source?
3034 * This is very inefficient for long connection lists.
3035 */
3036 lc = nc;
3037 for (nc = mg_next(lc->mgr, NULL); nc != NULL; nc = mg_next(lc->mgr, nc)) {
3038 if (memcmp(&nc->sa.sa, &sa.sa, sa_len) == 0 && nc->listener == lc) {
3039 break;
3040 }
3041 }
3042 if (nc == NULL) {
3043 struct mg_add_sock_opts opts;
3044 memset(&opts, 0, sizeof(opts));
3045 /* Create fake connection w/out sock initialization */
3046 nc = mg_create_connection_base(lc->mgr, lc->handler, opts);
3047 if (nc != NULL) {
3048 nc->sock = lc->sock;
3049 nc->listener = lc;
3050 nc->sa = sa;
3051 nc->proto_handler = lc->proto_handler;
3052 nc->user_data = lc->user_data;
3054 nc->flags = MG_F_UDP;
3055 /*
3056 * Long-lived UDP "connections" i.e. interactions that involve more
3057 * than one request and response are rare, most are transactional:
3058 * response is sent and the "connection" is closed. Or - should be.
3059 * But users (including ourselves) tend to forget about that part,
3060 * because UDP is connectionless and one does not think about
3061 * processing a UDP request as handling a connection that needs to be
3062 * closed. Thus, we begin with SEND_AND_CLOSE flag set, which should
3063 * be a reasonable default for most use cases, but it is possible to
3064 * turn it off the connection should be kept alive after processing.
3065 */
3067 mg_add_conn(lc->mgr, nc);
3068 mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
3069 }
3070 }
3071 }
3072 if (nc != NULL) {
3073 DBG(("%p <- %d bytes from %s:%d", nc, n, inet_ntoa(nc->sa.sin.sin_addr),
3074 ntohs(nc->sa.sin.sin_port)));
3075 if (nc == lc) {
3076 nc->recv_mbuf.len += n;
3077 } else {
3078 mbuf_append(&nc->recv_mbuf, buf, n);
3079 }
3080 mbuf_trim(&lc->recv_mbuf);
3081 lc->last_io_time = nc->last_io_time = (time_t) mg_time();
3082#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
3083 if (nc->mgr && nc->mgr->hexdump_file != NULL) {
3085 }
3086#endif
3087 if (n != 0) {
3088 mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n);
3089 }
3090 }
3091
3092out:
3093 mbuf_free(&lc->recv_mbuf);
3094 return n;
3095}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_remove_conn()

MG_INTERNAL void mg_remove_conn ( struct mg_connection c)

Definition at line 2433 of file mongoose616.cxx.

2433 {
2434 if (conn->prev == NULL) conn->mgr->active_connections = conn->next;
2435 if (conn->prev) conn->prev->next = conn->next;
2436 if (conn->next) conn->next->prev = conn->prev;
2437 conn->prev = conn->next = NULL;
2438 conn->iface->vtable->remove_conn(conn);
2439}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_run_in_task()

void mg_run_in_task ( void(*)(struct mg_mgr *mgr, void *arg)  cb,
void cb_arg 
)

Definition at line 14550 of file mongoose616.cxx.

14550 {
14551 struct mg_q_msg msg = {MG_Q_MSG_CB, cb, cb_arg};
14553}
Here is the call graph for this function:

◆ mg_set_non_blocking_mode()

void mg_set_non_blocking_mode ( sock_t  sock)

Definition at line 3851 of file mongoose616.cxx.

3851 {
3852#ifdef _WIN32
3853 unsigned long on = 1;
3854 ioctlsocket(sock, FIONBIO, &on);
3855#else
3856 int flags = fcntl(sock, F_GETFL, 0);
3857 fcntl(sock, F_SETFL, flags | O_NONBLOCK);
3858#endif
3859}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_sl_if_add_conn()

void mg_sl_if_add_conn ( struct mg_connection nc)

Definition at line 14866 of file mongoose616.cxx.

14866 {
14867 (void) nc;
14868}
Here is the call graph for this function:

◆ mg_sl_if_connect_tcp()

static void mg_sl_if_connect_tcp ( struct mg_connection nc,
const union socket_address sa 
)
static

Definition at line 14645 of file mongoose616.cxx.

14646 {
14647 int proto = 0;
14648#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
14649 if (nc->flags & MG_F_SSL) proto = SL_SEC_SOCKET;
14650#endif
14651 sock_t sock = sl_Socket(AF_INET, SOCK_STREAM, proto);
14652 if (sock < 0) {
14653 nc->err = sock;
14654 goto out;
14655 }
14656 mg_sock_set(nc, sock);
14657#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
14658 nc->err = sl_set_ssl_opts(sock, nc);
14659 if (nc->err != 0) goto out;
14660#endif
14661 nc->err = sl_Connect(sock, &sa->sa, sizeof(sa->sin));
14662out:
14663 DBG(("%p to %s:%d sock %d %d err %d", nc, inet_ntoa(sa->sin.sin_addr),
14664 ntohs(sa->sin.sin_port), nc->sock, proto, nc->err));
14665}
Here is the call graph for this function:

◆ mg_sl_if_connect_udp()

static void mg_sl_if_connect_udp ( struct mg_connection nc)
static

Definition at line 14667 of file mongoose616.cxx.

14667 {
14668 sock_t sock = sl_Socket(AF_INET, SOCK_DGRAM, 0);
14669 if (sock < 0) {
14670 nc->err = sock;
14671 return;
14672 }
14673 mg_sock_set(nc, sock);
14674 nc->err = 0;
14675}
Here is the call graph for this function:

◆ mg_sl_if_create_conn()

static int mg_sl_if_create_conn ( struct mg_connection nc)
static

Definition at line 14730 of file mongoose616.cxx.

14730 {
14731 (void) nc;
14732 return 1;
14733}
Here is the call graph for this function:

◆ mg_sl_if_destroy_conn()

void mg_sl_if_destroy_conn ( struct mg_connection nc)

Definition at line 14735 of file mongoose616.cxx.

14735 {
14736 if (nc->sock == INVALID_SOCKET) return;
14737 /* For UDP, only close outgoing sockets or listeners. */
14738 if (!(nc->flags & MG_F_UDP) || nc->listener == NULL) {
14739 sl_Close(nc->sock);
14740 }
14741 nc->sock = INVALID_SOCKET;
14742}
Here is the call graph for this function:

◆ mg_sl_if_free()

void mg_sl_if_free ( struct mg_iface iface)

Definition at line 14862 of file mongoose616.cxx.

14862 {
14863 (void) iface;
14864}
Here is the call graph for this function:

◆ mg_sl_if_get_conn_addr()

void mg_sl_if_get_conn_addr ( struct mg_connection nc,
int  remote,
union socket_address sa 
)

Definition at line 14970 of file mongoose616.cxx.

14971 {
14972 /* SimpleLink does not provide a way to get socket's peer address after
14973 * accept or connect. Address should have been preserved in the connection,
14974 * so we do our best here by using it. */
14975 if (remote) memcpy(sa, &nc->sa, sizeof(*sa));
14976}
Here is the call graph for this function:

◆ mg_sl_if_init()

void mg_sl_if_init ( struct mg_iface iface)

Definition at line 14857 of file mongoose616.cxx.

14857 {
14858 (void) iface;
14859 DBG(("%p using sl_Select()", iface->mgr));
14860}
Here is the call graph for this function:

◆ mg_sl_if_listen_tcp()

static int mg_sl_if_listen_tcp ( struct mg_connection nc,
union socket_address sa 
)
static

Definition at line 14677 of file mongoose616.cxx.

14678 {
14679 int proto = 0;
14680 if (nc->flags & MG_F_SSL) proto = SL_SEC_SOCKET;
14681 sock_t sock = mg_open_listening_socket(nc, sa, SOCK_STREAM, proto);
14682 if (sock < 0) return sock;
14683 mg_sock_set(nc, sock);
14684 return 0;
14685}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_sl_if_listen_udp()

static int mg_sl_if_listen_udp ( struct mg_connection nc,
union socket_address sa 
)
static

Definition at line 14687 of file mongoose616.cxx.

14688 {
14689 sock_t sock = mg_open_listening_socket(nc, sa, SOCK_DGRAM, 0);
14690 if (sock == INVALID_SOCKET) return (errno ? errno : 1);
14691 mg_sock_set(nc, sock);
14692 return 0;
14693}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_sl_if_poll()

time_t mg_sl_if_poll ( struct mg_iface iface,
int  timeout_ms 
)

Definition at line 14874 of file mongoose616.cxx.

14874 {
14875 struct mg_mgr *mgr = iface->mgr;
14876 double now = mg_time();
14877 double min_timer;
14878 struct mg_connection *nc, *tmp;
14879 struct SlTimeval_t tv;
14882 int num_fds, num_ev = 0, num_timers = 0;
14883
14887
14888 /*
14889 * Note: it is ok to have connections with sock == INVALID_SOCKET in the list,
14890 * e.g. timer-only "connections".
14891 */
14892 min_timer = 0;
14893 for (nc = mgr->active_connections, num_fds = 0; nc != NULL; nc = tmp) {
14894 tmp = nc->next;
14895
14896 if (nc->sock != INVALID_SOCKET) {
14897 num_fds++;
14898
14899 if (!(nc->flags & MG_F_WANT_WRITE) &&
14900 nc->recv_mbuf.len < nc->recv_mbuf_limit &&
14901 (!(nc->flags & MG_F_UDP) || nc->listener == NULL)) {
14903 if (max_fd == INVALID_SOCKET || nc->sock > max_fd) max_fd = nc->sock;
14904 }
14905
14906 if (((nc->flags & MG_F_CONNECTING) && !(nc->flags & MG_F_WANT_READ)) ||
14907 (nc->send_mbuf.len > 0 && !(nc->flags & MG_F_CONNECTING))) {
14910 if (max_fd == INVALID_SOCKET || nc->sock > max_fd) max_fd = nc->sock;
14911 }
14912 }
14913
14914 if (nc->ev_timer_time > 0) {
14915 if (num_timers == 0 || nc->ev_timer_time < min_timer) {
14917 }
14918 num_timers++;
14919 }
14920 }
14921
14922 /*
14923 * If there is a timer to be fired earlier than the requested timeout,
14924 * adjust the timeout.
14925 */
14926 if (num_timers > 0) {
14927 double timer_timeout_ms = (min_timer - mg_time()) * 1000 + 1 /* rounding */;
14930 }
14931 }
14932 if (timeout_ms < 0) timeout_ms = 0;
14933
14934 tv.tv_sec = timeout_ms / 1000;
14935 tv.tv_usec = (timeout_ms % 1000) * 1000;
14936
14937 if (num_fds > 0) {
14938 num_ev = sl_Select((int) max_fd + 1, &read_set, &write_set, &err_set, &tv);
14939 }
14940
14941 now = mg_time();
14942 DBG(("sl_Select @ %ld num_ev=%d of %d, timeout=%d", (long) now, num_ev,
14944
14945 for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
14946 int fd_flags = 0;
14947 if (nc->sock != INVALID_SOCKET) {
14948 if (num_ev > 0) {
14949 fd_flags =
14951 (!(nc->flags & MG_F_UDP) || nc->listener == NULL)
14953 : 0) |
14955 : 0) |
14957 }
14958 /* SimpleLink does not report UDP sockets as writable. */
14959 if (nc->flags & MG_F_UDP && nc->send_mbuf.len > 0) {
14961 }
14962 }
14963 tmp = nc->next;
14965 }
14966
14967 return now;
14968}
Here is the call graph for this function:

◆ mg_sl_if_remove_conn()

void mg_sl_if_remove_conn ( struct mg_connection nc)

Definition at line 14870 of file mongoose616.cxx.

14870 {
14871 (void) nc;
14872}
Here is the call graph for this function:

◆ mg_sl_if_sock_set()

void mg_sl_if_sock_set ( struct mg_connection nc,
sock_t  sock 
)

Definition at line 14851 of file mongoose616.cxx.

14851 {
14853 nc->sock = sock;
14854 DBG(("%p %d", nc, sock));
14855}
Here is the call graph for this function:

◆ mg_sl_if_tcp_recv()

static int mg_sl_if_tcp_recv ( struct mg_connection nc,
void buf,
size_t  len 
)
static

Definition at line 14709 of file mongoose616.cxx.

14709 {
14710 int n = sl_Recv(nc->sock, buf, len, 0);
14711 if (n == 0) {
14712 /* Orderly shutdown of the socket, try flushing output. */
14714 } else if (n < 0 && !mg_is_error(n)) {
14715 n = 0;
14716 }
14717 return n;
14718}
Here is the call graph for this function:

◆ mg_sl_if_tcp_send()

static int mg_sl_if_tcp_send ( struct mg_connection nc,
const void buf,
size_t  len 
)
static

Definition at line 14695 of file mongoose616.cxx.

14696 {
14697 int n = (int) sl_Send(nc->sock, buf, len, 0);
14698 if (n < 0 && !mg_is_error(n)) n = 0;
14699 return n;
14700}
Here is the call graph for this function:

◆ mg_sl_if_udp_recv()

static int mg_sl_if_udp_recv ( struct mg_connection nc,
void buf,
size_t  len,
union socket_address sa,
size_t sa_len 
)
static

Definition at line 14720 of file mongoose616.cxx.

14721 {
14723 int n = sl_RecvFrom(nc->sock, buf, MG_UDP_RECV_BUFFER_SIZE, 0,
14724 (SlSockAddr_t *) sa, &sa_len_t);
14725 *sa_len = sa_len_t;
14726 if (n < 0 && !mg_is_error(n)) n = 0;
14727 return n;
14728}
Here is the call graph for this function:

◆ mg_sl_if_udp_send()

static int mg_sl_if_udp_send ( struct mg_connection nc,
const void buf,
size_t  len 
)
static

Definition at line 14702 of file mongoose616.cxx.

14703 {
14704 int n = sl_SendTo(nc->sock, buf, len, 0, &nc->sa.sa, sizeof(nc->sa.sin));
14705 if (n < 0 && !mg_is_error(n)) n = 0;
14706 return n;
14707}
Here is the call graph for this function:

◆ mg_sock_get_addr()

static void mg_sock_get_addr ( sock_t  sock,
int  remote,
union socket_address sa 
)
static

Definition at line 4366 of file mongoose616.cxx.

4367 {
4368 socklen_t slen = sizeof(*sa);
4369 memset(sa, 0, slen);
4370 if (remote) {
4371 getpeername(sock, &sa->sa, &slen);
4372 } else {
4373 getsockname(sock, &sa->sa, &slen);
4374 }
4375}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_socket_if_add_conn()

void mg_socket_if_add_conn ( struct mg_connection nc)

Definition at line 4155 of file mongoose616.cxx.

4155 {
4156 (void) nc;
4157}
Here is the call graph for this function:

◆ mg_socket_if_connect_tcp()

void mg_socket_if_connect_tcp ( struct mg_connection nc,
const union socket_address sa 
)

Definition at line 3873 of file mongoose616.cxx.

3874 {
3875 int rc, proto = 0;
3876 nc->sock = socket(AF_INET, SOCK_STREAM, proto);
3877 if (nc->sock == INVALID_SOCKET) {
3878 nc->err = mg_get_errno() ? mg_get_errno() : 1;
3879 return;
3880 }
3881#if !defined(MG_ESP8266)
3883#endif
3884 rc = connect(nc->sock, &sa->sa, sizeof(sa->sin));
3885 nc->err = rc < 0 && mg_is_error() ? mg_get_errno() : 0;
3886 DBG(("%p sock %d rc %d errno %d err %d", nc, nc->sock, rc, mg_get_errno(),
3887 nc->err));
3888}
Here is the call graph for this function:

◆ mg_socket_if_connect_udp()

void mg_socket_if_connect_udp ( struct mg_connection nc)

Definition at line 3890 of file mongoose616.cxx.

3890 {
3891 nc->sock = socket(AF_INET, SOCK_DGRAM, 0);
3892 if (nc->sock == INVALID_SOCKET) {
3893 nc->err = mg_get_errno() ? mg_get_errno() : 1;
3894 return;
3895 }
3896 if (nc->flags & MG_F_ENABLE_BROADCAST) {
3897 int optval = 1;
3898 if (setsockopt(nc->sock, SOL_SOCKET, SO_BROADCAST, (const char *) &optval,
3899 sizeof(optval)) < 0) {
3900 nc->err = mg_get_errno() ? mg_get_errno() : 1;
3901 return;
3902 }
3903 }
3904 nc->err = 0;
3905}
Here is the call graph for this function:

◆ mg_socket_if_create_conn()

int mg_socket_if_create_conn ( struct mg_connection nc)

Definition at line 3962 of file mongoose616.cxx.

3962 {
3963 (void) nc;
3964 return 1;
3965}
Here is the call graph for this function:

◆ mg_socket_if_destroy_conn()

void mg_socket_if_destroy_conn ( struct mg_connection nc)

Definition at line 3967 of file mongoose616.cxx.

3967 {
3968 if (nc->sock == INVALID_SOCKET) return;
3969 if (!(nc->flags & MG_F_UDP)) {
3970 closesocket(nc->sock);
3971 } else {
3972 /* Only close outgoing UDP sockets or listeners. */
3973 if (nc->listener == NULL) closesocket(nc->sock);
3974 }
3975 nc->sock = INVALID_SOCKET;
3976}
Here is the call graph for this function:

◆ mg_socket_if_free()

void mg_socket_if_free ( struct mg_iface iface)

Definition at line 4151 of file mongoose616.cxx.

4151 {
4152 (void) iface;
4153}
Here is the call graph for this function:

◆ mg_socket_if_get_conn_addr()

void mg_socket_if_get_conn_addr ( struct mg_connection nc,
int  remote,
union socket_address sa 
)

Definition at line 4383 of file mongoose616.cxx.

4384 {
4385 if ((nc->flags & MG_F_UDP) && remote) {
4386 memcpy(sa, &nc->sa, sizeof(*sa));
4387 return;
4388 }
4389 mg_sock_get_addr(nc->sock, remote, sa);
4390}
Here is the call graph for this function:

◆ mg_socket_if_init()

void mg_socket_if_init ( struct mg_iface iface)

Definition at line 4143 of file mongoose616.cxx.

4143 {
4144 (void) iface;
4145 DBG(("%p using select()", iface->mgr));
4146#if MG_ENABLE_BROADCAST
4147 mg_socketpair(iface->mgr->ctl, SOCK_DGRAM);
4148#endif
4149}
Here is the call graph for this function:

◆ mg_socket_if_listen_tcp()

int mg_socket_if_listen_tcp ( struct mg_connection nc,
union socket_address sa 
)

Definition at line 3907 of file mongoose616.cxx.

3908 {
3909 int proto = 0;
3910 sock_t sock = mg_open_listening_socket(sa, SOCK_STREAM, proto);
3911 if (sock == INVALID_SOCKET) {
3912 return (mg_get_errno() ? mg_get_errno() : 1);
3913 }
3914 mg_sock_set(nc, sock);
3915 return 0;
3916}
Here is the call graph for this function:

◆ mg_socket_if_listen_udp()

static int mg_socket_if_listen_udp ( struct mg_connection nc,
union socket_address sa 
)
static

Definition at line 3918 of file mongoose616.cxx.

3919 {
3921 if (sock == INVALID_SOCKET) return (mg_get_errno() ? mg_get_errno() : 1);
3922 mg_sock_set(nc, sock);
3923 return 0;
3924}
Here is the call graph for this function:

◆ mg_socket_if_poll()

time_t mg_socket_if_poll ( struct mg_iface iface,
int  timeout_ms 
)

Definition at line 4176 of file mongoose616.cxx.

4176 {
4177 struct mg_mgr *mgr = iface->mgr;
4178 double now = mg_time();
4179 double min_timer;
4180 struct mg_connection *nc, *tmp;
4181 struct timeval tv;
4184 int num_fds, num_ev, num_timers = 0;
4185#ifdef __unix__
4186 int try_dup = 1;
4187#endif
4188
4189 FD_ZERO(&read_set);
4191 FD_ZERO(&err_set);
4192#if MG_ENABLE_BROADCAST
4193 mg_add_to_set(mgr->ctl[1], &read_set, &max_fd);
4194#endif
4195
4196 /*
4197 * Note: it is ok to have connections with sock == INVALID_SOCKET in the list,
4198 * e.g. timer-only "connections".
4199 */
4200 min_timer = 0;
4201 for (nc = mgr->active_connections, num_fds = 0; nc != NULL; nc = tmp) {
4202 tmp = nc->next;
4203
4204 if (nc->sock != INVALID_SOCKET) {
4205 num_fds++;
4206
4207#ifdef __unix__
4208 /* A hack to make sure all our file descriptos fit into FD_SETSIZE. */
4209 if (nc->sock >= (sock_t) FD_SETSIZE && try_dup) {
4210 int new_sock = dup(nc->sock);
4211 if (new_sock >= 0) {
4212 if (new_sock < (sock_t) FD_SETSIZE) {
4213 closesocket(nc->sock);
4214 DBG(("new sock %d -> %d", nc->sock, new_sock));
4215 nc->sock = new_sock;
4216 } else {
4218 DBG(("new sock is still larger than FD_SETSIZE, disregard"));
4219 try_dup = 0;
4220 }
4221 } else {
4222 try_dup = 0;
4223 }
4224 }
4225#endif
4226
4227 if (nc->recv_mbuf.len < nc->recv_mbuf_limit &&
4228 (!(nc->flags & MG_F_UDP) || nc->listener == NULL)) {
4230 }
4231
4232 if (((nc->flags & MG_F_CONNECTING) && !(nc->flags & MG_F_WANT_READ)) ||
4233 (nc->send_mbuf.len > 0 && !(nc->flags & MG_F_CONNECTING))) {
4236 }
4237 }
4238
4239 if (nc->ev_timer_time > 0) {
4240 if (num_timers == 0 || nc->ev_timer_time < min_timer) {
4242 }
4243 num_timers++;
4244 }
4245 }
4246
4247 /*
4248 * If there is a timer to be fired earlier than the requested timeout,
4249 * adjust the timeout.
4250 */
4251 if (num_timers > 0) {
4252 double timer_timeout_ms = (min_timer - mg_time()) * 1000 + 1 /* rounding */;
4255 }
4256 }
4257 if (timeout_ms < 0) timeout_ms = 0;
4258
4259 tv.tv_sec = timeout_ms / 1000;
4260 tv.tv_usec = (timeout_ms % 1000) * 1000;
4261
4262 num_ev = select((int) max_fd + 1, &read_set, &write_set, &err_set, &tv);
4263 now = mg_time();
4264#if 0
4265 DBG(("select @ %ld num_ev=%d of %d, timeout=%d", (long) now, num_ev, num_fds,
4266 timeout_ms));
4267#endif
4268
4269#if MG_ENABLE_BROADCAST
4270 if (num_ev > 0 && mgr->ctl[1] != INVALID_SOCKET &&
4271 FD_ISSET(mgr->ctl[1], &read_set)) {
4273 }
4274#endif
4275
4276 for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
4277 int fd_flags = 0;
4278 if (nc->sock != INVALID_SOCKET) {
4279 if (num_ev > 0) {
4280 fd_flags = (FD_ISSET(nc->sock, &read_set) &&
4281 (!(nc->flags & MG_F_UDP) || nc->listener == NULL)
4283 : 0) |
4284 (FD_ISSET(nc->sock, &write_set) ? _MG_F_FD_CAN_WRITE : 0) |
4285 (FD_ISSET(nc->sock, &err_set) ? _MG_F_FD_ERROR : 0);
4286 }
4287#if MG_LWIP
4288 /* With LWIP socket emulation layer, we don't get write events for UDP */
4289 if ((nc->flags & MG_F_UDP) && nc->listener == NULL) {
4291 }
4292#endif
4293 }
4294 tmp = nc->next;
4296 }
4297
4298 return (time_t) now;
4299}
Here is the call graph for this function:

◆ mg_socket_if_remove_conn()

void mg_socket_if_remove_conn ( struct mg_connection nc)

Definition at line 4159 of file mongoose616.cxx.

4159 {
4160 (void) nc;
4161}
Here is the call graph for this function:

◆ mg_socket_if_sock_set()

void mg_socket_if_sock_set ( struct mg_connection nc,
sock_t  sock 
)

Definition at line 4136 of file mongoose616.cxx.

4136 {
4139 nc->sock = sock;
4140 DBG(("%p %d", nc, sock));
4141}
Here is the call graph for this function:

◆ mg_socket_if_tcp_recv()

static int mg_socket_if_tcp_recv ( struct mg_connection nc,
void buf,
size_t  len 
)
static

Definition at line 3940 of file mongoose616.cxx.

3941 {
3942 int n = (int) MG_RECV_FUNC(nc->sock, buf, len, 0);
3943 if (n == 0) {
3944 /* Orderly shutdown of the socket, try flushing output. */
3946 } else if (n < 0 && !mg_is_error()) {
3947 n = 0;
3948 }
3949 return n;
3950}
Here is the call graph for this function:

◆ mg_socket_if_tcp_send()

static int mg_socket_if_tcp_send ( struct mg_connection nc,
const void buf,
size_t  len 
)
static

Definition at line 3926 of file mongoose616.cxx.

3927 {
3928 int n = (int) MG_SEND_FUNC(nc->sock, buf, len, 0);
3929 if (n < 0 && !mg_is_error()) n = 0;
3930 return n;
3931}
Here is the call graph for this function:

◆ mg_socket_if_udp_recv()

static int mg_socket_if_udp_recv ( struct mg_connection nc,
void buf,
size_t  len,
union socket_address sa,
size_t sa_len 
)
static

Definition at line 3952 of file mongoose616.cxx.

3954 {
3956 int n = recvfrom(nc->sock, buf, len, 0, &sa->sa, &sa_len_st);
3957 *sa_len = sa_len_st;
3958 if (n < 0 && !mg_is_error()) n = 0;
3959 return n;
3960}
Here is the call graph for this function:

◆ mg_socket_if_udp_send()

static int mg_socket_if_udp_send ( struct mg_connection nc,
const void buf,
size_t  len 
)
static

Definition at line 3933 of file mongoose616.cxx.

3934 {
3935 int n = sendto(nc->sock, buf, len, 0, &nc->sa.sa, sizeof(nc->sa.sin));
3936 if (n < 0 && !mg_is_error()) n = 0;
3937 return n;
3938}
Here is the call graph for this function:

◆ mg_start_task()

bool mg_start_task ( int  priority,
int  stack_size,
mg_init_cb  mg_init 
)

Definition at line 14522 of file mongoose616.cxx.

14522 {
14523 if (osi_MsgQCreate(&s_mg_q, "MG", sizeof(struct mg_q_msg), 16) != OSI_OK) {
14524 return false;
14525 }
14526 if (osi_TaskCreate(mg_task, (const signed char *) "MG", stack_size,
14527 (void *) mg_init, priority, NULL) != OSI_OK) {
14528 return false;
14529 }
14530 return true;
14531}
Here is the call graph for this function:

◆ mg_str_starts_with()

int mg_str_starts_with ( struct mg_str  s,
struct mg_str  prefix 
)

Definition at line 1827 of file mongoose616.cxx.

1827 {
1828 const struct mg_str sp = MG_MK_STR_N(s.p, prefix.len);
1829 if (s.len < prefix.len) return 0;
1830 return (mg_strcmp(sp, prefix) == 0);
1831}
#define MG_MK_STR_N(str_literal, len)
Here is the call graph for this function:

◆ mg_strchr()

const char * mg_strchr ( const struct mg_str  s,
int  c 
)

Definition at line 1757 of file mongoose616.cxx.

1757 {
1758 size_t i;
1759 for (i = 0; i < s.len; i++) {
1760 if (s.p[i] == c) return &s.p[i];
1761 }
1762 return NULL;
1763}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_strcmp()

int mg_strcmp ( const struct mg_str  str1,
const struct mg_str  str2 
)

Definition at line 1766 of file mongoose616.cxx.

1766 {
1767 size_t i = 0;
1768 while (i < str1.len && i < str2.len) {
1769 if (str1.p[i] < str2.p[i]) return -1;
1770 if (str1.p[i] > str2.p[i]) return 1;
1771 i++;
1772 }
1773 if (i < str1.len) return 1;
1774 if (i < str2.len) return -1;
1775 return 0;
1776}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_strdup()

struct mg_str mg_strdup ( const struct mg_str  s)

Definition at line 1747 of file mongoose616.cxx.

1747 {
1748 return mg_strdup_common(s, 0 /* NUL-terminate */);
1749}
static struct mg_str mg_strdup_common(const struct mg_str s, int nul_terminate)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_strdup_common()

static struct mg_str mg_strdup_common ( const struct mg_str  s,
int  nul_terminate 
)
static

Definition at line 1731 of file mongoose616.cxx.

1732 {
1733 struct mg_str r = {NULL, 0};
1734 if (s.len > 0 && s.p != NULL) {
1735 char *sc = (char *) MG_MALLOC(s.len + (nul_terminate ? 1 : 0));
1736 if (sc != NULL) {
1737 memcpy(sc, s.p, s.len);
1738 if (nul_terminate) sc[s.len] = '\0';
1739 r.p = sc;
1740 r.len = s.len;
1741 }
1742 }
1743 return r;
1744}
Here is the call graph for this function:

◆ mg_strdup_nul()

struct mg_str mg_strdup_nul ( const struct mg_str  s)

Definition at line 1752 of file mongoose616.cxx.

1752 {
1753 return mg_strdup_common(s, 1 /* NUL-terminate */);
1754}
Here is the call graph for this function:

◆ mg_strfree()

void mg_strfree ( struct mg_str s)

Definition at line 1793 of file mongoose616.cxx.

1793 {
1794 char *sp = (char *) s->p;
1795 s->p = NULL;
1796 s->len = 0;
1797 if (sp != NULL) free(sp);
1798}
Here is the call graph for this function:

◆ mg_strncmp()

int mg_strncmp ( const struct mg_str  str1,
const struct mg_str  str2,
size_t  n 
)

Definition at line 1779 of file mongoose616.cxx.

1779 {
1780 struct mg_str s1 = str1;
1781 struct mg_str s2 = str2;
1782
1783 if (s1.len > n) {
1784 s1.len = n;
1785 }
1786 if (s2.len > n) {
1787 s2.len = n;
1788 }
1789 return mg_strcmp(s1, s2);
1790}
Here is the call graph for this function:

◆ mg_strstr()

const char * mg_strstr ( const struct mg_str  haystack,
const struct mg_str  needle 
)

Definition at line 1802 of file mongoose616.cxx.

1803 {
1804 size_t i;
1805 if (needle.len > haystack.len) return NULL;
1806 for (i = 0; i <= haystack.len - needle.len; i++) {
1807 if (memcmp(haystack.p + i, needle.p, needle.len) == 0) {
1808 return haystack.p + i;
1809 }
1810 }
1811 return NULL;
1812}
Here is the call graph for this function:

◆ mg_strstrip()

struct mg_str mg_strstrip ( struct mg_str  s)

Definition at line 1815 of file mongoose616.cxx.

1815 {
1816 while (s.len > 0 && isspace((int) *s.p)) {
1817 s.p++;
1818 s.len--;
1819 }
1820 while (s.len > 0 && isspace((int) *(s.p + s.len - 1))) {
1821 s.len--;
1822 }
1823 return s;
1824}
Here is the call graph for this function:

◆ mg_task()

static void mg_task ( void arg)
static

Definition at line 14533 of file mongoose616.cxx.

14533 {
14534 struct mg_mgr mgr;
14536 mg_mgr_init(&mgr, NULL);
14537 mg_init(&mgr);
14538 while (1) {
14539 struct mg_q_msg msg;
14540 mg_mgr_poll(&mgr, 1);
14541 if (osi_MsgQRead(&s_mg_q, &msg, 1) != OSI_OK) continue;
14542 switch (msg.type) {
14543 case MG_Q_MSG_CB: {
14544 msg.cb(&mgr, msg.arg);
14545 }
14546 }
14547 }
14548}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_timer()

MG_INTERNAL void mg_timer ( struct mg_connection c,
double  now 
)

Definition at line 2483 of file mongoose616.cxx.

2483 {
2484 if (c->ev_timer_time > 0 && now >= c->ev_timer_time) {
2485 double old_value = c->ev_timer_time;
2486 c->ev_timer_time = 0;
2487 mg_call(c, NULL, c->user_data, MG_EV_TIMER, &old_value);
2488 }
2489}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mg_url_encode()

struct mg_str mg_url_encode ( const struct mg_str  src)

Definition at line 10961 of file mongoose616.cxx.

10961 {
10962 return mg_url_encode_opt(src, mg_mk_str("._-$,;~()/"), 0);
10963}
Here is the call graph for this function:

◆ mg_url_encode_opt()

struct mg_str mg_url_encode_opt ( const struct mg_str  src,
const struct mg_str  safe,
unsigned int  flags 
)

Definition at line 10935 of file mongoose616.cxx.

10936 {
10937 const char *hex =
10938 (flags & MG_URL_ENCODE_F_UPPERCASE_HEX ? "0123456789ABCDEF"
10939 : "0123456789abcdef");
10940 size_t i = 0;
10941 struct mbuf mb;
10942 mbuf_init(&mb, src.len);
10943
10944 for (i = 0; i < src.len; i++) {
10945 const unsigned char c = *((const unsigned char *) src.p + i);
10946 if (isalnum(c) || mg_strchr(safe, c) != NULL) {
10947 mbuf_append(&mb, &c, 1);
10948 } else if (c == ' ' && (flags & MG_URL_ENCODE_F_SPACE_AS_PLUS)) {
10949 mbuf_append(&mb, "+", 1);
10950 } else {
10951 mbuf_append(&mb, "%", 1);
10952 mbuf_append(&mb, &hex[c >> 4], 1);
10953 mbuf_append(&mb, &hex[c & 15], 1);
10954 }
10955 }
10956 mbuf_append(&mb, "", 1);
10957 mbuf_trim(&mb);
10958 return mg_mk_str_n(mb.buf, mb.len - 1);
10959}
#define MG_URL_ENCODE_F_UPPERCASE_HEX
#define MG_URL_ENCODE_F_SPACE_AS_PLUS
Here is the call graph for this function:
Here is the caller graph for this function:

◆ parse_net()

static int parse_net ( const char spec,
uint32_t net,
uint32_t mask 
)
static

Definition at line 3481 of file mongoose616.cxx.

3481 {
3482 int n, a, b, c, d, slash = 32, len = 0;
3483
3484 if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5 ||
3485 sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) &&
3486 isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) && slash >= 0 &&
3487 slash < 33) {
3488 len = n;
3489 *net =
3490 ((uint32_t) a << 24) | ((uint32_t) b << 16) | ((uint32_t) c << 8) | d;
3491 *mask = slash ? 0xffffffffU << (32 - slash) : 0;
3492 }
3493
3494 return len;
3495}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ parse_uri_component()

static void parse_uri_component ( const char **  p,
const char end,
const char seps,
struct mg_str res 
)
static

Definition at line 5619 of file mongoose616.cxx.

5620 {
5621 const char *q;
5622 res->p = *p;
5623 for (; *p < end; (*p)++) {
5624 for (q = seps; *q != '\0'; q++) {
5625 if (**p == *q) break;
5626 }
5627 if (*q != '\0') break;
5628 }
5629 res->len = (*p) - res->p;
5630 if (*p < end) (*p)++;
5631}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ recv_avail_size()

MG_INTERNAL size_t recv_avail_size ( struct mg_connection conn,
size_t  max 
)

Definition at line 2491 of file mongoose616.cxx.

2491 {
2492 size_t avail;
2493 if (conn->recv_mbuf_limit < conn->recv_mbuf.len) return 0;
2494 avail = conn->recv_mbuf_limit - conn->recv_mbuf.len;
2495 return avail > max ? max : avail;
2496}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sl_restart_cb()

void sl_restart_cb ( struct mg_mgr mgr)

Definition at line 14978 of file mongoose616.cxx.

14978 {
14979 /*
14980 * SimpleLink has been restarted, meaning all sockets have been invalidated.
14981 * We try our best - we'll restart the listeners, but for outgoing
14982 * connections we have no option but to terminate.
14983 */
14984 struct mg_connection *nc;
14985 for (nc = mg_next(mgr, NULL); nc != NULL; nc = mg_next(mgr, nc)) {
14986 if (nc->sock == INVALID_SOCKET) continue; /* Could be a timer */
14987 if (nc->flags & MG_F_LISTENING) {
14988 DBG(("restarting %p %s:%d", nc, inet_ntoa(nc->sa.sin.sin_addr),
14989 ntohs(nc->sa.sin.sin_port)));
14990 int res = (nc->flags & MG_F_UDP ? mg_sl_if_listen_udp(nc, &nc->sa)
14991 : mg_sl_if_listen_tcp(nc, &nc->sa));
14992 if (res == 0) continue;
14993 /* Well, we tried and failed. Fall through to closing. */
14994 }
14995 nc->sock = INVALID_SOCKET;
14996 DBG(("terminating %p %s:%d", nc, inet_ntoa(nc->sa.sin.sin_addr),
14997 ntohs(nc->sa.sin.sin_port)));
14998 /* TODO(rojer): Outgoing UDP? */
15000 }
15001}
Here is the call graph for this function:

◆ str_util_lowercase()

static int str_util_lowercase ( const char s)
static

Definition at line 2187 of file mongoose616.cxx.

2187 {
2188 return tolower(*(const unsigned char *) s);
2189}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ tcp_close_tcpip()

static void tcp_close_tcpip ( void arg)
static

Definition at line 15727 of file mongoose616.cxx.

15727 {
15728 tcp_close((struct tcp_pcb *) arg);
15729}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ tcp_output_tcpip()

static void tcp_output_tcpip ( void arg)
static

Definition at line 15847 of file mongoose616.cxx.

15847 {
15848 tcp_output((struct tcp_pcb *) arg);
15849}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ tcp_recved_tcpip()

void tcp_recved_tcpip ( void arg)

Definition at line 15966 of file mongoose616.cxx.

15966 {
15967 struct tcp_recved_ctx *ctx = (struct tcp_recved_ctx *) arg;
15968 if (ctx->tpcb != NULL) tcp_recved(ctx->tpcb, ctx->len);
15969}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ udp_remove_tcpip()

static void udp_remove_tcpip ( void arg)
static

Definition at line 16011 of file mongoose616.cxx.

16011 {
16012 udp_remove((struct udp_pcb *) arg);
16013}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ udp_sendto_tcpip()

static void udp_sendto_tcpip ( void arg)
static

Definition at line 15916 of file mongoose616.cxx.

15916 {
15917 struct udp_sendto_ctx *ctx = (struct udp_sendto_ctx *) arg;
15918 ctx->ret = udp_sendto(ctx->upcb, ctx->p, ctx->ip, ctx->port);
15919}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ xxx_tcpip()

static void xxx_tcpip ( void arg)
static

Definition at line 15438 of file mongoose616.cxx.

15438 {
15439 struct mg_lwip_netif_tcpip_call_ctx *ctx =
15441 ctx->fn(ctx->arg);
15443}
Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ mg_default_iface_vtable

const struct mg_iface_vtable mg_default_iface_vtable = MG_NULL_IFACE_VTABLE

Definition at line 3832 of file mongoose616.cxx.

◆ mg_ifaces

Initial value:

Definition at line 3643 of file mongoose616.cxx.

3643 {
3645};

◆ mg_lwip_iface_vtable

Definition at line 16097 of file mongoose616.cxx.

◆ mg_num_ifaces

int mg_num_ifaces = (int) (sizeof(mg_ifaces) / sizeof(mg_ifaces[0]))

Definition at line 3647 of file mongoose616.cxx.

◆ mg_pic32_iface_vtable

Definition at line 16709 of file mongoose616.cxx.

◆ mg_simplelink_iface_vtable

const struct mg_iface_vtable mg_simplelink_iface_vtable = MG_SL_IFACE_VTABLE

Definition at line 15026 of file mongoose616.cxx.

◆ mg_socket_iface_vtable

Definition at line 4415 of file mongoose616.cxx.

◆ s_mg_q

OsiMsgQ_t s_mg_q
static

Definition at line 14519 of file mongoose616.cxx.

◆ s_tcpip_call_lock_sem

sys_sem_t s_tcpip_call_lock_sem = NULL
static

Definition at line 15432 of file mongoose616.cxx.

◆ s_tcpip_call_sync_sem

sys_sem_t s_tcpip_call_sync_sem = NULL
static

Definition at line 15433 of file mongoose616.cxx.

◆ test_calloc

void *(* test_calloc) (size_t count, size_t size) ( size_t  count,
size_t  size 
)
extern

◆ test_malloc

void *(* test_malloc) (size_t size) ( size_t  size)
extern

◆ WEAK

Initial value:

Definition at line 617 of file mongoose616.cxx.