Mongoose net_if and ssl_if refactoring

A major cleanup, disentangling net_if and ssl_if.
Pulled a lot of common logic into the core and reduced size of net_if implementations.

CL: Mongoose net_if and ssl_if refactoring

PUBLISHED_FROM=29bd4dcb264a1fd96b3dd164e2d880e1c2c0921e
This commit is contained in:
Deomid Ryabkov 2018-03-27 00:25:18 +01:00 committed by Cesanta Bot
parent c80f4c5313
commit 3e33e57707
17 changed files with 1358 additions and 2007 deletions

1653
mongoose.c

File diff suppressed because it is too large Load Diff

View File

@ -3245,10 +3245,12 @@ struct mg_iface_vtable {
void (*connect_udp)(struct mg_connection *nc);
/* Send functions for TCP and UDP. Sent data is copied before return. */
void (*tcp_send)(struct mg_connection *nc, const void *buf, size_t len);
void (*udp_send)(struct mg_connection *nc, const void *buf, size_t len);
int (*tcp_send)(struct mg_connection *nc, const void *buf, size_t len);
int (*udp_send)(struct mg_connection *nc, const void *buf, size_t len);
void (*recved)(struct mg_connection *nc, size_t len);
int (*tcp_recv)(struct mg_connection *nc, void *buf, size_t len);
int (*udp_recv)(struct mg_connection *nc, void *buf, size_t len,
union socket_address *sa, size_t *sa_len);
/* Perform interface-related connection initialization. Return 1 on ok. */
int (*create_conn)(struct mg_connection *nc);
@ -3289,19 +3291,15 @@ void mg_if_accept_tcp_cb(struct mg_connection *nc, union socket_address *sa,
/* Callback invoked by connect methods. err = 0 -> ok, != 0 -> error. */
void mg_if_connect_cb(struct mg_connection *nc, int err);
/* Callback that reports that data has been put on the wire. */
void mg_if_sent_cb(struct mg_connection *nc, int num_sent);
/*
* Receive callback.
* if `own` is true, buf must be heap-allocated and ownership is transferred
* to the core.
* Core will acknowledge consumption by calling iface::recved.
* Callback that tells the core that data can be received.
* Core will use tcp/udp_recv to retrieve the data.
*/
void mg_if_recv_tcp_cb(struct mg_connection *nc, void *buf, int len, int own);
void mg_if_can_recv_cb(struct mg_connection *nc);
void mg_if_can_send_cb(struct mg_connection *nc);
/*
* Receive callback.
* buf must be heap-allocated and ownership is transferred to the core.
* Core will acknowledge consumption by calling iface::recved.
*/
void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
union socket_address *sa, size_t sa_len);
@ -3309,10 +3307,7 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
/* void mg_if_close_conn(struct mg_connection *nc); */
/* Deliver a POLL event to the connection. */
void mg_if_poll(struct mg_connection *nc, time_t now);
/* Deliver a TIMER event to the connection. */
void mg_if_timer(struct mg_connection *c, double now);
int mg_if_poll(struct mg_connection *nc, double now);
#ifdef __cplusplus
}

View File

@ -50,15 +50,7 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) {
if (nc->iface == NULL || nc->mgr == NULL) continue;
switch (sig) {
case MG_SIG_CONNECT_RESULT: {
#if MG_ENABLE_SSL
if (cs->err == 0 && (nc->flags & MG_F_SSL) &&
!(nc->flags & MG_F_SSL_HANDSHAKE_DONE)) {
mg_lwip_ssl_do_hs(nc);
} else
#endif
{
mg_if_connect_cb(nc, cs->err);
}
mg_if_connect_cb(nc, cs->err);
break;
}
case MG_SIG_CLOSE_CONN: {
@ -68,11 +60,8 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) {
}
case MG_SIG_RECV: {
cs->recv_pending = 0;
if (nc->flags & MG_F_UDP) {
mg_lwip_handle_recv_udp(nc);
} else {
mg_lwip_handle_recv_tcp(nc);
}
mg_if_can_recv_cb(nc);
mbuf_trim(&nc->recv_mbuf);
break;
}
case MG_SIG_TOMBSTONE: {
@ -87,7 +76,8 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) {
}
void mg_lwip_if_init(struct mg_iface *iface) {
LOG(LL_INFO, ("%p Mongoose init", iface));
LOG(LL_INFO, ("Mongoose %s, LwIP %u.%u.%u", MG_VERSION, LWIP_VERSION_MAJOR,
LWIP_VERSION_MINOR, LWIP_VERSION_REVISION));
iface->data = MG_CALLOC(1, sizeof(struct mg_ev_mgr_lwip_data));
}
@ -126,42 +116,7 @@ time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
tmp = nc->next;
n++;
if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) ||
((nc->flags & MG_F_SEND_AND_CLOSE) && (nc->flags & MG_F_UDP) &&
(nc->send_mbuf.len == 0))) {
mg_close_conn(nc);
continue;
}
mg_if_poll(nc, now);
mg_if_timer(nc, now);
#if MG_ENABLE_SSL
if ((nc->flags & MG_F_SSL) && cs != NULL && cs->pcb.tcp != NULL &&
cs->pcb.tcp->state == ESTABLISHED) {
if (((nc->flags & MG_F_WANT_WRITE) ||
((nc->send_mbuf.len > 0) &&
(nc->flags & MG_F_SSL_HANDSHAKE_DONE))) &&
cs->pcb.tcp->snd_buf > 0) {
/* Can write more. */
if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
if (!(nc->flags & MG_F_CONNECTING)) mg_lwip_ssl_send(nc);
} else {
mg_lwip_ssl_do_hs(nc);
}
}
if (cs->rx_chain != NULL || (nc->flags & MG_F_WANT_READ)) {
if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
if (!(nc->flags & MG_F_CONNECTING)) mg_lwip_ssl_recv(nc);
} else {
mg_lwip_ssl_do_hs(nc);
}
}
} else
#endif /* MG_ENABLE_SSL */
{
if (nc->send_mbuf.len > 0 && !(nc->flags & MG_F_CONNECTING)) {
mg_lwip_send_more(nc);
}
}
if (!mg_if_poll(nc, now)) continue;
if (nc->sock != INVALID_SOCKET &&
!(nc->flags & (MG_F_UDP | MG_F_LISTENING)) && cs->pcb.tcp != NULL &&
cs->pcb.tcp->unsent != NULL) {
@ -175,14 +130,17 @@ time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms) {
}
if (nc->sock != INVALID_SOCKET) {
/* Try to consume data from cs->rx_chain */
mg_lwip_consume_rx_chain_tcp(nc);
/*
* If the connection is about to close, and rx_chain is finally empty,
* send the MG_SIG_CLOSE_CONN signal
*/
if (cs->draining_rx_chain && cs->rx_chain == NULL) {
if (mg_lwip_if_can_send(nc, cs)) {
mg_if_can_send_cb(nc);
mbuf_trim(&nc->send_mbuf);
}
if (cs->rx_chain != NULL) {
mg_if_can_recv_cb(nc);
} else if (cs->draining_rx_chain) {
/*
* If the connection is about to close, and rx_chain is finally empty,
* send the MG_SIG_CLOSE_CONN signal
*/
mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
}
}
@ -210,21 +168,9 @@ uint32_t mg_lwip_get_poll_delay_ms(struct mg_mgr *mgr) {
}
num_timers++;
}
if (nc->send_mbuf.len > 0
#if MG_ENABLE_SSL
|| (nc->flags & MG_F_WANT_WRITE)
#endif
) {
int can_send = 0;
/* We have stuff to send, but can we? */
if (nc->flags & MG_F_UDP) {
/* UDP is always ready for sending. */
can_send = (cs->pcb.udp != NULL);
} else {
can_send = (cs->pcb.tcp != NULL && cs->pcb.tcp->snd_buf > 0);
}
/* We want and can send, request a poll immediately. */
if (can_send) return 0;
/* We want and can send data, request a poll immediately. */
if (nc->sock != INVALID_SOCKET && mg_lwip_if_can_send(nc, cs)) {
return 0;
}
}
uint32_t timeout_ms = ~0;

View File

@ -57,10 +57,6 @@
typedef void (*tcpip_callback_fn)(void *arg);
#endif
void mg_lwip_ssl_do_hs(struct mg_connection *nc);
void mg_lwip_ssl_send(struct mg_connection *nc);
void mg_lwip_ssl_recv(struct mg_connection *nc);
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);
@ -132,10 +128,12 @@ 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) {
struct mg_connection *nc = (struct mg_connection *) arg;
DBG(("%p %p %u %d", nc, tpcb, (p != NULL ? p->tot_len : 0), err));
struct mg_lwip_conn_state *cs =
(nc ? (struct mg_lwip_conn_state *) nc->sock : NULL);
DBG(("%p %p %p %p %u %d", nc, cs, tpcb, p, (p != NULL ? p->tot_len : 0),
err));
if (p == NULL) {
if (nc != NULL && !(nc->flags & MG_F_CLOSE_IMMEDIATELY)) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
if (cs->rx_chain != NULL) {
/*
* rx_chain still contains non-consumed data, don't close the
@ -153,7 +151,6 @@ static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb,
tcp_abort(tpcb);
return ERR_ARG;
}
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
/*
* If we get a chain of more than one segment at once, we need to bump
* refcount on the subsequent bufs to make them independent.
@ -168,7 +165,7 @@ static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb,
} else if (pbuf_clen(cs->rx_chain) >= 4) {
/* ESP SDK has a limited pool of 5 pbufs. We must not hog them all or RX
* will be completely blocked. We already have at least 4 in the chain,
* this one is, so we have to make a copy and release this one. */
* this one is the last, so we have to make a copy and release this one. */
struct pbuf *np = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
if (np != NULL) {
pbuf_copy(np, p);
@ -176,58 +173,9 @@ static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb,
p = np;
}
}
mgos_unlock();
mg_lwip_recv_common(nc, p);
return ERR_OK;
}
static void mg_lwip_consume_rx_chain_tcp(struct mg_connection *nc) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
if (cs->rx_chain == NULL) return;
#if MG_ENABLE_SSL
if (nc->flags & MG_F_SSL) {
if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
mg_lwip_ssl_recv(nc);
} else {
mg_lwip_ssl_do_hs(nc);
}
return;
}
#endif
mgos_lock();
while (cs->rx_chain != NULL && nc->recv_mbuf.len < nc->recv_mbuf_limit) {
struct pbuf *seg = cs->rx_chain;
size_t seg_len = (seg->len - cs->rx_offset);
size_t buf_avail = (nc->recv_mbuf_limit - nc->recv_mbuf.len);
size_t len = MIN(seg_len, buf_avail);
char *data = (char *) MG_MALLOC(len);
if (data == NULL) {
mgos_unlock();
DBG(("OOM"));
return;
}
pbuf_copy_partial(seg, data, len, cs->rx_offset);
cs->rx_offset += len;
if (cs->rx_offset == cs->rx_chain->len) {
cs->rx_chain = pbuf_dechain(cs->rx_chain);
pbuf_free(seg);
cs->rx_offset = 0;
}
mgos_unlock();
mg_if_recv_tcp_cb(nc, data, len, 1 /* own */);
mgos_lock();
}
mgos_unlock();
}
static void mg_lwip_handle_recv_tcp(struct mg_connection *nc) {
mg_lwip_consume_rx_chain_tcp(nc);
if (nc->send_mbuf.len > 0) {
mg_lwip_mgr_schedule_poll(nc->mgr);
}
return ERR_OK;
}
static err_t mg_lwip_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb,
@ -313,13 +261,14 @@ static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p,
/* Logic in the recv handler requires that there be exactly one data pbuf. */
p = pbuf_coalesce(p, PBUF_RAW);
pbuf_chain(sap, p);
mgos_lock();
mg_lwip_recv_common(nc, sap);
mgos_unlock();
(void) pcb;
}
static void mg_lwip_recv_common(struct mg_connection *nc, struct pbuf *p) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
mgos_lock();
if (cs->rx_chain == NULL) {
cs->rx_chain = p;
} else {
@ -329,32 +278,30 @@ static void mg_lwip_recv_common(struct mg_connection *nc, struct pbuf *p) {
cs->recv_pending = 1;
mg_lwip_post_signal(MG_SIG_RECV, nc);
}
mgos_unlock();
}
static void mg_lwip_handle_recv_udp(struct mg_connection *nc) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
static int mg_lwip_if_udp_recv(struct mg_connection *nc, void *buf, size_t len,
union socket_address *sa, size_t *sa_len) {
/*
* For UDP, RX chain consists of interleaved address and packet bufs:
* Address pbuf followed by exactly one data pbuf (recv_cb took care of that).
*/
while (cs->rx_chain != NULL) {
struct pbuf *sap = cs->rx_chain;
struct pbuf *p = sap->next;
cs->rx_chain = pbuf_dechain(p);
size_t data_len = p->len;
char *data = (char *) MG_MALLOC(data_len);
if (data != NULL) {
pbuf_copy_partial(p, data, data_len, 0);
pbuf_free(p);
mg_if_recv_udp_cb(nc, data, data_len,
(union socket_address *) sap->payload, sap->len);
pbuf_free(sap);
} else {
pbuf_free(p);
pbuf_free(sap);
}
int res = 0;
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
if (nc->sock == INVALID_SOCKET) return -1;
mgos_lock();
if (cs->rx_chain != NULL) {
struct pbuf *ap = cs->rx_chain;
struct pbuf *dp = ap->next;
cs->rx_chain = pbuf_dechain(dp);
res = MIN(dp->len, len);
pbuf_copy_partial(dp, buf, res, 0);
pbuf_free(dp);
pbuf_copy_partial(ap, sa, MIN(*sa_len, ap->len), 0);
pbuf_free(ap);
}
mgos_unlock();
return res;
}
static void mg_lwip_if_connect_udp_tcpip(void *arg) {
@ -376,13 +323,6 @@ void mg_lwip_if_connect_udp(struct mg_connection *nc) {
tcpip_callback(mg_lwip_if_connect_udp_tcpip, nc);
}
void mg_lwip_accept_conn(struct mg_connection *nc, struct tcp_pcb *tpcb) {
union socket_address sa;
SET_ADDR(&sa, &tpcb->remote_ip);
sa.sin.sin_port = htons(tpcb->remote_port);
mg_if_accept_tcp_cb(nc, &sa, sizeof(sa.sin));
}
static void tcp_close_tcpip(void *arg) {
tcp_close((struct tcp_pcb *) arg);
}
@ -390,17 +330,11 @@ static void tcp_close_tcpip(void *arg) {
void mg_lwip_handle_accept(struct mg_connection *nc) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
if (cs->pcb.tcp == NULL) return;
#if MG_ENABLE_SSL
if (cs->lc->flags & MG_F_SSL) {
if (mg_ssl_if_conn_accept(nc, cs->lc) != MG_SSL_OK) {
LOG(LL_ERROR, ("SSL error"));
tcpip_callback(tcp_close_tcpip, cs->pcb.tcp);
}
} else
#endif
{
mg_lwip_accept_conn(nc, cs->pcb.tcp);
}
union socket_address sa;
struct tcp_pcb *tpcb = cs->pcb.tcp;
SET_ADDR(&sa, &tpcb->remote_ip);
sa.sin.sin_port = htons(tpcb->remote_port);
mg_if_accept_tcp_cb(nc, &sa, sizeof(sa.sin));
}
static err_t mg_lwip_accept_cb(void *arg, struct tcp_pcb *newtpcb, err_t err) {
@ -557,14 +491,13 @@ static void mg_lwip_tcp_write_tcpip(void *arg) {
ctx->ret = len;
}
static int mg_lwip_tcp_write(struct mg_connection *nc, const void *data,
uint16_t len) {
struct mg_lwip_tcp_write_ctx ctx = {.nc = nc, .data = data, .len = len};
int mg_lwip_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len) {
struct mg_lwip_tcp_write_ctx ctx = {.nc = nc, .data = buf, .len = len};
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
if (nc->sock == INVALID_SOCKET) return -1;
struct tcp_pcb *tpcb = cs->pcb.tcp;
if (tpcb == NULL) {
return -1;
}
if (tpcb == NULL) return -1;
if (tpcb->snd_buf <= 0) return 0;
tcpip_callback(mg_lwip_tcp_write_tcpip, &ctx);
return ctx.ret;
}
@ -582,18 +515,10 @@ static void udp_sendto_tcpip(void *arg) {
ctx->ret = udp_sendto(ctx->upcb, ctx->p, ctx->ip, ctx->port);
}
static int mg_lwip_udp_send(struct mg_connection *nc, const void *data,
uint16_t len) {
static int mg_lwip_if_udp_send(struct mg_connection *nc, const void *data,
size_t len) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
if (cs->pcb.udp == NULL) {
/*
* In case of UDP, this usually means, what
* async DNS resolve is still in progress and connection
* is not ready yet
*/
DBG(("%p socket is not connected", nc));
return -1;
}
if (nc->sock == INVALID_SOCKET || cs->pcb.udp == NULL) return -1;
struct udp_pcb *upcb = cs->pcb.udp;
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
#if defined(LWIP_IPV4) && LWIP_IPV4 && defined(LWIP_IPV6) && LWIP_IPV6
@ -602,46 +527,28 @@ static int mg_lwip_udp_send(struct mg_connection *nc, const void *data,
ip_addr_t ip = {.addr = nc->sa.sin.sin_addr.s_addr};
#endif
u16_t port = ntohs(nc->sa.sin.sin_port);
if (p == NULL) {
DBG(("OOM"));
return 0;
}
if (p == NULL) return 0;
memcpy(p->payload, data, len);
struct udp_sendto_ctx ctx = {.upcb = upcb, .p = p, .ip = &ip, .port = port};
tcpip_callback(udp_sendto_tcpip, &ctx);
cs->err = ctx.ret;
pbuf_free(p);
return (cs->err == ERR_OK ? len : -1);
return (cs->err == ERR_OK ? (int) len : -2);
}
static void mg_lwip_send_more(struct mg_connection *nc) {
int num_sent = 0;
if (nc->sock == INVALID_SOCKET) return;
if (nc->flags & MG_F_UDP) {
num_sent = mg_lwip_udp_send(nc, nc->send_mbuf.buf, nc->send_mbuf.len);
DBG(("%p mg_lwip_udp_send %u = %d", nc, nc->send_mbuf.len, num_sent));
} else {
num_sent = mg_lwip_tcp_write(nc, nc->send_mbuf.buf, nc->send_mbuf.len);
DBG(("%p mg_lwip_tcp_write %u = %d", nc, nc->send_mbuf.len, num_sent));
static int mg_lwip_if_can_send(struct mg_connection *nc,
struct mg_lwip_conn_state *cs) {
int can_send = 0;
if (nc->send_mbuf.len > 0 || (nc->flags & MG_F_WANT_WRITE)) {
/* We have stuff to send, but can we? */
if (nc->flags & MG_F_UDP) {
/* UDP is always ready for sending. */
can_send = (cs->pcb.udp != NULL);
} else {
can_send = (cs->pcb.tcp != NULL && cs->pcb.tcp->snd_buf > 0);
}
}
if (num_sent == 0) return;
if (num_sent > 0) {
mg_if_sent_cb(nc, num_sent);
} else {
mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
}
}
void mg_lwip_if_tcp_send(struct mg_connection *nc, const void *buf,
size_t len) {
mbuf_append(&nc->send_mbuf, buf, len);
mg_lwip_mgr_schedule_poll(nc->mgr);
}
void mg_lwip_if_udp_send(struct mg_connection *nc, const void *buf,
size_t len) {
mbuf_append(&nc->send_mbuf, buf, len);
mg_lwip_mgr_schedule_poll(nc->mgr);
return can_send;
}
struct tcp_recved_ctx {
@ -654,27 +561,35 @@ void tcp_recved_tcpip(void *arg) {
tcp_recved(ctx->tpcb, ctx->len);
}
void mg_lwip_if_recved(struct mg_connection *nc, size_t len) {
if (nc->flags & MG_F_UDP) return;
static int mg_lwip_if_tcp_recv(struct mg_connection *nc, void *buf,
size_t len) {
int res = 0;
char *bufp = buf;
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
if (nc->sock == INVALID_SOCKET || cs->pcb.tcp == NULL) {
DBG(("%p invalid socket", nc));
return;
if (nc->sock == INVALID_SOCKET) return -1;
mgos_lock();
while (cs->rx_chain != NULL && len > 0) {
struct pbuf *seg = cs->rx_chain;
size_t seg_len = (seg->len - cs->rx_offset);
size_t copy_len = MIN(len, seg_len);
pbuf_copy_partial(seg, bufp, copy_len, cs->rx_offset);
len -= copy_len;
res += copy_len;
bufp += copy_len;
cs->rx_offset += copy_len;
if (cs->rx_offset == cs->rx_chain->len) {
cs->rx_chain = pbuf_dechain(cs->rx_chain);
pbuf_free(seg);
cs->rx_offset = 0;
}
}
DBG(("%p %p %u %u", nc, cs->pcb.tcp, len,
(cs->rx_chain ? cs->rx_chain->tot_len : 0)));
struct tcp_recved_ctx ctx = {.tpcb = cs->pcb.tcp, .len = len};
#if MG_ENABLE_SSL
if (!(nc->flags & MG_F_SSL)) {
mgos_unlock();
if (res > 0) {
struct tcp_recved_ctx ctx = {.tpcb = cs->pcb.tcp, .len = res};
tcpip_callback(tcp_recved_tcpip, &ctx);
} else {
/* Currently SSL acknowledges data immediately.
* TODO(rojer): Find a way to propagate mg_lwip_if_recved. */
}
#else
tcpip_callback(tcp_recved_tcpip, &ctx);
#endif
mbuf_trim(&nc->recv_mbuf);
return res;
}
int mg_lwip_if_create_conn(struct mg_connection *nc) {
@ -763,7 +678,8 @@ void mg_lwip_if_sock_set(struct mg_connection *nc, sock_t sock) {
mg_lwip_if_connect_udp, \
mg_lwip_if_tcp_send, \
mg_lwip_if_udp_send, \
mg_lwip_if_recved, \
mg_lwip_if_tcp_recv, \
mg_lwip_if_udp_recv, \
mg_lwip_if_create_conn, \
mg_lwip_if_destroy_conn, \
mg_lwip_if_sock_set, \

View File

@ -30,9 +30,9 @@ struct mg_lwip_conn_state {
/* Last SSL write size, for retries. */
int last_ssl_write_size;
/* Whether MG_SIG_RECV is already pending for this connection */
int recv_pending : 1;
int recv_pending;
/* Whether the connection is about to close, just `rx_chain` needs to drain */
int draining_rx_chain : 1;
int draining_rx_chain;
};
enum mg_sig_type {

View File

@ -1,197 +0,0 @@
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* All rights reserved
*/
#if MG_ENABLE_SSL && MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL
#include "common/mg_mem.h"
#include "common/cs_dbg.h"
#include <lwip/pbuf.h>
#include <lwip/tcp.h>
#ifndef MG_LWIP_SSL_IO_SIZE
#define MG_LWIP_SSL_IO_SIZE 1024
#endif
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
void mg_lwip_ssl_do_hs(struct mg_connection *nc) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
int server_side = (nc->listener != NULL);
enum mg_ssl_if_result res;
if (nc->flags & MG_F_CLOSE_IMMEDIATELY) return;
res = mg_ssl_if_handshake(nc);
DBG(("%p %lu %d %d", nc, nc->flags, server_side, res));
if (res != MG_SSL_OK) {
if (res == MG_SSL_WANT_WRITE) {
nc->flags |= MG_F_WANT_WRITE;
cs->err = 0;
} else if (res == MG_SSL_WANT_READ) {
/*
* Nothing to do in particular, we are callback-driven.
* What we definitely do not need anymore is SSL reading (nothing left).
*/
nc->flags &= ~MG_F_WANT_READ;
cs->err = 0;
} else {
cs->err = res;
if (server_side) {
mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
} else {
mg_lwip_post_signal(MG_SIG_CONNECT_RESULT, nc);
}
}
} else {
cs->err = 0;
nc->flags &= ~MG_F_WANT_WRITE;
/*
* Handshake is done. Schedule a read immediately to consume app data
* which may already be waiting.
*/
nc->flags |= (MG_F_SSL_HANDSHAKE_DONE | MG_F_WANT_READ);
if (server_side) {
mg_lwip_accept_conn(nc, cs->pcb.tcp);
} else {
mg_lwip_post_signal(MG_SIG_CONNECT_RESULT, nc);
}
}
}
void mg_lwip_ssl_send(struct mg_connection *nc) {
if (nc->sock == INVALID_SOCKET) {
DBG(("%p invalid socket", nc));
return;
}
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
/* It's ok if the buffer is empty. Return value of 0 may also be valid. */
int len = cs->last_ssl_write_size;
if (len == 0) {
len = MIN(MG_LWIP_SSL_IO_SIZE, nc->send_mbuf.len);
}
int ret = mg_ssl_if_write(nc, nc->send_mbuf.buf, len);
DBG(("%p SSL_write %u = %d", nc, len, ret));
if (ret > 0) {
mg_if_sent_cb(nc, ret);
cs->last_ssl_write_size = 0;
} else if (ret < 0) {
/* This is tricky. We must remember the exact data we were sending to retry
* exactly the same send next time. */
cs->last_ssl_write_size = len;
}
if (ret == len) {
nc->flags &= ~MG_F_WANT_WRITE;
} else if (ret == MG_SSL_WANT_WRITE) {
nc->flags |= MG_F_WANT_WRITE;
} else {
mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
}
}
void mg_lwip_ssl_recv(struct mg_connection *nc) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
/* Don't deliver data before connect callback */
if (nc->flags & MG_F_CONNECTING) return;
while (nc->recv_mbuf.len < nc->recv_mbuf_limit) {
char *buf = (char *) MG_MALLOC(MG_LWIP_SSL_IO_SIZE);
if (buf == NULL) return;
int ret = mg_ssl_if_read(nc, buf, MG_LWIP_SSL_IO_SIZE);
DBG(("%p %p SSL_read %u = %d", nc, cs->rx_chain, MG_LWIP_SSL_IO_SIZE, ret));
if (ret <= 0) {
MG_FREE(buf);
if (ret == MG_SSL_WANT_WRITE) {
nc->flags |= MG_F_WANT_WRITE;
return;
} else if (ret == MG_SSL_WANT_READ) {
/*
* Nothing to do in particular, we are callback-driven.
* What we definitely do not need anymore is SSL reading (nothing left).
*/
nc->flags &= ~MG_F_WANT_READ;
cs->err = 0;
return;
} else {
mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc);
return;
}
} else {
mg_if_recv_tcp_cb(nc, buf, ret, 1 /* own */);
}
}
}
#ifdef KR_VERSION
ssize_t kr_send(int fd, const void *buf, size_t len) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) fd;
int ret = mg_lwip_tcp_write(cs->nc, buf, len);
DBG(("%p mg_lwip_tcp_write %u = %d", cs->nc, len, ret));
if (ret == 0) ret = KR_IO_WOULDBLOCK;
return ret;
}
ssize_t kr_recv(int fd, void *buf, size_t len) {
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) fd;
struct pbuf *seg = cs->rx_chain;
if (seg == NULL) {
DBG(("%u - nothing to read", len));
return KR_IO_WOULDBLOCK;
}
size_t seg_len = (seg->len - cs->rx_offset);
DBG(("%u %u %u %u", len, cs->rx_chain->len, seg_len, cs->rx_chain->tot_len));
len = MIN(len, seg_len);
pbuf_copy_partial(seg, buf, len, cs->rx_offset);
cs->rx_offset += len;
tcp_recved(cs->pcb.tcp, len);
if (cs->rx_offset == cs->rx_chain->len) {
cs->rx_chain = pbuf_dechain(cs->rx_chain);
pbuf_free(seg);
cs->rx_offset = 0;
}
return len;
}
#elif MG_SSL_IF == MG_SSL_IF_MBEDTLS
int ssl_socket_send(void *ctx, const unsigned char *buf, size_t len) {
struct mg_connection *nc = (struct mg_connection *) ctx;
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
int ret = mg_lwip_tcp_write(cs->nc, buf, len);
if (ret == 0) ret = MBEDTLS_ERR_SSL_WANT_WRITE;
LOG(LL_DEBUG, ("%p %d -> %d", nc, len, ret));
return ret;
}
int ssl_socket_recv(void *ctx, unsigned char *buf, size_t len) {
struct mg_connection *nc = (struct mg_connection *) ctx;
struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock;
struct pbuf *seg = cs->rx_chain;
if (seg == NULL) {
DBG(("%u - nothing to read", len));
return MBEDTLS_ERR_SSL_WANT_READ;
}
size_t seg_len = (seg->len - cs->rx_offset);
DBG(("%u %u %u %u", len, cs->rx_chain->len, seg_len, cs->rx_chain->tot_len));
mgos_lock();
len = MIN(len, seg_len);
pbuf_copy_partial(seg, buf, len, cs->rx_offset);
cs->rx_offset += len;
/* TCP PCB may be NULL if connection has already been closed
* but we still have data to deliver to SSL. */
if (cs->pcb.tcp != NULL) tcp_recved(cs->pcb.tcp, len);
if (cs->rx_offset == cs->rx_chain->len) {
cs->rx_chain = pbuf_dechain(cs->rx_chain);
pbuf_free(seg);
cs->rx_offset = 0;
}
mgos_unlock();
LOG(LL_DEBUG, ("%p <- %d", nc, (int) len));
return len;
}
#endif
#endif /* MG_ENABLE_SSL && MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL */

View File

@ -22,7 +22,9 @@
#endif
#define MG_NET_IF MG_NET_IF_SIMPLELINK
#ifndef MG_SSL_IF
#define MG_SSL_IF MG_SSL_IF_SIMPLELINK
#endif
/* Only SPIFFS supports directories, SLFS does not. */
#if defined(CC3220_FS_SPIFFS) && !defined(MG_ENABLE_DIRECTORY_LISTING)

View File

@ -17,7 +17,7 @@ static sock_t mg_open_listening_socket(struct mg_connection *nc,
union socket_address *sa, int type,
int proto);
void mg_set_non_blocking_mode(sock_t sock) {
static void mg_set_non_blocking_mode(sock_t sock) {
SlSockNonblocking_t opt;
#if SL_MAJOR_VERSION_NUM < 2
opt.NonblockingEnabled = 1;
@ -31,17 +31,19 @@ static int mg_is_error(int n) {
return (n < 0 && n != SL_ERROR_BSD_EALREADY && n != SL_ERROR_BSD_EAGAIN);
}
void mg_sl_if_connect_tcp(struct mg_connection *nc,
const union socket_address *sa) {
static void mg_sl_if_connect_tcp(struct mg_connection *nc,
const union socket_address *sa) {
int proto = 0;
#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
if (nc->flags & MG_F_SSL) proto = SL_SEC_SOCKET;
#endif
sock_t sock = sl_Socket(AF_INET, SOCK_STREAM, proto);
if (sock < 0) {
nc->err = sock;
goto out;
}
mg_sock_set(nc, sock);
#if MG_ENABLE_SSL
#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
nc->err = sl_set_ssl_opts(sock, nc);
if (nc->err != 0) goto out;
#endif
@ -51,7 +53,7 @@ out:
ntohs(sa->sin.sin_port), nc->sock, proto, nc->err));
}
void mg_sl_if_connect_udp(struct mg_connection *nc) {
static void mg_sl_if_connect_udp(struct mg_connection *nc) {
sock_t sock = sl_Socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
nc->err = sock;
@ -61,7 +63,8 @@ void mg_sl_if_connect_udp(struct mg_connection *nc) {
nc->err = 0;
}
int mg_sl_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) {
static int mg_sl_if_listen_tcp(struct mg_connection *nc,
union socket_address *sa) {
int proto = 0;
if (nc->flags & MG_F_SSL) proto = SL_SEC_SOCKET;
sock_t sock = mg_open_listening_socket(nc, sa, SOCK_STREAM, proto);
@ -70,27 +73,50 @@ int mg_sl_if_listen_tcp(struct mg_connection *nc, union socket_address *sa) {
return 0;
}
int mg_sl_if_listen_udp(struct mg_connection *nc, union socket_address *sa) {
static int mg_sl_if_listen_udp(struct mg_connection *nc,
union socket_address *sa) {
sock_t sock = mg_open_listening_socket(nc, sa, SOCK_DGRAM, 0);
if (sock == INVALID_SOCKET) return (errno ? errno : 1);
mg_sock_set(nc, sock);
return 0;
}
void mg_sl_if_tcp_send(struct mg_connection *nc, const void *buf, size_t len) {
mbuf_append(&nc->send_mbuf, buf, len);
static int mg_sl_if_tcp_send(struct mg_connection *nc, const void *buf,
size_t len) {
int n = (int) sl_Send(nc->sock, buf, len, 0);
if (n < 0 && !mg_is_error(n)) n = 0;
return n;
}
void mg_sl_if_udp_send(struct mg_connection *nc, const void *buf, size_t len) {
mbuf_append(&nc->send_mbuf, buf, len);
static int mg_sl_if_udp_send(struct mg_connection *nc, const void *buf,
size_t len) {
int n = sl_SendTo(nc->sock, buf, len, 0, &nc->sa.sa, sizeof(nc->sa.sin));
if (n < 0 && !mg_is_error(n)) n = 0;
return n;
}
void mg_sl_if_recved(struct mg_connection *nc, size_t len) {
(void) nc;
(void) len;
static int mg_sl_if_tcp_recv(struct mg_connection *nc, void *buf, size_t len) {
int n = sl_Recv(nc->sock, buf, len, 0);
if (n == 0) {
/* Orderly shutdown of the socket, try flushing output. */
nc->flags |= MG_F_SEND_AND_CLOSE;
} else if (n < 0 && !mg_is_error(n)) {
n = 0;
}
return n;
}
int mg_sl_if_create_conn(struct mg_connection *nc) {
static int mg_sl_if_udp_recv(struct mg_connection *nc, void *buf, size_t len,
union socket_address *sa, size_t *sa_len) {
SlSocklen_t sa_len_t = *sa_len;
int n = sl_RecvFrom(nc->sock, buf, MG_UDP_RECV_BUFFER_SIZE, 0,
(SlSockAddr_t *) sa, &sa_len_t);
*sa_len = sa_len_t;
if (n < 0 && !mg_is_error(n)) n = 0;
return n;
}
static int mg_sl_if_create_conn(struct mg_connection *nc) {
(void) nc;
return 1;
}
@ -121,7 +147,6 @@ static int mg_accept_conn(struct mg_connection *lc) {
DBG(("%p conn from %s:%d", nc, inet_ntoa(sa.sin.sin_addr),
ntohs(sa.sin.sin_port)));
mg_sock_set(nc, sock);
if (nc->flags & MG_F_SSL) nc->flags |= MG_F_SSL_HANDSHAKE_DONE;
mg_if_accept_tcp_cb(nc, &sa, sa_len);
return 1;
}
@ -135,11 +160,11 @@ static sock_t mg_open_listening_socket(struct mg_connection *nc,
(sa->sa.sa_family == AF_INET) ? sizeof(sa->sin) : sizeof(sa->sin6);
sock_t sock = sl_Socket(sa->sa.sa_family, type, proto);
if (sock < 0) return sock;
#if MG_ENABLE_SSL && MG_SSL_IF == MG_SSL_IF_SIMPLELINK
if ((r = sl_set_ssl_opts(sock, nc)) < 0) goto clean;
#endif
if ((r = sl_Bind(sock, &sa->sa, sa_len)) < 0) goto clean;
if (type != SOCK_DGRAM) {
#if MG_ENABLE_SSL
if ((r = sl_set_ssl_opts(sock, nc)) < 0) goto clean;
#endif
if ((r = sl_Listen(sock, SOMAXCONN)) < 0) goto clean;
}
mg_set_non_blocking_mode(sock);
@ -151,86 +176,18 @@ clean:
return sock;
}
static void mg_write_to_socket(struct mg_connection *nc) {
struct mbuf *io = &nc->send_mbuf;
int n = 0;
if (nc->flags & MG_F_UDP) {
n = sl_SendTo(nc->sock, io->buf, io->len, 0, &nc->sa.sa,
sizeof(nc->sa.sin));
DBG(("%p %d %d %d %s:%hu", nc, nc->sock, n, errno,
inet_ntoa(nc->sa.sin.sin_addr), ntohs(nc->sa.sin.sin_port)));
} else {
n = (int) sl_Send(nc->sock, io->buf, io->len, 0);
DBG(("%p %d bytes -> %d", nc, n, nc->sock));
}
if (n > 0) {
mg_if_sent_cb(nc, n);
} else if (n < 0 && mg_is_error(n)) {
/* Something went wrong, drop the connection. */
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
}
}
MG_INTERNAL size_t recv_avail_size(struct mg_connection *conn, size_t max) {
size_t avail;
if (conn->recv_mbuf_limit < conn->recv_mbuf.len) return 0;
avail = conn->recv_mbuf_limit - conn->recv_mbuf.len;
return avail > max ? max : avail;
}
static void mg_handle_tcp_read(struct mg_connection *conn) {
int n = 0;
char *buf = (char *) MG_MALLOC(MG_TCP_RECV_BUFFER_SIZE);
if (buf == NULL) {
DBG(("OOM"));
return;
}
n = (int) sl_Recv(conn->sock, buf,
recv_avail_size(conn, MG_TCP_RECV_BUFFER_SIZE), 0);
DBG(("%p %d bytes <- %d", conn, n, conn->sock));
if (n > 0) {
mg_if_recv_tcp_cb(conn, buf, n, 1 /* own */);
} else {
MG_FREE(buf);
}
if (n == 0) {
/* Orderly shutdown of the socket, try flushing output. */
conn->flags |= MG_F_SEND_AND_CLOSE;
} else if (mg_is_error(n)) {
conn->flags |= MG_F_CLOSE_IMMEDIATELY;
}
}
static void mg_handle_udp_read(struct mg_connection *nc) {
char *buf = (char *) MG_MALLOC(MG_UDP_RECV_BUFFER_SIZE);
if (buf == NULL) return;
union socket_address sa;
socklen_t sa_len = sizeof(sa);
int n = sl_RecvFrom(nc->sock, buf, MG_UDP_RECV_BUFFER_SIZE, 0,
(SlSockAddr_t *) &sa, &sa_len);
DBG(("%p %d bytes from %s:%d", nc, n, inet_ntoa(nc->sa.sin.sin_addr),
ntohs(nc->sa.sin.sin_port)));
if (n > 0) {
mg_if_recv_udp_cb(nc, buf, n, &sa, sa_len);
} else {
MG_FREE(buf);
}
}
#define _MG_F_FD_CAN_READ 1
#define _MG_F_FD_CAN_WRITE 1 << 1
#define _MG_F_FD_ERROR 1 << 2
void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
DBG(("%p fd=%d fd_flags=%d nc_flags=%lu rmbl=%d smbl=%d", nc, nc->sock,
DBG(("%p fd=%d fd_flags=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock,
fd_flags, nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
if (!mg_if_poll(nc, now)) return;
if (nc->flags & MG_F_CONNECTING) {
if (nc->flags & MG_F_UDP || nc->err != SL_ERROR_BSD_EALREADY) {
if ((nc->flags & MG_F_UDP) || nc->err != SL_ERROR_BSD_EALREADY) {
mg_if_connect_cb(nc, nc->err);
} else {
/* In SimpleLink, to get status of non-blocking connect() we need to wait
@ -252,9 +209,6 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
) {
nc->err = 0;
}
if (nc->flags & MG_F_SSL && nc->err == 0) {
nc->flags |= MG_F_SSL_HANDSHAKE_DONE;
}
mg_if_connect_cb(nc, nc->err);
}
}
@ -264,28 +218,21 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
if (fd_flags & _MG_F_FD_CAN_READ) {
if (nc->flags & MG_F_UDP) {
mg_handle_udp_read(nc);
mg_if_can_recv_cb(nc);
} else {
if (nc->flags & MG_F_LISTENING) {
mg_accept_conn(nc);
} else {
mg_handle_tcp_read(nc);
mg_if_can_recv_cb(nc);
}
}
}
if (!(nc->flags & MG_F_CLOSE_IMMEDIATELY)) {
if ((fd_flags & _MG_F_FD_CAN_WRITE) && nc->send_mbuf.len > 0) {
mg_write_to_socket(nc);
}
if (!(fd_flags & (_MG_F_FD_CAN_READ | _MG_F_FD_CAN_WRITE))) {
mg_if_poll(nc, now);
}
mg_if_timer(nc, now);
if (fd_flags & _MG_F_FD_CAN_WRITE) {
mg_if_can_send_cb(nc);
}
DBG(("%p after fd=%d nc_flags=%lu rmbl=%d smbl=%d", nc, nc->sock, nc->flags,
DBG(("%p after fd=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock, nc->flags,
(int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
}
@ -406,14 +353,6 @@ time_t mg_sl_if_poll(struct mg_iface *iface, int timeout_ms) {
mg_mgr_handle_conn(nc, fd_flags, now);
}
for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
tmp = nc->next;
if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) ||
(nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE))) {
mg_close_conn(nc);
}
}
return now;
}
@ -464,7 +403,8 @@ void sl_restart_cb(struct mg_mgr *mgr) {
mg_sl_if_connect_udp, \
mg_sl_if_tcp_send, \
mg_sl_if_udp_send, \
mg_sl_if_recved, \
mg_sl_if_tcp_recv, \
mg_sl_if_udp_recv, \
mg_sl_if_create_conn, \
mg_sl_if_destroy_conn, \
mg_sl_if_sock_set, \

View File

@ -54,6 +54,31 @@ enum mg_ssl_if_result mg_ssl_if_conn_init(
return MG_SSL_OK;
}
enum mg_ssl_if_result mg_ssl_if_conn_accept(struct mg_connection *nc,
struct mg_connection *lc) {
/* SimpleLink does everything for us, nothing for us to do. */
(void) nc;
(void) lc;
return MG_SSL_OK;
}
enum mg_ssl_if_result mg_ssl_if_handshake(struct mg_connection *nc) {
/* SimpleLink has already performed the handshake, nothing to do. */
return MG_SSL_OK;
}
int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t len) {
/* SimpelLink handles TLS, so this is just a pass-through. */
int n = nc->iface->vtable->tcp_recv(nc, buf, len);
if (n == 0) nc->flags |= MG_F_WANT_READ;
return n;
}
int mg_ssl_if_write(struct mg_connection *nc, const void *buf, size_t len) {
/* SimpelLink handles TLS, so this is just a pass-through. */
return nc->iface->vtable->tcp_send(nc, buf, len);
}
void mg_ssl_if_conn_close_notify(struct mg_connection *nc) {
/* Nothing to do */
(void) nc;
@ -154,56 +179,59 @@ int sl_set_ssl_opts(int sock, struct mg_connection *nc) {
const struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
DBG(("%p ssl ctx: %p", nc, ctx));
if (ctx != NULL) {
DBG(("%p %s,%s,%s,%s", nc, (ctx->ssl_cert ? ctx->ssl_cert : "-"),
(ctx->ssl_key ? ctx->ssl_cert : "-"),
(ctx->ssl_ca_cert ? ctx->ssl_ca_cert : "-"),
(ctx->ssl_server_name ? ctx->ssl_server_name : "-")));
if (ctx->ssl_cert != NULL && ctx->ssl_key != NULL) {
char *ssl_cert = sl_pem2der(ctx->ssl_cert);
char *ssl_key = sl_pem2der(ctx->ssl_key);
if (ssl_cert != NULL && ssl_key != NULL) {
err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME, ssl_cert,
strlen(ssl_cert));
LOG(LL_INFO, ("CERTIFICATE_FILE_NAME %s -> %d", ssl_cert, err));
if (ctx == NULL) return 0;
DBG(("%p %s,%s,%s,%s", nc, (ctx->ssl_cert ? ctx->ssl_cert : "-"),
(ctx->ssl_key ? ctx->ssl_cert : "-"),
(ctx->ssl_ca_cert ? ctx->ssl_ca_cert : "-"),
(ctx->ssl_server_name ? ctx->ssl_server_name : "-")));
if (ctx->ssl_cert != NULL && ctx->ssl_key != NULL) {
char *ssl_cert = sl_pem2der(ctx->ssl_cert), *ssl_key = NULL;
if (ssl_cert != NULL) {
err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME, ssl_cert,
strlen(ssl_cert));
MG_FREE(ssl_cert);
LOG(LL_DEBUG, ("CERTIFICATE_FILE_NAME %s -> %d", ssl_cert, err));
ssl_key = sl_pem2der(ctx->ssl_key);
if (ssl_key != NULL) {
err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
SL_SO_SECURE_FILES_PRIVATE_KEY_FILE_NAME, ssl_key,
strlen(ssl_key));
LOG(LL_INFO, ("PRIVATE_KEY_FILE_NAME %s -> %d", ssl_key, err));
MG_FREE(ssl_key);
LOG(LL_DEBUG, ("PRIVATE_KEY_FILE_NAME %s -> %d", ssl_key, err));
} else {
err = -1;
}
MG_FREE(ssl_cert);
MG_FREE(ssl_key);
} else {
err = -1;
}
if (err != 0) return err;
}
if (ctx->ssl_ca_cert != NULL) {
if (ctx->ssl_ca_cert[0] != '\0') {
char *ssl_ca_cert = sl_pem2der(ctx->ssl_ca_cert);
if (ssl_ca_cert != NULL) {
err =
sl_SetSockOpt(sock, SL_SOL_SOCKET, SL_SO_SECURE_FILES_CA_FILE_NAME,
ssl_ca_cert, strlen(ssl_ca_cert));
LOG(LL_DEBUG, ("CA_FILE_NAME %s -> %d", ssl_ca_cert, err));
} else {
err = -1;
}
MG_FREE(ssl_ca_cert);
if (err != 0) return err;
}
if (ctx->ssl_ca_cert != NULL) {
if (ctx->ssl_ca_cert[0] != '\0') {
char *ssl_ca_cert = sl_pem2der(ctx->ssl_ca_cert);
if (ssl_ca_cert != NULL) {
err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
SL_SO_SECURE_FILES_CA_FILE_NAME, ssl_ca_cert,
strlen(ssl_ca_cert));
LOG(LL_INFO, ("CA_FILE_NAME %s -> %d", ssl_ca_cert, err));
} else {
err = -1;
}
MG_FREE(ssl_ca_cert);
if (err != 0) return err;
}
}
if (ctx->ssl_server_name != NULL) {
err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
SL_SO_SECURE_DOMAIN_NAME_VERIFICATION,
ctx->ssl_server_name, strlen(ctx->ssl_server_name));
DBG(("DOMAIN_NAME_VERIFICATION %s -> %d", ctx->ssl_server_name, err));
/* Domain name verificationw as added in a NWP service pack, older
* versions return SL_ERROR_BSD_ENOPROTOOPT. There isn't much we can do
* about it,
* so we ignore the error. */
if (err != 0 && err != SL_ERROR_BSD_ENOPROTOOPT) return err;
}
}
if (ctx->ssl_server_name != NULL) {
err = sl_SetSockOpt(sock, SL_SOL_SOCKET,
SL_SO_SECURE_DOMAIN_NAME_VERIFICATION,
ctx->ssl_server_name, strlen(ctx->ssl_server_name));
DBG(("DOMAIN_NAME_VERIFICATION %s -> %d", ctx->ssl_server_name, err));
/* Domain name verificationw as added in a NWP service pack, older
* versions return SL_ERROR_BSD_ENOPROTOOPT. There isn't much we can do
* about it,
* so we ignore the error. */
if (err != 0 && err != SL_ERROR_BSD_ENOPROTOOPT) return err;
}
return 0;
}

View File

@ -96,7 +96,6 @@ SOURCES = $(COMMON)/mg_mem.h \
$(COMMON)/platforms/lwip/mg_lwip_net_if.h \
$(COMMON)/platforms/lwip/mg_lwip_net_if.c \
$(COMMON)/platforms/lwip/mg_lwip_ev_mgr.c \
$(COMMON)/platforms/lwip/mg_lwip_ssl_if.c \
$(COMMON)/platforms/wince/wince_libc.c \
$(COMMON)/platforms/pic32/pic32_net_if.h \
$(COMMON)/platforms/pic32/pic32_net_if.c \

View File

@ -24,6 +24,13 @@
#define MG_MAX_HOST_LEN 200
#ifndef MG_TCP_IO_SIZE
#define MG_TCP_IO_SIZE 1460
#endif
#ifndef MG_UDP_IO_SIZE
#define MG_UDP_IO_SIZE 1460
#endif
#define MG_COPY_COMMON_CONNECTION_OPTIONS(dst, src) \
memcpy(dst, src, sizeof(*dst));
@ -64,8 +71,6 @@ MG_INTERNAL void mg_remove_conn(struct mg_connection *conn) {
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 nesting_level = 0;
nesting_level++;
if (ev_handler == NULL) {
/*
* If protocol handler is specified, call it. Otherwise, call user-specified
@ -74,7 +79,7 @@ MG_INTERNAL void mg_call(struct mg_connection *nc,
ev_handler = nc->proto_handler ? nc->proto_handler : nc->handler;
}
if (ev != MG_EV_POLL) {
DBG(("%p %s ev=%d ev_data=%p flags=%lu rmbl=%d smbl=%d", nc,
DBG(("%p %s ev=%d ev_data=%p flags=0x%lx rmbl=%d smbl=%d", nc,
ev_handler == nc->handler ? "user" : "proto", ev, ev_data, nc->flags,
(int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
}
@ -87,33 +92,24 @@ MG_INTERNAL void mg_call(struct mg_connection *nc,
#endif
if (ev_handler != NULL) {
unsigned long flags_before = nc->flags;
size_t recv_mbuf_before = nc->recv_mbuf.len, recved;
ev_handler(nc, ev, ev_data MG_UD_ARG(user_data));
recved = (recv_mbuf_before - nc->recv_mbuf.len);
/* Prevent user handler from fiddling with system flags. */
if (ev_handler == nc->handler && nc->flags != flags_before) {
nc->flags = (flags_before & ~_MG_CALLBACK_MODIFIABLE_FLAGS_MASK) |
(nc->flags & _MG_CALLBACK_MODIFIABLE_FLAGS_MASK);
}
/* It's important to not double-count recved bytes, and since mg_call can be
* called recursively (e.g. proto_handler invokes user handler), we keep
* track of recursion and only report received bytes at the top level. */
if (nesting_level == 1 && recved > 0 && !(nc->flags & MG_F_UDP)) {
nc->iface->vtable->recved(nc, recved);
}
}
if (ev != MG_EV_POLL) {
DBG(("%p after %s flags=%lu rmbl=%d smbl=%d", nc,
DBG(("%p after %s flags=0x%lx rmbl=%d smbl=%d", nc,
ev_handler == nc->handler ? "user" : "proto", nc->flags,
(int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
}
nesting_level--;
#if !MG_ENABLE_CALLBACK_USERDATA
(void) user_data;
#endif
}
void mg_if_timer(struct mg_connection *c, double now) {
MG_INTERNAL void mg_timer(struct mg_connection *c, double now) {
if (c->ev_timer_time > 0 && now >= c->ev_timer_time) {
double old_value = c->ev_timer_time;
c->ev_timer_time = 0;
@ -121,13 +117,45 @@ void mg_if_timer(struct mg_connection *c, double now) {
}
}
void mg_if_poll(struct mg_connection *nc, time_t now) {
if (!(nc->flags & MG_F_SSL) || (nc->flags & MG_F_SSL_HANDSHAKE_DONE)) {
mg_call(nc, NULL, nc->user_data, MG_EV_POLL, &now);
MG_INTERNAL size_t recv_avail_size(struct mg_connection *conn, size_t max) {
size_t avail;
if (conn->recv_mbuf_limit < conn->recv_mbuf.len) return 0;
avail = conn->recv_mbuf_limit - conn->recv_mbuf.len;
return avail > max ? max : avail;
}
static int mg_do_recv(struct mg_connection *nc);
int mg_if_poll(struct mg_connection *nc, double now) {
if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) ||
(nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE))) {
mg_close_conn(nc);
return 0;
}
#if MG_ENABLE_SSL
if ((nc->flags & (MG_F_SSL | MG_F_LISTENING | MG_F_CONNECTING)) == MG_F_SSL) {
/* SSL library may have data to be delivered to the app in its buffers,
* drain them. */
int recved = 0;
do {
if (nc->flags & (MG_F_WANT_READ | MG_F_WANT_WRITE)) break;
if (recv_avail_size(nc, MG_TCP_IO_SIZE) <= 0) break;
recved = mg_do_recv(nc);
} while (recved > 0);
}
#endif /* MG_ENABLE_SSL */
mg_timer(nc, now);
{
time_t now_t = (time_t) now;
mg_call(nc, NULL, nc->user_data, MG_EV_POLL, &now_t);
}
return 1;
}
void mg_destroy_conn(struct mg_connection *conn, int destroy_if) {
if (conn->sock != INVALID_SOCKET) { /* Don't print timer-only conns */
LOG(LL_DEBUG, ("%p 0x%lx %d", conn, conn->flags, destroy_if));
}
if (destroy_if) conn->iface->vtable->destroy_conn(conn);
if (conn->proto_data != NULL && conn->proto_data_destructor != NULL) {
conn->proto_data_destructor(conn->proto_data);
@ -143,7 +171,6 @@ void mg_destroy_conn(struct mg_connection *conn, int destroy_if) {
}
void mg_close_conn(struct mg_connection *conn) {
DBG(("%p %lu %d", conn, conn->flags, conn->sock));
#if MG_ENABLE_SSL
if (conn->flags & MG_F_SSL_HANDSHAKE_DONE) {
mg_ssl_if_conn_close_notify(conn);
@ -180,15 +207,6 @@ void mg_mgr_init_opt(struct mg_mgr *m, void *user_data,
signal(SIGPIPE, SIG_IGN);
#endif
#if MG_ENABLE_SSL
{
static int init_done;
if (!init_done) {
mg_ssl_if_init();
init_done++;
}
}
#endif
{
int i;
if (opts.num_ifaces == 0) {
@ -211,6 +229,15 @@ void mg_mgr_init_opt(struct mg_mgr *m, void *user_data,
}
DBG(("=================================="));
DBG(("init mgr=%p", m));
#if MG_ENABLE_SSL
{
static int init_done;
if (!init_done) {
mg_ssl_if_init();
init_done++;
}
}
#endif
}
void mg_mgr_free(struct mg_mgr *m) {
@ -453,6 +480,37 @@ MG_INTERNAL int mg_parse_address(const char *str, union socket_address *sa,
return port < 0xffffUL && (ch == '\0' || ch == ',' || isspace(ch)) ? len : -1;
}
#if MG_ENABLE_SSL
MG_INTERNAL void mg_ssl_handshake(struct mg_connection *nc) {
int err = 0;
int server_side = (nc->listener != NULL);
enum mg_ssl_if_result res;
if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) return;
res = mg_ssl_if_handshake(nc);
LOG(LL_DEBUG, ("%p %d res %d", nc, server_side, res));
if (res == MG_SSL_OK) {
nc->flags |= MG_F_SSL_HANDSHAKE_DONE;
nc->flags &= ~(MG_F_WANT_READ | MG_F_WANT_WRITE);
if (server_side) {
mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
} else {
mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err);
}
} else if (res == MG_SSL_WANT_READ) {
nc->flags |= MG_F_WANT_READ;
} else if (res == MG_SSL_WANT_WRITE) {
nc->flags |= MG_F_WANT_WRITE;
} else {
if (!server_side) {
err = res;
mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err);
}
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
}
}
#endif /* MG_ENABLE_SSL */
struct mg_connection *mg_if_accept_new_conn(struct mg_connection *lc) {
struct mg_add_sock_opts opts;
struct mg_connection *nc;
@ -466,95 +524,125 @@ struct mg_connection *mg_if_accept_new_conn(struct mg_connection *lc) {
nc->iface = lc->iface;
if (lc->flags & MG_F_SSL) nc->flags |= MG_F_SSL;
mg_add_conn(nc->mgr, nc);
DBG(("%p %p %d %d", lc, nc, nc->sock, (int) nc->flags));
LOG(LL_DEBUG, ("%p %p %d %d", lc, nc, nc->sock, (int) nc->flags));
return nc;
}
void mg_if_accept_tcp_cb(struct mg_connection *nc, union socket_address *sa,
size_t sa_len) {
(void) sa_len;
LOG(LL_DEBUG, ("%p %s://%s:%hu", nc, (nc->flags & MG_F_UDP ? "udp" : "tcp"),
inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port)));
nc->sa = *sa;
mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
#if MG_ENABLE_SSL
if (nc->listener->flags & MG_F_SSL) {
nc->flags |= MG_F_SSL;
if (mg_ssl_if_conn_accept(nc, nc->listener) == MG_SSL_OK) {
mg_ssl_handshake(nc);
} else {
mg_close_conn(nc);
}
} else
#endif
{
mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
}
(void) sa_len;
}
void mg_send(struct mg_connection *nc, const void *buf, int len) {
nc->last_io_time = (time_t) mg_time();
mbuf_append(&nc->send_mbuf, buf, 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);
static int mg_do_recv(struct mg_connection *nc) {
int res = 0;
char *buf = NULL;
size_t len = (nc->flags & MG_F_UDP ? MG_UDP_IO_SIZE : MG_TCP_IO_SIZE);
if ((nc->flags & (MG_F_CLOSE_IMMEDIATELY | MG_F_CONNECTING)) ||
((nc->flags & MG_F_LISTENING) && !(nc->flags & MG_F_UDP))) {
return -1;
}
len = recv_avail_size(nc, len);
if (len == 0) return -2;
if (nc->recv_mbuf.size < nc->recv_mbuf.len + len) {
mbuf_resize(&nc->recv_mbuf, nc->recv_mbuf.len + len);
}
buf = nc->recv_mbuf.buf + nc->recv_mbuf.len;
len = nc->recv_mbuf.size - nc->recv_mbuf.len;
if (nc->flags & MG_F_UDP) {
nc->iface->vtable->udp_send(nc, buf, len);
res = mg_recv_udp(nc, buf, len);
} else {
nc->iface->vtable->tcp_send(nc, buf, len);
res = mg_recv_tcp(nc, buf, len);
}
return res;
}
void mg_if_sent_cb(struct mg_connection *nc, int num_sent) {
DBG(("%p %d", nc, num_sent));
#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
if (nc->mgr && nc->mgr->hexdump_file != NULL) {
char *buf = nc->send_mbuf.buf;
mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, num_sent, MG_EV_SEND);
}
#endif
if (num_sent < 0) {
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
} else {
mbuf_remove(&nc->send_mbuf, num_sent);
mbuf_trim(&nc->send_mbuf);
}
mg_call(nc, NULL, nc->user_data, MG_EV_SEND, &num_sent);
void mg_if_can_recv_cb(struct mg_connection *nc) {
mg_do_recv(nc);
}
MG_INTERNAL void mg_recv_common(struct mg_connection *nc, void *buf, int len,
int own) {
DBG(("%p %d %u", nc, len, (unsigned int) nc->recv_mbuf.len));
#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
if (nc->mgr && nc->mgr->hexdump_file != NULL) {
mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, len, MG_EV_RECV);
}
#endif
if (nc->flags & MG_F_CLOSE_IMMEDIATELY) {
DBG(("%p discarded %d bytes", nc, len));
/*
* This connection will not survive next poll. Do not deliver events,
* send data to /dev/null without acking.
*/
if (own) {
MG_FREE(buf);
static int mg_recv_tcp(struct mg_connection *nc, char *buf, size_t len) {
int n = 0;
#if MG_ENABLE_SSL
if (nc->flags & MG_F_SSL) {
if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
n = mg_ssl_if_read(nc, buf, len);
DBG(("%p <- %d bytes (SSL)", nc, n));
if (n < 0) {
if (n == MG_SSL_WANT_READ) {
nc->flags |= MG_F_WANT_READ;
n = 0;
} else {
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
}
} else if (n > 0) {
nc->flags &= ~MG_F_WANT_READ;
}
} else {
mg_ssl_handshake(nc);
}
return;
} else
#endif
{
n = nc->iface->vtable->tcp_recv(nc, buf, len);
DBG(("%p <- %d bytes", nc, n));
}
nc->last_io_time = (time_t) mg_time();
if (!own) {
mbuf_append(&nc->recv_mbuf, buf, len);
} else if (nc->recv_mbuf.len == 0) {
/* Adopt buf as recv_mbuf's backing store. */
mbuf_free(&nc->recv_mbuf);
nc->recv_mbuf.buf = (char *) buf;
nc->recv_mbuf.size = nc->recv_mbuf.len = len;
} else {
mbuf_append(&nc->recv_mbuf, buf, len);
MG_FREE(buf);
if (n > 0) {
nc->recv_mbuf.len += n;
nc->last_io_time = (time_t) mg_time();
#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
if (nc->mgr && nc->mgr->hexdump_file != NULL) {
mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV);
}
#endif
mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n);
} else if (n < 0) {
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
}
mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &len);
return n;
}
void mg_if_recv_tcp_cb(struct mg_connection *nc, void *buf, int len, int own) {
mg_recv_common(nc, buf, len, own);
}
void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
union socket_address *sa, size_t sa_len) {
assert(nc->flags & MG_F_UDP);
DBG(("%p %u", nc, (unsigned int) len));
static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len) {
int n = 0;
struct mg_connection *lc = nc;
union socket_address sa;
size_t sa_len = sizeof(sa);
n = nc->iface->vtable->udp_recv(lc, buf, len, &sa, &sa_len);
if (n < 0) {
lc->flags |= MG_F_CLOSE_IMMEDIATELY;
goto out;
}
if (nc->flags & MG_F_LISTENING) {
struct mg_connection *lc = nc;
/*
* Do we have an existing connection for this source?
* This is very inefficient for long connection lists.
*/
lc = nc;
for (nc = mg_next(lc->mgr, NULL); nc != NULL; nc = mg_next(lc->mgr, nc)) {
if (memcmp(&nc->sa.sa, &sa->sa, sa_len) == 0 && nc->listener == lc) {
if (memcmp(&nc->sa.sa, &sa.sa, sa_len) == 0 && nc->listener == lc) {
break;
}
}
@ -566,7 +654,7 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
if (nc != NULL) {
nc->sock = lc->sock;
nc->listener = lc;
nc->sa = *sa;
nc->sa = sa;
nc->proto_handler = lc->proto_handler;
nc->user_data = lc->user_data;
nc->recv_mbuf_limit = lc->recv_mbuf_limit;
@ -585,18 +673,88 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
nc->flags |= MG_F_SEND_AND_CLOSE;
mg_add_conn(lc->mgr, nc);
mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
} else {
DBG(("OOM"));
/* No return here, we still need to drop on the floor */
}
}
}
if (nc != NULL) {
mg_recv_common(nc, buf, len, 1);
} else {
/* Drop on the floor. */
MG_FREE(buf);
DBG(("%p <- %d bytes from %s:%d", nc, n, inet_ntoa(nc->sa.sin.sin_addr),
ntohs(nc->sa.sin.sin_port)));
if (nc == lc) {
nc->recv_mbuf.len += n;
} else {
mbuf_append(&nc->recv_mbuf, buf, n);
}
mbuf_trim(&lc->recv_mbuf);
lc->last_io_time = nc->last_io_time = (time_t) mg_time();
#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
if (nc->mgr && nc->mgr->hexdump_file != NULL) {
mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV);
}
#endif
mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n);
}
out:
mbuf_free(&lc->recv_mbuf);
return n;
}
void mg_if_can_send_cb(struct mg_connection *nc) {
int n = 0;
const char *buf = nc->send_mbuf.buf;
size_t len = nc->send_mbuf.len;
if (nc->flags & (MG_F_CLOSE_IMMEDIATELY | MG_F_CONNECTING)) {
return;
}
if (!(nc->flags & MG_F_UDP)) {
if (nc->flags & MG_F_LISTENING) return;
if (len > MG_TCP_IO_SIZE) len = MG_TCP_IO_SIZE;
}
#if MG_ENABLE_SSL
if (nc->flags & MG_F_SSL) {
if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
if (len > 0) {
n = mg_ssl_if_write(nc, buf, len);
DBG(("%p -> %d bytes (SSL)", nc, n));
}
if (n < 0) {
if (n == MG_SSL_WANT_WRITE) {
nc->flags |= MG_F_WANT_WRITE;
n = 0;
} else {
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
}
} else {
nc->flags &= ~MG_F_WANT_WRITE;
}
} else {
mg_ssl_handshake(nc);
}
} else
#endif
{
if (nc->flags & MG_F_UDP) {
n = nc->iface->vtable->udp_send(nc, buf, len);
} else {
n = nc->iface->vtable->tcp_send(nc, buf, len);
}
DBG(("%p -> %d bytes", nc, n));
}
#if !defined(NO_LIBC) && MG_ENABLE_HEXDUMP
if (n > 0 && nc->mgr && nc->mgr->hexdump_file != NULL) {
mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_SEND);
}
#endif
if (n < 0) {
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
} else if (n > 0) {
nc->last_io_time = (time_t) mg_time();
mbuf_remove(&nc->send_mbuf, n);
mbuf_trim(&nc->send_mbuf);
}
if (n != 0) mg_call(nc, NULL, nc->user_data, MG_EV_SEND, &n);
}
/*
@ -608,8 +766,8 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
MG_INTERNAL struct mg_connection *mg_do_connect(struct mg_connection *nc,
int proto,
union socket_address *sa) {
DBG(("%p %s://%s:%hu", nc, proto == SOCK_DGRAM ? "udp" : "tcp",
inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port)));
LOG(LL_DEBUG, ("%p %s://%s:%hu", nc, proto == SOCK_DGRAM ? "udp" : "tcp",
inet_ntoa(sa->sin.sin_addr), ntohs(sa->sin.sin_port)));
nc->flags |= MG_F_CONNECTING;
if (proto == SOCK_DGRAM) {
@ -622,12 +780,21 @@ MG_INTERNAL struct mg_connection *mg_do_connect(struct mg_connection *nc,
}
void mg_if_connect_cb(struct mg_connection *nc, int err) {
DBG(("%p connect, err=%d", nc, err));
LOG(LL_DEBUG,
("%p %s://%s:%hu -> %d", nc, (nc->flags & MG_F_UDP ? "udp" : "tcp"),
inet_ntoa(nc->sa.sin.sin_addr), ntohs(nc->sa.sin.sin_port), err));
nc->flags &= ~MG_F_CONNECTING;
if (err != 0) {
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
}
mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err);
#if MG_ENABLE_SSL
if (err == 0 && (nc->flags & MG_F_SSL)) {
mg_ssl_handshake(nc);
} else
#endif
{
mg_call(nc, NULL, nc->user_data, MG_EV_CONNECT, &err);
}
}
#if MG_ENABLE_ASYNC_RESOLVER
@ -717,7 +884,8 @@ struct mg_connection *mg_connect_opt(struct mg_mgr *mgr, const char *address,
#endif
#if MG_ENABLE_SSL
DBG(("%p %s %s,%s,%s", nc, address, (opts.ssl_cert ? opts.ssl_cert : "-"),
LOG(LL_DEBUG,
("%p %s %s,%s,%s", nc, address, (opts.ssl_cert ? opts.ssl_cert : "-"),
(opts.ssl_key ? opts.ssl_key : "-"),
(opts.ssl_ca_cert ? opts.ssl_ca_cert : "-")));
@ -963,7 +1131,7 @@ double mg_set_timer(struct mg_connection *c, double timestamp) {
DBG(("%p %p %d -> %lu", c, c->priv_2, (c->flags & MG_F_RESOLVING ? 1 : 0),
(unsigned long) timestamp));
if ((c->flags & MG_F_RESOLVING) && c->priv_2 != NULL) {
((struct mg_connection *) c->priv_2)->ev_timer_time = timestamp;
mg_set_timer((struct mg_connection *) c->priv_2, timestamp);
}
return result;
}

View File

@ -54,10 +54,12 @@ struct mg_iface_vtable {
void (*connect_udp)(struct mg_connection *nc);
/* Send functions for TCP and UDP. Sent data is copied before return. */
void (*tcp_send)(struct mg_connection *nc, const void *buf, size_t len);
void (*udp_send)(struct mg_connection *nc, const void *buf, size_t len);
int (*tcp_send)(struct mg_connection *nc, const void *buf, size_t len);
int (*udp_send)(struct mg_connection *nc, const void *buf, size_t len);
void (*recved)(struct mg_connection *nc, size_t len);
int (*tcp_recv)(struct mg_connection *nc, void *buf, size_t len);
int (*udp_recv)(struct mg_connection *nc, void *buf, size_t len,
union socket_address *sa, size_t *sa_len);
/* Perform interface-related connection initialization. Return 1 on ok. */
int (*create_conn)(struct mg_connection *nc);
@ -98,19 +100,15 @@ void mg_if_accept_tcp_cb(struct mg_connection *nc, union socket_address *sa,
/* Callback invoked by connect methods. err = 0 -> ok, != 0 -> error. */
void mg_if_connect_cb(struct mg_connection *nc, int err);
/* Callback that reports that data has been put on the wire. */
void mg_if_sent_cb(struct mg_connection *nc, int num_sent);
/*
* Receive callback.
* if `own` is true, buf must be heap-allocated and ownership is transferred
* to the core.
* Core will acknowledge consumption by calling iface::recved.
* Callback that tells the core that data can be received.
* Core will use tcp/udp_recv to retrieve the data.
*/
void mg_if_recv_tcp_cb(struct mg_connection *nc, void *buf, int len, int own);
void mg_if_can_recv_cb(struct mg_connection *nc);
void mg_if_can_send_cb(struct mg_connection *nc);
/*
* Receive callback.
* buf must be heap-allocated and ownership is transferred to the core.
* Core will acknowledge consumption by calling iface::recved.
*/
void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
union socket_address *sa, size_t sa_len);
@ -118,10 +116,7 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
/* void mg_if_close_conn(struct mg_connection *nc); */
/* Deliver a POLL event to the connection. */
void mg_if_poll(struct mg_connection *nc, time_t now);
/* Deliver a TIMER event to the connection. */
void mg_if_timer(struct mg_connection *c, double now);
int mg_if_poll(struct mg_connection *nc, double now);
#ifdef __cplusplus
}

View File

@ -9,14 +9,8 @@
#include "mg_internal.h"
#include "mg_util.h"
#define MG_TCP_RECV_BUFFER_SIZE 1024
#define MG_UDP_RECV_BUFFER_SIZE 1500
static sock_t mg_open_listening_socket(union socket_address *sa, int type,
int proto);
#if MG_ENABLE_SSL
static void mg_ssl_begin(struct mg_connection *nc);
#endif
void mg_set_non_blocking_mode(sock_t sock) {
#ifdef _WIN32
@ -85,27 +79,48 @@ int mg_socket_if_listen_tcp(struct mg_connection *nc,
return 0;
}
int mg_socket_if_listen_udp(struct mg_connection *nc,
union socket_address *sa) {
static int mg_socket_if_listen_udp(struct mg_connection *nc,
union socket_address *sa) {
sock_t sock = mg_open_listening_socket(sa, SOCK_DGRAM, 0);
if (sock == INVALID_SOCKET) return (mg_get_errno() ? mg_get_errno() : 1);
mg_sock_set(nc, sock);
return 0;
}
void mg_socket_if_tcp_send(struct mg_connection *nc, const void *buf,
size_t len) {
mbuf_append(&nc->send_mbuf, buf, len);
static int mg_socket_if_tcp_send(struct mg_connection *nc, const void *buf,
size_t len) {
int n = (int) MG_SEND_FUNC(nc->sock, buf, len, 0);
if (n < 0 && !mg_is_error()) n = 0;
return n;
}
void mg_socket_if_udp_send(struct mg_connection *nc, const void *buf,
size_t len) {
mbuf_append(&nc->send_mbuf, buf, len);
static int mg_socket_if_udp_send(struct mg_connection *nc, const void *buf,
size_t len) {
int n = sendto(nc->sock, buf, len, 0, &nc->sa.sa, sizeof(nc->sa.sin));
if (n < 0 && !mg_is_error()) n = 0;
return n;
}
void mg_socket_if_recved(struct mg_connection *nc, size_t len) {
(void) nc;
(void) len;
static int mg_socket_if_tcp_recv(struct mg_connection *nc, void *buf,
size_t len) {
int n = (int) MG_RECV_FUNC(nc->sock, buf, len, 0);
if (n == 0) {
/* Orderly shutdown of the socket, try flushing output. */
nc->flags |= MG_F_SEND_AND_CLOSE;
} else if (n < 0 && !mg_is_error()) {
n = 0;
}
return n;
}
static int mg_socket_if_udp_recv(struct mg_connection *nc, void *buf,
size_t len, union socket_address *sa,
size_t *sa_len) {
socklen_t sa_len_st = *sa_len;
int n = recvfrom(nc->sock, buf, len, 0, &sa->sa, &sa_len_st);
*sa_len = sa_len_st;
if (n < 0 && !mg_is_error()) n = 0;
return n;
}
int mg_socket_if_create_conn(struct mg_connection *nc) {
@ -142,14 +157,7 @@ static int mg_accept_conn(struct mg_connection *lc) {
DBG(("%p conn from %s:%d", nc, inet_ntoa(sa.sin.sin_addr),
ntohs(sa.sin.sin_port)));
mg_sock_set(nc, sock);
#if MG_ENABLE_SSL
if (lc->flags & MG_F_SSL) {
if (mg_ssl_if_conn_accept(nc, lc) != MG_SSL_OK) mg_close_conn(nc);
} else
#endif
{
mg_if_accept_tcp_cb(nc, &sa, sa_len);
}
mg_if_accept_tcp_cb(nc, &sa, sa_len);
return 1;
}
@ -200,165 +208,6 @@ static sock_t mg_open_listening_socket(union socket_address *sa, int type,
return sock;
}
static void mg_write_to_socket(struct mg_connection *nc) {
struct mbuf *io = &nc->send_mbuf;
int n = 0;
#if MG_LWIP
/* With LWIP we don't know if the socket is ready */
if (io->len == 0) return;
#endif
assert(io->len > 0);
if (nc->flags & MG_F_UDP) {
int n =
sendto(nc->sock, io->buf, io->len, 0, &nc->sa.sa, sizeof(nc->sa.sin));
DBG(("%p %d %d %d %s:%hu", nc, nc->sock, n, mg_get_errno(),
inet_ntoa(nc->sa.sin.sin_addr), ntohs(nc->sa.sin.sin_port)));
mg_if_sent_cb(nc, n);
return;
}
#if MG_ENABLE_SSL
if (nc->flags & MG_F_SSL) {
if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) {
n = mg_ssl_if_write(nc, io->buf, io->len);
DBG(("%p %d bytes -> %d (SSL)", nc, n, nc->sock));
if (n < 0) {
if (n != MG_SSL_WANT_READ && n != MG_SSL_WANT_WRITE) {
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
}
return;
} else {
/* Successful SSL operation, clear off SSL wait flags */
nc->flags &= ~(MG_F_WANT_READ | MG_F_WANT_WRITE);
}
} else {
mg_ssl_begin(nc);
return;
}
} else
#endif
{
n = (int) MG_SEND_FUNC(nc->sock, io->buf, io->len, 0);
DBG(("%p %d bytes -> %d", nc, n, nc->sock));
}
mg_if_sent_cb(nc, n);
}
MG_INTERNAL size_t recv_avail_size(struct mg_connection *conn, size_t max) {
size_t avail;
if (conn->recv_mbuf_limit < conn->recv_mbuf.len) return 0;
avail = conn->recv_mbuf_limit - conn->recv_mbuf.len;
return avail > max ? max : avail;
}
static void mg_handle_tcp_read(struct mg_connection *conn) {
int n = 0;
char *buf = (char *) MG_MALLOC(MG_TCP_RECV_BUFFER_SIZE);
if (buf == NULL) {
DBG(("OOM"));
return;
}
#if MG_ENABLE_SSL
if (conn->flags & MG_F_SSL) {
if (conn->flags & MG_F_SSL_HANDSHAKE_DONE) {
/* SSL library may have more bytes ready to read than we ask to read.
* Therefore, read in a loop until we read everything. Without the loop,
* we skip to the next select() cycle which can just timeout. */
while ((n = mg_ssl_if_read(conn, buf, MG_TCP_RECV_BUFFER_SIZE)) > 0) {
DBG(("%p %d bytes <- %d (SSL)", conn, n, conn->sock));
mg_if_recv_tcp_cb(conn, buf, n, 1 /* own */);
buf = NULL;
if (conn->flags & MG_F_CLOSE_IMMEDIATELY) break;
/* buf has been freed, we need a new one. */
buf = (char *) MG_MALLOC(MG_TCP_RECV_BUFFER_SIZE);
if (buf == NULL) break;
}
MG_FREE(buf);
if (n < 0 && n != MG_SSL_WANT_READ) conn->flags |= MG_F_CLOSE_IMMEDIATELY;
} else {
MG_FREE(buf);
mg_ssl_begin(conn);
return;
}
} else
#endif
{
n = (int) MG_RECV_FUNC(conn->sock, buf,
recv_avail_size(conn, MG_TCP_RECV_BUFFER_SIZE), 0);
DBG(("%p %d bytes (PLAIN) <- %d", conn, n, conn->sock));
if (n > 0) {
mg_if_recv_tcp_cb(conn, buf, n, 1 /* own */);
} else {
MG_FREE(buf);
}
if (n == 0) {
/* Orderly shutdown of the socket, try flushing output. */
conn->flags |= MG_F_SEND_AND_CLOSE;
} else if (n < 0 && mg_is_error()) {
conn->flags |= MG_F_CLOSE_IMMEDIATELY;
}
}
}
static int mg_recvfrom(struct mg_connection *nc, union socket_address *sa,
socklen_t *sa_len, char **buf) {
int n;
*buf = (char *) MG_MALLOC(MG_UDP_RECV_BUFFER_SIZE);
if (*buf == NULL) {
DBG(("Out of memory"));
return -ENOMEM;
}
n = recvfrom(nc->sock, *buf, MG_UDP_RECV_BUFFER_SIZE, 0, &sa->sa, sa_len);
if (n <= 0) {
DBG(("%p recvfrom: %s", nc, strerror(mg_get_errno())));
MG_FREE(*buf);
}
return n;
}
static void mg_handle_udp_read(struct mg_connection *nc) {
char *buf = NULL;
union socket_address sa;
socklen_t sa_len = sizeof(sa);
int n = mg_recvfrom(nc, &sa, &sa_len, &buf);
DBG(("%p %d bytes from %s:%d", nc, n, inet_ntoa(nc->sa.sin.sin_addr),
ntohs(nc->sa.sin.sin_port)));
mg_if_recv_udp_cb(nc, buf, n, &sa, sa_len);
}
#if MG_ENABLE_SSL
static void mg_ssl_begin(struct mg_connection *nc) {
int server_side = (nc->listener != NULL);
enum mg_ssl_if_result res = mg_ssl_if_handshake(nc);
DBG(("%p %d res %d", nc, server_side, res));
if (res == MG_SSL_OK) {
nc->flags |= MG_F_SSL_HANDSHAKE_DONE;
nc->flags &= ~(MG_F_WANT_READ | MG_F_WANT_WRITE);
if (server_side) {
union socket_address sa;
socklen_t sa_len = sizeof(sa);
(void) getpeername(nc->sock, &sa.sa, &sa_len);
mg_if_accept_tcp_cb(nc, &sa, sa_len);
} else {
mg_if_connect_cb(nc, 0);
}
} else if (res != MG_SSL_WANT_READ && res != MG_SSL_WANT_WRITE) {
if (!server_side) {
mg_if_connect_cb(nc, res);
}
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
}
}
#endif /* MG_ENABLE_SSL */
#define _MG_F_FD_CAN_READ 1
#define _MG_F_FD_CAN_WRITE 1 << 1
#define _MG_F_FD_ERROR 1 << 2
@ -367,11 +216,13 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
int worth_logging =
fd_flags != 0 || (nc->flags & (MG_F_WANT_READ | MG_F_WANT_WRITE));
if (worth_logging) {
DBG(("%p fd=%d fd_flags=%d nc_flags=%lu rmbl=%d smbl=%d", nc, nc->sock,
DBG(("%p fd=%d fd_flags=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock,
fd_flags, nc->flags, (int) nc->recv_mbuf.len,
(int) nc->send_mbuf.len));
}
if (!mg_if_poll(nc, now)) return;
if (nc->flags & MG_F_CONNECTING) {
if (fd_flags != 0) {
int err = 0;
@ -392,15 +243,7 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
*/
err = nc->err;
#endif
#if MG_ENABLE_SSL
if ((nc->flags & MG_F_SSL) && err == 0) {
mg_ssl_begin(nc);
} else {
mg_if_connect_cb(nc, err);
}
#else
mg_if_connect_cb(nc, err);
#endif
} else if (nc->err != 0) {
mg_if_connect_cb(nc, nc->err);
}
@ -408,7 +251,7 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
if (fd_flags & _MG_F_FD_CAN_READ) {
if (nc->flags & MG_F_UDP) {
mg_handle_udp_read(nc);
mg_if_can_recv_cb(nc);
} else {
if (nc->flags & MG_F_LISTENING) {
/*
@ -418,22 +261,16 @@ void mg_mgr_handle_conn(struct mg_connection *nc, int fd_flags, double now) {
*/
mg_accept_conn(nc);
} else {
mg_handle_tcp_read(nc);
mg_if_can_recv_cb(nc);
}
}
}
if (!(nc->flags & MG_F_CLOSE_IMMEDIATELY)) {
if ((fd_flags & _MG_F_FD_CAN_WRITE) && nc->send_mbuf.len > 0) {
mg_write_to_socket(nc);
}
mg_if_poll(nc, (time_t) now);
mg_if_timer(nc, now);
}
if (fd_flags & _MG_F_FD_CAN_WRITE) mg_if_can_send_cb(nc);
if (worth_logging) {
DBG(("%p after fd=%d nc_flags=%lu rmbl=%d smbl=%d", nc, nc->sock, nc->flags,
(int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
DBG(("%p after fd=%d nc_flags=0x%lx rmbl=%d smbl=%d", nc, nc->sock,
nc->flags, (int) nc->recv_mbuf.len, (int) nc->send_mbuf.len));
}
}
@ -547,8 +384,7 @@ time_t mg_socket_if_poll(struct mg_iface *iface, int timeout_ms) {
}
#endif
if (!(nc->flags & MG_F_WANT_WRITE) &&
nc->recv_mbuf.len < nc->recv_mbuf_limit &&
if (nc->recv_mbuf.len < nc->recv_mbuf_limit &&
(!(nc->flags & MG_F_UDP) || nc->listener == NULL)) {
mg_add_to_set(nc->sock, &read_set, &max_fd);
}
@ -619,14 +455,6 @@ time_t mg_socket_if_poll(struct mg_iface *iface, int timeout_ms) {
mg_mgr_handle_conn(nc, fd_flags, now);
}
for (nc = mgr->active_connections; nc != NULL; nc = tmp) {
tmp = nc->next;
if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) ||
(nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE))) {
mg_close_conn(nc);
}
}
return (time_t) now;
}
@ -735,7 +563,8 @@ void mg_socket_if_get_conn_addr(struct mg_connection *nc, int remote,
mg_socket_if_connect_udp, \
mg_socket_if_tcp_send, \
mg_socket_if_udp_send, \
mg_socket_if_recved, \
mg_socket_if_tcp_recv, \
mg_socket_if_udp_recv, \
mg_socket_if_create_conn, \
mg_socket_if_destroy_conn, \
mg_socket_if_sock_set, \

View File

@ -9,18 +9,35 @@ struct socksdata {
char *proxy_addr; /* HOST:PORT of the socks5 proxy server */
struct mg_connection *s; /* Respective connection to the server */
struct mg_connection *c; /* Connection to the client */
struct mbuf tmp; /* Temporary buffer for sent data */
};
static void socks_if_disband(struct socksdata *d) {
LOG(LL_DEBUG, ("disbanding proxy %p %p", d->c, d->s));
if (d->c) d->c->flags |= MG_F_SEND_AND_CLOSE;
if (d->s) d->s->flags |= MG_F_SEND_AND_CLOSE;
d->c = d->s = NULL;
if (d->c) {
d->c->flags |= MG_F_SEND_AND_CLOSE;
d->c->user_data = NULL;
d->c = NULL;
}
if (d->s) {
d->s->flags |= MG_F_SEND_AND_CLOSE;
d->s->user_data = NULL;
d->s = NULL;
}
}
static void socks_if_relay(struct mg_connection *s) {
struct socksdata *d = (struct socksdata *) s->user_data;
if (d == NULL || d->c == NULL || !(s->flags & MG_SOCKS_CONNECT_DONE) ||
d->s == NULL) {
return;
}
if (s->recv_mbuf.len > 0) mg_if_can_recv_cb(d->c);
if (d->c->send_mbuf.len > 0 && s->send_mbuf.len == 0) mg_if_can_send_cb(d->c);
}
static void socks_if_handler(struct mg_connection *c, int ev, void *ev_data) {
struct socksdata *d = (struct socksdata *) c->user_data;
if (d == NULL) return;
if (ev == MG_EV_CONNECT) {
int res = *(int *) ev_data;
if (res == 0) {
@ -53,6 +70,7 @@ static void socks_if_handler(struct mg_connection *c, int ev, void *ev_data) {
memcpy(buf + 4, &d->c->sa.sin.sin_addr, 4);
memcpy(buf + 8, &d->c->sa.sin.sin_port, 2);
mg_send(c, buf, sizeof(buf));
LOG(LL_DEBUG, ("%p Sent connect request", c));
}
/* Process connect request */
if ((c->flags & MG_SOCKS_HANDSHAKE_DONE) &&
@ -65,17 +83,12 @@ static void socks_if_handler(struct mg_connection *c, int ev, void *ev_data) {
}
mbuf_remove(&c->recv_mbuf, 10);
c->flags |= MG_SOCKS_CONNECT_DONE;
/* Connected. Move sent data from client, if any, to server */
if (d->s && d->c) {
mbuf_append(&d->s->send_mbuf, d->tmp.buf, d->tmp.len);
mbuf_free(&d->tmp);
}
}
/* All flags are set, we're in relay mode */
if ((c->flags & MG_SOCKS_CONNECT_DONE) && d->c && d->s) {
mbuf_append(&d->c->recv_mbuf, d->s->recv_mbuf.buf, d->s->recv_mbuf.len);
mbuf_remove(&d->s->recv_mbuf, d->s->recv_mbuf.len);
LOG(LL_DEBUG, ("%p Connect done %p", c, d->c));
mg_if_connect_cb(d->c, 0);
}
socks_if_relay(c);
} else if (ev == MG_EV_SEND || ev == MG_EV_POLL) {
socks_if_relay(c);
}
}
@ -85,7 +98,7 @@ static void mg_socks_if_connect_tcp(struct mg_connection *c,
d->c = c;
d->s = mg_connect(c->mgr, d->proxy_addr, socks_if_handler);
d->s->user_data = d;
LOG(LL_DEBUG, ("%p %s", c, d->proxy_addr));
LOG(LL_DEBUG, ("%p %s %p %p", c, d->proxy_addr, d, d->s));
(void) sa;
}
@ -107,29 +120,44 @@ static int mg_socks_if_listen_udp(struct mg_connection *c,
return -1;
}
static void mg_socks_if_tcp_send(struct mg_connection *c, const void *buf,
size_t len) {
static int mg_socks_if_tcp_send(struct mg_connection *c, const void *buf,
size_t len) {
int res;
struct socksdata *d = (struct socksdata *) c->iface->data;
LOG(LL_DEBUG, ("%p -> %p %d %d", c, buf, (int) len, (int) c->send_mbuf.len));
if (d && d->s && d->s->flags & MG_SOCKS_CONNECT_DONE) {
mbuf_append(&d->s->send_mbuf, d->tmp.buf, d->tmp.len);
mbuf_append(&d->s->send_mbuf, buf, len);
mbuf_free(&d->tmp);
} else {
mbuf_append(&d->tmp, buf, len);
}
if (d->s == NULL) return -1;
res = (int) mbuf_append(&d->s->send_mbuf, buf, len);
DBG(("%p -> %d -> %p", c, res, d->s));
return res;
}
static void mg_socks_if_udp_send(struct mg_connection *c, const void *buf,
size_t len) {
static int mg_socks_if_udp_send(struct mg_connection *c, const void *buf,
size_t len) {
(void) c;
(void) buf;
(void) len;
return -1;
}
static void mg_socks_if_recved(struct mg_connection *c, size_t len) {
int mg_socks_if_tcp_recv(struct mg_connection *c, void *buf, size_t len) {
struct socksdata *d = (struct socksdata *) c->iface->data;
if (d->s == NULL) return -1;
if (len > d->s->recv_mbuf.len) len = d->s->recv_mbuf.len;
if (len > 0) {
memcpy(buf, d->s->recv_mbuf.buf, len);
mbuf_remove(&d->s->recv_mbuf, len);
}
DBG(("%p <- %d <- %p", c, (int) len, d->s));
return len;
}
int mg_socks_if_udp_recv(struct mg_connection *c, void *buf, size_t len,
union socket_address *sa, size_t *sa_len) {
(void) c;
(void) buf;
(void) len;
(void) sa;
(void) sa_len;
return -1;
}
static int mg_socks_if_create_conn(struct mg_connection *c) {
@ -158,7 +186,6 @@ static void mg_socks_if_free(struct mg_iface *iface) {
LOG(LL_DEBUG, ("%p", iface));
if (d != NULL) {
socks_if_disband(d);
mbuf_free(&d->tmp);
MG_FREE(d->proxy_addr);
MG_FREE(d);
iface->data = NULL;
@ -189,14 +216,15 @@ static void mg_socks_if_get_conn_addr(struct mg_connection *c, int remote,
}
const struct mg_iface_vtable mg_socks_iface_vtable = {
mg_socks_if_init, mg_socks_if_free,
mg_socks_if_add_conn, mg_socks_if_remove_conn,
mg_socks_if_poll, mg_socks_if_listen_tcp,
mg_socks_if_listen_udp, mg_socks_if_connect_tcp,
mg_socks_if_connect_udp, mg_socks_if_tcp_send,
mg_socks_if_udp_send, mg_socks_if_recved,
mg_socks_if_create_conn, mg_socks_if_destroy_conn,
mg_socks_if_sock_set, mg_socks_if_get_conn_addr,
mg_socks_if_init, mg_socks_if_free,
mg_socks_if_add_conn, mg_socks_if_remove_conn,
mg_socks_if_poll, mg_socks_if_listen_tcp,
mg_socks_if_listen_udp, mg_socks_if_connect_tcp,
mg_socks_if_connect_udp, mg_socks_if_tcp_send,
mg_socks_if_udp_send, mg_socks_if_tcp_recv,
mg_socks_if_udp_recv, mg_socks_if_create_conn,
mg_socks_if_destroy_conn, mg_socks_if_sock_set,
mg_socks_if_get_conn_addr,
};
struct mg_iface *mg_socks_mk_iface(struct mg_mgr *mgr, const char *proxy_addr) {

View File

@ -148,7 +148,6 @@ static void mg_resolve_async_eh(struct mg_connection *nc, int ev,
time_t now = (time_t) mg_time();
struct mg_resolve_async_request *req;
struct mg_dns_message *msg;
int first = 0;
#if !MG_ENABLE_CALLBACK_USERDATA
void *user_data = nc->user_data;
#endif
@ -162,17 +161,16 @@ static void mg_resolve_async_eh(struct mg_connection *nc, int ev,
}
switch (ev) {
case MG_EV_CONNECT:
/* don't depend on timer not being at epoch for sending out first req */
first = 1;
/* fallthrough */
case MG_EV_POLL:
if (req->retries > req->max_retries) {
req->err = MG_RESOLVE_EXCEEDED_RETRY_COUNT;
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
break;
}
if (first || now - req->last_time >= req->timeout) {
if (nc->flags & MG_F_CONNECTING) break;
/* fallthrough */
case MG_EV_CONNECT:
if (req->retries == 0 || now - req->last_time >= req->timeout) {
mg_send_dns_query(nc, req->name, req->query);
req->last_time = now;
req->retries++;

View File

@ -7,9 +7,12 @@
#include <mbedtls/debug.h>
#include <mbedtls/ecp.h>
#include <mbedtls/net.h>
#include <mbedtls/platform.h>
#include <mbedtls/ssl.h>
#include <mbedtls/ssl_internal.h>
#include <mbedtls/x509_crt.h>
#include <mbedtls/version.h>
static void mg_ssl_mbed_log(void *ctx, int level, const char *file, int line,
const char *str) {
@ -19,6 +22,8 @@ static void mg_ssl_mbed_log(void *ctx, int level, const char *file, int line,
cs_level = LL_ERROR;
break;
case 2:
cs_level = LL_INFO;
break;
case 3:
cs_level = LL_DEBUG;
break;
@ -38,12 +43,14 @@ struct mg_ssl_if_ctx {
mbedtls_pk_context *key;
mbedtls_x509_crt *ca_cert;
struct mbuf cipher_suites;
size_t saved_len;
};
/* Must be provided by the platform. ctx is struct mg_connection. */
extern int mg_ssl_if_mbed_random(void *ctx, unsigned char *buf, size_t len);
void mg_ssl_if_init() {
LOG(LL_INFO, ("%s", MBEDTLS_VERSION_STRING_FULL));
}
enum mg_ssl_if_result mg_ssl_if_conn_accept(struct mg_connection *nc,
@ -164,40 +171,41 @@ enum mg_ssl_if_result mg_ssl_if_conn_init(
return MG_SSL_OK;
}
#if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL
int ssl_socket_send(void *ctx, const unsigned char *buf, size_t len);
int ssl_socket_recv(void *ctx, unsigned char *buf, size_t len);
#else
static int ssl_socket_send(void *ctx, const unsigned char *buf, size_t len) {
static int mg_ssl_if_mbed_send(void *ctx, const unsigned char *buf,
size_t len) {
struct mg_connection *nc = (struct mg_connection *) ctx;
int n = (int) MG_SEND_FUNC(nc->sock, buf, len, 0);
LOG(LL_DEBUG, ("%p %d -> %d", nc, (int) len, n));
if (n >= 0) return n;
n = mg_get_errno();
return ((n == EAGAIN || n == EINPROGRESS) ? MBEDTLS_ERR_SSL_WANT_WRITE : -1);
int n = nc->iface->vtable->tcp_send(nc, buf, len);
if (n > 0) return n;
if (n == 0) return MBEDTLS_ERR_SSL_WANT_WRITE;
return MBEDTLS_ERR_NET_SEND_FAILED;
}
static int ssl_socket_recv(void *ctx, unsigned char *buf, size_t len) {
static int mg_ssl_if_mbed_recv(void *ctx, unsigned char *buf, size_t len) {
struct mg_connection *nc = (struct mg_connection *) ctx;
int n = (int) MG_RECV_FUNC(nc->sock, buf, len, 0);
LOG(LL_DEBUG, ("%p %d <- %d", nc, (int) len, n));
if (n >= 0) return n;
n = mg_get_errno();
return ((n == EAGAIN || n == EINPROGRESS) ? MBEDTLS_ERR_SSL_WANT_READ : -1);
int n = nc->iface->vtable->tcp_recv(nc, buf, len);
if (n > 0) return n;
if (n == 0) return MBEDTLS_ERR_SSL_WANT_READ;
return MBEDTLS_ERR_NET_RECV_FAILED;
}
#endif
static enum mg_ssl_if_result mg_ssl_if_mbed_err(struct mg_connection *nc,
int ret) {
if (ret == MBEDTLS_ERR_SSL_WANT_READ) return MG_SSL_WANT_READ;
if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) return MG_SSL_WANT_WRITE;
if (ret !=
MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { /* CLOSE_NOTIFY = Normal shutdown */
LOG(LL_ERROR, ("%p SSL error: %d", nc, ret));
enum mg_ssl_if_result res = MG_SSL_OK;
if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
res = MG_SSL_WANT_READ;
} else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
res = MG_SSL_WANT_WRITE;
} else if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
LOG(LL_DEBUG, ("%p TLS connection closed by peer", nc));
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
res = MG_SSL_OK;
} else {
LOG(LL_ERROR, ("%p mbedTLS error: -0x%04x", nc, -ret));
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
res = MG_SSL_ERROR;
}
nc->err = ret;
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
return MG_SSL_ERROR;
return res;
}
static void mg_ssl_if_mbed_free_certs_and_keys(struct mg_ssl_if_ctx *ctx) {
@ -228,7 +236,8 @@ enum mg_ssl_if_result mg_ssl_if_handshake(struct mg_connection *nc) {
int err;
/* If bio is not yet set, do it now. */
if (ctx->ssl->p_bio == NULL) {
mbedtls_ssl_set_bio(ctx->ssl, nc, ssl_socket_send, ssl_socket_recv, NULL);
mbedtls_ssl_set_bio(ctx->ssl, nc, mg_ssl_if_mbed_send, mg_ssl_if_mbed_recv,
NULL);
}
err = mbedtls_ssl_handshake(ctx->ssl);
if (err != 0) return mg_ssl_if_mbed_err(nc, err);
@ -254,20 +263,35 @@ enum mg_ssl_if_result mg_ssl_if_handshake(struct mg_connection *nc) {
return MG_SSL_OK;
}
int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t buf_size) {
int mg_ssl_if_read(struct mg_connection *nc, void *buf, size_t len) {
struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
int n = mbedtls_ssl_read(ctx->ssl, (unsigned char *) buf, buf_size);
DBG(("%p %d -> %d", nc, (int) buf_size, n));
int n = mbedtls_ssl_read(ctx->ssl, (unsigned char *) buf, len);
DBG(("%p %d -> %d", nc, (int) len, n));
if (n < 0) return mg_ssl_if_mbed_err(nc, n);
if (n == 0) nc->flags |= MG_F_CLOSE_IMMEDIATELY;
return n;
}
int mg_ssl_if_write(struct mg_connection *nc, const void *data, size_t len) {
int mg_ssl_if_write(struct mg_connection *nc, const void *buf, size_t len) {
struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
int n = mbedtls_ssl_write(ctx->ssl, (const unsigned char *) data, len);
DBG(("%p %d -> %d", nc, (int) len, n));
if (n < 0) return mg_ssl_if_mbed_err(nc, n);
/* Per mbedTLS docs, if write returns WANT_READ or WANT_WRITE, the operation
* should be retried with the same data and length.
* Here we assume that the data being pushed will remain the same but the
* amount may grow between calls so we save the length that was used and
* retry. The assumption being that the data itself won't change and won't
* be removed. */
size_t l = len;
if (ctx->saved_len > 0 && ctx->saved_len < l) l = ctx->saved_len;
int n = mbedtls_ssl_write(ctx->ssl, (const unsigned char *) buf, l);
DBG(("%p %d,%d,%d -> %d", nc, (int) len, (int) ctx->saved_len, (int) l, n));
if (n < 0) {
if (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE) {
ctx->saved_len = len;
}
return mg_ssl_if_mbed_err(nc, n);
} else if (n > 0) {
ctx->saved_len = 0;
}
return n;
}

View File

@ -1145,7 +1145,7 @@ static const char *test_timer(void) {
ASSERT((c = mg_connect(&m, "awful.sad:1234", ev_timer_handler)) != NULL);
c->user_data = &n;
mg_set_timer(c, 1);
mg_mgr_poll(&m, 1);
poll_until(&m, 1, c_int_eq, &n, (void *) 101);
ASSERT_EQ(n, 101);
mg_mgr_free(&m);
@ -2019,6 +2019,7 @@ static const char *test_http(void) {
ASSERT((nc = mg_connect(&mgr, local_addr, cb7)) != NULL);
mg_set_protocol_http_websocket(nc);
nc->user_data = status;
mbuf_resize(&nc->recv_mbuf, 10000000);
/* Wine and GDB set argv0 to full path: strip the dir component */
if ((this_binary = strrchr(g_argv_0, '\\')) != NULL) {
@ -5454,12 +5455,14 @@ static const char *test_socks(void) {
this_binary = g_argv_0;
}
mg_printf(c, "GET /%s HTTP/1.0\n\n", this_binary);
mbuf_resize(&c->recv_mbuf, 10000000);
/* Run event loop. Use more cycles to let file download complete. */
poll_until(&mgr, 5, c_str_ne, status, (void *) "");
mg_mgr_free(&mgr);
poll_until(&mgr, 10, c_str_ne, status, (void *) "");
ASSERT_STREQ(status, "success");
mg_mgr_free(&mgr);
return NULL;
}
#endif