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