Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_altcp_tcp.c Source File

lwip_altcp_tcp.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * Application layered TCP connection API (to be used from TCPIP thread)\n
00004  * This interface mimics the tcp callback API to the application while preventing
00005  * direct linking (much like virtual functions).
00006  * This way, an application can make use of other application layer protocols
00007  * on top of TCP without knowing the details (e.g. TLS, proxy connection).
00008  *
00009  * This file contains the base implementation calling into tcp.
00010  */
00011 
00012 /*
00013  * Copyright (c) 2017 Simon Goldschmidt
00014  * All rights reserved.
00015  *
00016  * Redistribution and use in source and binary forms, with or without modification,
00017  * are permitted provided that the following conditions are met:
00018  *
00019  * 1. Redistributions of source code must retain the above copyright notice,
00020  *    this list of conditions and the following disclaimer.
00021  * 2. Redistributions in binary form must reproduce the above copyright notice,
00022  *    this list of conditions and the following disclaimer in the documentation
00023  *    and/or other materials provided with the distribution.
00024  * 3. The name of the author may not be used to endorse or promote products
00025  *    derived from this software without specific prior written permission.
00026  *
00027  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00028  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00029  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00030  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00031  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00032  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00033  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00034  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00035  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00036  * OF SUCH DAMAGE.
00037  *
00038  * This file is part of the lwIP TCP/IP stack.
00039  *
00040  * Author: Simon Goldschmidt <goldsimon@gmx.de>
00041  *
00042  */
00043 
00044 #include "lwip/opt.h"
00045 
00046 #if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */
00047 
00048 #include "lwip/altcp.h"
00049 #include "lwip/altcp_tcp.h"
00050 #include "lwip/priv/altcp_priv.h"
00051 #include "lwip/tcp.h"
00052 #include "lwip/mem.h"
00053 
00054 #include <string.h>
00055 
00056 #define ALTCP_TCP_ASSERT_CONN(conn) do { \
00057   LWIP_ASSERT("conn->inner_conn == NULL", (conn)->inner_conn == NULL); \
00058   LWIP_UNUSED_ARG(conn); /* for LWIP_NOASSERT */ } while(0)
00059 #define ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb) do { \
00060   LWIP_ASSERT("pcb mismatch", (conn)->state == tpcb); \
00061   LWIP_UNUSED_ARG(tpcb); /* for LWIP_NOASSERT */ \
00062   ALTCP_TCP_ASSERT_CONN(conn); } while(0)
00063 
00064 
00065 /* Variable prototype, the actual declaration is at the end of this file
00066    since it contains pointers to static functions declared here */
00067 extern const struct altcp_functions altcp_tcp_functions;
00068 
00069 static void altcp_tcp_setup(struct altcp_pcb *conn, struct tcp_pcb *tpcb);
00070 
00071 /* callback functions for TCP */
00072 static err_t
00073 altcp_tcp_accept(void *arg, struct tcp_pcb *new_tpcb, err_t err)
00074 {
00075   struct altcp_pcb *listen_conn = (struct altcp_pcb *)arg;
00076   if (listen_conn && listen_conn->accept) {
00077     /* create a new altcp_conn to pass to the next 'accept' callback */
00078     struct altcp_pcb *new_conn = altcp_alloc();
00079     if (new_conn == NULL) {
00080       return ERR_MEM;
00081     }
00082     altcp_tcp_setup(new_conn, new_tpcb);
00083     return listen_conn->accept(listen_conn->arg, new_conn, err);
00084   }
00085   return ERR_ARG;
00086 }
00087 
00088 static err_t
00089 altcp_tcp_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
00090 {
00091   struct altcp_pcb *conn = (struct altcp_pcb *)arg;
00092   if (conn) {
00093     ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb);
00094     if (conn->connected) {
00095       return conn->connected(conn->arg, conn, err);
00096     }
00097   }
00098   return ERR_OK;
00099 }
00100 
00101 static err_t
00102 altcp_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
00103 {
00104   struct altcp_pcb *conn = (struct altcp_pcb *)arg;
00105   if (conn) {
00106     ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb);
00107     if (conn->recv) {
00108       return conn->recv(conn->arg, conn, p, err);
00109     }
00110   }
00111   if (p != NULL) {
00112     /* prevent memory leaks */
00113     pbuf_free(p);
00114   }
00115   return ERR_OK;
00116 }
00117 
00118 static err_t
00119 altcp_tcp_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
00120 {
00121   struct altcp_pcb *conn = (struct altcp_pcb *)arg;
00122   if (conn) {
00123     ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb);
00124     if (conn->sent) {
00125       return conn->sent(conn->arg, conn, len);
00126     }
00127   }
00128   return ERR_OK;
00129 }
00130 
00131 static err_t
00132 altcp_tcp_poll(void *arg, struct tcp_pcb *tpcb)
00133 {
00134   struct altcp_pcb *conn = (struct altcp_pcb *)arg;
00135   if (conn) {
00136     ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb);
00137     if (conn->poll) {
00138       return conn->poll(conn->arg, conn);
00139     }
00140   }
00141   return ERR_OK;
00142 }
00143 
00144 static void
00145 altcp_tcp_err(void *arg, err_t err)
00146 {
00147   struct altcp_pcb *conn = (struct altcp_pcb *)arg;
00148   if (conn) {
00149     conn->state = NULL; /* already freed */
00150     if (conn->err) {
00151       conn->err(conn->arg, err);
00152     }
00153     altcp_free(conn);
00154   }
00155 }
00156 
00157 /* setup functions */
00158 
00159 static void
00160 altcp_tcp_remove_callbacks(struct tcp_pcb *tpcb)
00161 {
00162   tcp_arg(tpcb, NULL);
00163   tcp_recv(tpcb, NULL);
00164   tcp_sent(tpcb, NULL);
00165   tcp_err(tpcb, NULL);
00166   tcp_poll(tpcb, NULL, tpcb->pollinterval);
00167 }
00168 
00169 static void
00170 altcp_tcp_setup_callbacks(struct altcp_pcb *conn, struct tcp_pcb *tpcb)
00171 {
00172   tcp_arg(tpcb, conn);
00173   tcp_recv(tpcb, altcp_tcp_recv);
00174   tcp_sent(tpcb, altcp_tcp_sent);
00175   tcp_err(tpcb, altcp_tcp_err);
00176   /* tcp_poll is set when interval is set by application */
00177   /* listen is set totally different :-) */
00178 }
00179 
00180 static void
00181 altcp_tcp_setup(struct altcp_pcb *conn, struct tcp_pcb *tpcb)
00182 {
00183   altcp_tcp_setup_callbacks(conn, tpcb);
00184   conn->state = tpcb;
00185   conn->fns = &altcp_tcp_functions;
00186 }
00187 
00188 struct altcp_pcb *
00189 altcp_tcp_new_ip_type(u8_t ip_type)
00190 {
00191   /* Allocate the tcp pcb first to invoke the priority handling code
00192      if we're out of pcbs */
00193   struct tcp_pcb *tpcb = tcp_new_ip_type(ip_type);
00194   if (tpcb != NULL) {
00195     struct altcp_pcb *ret = altcp_alloc();
00196     if (ret != NULL) {
00197       altcp_tcp_setup(ret, tpcb);
00198       return ret;
00199     } else {
00200       /* altcp_pcb allocation failed -> free the tcp_pcb too */
00201       tcp_close(tpcb);
00202     }
00203   }
00204   return NULL;
00205 }
00206 
00207 /** altcp_tcp allocator function fitting to @ref altcp_allocator_t / @ref altcp_new.
00208 *
00209 * arg pointer is not used for TCP.
00210 */
00211 struct altcp_pcb *
00212 altcp_tcp_alloc(void *arg, u8_t ip_type)
00213 {
00214   LWIP_UNUSED_ARG(arg);
00215   return altcp_tcp_new_ip_type(ip_type);
00216 }
00217 
00218 struct altcp_pcb *
00219 altcp_tcp_wrap(struct tcp_pcb *tpcb)
00220 {
00221   if (tpcb != NULL) {
00222     struct altcp_pcb *ret = altcp_alloc();
00223     if (ret != NULL) {
00224       altcp_tcp_setup(ret, tpcb);
00225       return ret;
00226     }
00227   }
00228   return NULL;
00229 }
00230 
00231 
00232 /* "virtual" functions calling into tcp */
00233 static void
00234 altcp_tcp_set_poll(struct altcp_pcb *conn, u8_t interval)
00235 {
00236   if (conn != NULL) {
00237     struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
00238     ALTCP_TCP_ASSERT_CONN(conn);
00239     tcp_poll(pcb, altcp_tcp_poll, interval);
00240   }
00241 }
00242 
00243 static void
00244 altcp_tcp_recved(struct altcp_pcb *conn, u16_t len)
00245 {
00246   if (conn != NULL) {
00247     struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
00248     ALTCP_TCP_ASSERT_CONN(conn);
00249     tcp_recved(pcb, len);
00250   }
00251 }
00252 
00253 static err_t
00254 altcp_tcp_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port)
00255 {
00256   struct tcp_pcb *pcb;
00257   if (conn == NULL) {
00258     return ERR_VAL;
00259   }
00260   ALTCP_TCP_ASSERT_CONN(conn);
00261   pcb = (struct tcp_pcb *)conn->state;
00262   return tcp_bind(pcb, ipaddr, port);
00263 }
00264 
00265 static err_t
00266 altcp_tcp_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected)
00267 {
00268   struct tcp_pcb *pcb;
00269   if (conn == NULL) {
00270     return ERR_VAL;
00271   }
00272   ALTCP_TCP_ASSERT_CONN(conn);
00273   conn->connected = connected;
00274   pcb = (struct tcp_pcb *)conn->state;
00275   return tcp_connect(pcb, ipaddr, port, altcp_tcp_connected);
00276 }
00277 
00278 static struct altcp_pcb *
00279 altcp_tcp_listen(struct altcp_pcb *conn, u8_t backlog, err_t *err)
00280 {
00281   struct tcp_pcb *pcb;
00282   struct tcp_pcb *lpcb;
00283   if (conn == NULL) {
00284     return NULL;
00285   }
00286   ALTCP_TCP_ASSERT_CONN(conn);
00287   pcb = (struct tcp_pcb *)conn->state;
00288   lpcb = tcp_listen_with_backlog_and_err(pcb, backlog, err);
00289   if (lpcb != NULL) {
00290     conn->state = lpcb;
00291     tcp_accept(lpcb, altcp_tcp_accept);
00292     return conn;
00293   }
00294   return NULL;
00295 }
00296 
00297 static void
00298 altcp_tcp_abort(struct altcp_pcb *conn)
00299 {
00300   if (conn != NULL) {
00301     struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
00302     ALTCP_TCP_ASSERT_CONN(conn);
00303     if (pcb) {
00304       tcp_abort(pcb);
00305     }
00306   }
00307 }
00308 
00309 static err_t
00310 altcp_tcp_close(struct altcp_pcb *conn)
00311 {
00312   struct tcp_pcb *pcb;
00313   if (conn == NULL) {
00314     return ERR_VAL;
00315   }
00316   ALTCP_TCP_ASSERT_CONN(conn);
00317   pcb = (struct tcp_pcb *)conn->state;
00318   if (pcb) {
00319     err_t err;
00320     tcp_poll_fn oldpoll = pcb->poll;
00321     altcp_tcp_remove_callbacks(pcb);
00322     err = tcp_close(pcb);
00323     if (err != ERR_OK) {
00324       /* not closed, set up all callbacks again */
00325       altcp_tcp_setup_callbacks(conn, pcb);
00326       /* poll callback is not included in the above */
00327       tcp_poll(pcb, oldpoll, pcb->pollinterval);
00328       return err;
00329     }
00330     conn->state = NULL; /* unsafe to reference pcb after tcp_close(). */
00331   }
00332   altcp_free(conn);
00333   return ERR_OK;
00334 }
00335 
00336 static err_t
00337 altcp_tcp_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx)
00338 {
00339   struct tcp_pcb *pcb;
00340   if (conn == NULL) {
00341     return ERR_VAL;
00342   }
00343   ALTCP_TCP_ASSERT_CONN(conn);
00344   pcb = (struct tcp_pcb *)conn->state;
00345   return tcp_shutdown(pcb, shut_rx, shut_tx);
00346 }
00347 
00348 static err_t
00349 altcp_tcp_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags)
00350 {
00351   struct tcp_pcb *pcb;
00352   if (conn == NULL) {
00353     return ERR_VAL;
00354   }
00355   ALTCP_TCP_ASSERT_CONN(conn);
00356   pcb = (struct tcp_pcb *)conn->state;
00357   return tcp_write(pcb, dataptr, len, apiflags);
00358 }
00359 
00360 static err_t
00361 altcp_tcp_output(struct altcp_pcb *conn)
00362 {
00363   struct tcp_pcb *pcb;
00364   if (conn == NULL) {
00365     return ERR_VAL;
00366   }
00367   ALTCP_TCP_ASSERT_CONN(conn);
00368   pcb = (struct tcp_pcb *)conn->state;
00369   return tcp_output(pcb);
00370 }
00371 
00372 static u16_t
00373 altcp_tcp_mss(struct altcp_pcb *conn)
00374 {
00375   struct tcp_pcb *pcb;
00376   if (conn == NULL) {
00377     return 0;
00378   }
00379   ALTCP_TCP_ASSERT_CONN(conn);
00380   pcb = (struct tcp_pcb *)conn->state;
00381   return tcp_mss(pcb);
00382 }
00383 
00384 static u16_t
00385 altcp_tcp_sndbuf(struct altcp_pcb *conn)
00386 {
00387   struct tcp_pcb *pcb;
00388   if (conn == NULL) {
00389     return 0;
00390   }
00391   ALTCP_TCP_ASSERT_CONN(conn);
00392   pcb = (struct tcp_pcb *)conn->state;
00393   return tcp_sndbuf(pcb);
00394 }
00395 
00396 static u16_t
00397 altcp_tcp_sndqueuelen(struct altcp_pcb *conn)
00398 {
00399   struct tcp_pcb *pcb;
00400   if (conn == NULL) {
00401     return 0;
00402   }
00403   ALTCP_TCP_ASSERT_CONN(conn);
00404   pcb = (struct tcp_pcb *)conn->state;
00405   return tcp_sndqueuelen(pcb);
00406 }
00407 
00408 static void
00409 altcp_tcp_nagle_disable(struct altcp_pcb *conn)
00410 {
00411   if (conn && conn->state) {
00412     struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
00413     ALTCP_TCP_ASSERT_CONN(conn);
00414     tcp_nagle_disable(pcb);
00415   }
00416 }
00417 
00418 static void
00419 altcp_tcp_nagle_enable(struct altcp_pcb *conn)
00420 {
00421   if (conn && conn->state) {
00422     struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
00423     ALTCP_TCP_ASSERT_CONN(conn);
00424     tcp_nagle_enable(pcb);
00425   }
00426 }
00427 
00428 static int
00429 altcp_tcp_nagle_disabled(struct altcp_pcb *conn)
00430 {
00431   if (conn && conn->state) {
00432     struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
00433     ALTCP_TCP_ASSERT_CONN(conn);
00434     return tcp_nagle_disabled(pcb);
00435   }
00436   return 0;
00437 }
00438 
00439 static void
00440 altcp_tcp_setprio(struct altcp_pcb *conn, u8_t prio)
00441 {
00442   if (conn != NULL) {
00443     struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
00444     ALTCP_TCP_ASSERT_CONN(conn);
00445     tcp_setprio(pcb, prio);
00446   }
00447 }
00448 
00449 static void
00450 altcp_tcp_dealloc(struct altcp_pcb *conn)
00451 {
00452   LWIP_UNUSED_ARG(conn);
00453   ALTCP_TCP_ASSERT_CONN(conn);
00454   /* no private state to clean up */
00455 }
00456 
00457 static err_t
00458 altcp_tcp_get_tcp_addrinfo(struct altcp_pcb *conn, int local, ip_addr_t *addr, u16_t *port)
00459 {
00460   if (conn) {
00461     struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
00462     ALTCP_TCP_ASSERT_CONN(conn);
00463     return tcp_tcp_get_tcp_addrinfo(pcb, local, addr, port);
00464   }
00465   return ERR_VAL;
00466 }
00467 
00468 static ip_addr_t *
00469 altcp_tcp_get_ip(struct altcp_pcb *conn, int local)
00470 {
00471   if (conn) {
00472     struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
00473     ALTCP_TCP_ASSERT_CONN(conn);
00474     if (pcb) {
00475       if (local) {
00476         return &pcb->local_ip;
00477       } else {
00478         return &pcb->remote_ip;
00479       }
00480     }
00481   }
00482   return NULL;
00483 }
00484 
00485 static u16_t
00486 altcp_tcp_get_port(struct altcp_pcb *conn, int local)
00487 {
00488   if (conn) {
00489     struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
00490     ALTCP_TCP_ASSERT_CONN(conn);
00491     if (pcb) {
00492       if (local) {
00493         return pcb->local_port;
00494       } else {
00495         return pcb->remote_port;
00496       }
00497     }
00498   }
00499   return 0;
00500 }
00501 
00502 #ifdef LWIP_DEBUG
00503 static enum tcp_state
00504 altcp_tcp_dbg_get_tcp_state(struct altcp_pcb *conn)
00505 {
00506   if (conn) {
00507     struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
00508     ALTCP_TCP_ASSERT_CONN(conn);
00509     if (pcb) {
00510       return pcb->state;
00511     }
00512   }
00513   return CLOSED;
00514 }
00515 #endif
00516 const struct altcp_functions altcp_tcp_functions = {
00517   altcp_tcp_set_poll,
00518   altcp_tcp_recved,
00519   altcp_tcp_bind,
00520   altcp_tcp_connect,
00521   altcp_tcp_listen,
00522   altcp_tcp_abort,
00523   altcp_tcp_close,
00524   altcp_tcp_shutdown,
00525   altcp_tcp_write,
00526   altcp_tcp_output,
00527   altcp_tcp_mss,
00528   altcp_tcp_sndbuf,
00529   altcp_tcp_sndqueuelen,
00530   altcp_tcp_nagle_disable,
00531   altcp_tcp_nagle_enable,
00532   altcp_tcp_nagle_disabled,
00533   altcp_tcp_setprio,
00534   altcp_tcp_dealloc,
00535   altcp_tcp_get_tcp_addrinfo,
00536   altcp_tcp_get_ip,
00537   altcp_tcp_get_port
00538 #ifdef LWIP_DEBUG
00539   , altcp_tcp_dbg_get_tcp_state
00540 #endif
00541 };
00542 
00543 #endif /* LWIP_ALTCP */