mirror of
https://github.com/cesanta/mongoose.git
synced 2025-01-14 09:48:01 +08: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:
parent
c80f4c5313
commit
3e33e57707
1653
mongoose.c
1653
mongoose.c
File diff suppressed because it is too large
Load Diff
25
mongoose.h
25
mongoose.h
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 \
|
||||
|
372
src/mg_net.c
372
src/mg_net.c
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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, \
|
||||
|
@ -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) {
|
||||
|
@ -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++;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user