source: azure_iot_hub_f767zi/trunk/asp_baseplatform/lwip/lwip-2.1.2/src/core/altcp_tcp.c@ 457

Last change on this file since 457 was 457, checked in by coas-nagasima, 4 years ago

ファイルを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 13.0 KB
Line 
1/**
2 * @file
3 * Application layered TCP connection API (to be used from TCPIP thread)\n
4 * This interface mimics the tcp callback API to the application while preventing
5 * direct linking (much like virtual functions).
6 * This way, an application can make use of other application layer protocols
7 * on top of TCP without knowing the details (e.g. TLS, proxy connection).
8 *
9 * This file contains the base implementation calling into tcp.
10 */
11
12/*
13 * Copyright (c) 2017 Simon Goldschmidt
14 * All rights reserved.
15 *
16 * Redistribution and use in source and binary forms, with or without modification,
17 * are permitted provided that the following conditions are met:
18 *
19 * 1. Redistributions of source code must retain the above copyright notice,
20 * this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright notice,
22 * this list of conditions and the following disclaimer in the documentation
23 * and/or other materials provided with the distribution.
24 * 3. The name of the author may not be used to endorse or promote products
25 * derived from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
28 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
29 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
30 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
32 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
35 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
36 * OF SUCH DAMAGE.
37 *
38 * This file is part of the lwIP TCP/IP stack.
39 *
40 * Author: Simon Goldschmidt <goldsimon@gmx.de>
41 *
42 */
43
44#include "lwip/opt.h"
45
46#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */
47
48#include "lwip/altcp.h"
49#include "lwip/altcp_tcp.h"
50#include "lwip/priv/altcp_priv.h"
51#include "lwip/tcp.h"
52#include "lwip/mem.h"
53
54#include <string.h>
55
56#define ALTCP_TCP_ASSERT_CONN(conn) do { \
57 LWIP_ASSERT("conn->inner_conn == NULL", (conn)->inner_conn == NULL); \
58 LWIP_UNUSED_ARG(conn); /* for LWIP_NOASSERT */ } while(0)
59#define ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb) do { \
60 LWIP_ASSERT("pcb mismatch", (conn)->state == tpcb); \
61 LWIP_UNUSED_ARG(tpcb); /* for LWIP_NOASSERT */ \
62 ALTCP_TCP_ASSERT_CONN(conn); } while(0)
63
64
65/* Variable prototype, the actual declaration is at the end of this file
66 since it contains pointers to static functions declared here */
67extern const struct altcp_functions altcp_tcp_functions;
68
69static void altcp_tcp_setup(struct altcp_pcb *conn, struct tcp_pcb *tpcb);
70
71/* callback functions for TCP */
72static err_t
73altcp_tcp_accept(void *arg, struct tcp_pcb *new_tpcb, err_t err)
74{
75 struct altcp_pcb *listen_conn = (struct altcp_pcb *)arg;
76 if (listen_conn && listen_conn->accept) {
77 /* create a new altcp_conn to pass to the next 'accept' callback */
78 struct altcp_pcb *new_conn = altcp_alloc();
79 if (new_conn == NULL) {
80 return ERR_MEM;
81 }
82 altcp_tcp_setup(new_conn, new_tpcb);
83 return listen_conn->accept(listen_conn->arg, new_conn, err);
84 }
85 return ERR_ARG;
86}
87
88static err_t
89altcp_tcp_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
90{
91 struct altcp_pcb *conn = (struct altcp_pcb *)arg;
92 if (conn) {
93 ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb);
94 if (conn->connected) {
95 return conn->connected(conn->arg, conn, err);
96 }
97 }
98 return ERR_OK;
99}
100
101static err_t
102altcp_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
103{
104 struct altcp_pcb *conn = (struct altcp_pcb *)arg;
105 if (conn) {
106 ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb);
107 if (conn->recv) {
108 return conn->recv(conn->arg, conn, p, err);
109 }
110 }
111 if (p != NULL) {
112 /* prevent memory leaks */
113 pbuf_free(p);
114 }
115 return ERR_OK;
116}
117
118static err_t
119altcp_tcp_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
120{
121 struct altcp_pcb *conn = (struct altcp_pcb *)arg;
122 if (conn) {
123 ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb);
124 if (conn->sent) {
125 return conn->sent(conn->arg, conn, len);
126 }
127 }
128 return ERR_OK;
129}
130
131static err_t
132altcp_tcp_poll(void *arg, struct tcp_pcb *tpcb)
133{
134 struct altcp_pcb *conn = (struct altcp_pcb *)arg;
135 if (conn) {
136 ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb);
137 if (conn->poll) {
138 return conn->poll(conn->arg, conn);
139 }
140 }
141 return ERR_OK;
142}
143
144static void
145altcp_tcp_err(void *arg, err_t err)
146{
147 struct altcp_pcb *conn = (struct altcp_pcb *)arg;
148 if (conn) {
149 conn->state = NULL; /* already freed */
150 if (conn->err) {
151 conn->err(conn->arg, err);
152 }
153 altcp_free(conn);
154 }
155}
156
157/* setup functions */
158
159static void
160altcp_tcp_remove_callbacks(struct tcp_pcb *tpcb)
161{
162 tcp_arg(tpcb, NULL);
163 tcp_recv(tpcb, NULL);
164 tcp_sent(tpcb, NULL);
165 tcp_err(tpcb, NULL);
166 tcp_poll(tpcb, NULL, tpcb->pollinterval);
167}
168
169static void
170altcp_tcp_setup_callbacks(struct altcp_pcb *conn, struct tcp_pcb *tpcb)
171{
172 tcp_arg(tpcb, conn);
173 tcp_recv(tpcb, altcp_tcp_recv);
174 tcp_sent(tpcb, altcp_tcp_sent);
175 tcp_err(tpcb, altcp_tcp_err);
176 /* tcp_poll is set when interval is set by application */
177 /* listen is set totally different :-) */
178}
179
180static void
181altcp_tcp_setup(struct altcp_pcb *conn, struct tcp_pcb *tpcb)
182{
183 altcp_tcp_setup_callbacks(conn, tpcb);
184 conn->state = tpcb;
185 conn->fns = &altcp_tcp_functions;
186}
187
188struct altcp_pcb *
189altcp_tcp_new_ip_type(u8_t ip_type)
190{
191 /* Allocate the tcp pcb first to invoke the priority handling code
192 if we're out of pcbs */
193 struct tcp_pcb *tpcb = tcp_new_ip_type(ip_type);
194 if (tpcb != NULL) {
195 struct altcp_pcb *ret = altcp_alloc();
196 if (ret != NULL) {
197 altcp_tcp_setup(ret, tpcb);
198 return ret;
199 } else {
200 /* altcp_pcb allocation failed -> free the tcp_pcb too */
201 tcp_close(tpcb);
202 }
203 }
204 return NULL;
205}
206
207/** altcp_tcp allocator function fitting to @ref altcp_allocator_t / @ref altcp_new.
208*
209* arg pointer is not used for TCP.
210*/
211struct altcp_pcb *
212altcp_tcp_alloc(void *arg, u8_t ip_type)
213{
214 LWIP_UNUSED_ARG(arg);
215 return altcp_tcp_new_ip_type(ip_type);
216}
217
218struct altcp_pcb *
219altcp_tcp_wrap(struct tcp_pcb *tpcb)
220{
221 if (tpcb != NULL) {
222 struct altcp_pcb *ret = altcp_alloc();
223 if (ret != NULL) {
224 altcp_tcp_setup(ret, tpcb);
225 return ret;
226 }
227 }
228 return NULL;
229}
230
231
232/* "virtual" functions calling into tcp */
233static void
234altcp_tcp_set_poll(struct altcp_pcb *conn, u8_t interval)
235{
236 if (conn != NULL) {
237 struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
238 ALTCP_TCP_ASSERT_CONN(conn);
239 tcp_poll(pcb, altcp_tcp_poll, interval);
240 }
241}
242
243static void
244altcp_tcp_recved(struct altcp_pcb *conn, u16_t len)
245{
246 if (conn != NULL) {
247 struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
248 ALTCP_TCP_ASSERT_CONN(conn);
249 tcp_recved(pcb, len);
250 }
251}
252
253static err_t
254altcp_tcp_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port)
255{
256 struct tcp_pcb *pcb;
257 if (conn == NULL) {
258 return ERR_VAL;
259 }
260 ALTCP_TCP_ASSERT_CONN(conn);
261 pcb = (struct tcp_pcb *)conn->state;
262 return tcp_bind(pcb, ipaddr, port);
263}
264
265static err_t
266altcp_tcp_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected)
267{
268 struct tcp_pcb *pcb;
269 if (conn == NULL) {
270 return ERR_VAL;
271 }
272 ALTCP_TCP_ASSERT_CONN(conn);
273 conn->connected = connected;
274 pcb = (struct tcp_pcb *)conn->state;
275 return tcp_connect(pcb, ipaddr, port, altcp_tcp_connected);
276}
277
278static struct altcp_pcb *
279altcp_tcp_listen(struct altcp_pcb *conn, u8_t backlog, err_t *err)
280{
281 struct tcp_pcb *pcb;
282 struct tcp_pcb *lpcb;
283 if (conn == NULL) {
284 return NULL;
285 }
286 ALTCP_TCP_ASSERT_CONN(conn);
287 pcb = (struct tcp_pcb *)conn->state;
288 lpcb = tcp_listen_with_backlog_and_err(pcb, backlog, err);
289 if (lpcb != NULL) {
290 conn->state = lpcb;
291 tcp_accept(lpcb, altcp_tcp_accept);
292 return conn;
293 }
294 return NULL;
295}
296
297static void
298altcp_tcp_abort(struct altcp_pcb *conn)
299{
300 if (conn != NULL) {
301 struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
302 ALTCP_TCP_ASSERT_CONN(conn);
303 if (pcb) {
304 tcp_abort(pcb);
305 }
306 }
307}
308
309static err_t
310altcp_tcp_close(struct altcp_pcb *conn)
311{
312 struct tcp_pcb *pcb;
313 if (conn == NULL) {
314 return ERR_VAL;
315 }
316 ALTCP_TCP_ASSERT_CONN(conn);
317 pcb = (struct tcp_pcb *)conn->state;
318 if (pcb) {
319 err_t err;
320 tcp_poll_fn oldpoll = pcb->poll;
321 altcp_tcp_remove_callbacks(pcb);
322 err = tcp_close(pcb);
323 if (err != ERR_OK) {
324 /* not closed, set up all callbacks again */
325 altcp_tcp_setup_callbacks(conn, pcb);
326 /* poll callback is not included in the above */
327 tcp_poll(pcb, oldpoll, pcb->pollinterval);
328 return err;
329 }
330 conn->state = NULL; /* unsafe to reference pcb after tcp_close(). */
331 }
332 altcp_free(conn);
333 return ERR_OK;
334}
335
336static err_t
337altcp_tcp_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx)
338{
339 struct tcp_pcb *pcb;
340 if (conn == NULL) {
341 return ERR_VAL;
342 }
343 ALTCP_TCP_ASSERT_CONN(conn);
344 pcb = (struct tcp_pcb *)conn->state;
345 return tcp_shutdown(pcb, shut_rx, shut_tx);
346}
347
348static err_t
349altcp_tcp_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags)
350{
351 struct tcp_pcb *pcb;
352 if (conn == NULL) {
353 return ERR_VAL;
354 }
355 ALTCP_TCP_ASSERT_CONN(conn);
356 pcb = (struct tcp_pcb *)conn->state;
357 return tcp_write(pcb, dataptr, len, apiflags);
358}
359
360static err_t
361altcp_tcp_output(struct altcp_pcb *conn)
362{
363 struct tcp_pcb *pcb;
364 if (conn == NULL) {
365 return ERR_VAL;
366 }
367 ALTCP_TCP_ASSERT_CONN(conn);
368 pcb = (struct tcp_pcb *)conn->state;
369 return tcp_output(pcb);
370}
371
372static u16_t
373altcp_tcp_mss(struct altcp_pcb *conn)
374{
375 struct tcp_pcb *pcb;
376 if (conn == NULL) {
377 return 0;
378 }
379 ALTCP_TCP_ASSERT_CONN(conn);
380 pcb = (struct tcp_pcb *)conn->state;
381 return tcp_mss(pcb);
382}
383
384static u16_t
385altcp_tcp_sndbuf(struct altcp_pcb *conn)
386{
387 struct tcp_pcb *pcb;
388 if (conn == NULL) {
389 return 0;
390 }
391 ALTCP_TCP_ASSERT_CONN(conn);
392 pcb = (struct tcp_pcb *)conn->state;
393 return tcp_sndbuf(pcb);
394}
395
396static u16_t
397altcp_tcp_sndqueuelen(struct altcp_pcb *conn)
398{
399 struct tcp_pcb *pcb;
400 if (conn == NULL) {
401 return 0;
402 }
403 ALTCP_TCP_ASSERT_CONN(conn);
404 pcb = (struct tcp_pcb *)conn->state;
405 return tcp_sndqueuelen(pcb);
406}
407
408static void
409altcp_tcp_nagle_disable(struct altcp_pcb *conn)
410{
411 if (conn && conn->state) {
412 struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
413 ALTCP_TCP_ASSERT_CONN(conn);
414 tcp_nagle_disable(pcb);
415 }
416}
417
418static void
419altcp_tcp_nagle_enable(struct altcp_pcb *conn)
420{
421 if (conn && conn->state) {
422 struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
423 ALTCP_TCP_ASSERT_CONN(conn);
424 tcp_nagle_enable(pcb);
425 }
426}
427
428static int
429altcp_tcp_nagle_disabled(struct altcp_pcb *conn)
430{
431 if (conn && conn->state) {
432 struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
433 ALTCP_TCP_ASSERT_CONN(conn);
434 return tcp_nagle_disabled(pcb);
435 }
436 return 0;
437}
438
439static void
440altcp_tcp_setprio(struct altcp_pcb *conn, u8_t prio)
441{
442 if (conn != NULL) {
443 struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
444 ALTCP_TCP_ASSERT_CONN(conn);
445 tcp_setprio(pcb, prio);
446 }
447}
448
449static void
450altcp_tcp_dealloc(struct altcp_pcb *conn)
451{
452 LWIP_UNUSED_ARG(conn);
453 ALTCP_TCP_ASSERT_CONN(conn);
454 /* no private state to clean up */
455}
456
457static err_t
458altcp_tcp_get_tcp_addrinfo(struct altcp_pcb *conn, int local, ip_addr_t *addr, u16_t *port)
459{
460 if (conn) {
461 struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
462 ALTCP_TCP_ASSERT_CONN(conn);
463 return tcp_tcp_get_tcp_addrinfo(pcb, local, addr, port);
464 }
465 return ERR_VAL;
466}
467
468static ip_addr_t *
469altcp_tcp_get_ip(struct altcp_pcb *conn, int local)
470{
471 if (conn) {
472 struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
473 ALTCP_TCP_ASSERT_CONN(conn);
474 if (pcb) {
475 if (local) {
476 return &pcb->local_ip;
477 } else {
478 return &pcb->remote_ip;
479 }
480 }
481 }
482 return NULL;
483}
484
485static u16_t
486altcp_tcp_get_port(struct altcp_pcb *conn, int local)
487{
488 if (conn) {
489 struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
490 ALTCP_TCP_ASSERT_CONN(conn);
491 if (pcb) {
492 if (local) {
493 return pcb->local_port;
494 } else {
495 return pcb->remote_port;
496 }
497 }
498 }
499 return 0;
500}
501
502#ifdef LWIP_DEBUG
503static enum tcp_state
504altcp_tcp_dbg_get_tcp_state(struct altcp_pcb *conn)
505{
506 if (conn) {
507 struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
508 ALTCP_TCP_ASSERT_CONN(conn);
509 if (pcb) {
510 return pcb->state;
511 }
512 }
513 return CLOSED;
514}
515#endif
516const struct altcp_functions altcp_tcp_functions = {
517 altcp_tcp_set_poll,
518 altcp_tcp_recved,
519 altcp_tcp_bind,
520 altcp_tcp_connect,
521 altcp_tcp_listen,
522 altcp_tcp_abort,
523 altcp_tcp_close,
524 altcp_tcp_shutdown,
525 altcp_tcp_write,
526 altcp_tcp_output,
527 altcp_tcp_mss,
528 altcp_tcp_sndbuf,
529 altcp_tcp_sndqueuelen,
530 altcp_tcp_nagle_disable,
531 altcp_tcp_nagle_enable,
532 altcp_tcp_nagle_disabled,
533 altcp_tcp_setprio,
534 altcp_tcp_dealloc,
535 altcp_tcp_get_tcp_addrinfo,
536 altcp_tcp_get_ip,
537 altcp_tcp_get_port
538#ifdef LWIP_DEBUG
539 , altcp_tcp_dbg_get_tcp_state
540#endif
541};
542
543#endif /* LWIP_ALTCP */
Note: See TracBrowser for help on using the repository browser.