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