diff --git a/src/apps/http/http_client.c b/src/apps/http/http_client.c index 3db772d8..3457a4f5 100644 --- a/src/apps/http/http_client.c +++ b/src/apps/http/http_client.c @@ -42,6 +42,7 @@ * - select outgoing http version * - optionally follow redirect * - check request uri for invalid characters? (e.g. encode spaces) + * - IPv6 support */ #include "lwip/apps/http_client.h" @@ -535,21 +536,11 @@ httpc_init_connection_common(httpc_state_t **connection, const httpc_connection_ req->uri = req->server_name + server_name_len + 1; memcpy(req->uri, uri, uri_len + 1); #endif - req->pcb = altcp_tcp_new(); + req->pcb = altcp_new(settings->altcp_allocator); if(req->pcb == NULL) { httpc_free_state(req); return ERR_MEM; } -#if LWIP_ALTCP_TLS - if (settings->tls_config) { - struct altcp_pcb *pcbs = altcp_tls_new(settings->tls_config, req->pcb); - if (pcbs == NULL) { - httpc_free_state(req); - return ERR_MEM; - } - req->pcb = pcbs; - } -#endif req->remote_port = settings->use_proxy ? settings->proxy_port : server_port; altcp_arg(req->pcb, req); altcp_recv(req->pcb, httpc_tcp_recv); diff --git a/src/core/altcp.c b/src/core/altcp.c index 2941a6c4..c174789f 100644 --- a/src/core/altcp.c +++ b/src/core/altcp.c @@ -49,6 +49,7 @@ #include "lwip/altcp.h" #include "lwip/priv/altcp_priv.h" +#include "lwip/altcp_tcp.h" #include "lwip/tcp.h" #include "lwip/mem.h" @@ -56,6 +57,9 @@ extern const struct altcp_functions altcp_tcp_functions; +/** For altcp layer implementations only: allocate a new struct altcp_pcb from the pool + * and zero the memory + */ struct altcp_pcb * altcp_alloc(void) { @@ -66,6 +70,8 @@ altcp_alloc(void) return ret; } +/** For altcp layer implementations only: return a struct altcp_pcb to the pool + */ void altcp_free(struct altcp_pcb *conn) { @@ -77,6 +83,47 @@ altcp_free(struct altcp_pcb *conn) } } +/** altcp_new_ip6: @ref altcp_new for IPv6 */ +struct altcp_pcb * +altcp_new_ip6(altcp_allocator_t *allocator) +{ + return altcp_new_ip_type(allocator, IPADDR_TYPE_V6); +} + +/** altcp_new: @ref altcp_new for IPv4 */ +struct altcp_pcb * +altcp_new(altcp_allocator_t *allocator) +{ + return altcp_new_ip_type(allocator, IPADDR_TYPE_V4); +} + +/** altcp_new_ip_type: called by applications to allocate a new pcb with the help of an + * allocator function. + * + * @param allocator allocator function and argument + * @param ip_type IP version of the pcb (IPADDR_TYPE_V4/IPADDR_TYPE_V6) + * @return a new altcp_pcb or NULL on error + */ +struct altcp_pcb * +altcp_new_ip_type(altcp_allocator_t *allocator, u8_t ip_type) +{ + struct altcp_pcb *conn; + if (allocator == NULL) { + /* no allocator given, create a simple TCP connection */ + return altcp_tcp_new_ip_type(ip_type); + } + if (allocator->alloc == NULL) { + /* illegal allocator */ + return NULL; + } + conn = allocator->alloc(allocator->arg, ip_type); + if (conn == NULL) { + /* allocation failed */ + return NULL; + } + return conn; +} + /** * @ingroup altcp * @see tcp_arg() diff --git a/src/core/altcp_alloc.c b/src/core/altcp_alloc.c new file mode 100644 index 00000000..7bc065c9 --- /dev/null +++ b/src/core/altcp_alloc.c @@ -0,0 +1,81 @@ +/** + * @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 allocation implementation that combine several layers. + */ + +/* + * 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/altcp_tcp.h" +#include "lwip/altcp_tls.h" +#include "lwip/priv/altcp_priv.h" +#include "lwip/mem.h" + +#include + +#if LWIP_ALTCP_TLS + +/** This standard allocator function creates an altcp pcb for + * TLS over TCP */ +struct altcp_pcb * +altcp_tls_alloc(void *arg, u8_t ip_type) +{ + struct altcp_pcb *inner_conn, *ret; + struct altcp_tls_config *config = (struct altcp_tls_config *)arg; + LWIP_UNUSED_ARG(ip_type); + + inner_conn = altcp_tcp_new_ip_type(ip_type); + if (inner_conn == NULL) { + return NULL; + } + ret = altcp_tls_new(config, inner_conn); + if (ret == NULL) { + altcp_free(inner_conn); + } + return ret; +} + + +#endif /* LWIP_ALTCP_TLS */ + +#endif /* LWIP_ALTCP */ diff --git a/src/core/altcp_tcp.c b/src/core/altcp_tcp.c index ebb0adf5..ce2caa3a 100644 --- a/src/core/altcp_tcp.c +++ b/src/core/altcp_tcp.c @@ -201,6 +201,17 @@ altcp_tcp_new_ip_type(u8_t ip_type) return NULL; } +/** altcp_tcp allocator function fitting to @ref altcp_allocator_t / @ref altcp_new. +* +* arg pointer is not used for TCP. +*/ +struct altcp_pcb * +altcp_tcp_alloc(void *arg, u8_t ip_type) +{ + LWIP_UNUSED_ARG(arg); + return altcp_tcp_new_ip_type(ip_type); +} + struct altcp_pcb * altcp_tcp_wrap(struct tcp_pcb *tpcb) { diff --git a/src/include/lwip/altcp.h b/src/include/lwip/altcp.h index 37c9c5d9..75e5649a 100644 --- a/src/include/lwip/altcp.h +++ b/src/include/lwip/altcp.h @@ -66,6 +66,7 @@ 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); +typedef struct altcp_pcb* (*altcp_new_fn)(void *arg, u8_t ip_type); struct altcp_pcb { const struct altcp_functions *fns; @@ -82,6 +83,15 @@ struct altcp_pcb { u8_t pollinterval; }; +typedef struct altcp_allocator_s { + altcp_new_fn alloc; + void *arg; +} altcp_allocator_t; + +struct altcp_pcb *altcp_new(altcp_allocator_t *allocator); +struct altcp_pcb *altcp_new_ip6(altcp_allocator_t *allocator); +struct altcp_pcb *altcp_new_ip_type(altcp_allocator_t *allocator, u8_t ip_type); + 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); @@ -145,6 +155,10 @@ enum tcp_state altcp_dbg_get_tcp_state(struct altcp_pcb *conn); #define altcp_tcp_new tcp_new #define altcp_tcp_new_ip6 tcp_new_ip6 +#define altcp_new(allocator) tcp_new() +#define altcp_new_ip6(allocator) tcp_new_ip6() +#define altcp_new_ip_type(allocator, ip_type) tcp_new_ip_type(ip_type) + #define altcp_arg tcp_arg #define altcp_accept tcp_accept #define altcp_recv tcp_recv diff --git a/src/include/lwip/altcp_tcp.h b/src/include/lwip/altcp_tcp.h index 3bccd635..dbde5846 100644 --- a/src/include/lwip/altcp_tcp.h +++ b/src/include/lwip/altcp_tcp.h @@ -58,6 +58,8 @@ 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) +struct altcp_pcb *altcp_tcp_alloc(void *arg, u8_t ip_type); + struct tcp_pcb; struct altcp_pcb *altcp_tcp_wrap(struct tcp_pcb *tpcb); diff --git a/src/include/lwip/altcp_tls.h b/src/include/lwip/altcp_tls.h index fb554a8d..1c0da116 100644 --- a/src/include/lwip/altcp_tls.h +++ b/src/include/lwip/altcp_tls.h @@ -82,6 +82,13 @@ void altcp_tls_free_config(struct altcp_tls_config *conf); */ struct altcp_pcb *altcp_tls_new(struct altcp_tls_config *config, struct altcp_pcb *inner_pcb); +/** @ingroup altcp_tls + * Create new ALTCP_TLS layer + * This allocator function fits to @ref altcp_allocator_t / @ref altcp_new. + * 'arg' must contain a struct altcp_tls_config *. + */ +struct altcp_pcb *altcp_tls_alloc(void *arg, u8_t ip_type); + /** @ingroup altcp_tls * Return pointer to internal TLS context so application can tweak it. * Real type depends on port (e.g. mbedtls) diff --git a/src/include/lwip/apps/http_client.h b/src/include/lwip/apps/http_client.h index 899f47ac..cf44cab1 100644 --- a/src/include/lwip/apps/http_client.h +++ b/src/include/lwip/apps/http_client.h @@ -123,8 +123,8 @@ typedef struct _httpc_connection { u8_t use_proxy; /* @todo: add username:pass? */ -#if LWIP_ALTCP_TLS - struct altcp_tls_config *tls_config; +#if LWIP_ALTCP + altcp_allocator_t *altcp_allocator; #endif /* this callback is called when the transfer is finished (or aborted) */