Commit 3e33e577 authored by Deomid Ryabkov's avatar Deomid Ryabkov Committed by Cesanta Bot

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
parent c80f4c53
This diff is collapsed.
......@@ -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);
}
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 (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
*/
if (cs->draining_rx_chain && cs->rx_chain == NULL) {
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;
......
This diff is collapsed.
......@@ -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 {
......
/*
* 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)
......
This diff is collapsed.
......@@ -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,38 +179,42 @@ 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) {
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);
char *ssl_key = sl_pem2der(ctx->ssl_key);
if (ssl_cert != NULL && 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));
LOG(LL_INFO, ("CERTIFICATE_FILE_NAME %s -> %d", ssl_cert, err));
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;
}
} else {
err = -1;
}
MG_FREE(ssl_cert);
MG_FREE(ssl_key);
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));
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;
}
......@@ -204,7 +233,6 @@ int sl_set_ssl_opts(int sock, struct mg_connection *nc) {
* 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 \
......
This diff is collapsed.
......@@ -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
}
......
This diff is collapsed.
......@@ -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,
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,
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;
......@@ -194,9 +221,10 @@ const struct mg_iface_vtable mg_socks_iface_vtable = {
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_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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment