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