1/**
2 * @file
3 * @defgroup altcp Application layered TCP Functions
4 * @ingroup altcp_api
5 *
6 * This file contains the common functions for altcp to work.
7 * For more details see @ref altcp_api.
8 */
9
10/**
11 * @defgroup altcp_api Application layered TCP Introduction
12 * @ingroup callbackstyle_api
13 *
14 * Overview
15 * --------
16 * altcp (application layered TCP connection API; to be used from TCPIP thread)
17 * is an abstraction layer that prevents applications linking hard against the
18 * @ref tcp.h functions while providing the same functionality. It is used to
19 * e.g. add SSL/TLS (see LWIP_ALTCP_TLS) or proxy-connect support to an application
20 * written for the tcp callback API without that application knowing the
21 * protocol details.
22 *
23 * * This interface mimics the tcp callback API to the application while preventing
24 *   direct linking (much like virtual functions).
25 * * This way, an application can make use of other application layer protocols
26 *   on top of TCP without knowing the details (e.g. TLS, proxy connection).
27 * * This is achieved by simply including "lwip/altcp.h" instead of "lwip/tcp.h",
28 *   replacing "struct tcp_pcb" with "struct altcp_pcb" and prefixing all functions
29 *   with "altcp_" instead of "tcp_".
30 *
31 * With altcp support disabled (LWIP_ALTCP==0), applications written against the
32 * altcp API can still be compiled but are directly linked against the tcp.h
33 * callback API and then cannot use layered protocols. To minimize code changes
34 * in this case, the use of altcp_allocators is strongly suggested.
35 *
36 * Usage
37 * -----
38 * To make use of this API from an existing tcp raw API application:
39 * * Include "lwip/altcp.h" instead of "lwip/tcp.h"
40 * * Replace "struct tcp_pcb" with "struct altcp_pcb"
41 * * Prefix all called tcp API functions with "altcp_" instead of "tcp_" to link
42 *   against the altcp functions
43 * * @ref altcp_new (and @ref altcp_new_ip_type/@ref altcp_new_ip6) take
44 *   an @ref altcp_allocator_t as an argument, whereas the original tcp API
45 *   functions take no arguments.
46 * * An @ref altcp_allocator_t allocator is an object that holds a pointer to an
47 *   allocator object and a corresponding state (e.g. for TLS, the corresponding
48 *   state may hold certificates or keys). This way, the application does not
49 *   even need to know if it uses TLS or pure TCP, this is handled at runtime
50 *   by passing a specific allocator.
51 * * An application can alternatively bind hard to the altcp_tls API by calling
52 *   @ref altcp_tls_new or @ref altcp_tls_wrap.
53 * * The TLS layer is not directly implemented by lwIP, but a port to mbedTLS is
54 *   provided.
55 * * Another altcp layer is proxy-connect to use TLS behind a HTTP proxy (see
56 *   @ref altcp_proxyconnect.h)
57 *
58 * altcp_allocator_t
59 * -----------------
60 * An altcp allocator is created by the application by combining an allocator
61 * callback function and a corresponding state, e.g.:\code{.c}
62 * static const unsigned char cert[] = {0x2D, ... (see mbedTLS doc for how to create this)};
63 * struct altcp_tls_config * conf = altcp_tls_create_config_client(cert, sizeof(cert));
64 * altcp_allocator_t tls_allocator = {
65 *   altcp_tls_alloc, conf
66 * };
67 * \endcode
68 *
69 *
70 * struct altcp_tls_config
71 * -----------------------
72 * The struct altcp_tls_config holds state that is needed to create new TLS client
73 * or server connections (e.g. certificates and private keys).
74 *
75 * It is not defined by lwIP itself but by the TLS port (e.g. altcp_tls to mbedTLS
76 * adaption). However, the parameters used to create it are defined in @ref
77 * altcp_tls.h (see @ref altcp_tls_create_config_server_privkey_cert for servers
78 * and @ref altcp_tls_create_config_client/@ref altcp_tls_create_config_client_2wayauth
79 * for clients).
80 *
81 * For mbedTLS, ensure that certificates can be parsed by 'mbedtls_x509_crt_parse()' and
82 * private keys can be parsed by 'mbedtls_pk_parse_key()'.
83 */
84
85/*
86 * Copyright (c) 2017 Simon Goldschmidt
87 * All rights reserved.
88 *
89 * Redistribution and use in source and binary forms, with or without modification,
90 * are permitted provided that the following conditions are met:
91 *
92 * 1. Redistributions of source code must retain the above copyright notice,
93 *    this list of conditions and the following disclaimer.
94 * 2. Redistributions in binary form must reproduce the above copyright notice,
95 *    this list of conditions and the following disclaimer in the documentation
96 *    and/or other materials provided with the distribution.
97 * 3. The name of the author may not be used to endorse or promote products
98 *    derived from this software without specific prior written permission.
99 *
100 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
101 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
102 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
103 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
104 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
105 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
106 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
107 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
108 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
109 * OF SUCH DAMAGE.
110 *
111 * This file is part of the lwIP TCP/IP stack.
112 *
113 * Author: Simon Goldschmidt <goldsimon@gmx.de>
114 *
115 */
116
117#include "lwip/opt.h"
118
119#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */
120
121#include "lwip/altcp.h"
122#include "lwip/priv/altcp_priv.h"
123#include "lwip/altcp_tcp.h"
124#include "lwip/tcp.h"
125#include "lwip/mem.h"
126
127#include <string.h>
128
129extern const struct altcp_functions altcp_tcp_functions;
130
131/**
132 * For altcp layer implementations only: allocate a new struct altcp_pcb from the pool
133 * and zero the memory
134 */
135struct altcp_pcb *
136altcp_alloc(void)
137{
138  struct altcp_pcb *ret = (struct altcp_pcb *)memp_malloc(MEMP_ALTCP_PCB);
139  if (ret != NULL) {
140    memset(ret, 0, sizeof(struct altcp_pcb));
141  }
142  return ret;
143}
144
145/**
146 * For altcp layer implementations only: return a struct altcp_pcb to the pool
147 */
148void
149altcp_free(struct altcp_pcb *conn)
150{
151  if (conn) {
152    if (conn->fns && conn->fns->dealloc) {
153      conn->fns->dealloc(conn);
154    }
155    memp_free(MEMP_ALTCP_PCB, conn);
156  }
157}
158
159/**
160 * @ingroup altcp
161 * altcp_new_ip6: @ref altcp_new for IPv6
162 */
163struct altcp_pcb *
164altcp_new_ip6(altcp_allocator_t *allocator)
165{
166  return altcp_new_ip_type(allocator, IPADDR_TYPE_V6);
167}
168
169/**
170 * @ingroup altcp
171 * altcp_new: @ref altcp_new for IPv4
172 */
173struct altcp_pcb *
174altcp_new(altcp_allocator_t *allocator)
175{
176  return altcp_new_ip_type(allocator, IPADDR_TYPE_V4);
177}
178
179/**
180 * @ingroup altcp
181 * altcp_new_ip_type: called by applications to allocate a new pcb with the help of an
182 * allocator function.
183 *
184 * @param allocator allocator function and argument
185 * @param ip_type IP version of the pcb (@ref lwip_ip_addr_type)
186 * @return a new altcp_pcb or NULL on error
187 */
188struct altcp_pcb *
189altcp_new_ip_type(altcp_allocator_t *allocator, u8_t ip_type)
190{
191  struct altcp_pcb *conn;
192  if (allocator == NULL) {
193    /* no allocator given, create a simple TCP connection */
194    return altcp_tcp_new_ip_type(ip_type);
195  }
196  if (allocator->alloc == NULL) {
197    /* illegal allocator */
198    return NULL;
199  }
200  conn = allocator->alloc(allocator->arg, ip_type);
201  if (conn == NULL) {
202    /* allocation failed */
203    return NULL;
204  }
205  return conn;
206}
207
208/**
209 * @ingroup altcp
210 * @see tcp_arg()
211 */
212void
213altcp_arg(struct altcp_pcb *conn, void *arg)
214{
215  if (conn) {
216    conn->arg = arg;
217  }
218}
219
220/**
221 * @ingroup altcp
222 * @see tcp_accept()
223 */
224void
225altcp_accept(struct altcp_pcb *conn, altcp_accept_fn accept)
226{
227  if (conn != NULL) {
228    conn->accept = accept;
229  }
230}
231
232/**
233 * @ingroup altcp
234 * @see tcp_recv()
235 */
236void
237altcp_recv(struct altcp_pcb *conn, altcp_recv_fn recv)
238{
239  if (conn) {
240    conn->recv = recv;
241  }
242}
243
244/**
245 * @ingroup altcp
246 * @see tcp_sent()
247 */
248void
249altcp_sent(struct altcp_pcb *conn, altcp_sent_fn sent)
250{
251  if (conn) {
252    conn->sent = sent;
253  }
254}
255
256/**
257 * @ingroup altcp
258 * @see tcp_poll()
259 */
260void
261altcp_poll(struct altcp_pcb *conn, altcp_poll_fn poll, u8_t interval)
262{
263  if (conn) {
264    conn->poll = poll;
265    conn->pollinterval = interval;
266    if (conn->fns && conn->fns->set_poll) {
267      conn->fns->set_poll(conn, interval);
268    }
269  }
270}
271
272/**
273 * @ingroup altcp
274 * @see tcp_err()
275 */
276void
277altcp_err(struct altcp_pcb *conn, altcp_err_fn err)
278{
279  if (conn) {
280    conn->err = err;
281  }
282}
283
284/* Generic functions calling the "virtual" ones */
285
286/**
287 * @ingroup altcp
288 * @see tcp_recved()
289 */
290void
291altcp_recved(struct altcp_pcb *conn, u16_t len)
292{
293  if (conn && conn->fns && conn->fns->recved) {
294    conn->fns->recved(conn, len);
295  }
296}
297
298/**
299 * @ingroup altcp
300 * @see tcp_bind()
301 */
302err_t
303altcp_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port)
304{
305  if (conn && conn->fns && conn->fns->bind) {
306    return conn->fns->bind(conn, ipaddr, port);
307  }
308  return ERR_VAL;
309}
310
311/**
312 * @ingroup altcp
313 * @see tcp_connect()
314 */
315err_t
316altcp_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected)
317{
318  if (conn && conn->fns && conn->fns->connect) {
319    return conn->fns->connect(conn, ipaddr, port, connected);
320  }
321  return ERR_VAL;
322}
323
324/**
325 * @ingroup altcp
326 * @see tcp_listen_with_backlog_and_err()
327 */
328struct altcp_pcb *
329altcp_listen_with_backlog_and_err(struct altcp_pcb *conn, u8_t backlog, err_t *err)
330{
331  if (conn && conn->fns && conn->fns->listen) {
332    return conn->fns->listen(conn, backlog, err);
333  }
334  return NULL;
335}
336
337/**
338 * @ingroup altcp
339 * @see tcp_abort()
340 */
341void
342altcp_abort(struct altcp_pcb *conn)
343{
344  if (conn && conn->fns && conn->fns->abort) {
345    conn->fns->abort(conn);
346  }
347}
348
349/**
350 * @ingroup altcp
351 * @see tcp_close()
352 */
353err_t
354altcp_close(struct altcp_pcb *conn)
355{
356  if (conn && conn->fns && conn->fns->close) {
357    return conn->fns->close(conn);
358  }
359  return ERR_VAL;
360}
361
362/**
363 * @ingroup altcp
364 * @see tcp_shutdown()
365 */
366err_t
367altcp_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx)
368{
369  if (conn && conn->fns && conn->fns->shutdown) {
370    return conn->fns->shutdown(conn, shut_rx, shut_tx);
371  }
372  return ERR_VAL;
373}
374
375/**
376 * @ingroup altcp
377 * @see tcp_write()
378 */
379err_t
380altcp_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags)
381{
382  if (conn && conn->fns && conn->fns->write) {
383    return conn->fns->write(conn, dataptr, len, apiflags);
384  }
385  return ERR_VAL;
386}
387
388/**
389 * @ingroup altcp
390 * @see tcp_output()
391 */
392err_t
393altcp_output(struct altcp_pcb *conn)
394{
395  if (conn && conn->fns && conn->fns->output) {
396    return conn->fns->output(conn);
397  }
398  return ERR_VAL;
399}
400
401/**
402 * @ingroup altcp
403 * @see tcp_mss()
404 */
405u16_t
406altcp_mss(struct altcp_pcb *conn)
407{
408  if (conn && conn->fns && conn->fns->mss) {
409    return conn->fns->mss(conn);
410  }
411  return 0;
412}
413
414/**
415 * @ingroup altcp
416 * @see tcp_sndbuf()
417 */
418u16_t
419altcp_sndbuf(struct altcp_pcb *conn)
420{
421  if (conn && conn->fns && conn->fns->sndbuf) {
422    return conn->fns->sndbuf(conn);
423  }
424  return 0;
425}
426
427/**
428 * @ingroup altcp
429 * @see tcp_sndqueuelen()
430 */
431u16_t
432altcp_sndqueuelen(struct altcp_pcb *conn)
433{
434  if (conn && conn->fns && conn->fns->sndqueuelen) {
435    return conn->fns->sndqueuelen(conn);
436  }
437  return 0;
438}
439
440void
441altcp_nagle_disable(struct altcp_pcb *conn)
442{
443  if (conn && conn->fns && conn->fns->nagle_disable) {
444    conn->fns->nagle_disable(conn);
445  }
446}
447
448void
449altcp_nagle_enable(struct altcp_pcb *conn)
450{
451  if (conn && conn->fns && conn->fns->nagle_enable) {
452    conn->fns->nagle_enable(conn);
453  }
454}
455
456int
457altcp_nagle_disabled(struct altcp_pcb *conn)
458{
459  if (conn && conn->fns && conn->fns->nagle_disabled) {
460    return conn->fns->nagle_disabled(conn);
461  }
462  return 0;
463}
464
465/**
466 * @ingroup altcp
467 * @see tcp_setprio()
468 */
469void
470altcp_setprio(struct altcp_pcb *conn, u8_t prio)
471{
472  if (conn && conn->fns && conn->fns->setprio) {
473    conn->fns->setprio(conn, prio);
474  }
475}
476
477err_t
478altcp_get_tcp_addrinfo(struct altcp_pcb *conn, int local, ip_addr_t *addr, u16_t *port)
479{
480  if (conn && conn->fns && conn->fns->addrinfo) {
481    return conn->fns->addrinfo(conn, local, addr, port);
482  }
483  return ERR_VAL;
484}
485
486ip_addr_t *
487altcp_get_ip(struct altcp_pcb *conn, int local)
488{
489  if (conn && conn->fns && conn->fns->getip) {
490    return conn->fns->getip(conn, local);
491  }
492  return NULL;
493}
494
495u16_t
496altcp_get_port(struct altcp_pcb *conn, int local)
497{
498  if (conn && conn->fns && conn->fns->getport) {
499    return conn->fns->getport(conn, local);
500  }
501  return 0;
502}
503
504#ifdef LWIP_DEBUG
505enum tcp_state
506altcp_dbg_get_tcp_state(struct altcp_pcb *conn)
507{
508  if (conn && conn->fns && conn->fns->dbg_get_tcp_state) {
509    return conn->fns->dbg_get_tcp_state(conn);
510  }
511  return CLOSED;
512}
513#endif
514
515/* Default implementations for the "virtual" functions */
516
517void
518altcp_default_set_poll(struct altcp_pcb *conn, u8_t interval)
519{
520  if (conn && conn->inner_conn) {
521    altcp_poll(conn->inner_conn, conn->poll, interval);
522  }
523}
524
525void
526altcp_default_recved(struct altcp_pcb *conn, u16_t len)
527{
528  if (conn && conn->inner_conn) {
529    altcp_recved(conn->inner_conn, len);
530  }
531}
532
533err_t
534altcp_default_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port)
535{
536  if (conn && conn->inner_conn) {
537    return altcp_bind(conn->inner_conn, ipaddr, port);
538  }
539  return ERR_VAL;
540}
541
542err_t
543altcp_default_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx)
544{
545  if (conn) {
546    if (shut_rx && shut_tx && conn->fns && conn->fns->close) {
547      /* default shutdown for both sides is close */
548      return conn->fns->close(conn);
549    }
550    if (conn->inner_conn) {
551      return altcp_shutdown(conn->inner_conn, shut_rx, shut_tx);
552    }
553  }
554  return ERR_VAL;
555}
556
557err_t
558altcp_default_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags)
559{
560  if (conn && conn->inner_conn) {
561    return altcp_write(conn->inner_conn, dataptr, len, apiflags);
562  }
563  return ERR_VAL;
564}
565
566err_t
567altcp_default_output(struct altcp_pcb *conn)
568{
569  if (conn && conn->inner_conn) {
570    return altcp_output(conn->inner_conn);
571  }
572  return ERR_VAL;
573}
574
575u16_t
576altcp_default_mss(struct altcp_pcb *conn)
577{
578  if (conn && conn->inner_conn) {
579    return altcp_mss(conn->inner_conn);
580  }
581  return 0;
582}
583
584u16_t
585altcp_default_sndbuf(struct altcp_pcb *conn)
586{
587  if (conn && conn->inner_conn) {
588    return altcp_sndbuf(conn->inner_conn);
589  }
590  return 0;
591}
592
593u16_t
594altcp_default_sndqueuelen(struct altcp_pcb *conn)
595{
596  if (conn && conn->inner_conn) {
597    return altcp_sndqueuelen(conn->inner_conn);
598  }
599  return 0;
600}
601
602void
603altcp_default_nagle_disable(struct altcp_pcb *conn)
604{
605  if (conn && conn->inner_conn) {
606    altcp_nagle_disable(conn->inner_conn);
607  }
608}
609
610void
611altcp_default_nagle_enable(struct altcp_pcb *conn)
612{
613  if (conn && conn->inner_conn) {
614    altcp_nagle_enable(conn->inner_conn);
615  }
616}
617
618int
619altcp_default_nagle_disabled(struct altcp_pcb *conn)
620{
621  if (conn && conn->inner_conn) {
622    return altcp_nagle_disabled(conn->inner_conn);
623  }
624  return 0;
625}
626
627void
628altcp_default_setprio(struct altcp_pcb *conn, u8_t prio)
629{
630  if (conn && conn->inner_conn) {
631    altcp_setprio(conn->inner_conn, prio);
632  }
633}
634
635void
636altcp_default_dealloc(struct altcp_pcb *conn)
637{
638  LWIP_UNUSED_ARG(conn);
639  /* nothing to do */
640}
641
642err_t
643altcp_default_get_tcp_addrinfo(struct altcp_pcb *conn, int local, ip_addr_t *addr, u16_t *port)
644{
645  if (conn && conn->inner_conn) {
646    return altcp_get_tcp_addrinfo(conn->inner_conn, local, addr, port);
647  }
648  return ERR_VAL;
649}
650
651ip_addr_t *
652altcp_default_get_ip(struct altcp_pcb *conn, int local)
653{
654  if (conn && conn->inner_conn) {
655    return altcp_get_ip(conn->inner_conn, local);
656  }
657  return NULL;
658}
659
660u16_t
661altcp_default_get_port(struct altcp_pcb *conn, int local)
662{
663  if (conn && conn->inner_conn) {
664    return altcp_get_port(conn->inner_conn, local);
665  }
666  return 0;
667}
668
669#ifdef LWIP_DEBUG
670enum tcp_state
671altcp_default_dbg_get_tcp_state(struct altcp_pcb *conn)
672{
673  if (conn && conn->inner_conn) {
674    return altcp_dbg_get_tcp_state(conn->inner_conn);
675  }
676  return CLOSED;
677}
678#endif
679
680
681#endif /* LWIP_ALTCP */
682