diff --git a/src/apps/altcp_tls/altcp_mbedtls.c b/src/apps/altcp_tls/altcp_mbedtls.c new file mode 100644 index 00000000..4757f00c --- /dev/null +++ b/src/apps/altcp_tls/altcp_mbedtls.c @@ -0,0 +1,753 @@ +/** + * @file + * Application layered TCP connection API (to be used from TCPIP thread) + * + * This file contains a TLS layer using mbedTLS + */ + +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#include "lwip/opt.h" + +#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/altcp.h" +#include "lwip/priv/altcp_priv.h" +#include "lwip/mem.h" + +/* TODO: which includes are really needed? */ +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/certs.h" +#include "mbedtls/x509.h" +#include "mbedtls/ssl.h" +#include "mbedtls/net.h" +#include "mbedtls/error.h" +#include "mbedtls/debug.h" +#include "mbedtls/platform.h" +#include "mbedtls/memory_buffer_alloc.h" +#include "mbedtls/ssl_cache.h" +#include "mbedtls/platform.h" + +#include + +typedef struct altcp_mbedtls_state_s { + mbedtls_ssl_context ssl_context; + /* chain of rx pbufs (before decryption) */ + struct pbuf* rx; + u8_t handshake_done; +} altcp_mbedtls_state_t; + +/* Variable prototype, the actual declaration is at the end of this file + since it contains pointers to static functions declared here */ +extern const struct altcp_functions altcp_mbedtls_functions; + +/* global configuration (not connection-specific) */ +static mbedtls_ssl_config conf; +#ifdef MBEDTLS_SSL_CACHE_C +/* cache for cached fast connection startup */ +static struct mbedtls_ssl_cache_context cache; +#endif + +static err_t altcp_mbedtls_setup(struct altcp_pcb *conn, struct altcp_pcb *inner_conn); + +static altcp_mbedtls_state_t * +altcp_mbedtls_alloc(void) +{ + altcp_mbedtls_state_t *ret = (altcp_mbedtls_state_t *)mem_malloc(sizeof(altcp_mbedtls_state_t)); + if (ret != NULL) { + memset(ret, 0, sizeof(altcp_mbedtls_state_t)); + } + return ret; +} + +static void +altcp_mbedtls_free(altcp_mbedtls_state_t *state) +{ + LWIP_ASSERT("state != NULL", state != NULL); + mem_free(state); +} + +/* callback functions from mbedtls (I/O) */ +static int +altcp_mbedtls_bio_send(void* ctx, const unsigned char* dataptr, size_t size) +{ + struct altcp_pcb *conn = (struct altcp_pcb *) ctx; + int written = 0; + size_t size_left = size; + u8_t apiflags = ALTCP_WRITE_FLAG_COPY; + + while (size_left) { + u16_t write_len = (u16_t)LWIP_MIN(size_left, 0xFFFF); + err_t err = altcp_write(conn, (const void *)dataptr, write_len, apiflags); + if (err == ERR_OK) { + written += write_len; + size_left -= write_len; + } else { + LWIP_ASSERT("tls_write, tcp_write: ERR MEM", err == ERR_MEM ); + break; + } + } + return written; +} + +static int +altcp_mbedtls_bio_recv(void *ctx, unsigned char *buf, size_t len) +{ + struct altcp_pcb *conn = (struct altcp_pcb *)ctx; + altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state; + struct pbuf* p; + u16_t ret; + /* limit number of byts to copy to fit into an s16_t for pbuf_header */ + u16_t copy_len = (u16_t)LWIP_MIN(len, 0x7FFF); + err_t err; + + if (state == NULL) { + return 0; + } + p = state->rx; + + LWIP_ASSERT("len is too big", len <= 0xFFFF); + + if (p == NULL) { + return MBEDTLS_ERR_SSL_WANT_READ; + } + //PFTRACE(("-after handshake: remote port: %d pbuf len: %d pbuf tot len %d\n",pcb->remote_port, p->len, p->tot_len)); + ret = pbuf_copy_partial(p, buf, copy_len, 0); + LWIP_ASSERT("ret <= p->len", ret <= p->len); + err = pbuf_header(p, -(s16_t)ret); + LWIP_ASSERT("error", err == ERR_OK); + if(p->len == 0) { + state->rx = p->next; + p->next = NULL; + pbuf_free(p); + } + + return ret; +} + +/* callback functions from inner connection */ +static err_t +altcp_mbedtls_lower_accept(void *arg, struct altcp_pcb *accepted_conn, err_t err) +{ + struct altcp_pcb *listen_conn = (struct altcp_pcb *)arg; + if (listen_conn && listen_conn->accept) { + err_t setup_err; + /* create a new altcp_conn to pass to the next 'accept' callback */ + struct altcp_pcb *new_conn = altcp_alloc(); + if (new_conn == NULL) { + return ERR_MEM; + } + setup_err = altcp_mbedtls_setup(new_conn, accepted_conn); + if (setup_err != ERR_OK) { + altcp_free(new_conn); + return setup_err; + } + return listen_conn->accept(listen_conn->arg, new_conn, err); + } + return ERR_ARG; +} + +static err_t +altcp_mbedtls_lower_connected(void *arg, struct altcp_pcb *inner_conn, err_t err) +{ + struct altcp_pcb *conn = (struct altcp_pcb *)arg; + if (conn) { + LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn); + /* upper connected is called when handshake is done */ + return ERR_OK; + } + return ERR_VAL; +} + +static err_t +altcp_mbedtls_lower_recv(void *arg, struct altcp_pcb *inner_conn, struct pbuf *p, err_t err) +{ + struct altcp_pcb *conn = (struct altcp_pcb *)arg; + if (!conn) { + if (p != NULL) { + /* prevent memory leaks */ + pbuf_free(p); + } + return ERR_RST; + } + altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state; + LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn); + LWIP_ASSERT("conn->state != NULL", conn->state != NULL); + + /* handle NULL pbufs or other errors */ + if ((p == NULL) || (err != ERR_OK)) { + if (state->handshake_done) { + if (conn->recv) { + return conn->recv(conn->arg, conn, p, err); + } else { + if (p) { + pbuf_free(p); + } + altcp_close(conn); + return ERR_OK; + } + } else { + /* before connection setup is done: call 'err' */ + if (p) { + pbuf_free(p); + } + if (conn->err) { + conn->err(conn->arg, ERR_CLSD); + } + altcp_close(conn); + } + } + + // If there are more pbufs waiting for encryption, new pbuf is appended to queue. + if (state->rx == NULL) { + state->rx = p; + } else { + LWIP_ASSERT("rx pbuf overflow", (int)p->tot_len + (int)p->len <= 0xFFFF); + pbuf_cat(state->rx, p); + } + + if (!state->handshake_done) { + /* handle connection setup (handshake not done) */ + int ret; + + /* during handshake: mark all data as received */ + altcp_recved(conn, p->tot_len); + + ret = mbedtls_ssl_handshake(&state->ssl_context); + if(ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) { + /* handshake not done, wait for more recv calls */ + return ERR_OK; + } + if (ret != 0) { + LWIP_ASSERT("mbedtls_ssl_handshake failed \n", ret == 0); + // ssl context reset() + // current connection has to be closed! + // tls_close() + conn->recv(conn->arg, conn, NULL, ERR_OK); + /*if (tcp_close(pcb) != ERR_OK) { + tcp_abort(pcb); + }*/ + return ERR_OK; + } + state->handshake_done = 1; + /* issue "connect" callback" to upper connection */ + if (conn->connected) { + conn->connected(conn->arg, conn, ERR_OK); + } + } else { + /* handle connection data */ + int ret; + // TODO: call recved for unencrypted overhead only + altcp_recved(conn, p->tot_len); + + do { + struct pbuf *buf = pbuf_alloc(PBUF_RAW, PBUF_POOL_BUFSIZE, PBUF_RAM); + if (buf == NULL) { + // try again later? + // TODO: close connection? + return ERR_OK; + } + + // encrypted buf-> payload always 29 Bytes shorter than received p->payload + ret = mbedtls_ssl_read(&state->ssl_context, (unsigned char *)buf->payload, PBUF_POOL_BUFSIZE); + if (ret < 0) { + if (ret == MBEDTLS_ERR_SSL_CLIENT_RECONNECT) { + LWIP_ASSERT("new connection on same source port.\n", 0);//ret == MBEDTLS_ERR_SSL_CLIENT_RECONNECT); + // client is initiating a new connection using the same source port -> close connection or make handshake + } else if ((ret != MBEDTLS_ERR_SSL_WANT_READ) && (ret != MBEDTLS_ERR_SSL_WANT_WRITE)) { + //PFTRACE(("LWIP ASSERT remote port: %d, ret: %d", pcb->remote_port, ret)); + //LWIP_ASSERT("connection was closed gracefully\n", ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY); + //LWIP_ASSERT("connection was reset by peer\n", ret == MBEDTLS_ERR_NET_CONN_RESET); + //pbuf_free(buf); + //return ERR_OK; + } else { + //LWIP_ASSERT("TODO", 0); + pbuf_free(buf); + return ERR_OK; + } + pbuf_free(buf); + //http_abort_conn();... + return ERR_ABRT; // TODO: close 'pcb'? + } else { + LWIP_ASSERT("TODO", ret <= 0xFFFF && ret <= PBUF_POOL_BUFSIZE); + pbuf_realloc(buf, (uint16_t)ret); + + //PFTRACE(("tls pbuf tot len= %d ",pbuf_len - buf->tot_len)); + //tcp_recved(pcb, pbuf_len-buf->tot_len); + //tcp_recved(pcb, pbuf_len); + //PFTRACE(("- after encryprion remote port: %d rcv_wnd %d, buf len: %d buf tot len %d\n", pcb->remote_port, pcb->rcv_wnd, buf->len, buf->tot_len)); + if (conn->recv) { + conn->recv(conn->arg, conn, buf, err); // TODO: check return value + } + /* TODO: if(conn->state != ESTABLISHED) + { + //time2= (uint64_t)pfGetSystemTime(); + //PFTRACE(("TLS_RECV (in while), TCP Remote port: %d Time dif: %d", pcb->remote_port, (int) (time2-time1))); + + return ERR_OK; + }*/ + } + } + while (ret > 0); + } + return ERR_OK; +} + +static err_t +altcp_mbedtls_lower_sent(void *arg, struct altcp_pcb *inner_conn, u16_t len) +{ + struct altcp_pcb *conn = (struct altcp_pcb *)arg; + if (conn) { + altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state; + LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn); + if (!state->handshake_done) { + /* TODO: do something here? */ + return ERR_OK; + } + if (conn->sent) { + return conn->sent(conn->arg, conn, len); + } + } + return ERR_OK; +} + +static err_t +altcp_mbedtls_lower_poll(void *arg, struct altcp_pcb *inner_conn) +{ + struct altcp_pcb *conn = (struct altcp_pcb *)arg; + if (conn) { + LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn); + if (conn->poll) { + return conn->poll(conn->arg, conn); + } + } + return ERR_OK; +} + +static void +altcp_mbedtls_lower_err(void *arg, err_t err) +{ + struct altcp_pcb *conn = (struct altcp_pcb *)arg; + if (conn) { + if (conn->err) { + conn->err(conn->arg, err); + } + } +} + +/* setup functions */ +static void +altcp_mbedtls_setup_callbacks(struct altcp_pcb *conn, struct altcp_pcb *inner_conn) +{ + altcp_arg(inner_conn, conn); + altcp_recv(inner_conn, altcp_mbedtls_lower_recv); + altcp_sent(inner_conn, altcp_mbedtls_lower_sent); + altcp_err(inner_conn, altcp_mbedtls_lower_err); + /* tcp_poll is set when interval is set by application */ + /* listen is set totally different :-) */ +} + +/* TODO: return error? */ +static err_t +altcp_mbedtls_setup(struct altcp_pcb *conn, struct altcp_pcb *inner_conn) +{ + int ret; + /* allocate mbedtls context */ + altcp_mbedtls_state_t *state = altcp_mbedtls_alloc(); + if (state == NULL) { + return ERR_MEM; + } + /* initialize mbedtls context: */ + mbedtls_ssl_init(&state->ssl_context); + ret = mbedtls_ssl_setup(&state->ssl_context, &conf); + if (ret != 0) { + LWIP_ASSERT("mbedtls_ssl_setup failed. \n", ret == 0); + /* TODO: convert 'ret' to err_t */ + return ERR_MEM; + } + /* tell mbedtls about our I/O functions */ + mbedtls_ssl_set_bio(&state->ssl_context, conn, altcp_mbedtls_bio_send, altcp_mbedtls_bio_recv, NULL); + + altcp_mbedtls_setup_callbacks(conn, inner_conn); + conn->inner_conn = inner_conn; + conn->fns = &altcp_mbedtls_functions; + return ERR_OK; +} + +struct altcp_pcb * +altcp_tls_new(struct altcp_pcb *inner_pcb) +{ + struct altcp_pcb *ret; + if (inner_pcb == NULL) { + return NULL; + } + ret = altcp_alloc(); + if (ret != NULL) { + if (altcp_mbedtls_setup(ret, inner_pcb) != ERR_OK) { + altcp_free(ret); + return NULL; + } + } + return ret; +} + +static void +altcp_mbedtls_debug(void *ctx, int level, const char *file, int line, const char *str) +{ + LWIP_UNUSED_ARG(str); + LWIP_UNUSED_ARG(level); + LWIP_UNUSED_ARG(file); + LWIP_UNUSED_ARG(line); + LWIP_UNUSED_ARG(ctx); +} + +struct tls_malloc_helper +{ + size_t c; + size_t len; +}; + +struct tls_malloc_stats_s +{ + size_t allocedBytes; + size_t allocCnt; + size_t maxBytes; + size_t totalBytes; +}; +struct tls_malloc_stats_s tls_malloc_stats; +volatile int tls_malloc_clear_stats; + +static void *tls_malloc(size_t c, size_t len) +{ + struct tls_malloc_helper* hlpr; + void* ret; + if(tls_malloc_clear_stats) + { + if(tls_malloc_clear_stats) + { + tls_malloc_clear_stats = 0; + memset(&tls_malloc_stats, 0, sizeof(tls_malloc_stats)); + } + } + //LWIP_MEMPOOL_ALLOC(name); + hlpr = (struct tls_malloc_helper*)mem_malloc(sizeof(struct tls_malloc_helper) + (c*len)); + //LWIP_ASSERT("alloc failure", hlpr != NULL); + if(hlpr == NULL) + { + return NULL; + } + tls_malloc_stats.allocCnt++; + tls_malloc_stats.allocedBytes += c*len; + if(tls_malloc_stats.allocedBytes > tls_malloc_stats.maxBytes) + { + tls_malloc_stats.maxBytes = tls_malloc_stats.allocedBytes; + } + tls_malloc_stats.totalBytes += c*len; + hlpr->c = c; + hlpr->len = len; + ret = hlpr + 1; + memset(ret, 0, c*len); // zeroing the allocated chunk is required! + return ret; +} + +static void tls_free(void * ptr) +{ + struct tls_malloc_helper* hlpr; + if(ptr == NULL) + { + return; // this obviously happens... + } + hlpr = ((struct tls_malloc_helper*)ptr)-1; + if(!tls_malloc_clear_stats) + { + tls_malloc_stats.allocedBytes -= hlpr->c*hlpr->len; + } + //LWIP_MEMPOOL_FREE(name, x); + mem_free(hlpr); +} + +int dummy_rng(void *ctx, unsigned char *buffer , size_t len) +{ + static size_t ctr; + size_t i; + LWIP_UNUSED_ARG(ctx); + for(i = 0; i < len; i++) { + buffer[i] = (unsigned char)++ctr; + } + return 0; +} + +err_t +altcp_tls_global_init(const u8_t *privkey, size_t privkey_len, + const u8_t *privkey_pass, size_t privkey_pass_len, + const u8_t *cert, size_t cert_len) +{ + int ret; + static mbedtls_entropy_context entropy; + static mbedtls_ctr_drbg_context ctr_drbg; + static mbedtls_x509_crt srvcert; + static mbedtls_pk_context pkey; + + /* TODO: set mbedtls allocation methods */ + //mbedtls_platform_set_calloc_free( &tls_malloc, &tls_free ); + + mbedtls_ssl_config_init( &conf ); + mbedtls_x509_crt_init( &srvcert ); + mbedtls_pk_init( &pkey ); + mbedtls_entropy_init( &entropy ); + mbedtls_ctr_drbg_init( &ctr_drbg ); + + /* Load the certificates and private key */ + ret = mbedtls_x509_crt_parse(&srvcert, cert, cert_len); + if (ret != 0) { + LWIP_ASSERT("mbedtls_x509_crt_parse failed. \n", ret == 0); + /* TODO: convert 'ret' to err_t */ + return ERR_ARG; + } + //key_pem_format[privkeylen]='\0'; + ret = mbedtls_pk_parse_key(&pkey, (const unsigned char *) privkey, privkey_len, privkey_pass, privkey_pass_len); + if (ret != 0) { + LWIP_ASSERT("mbedtls_pk_parse_public_key failed. \n", ret == 0); + /* TODO: convert 'ret' to err_t */ + return ERR_ARG; + } + + /* Seed the RNG (TODO: add custom entropy) */ + ret = mbedtls_ctr_drbg_seed(&ctr_drbg, dummy_rng, &entropy, NULL, 0); + if (ret != 0) { + LWIP_ASSERT("mbedtls_ctr_drbg_seed failed. \n", ret == 0); + /* TODO: convert 'ret' to err_t */ + return ERR_VAL; + } + + /* Setup ssl context (TODO: what's different for a client here? -> might better be done on listen/connect) */ + ret = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_SERVER, + MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); + if (ret != 0) { + LWIP_ASSERT("mbedtls_ssl_config_defaults failed.\n", ret == 0); + /* TODO: convert 'ret' to err_t */ + return ERR_VAL; + } + + mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg); + mbedtls_ssl_conf_dbg(&conf, altcp_mbedtls_debug, stdout); +#ifdef MBEDTLS_SSL_CACHE_C + mbedtls_ssl_conf_session_cache(&conf, &cache, mbedtls_ssl_cache_get, mbedtls_ssl_cache_set); + //mbedtls_ssl_cache_set_timeout(&cache, 30); + mbedtls_ssl_cache_set_max_entries(&cache, 30); +#endif + + mbedtls_ssl_conf_ca_chain( &conf, srvcert.next, NULL ); + ret = mbedtls_ssl_conf_own_cert(&conf, &srvcert, &pkey); + if (ret != 0) { + LWIP_ASSERT("mbedtls_ssl_conf_own_cert failed.\n", ret == 0); + /* TODO: convert 'ret' to err_t */ + return ERR_VAL; + } + return ERR_OK; +} + +/* "virtual" functions */ +static void +altcp_mbedtls_set_poll(struct altcp_pcb *conn, u8_t interval) +{ + if (conn != NULL) { + altcp_poll(conn->inner_conn, altcp_mbedtls_lower_poll, interval); + } +} + +static void +altcp_mbedtls_recved(struct altcp_pcb *conn, u16_t len) +{ + if (conn != NULL) { + altcp_recved(conn->inner_conn, len); + } +} + +static err_t +altcp_mbedtls_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port) +{ + if (conn == NULL) { + return ERR_VAL; + } + return altcp_bind(conn->inner_conn, ipaddr, port); +} + +static err_t +altcp_mbedtls_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected) +{ + if (conn == NULL) { + return ERR_VAL; + } + conn->connected = connected; + return altcp_connect(conn->inner_conn, ipaddr, port, altcp_mbedtls_lower_connected); +} + +static struct altcp_pcb * +altcp_mbedtls_listen(struct altcp_pcb *conn, u8_t backlog, err_t *err) +{ + struct altcp_pcb *lpcb; + if (conn == NULL) { + return NULL; + } + lpcb = altcp_listen_with_backlog_and_err(conn->inner_conn, backlog, err); + if (lpcb != NULL) { + conn->inner_conn = lpcb; + altcp_accept(lpcb, altcp_mbedtls_lower_accept); + return conn; + } + return NULL; +} + +static void +altcp_mbedtls_abort(struct altcp_pcb *conn) +{ + if (conn != NULL) { + altcp_abort(conn->inner_conn); + } +} + +static err_t +altcp_mbedtls_close(struct altcp_pcb *conn) +{ + if (conn == NULL) { + return ERR_VAL; + } + return altcp_close(conn->inner_conn); +} + +static err_t +altcp_mbedtls_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx) +{ + if (conn == NULL) { + return ERR_VAL; + } + return altcp_shutdown(conn->inner_conn, shut_rx, shut_tx); +} + +static err_t +altcp_mbedtls_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags) +{ + int ret; + altcp_mbedtls_state_t *state; + + LWIP_UNUSED_ARG(apiflags); + + if (conn == NULL) { + return ERR_VAL; + } + + state = (altcp_mbedtls_state_t*)conn->state; + + ret = mbedtls_ssl_write(&state->ssl_context, (const unsigned char *)dataptr, len); + if(ret == len) { + return ERR_OK; + } else { + /* assumption: either everything sent or error */ + LWIP_ASSERT("ret <= 0", ret <= 0); + /* TODO: convert error to err_t */ + return ERR_MEM; + } +} + +static err_t +altcp_mbedtls_output(struct altcp_pcb *conn) +{ + if (conn == NULL) { + return ERR_VAL; + } + return altcp_output(conn->inner_conn); +} + +static u16_t +altcp_mbedtls_mss(struct altcp_pcb *conn) +{ + if (conn == NULL) { + return 0; + } + return altcp_mss(conn->inner_conn); +} + +static u16_t +altcp_mbedtls_sndbuf(struct altcp_pcb *conn) +{ + if (conn == NULL) { + return 0; + } + return altcp_sndbuf(conn->inner_conn); +} + +static u16_t +altcp_mbedtls_sndqueuelen(struct altcp_pcb *conn) +{ + if (conn == NULL) { + return 0; + } + return altcp_sndqueuelen(conn->inner_conn); +} + +static void +altcp_mbedtls_setprio(struct altcp_pcb *conn, u8_t prio) +{ + if (conn != NULL) { + altcp_setprio(conn->inner_conn, prio); + } +} + +static void +altcp_mbedtls_dealloc(struct altcp_pcb *conn) +{ + LWIP_UNUSED_ARG(conn); + /* TODO: clean up and free tls state */ +} + +const struct altcp_functions altcp_mbedtls_functions = { + altcp_mbedtls_set_poll, + altcp_mbedtls_recved, + altcp_mbedtls_bind, + altcp_mbedtls_connect, + altcp_mbedtls_listen, + altcp_mbedtls_abort, + altcp_mbedtls_close, + altcp_mbedtls_shutdown, + altcp_mbedtls_write, + altcp_mbedtls_output, + altcp_mbedtls_mss, + altcp_mbedtls_sndbuf, + altcp_mbedtls_sndqueuelen, + altcp_mbedtls_setprio, + altcp_mbedtls_dealloc +}; + +#endif /* LWIP_ALTCP */ diff --git a/src/apps/httpd/fsdata.c b/src/apps/httpd/fsdata.c index 45274cd1..ab9da7e1 100644 --- a/src/apps/httpd/fsdata.c +++ b/src/apps/httpd/fsdata.c @@ -5,8 +5,29 @@ #define file_NULL (struct fsdata_file *) NULL +#ifndef FS_FILE_FLAGS_HEADER_INCLUDED +#define FS_FILE_FLAGS_HEADER_INCLUDED 1 +#endif +#ifndef FS_FILE_FLAGS_HEADER_PERSISTENT +#define FS_FILE_FLAGS_HEADER_PERSISTENT 0 +#endif +/* FSDATA_FILE_ALIGNMENT: 0=off, 1=by variable, 2=by include */ +#ifndef FSDATA_FILE_ALIGNMENT +#define FSDATA_FILE_ALIGNMENT 0 +#endif +#ifndef FSDATA_ALIGN_PRE +#define FSDATA_ALIGN_PRE +#endif +#ifndef FSDATA_ALIGN_POST +#define FSDATA_ALIGN_POST +#endif +#if FSDATA_FILE_ALIGNMENT==2 +#include "fsdata_alignment.h" +#endif +#if FSDATA_FILE_ALIGNMENT==1 static const unsigned int dummy_align__img_sics_gif = 0; -static const unsigned char data__img_sics_gif[] = { +#endif +static const unsigned char FSDATA_ALIGN_PRE data__img_sics_gif[] FSDATA_ALIGN_POST = { /* /img/sics.gif (14 chars) */ 0x2f,0x69,0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x00,0x00,0x00, @@ -15,16 +36,21 @@ static const unsigned char data__img_sics_gif[] = { " (17 bytes) */ 0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d, 0x0a, -/* "Server: lwIP/1.3.1 (http://savannah.nongnu.org/projects/lwip) -" (63 bytes) */ -0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x31,0x2e,0x33, -0x2e,0x31,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e, -0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70, -0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a, -/* "Content-type: image/gif +/* "Server: lwIP/2.0.3d (http://savannah.nongnu.org/projects/lwip) +" (64 bytes) */ +0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x32,0x2e,0x30, +0x2e,0x33,0x64,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61, +0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f, +0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a, + +/* "Content-Length: 724 +" (18+ bytes) */ +0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20, +0x37,0x32,0x34,0x0d,0x0a, +/* "Content-Type: image/gif " (27 bytes) */ -0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x3a,0x20,0x69,0x6d, +0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x69,0x6d, 0x61,0x67,0x65,0x2f,0x67,0x69,0x66,0x0d,0x0a,0x0d,0x0a, /* raw file data (724 bytes) */ 0x47,0x49,0x46,0x38,0x39,0x61,0x46,0x00,0x22,0x00,0xa5,0x00,0x00,0xd9,0x2b,0x39, @@ -74,8 +100,10 @@ static const unsigned char data__img_sics_gif[] = { 0x82,0x0c,0x36,0xe8,0xe0,0x83,0x10,0x46,0x28,0xe1,0x84,0x14,0x56,0x68,0xa1,0x10, 0x41,0x00,0x00,0x3b,}; +#if FSDATA_FILE_ALIGNMENT==1 static const unsigned int dummy_align__404_html = 1; -static const unsigned char data__404_html[] = { +#endif +static const unsigned char FSDATA_ALIGN_PRE data__404_html[] FSDATA_ALIGN_POST = { /* /404.html (10 chars) */ 0x2f,0x34,0x30,0x34,0x2e,0x68,0x74,0x6d,0x6c,0x00,0x00,0x00, @@ -84,16 +112,21 @@ static const unsigned char data__404_html[] = { " (29 bytes) */ 0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x34,0x30,0x34,0x20,0x46,0x69,0x6c, 0x65,0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x0d,0x0a, -/* "Server: lwIP/1.3.1 (http://savannah.nongnu.org/projects/lwip) -" (63 bytes) */ -0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x31,0x2e,0x33, -0x2e,0x31,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e, -0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70, -0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a, -/* "Content-type: text/html +/* "Server: lwIP/2.0.3d (http://savannah.nongnu.org/projects/lwip) +" (64 bytes) */ +0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x32,0x2e,0x30, +0x2e,0x33,0x64,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61, +0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f, +0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a, + +/* "Content-Length: 565 +" (18+ bytes) */ +0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20, +0x35,0x36,0x35,0x0d,0x0a, +/* "Content-Type: text/html " (27 bytes) */ -0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x3a,0x20,0x74,0x65, +0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65, 0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a,0x0d,0x0a, /* raw file data (565 bytes) */ 0x3c,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,0x3c,0x68,0x65,0x61,0x64,0x3e,0x3c,0x74, @@ -133,8 +166,10 @@ static const unsigned char data__404_html[] = { 0x3e,0x0d,0x0a,0x3c,0x2f,0x62,0x6f,0x64,0x79,0x3e,0x0d,0x0a,0x3c,0x2f,0x68,0x74, 0x6d,0x6c,0x3e,0x0d,0x0a,}; +#if FSDATA_FILE_ALIGNMENT==1 static const unsigned int dummy_align__index_html = 2; -static const unsigned char data__index_html[] = { +#endif +static const unsigned char FSDATA_ALIGN_PRE data__index_html[] FSDATA_ALIGN_POST = { /* /index.html (12 chars) */ 0x2f,0x69,0x6e,0x64,0x65,0x78,0x2e,0x68,0x74,0x6d,0x6c,0x00, @@ -143,16 +178,21 @@ static const unsigned char data__index_html[] = { " (17 bytes) */ 0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d, 0x0a, -/* "Server: lwIP/1.3.1 (http://savannah.nongnu.org/projects/lwip) -" (63 bytes) */ -0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x31,0x2e,0x33, -0x2e,0x31,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e, -0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70, -0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a, -/* "Content-type: text/html +/* "Server: lwIP/2.0.3d (http://savannah.nongnu.org/projects/lwip) +" (64 bytes) */ +0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x32,0x2e,0x30, +0x2e,0x33,0x64,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61, +0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f, +0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a, + +/* "Content-Length: 1751 +" (18+ bytes) */ +0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20, +0x31,0x37,0x35,0x31,0x0d,0x0a, +/* "Content-Type: text/html " (27 bytes) */ -0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x3a,0x20,0x74,0x65, +0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65, 0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a,0x0d,0x0a, /* raw file data (1751 bytes) */ 0x3c,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,0x3c,0x68,0x65,0x61,0x64,0x3e,0x3c,0x74, @@ -273,7 +313,7 @@ file_NULL, data__img_sics_gif, data__img_sics_gif + 16, sizeof(data__img_sics_gif) - 16, -1, +FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT, }}; const struct fsdata_file file__404_html[] = { { @@ -281,7 +321,7 @@ file__img_sics_gif, data__404_html, data__404_html + 12, sizeof(data__404_html) - 12, -1, +FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT, }}; const struct fsdata_file file__index_html[] = { { @@ -289,7 +329,7 @@ file__404_html, data__index_html, data__index_html + 12, sizeof(data__index_html) - 12, -1, +FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT, }}; #define FS_ROOT file__index_html diff --git a/src/core/altcp.c b/src/core/altcp.c new file mode 100644 index 00000000..147e45cd --- /dev/null +++ b/src/core/altcp.c @@ -0,0 +1,245 @@ +/** + * @file + * Application layered TCP connection API (to be used from TCPIP thread)\n + * This interface mimics the tcp callback API to the application while preventing + * direct linking (much like virtual functions). + * This way, an application can make use of other application layer protocols + * on top of TCP without knowing the details (e.g. TLS, proxy connection). + * + * This file contains the common functions for altcp to work. + */ + +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#include "lwip/opt.h" + +#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/altcp.h" +#include "lwip/priv/altcp_priv.h" +#include "lwip/tcp.h" +#include "lwip/mem.h" + +#include + +extern const struct altcp_functions altcp_tcp_functions; + +struct altcp_pcb * +altcp_alloc(void) +{ + /* FIXME: pool alloc */ + struct altcp_pcb *ret = (struct altcp_pcb *)mem_malloc(sizeof(struct altcp_pcb)); + if (ret != NULL) { + memset(ret, 0, sizeof(struct altcp_pcb)); + } + return ret; +} + +void +altcp_free(struct altcp_pcb *conn) +{ + /* FIXME: pool alloc */ + if (conn) { + mem_free(conn); + } +} + +void +altcp_arg(struct altcp_pcb *conn, void *arg) +{ + if (conn) { + conn->arg = arg; + } +} + +void +altcp_accept(struct altcp_pcb *conn, altcp_accept_fn accept) +{ + if (conn != NULL) { + conn->accept = accept; + } +} + +void +altcp_recv(struct altcp_pcb *conn, altcp_recv_fn recv) +{ + if (conn) { + conn->recv = recv; + } +} + +void +altcp_sent(struct altcp_pcb *conn, altcp_sent_fn sent) +{ + if (conn) { + conn->sent = sent; + } +} + +void +altcp_poll(struct altcp_pcb *conn, altcp_poll_fn poll, u8_t interval) +{ + if (conn) { + conn->poll = poll; + conn->pollinterval = interval; + if (conn->fns && conn->fns->set_poll) { + conn->fns->set_poll(conn, interval); + } + } +} + +void +altcp_err(struct altcp_pcb *conn, altcp_err_fn err) +{ + if (conn) { + conn->err = err; + } +} + +/* Generic functions calling the "virtual" ones */ + +void +altcp_recved(struct altcp_pcb *conn, u16_t len) +{ + if (conn && conn->fns && conn->fns->recved) { + conn->fns->recved(conn, len); + } +} + +err_t +altcp_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port) +{ + if (conn && conn->fns && conn->fns->bind) { + return conn->fns->bind(conn, ipaddr, port); + } + return ERR_VAL; +} + +err_t +altcp_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected) +{ + if (conn && conn->fns && conn->fns->connect) { + return conn->fns->connect(conn, ipaddr, port, connected); + } + return ERR_VAL; +} + +struct altcp_pcb * +altcp_listen_with_backlog_and_err(struct altcp_pcb *conn, u8_t backlog, err_t *err) +{ + if (conn && conn->fns && conn->fns->listen) { + return conn->fns->listen(conn, backlog, err); + } + return NULL; +} + +void +altcp_abort(struct altcp_pcb *conn) +{ + if (conn && conn->fns && conn->fns->abort) { + conn->fns->abort(conn); + } +} + +err_t +altcp_close(struct altcp_pcb *conn) +{ + if (conn && conn->fns && conn->fns->close) { + return conn->fns->close(conn); + } + return ERR_VAL; +} + +err_t +altcp_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx) +{ + if (conn && conn->fns && conn->fns->shutdown) { + return conn->fns->shutdown(conn, shut_rx, shut_tx); + } + return ERR_VAL; +} + +err_t +altcp_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags) +{ + if (conn && conn->fns && conn->fns->write) { + return conn->fns->write(conn, dataptr, len, apiflags); + } + return ERR_VAL; +} + +err_t +altcp_output(struct altcp_pcb *conn) +{ + if (conn && conn->fns && conn->fns->output) { + return conn->fns->output(conn); + } + return ERR_VAL; +} + +u16_t +altcp_mss(struct altcp_pcb *conn) +{ + if (conn && conn->fns && conn->fns->mss) { + return conn->fns->mss(conn); + } + return 0; +} + +u16_t +altcp_sndbuf(struct altcp_pcb *conn) +{ + if (conn && conn->fns && conn->fns->sndbuf) { + return conn->fns->sndbuf(conn); + } + return 0; +} + +u16_t +altcp_sndqueuelen(struct altcp_pcb *conn) +{ + if (conn && conn->fns && conn->fns->sndqueuelen) { + return conn->fns->sndqueuelen(conn); + } + return 0; +} + +void +altcp_setprio(struct altcp_pcb *conn, u8_t prio) +{ + if (conn && conn->fns && conn->fns->setprio) { + conn->fns->setprio(conn, prio); + } +} + +#endif /* LWIP_ALTCP */ diff --git a/src/core/altcp_tcp.c b/src/core/altcp_tcp.c new file mode 100644 index 00000000..7dab943e --- /dev/null +++ b/src/core/altcp_tcp.c @@ -0,0 +1,364 @@ +/** + * @file + * Application layered TCP connection API (to be used from TCPIP thread)\n + * This interface mimics the tcp callback API to the application while preventing + * direct linking (much like virtual functions). + * This way, an application can make use of other application layer protocols + * on top of TCP without knowing the details (e.g. TLS, proxy connection). + * + * This file contains the base implementation calling into tcp. + */ + +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#include "lwip/opt.h" + +#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/altcp.h" +#include "lwip/priv/altcp_priv.h" +#include "lwip/tcp.h" +#include "lwip/mem.h" + +#include + +/* Variable prototype, the actual declaration is at the end of this file + since it contains pointers to static functions declared here */ +extern const struct altcp_functions altcp_tcp_functions; + +static void altcp_tcp_setup(struct altcp_pcb *conn, struct tcp_pcb *tpcb); + +/* callback functions for TCP */ +static err_t +altcp_tcp_accept(void *arg, struct tcp_pcb *new_tpcb, err_t err) +{ + struct altcp_pcb *listen_conn = (struct altcp_pcb *)arg; + if (listen_conn && listen_conn->accept) { + /* create a new altcp_conn to pass to the next 'accept' callback */ + struct altcp_pcb *new_conn = altcp_alloc(); + if (new_conn == NULL) { + return ERR_MEM; + } + altcp_tcp_setup(new_conn, new_tpcb); + return listen_conn->accept(listen_conn->arg, new_conn, err); + } + return ERR_ARG; +} + +static err_t +altcp_tcp_connected(void *arg, struct tcp_pcb *tpcb, err_t err) +{ + struct altcp_pcb *conn = (struct altcp_pcb *)arg; + if (conn) { + LWIP_ASSERT("pcb mismatch", conn->inner_conn == (struct altcp_pcb *)tpcb); + if (conn->connected) { + return conn->connected(conn->arg, conn, err); + } + } + return ERR_OK; +} + +static err_t +altcp_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) +{ + struct altcp_pcb *conn = (struct altcp_pcb *)arg; + if (conn) { + LWIP_ASSERT("pcb mismatch", conn->inner_conn == (struct altcp_pcb *)tpcb); + if (conn->recv) { + return conn->recv(conn->arg, conn, p, err); + } + } + if (p != NULL) { + /* prevent memory leaks */ + pbuf_free(p); + } + return ERR_OK; +} + +static err_t +altcp_tcp_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) +{ + struct altcp_pcb *conn = (struct altcp_pcb *)arg; + if (conn) { + LWIP_ASSERT("pcb mismatch", conn->inner_conn == (struct altcp_pcb *)tpcb); + if (conn->sent) { + return conn->sent(conn->arg, conn, len); + } + } + return ERR_OK; +} + +static err_t +altcp_tcp_poll(void *arg, struct tcp_pcb *tpcb) +{ + struct altcp_pcb *conn = (struct altcp_pcb *)arg; + if (conn) { + LWIP_ASSERT("pcb mismatch", conn->inner_conn == (struct altcp_pcb *)tpcb); + if (conn->poll) { + return conn->poll(conn->arg, conn); + } + } + return ERR_OK; +} + +static void +altcp_tcp_err(void *arg, err_t err) +{ + struct altcp_pcb *conn = (struct altcp_pcb *)arg; + if (conn) { + if (conn->err) { + conn->err(conn->arg, err); + } + } +} + +/* setup functions */ +static void +altcp_tcp_setup_callbacks(struct altcp_pcb *conn, struct tcp_pcb *tpcb) +{ + tcp_arg(tpcb, conn); + tcp_recv(tpcb, altcp_tcp_recv); + tcp_sent(tpcb, altcp_tcp_sent); + tcp_err(tpcb, altcp_tcp_err); + /* tcp_poll is set when interval is set by application */ + /* listen is set totally different :-) */ +} + +static void +altcp_tcp_setup(struct altcp_pcb *conn, struct tcp_pcb *tpcb) +{ + altcp_tcp_setup_callbacks(conn, tpcb); + conn->inner_conn = (struct altcp_pcb *)tpcb; + conn->fns = &altcp_tcp_functions; +} + +struct altcp_pcb * +altcp_tcp_new_ip_type(u8_t ip_type) +{ + /* FIXME: pool alloc */ + struct altcp_pcb *ret = altcp_alloc(); + if (ret != NULL) { + struct tcp_pcb *tpcb = tcp_new_ip_type(ip_type); + if (tpcb != NULL) { + altcp_tcp_setup(ret, tpcb); + } else { + /* tcp_pcb allocation failed -> free the altcp_pcb too */ + altcp_free(ret); + ret = NULL; + } + } + return ret; +} + + +/* "virtual" functions calling into tcp */ +static void +altcp_tcp_set_poll(struct altcp_pcb *conn, u8_t interval) +{ + if (conn != NULL) { + struct tcp_pcb *pcb = (struct tcp_pcb *)conn->inner_conn; + tcp_poll(pcb, altcp_tcp_poll, interval); + } +} + +static void +altcp_tcp_recved(struct altcp_pcb *conn, u16_t len) +{ + if (conn != NULL) { + struct tcp_pcb *pcb = (struct tcp_pcb *)conn->inner_conn; + tcp_recved(pcb, len); + } +} + +static err_t +altcp_tcp_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port) +{ + struct tcp_pcb *pcb; + if (conn == NULL) { + return ERR_VAL; + } + pcb = (struct tcp_pcb *)conn->inner_conn; + return tcp_bind(pcb, ipaddr, port); +} + +static err_t +altcp_tcp_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected) +{ + struct tcp_pcb *pcb; + if (conn == NULL) { + return ERR_VAL; + } + conn->connected = connected; + pcb = (struct tcp_pcb *)conn->inner_conn; + return tcp_connect(pcb, ipaddr, port, altcp_tcp_connected); +} + +static struct altcp_pcb * +altcp_tcp_listen(struct altcp_pcb *conn, u8_t backlog, err_t *err) +{ + struct tcp_pcb *pcb; + struct tcp_pcb *lpcb; + if (conn == NULL) { + return NULL; + } + pcb = (struct tcp_pcb *)conn->inner_conn; + lpcb = tcp_listen_with_backlog_and_err(pcb, backlog, err); + if (lpcb != NULL) { + conn->inner_conn = (struct altcp_pcb *)lpcb; + tcp_accept(lpcb, altcp_tcp_accept); + return conn; + } + return NULL; +} + +static void +altcp_tcp_abort(struct altcp_pcb *conn) +{ + if (conn != NULL) { + struct tcp_pcb *pcb = (struct tcp_pcb *)conn->inner_conn; + tcp_abort(pcb); + } +} + +static err_t +altcp_tcp_close(struct altcp_pcb *conn) +{ + struct tcp_pcb *pcb; + if (conn == NULL) { + return ERR_VAL; + } + pcb = (struct tcp_pcb *)conn->inner_conn; + return tcp_close(pcb); +} + +static err_t +altcp_tcp_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx) +{ + struct tcp_pcb *pcb; + if (conn == NULL) { + return ERR_VAL; + } + pcb = (struct tcp_pcb *)conn->inner_conn; + return tcp_shutdown(pcb, shut_rx, shut_tx); +} + +static err_t +altcp_tcp_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags) +{ + struct tcp_pcb *pcb; + if (conn == NULL) { + return ERR_VAL; + } + pcb = (struct tcp_pcb *)conn->inner_conn; + return tcp_write(pcb, dataptr, len, apiflags); +} + +static err_t +altcp_tcp_output(struct altcp_pcb *conn) +{ + struct tcp_pcb *pcb; + if (conn == NULL) { + return ERR_VAL; + } + pcb = (struct tcp_pcb *)conn->inner_conn; + return tcp_output(pcb); +} + +static u16_t +altcp_tcp_mss(struct altcp_pcb *conn) +{ + struct tcp_pcb *pcb; + if (conn == NULL) { + return 0; + } + pcb = (struct tcp_pcb *)conn->inner_conn; + return tcp_mss(pcb); +} + +static u16_t +altcp_tcp_sndbuf(struct altcp_pcb *conn) +{ + struct tcp_pcb *pcb; + if (conn == NULL) { + return 0; + } + pcb = (struct tcp_pcb *)conn->inner_conn; + return tcp_sndbuf(pcb); +} + +static u16_t +altcp_tcp_sndqueuelen(struct altcp_pcb *conn) +{ + struct tcp_pcb *pcb; + if (conn == NULL) { + return 0; + } + pcb = (struct tcp_pcb *)conn->inner_conn; + return tcp_sndqueuelen(pcb); +} + +static void +altcp_tcp_setprio(struct altcp_pcb *conn, u8_t prio) +{ + if (conn != NULL) { + struct tcp_pcb *pcb = (struct tcp_pcb *)conn->inner_conn; + tcp_setprio(pcb, prio); + } +} + +static void +altcp_tcp_dealloc(struct altcp_pcb *conn) +{ + LWIP_UNUSED_ARG(conn); + /* no private state to clean up */ +} + +const struct altcp_functions altcp_tcp_functions = { + altcp_tcp_set_poll, + altcp_tcp_recved, + altcp_tcp_bind, + altcp_tcp_connect, + altcp_tcp_listen, + altcp_tcp_abort, + altcp_tcp_close, + altcp_tcp_shutdown, + altcp_tcp_write, + altcp_tcp_output, + altcp_tcp_mss, + altcp_tcp_sndbuf, + altcp_tcp_sndqueuelen, + altcp_tcp_setprio, + altcp_tcp_dealloc +}; + +#endif /* LWIP_ALTCP */ diff --git a/src/include/lwip/altcp.h b/src/include/lwip/altcp.h new file mode 100644 index 00000000..c758a157 --- /dev/null +++ b/src/include/lwip/altcp.h @@ -0,0 +1,165 @@ +/** + * @file + * Application layered TCP connection API (to be used from TCPIP thread)\n + * This interface mimics the tcp callback API to the application while preventing + * direct linking (much like virtual functions). + * This way, an application can make use of other application layer protocols + * on top of TCP without knowing the details (e.g. TLS, proxy connection). + * + * This file contains the generic API. + */ + +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_ALTCP_H +#define LWIP_HDR_ALTCP_H + +#include "lwip/opt.h" + +#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct altcp_pcb; +struct altcp_functions; + +typedef err_t (*altcp_accept_fn)(void *arg, struct altcp_pcb *new_conn, err_t err); +typedef err_t (*altcp_connected_fn)(void *arg, struct altcp_pcb *conn, err_t err); +typedef err_t (*altcp_recv_fn)(void *arg, struct altcp_pcb *conn, struct pbuf *p, err_t err); +typedef err_t (*altcp_sent_fn)(void *arg, struct altcp_pcb *conn, u16_t len); +typedef err_t (*altcp_poll_fn)(void *arg, struct altcp_pcb *conn); +typedef void (*altcp_err_fn)(void *arg, err_t err); + + +struct altcp_pcb { + const struct altcp_functions *fns; + struct altcp_pcb *inner_conn; + void *arg; + void *state; + /* application callbacks */ + altcp_accept_fn accept; + altcp_connected_fn connected; + altcp_recv_fn recv; + altcp_sent_fn sent; + altcp_poll_fn poll; + altcp_err_fn err; + u8_t pollinterval; +}; + +void altcp_arg(struct altcp_pcb *conn, void *arg); +void altcp_accept(struct altcp_pcb *conn, altcp_accept_fn accept); +void altcp_recv(struct altcp_pcb *conn, altcp_recv_fn recv); +void altcp_sent(struct altcp_pcb *conn, altcp_sent_fn sent); +void altcp_poll(struct altcp_pcb *conn, altcp_poll_fn poll, u8_t interval); +void altcp_err(struct altcp_pcb *conn, altcp_err_fn err); + +void altcp_recved(struct altcp_pcb *conn, u16_t len); +err_t altcp_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port); +err_t altcp_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected); + +/* return conn for source code compatibility to tcp callback API only */ +struct altcp_pcb *altcp_listen_with_backlog_and_err(struct altcp_pcb *conn, u8_t backlog, err_t *err); +#define altcp_listen_with_backlog(conn, backlog) altcp_listen_with_backlog_and_err(conn, backlog, NULL) +/** @ingroup altcp */ +#define altcp_listen(conn) altcp_listen_with_backlog_and_err(conn, TCP_DEFAULT_LISTEN_BACKLOG, NULL) + +void altcp_abort(struct altcp_pcb *conn); +err_t altcp_close(struct altcp_pcb *conn); +err_t altcp_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx); + +/* Flags for "apiflags" parameter in tcp_write */ +#define ALTCP_WRITE_FLAG_COPY 0x01 +#define ALTCP_WRITE_FLAG_MORE 0x02 +err_t altcp_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags); +err_t altcp_output(struct altcp_pcb *conn); + +u16_t altcp_mss(struct altcp_pcb *conn); +u16_t altcp_sndbuf(struct altcp_pcb *conn); +u16_t altcp_sndqueuelen(struct altcp_pcb *conn); + +#define TCP_PRIO_MIN 1 +#define TCP_PRIO_NORMAL 64 +#define TCP_PRIO_MAX 127 +void altcp_setprio(struct altcp_pcb *conn, u8_t prio); + +#ifdef __cplusplus +} +#endif + +#else /* LWIP_ALTCP */ + +#include "lwip/tcp.h" + +#define altcp_pcb tcp_pcb +#define altcp_tcp_new_ip_type tcp_new_ip_type + +#define altcp_arg tcp_arg +#define altcp_accept tcp_accept +#define altcp_recv tcp_recv +#define altcp_sent tcp_sent +#define altcp_poll tcp_poll +#define altcp_err tcp_err + +#define altcp_recved tcp_recved +#define altcp_bind tcp_bind +#define altcp_connect tcp_connect + +/* return conn for source code compatibility to tcp callback API only */ +#define altcp_listen_with_backlog_and_err tcp_listen_with_backlog_and_err +#define altcp_listen_with_backlog tcp_listen_with_backlog +/** @ingroup altcp */ +#define altcp_listen tcp_listen + +#define altcp_abort tcp_abort +#define altcp_close tcp_close +#define altcp_shutdown tcp_shutdown + +/* Flags for "apiflags" parameter in tcp_write */ +#define ALTCP_WRITE_FLAG_COPY TCP_WRITE_FLAG_COPY +#define ALTCP_WRITE_FLAG_MORE TCP_WRITE_FLAG_MORE +#define altcp_write tcp_write +#define altcp_output tcp_output + +#define altcp_mss tcp_mss +#define altcp_sndbuf tcp_sndbuf +#define altcp_sndqueuelen tcp_sndqueuelen +#define altcp_setprio tcp_setprio + +#endif /* LWIP_ALTCP */ + +#endif /* LWIP_HDR_ALTCP_H */ diff --git a/src/include/lwip/altcp_tcp.h b/src/include/lwip/altcp_tcp.h new file mode 100644 index 00000000..30d025d2 --- /dev/null +++ b/src/include/lwip/altcp_tcp.h @@ -0,0 +1,71 @@ +/** + * @file + * Application layered TCP connection API (to be used from TCPIP thread)\n + * This interface mimics the tcp callback API to the application while preventing + * direct linking (much like virtual functions). + * This way, an application can make use of other application layer protocols + * on top of TCP without knowing the details (e.g. TLS, proxy connection). + * + * This file contains the base implementation calling into tcp. + */ + +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_ALTCP_TCP_H +#define LWIP_HDR_ALTCP_TCP_H + +#include "lwip/opt.h" + +#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/altcp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*TODO: err_t pconn_set_tcp(struct altcp_pcb *pconn, struct tcp_pcb *tpcb); +struct tcp_pcb *pconn_get_tcp_pcb(struct altcp_pcb *pconn);*/ +struct altcp_pcb *altcp_tcp_new_ip_type(u8_t ip_type); + +#define altcp_tcp_new() altcp_tcp_new_ip_type(IPADDR_TYPE_V4) +#define altcp_tcp_new_ip6() altcp_tcp_new_ip_type(IPADDR_TYPE_V6) + +#ifdef __cplusplus +} +#endif + +#else /* LWIP_ALTCP */ +/* TODO: define altcp_* functions to raw tcp and include lwip/tcp.h? */ +#endif /* LWIP_ALTCP */ + +#endif /* LWIP_HDR_ALTCP_TCP_H */ diff --git a/src/include/lwip/apps/altcp_tls.h b/src/include/lwip/apps/altcp_tls.h new file mode 100644 index 00000000..0ce5e293 --- /dev/null +++ b/src/include/lwip/apps/altcp_tls.h @@ -0,0 +1,63 @@ +/** + * @file + * Application layered TCP connection API (to be used from TCPIP thread) + * + * This file contains function prototypes for a TLS layer. + */ + +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_ALTCP_TLS_H +#define LWIP_HDR_ALTCP_TLS_H + +#include "lwip/opt.h" + +#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/altcp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +err_t altcp_tls_global_init(const u8_t *privkey, size_t privkey_len, + const u8_t *privkey_pass, size_t privkey_pass_len, + const u8_t *cert, size_t cert_len); +struct altcp_pcb *altcp_tls_new(struct altcp_pcb *inner_pcb); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_ALTCP */ + +#endif /* LWIP_HDR_ALTCP_TLS_H */ diff --git a/src/include/lwip/priv/altcp_priv.h b/src/include/lwip/priv/altcp_priv.h new file mode 100644 index 00000000..529777e8 --- /dev/null +++ b/src/include/lwip/priv/altcp_priv.h @@ -0,0 +1,106 @@ +/** + * @file + * Application layered TCP connection API (to be used from TCPIP thread)\n + * This interface mimics the tcp callback API to the application while preventing + * direct linking (much like virtual functions). + * This way, an application can make use of other application layer protocols + * on top of TCP without knowing the details (e.g. TLS, proxy connection). + */ + +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_ALTCP_PRIV_H +#define LWIP_HDR_ALTCP_PRIV_H + +#include "lwip/opt.h" + +#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/altcp.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct altcp_pcb *altcp_alloc(void); +void altcp_free(struct altcp_pcb *conn); + +/* Function prototypes for application layers */ +typedef void (*altcp_set_poll_fn)(struct altcp_pcb *conn, u8_t interval); +typedef void (*altcp_recved_fn)(struct altcp_pcb *conn, u16_t len); +typedef err_t (*altcp_bind_fn)(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port); +typedef err_t (*altcp_connect_fn)(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected); + +typedef struct altcp_pcb *(*altcp_listen_fn)(struct altcp_pcb *conn, u8_t backlog, err_t *err); + +typedef void (*altcp_abort_fn)(struct altcp_pcb *conn); +typedef err_t (*altcp_close_fn)(struct altcp_pcb *conn); +typedef err_t (*altcp_shutdown_fn)(struct altcp_pcb *conn, int shut_rx, int shut_tx); + +typedef err_t (*altcp_write_fn)(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags); +typedef err_t (*altcp_output_fn)(struct altcp_pcb *conn); + +typedef u16_t (*altcp_mss_fn)(struct altcp_pcb *conn); +typedef u16_t (*altcp_sndbuf_fn)(struct altcp_pcb *conn); +typedef u16_t (*altcp_sndqueuelen_fn)(struct altcp_pcb *conn); + +typedef void (*altcp_setprio_fn)(struct altcp_pcb *conn, u8_t prio); + +typedef void (*altcp_dealloc_fn)(struct altcp_pcb *conn); + +struct altcp_functions { + altcp_set_poll_fn set_poll; + altcp_recved_fn recved; + altcp_bind_fn bind; + altcp_connect_fn connect; + altcp_listen_fn listen; + altcp_abort_fn abort; + altcp_close_fn close; + altcp_shutdown_fn shutdown; + altcp_write_fn write; + altcp_output_fn output; + altcp_mss_fn mss; + altcp_sndbuf_fn sndbuf; + altcp_sndqueuelen_fn sndqueuelen; + altcp_setprio_fn setprio; + altcp_dealloc_fn dealloc; +}; + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_ALTCP */ + +#endif /* LWIP_HDR_ALTCP_PRIV_H */