xref: /nrf52832-nimble/rt-thread/components/net/lwip-2.1.0/src/apps/http/altcp_proxyconnect.c (revision 104654410c56c573564690304ae786df310c91fc)
1 /**
2  * @file
3  * Application layered TCP connection API that executes a proxy-connect.
4  *
5  * This file provides a starting layer that executes a proxy-connect e.g. to
6  * set up TLS connections through a http proxy.
7  */
8 
9 /*
10  * Copyright (c) 2018 Simon Goldschmidt
11  * All rights reserved.
12  *
13  * Redistribution and use in source and binary forms, with or without modification,
14  * are permitted provided that the following conditions are met:
15  *
16  * 1. Redistributions of source code must retain the above copyright notice,
17  *    this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright notice,
19  *    this list of conditions and the following disclaimer in the documentation
20  *    and/or other materials provided with the distribution.
21  * 3. The name of the author may not be used to endorse or promote products
22  *    derived from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
25  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
27  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
29  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33  * OF SUCH DAMAGE.
34  *
35  * This file is part of the lwIP TCP/IP stack.
36  *
37  * Author: Simon Goldschmidt <[email protected]>
38  *
39  */
40 
41 #include "lwip/apps/altcp_proxyconnect.h"
42 
43 #if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */
44 
45 #include "lwip/altcp.h"
46 #include "lwip/priv/altcp_priv.h"
47 
48 #include "lwip/altcp_tcp.h"
49 #include "lwip/altcp_tls.h"
50 
51 #include "lwip/mem.h"
52 #include "lwip/init.h"
53 
54 /** This string is passed in the HTTP header as "User-Agent: " */
55 #ifndef ALTCP_PROXYCONNECT_CLIENT_AGENT
56 #define ALTCP_PROXYCONNECT_CLIENT_AGENT "lwIP/" LWIP_VERSION_STRING " (http://savannah.nongnu.org/projects/lwip)"
57 #endif
58 
59 #define ALTCP_PROXYCONNECT_FLAGS_CONNECT_STARTED  0x01
60 #define ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE   0x02
61 
62 typedef struct altcp_proxyconnect_state_s
63 {
64   ip_addr_t outer_addr;
65   u16_t outer_port;
66   struct altcp_proxyconnect_config *conf;
67   u8_t flags;
68 } altcp_proxyconnect_state_t;
69 
70 /* Variable prototype, the actual declaration is at the end of this file
71    since it contains pointers to static functions declared here */
72 extern const struct altcp_functions altcp_proxyconnect_functions;
73 
74 /* memory management functions: */
75 
76 static altcp_proxyconnect_state_t *
altcp_proxyconnect_state_alloc(void)77 altcp_proxyconnect_state_alloc(void)
78 {
79   altcp_proxyconnect_state_t *ret = (altcp_proxyconnect_state_t *)mem_calloc(1, sizeof(altcp_proxyconnect_state_t));
80   return ret;
81 }
82 
83 static void
altcp_proxyconnect_state_free(altcp_proxyconnect_state_t * state)84 altcp_proxyconnect_state_free(altcp_proxyconnect_state_t *state)
85 {
86   LWIP_ASSERT("state != NULL", state != NULL);
87   mem_free(state);
88 }
89 
90 /* helper functions */
91 
92 #define PROXY_CONNECT "CONNECT %s:%d HTTP/1.1\r\n" /* HOST, PORT */ \
93   "User-Agent: %s\r\n" /* User-Agent */\
94   "Proxy-Connection: keep-alive\r\n" \
95   "Connection: keep-alive\r\n" \
96   "\r\n"
97 #define PROXY_CONNECT_FORMAT(host, port) PROXY_CONNECT, host, port, ALTCP_PROXYCONNECT_CLIENT_AGENT
98 
99 /* Format the http proxy connect request via snprintf */
100 static int
altcp_proxyconnect_format_request(char * buffer,size_t bufsize,const char * host,int port)101 altcp_proxyconnect_format_request(char *buffer, size_t bufsize, const char *host, int port)
102 {
103   return snprintf(buffer, bufsize, PROXY_CONNECT_FORMAT(host, port));
104 }
105 
106 /* Create and send the http proxy connect request */
107 static err_t
altcp_proxyconnect_send_request(struct altcp_pcb * conn)108 altcp_proxyconnect_send_request(struct altcp_pcb *conn)
109 {
110   int len, len2;
111   mem_size_t alloc_len;
112   char *buffer, *host;
113   altcp_proxyconnect_state_t *state = (altcp_proxyconnect_state_t *)conn->state;
114 
115   if (!state) {
116     return ERR_VAL;
117   }
118   /* Use printf with zero length to get the required allocation size */
119   len = altcp_proxyconnect_format_request(NULL, 0, "", state->outer_port);
120   if (len < 0) {
121     return ERR_VAL;
122   }
123   /* add allocation size for IP address strings */
124 #if LWIP_IPV6
125   len += 40; /* worst-case IPv6 address length */
126 #else
127   len += 16; /* worst-case IPv4 address length */
128 #endif
129   alloc_len = (mem_size_t)len;
130   if ((len < 0) || (int)alloc_len != len) {
131     /* overflow */
132     return ERR_MEM;
133   }
134   /* Allocate a bufer for the request string */
135   buffer = (char *)mem_malloc(alloc_len);
136   if (buffer == NULL) {
137     return ERR_MEM;
138   }
139   host = ipaddr_ntoa(&state->outer_addr);
140   len2 = altcp_proxyconnect_format_request(buffer, alloc_len, host, state->outer_port);
141   if ((len2 > 0) && (len2 <= len) && (len2 <= 0xFFFF)) {
142     err_t err = altcp_write(conn->inner_conn, buffer, (u16_t)len2, TCP_WRITE_FLAG_COPY);
143     if (err != ERR_OK) {
144       /* @todo: abort? */
145       mem_free(buffer);
146       return err;
147     }
148   }
149   mem_free(buffer);
150   return ERR_OK;
151 }
152 
153 /* callback functions from inner/lower connection: */
154 
155 /** Connected callback from lower connection (i.e. TCP).
156  * Not really implemented/tested yet...
157  */
158 static err_t
altcp_proxyconnect_lower_connected(void * arg,struct altcp_pcb * inner_conn,err_t err)159 altcp_proxyconnect_lower_connected(void *arg, struct altcp_pcb *inner_conn, err_t err)
160 {
161   struct altcp_pcb *conn = (struct altcp_pcb *)arg;
162   if (conn && conn->state) {
163     LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
164     LWIP_UNUSED_ARG(inner_conn); /* for LWIP_NOASSERT */
165     /* upper connected is called when handshake is done */
166     if (err != ERR_OK) {
167       if (conn->connected) {
168         if (conn->connected(conn->arg, conn, err) == ERR_ABRT) {
169           return ERR_ABRT;
170         }
171         return ERR_OK;
172       }
173     }
174     /* send proxy connect request here */
175     return altcp_proxyconnect_send_request(conn);
176   }
177   return ERR_VAL;
178 }
179 
180 /** Recv callback from lower connection (i.e. TCP)
181  * This one mainly differs between connection setup (wait for proxy OK string)
182  * and application phase (data is passed on to the application).
183  */
184 static err_t
altcp_proxyconnect_lower_recv(void * arg,struct altcp_pcb * inner_conn,struct pbuf * p,err_t err)185 altcp_proxyconnect_lower_recv(void *arg, struct altcp_pcb *inner_conn, struct pbuf *p, err_t err)
186 {
187   altcp_proxyconnect_state_t *state;
188   struct altcp_pcb *conn = (struct altcp_pcb *)arg;
189 
190   LWIP_ASSERT("no err expected", err == ERR_OK);
191   LWIP_UNUSED_ARG(err);
192 
193   if (!conn) {
194     /* no connection given as arg? should not happen, but prevent pbuf/conn leaks */
195     if (p != NULL) {
196       pbuf_free(p);
197     }
198     altcp_close(inner_conn);
199     return ERR_CLSD;
200   }
201   state = (altcp_proxyconnect_state_t *)conn->state;
202   LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
203   if (!state) {
204     /* already closed */
205     if (p != NULL) {
206       pbuf_free(p);
207     }
208     altcp_close(inner_conn);
209     return ERR_CLSD;
210   }
211   if (state->flags & ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE) {
212     /* application phase, just pass this through */
213     if (conn->recv) {
214       return conn->recv(conn->arg, conn, p, err);
215     }
216     pbuf_free(p);
217     return ERR_OK;
218   } else {
219     /* setup phase */
220     /* handle NULL pbuf (inner connection closed) */
221     if (p == NULL) {
222       if (altcp_close(conn) != ERR_OK) {
223         altcp_abort(conn);
224         return ERR_ABRT;
225       }
226       return ERR_OK;
227     } else {
228       /* @todo: parse setup phase rx data
229          for now, we just wait for the end of the header... */
230       u16_t idx = pbuf_memfind(p, "\r\n\r\n", 4, 0);
231       altcp_recved(inner_conn, p->tot_len);
232       pbuf_free(p);
233       if (idx != 0xFFFF) {
234         state->flags |= ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE;
235         if (conn->connected) {
236           return conn->connected(conn->arg, conn, ERR_OK);
237         }
238       }
239       return ERR_OK;
240     }
241   }
242 }
243 
244 /** Sent callback from lower connection (i.e. TCP)
245  * This only informs the upper layer to try to send more, not about
246  * the number of ACKed bytes.
247  */
248 static err_t
altcp_proxyconnect_lower_sent(void * arg,struct altcp_pcb * inner_conn,u16_t len)249 altcp_proxyconnect_lower_sent(void *arg, struct altcp_pcb *inner_conn, u16_t len)
250 {
251   struct altcp_pcb *conn = (struct altcp_pcb *)arg;
252   LWIP_UNUSED_ARG(len);
253   if (conn) {
254     altcp_proxyconnect_state_t *state = (altcp_proxyconnect_state_t *)conn->state;
255     LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
256     LWIP_UNUSED_ARG(inner_conn); /* for LWIP_NOASSERT */
257     if (!state || !(state->flags & ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE)) {
258       /* @todo: do something here? */
259       return ERR_OK;
260     }
261     /* pass this on to upper sent */
262     if (conn->sent) {
263       return conn->sent(conn->arg, conn, len);
264     }
265   }
266   return ERR_OK;
267 }
268 
269 /** Poll callback from lower connection (i.e. TCP)
270  * Just pass this on to the application.
271  * @todo: retry sending?
272  */
273 static err_t
altcp_proxyconnect_lower_poll(void * arg,struct altcp_pcb * inner_conn)274 altcp_proxyconnect_lower_poll(void *arg, struct altcp_pcb *inner_conn)
275 {
276   struct altcp_pcb *conn = (struct altcp_pcb *)arg;
277   if (conn) {
278     LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn);
279     LWIP_UNUSED_ARG(inner_conn); /* for LWIP_NOASSERT */
280     if (conn->poll) {
281       return conn->poll(conn->arg, conn);
282     }
283   }
284   return ERR_OK;
285 }
286 
287 static void
altcp_proxyconnect_lower_err(void * arg,err_t err)288 altcp_proxyconnect_lower_err(void *arg, err_t err)
289 {
290   struct altcp_pcb *conn = (struct altcp_pcb *)arg;
291   if (conn) {
292     conn->inner_conn = NULL; /* already freed */
293     if (conn->err) {
294       conn->err(conn->arg, err);
295     }
296     altcp_free(conn);
297   }
298 }
299 
300 
301 /* setup functions */
302 
303 static void
altcp_proxyconnect_setup_callbacks(struct altcp_pcb * conn,struct altcp_pcb * inner_conn)304 altcp_proxyconnect_setup_callbacks(struct altcp_pcb *conn, struct altcp_pcb *inner_conn)
305 {
306   altcp_arg(inner_conn, conn);
307   altcp_recv(inner_conn, altcp_proxyconnect_lower_recv);
308   altcp_sent(inner_conn, altcp_proxyconnect_lower_sent);
309   altcp_err(inner_conn, altcp_proxyconnect_lower_err);
310   /* tcp_poll is set when interval is set by application */
311   /* listen is set totally different :-) */
312 }
313 
314 static err_t
altcp_proxyconnect_setup(struct altcp_proxyconnect_config * config,struct altcp_pcb * conn,struct altcp_pcb * inner_conn)315 altcp_proxyconnect_setup(struct altcp_proxyconnect_config *config, struct altcp_pcb *conn, struct altcp_pcb *inner_conn)
316 {
317   altcp_proxyconnect_state_t *state;
318   if (!config) {
319     return ERR_ARG;
320   }
321   LWIP_ASSERT("invalid inner_conn", conn != inner_conn);
322 
323   /* allocate proxyconnect context */
324   state = altcp_proxyconnect_state_alloc();
325   if (state == NULL) {
326     return ERR_MEM;
327   }
328   state->flags = 0;
329   state->conf = config;
330   altcp_proxyconnect_setup_callbacks(conn, inner_conn);
331   conn->inner_conn = inner_conn;
332   conn->fns = &altcp_proxyconnect_functions;
333   conn->state = state;
334   return ERR_OK;
335 }
336 
337 /** Allocate a new altcp layer connecting through a proxy.
338  * This function gets the inner pcb passed.
339  *
340  * @param config struct altcp_proxyconnect_config that contains the proxy settings
341  * @param inner_pcb pcb that makes the connection to the proxy (i.e. tcp pcb)
342  */
343 struct altcp_pcb *
altcp_proxyconnect_new(struct altcp_proxyconnect_config * config,struct altcp_pcb * inner_pcb)344 altcp_proxyconnect_new(struct altcp_proxyconnect_config *config, struct altcp_pcb *inner_pcb)
345 {
346   struct altcp_pcb *ret;
347   if (inner_pcb == NULL) {
348     return NULL;
349   }
350   ret = altcp_alloc();
351   if (ret != NULL) {
352     if (altcp_proxyconnect_setup(config, ret, inner_pcb) != ERR_OK) {
353       altcp_free(ret);
354       return NULL;
355     }
356   }
357   return ret;
358 }
359 
360 /** Allocate a new altcp layer connecting through a proxy.
361  * This function allocates the inner pcb as tcp pcb, resulting in a direct tcp
362  * connection to the proxy.
363  *
364  * @param config struct altcp_proxyconnect_config that contains the proxy settings
365  * @param ip_type IP type of the connection (@ref lwip_ip_addr_type)
366  */
367 struct altcp_pcb *
altcp_proxyconnect_new_tcp(struct altcp_proxyconnect_config * config,u8_t ip_type)368 altcp_proxyconnect_new_tcp(struct altcp_proxyconnect_config *config, u8_t ip_type)
369 {
370   struct altcp_pcb *inner_pcb, *ret;
371 
372   /* inner pcb is tcp */
373   inner_pcb = altcp_tcp_new_ip_type(ip_type);
374   if (inner_pcb == NULL) {
375     return NULL;
376   }
377   ret = altcp_proxyconnect_new(config, inner_pcb);
378   if (ret == NULL) {
379     altcp_close(inner_pcb);
380   }
381   return ret;
382 }
383 
384 /** Allocator function to allocate a proxy connect altcp pcb connecting directly
385  * via tcp to the proxy.
386  *
387  * The returned pcb is a chain: altcp_proxyconnect - altcp_tcp - tcp pcb
388  *
389  * This function is meant for use with @ref altcp_new.
390  *
391  * @param arg struct altcp_proxyconnect_config that contains the proxy settings
392  * @param ip_type IP type of the connection (@ref lwip_ip_addr_type)
393  */
394 struct altcp_pcb *
altcp_proxyconnect_alloc(void * arg,u8_t ip_type)395 altcp_proxyconnect_alloc(void *arg, u8_t ip_type)
396 {
397   return altcp_proxyconnect_new_tcp((struct altcp_proxyconnect_config *)arg, ip_type);
398 }
399 
400 
401 #if LWIP_ALTCP_TLS
402 
403 /** Allocator function to allocate a TLS connection through a proxy.
404  *
405  * The returned pcb is a chain: altcp_tls - altcp_proxyconnect - altcp_tcp - tcp pcb
406  *
407  * This function is meant for use with @ref altcp_new.
408  *
409  * @param arg struct altcp_proxyconnect_tls_config that contains the proxy settings
410  *        and tls settings
411  * @param ip_type IP type of the connection (@ref lwip_ip_addr_type)
412  */
413 struct altcp_pcb *
altcp_proxyconnect_tls_alloc(void * arg,u8_t ip_type)414 altcp_proxyconnect_tls_alloc(void *arg, u8_t ip_type)
415 {
416   struct altcp_proxyconnect_tls_config *cfg = (struct altcp_proxyconnect_tls_config *)arg;
417   struct altcp_pcb *proxy_pcb;
418   struct altcp_pcb *tls_pcb;
419 
420   proxy_pcb = altcp_proxyconnect_new_tcp(&cfg->proxy, ip_type);
421   tls_pcb = altcp_tls_wrap(cfg->tls_config, proxy_pcb);
422 
423   if (tls_pcb == NULL) {
424     altcp_close(proxy_pcb);
425   }
426   return tls_pcb;
427 }
428 #endif /* LWIP_ALTCP_TLS */
429 
430 /* "virtual" functions */
431 static void
altcp_proxyconnect_set_poll(struct altcp_pcb * conn,u8_t interval)432 altcp_proxyconnect_set_poll(struct altcp_pcb *conn, u8_t interval)
433 {
434   if (conn != NULL) {
435     altcp_poll(conn->inner_conn, altcp_proxyconnect_lower_poll, interval);
436   }
437 }
438 
439 static void
altcp_proxyconnect_recved(struct altcp_pcb * conn,u16_t len)440 altcp_proxyconnect_recved(struct altcp_pcb *conn, u16_t len)
441 {
442   altcp_proxyconnect_state_t *state;
443   if (conn == NULL) {
444     return;
445   }
446   state = (altcp_proxyconnect_state_t *)conn->state;
447   if (state == NULL) {
448     return;
449   }
450   if (!(state->flags & ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE)) {
451     return;
452   }
453   altcp_recved(conn->inner_conn, len);
454 }
455 
456 static err_t
altcp_proxyconnect_connect(struct altcp_pcb * conn,const ip_addr_t * ipaddr,u16_t port,altcp_connected_fn connected)457 altcp_proxyconnect_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected)
458 {
459   altcp_proxyconnect_state_t *state;
460 
461   if ((conn == NULL) || (ipaddr == NULL)) {
462     return ERR_VAL;
463   }
464   state = (altcp_proxyconnect_state_t *)conn->state;
465   if (state == NULL) {
466     return ERR_VAL;
467   }
468   if (state->flags & ALTCP_PROXYCONNECT_FLAGS_CONNECT_STARTED) {
469     return ERR_VAL;
470   }
471   state->flags |= ALTCP_PROXYCONNECT_FLAGS_CONNECT_STARTED;
472 
473   conn->connected = connected;
474   /* connect to our proxy instead, but store the requested address and port */
475   ip_addr_copy(state->outer_addr, *ipaddr);
476   state->outer_port = port;
477 
478   return altcp_connect(conn->inner_conn, &state->conf->proxy_addr, state->conf->proxy_port, altcp_proxyconnect_lower_connected);
479 }
480 
481 static struct altcp_pcb *
altcp_proxyconnect_listen(struct altcp_pcb * conn,u8_t backlog,err_t * err)482 altcp_proxyconnect_listen(struct altcp_pcb *conn, u8_t backlog, err_t *err)
483 {
484   LWIP_UNUSED_ARG(conn);
485   LWIP_UNUSED_ARG(backlog);
486   LWIP_UNUSED_ARG(err);
487   /* listen not supported! */
488   return NULL;
489 }
490 
491 static void
altcp_proxyconnect_abort(struct altcp_pcb * conn)492 altcp_proxyconnect_abort(struct altcp_pcb *conn)
493 {
494   if (conn != NULL) {
495     if (conn->inner_conn != NULL) {
496       altcp_abort(conn->inner_conn);
497     }
498     altcp_free(conn);
499   }
500 }
501 
502 static err_t
altcp_proxyconnect_close(struct altcp_pcb * conn)503 altcp_proxyconnect_close(struct altcp_pcb *conn)
504 {
505   if (conn == NULL) {
506     return ERR_VAL;
507   }
508   if (conn->inner_conn != NULL) {
509     err_t err = altcp_close(conn->inner_conn);
510     if (err != ERR_OK) {
511       /* closing inner conn failed, return the error */
512       return err;
513     }
514   }
515   /* no inner conn or closing it succeeded, deallocate myself */
516   altcp_free(conn);
517   return ERR_OK;
518 }
519 
520 static err_t
altcp_proxyconnect_write(struct altcp_pcb * conn,const void * dataptr,u16_t len,u8_t apiflags)521 altcp_proxyconnect_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags)
522 {
523   altcp_proxyconnect_state_t *state;
524 
525   LWIP_UNUSED_ARG(apiflags);
526 
527   if (conn == NULL) {
528     return ERR_VAL;
529   }
530 
531   state = (altcp_proxyconnect_state_t *)conn->state;
532   if (state == NULL) {
533     /* @todo: which error? */
534     return ERR_CLSD;
535   }
536   if (!(state->flags & ALTCP_PROXYCONNECT_FLAGS_HANDSHAKE_DONE)) {
537     /* @todo: which error? */
538     return ERR_VAL;
539   }
540   return altcp_write(conn->inner_conn, dataptr, len, apiflags);
541 }
542 
543 static void
altcp_proxyconnect_dealloc(struct altcp_pcb * conn)544 altcp_proxyconnect_dealloc(struct altcp_pcb *conn)
545 {
546   /* clean up and free tls state */
547   if (conn) {
548     altcp_proxyconnect_state_t *state = (altcp_proxyconnect_state_t *)conn->state;
549     if (state) {
550       altcp_proxyconnect_state_free(state);
551       conn->state = NULL;
552     }
553   }
554 }
555 const struct altcp_functions altcp_proxyconnect_functions = {
556   altcp_proxyconnect_set_poll,
557   altcp_proxyconnect_recved,
558   altcp_default_bind,
559   altcp_proxyconnect_connect,
560   altcp_proxyconnect_listen,
561   altcp_proxyconnect_abort,
562   altcp_proxyconnect_close,
563   altcp_default_shutdown,
564   altcp_proxyconnect_write,
565   altcp_default_output,
566   altcp_default_mss,
567   altcp_default_sndbuf,
568   altcp_default_sndqueuelen,
569   altcp_default_nagle_disable,
570   altcp_default_nagle_enable,
571   altcp_default_nagle_disabled,
572   altcp_default_setprio,
573   altcp_proxyconnect_dealloc,
574   altcp_default_get_tcp_addrinfo,
575   altcp_default_get_ip,
576   altcp_default_get_port
577 #ifdef LWIP_DEBUG
578   , altcp_default_dbg_get_tcp_state
579 #endif
580 };
581 
582 #endif /* LWIP_ALTCP */
583