BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 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) LWIP_ASSERT("conn->inner_conn == NULL", (conn)->inner_conn == NULL)
57 #define ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb) do { \
58 LWIP_ASSERT("pcb mismatch", (conn)->state == tpcb); \
59 ALTCP_TCP_ASSERT_CONN(conn); } while(0)
60  
61  
62 /* Variable prototype, the actual declaration is at the end of this file
63 since it contains pointers to static functions declared here */
64 extern const struct altcp_functions altcp_tcp_functions;
65  
66 static void altcp_tcp_setup(struct altcp_pcb *conn, struct tcp_pcb *tpcb);
67  
68 /* callback functions for TCP */
69 static err_t
70 altcp_tcp_accept(void *arg, struct tcp_pcb *new_tpcb, err_t err)
71 {
72 struct altcp_pcb *listen_conn = (struct altcp_pcb *)arg;
73 if (listen_conn && listen_conn->accept) {
74 /* create a new altcp_conn to pass to the next 'accept' callback */
75 struct altcp_pcb *new_conn = altcp_alloc();
76 if (new_conn == NULL) {
77 return ERR_MEM;
78 }
79 altcp_tcp_setup(new_conn, new_tpcb);
80 return listen_conn->accept(listen_conn->arg, new_conn, err);
81 }
82 return ERR_ARG;
83 }
84  
85 static err_t
86 altcp_tcp_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
87 {
88 struct altcp_pcb *conn = (struct altcp_pcb *)arg;
89 if (conn) {
90 ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb);
91 if (conn->connected) {
92 return conn->connected(conn->arg, conn, err);
93 }
94 }
95 return ERR_OK;
96 }
97  
98 static err_t
99 altcp_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
100 {
101 struct altcp_pcb *conn = (struct altcp_pcb *)arg;
102 if (conn) {
103 ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb);
104 if (conn->recv) {
105 return conn->recv(conn->arg, conn, p, err);
106 }
107 }
108 if (p != NULL) {
109 /* prevent memory leaks */
110 pbuf_free(p);
111 }
112 return ERR_OK;
113 }
114  
115 static err_t
116 altcp_tcp_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
117 {
118 struct altcp_pcb *conn = (struct altcp_pcb *)arg;
119 if (conn) {
120 ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb);
121 if (conn->sent) {
122 return conn->sent(conn->arg, conn, len);
123 }
124 }
125 return ERR_OK;
126 }
127  
128 static err_t
129 altcp_tcp_poll(void *arg, struct tcp_pcb *tpcb)
130 {
131 struct altcp_pcb *conn = (struct altcp_pcb *)arg;
132 if (conn) {
133 ALTCP_TCP_ASSERT_CONN_PCB(conn, tpcb);
134 if (conn->poll) {
135 return conn->poll(conn->arg, conn);
136 }
137 }
138 return ERR_OK;
139 }
140  
141 static void
142 altcp_tcp_err(void *arg, err_t err)
143 {
144 struct altcp_pcb *conn = (struct altcp_pcb *)arg;
145 if (conn) {
146 conn->state = NULL; /* already freed */
147 if (conn->err) {
148 conn->err(conn->arg, err);
149 }
150 altcp_free(conn);
151 }
152 }
153  
154 /* setup functions */
155  
156 static void
157 altcp_tcp_remove_callbacks(struct tcp_pcb *tpcb)
158 {
159 tcp_arg(tpcb, NULL);
160 tcp_recv(tpcb, NULL);
161 tcp_sent(tpcb, NULL);
162 tcp_err(tpcb, NULL);
163 tcp_poll(tpcb, NULL, tpcb->pollinterval);
164 }
165  
166 static void
167 altcp_tcp_setup_callbacks(struct altcp_pcb *conn, struct tcp_pcb *tpcb)
168 {
169 tcp_arg(tpcb, conn);
170 tcp_recv(tpcb, altcp_tcp_recv);
171 tcp_sent(tpcb, altcp_tcp_sent);
172 tcp_err(tpcb, altcp_tcp_err);
173 /* tcp_poll is set when interval is set by application */
174 /* listen is set totally different :-) */
175 }
176  
177 static void
178 altcp_tcp_setup(struct altcp_pcb *conn, struct tcp_pcb *tpcb)
179 {
180 altcp_tcp_setup_callbacks(conn, tpcb);
181 conn->state = tpcb;
182 conn->fns = &altcp_tcp_functions;
183 }
184  
185 struct altcp_pcb *
186 altcp_tcp_new_ip_type(u8_t ip_type)
187 {
188 struct altcp_pcb *ret = altcp_alloc();
189 if (ret != NULL) {
190 struct tcp_pcb *tpcb = tcp_new_ip_type(ip_type);
191 if (tpcb != NULL) {
192 altcp_tcp_setup(ret, tpcb);
193 } else {
194 /* tcp_pcb allocation failed -> free the altcp_pcb too */
195 altcp_free(ret);
196 ret = NULL;
197 }
198 }
199 return ret;
200 }
201  
202 struct altcp_pcb *
203 altcp_tcp_wrap(struct tcp_pcb *tpcb)
204 {
205 if (tpcb != NULL) {
206 struct altcp_pcb *ret = altcp_alloc();
207 if (ret != NULL) {
208 altcp_tcp_setup(ret, tpcb);
209 return ret;
210 }
211 }
212 return NULL;
213 }
214  
215  
216 /* "virtual" functions calling into tcp */
217 static void
218 altcp_tcp_set_poll(struct altcp_pcb *conn, u8_t interval)
219 {
220 if (conn != NULL) {
221 struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
222 ALTCP_TCP_ASSERT_CONN(conn);
223 tcp_poll(pcb, altcp_tcp_poll, interval);
224 }
225 }
226  
227 static void
228 altcp_tcp_recved(struct altcp_pcb *conn, u16_t len)
229 {
230 if (conn != NULL) {
231 struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
232 ALTCP_TCP_ASSERT_CONN(conn);
233 tcp_recved(pcb, len);
234 }
235 }
236  
237 static err_t
238 altcp_tcp_bind(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port)
239 {
240 struct tcp_pcb *pcb;
241 if (conn == NULL) {
242 return ERR_VAL;
243 }
244 ALTCP_TCP_ASSERT_CONN(conn);
245 pcb = (struct tcp_pcb *)conn->state;
246 return tcp_bind(pcb, ipaddr, port);
247 }
248  
249 static err_t
250 altcp_tcp_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected)
251 {
252 struct tcp_pcb *pcb;
253 if (conn == NULL) {
254 return ERR_VAL;
255 }
256 ALTCP_TCP_ASSERT_CONN(conn);
257 conn->connected = connected;
258 pcb = (struct tcp_pcb *)conn->state;
259 return tcp_connect(pcb, ipaddr, port, altcp_tcp_connected);
260 }
261  
262 static struct altcp_pcb *
263 altcp_tcp_listen(struct altcp_pcb *conn, u8_t backlog, err_t *err)
264 {
265 struct tcp_pcb *pcb;
266 struct tcp_pcb *lpcb;
267 if (conn == NULL) {
268 return NULL;
269 }
270 ALTCP_TCP_ASSERT_CONN(conn);
271 pcb = (struct tcp_pcb *)conn->state;
272 lpcb = tcp_listen_with_backlog_and_err(pcb, backlog, err);
273 if (lpcb != NULL) {
274 conn->state = lpcb;
275 tcp_accept(lpcb, altcp_tcp_accept);
276 return conn;
277 }
278 return NULL;
279 }
280  
281 static void
282 altcp_tcp_abort(struct altcp_pcb *conn)
283 {
284 if (conn != NULL) {
285 struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
286 ALTCP_TCP_ASSERT_CONN(conn);
287 if (pcb) {
288 tcp_abort(pcb);
289 }
290 }
291 }
292  
293 static err_t
294 altcp_tcp_close(struct altcp_pcb *conn)
295 {
296 struct tcp_pcb *pcb;
297 if (conn == NULL) {
298 return ERR_VAL;
299 }
300 ALTCP_TCP_ASSERT_CONN(conn);
301 pcb = (struct tcp_pcb *)conn->state;
302 if (pcb) {
303 err_t err;
304 tcp_poll_fn oldpoll = pcb->poll;
305 altcp_tcp_remove_callbacks(pcb);
306 err = tcp_close(pcb);
307 if (err != ERR_OK) {
308 /* not closed, set up all callbacks again */
309 altcp_tcp_setup_callbacks(conn, pcb);
310 /* poll callback is not included in the above */
311 tcp_poll(pcb, oldpoll, pcb->pollinterval);
312 return err;
313 }
314 conn->state = NULL; /* unsafe to reference pcb after tcp_close(). */
315 }
316 altcp_free(conn);
317 return ERR_OK;
318 }
319  
320 static err_t
321 altcp_tcp_shutdown(struct altcp_pcb *conn, int shut_rx, int shut_tx)
322 {
323 struct tcp_pcb *pcb;
324 if (conn == NULL) {
325 return ERR_VAL;
326 }
327 ALTCP_TCP_ASSERT_CONN(conn);
328 pcb = (struct tcp_pcb *)conn->state;
329 return tcp_shutdown(pcb, shut_rx, shut_tx);
330 }
331  
332 static err_t
333 altcp_tcp_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags)
334 {
335 struct tcp_pcb *pcb;
336 if (conn == NULL) {
337 return ERR_VAL;
338 }
339 ALTCP_TCP_ASSERT_CONN(conn);
340 pcb = (struct tcp_pcb *)conn->state;
341 return tcp_write(pcb, dataptr, len, apiflags);
342 }
343  
344 static err_t
345 altcp_tcp_output(struct altcp_pcb *conn)
346 {
347 struct tcp_pcb *pcb;
348 if (conn == NULL) {
349 return ERR_VAL;
350 }
351 ALTCP_TCP_ASSERT_CONN(conn);
352 pcb = (struct tcp_pcb *)conn->state;
353 return tcp_output(pcb);
354 }
355  
356 static u16_t
357 altcp_tcp_mss(struct altcp_pcb *conn)
358 {
359 struct tcp_pcb *pcb;
360 if (conn == NULL) {
361 return 0;
362 }
363 ALTCP_TCP_ASSERT_CONN(conn);
364 pcb = (struct tcp_pcb *)conn->state;
365 return tcp_mss(pcb);
366 }
367  
368 static u16_t
369 altcp_tcp_sndbuf(struct altcp_pcb *conn)
370 {
371 struct tcp_pcb *pcb;
372 if (conn == NULL) {
373 return 0;
374 }
375 ALTCP_TCP_ASSERT_CONN(conn);
376 pcb = (struct tcp_pcb *)conn->state;
377 return tcp_sndbuf(pcb);
378 }
379  
380 static u16_t
381 altcp_tcp_sndqueuelen(struct altcp_pcb *conn)
382 {
383 struct tcp_pcb *pcb;
384 if (conn == NULL) {
385 return 0;
386 }
387 ALTCP_TCP_ASSERT_CONN(conn);
388 pcb = (struct tcp_pcb *)conn->state;
389 return tcp_sndqueuelen(pcb);
390 }
391  
392 static void
393 altcp_tcp_nagle_disable(struct altcp_pcb *conn)
394 {
395 if (conn && conn->state) {
396 struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
397 ALTCP_TCP_ASSERT_CONN(conn);
398 tcp_nagle_disable(pcb);
399 }
400 }
401  
402 static void
403 altcp_tcp_nagle_enable(struct altcp_pcb *conn)
404 {
405 if (conn && conn->state) {
406 struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
407 ALTCP_TCP_ASSERT_CONN(conn);
408 tcp_nagle_enable(pcb);
409 }
410 }
411  
412 static int
413 altcp_tcp_nagle_disabled(struct altcp_pcb *conn)
414 {
415 if (conn && conn->state) {
416 struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
417 ALTCP_TCP_ASSERT_CONN(conn);
418 return tcp_nagle_disabled(pcb);
419 }
420 return 0;
421 }
422  
423 static void
424 altcp_tcp_setprio(struct altcp_pcb *conn, u8_t prio)
425 {
426 if (conn != NULL) {
427 struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
428 ALTCP_TCP_ASSERT_CONN(conn);
429 tcp_setprio(pcb, prio);
430 }
431 }
432  
433 static void
434 altcp_tcp_dealloc(struct altcp_pcb *conn)
435 {
436 LWIP_UNUSED_ARG(conn);
437 ALTCP_TCP_ASSERT_CONN(conn);
438 /* no private state to clean up */
439 }
440  
441 static err_t
442 altcp_tcp_get_tcp_addrinfo(struct altcp_pcb *conn, int local, ip_addr_t *addr, u16_t *port)
443 {
444 if (conn) {
445 struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
446 ALTCP_TCP_ASSERT_CONN(conn);
447 return tcp_tcp_get_tcp_addrinfo(pcb, local, addr, port);
448 }
449 return ERR_VAL;
450 }
451  
452 static ip_addr_t *
453 altcp_tcp_get_ip(struct altcp_pcb *conn, int local)
454 {
455 if (conn) {
456 struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
457 ALTCP_TCP_ASSERT_CONN(conn);
458 if (pcb) {
459 if (local) {
460 return &pcb->local_ip;
461 } else {
462 return &pcb->remote_ip;
463 }
464 }
465 }
466 return NULL;
467 }
468  
469 static u16_t
470 altcp_tcp_get_port(struct altcp_pcb *conn, int local)
471 {
472 if (conn) {
473 struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
474 ALTCP_TCP_ASSERT_CONN(conn);
475 if (pcb) {
476 if (local) {
477 return pcb->local_port;
478 } else {
479 return pcb->remote_port;
480 }
481 }
482 }
483 return 0;
484 }
485  
486 #ifdef LWIP_DEBUG
487 static enum tcp_state
488 altcp_tcp_dbg_get_tcp_state(struct altcp_pcb *conn)
489 {
490 if (conn) {
491 struct tcp_pcb *pcb = (struct tcp_pcb *)conn->state;
492 ALTCP_TCP_ASSERT_CONN(conn);
493 if (pcb) {
494 return pcb->state;
495 }
496 }
497 return CLOSED;
498 }
499 #endif
500 const struct altcp_functions altcp_tcp_functions = {
501 altcp_tcp_set_poll,
502 altcp_tcp_recved,
503 altcp_tcp_bind,
504 altcp_tcp_connect,
505 altcp_tcp_listen,
506 altcp_tcp_abort,
507 altcp_tcp_close,
508 altcp_tcp_shutdown,
509 altcp_tcp_write,
510 altcp_tcp_output,
511 altcp_tcp_mss,
512 altcp_tcp_sndbuf,
513 altcp_tcp_sndqueuelen,
514 altcp_tcp_nagle_disable,
515 altcp_tcp_nagle_enable,
516 altcp_tcp_nagle_disabled,
517 altcp_tcp_setprio,
518 altcp_tcp_dealloc,
519 altcp_tcp_get_tcp_addrinfo,
520 altcp_tcp_get_ip,
521 altcp_tcp_get_port
522 #ifdef LWIP_DEBUG
523 , altcp_tcp_dbg_get_tcp_state
524 #endif
525 };
526  
527 #endif /* LWIP_ALTCP */