mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-24 11:54:49 +00:00
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:
1 parent
c80f4c5313
commit
3e33e57707
17 files changed
+1358
-2007
No files matched your search
@@ -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;
|
||||
|
||||
@@ -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, \
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 */
|
||||
@@ -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)
|
||||
|
||||
@@ -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, \
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user