BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
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 }