BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /** |
2 | * @file BDatagram_unix.c |
||
3 | * @author Ambroz Bizjak <ambrop7@gmail.com> |
||
4 | * |
||
5 | * @section LICENSE |
||
6 | * |
||
7 | * Redistribution and use in source and binary forms, with or without |
||
8 | * modification, are permitted provided that the following conditions are met: |
||
9 | * 1. Redistributions of source code must retain the above copyright |
||
10 | * notice, this list of conditions and the following disclaimer. |
||
11 | * 2. Redistributions in binary form must reproduce the above copyright |
||
12 | * notice, this list of conditions and the following disclaimer in the |
||
13 | * documentation and/or other materials provided with the distribution. |
||
14 | * 3. Neither the name of the author nor the |
||
15 | * names of its contributors may be used to endorse or promote products |
||
16 | * derived from this software without specific prior written permission. |
||
17 | * |
||
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
||
19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||
20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||
21 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
||
22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||
23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||
24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||
25 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||
27 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
28 | */ |
||
29 | |||
30 | #ifndef _GNU_SOURCE |
||
31 | #define _GNU_SOURCE |
||
32 | #endif |
||
33 | |||
34 | #include <stddef.h> |
||
35 | #include <string.h> |
||
36 | #include <unistd.h> |
||
37 | #include <errno.h> |
||
38 | #include <sys/types.h> |
||
39 | #include <sys/socket.h> |
||
40 | #ifdef BADVPN_LINUX |
||
41 | # include <netpacket/packet.h> |
||
42 | # include <net/ethernet.h> |
||
43 | #endif |
||
44 | |||
45 | #include <misc/nonblocking.h> |
||
46 | #include <base/BLog.h> |
||
47 | |||
48 | #include "BDatagram.h" |
||
49 | |||
50 | #include <generated/blog_channel_BDatagram.h> |
||
51 | |||
52 | struct sys_addr { |
||
53 | socklen_t len; |
||
54 | union { |
||
55 | struct sockaddr generic; |
||
56 | struct sockaddr_in ipv4; |
||
57 | struct sockaddr_in6 ipv6; |
||
58 | #ifdef BADVPN_LINUX |
||
59 | struct sockaddr_ll packet; |
||
60 | #endif |
||
61 | } addr; |
||
62 | }; |
||
63 | |||
64 | static int family_socket_to_sys (int family); |
||
65 | static void addr_socket_to_sys (struct sys_addr *out, BAddr addr); |
||
66 | static void addr_sys_to_socket (BAddr *out, struct sys_addr addr); |
||
67 | static void set_pktinfo (int fd, int family); |
||
68 | static void report_error (BDatagram *o); |
||
69 | static void do_send (BDatagram *o); |
||
70 | static void do_recv (BDatagram *o); |
||
71 | static void fd_handler (BDatagram *o, int events); |
||
72 | static void send_job_handler (BDatagram *o); |
||
73 | static void recv_job_handler (BDatagram *o); |
||
74 | static void send_if_handler_send (BDatagram *o, uint8_t *data, int data_len); |
||
75 | static void recv_if_handler_recv (BDatagram *o, uint8_t *data); |
||
76 | |||
77 | static int family_socket_to_sys (int family) |
||
78 | { |
||
79 | switch (family) { |
||
80 | case BADDR_TYPE_IPV4: |
||
81 | return AF_INET; |
||
82 | case BADDR_TYPE_IPV6: |
||
83 | return AF_INET6; |
||
84 | #ifdef BADVPN_LINUX |
||
85 | case BADDR_TYPE_PACKET: |
||
86 | return AF_PACKET; |
||
87 | #endif |
||
88 | } |
||
89 | |||
90 | ASSERT(0); |
||
91 | return 0; |
||
92 | } |
||
93 | |||
94 | static void addr_socket_to_sys (struct sys_addr *out, BAddr addr) |
||
95 | { |
||
96 | switch (addr.type) { |
||
97 | case BADDR_TYPE_IPV4: { |
||
98 | out->len = sizeof(out->addr.ipv4); |
||
99 | memset(&out->addr.ipv4, 0, sizeof(out->addr.ipv4)); |
||
100 | out->addr.ipv4.sin_family = AF_INET; |
||
101 | out->addr.ipv4.sin_port = addr.ipv4.port; |
||
102 | out->addr.ipv4.sin_addr.s_addr = addr.ipv4.ip; |
||
103 | } break; |
||
104 | |||
105 | case BADDR_TYPE_IPV6: { |
||
106 | out->len = sizeof(out->addr.ipv6); |
||
107 | memset(&out->addr.ipv6, 0, sizeof(out->addr.ipv6)); |
||
108 | out->addr.ipv6.sin6_family = AF_INET6; |
||
109 | out->addr.ipv6.sin6_port = addr.ipv6.port; |
||
110 | out->addr.ipv6.sin6_flowinfo = 0; |
||
111 | memcpy(out->addr.ipv6.sin6_addr.s6_addr, addr.ipv6.ip, 16); |
||
112 | out->addr.ipv6.sin6_scope_id = 0; |
||
113 | } break; |
||
114 | |||
115 | #ifdef BADVPN_LINUX |
||
116 | case BADDR_TYPE_PACKET: { |
||
117 | ASSERT(addr.packet.header_type == BADDR_PACKET_HEADER_TYPE_ETHERNET) |
||
118 | memset(&out->addr.packet, 0, sizeof(out->addr.packet)); |
||
119 | out->len = sizeof(out->addr.packet); |
||
120 | out->addr.packet.sll_family = AF_PACKET; |
||
121 | out->addr.packet.sll_protocol = addr.packet.phys_proto; |
||
122 | out->addr.packet.sll_ifindex = addr.packet.interface_index; |
||
123 | out->addr.packet.sll_hatype = 1; // linux/if_arp.h: #define ARPHRD_ETHER 1 |
||
124 | switch (addr.packet.packet_type) { |
||
125 | case BADDR_PACKET_PACKET_TYPE_HOST: |
||
126 | out->addr.packet.sll_pkttype = PACKET_HOST; |
||
127 | break; |
||
128 | case BADDR_PACKET_PACKET_TYPE_BROADCAST: |
||
129 | out->addr.packet.sll_pkttype = PACKET_BROADCAST; |
||
130 | break; |
||
131 | case BADDR_PACKET_PACKET_TYPE_MULTICAST: |
||
132 | out->addr.packet.sll_pkttype = PACKET_MULTICAST; |
||
133 | break; |
||
134 | case BADDR_PACKET_PACKET_TYPE_OTHERHOST: |
||
135 | out->addr.packet.sll_pkttype = PACKET_OTHERHOST; |
||
136 | break; |
||
137 | case BADDR_PACKET_PACKET_TYPE_OUTGOING: |
||
138 | out->addr.packet.sll_pkttype = PACKET_OUTGOING; |
||
139 | break; |
||
140 | default: |
||
141 | ASSERT(0); |
||
142 | } |
||
143 | out->addr.packet.sll_halen = 6; |
||
144 | memcpy(out->addr.packet.sll_addr, addr.packet.phys_addr, 6); |
||
145 | } break; |
||
146 | #endif |
||
147 | |||
148 | default: ASSERT(0); |
||
149 | } |
||
150 | } |
||
151 | |||
152 | static void addr_sys_to_socket (BAddr *out, struct sys_addr addr) |
||
153 | { |
||
154 | switch (addr.addr.generic.sa_family) { |
||
155 | case AF_INET: { |
||
156 | ASSERT(addr.len == sizeof(struct sockaddr_in)) |
||
157 | BAddr_InitIPv4(out, addr.addr.ipv4.sin_addr.s_addr, addr.addr.ipv4.sin_port); |
||
158 | } break; |
||
159 | |||
160 | case AF_INET6: { |
||
161 | ASSERT(addr.len == sizeof(struct sockaddr_in6)) |
||
162 | BAddr_InitIPv6(out, addr.addr.ipv6.sin6_addr.s6_addr, addr.addr.ipv6.sin6_port); |
||
163 | } break; |
||
164 | |||
165 | #ifdef BADVPN_LINUX |
||
166 | case AF_PACKET: { |
||
167 | if (addr.len < offsetof(struct sockaddr_ll, sll_addr) + 6) { |
||
168 | goto fail; |
||
169 | } |
||
170 | if (addr.addr.packet.sll_hatype != 1) { // linux/if_arp.h: #define ARPHRD_ETHER 1 |
||
171 | goto fail; |
||
172 | } |
||
173 | int packet_type; |
||
174 | switch (addr.addr.packet.sll_pkttype) { |
||
175 | case PACKET_HOST: |
||
176 | packet_type = BADDR_PACKET_PACKET_TYPE_HOST; |
||
177 | break; |
||
178 | case PACKET_BROADCAST: |
||
179 | packet_type = BADDR_PACKET_PACKET_TYPE_BROADCAST; |
||
180 | break; |
||
181 | case PACKET_MULTICAST: |
||
182 | packet_type = BADDR_PACKET_PACKET_TYPE_MULTICAST; |
||
183 | break; |
||
184 | case PACKET_OTHERHOST: |
||
185 | packet_type = BADDR_PACKET_PACKET_TYPE_OTHERHOST; |
||
186 | break; |
||
187 | case PACKET_OUTGOING: |
||
188 | packet_type = BADDR_PACKET_PACKET_TYPE_OUTGOING; |
||
189 | break; |
||
190 | default: |
||
191 | goto fail; |
||
192 | } |
||
193 | if (addr.addr.packet.sll_halen != 6) { |
||
194 | goto fail; |
||
195 | } |
||
196 | BAddr_InitPacket(out, addr.addr.packet.sll_protocol, addr.addr.packet.sll_ifindex, BADDR_PACKET_HEADER_TYPE_ETHERNET, packet_type, addr.addr.packet.sll_addr); |
||
197 | } break; |
||
198 | #endif |
||
199 | |||
200 | fail: |
||
201 | default: { |
||
202 | BAddr_InitNone(out); |
||
203 | } break; |
||
204 | } |
||
205 | } |
||
206 | |||
207 | static void set_pktinfo (int fd, int family) |
||
208 | { |
||
209 | int opt = 1; |
||
210 | |||
211 | switch (family) { |
||
212 | case BADDR_TYPE_IPV4: { |
||
213 | #ifdef BADVPN_FREEBSD |
||
214 | if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) < 0) { |
||
215 | BLog(BLOG_ERROR, "setsockopt(IP_RECVDSTADDR) failed"); |
||
216 | } |
||
217 | #else |
||
218 | if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) < 0) { |
||
219 | BLog(BLOG_ERROR, "setsockopt(IP_PKTINFO) failed"); |
||
220 | } |
||
221 | #endif |
||
222 | } break; |
||
223 | |||
224 | #ifdef IPV6_RECVPKTINFO |
||
225 | case BADDR_TYPE_IPV6: { |
||
226 | if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt, sizeof(opt)) < 0) { |
||
227 | BLog(BLOG_ERROR, "setsockopt(IPV6_RECVPKTINFO) failed"); |
||
228 | } |
||
229 | } break; |
||
230 | #endif |
||
231 | } |
||
232 | } |
||
233 | |||
234 | static void report_error (BDatagram *o) |
||
235 | { |
||
236 | DebugError_AssertNoError(&o->d_err); |
||
237 | |||
238 | // report error |
||
239 | DEBUGERROR(&o->d_err, o->handler(o->user, BDATAGRAM_EVENT_ERROR)); |
||
240 | return; |
||
241 | } |
||
242 | |||
243 | static void do_send (BDatagram *o) |
||
244 | { |
||
245 | DebugError_AssertNoError(&o->d_err); |
||
246 | ASSERT(o->send.inited) |
||
247 | ASSERT(o->send.busy) |
||
248 | ASSERT(o->send.have_addrs) |
||
249 | |||
250 | // limit |
||
251 | if (!BReactorLimit_Increment(&o->send.limit)) { |
||
252 | // wait for fd |
||
253 | o->wait_events |= BREACTOR_WRITE; |
||
254 | BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events); |
||
255 | return; |
||
256 | } |
||
257 | |||
258 | // convert destination address |
||
259 | struct sys_addr sysaddr; |
||
260 | addr_socket_to_sys(&sysaddr, o->send.remote_addr); |
||
261 | |||
262 | struct iovec iov; |
||
263 | iov.iov_base = (uint8_t *)o->send.busy_data; |
||
264 | iov.iov_len = o->send.busy_data_len; |
||
265 | |||
266 | union { |
||
267 | #ifdef BADVPN_FREEBSD |
||
268 | char in[CMSG_SPACE(sizeof(struct in_addr))]; |
||
269 | #else |
||
270 | char in[CMSG_SPACE(sizeof(struct in_pktinfo))]; |
||
271 | #endif |
||
272 | char in6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; |
||
273 | } cdata; |
||
274 | |||
275 | struct msghdr msg; |
||
276 | memset(&msg, 0, sizeof(msg)); |
||
277 | msg.msg_name = &sysaddr.addr.generic; |
||
278 | msg.msg_namelen = sysaddr.len; |
||
279 | msg.msg_iov = &iov; |
||
280 | msg.msg_iovlen = 1; |
||
281 | msg.msg_control = &cdata; |
||
282 | msg.msg_controllen = sizeof(cdata); |
||
283 | |||
284 | struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); |
||
285 | |||
286 | size_t controllen = 0; |
||
287 | |||
288 | switch (o->send.local_addr.type) { |
||
289 | case BADDR_TYPE_IPV4: { |
||
290 | #ifdef BADVPN_FREEBSD |
||
291 | memset(cmsg, 0, CMSG_SPACE(sizeof(struct in_addr))); |
||
292 | cmsg->cmsg_level = IPPROTO_IP; |
||
293 | cmsg->cmsg_type = IP_SENDSRCADDR; |
||
294 | cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); |
||
295 | struct in_addr *addrinfo = (struct in_addr *)CMSG_DATA(cmsg); |
||
296 | addrinfo->s_addr = o->send.local_addr.ipv4; |
||
297 | controllen += CMSG_SPACE(sizeof(struct in_addr)); |
||
298 | #else |
||
299 | memset(cmsg, 0, CMSG_SPACE(sizeof(struct in_pktinfo))); |
||
300 | cmsg->cmsg_level = IPPROTO_IP; |
||
301 | cmsg->cmsg_type = IP_PKTINFO; |
||
302 | cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); |
||
303 | struct in_pktinfo *pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg); |
||
304 | pktinfo->ipi_spec_dst.s_addr = o->send.local_addr.ipv4; |
||
305 | controllen += CMSG_SPACE(sizeof(struct in_pktinfo)); |
||
306 | #endif |
||
307 | } break; |
||
308 | |||
309 | case BADDR_TYPE_IPV6: { |
||
310 | memset(cmsg, 0, CMSG_SPACE(sizeof(struct in6_pktinfo))); |
||
311 | cmsg->cmsg_level = IPPROTO_IPV6; |
||
312 | cmsg->cmsg_type = IPV6_PKTINFO; |
||
313 | cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); |
||
314 | struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg); |
||
315 | memcpy(pktinfo->ipi6_addr.s6_addr, o->send.local_addr.ipv6, 16); |
||
316 | controllen += CMSG_SPACE(sizeof(struct in6_pktinfo)); |
||
317 | } break; |
||
318 | } |
||
319 | |||
320 | msg.msg_controllen = controllen; |
||
321 | |||
322 | if (msg.msg_controllen == 0) { |
||
323 | msg.msg_control = NULL; |
||
324 | } |
||
325 | |||
326 | // send |
||
327 | int bytes = sendmsg(o->fd, &msg, 0); |
||
328 | if (bytes < 0) { |
||
329 | if (errno == EAGAIN || errno == EWOULDBLOCK) { |
||
330 | // wait for fd |
||
331 | o->wait_events |= BREACTOR_WRITE; |
||
332 | BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events); |
||
333 | return; |
||
334 | } |
||
335 | |||
336 | report_error(o); |
||
337 | return; |
||
338 | } |
||
339 | |||
340 | ASSERT(bytes >= 0) |
||
341 | ASSERT(bytes <= o->send.busy_data_len) |
||
342 | |||
343 | if (bytes < o->send.busy_data_len) { |
||
344 | BLog(BLOG_ERROR, "send sent too little"); |
||
345 | } |
||
346 | |||
347 | // if recv wasn't started yet, start it |
||
348 | if (!o->recv.started) { |
||
349 | // set recv started |
||
350 | o->recv.started = 1; |
||
351 | |||
352 | // continue receiving |
||
353 | if (o->recv.inited && o->recv.busy) { |
||
354 | BPending_Set(&o->recv.job); |
||
355 | } |
||
356 | } |
||
357 | |||
358 | // set not busy |
||
359 | o->send.busy = 0; |
||
360 | |||
361 | // done |
||
362 | PacketPassInterface_Done(&o->send.iface); |
||
363 | } |
||
364 | |||
365 | static void do_recv (BDatagram *o) |
||
366 | { |
||
367 | DebugError_AssertNoError(&o->d_err); |
||
368 | ASSERT(o->recv.inited) |
||
369 | ASSERT(o->recv.busy) |
||
370 | ASSERT(o->recv.started) |
||
371 | |||
372 | // limit |
||
373 | if (!BReactorLimit_Increment(&o->recv.limit)) { |
||
374 | // wait for fd |
||
375 | o->wait_events |= BREACTOR_READ; |
||
376 | BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events); |
||
377 | return; |
||
378 | } |
||
379 | |||
380 | struct sys_addr sysaddr; |
||
381 | |||
382 | struct iovec iov; |
||
383 | iov.iov_base = o->recv.busy_data; |
||
384 | iov.iov_len = o->recv.mtu; |
||
385 | |||
386 | union { |
||
387 | #ifdef BADVPN_FREEBSD |
||
388 | char in[CMSG_SPACE(sizeof(struct in_addr))]; |
||
389 | #else |
||
390 | char in[CMSG_SPACE(sizeof(struct in_pktinfo))]; |
||
391 | #endif |
||
392 | char in6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; |
||
393 | } cdata; |
||
394 | |||
395 | struct msghdr msg; |
||
396 | memset(&msg, 0, sizeof(msg)); |
||
397 | msg.msg_name = &sysaddr.addr.generic; |
||
398 | msg.msg_namelen = sizeof(sysaddr.addr); |
||
399 | msg.msg_iov = &iov; |
||
400 | msg.msg_iovlen = 1; |
||
401 | msg.msg_control = &cdata; |
||
402 | msg.msg_controllen = sizeof(cdata); |
||
403 | |||
404 | // recv |
||
405 | int bytes = recvmsg(o->fd, &msg, 0); |
||
406 | if (bytes < 0) { |
||
407 | if (errno == EAGAIN || errno == EWOULDBLOCK) { |
||
408 | // wait for fd |
||
409 | o->wait_events |= BREACTOR_READ; |
||
410 | BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events); |
||
411 | return; |
||
412 | } |
||
413 | |||
414 | BLog(BLOG_ERROR, "recv failed"); |
||
415 | report_error(o); |
||
416 | return; |
||
417 | } |
||
418 | |||
419 | ASSERT(bytes >= 0) |
||
420 | ASSERT(bytes <= o->recv.mtu) |
||
421 | |||
422 | // read returned address |
||
423 | sysaddr.len = msg.msg_namelen; |
||
424 | addr_sys_to_socket(&o->recv.remote_addr, sysaddr); |
||
425 | |||
426 | // read returned local address |
||
427 | BIPAddr_InitInvalid(&o->recv.local_addr); |
||
428 | for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { |
||
429 | #ifdef BADVPN_FREEBSD |
||
430 | if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) { |
||
431 | struct in_addr *addrinfo = (struct in_addr *)CMSG_DATA(cmsg); |
||
432 | BIPAddr_InitIPv4(&o->recv.local_addr, addrinfo->s_addr); |
||
433 | } |
||
434 | #else |
||
435 | if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) { |
||
436 | struct in_pktinfo *pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg); |
||
437 | BIPAddr_InitIPv4(&o->recv.local_addr, pktinfo->ipi_addr.s_addr); |
||
438 | } |
||
439 | #endif |
||
440 | else if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) { |
||
441 | struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg); |
||
442 | BIPAddr_InitIPv6(&o->recv.local_addr, pktinfo->ipi6_addr.s6_addr); |
||
443 | } |
||
444 | } |
||
445 | |||
446 | // set have addresses |
||
447 | o->recv.have_addrs = 1; |
||
448 | |||
449 | // set not busy |
||
450 | o->recv.busy = 0; |
||
451 | |||
452 | // done |
||
453 | PacketRecvInterface_Done(&o->recv.iface, bytes); |
||
454 | } |
||
455 | |||
456 | static void fd_handler (BDatagram *o, int events) |
||
457 | { |
||
458 | DebugObject_Access(&o->d_obj); |
||
459 | DebugError_AssertNoError(&o->d_err); |
||
460 | |||
461 | // clear handled events |
||
462 | o->wait_events &= ~events; |
||
463 | BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events); |
||
464 | |||
465 | int have_send = 0; |
||
466 | int have_recv = 0; |
||
467 | |||
468 | if ((events & BREACTOR_WRITE) || ((events & (BREACTOR_ERROR|BREACTOR_HUP)) && o->send.inited && o->send.busy && o->send.have_addrs)) { |
||
469 | ASSERT(o->send.inited) |
||
470 | ASSERT(o->send.busy) |
||
471 | ASSERT(o->send.have_addrs) |
||
472 | |||
473 | have_send = 1; |
||
474 | } |
||
475 | |||
476 | if ((events & BREACTOR_READ) || ((events & (BREACTOR_ERROR|BREACTOR_HUP)) && o->recv.inited && o->recv.busy && o->recv.started)) { |
||
477 | ASSERT(o->recv.inited) |
||
478 | ASSERT(o->recv.busy) |
||
479 | ASSERT(o->recv.started) |
||
480 | |||
481 | have_recv = 1; |
||
482 | } |
||
483 | |||
484 | if (have_send) { |
||
485 | if (have_recv) { |
||
486 | BPending_Set(&o->recv.job); |
||
487 | } |
||
488 | |||
489 | do_send(o); |
||
490 | return; |
||
491 | } |
||
492 | |||
493 | if (have_recv) { |
||
494 | do_recv(o); |
||
495 | return; |
||
496 | } |
||
497 | |||
498 | BLog(BLOG_ERROR, "fd error event"); |
||
499 | report_error(o); |
||
500 | return; |
||
501 | } |
||
502 | |||
503 | static void send_job_handler (BDatagram *o) |
||
504 | { |
||
505 | DebugObject_Access(&o->d_obj); |
||
506 | DebugError_AssertNoError(&o->d_err); |
||
507 | ASSERT(o->send.inited) |
||
508 | ASSERT(o->send.busy) |
||
509 | ASSERT(o->send.have_addrs) |
||
510 | |||
511 | do_send(o); |
||
512 | return; |
||
513 | } |
||
514 | |||
515 | static void recv_job_handler (BDatagram *o) |
||
516 | { |
||
517 | DebugObject_Access(&o->d_obj); |
||
518 | DebugError_AssertNoError(&o->d_err); |
||
519 | ASSERT(o->recv.inited) |
||
520 | ASSERT(o->recv.busy) |
||
521 | ASSERT(o->recv.started) |
||
522 | |||
523 | do_recv(o); |
||
524 | return; |
||
525 | } |
||
526 | |||
527 | static void send_if_handler_send (BDatagram *o, uint8_t *data, int data_len) |
||
528 | { |
||
529 | DebugObject_Access(&o->d_obj); |
||
530 | DebugError_AssertNoError(&o->d_err); |
||
531 | ASSERT(o->send.inited) |
||
532 | ASSERT(!o->send.busy) |
||
533 | ASSERT(data_len >= 0) |
||
534 | ASSERT(data_len <= o->send.mtu) |
||
535 | |||
536 | // remember data |
||
537 | o->send.busy_data = data; |
||
538 | o->send.busy_data_len = data_len; |
||
539 | |||
540 | // set busy |
||
541 | o->send.busy = 1; |
||
542 | |||
543 | // if have no addresses, wait |
||
544 | if (!o->send.have_addrs) { |
||
545 | return; |
||
546 | } |
||
547 | |||
548 | // set job |
||
549 | BPending_Set(&o->send.job); |
||
550 | } |
||
551 | |||
552 | static void recv_if_handler_recv (BDatagram *o, uint8_t *data) |
||
553 | { |
||
554 | DebugObject_Access(&o->d_obj); |
||
555 | DebugError_AssertNoError(&o->d_err); |
||
556 | ASSERT(o->recv.inited) |
||
557 | ASSERT(!o->recv.busy) |
||
558 | |||
559 | // remember data |
||
560 | o->recv.busy_data = data; |
||
561 | |||
562 | // set busy |
||
563 | o->recv.busy = 1; |
||
564 | |||
565 | // if recv not started yet, wait |
||
566 | if (!o->recv.started) { |
||
567 | return; |
||
568 | } |
||
569 | |||
570 | // set job |
||
571 | BPending_Set(&o->recv.job); |
||
572 | } |
||
573 | |||
574 | int BDatagram_AddressFamilySupported (int family) |
||
575 | { |
||
576 | switch (family) { |
||
577 | case BADDR_TYPE_IPV4: |
||
578 | case BADDR_TYPE_IPV6: |
||
579 | #ifdef BADVPN_LINUX |
||
580 | case BADDR_TYPE_PACKET: |
||
581 | #endif |
||
582 | return 1; |
||
583 | } |
||
584 | |||
585 | return 0; |
||
586 | } |
||
587 | |||
588 | int BDatagram_Init (BDatagram *o, int family, BReactor *reactor, void *user, |
||
589 | BDatagram_handler handler) |
||
590 | { |
||
591 | ASSERT(BDatagram_AddressFamilySupported(family)) |
||
592 | ASSERT(handler) |
||
593 | BNetwork_Assert(); |
||
594 | |||
595 | // init arguments |
||
596 | o->reactor = reactor; |
||
597 | o->user = user; |
||
598 | o->handler = handler; |
||
599 | |||
600 | // init fd |
||
601 | if ((o->fd = socket(family_socket_to_sys(family), SOCK_DGRAM, 0)) < 0) { |
||
602 | BLog(BLOG_ERROR, "socket failed"); |
||
603 | goto fail0; |
||
604 | } |
||
605 | |||
606 | // set fd non-blocking |
||
607 | if (!badvpn_set_nonblocking(o->fd)) { |
||
608 | BLog(BLOG_ERROR, "badvpn_set_nonblocking failed"); |
||
609 | goto fail1; |
||
610 | } |
||
611 | |||
612 | // enable receiving pktinfo |
||
613 | set_pktinfo(o->fd, family); |
||
614 | |||
615 | // init BFileDescriptor |
||
616 | BFileDescriptor_Init(&o->bfd, o->fd, (BFileDescriptor_handler)fd_handler, o); |
||
617 | if (!BReactor_AddFileDescriptor(o->reactor, &o->bfd)) { |
||
618 | BLog(BLOG_ERROR, "BReactor_AddFileDescriptor failed"); |
||
619 | goto fail1; |
||
620 | } |
||
621 | |||
622 | // set no wait events |
||
623 | o->wait_events = 0; |
||
624 | |||
625 | // init limits |
||
626 | BReactorLimit_Init(&o->send.limit, o->reactor, BDATAGRAM_SEND_LIMIT); |
||
627 | BReactorLimit_Init(&o->recv.limit, o->reactor, BDATAGRAM_RECV_LIMIT); |
||
628 | |||
629 | // set have no send and recv addresses |
||
630 | o->send.have_addrs = 0; |
||
631 | o->recv.have_addrs = 0; |
||
632 | |||
633 | // set recv not started |
||
634 | o->recv.started = 0; |
||
635 | |||
636 | // set send and recv not inited |
||
637 | o->send.inited = 0; |
||
638 | o->recv.inited = 0; |
||
639 | |||
640 | DebugError_Init(&o->d_err, BReactor_PendingGroup(o->reactor)); |
||
641 | DebugObject_Init(&o->d_obj); |
||
642 | return 1; |
||
643 | |||
644 | fail1: |
||
645 | if (close(o->fd) < 0) { |
||
646 | BLog(BLOG_ERROR, "close failed"); |
||
647 | } |
||
648 | fail0: |
||
649 | return 0; |
||
650 | } |
||
651 | |||
652 | void BDatagram_Free (BDatagram *o) |
||
653 | { |
||
654 | DebugObject_Free(&o->d_obj); |
||
655 | DebugError_Free(&o->d_err); |
||
656 | ASSERT(!o->recv.inited) |
||
657 | ASSERT(!o->send.inited) |
||
658 | |||
659 | // free limits |
||
660 | BReactorLimit_Free(&o->recv.limit); |
||
661 | BReactorLimit_Free(&o->send.limit); |
||
662 | |||
663 | // free BFileDescriptor |
||
664 | BReactor_RemoveFileDescriptor(o->reactor, &o->bfd); |
||
665 | |||
666 | // free fd |
||
667 | if (close(o->fd) < 0) { |
||
668 | BLog(BLOG_ERROR, "close failed"); |
||
669 | } |
||
670 | } |
||
671 | |||
672 | int BDatagram_Bind (BDatagram *o, BAddr addr) |
||
673 | { |
||
674 | DebugObject_Access(&o->d_obj); |
||
675 | DebugError_AssertNoError(&o->d_err); |
||
676 | ASSERT(BDatagram_AddressFamilySupported(addr.type)) |
||
677 | |||
678 | // translate address |
||
679 | struct sys_addr sysaddr; |
||
680 | addr_socket_to_sys(&sysaddr, addr); |
||
681 | |||
682 | // bind |
||
683 | if (bind(o->fd, &sysaddr.addr.generic, sysaddr.len) < 0) { |
||
684 | BLog(BLOG_ERROR, "bind failed"); |
||
685 | return 0; |
||
686 | } |
||
687 | |||
688 | // if recv wasn't started yet, start it |
||
689 | if (!o->recv.started) { |
||
690 | // set recv started |
||
691 | o->recv.started = 1; |
||
692 | |||
693 | // continue receiving |
||
694 | if (o->recv.inited && o->recv.busy) { |
||
695 | BPending_Set(&o->recv.job); |
||
696 | } |
||
697 | } |
||
698 | |||
699 | return 1; |
||
700 | } |
||
701 | |||
702 | void BDatagram_SetSendAddrs (BDatagram *o, BAddr remote_addr, BIPAddr local_addr) |
||
703 | { |
||
704 | DebugObject_Access(&o->d_obj); |
||
705 | DebugError_AssertNoError(&o->d_err); |
||
706 | ASSERT(BDatagram_AddressFamilySupported(remote_addr.type)) |
||
707 | ASSERT(local_addr.type == BADDR_TYPE_NONE || BDatagram_AddressFamilySupported(local_addr.type)) |
||
708 | |||
709 | // set addresses |
||
710 | o->send.remote_addr = remote_addr; |
||
711 | o->send.local_addr = local_addr; |
||
712 | |||
713 | if (!o->send.have_addrs) { |
||
714 | // set have addresses |
||
715 | o->send.have_addrs = 1; |
||
716 | |||
717 | // start sending |
||
718 | if (o->send.inited && o->send.busy) { |
||
719 | BPending_Set(&o->send.job); |
||
720 | } |
||
721 | } |
||
722 | } |
||
723 | |||
724 | int BDatagram_GetLastReceiveAddrs (BDatagram *o, BAddr *remote_addr, BIPAddr *local_addr) |
||
725 | { |
||
726 | DebugObject_Access(&o->d_obj); |
||
727 | |||
728 | if (!o->recv.have_addrs) { |
||
729 | return 0; |
||
730 | } |
||
731 | |||
732 | *remote_addr = o->recv.remote_addr; |
||
733 | *local_addr = o->recv.local_addr; |
||
734 | return 1; |
||
735 | } |
||
736 | |||
737 | int BDatagram_GetLocalAddr (BDatagram *o, BAddr *local_addr) |
||
738 | { |
||
739 | DebugObject_Access(&o->d_obj); |
||
740 | |||
741 | struct sys_addr sysaddr; |
||
742 | sysaddr.len = sizeof(sysaddr.addr); |
||
743 | if (getsockname(o->fd, &sysaddr.addr.generic, &sysaddr.len) != 0) { |
||
744 | BLog(BLOG_ERROR, "BDatagram_GetLocalAddr: getsockname failed"); |
||
745 | return 0; |
||
746 | } |
||
747 | |||
748 | BAddr addr; |
||
749 | addr_sys_to_socket(&addr, sysaddr); |
||
750 | |||
751 | if (addr.type == BADDR_TYPE_NONE) { |
||
752 | BLog(BLOG_ERROR, "BDatagram_GetLocalAddr: Unsupported address family " |
||
753 | "from getsockname: %d", (int)sysaddr.addr.generic.sa_family); |
||
754 | return 0; |
||
755 | } |
||
756 | |||
757 | *local_addr = addr; |
||
758 | return 1; |
||
759 | } |
||
760 | |||
761 | int BDatagram_GetFd (BDatagram *o) |
||
762 | { |
||
763 | DebugObject_Access(&o->d_obj); |
||
764 | |||
765 | return o->fd; |
||
766 | } |
||
767 | |||
768 | int BDatagram_SetReuseAddr (BDatagram *o, int reuse) |
||
769 | { |
||
770 | DebugObject_Access(&o->d_obj); |
||
771 | ASSERT(reuse == 0 || reuse == 1) |
||
772 | |||
773 | if (setsockopt(o->fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) { |
||
774 | return 0; |
||
775 | } |
||
776 | |||
777 | return 1; |
||
778 | } |
||
779 | |||
780 | void BDatagram_SendAsync_Init (BDatagram *o, int mtu) |
||
781 | { |
||
782 | DebugObject_Access(&o->d_obj); |
||
783 | DebugError_AssertNoError(&o->d_err); |
||
784 | ASSERT(!o->send.inited) |
||
785 | ASSERT(mtu >= 0) |
||
786 | |||
787 | // init arguments |
||
788 | o->send.mtu = mtu; |
||
789 | |||
790 | // init interface |
||
791 | PacketPassInterface_Init(&o->send.iface, o->send.mtu, (PacketPassInterface_handler_send)send_if_handler_send, o, BReactor_PendingGroup(o->reactor)); |
||
792 | |||
793 | // init job |
||
794 | BPending_Init(&o->send.job, BReactor_PendingGroup(o->reactor), (BPending_handler)send_job_handler, o); |
||
795 | |||
796 | // set not busy |
||
797 | o->send.busy = 0; |
||
798 | |||
799 | // set inited |
||
800 | o->send.inited = 1; |
||
801 | } |
||
802 | |||
803 | void BDatagram_SendAsync_Free (BDatagram *o) |
||
804 | { |
||
805 | DebugObject_Access(&o->d_obj); |
||
806 | ASSERT(o->send.inited) |
||
807 | |||
808 | // update events |
||
809 | o->wait_events &= ~BREACTOR_WRITE; |
||
810 | BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events); |
||
811 | |||
812 | // free job |
||
813 | BPending_Free(&o->send.job); |
||
814 | |||
815 | // free interface |
||
816 | PacketPassInterface_Free(&o->send.iface); |
||
817 | |||
818 | // set not inited |
||
819 | o->send.inited = 0; |
||
820 | } |
||
821 | |||
822 | PacketPassInterface * BDatagram_SendAsync_GetIf (BDatagram *o) |
||
823 | { |
||
824 | DebugObject_Access(&o->d_obj); |
||
825 | ASSERT(o->send.inited) |
||
826 | |||
827 | return &o->send.iface; |
||
828 | } |
||
829 | |||
830 | void BDatagram_RecvAsync_Init (BDatagram *o, int mtu) |
||
831 | { |
||
832 | DebugObject_Access(&o->d_obj); |
||
833 | DebugError_AssertNoError(&o->d_err); |
||
834 | ASSERT(!o->recv.inited) |
||
835 | ASSERT(mtu >= 0) |
||
836 | |||
837 | // init arguments |
||
838 | o->recv.mtu = mtu; |
||
839 | |||
840 | // init interface |
||
841 | PacketRecvInterface_Init(&o->recv.iface, o->recv.mtu, (PacketRecvInterface_handler_recv)recv_if_handler_recv, o, BReactor_PendingGroup(o->reactor)); |
||
842 | |||
843 | // init job |
||
844 | BPending_Init(&o->recv.job, BReactor_PendingGroup(o->reactor), (BPending_handler)recv_job_handler, o); |
||
845 | |||
846 | // set not busy |
||
847 | o->recv.busy = 0; |
||
848 | |||
849 | // set inited |
||
850 | o->recv.inited = 1; |
||
851 | } |
||
852 | |||
853 | void BDatagram_RecvAsync_Free (BDatagram *o) |
||
854 | { |
||
855 | DebugObject_Access(&o->d_obj); |
||
856 | ASSERT(o->recv.inited) |
||
857 | |||
858 | // update events |
||
859 | o->wait_events &= ~BREACTOR_READ; |
||
860 | BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events); |
||
861 | |||
862 | // free job |
||
863 | BPending_Free(&o->recv.job); |
||
864 | |||
865 | // free interface |
||
866 | PacketRecvInterface_Free(&o->recv.iface); |
||
867 | |||
868 | // set not inited |
||
869 | o->recv.inited = 0; |
||
870 | } |
||
871 | |||
872 | PacketRecvInterface * BDatagram_RecvAsync_GetIf (BDatagram *o) |
||
873 | { |
||
874 | DebugObject_Access(&o->d_obj); |
||
875 | ASSERT(o->recv.inited) |
||
876 | |||
877 | return &o->recv.iface; |
||
878 | } |