BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * Copyright (C) Ambroz Bizjak <ambrop7@gmail.com> |
||
3 | * Contributions: |
||
4 | * Transparent DNS: Copyright (C) Kerem Hadimli <kerem.hadimli@gmail.com> |
||
5 | * |
||
6 | * Redistribution and use in source and binary forms, with or without |
||
7 | * modification, are permitted provided that the following conditions are met: |
||
8 | * 1. Redistributions of source code must retain the above copyright |
||
9 | * notice, this list of conditions and the following disclaimer. |
||
10 | * 2. Redistributions in binary form must reproduce the above copyright |
||
11 | * notice, this list of conditions and the following disclaimer in the |
||
12 | * documentation and/or other materials provided with the distribution. |
||
13 | * 3. Neither the name of the author nor the |
||
14 | * names of its contributors may be used to endorse or promote products |
||
15 | * derived from this software without specific prior written permission. |
||
16 | * |
||
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
||
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||
20 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
||
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
27 | */ |
||
28 | |||
29 | #include <stdlib.h> |
||
30 | #include <string.h> |
||
31 | |||
32 | #include <misc/offset.h> |
||
33 | #include <misc/byteorder.h> |
||
34 | #include <misc/compare.h> |
||
35 | #include <base/BLog.h> |
||
36 | |||
37 | #include <udpgw_client/UdpGwClient.h> |
||
38 | |||
39 | #include <generated/blog_channel_UdpGwClient.h> |
||
40 | |||
41 | static int uint16_comparator (void *unused, uint16_t *v1, uint16_t *v2); |
||
42 | static int conaddr_comparator (void *unused, struct UdpGwClient_conaddr *v1, struct UdpGwClient_conaddr *v2); |
||
43 | static void free_server (UdpGwClient *o); |
||
44 | static void decoder_handler_error (UdpGwClient *o); |
||
45 | static void recv_interface_handler_send (UdpGwClient *o, uint8_t *data, int data_len); |
||
46 | static void send_monitor_handler (UdpGwClient *o); |
||
47 | static void keepalive_if_handler_done (UdpGwClient *o); |
||
48 | static struct UdpGwClient_connection * find_connection_by_conaddr (UdpGwClient *o, struct UdpGwClient_conaddr conaddr); |
||
49 | static struct UdpGwClient_connection * find_connection_by_conid (UdpGwClient *o, uint16_t conid); |
||
50 | static uint16_t find_unused_conid (UdpGwClient *o); |
||
51 | static void connection_init (UdpGwClient *o, struct UdpGwClient_conaddr conaddr, uint8_t flags, const uint8_t *data, int data_len); |
||
52 | static void connection_free (struct UdpGwClient_connection *con); |
||
53 | static void connection_first_job_handler (struct UdpGwClient_connection *con); |
||
54 | static void connection_send (struct UdpGwClient_connection *con, uint8_t flags, const uint8_t *data, int data_len); |
||
55 | static struct UdpGwClient_connection * reuse_connection (UdpGwClient *o, struct UdpGwClient_conaddr conaddr); |
||
56 | |||
57 | static int uint16_comparator (void *unused, uint16_t *v1, uint16_t *v2) |
||
58 | { |
||
59 | return B_COMPARE(*v1, *v2); |
||
60 | } |
||
61 | |||
62 | static int conaddr_comparator (void *unused, struct UdpGwClient_conaddr *v1, struct UdpGwClient_conaddr *v2) |
||
63 | { |
||
64 | int r = BAddr_CompareOrder(&v1->remote_addr, &v2->remote_addr); |
||
65 | if (r) { |
||
66 | return r; |
||
67 | } |
||
68 | return BAddr_CompareOrder(&v1->local_addr, &v2->local_addr); |
||
69 | } |
||
70 | |||
71 | static void free_server (UdpGwClient *o) |
||
72 | { |
||
73 | // disconnect send connector |
||
74 | PacketPassConnector_DisconnectOutput(&o->send_connector); |
||
75 | |||
76 | // free send sender |
||
77 | PacketStreamSender_Free(&o->send_sender); |
||
78 | |||
79 | // free receive decoder |
||
80 | PacketProtoDecoder_Free(&o->recv_decoder); |
||
81 | |||
82 | // free receive interface |
||
83 | PacketPassInterface_Free(&o->recv_if); |
||
84 | } |
||
85 | |||
86 | static void decoder_handler_error (UdpGwClient *o) |
||
87 | { |
||
88 | DebugObject_Access(&o->d_obj); |
||
89 | ASSERT(o->have_server) |
||
90 | |||
91 | BLog(BLOG_ERROR, "decoder error"); |
||
92 | |||
93 | // report error |
||
94 | o->handler_servererror(o->user); |
||
95 | return; |
||
96 | } |
||
97 | |||
98 | static void recv_interface_handler_send (UdpGwClient *o, uint8_t *data, int data_len) |
||
99 | { |
||
100 | DebugObject_Access(&o->d_obj); |
||
101 | ASSERT(o->have_server) |
||
102 | ASSERT(data_len >= 0) |
||
103 | ASSERT(data_len <= o->udpgw_mtu) |
||
104 | |||
105 | // accept packet |
||
106 | PacketPassInterface_Done(&o->recv_if); |
||
107 | |||
108 | // check header |
||
109 | if (data_len < sizeof(struct udpgw_header)) { |
||
110 | BLog(BLOG_ERROR, "missing header"); |
||
111 | return; |
||
112 | } |
||
113 | struct udpgw_header header; |
||
114 | memcpy(&header, data, sizeof(header)); |
||
115 | data += sizeof(header); |
||
116 | data_len -= sizeof(header); |
||
117 | uint8_t flags = ltoh8(header.flags); |
||
118 | uint16_t conid = ltoh16(header.conid); |
||
119 | |||
120 | // parse address |
||
121 | BAddr remote_addr; |
||
122 | if ((flags & UDPGW_CLIENT_FLAG_IPV6)) { |
||
123 | if (data_len < sizeof(struct udpgw_addr_ipv6)) { |
||
124 | BLog(BLOG_ERROR, "missing ipv6 address"); |
||
125 | return; |
||
126 | } |
||
127 | struct udpgw_addr_ipv6 addr_ipv6; |
||
128 | memcpy(&addr_ipv6, data, sizeof(addr_ipv6)); |
||
129 | data += sizeof(addr_ipv6); |
||
130 | data_len -= sizeof(addr_ipv6); |
||
131 | BAddr_InitIPv6(&remote_addr, addr_ipv6.addr_ip, addr_ipv6.addr_port); |
||
132 | } else { |
||
133 | if (data_len < sizeof(struct udpgw_addr_ipv4)) { |
||
134 | BLog(BLOG_ERROR, "missing ipv4 address"); |
||
135 | return; |
||
136 | } |
||
137 | struct udpgw_addr_ipv4 addr_ipv4; |
||
138 | memcpy(&addr_ipv4, data, sizeof(addr_ipv4)); |
||
139 | data += sizeof(addr_ipv4); |
||
140 | data_len -= sizeof(addr_ipv4); |
||
141 | BAddr_InitIPv4(&remote_addr, addr_ipv4.addr_ip, addr_ipv4.addr_port); |
||
142 | } |
||
143 | |||
144 | // check remaining data |
||
145 | if (data_len > o->udp_mtu) { |
||
146 | BLog(BLOG_ERROR, "too much data"); |
||
147 | return; |
||
148 | } |
||
149 | |||
150 | // find connection |
||
151 | struct UdpGwClient_connection *con = find_connection_by_conid(o, conid); |
||
152 | if (!con) { |
||
153 | BLog(BLOG_ERROR, "unknown conid"); |
||
154 | return; |
||
155 | } |
||
156 | |||
157 | // check remote address |
||
158 | if (BAddr_CompareOrder(&con->conaddr.remote_addr, &remote_addr) != 0) { |
||
159 | BLog(BLOG_ERROR, "wrong remote address"); |
||
160 | return; |
||
161 | } |
||
162 | |||
163 | // move connection to front of the list |
||
164 | LinkedList1_Remove(&o->connections_list, &con->connections_list_node); |
||
165 | LinkedList1_Append(&o->connections_list, &con->connections_list_node); |
||
166 | |||
167 | // pass packet to user |
||
168 | o->handler_received(o->user, con->conaddr.local_addr, con->conaddr.remote_addr, data, data_len); |
||
169 | return; |
||
170 | } |
||
171 | |||
172 | static void send_monitor_handler (UdpGwClient *o) |
||
173 | { |
||
174 | DebugObject_Access(&o->d_obj); |
||
175 | |||
176 | if (o->keepalive_sending) { |
||
177 | return; |
||
178 | } |
||
179 | |||
180 | BLog(BLOG_INFO, "keepalive"); |
||
181 | |||
182 | // send keepalive |
||
183 | PacketPassInterface_Sender_Send(o->keepalive_if, (uint8_t *)&o->keepalive_packet, sizeof(o->keepalive_packet)); |
||
184 | |||
185 | // set sending keep-alive |
||
186 | o->keepalive_sending = 1; |
||
187 | } |
||
188 | |||
189 | static void keepalive_if_handler_done (UdpGwClient *o) |
||
190 | { |
||
191 | DebugObject_Access(&o->d_obj); |
||
192 | ASSERT(o->keepalive_sending) |
||
193 | |||
194 | // set not sending keepalive |
||
195 | o->keepalive_sending = 0; |
||
196 | } |
||
197 | |||
198 | static struct UdpGwClient_connection * find_connection_by_conaddr (UdpGwClient *o, struct UdpGwClient_conaddr conaddr) |
||
199 | { |
||
200 | BAVLNode *tree_node = BAVL_LookupExact(&o->connections_tree_by_conaddr, &conaddr); |
||
201 | if (!tree_node) { |
||
202 | return NULL; |
||
203 | } |
||
204 | |||
205 | return UPPER_OBJECT(tree_node, struct UdpGwClient_connection, connections_tree_by_conaddr_node); |
||
206 | } |
||
207 | |||
208 | static struct UdpGwClient_connection * find_connection_by_conid (UdpGwClient *o, uint16_t conid) |
||
209 | { |
||
210 | BAVLNode *tree_node = BAVL_LookupExact(&o->connections_tree_by_conid, &conid); |
||
211 | if (!tree_node) { |
||
212 | return NULL; |
||
213 | } |
||
214 | |||
215 | return UPPER_OBJECT(tree_node, struct UdpGwClient_connection, connections_tree_by_conid_node); |
||
216 | } |
||
217 | |||
218 | static uint16_t find_unused_conid (UdpGwClient *o) |
||
219 | { |
||
220 | ASSERT(o->num_connections < o->max_connections) |
||
221 | |||
222 | while (1) { |
||
223 | if (!find_connection_by_conid(o, o->next_conid)) { |
||
224 | return o->next_conid; |
||
225 | } |
||
226 | |||
227 | if (o->next_conid == o->max_connections - 1) { |
||
228 | o->next_conid = 0; |
||
229 | } else { |
||
230 | o->next_conid++; |
||
231 | } |
||
232 | } |
||
233 | } |
||
234 | |||
235 | static void connection_init (UdpGwClient *o, struct UdpGwClient_conaddr conaddr, uint8_t flags, const uint8_t *data, int data_len) |
||
236 | { |
||
237 | ASSERT(o->num_connections < o->max_connections) |
||
238 | ASSERT(!find_connection_by_conaddr(o, conaddr)) |
||
239 | ASSERT(data_len >= 0) |
||
240 | ASSERT(data_len <= o->udp_mtu) |
||
241 | |||
242 | // allocate structure |
||
243 | struct UdpGwClient_connection *con = (struct UdpGwClient_connection *)malloc(sizeof(*con)); |
||
244 | if (!con) { |
||
245 | BLog(BLOG_ERROR, "malloc failed"); |
||
246 | goto fail0; |
||
247 | } |
||
248 | |||
249 | // init arguments |
||
250 | con->client = o; |
||
251 | con->conaddr = conaddr; |
||
252 | con->first_flags = flags; |
||
253 | con->first_data = data; |
||
254 | con->first_data_len = data_len; |
||
255 | |||
256 | // allocate conid |
||
257 | con->conid = find_unused_conid(o); |
||
258 | |||
259 | // init first job |
||
260 | BPending_Init(&con->first_job, BReactor_PendingGroup(o->reactor), (BPending_handler)connection_first_job_handler, con); |
||
261 | BPending_Set(&con->first_job); |
||
262 | |||
263 | // init queue flow |
||
264 | PacketPassFairQueueFlow_Init(&con->send_qflow, &o->send_queue); |
||
265 | |||
266 | // init PacketProtoFlow |
||
267 | if (!PacketProtoFlow_Init(&con->send_ppflow, o->udpgw_mtu, o->send_buffer_size, PacketPassFairQueueFlow_GetInput(&con->send_qflow), BReactor_PendingGroup(o->reactor))) { |
||
268 | BLog(BLOG_ERROR, "PacketProtoFlow_Init failed"); |
||
269 | goto fail1; |
||
270 | } |
||
271 | con->send_if = PacketProtoFlow_GetInput(&con->send_ppflow); |
||
272 | |||
273 | // insert to connections tree by conaddr |
||
274 | ASSERT_EXECUTE(BAVL_Insert(&o->connections_tree_by_conaddr, &con->connections_tree_by_conaddr_node, NULL)) |
||
275 | |||
276 | // insert to connections tree by conid |
||
277 | ASSERT_EXECUTE(BAVL_Insert(&o->connections_tree_by_conid, &con->connections_tree_by_conid_node, NULL)) |
||
278 | |||
279 | // insert to connections list |
||
280 | LinkedList1_Append(&o->connections_list, &con->connections_list_node); |
||
281 | |||
282 | // increment number of connections |
||
283 | o->num_connections++; |
||
284 | |||
285 | return; |
||
286 | |||
287 | fail1: |
||
288 | PacketPassFairQueueFlow_Free(&con->send_qflow); |
||
289 | BPending_Free(&con->first_job); |
||
290 | free(con); |
||
291 | fail0: |
||
292 | return; |
||
293 | } |
||
294 | |||
295 | static void connection_free (struct UdpGwClient_connection *con) |
||
296 | { |
||
297 | UdpGwClient *o = con->client; |
||
298 | PacketPassFairQueueFlow_AssertFree(&con->send_qflow); |
||
299 | |||
300 | // decrement number of connections |
||
301 | o->num_connections--; |
||
302 | |||
303 | // remove from connections list |
||
304 | LinkedList1_Remove(&o->connections_list, &con->connections_list_node); |
||
305 | |||
306 | // remove from connections tree by conid |
||
307 | BAVL_Remove(&o->connections_tree_by_conid, &con->connections_tree_by_conid_node); |
||
308 | |||
309 | // remove from connections tree by conaddr |
||
310 | BAVL_Remove(&o->connections_tree_by_conaddr, &con->connections_tree_by_conaddr_node); |
||
311 | |||
312 | // free PacketProtoFlow |
||
313 | PacketProtoFlow_Free(&con->send_ppflow); |
||
314 | |||
315 | // free queue flow |
||
316 | PacketPassFairQueueFlow_Free(&con->send_qflow); |
||
317 | |||
318 | // free first job |
||
319 | BPending_Free(&con->first_job); |
||
320 | |||
321 | // free structure |
||
322 | free(con); |
||
323 | } |
||
324 | |||
325 | static void connection_first_job_handler (struct UdpGwClient_connection *con) |
||
326 | { |
||
327 | connection_send(con, UDPGW_CLIENT_FLAG_REBIND|con->first_flags, con->first_data, con->first_data_len); |
||
328 | } |
||
329 | |||
330 | static void connection_send (struct UdpGwClient_connection *con, uint8_t flags, const uint8_t *data, int data_len) |
||
331 | { |
||
332 | UdpGwClient *o = con->client; |
||
333 | B_USE(o) |
||
334 | ASSERT(data_len >= 0) |
||
335 | ASSERT(data_len <= o->udp_mtu) |
||
336 | |||
337 | // get buffer location |
||
338 | uint8_t *out; |
||
339 | if (!BufferWriter_StartPacket(con->send_if, &out)) { |
||
340 | BLog(BLOG_ERROR, "out of buffer"); |
||
341 | return; |
||
342 | } |
||
343 | int out_pos = 0; |
||
344 | |||
345 | if (con->conaddr.remote_addr.type == BADDR_TYPE_IPV6) { |
||
346 | flags |= UDPGW_CLIENT_FLAG_IPV6; |
||
347 | } |
||
348 | |||
349 | // write header |
||
350 | struct udpgw_header header; |
||
351 | header.flags = ltoh8(flags); |
||
352 | header.conid = ltoh16(con->conid); |
||
353 | memcpy(out + out_pos, &header, sizeof(header)); |
||
354 | out_pos += sizeof(header); |
||
355 | |||
356 | // write address |
||
357 | switch (con->conaddr.remote_addr.type) { |
||
358 | case BADDR_TYPE_IPV4: { |
||
359 | struct udpgw_addr_ipv4 addr_ipv4; |
||
360 | addr_ipv4.addr_ip = con->conaddr.remote_addr.ipv4.ip; |
||
361 | addr_ipv4.addr_port = con->conaddr.remote_addr.ipv4.port; |
||
362 | memcpy(out + out_pos, &addr_ipv4, sizeof(addr_ipv4)); |
||
363 | out_pos += sizeof(addr_ipv4); |
||
364 | } break; |
||
365 | case BADDR_TYPE_IPV6: { |
||
366 | struct udpgw_addr_ipv6 addr_ipv6; |
||
367 | memcpy(addr_ipv6.addr_ip, con->conaddr.remote_addr.ipv6.ip, sizeof(addr_ipv6.addr_ip)); |
||
368 | addr_ipv6.addr_port = con->conaddr.remote_addr.ipv6.port; |
||
369 | memcpy(out + out_pos, &addr_ipv6, sizeof(addr_ipv6)); |
||
370 | out_pos += sizeof(addr_ipv6); |
||
371 | } break; |
||
372 | } |
||
373 | |||
374 | // write packet to buffer |
||
375 | memcpy(out + out_pos, data, data_len); |
||
376 | out_pos += data_len; |
||
377 | |||
378 | // submit packet to buffer |
||
379 | BufferWriter_EndPacket(con->send_if, out_pos); |
||
380 | } |
||
381 | |||
382 | static struct UdpGwClient_connection * reuse_connection (UdpGwClient *o, struct UdpGwClient_conaddr conaddr) |
||
383 | { |
||
384 | ASSERT(!find_connection_by_conaddr(o, conaddr)) |
||
385 | ASSERT(o->num_connections > 0) |
||
386 | |||
387 | // get least recently used connection |
||
388 | struct UdpGwClient_connection *con = UPPER_OBJECT(LinkedList1_GetFirst(&o->connections_list), struct UdpGwClient_connection, connections_list_node); |
||
389 | |||
390 | // remove from connections tree by conaddr |
||
391 | BAVL_Remove(&o->connections_tree_by_conaddr, &con->connections_tree_by_conaddr_node); |
||
392 | |||
393 | // set new conaddr |
||
394 | con->conaddr = conaddr; |
||
395 | |||
396 | // insert to connections tree by conaddr |
||
397 | ASSERT_EXECUTE(BAVL_Insert(&o->connections_tree_by_conaddr, &con->connections_tree_by_conaddr_node, NULL)) |
||
398 | |||
399 | return con; |
||
400 | } |
||
401 | |||
402 | int UdpGwClient_Init (UdpGwClient *o, int udp_mtu, int max_connections, int send_buffer_size, btime_t keepalive_time, BReactor *reactor, void *user, |
||
403 | UdpGwClient_handler_servererror handler_servererror, |
||
404 | UdpGwClient_handler_received handler_received) |
||
405 | { |
||
406 | ASSERT(udp_mtu >= 0) |
||
407 | ASSERT(udpgw_compute_mtu(udp_mtu) >= 0) |
||
408 | ASSERT(udpgw_compute_mtu(udp_mtu) <= PACKETPROTO_MAXPAYLOAD) |
||
409 | ASSERT(max_connections > 0) |
||
410 | ASSERT(send_buffer_size > 0) |
||
411 | |||
412 | // init arguments |
||
413 | o->udp_mtu = udp_mtu; |
||
414 | o->max_connections = max_connections; |
||
415 | o->send_buffer_size = send_buffer_size; |
||
416 | o->keepalive_time = keepalive_time; |
||
417 | o->reactor = reactor; |
||
418 | o->user = user; |
||
419 | o->handler_servererror = handler_servererror; |
||
420 | o->handler_received = handler_received; |
||
421 | |||
422 | // limit max connections to number of conid's |
||
423 | if (o->max_connections > UINT16_MAX + 1) { |
||
424 | o->max_connections = UINT16_MAX + 1; |
||
425 | } |
||
426 | |||
427 | // compute MTUs |
||
428 | o->udpgw_mtu = udpgw_compute_mtu(o->udp_mtu); |
||
429 | o->pp_mtu = o->udpgw_mtu + sizeof(struct packetproto_header); |
||
430 | |||
431 | // init connections tree by conaddr |
||
432 | BAVL_Init(&o->connections_tree_by_conaddr, OFFSET_DIFF(struct UdpGwClient_connection, conaddr, connections_tree_by_conaddr_node), (BAVL_comparator)conaddr_comparator, NULL); |
||
433 | |||
434 | // init connections tree by conid |
||
435 | BAVL_Init(&o->connections_tree_by_conid, OFFSET_DIFF(struct UdpGwClient_connection, conid, connections_tree_by_conid_node), (BAVL_comparator)uint16_comparator, NULL); |
||
436 | |||
437 | // init connections list |
||
438 | LinkedList1_Init(&o->connections_list); |
||
439 | |||
440 | // set zero connections |
||
441 | o->num_connections = 0; |
||
442 | |||
443 | // set next conid |
||
444 | o->next_conid = 0; |
||
445 | |||
446 | // init send connector |
||
447 | PacketPassConnector_Init(&o->send_connector, o->pp_mtu, BReactor_PendingGroup(o->reactor)); |
||
448 | |||
449 | // init send monitor |
||
450 | PacketPassInactivityMonitor_Init(&o->send_monitor, PacketPassConnector_GetInput(&o->send_connector), o->reactor, o->keepalive_time, (PacketPassInactivityMonitor_handler)send_monitor_handler, o); |
||
451 | |||
452 | // init send queue |
||
453 | if (!PacketPassFairQueue_Init(&o->send_queue, PacketPassInactivityMonitor_GetInput(&o->send_monitor), BReactor_PendingGroup(o->reactor), 0, 1)) { |
||
454 | goto fail0; |
||
455 | } |
||
456 | |||
457 | // construct keepalive packet |
||
458 | o->keepalive_packet.pp.len = sizeof(o->keepalive_packet.udpgw); |
||
459 | memset(&o->keepalive_packet.udpgw, 0, sizeof(o->keepalive_packet.udpgw)); |
||
460 | o->keepalive_packet.udpgw.flags = UDPGW_CLIENT_FLAG_KEEPALIVE; |
||
461 | |||
462 | // init keepalive queue flow |
||
463 | PacketPassFairQueueFlow_Init(&o->keepalive_qflow, &o->send_queue); |
||
464 | o->keepalive_if = PacketPassFairQueueFlow_GetInput(&o->keepalive_qflow); |
||
465 | |||
466 | // init keepalive output |
||
467 | PacketPassInterface_Sender_Init(o->keepalive_if, (PacketPassInterface_handler_done)keepalive_if_handler_done, o); |
||
468 | |||
469 | // set not sending keepalive |
||
470 | o->keepalive_sending = 0; |
||
471 | |||
472 | // set have no server |
||
473 | o->have_server = 0; |
||
474 | |||
475 | DebugObject_Init(&o->d_obj); |
||
476 | return 1; |
||
477 | |||
478 | fail0: |
||
479 | PacketPassInactivityMonitor_Free(&o->send_monitor); |
||
480 | PacketPassConnector_Free(&o->send_connector); |
||
481 | return 0; |
||
482 | } |
||
483 | |||
484 | void UdpGwClient_Free (UdpGwClient *o) |
||
485 | { |
||
486 | DebugObject_Free(&o->d_obj); |
||
487 | |||
488 | // allow freeing send queue flows |
||
489 | PacketPassFairQueue_PrepareFree(&o->send_queue); |
||
490 | |||
491 | // free connections |
||
492 | while (!LinkedList1_IsEmpty(&o->connections_list)) { |
||
493 | struct UdpGwClient_connection *con = UPPER_OBJECT(LinkedList1_GetFirst(&o->connections_list), struct UdpGwClient_connection, connections_list_node); |
||
494 | connection_free(con); |
||
495 | } |
||
496 | |||
497 | // free server |
||
498 | if (o->have_server) { |
||
499 | free_server(o); |
||
500 | } |
||
501 | |||
502 | // free keepalive queue flow |
||
503 | PacketPassFairQueueFlow_Free(&o->keepalive_qflow); |
||
504 | |||
505 | // free send queue |
||
506 | PacketPassFairQueue_Free(&o->send_queue); |
||
507 | |||
508 | // free send |
||
509 | PacketPassInactivityMonitor_Free(&o->send_monitor); |
||
510 | |||
511 | // free send connector |
||
512 | PacketPassConnector_Free(&o->send_connector); |
||
513 | } |
||
514 | |||
515 | void UdpGwClient_SubmitPacket (UdpGwClient *o, BAddr local_addr, BAddr remote_addr, int is_dns, const uint8_t *data, int data_len) |
||
516 | { |
||
517 | DebugObject_Access(&o->d_obj); |
||
518 | ASSERT(local_addr.type == BADDR_TYPE_IPV4 || local_addr.type == BADDR_TYPE_IPV6) |
||
519 | ASSERT(remote_addr.type == BADDR_TYPE_IPV4 || remote_addr.type == BADDR_TYPE_IPV6) |
||
520 | ASSERT(data_len >= 0) |
||
521 | ASSERT(data_len <= o->udp_mtu) |
||
522 | |||
523 | // build conaddr |
||
524 | struct UdpGwClient_conaddr conaddr; |
||
525 | conaddr.local_addr = local_addr; |
||
526 | conaddr.remote_addr = remote_addr; |
||
527 | |||
528 | // lookup connection |
||
529 | struct UdpGwClient_connection *con = find_connection_by_conaddr(o, conaddr); |
||
530 | |||
531 | uint8_t flags = 0; |
||
532 | |||
533 | if (is_dns) { |
||
534 | // route to remote DNS server instead of provided address |
||
535 | flags |= UDPGW_CLIENT_FLAG_DNS; |
||
536 | } |
||
537 | |||
538 | // if no connection and can't create a new one, reuse the least recently used une |
||
539 | if (!con && o->num_connections == o->max_connections) { |
||
540 | con = reuse_connection(o, conaddr); |
||
541 | flags |= UDPGW_CLIENT_FLAG_REBIND; |
||
542 | } |
||
543 | |||
544 | if (!con) { |
||
545 | // create new connection |
||
546 | connection_init(o, conaddr, flags, data, data_len); |
||
547 | } else { |
||
548 | // move connection to front of the list |
||
549 | LinkedList1_Remove(&o->connections_list, &con->connections_list_node); |
||
550 | LinkedList1_Append(&o->connections_list, &con->connections_list_node); |
||
551 | |||
552 | // send packet to existing connection |
||
553 | connection_send(con, flags, data, data_len); |
||
554 | } |
||
555 | } |
||
556 | |||
557 | int UdpGwClient_ConnectServer (UdpGwClient *o, StreamPassInterface *send_if, StreamRecvInterface *recv_if) |
||
558 | { |
||
559 | DebugObject_Access(&o->d_obj); |
||
560 | ASSERT(!o->have_server) |
||
561 | |||
562 | // init receive interface |
||
563 | PacketPassInterface_Init(&o->recv_if, o->udpgw_mtu, (PacketPassInterface_handler_send)recv_interface_handler_send, o, BReactor_PendingGroup(o->reactor)); |
||
564 | |||
565 | // init receive decoder |
||
566 | if (!PacketProtoDecoder_Init(&o->recv_decoder, recv_if, &o->recv_if, BReactor_PendingGroup(o->reactor), o, (PacketProtoDecoder_handler_error)decoder_handler_error)) { |
||
567 | BLog(BLOG_ERROR, "PacketProtoDecoder_Init failed"); |
||
568 | goto fail1; |
||
569 | } |
||
570 | |||
571 | // init send sender |
||
572 | PacketStreamSender_Init(&o->send_sender, send_if, o->pp_mtu, BReactor_PendingGroup(o->reactor)); |
||
573 | |||
574 | // connect send connector |
||
575 | PacketPassConnector_ConnectOutput(&o->send_connector, PacketStreamSender_GetInput(&o->send_sender)); |
||
576 | |||
577 | // set have server |
||
578 | o->have_server = 1; |
||
579 | |||
580 | return 1; |
||
581 | |||
582 | fail1: |
||
583 | PacketPassInterface_Free(&o->recv_if); |
||
584 | return 0; |
||
585 | } |
||
586 | |||
587 | void UdpGwClient_DisconnectServer (UdpGwClient *o) |
||
588 | { |
||
589 | DebugObject_Access(&o->d_obj); |
||
590 | ASSERT(o->have_server) |
||
591 | |||
592 | // free server |
||
593 | free_server(o); |
||
594 | |||
595 | // set have no server |
||
596 | o->have_server = 0; |
||
597 | } |