BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file BDatagram_win.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 #include <stdlib.h>
31  
32 #include <base/BLog.h>
33  
34 #include "BDatagram.h"
35  
36 #include <generated/blog_channel_BDatagram.h>
37  
38 static int family_socket_to_sys (int family);
39 static void addr_socket_to_sys (struct BDatagram_sys_addr *out, BAddr addr);
40 static void addr_sys_to_socket (BAddr *out, struct BDatagram_sys_addr addr);
41 static void set_pktinfo (SOCKET sock, int family);
42 static void report_error (BDatagram *o);
43 static void datagram_abort (BDatagram *o);
44 static void start_send (BDatagram *o);
45 static void start_recv (BDatagram *o);
46 static void send_job_handler (BDatagram *o);
47 static void recv_job_handler (BDatagram *o);
48 static void send_if_handler_send (BDatagram *o, uint8_t *data, int data_len);
49 static void recv_if_handler_recv (BDatagram *o, uint8_t *data);
50 static void send_olap_handler (BDatagram *o, int event, DWORD bytes);
51 static void recv_olap_handler (BDatagram *o, int event, DWORD bytes);
52  
53 static int family_socket_to_sys (int family)
54 {
55 switch (family) {
56 case BADDR_TYPE_IPV4:
57 return AF_INET;
58 case BADDR_TYPE_IPV6:
59 return AF_INET6;
60 }
61  
62 ASSERT(0);
63 return 0;
64 }
65  
66 static void addr_socket_to_sys (struct BDatagram_sys_addr *out, BAddr addr)
67 {
68 switch (addr.type) {
69 case BADDR_TYPE_IPV4: {
70 out->len = sizeof(out->addr.ipv4);
71 memset(&out->addr.ipv4, 0, sizeof(out->addr.ipv4));
72 out->addr.ipv4.sin_family = AF_INET;
73 out->addr.ipv4.sin_port = addr.ipv4.port;
74 out->addr.ipv4.sin_addr.s_addr = addr.ipv4.ip;
75 } break;
76  
77 case BADDR_TYPE_IPV6: {
78 out->len = sizeof(out->addr.ipv6);
79 memset(&out->addr.ipv6, 0, sizeof(out->addr.ipv6));
80 out->addr.ipv6.sin6_family = AF_INET6;
81 out->addr.ipv6.sin6_port = addr.ipv6.port;
82 out->addr.ipv6.sin6_flowinfo = 0;
83 memcpy(out->addr.ipv6.sin6_addr.s6_addr, addr.ipv6.ip, 16);
84 out->addr.ipv6.sin6_scope_id = 0;
85 } break;
86  
87 default: ASSERT(0);
88 }
89 }
90  
91 static void addr_sys_to_socket (BAddr *out, struct BDatagram_sys_addr addr)
92 {
93 switch (addr.addr.generic.sa_family) {
94 case AF_INET: {
95 ASSERT(addr.len == sizeof(struct sockaddr_in))
96 BAddr_InitIPv4(out, addr.addr.ipv4.sin_addr.s_addr, addr.addr.ipv4.sin_port);
97 } break;
98  
99 case AF_INET6: {
100 ASSERT(addr.len == sizeof(struct sockaddr_in6))
101 BAddr_InitIPv6(out, addr.addr.ipv6.sin6_addr.s6_addr, addr.addr.ipv6.sin6_port);
102 } break;
103  
104 default: {
105 BAddr_InitNone(out);
106 } break;
107 }
108 }
109  
110 static void set_pktinfo (SOCKET sock, int family)
111 {
112 DWORD opt = 1;
113  
114 switch (family) {
115 case BADDR_TYPE_IPV4: {
116 if (setsockopt(sock, IPPROTO_IP, IP_PKTINFO, (char *)&opt, sizeof(opt)) < 0) {
117 BLog(BLOG_ERROR, "setsockopt(IP_PKTINFO) failed");
118 }
119 } break;
120  
121 case BADDR_TYPE_IPV6: {
122 if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, (char *)&opt, sizeof(opt)) < 0) {
123 BLog(BLOG_ERROR, "setsockopt(IPV6_PKTINFO) failed");
124 }
125 } break;
126 }
127 }
128  
129 static void report_error (BDatagram *o)
130 {
131 DebugError_AssertNoError(&o->d_err);
132  
133 // report error
134 DEBUGERROR(&o->d_err, o->handler(o->user, BDATAGRAM_EVENT_ERROR));
135 return;
136 }
137  
138 static void datagram_abort (BDatagram *o)
139 {
140 ASSERT(!o->aborted)
141  
142 // cancel I/O
143 if ((o->recv.inited && o->recv.data_have && o->recv.data_busy) || (o->send.inited && o->send.data_len >= 0 && o->send.data_busy)) {
144 if (!CancelIo((HANDLE)o->sock)) {
145 BLog(BLOG_ERROR, "CancelIo failed");
146 }
147 }
148  
149 // close socket
150 if (closesocket(o->sock) == SOCKET_ERROR) {
151 BLog(BLOG_ERROR, "closesocket failed");
152 }
153  
154 // wait for receiving to complete
155 if (o->recv.inited && o->recv.data_have && o->recv.data_busy) {
156 BReactorIOCPOverlapped_Wait(&o->recv.olap, NULL, NULL);
157 }
158  
159 // wait for sending to complete
160 if (o->send.inited && o->send.data_len >= 0 && o->send.data_busy) {
161 BReactorIOCPOverlapped_Wait(&o->send.olap, NULL, NULL);
162 }
163  
164 // free recv olap
165 BReactorIOCPOverlapped_Free(&o->recv.olap);
166  
167 // free send olap
168 BReactorIOCPOverlapped_Free(&o->send.olap);
169  
170 // set aborted
171 o->aborted = 1;
172 }
173  
174 static void start_send (BDatagram *o)
175 {
176 DebugError_AssertNoError(&o->d_err);
177 ASSERT(!o->aborted)
178 ASSERT(o->send.inited)
179 ASSERT(o->send.data_len >= 0)
180 ASSERT(!o->send.data_busy)
181 ASSERT(o->send.have_addrs)
182  
183 // convert destination address
184 addr_socket_to_sys(&o->send.sysaddr, o->send.remote_addr);
185  
186 WSABUF buf;
187 buf.buf = (char *)o->send.data;
188 buf.len = (o->send.data_len > ULONG_MAX ? ULONG_MAX : o->send.data_len);
189  
190 memset(&o->send.olap.olap, 0, sizeof(o->send.olap.olap));
191  
192 if (o->fnWSASendMsg) {
193 o->send.msg.name = &o->send.sysaddr.addr.generic;
194 o->send.msg.namelen = o->send.sysaddr.len;
195 o->send.msg.lpBuffers = &buf;
196 o->send.msg.dwBufferCount = 1;
197 o->send.msg.Control.buf = (char *)&o->send.cdata;
198 o->send.msg.Control.len = sizeof(o->send.cdata);
199 o->send.msg.dwFlags = 0;
200  
201 int sum = 0;
202  
203 WSACMSGHDR *cmsg = WSA_CMSG_FIRSTHDR(&o->send.msg);
204  
205 switch (o->send.local_addr.type) {
206 case BADDR_TYPE_IPV4: {
207 memset(cmsg, 0, WSA_CMSG_SPACE(sizeof(struct in_pktinfo)));
208 cmsg->cmsg_level = IPPROTO_IP;
209 cmsg->cmsg_type = IP_PKTINFO;
210 cmsg->cmsg_len = WSA_CMSG_LEN(sizeof(struct in_pktinfo));
211 struct in_pktinfo *pktinfo = (struct in_pktinfo *)WSA_CMSG_DATA(cmsg);
212 pktinfo->ipi_addr.s_addr = o->send.local_addr.ipv4;
213 sum += WSA_CMSG_SPACE(sizeof(struct in_pktinfo));
214 } break;
215 case BADDR_TYPE_IPV6: {
216 memset(cmsg, 0, WSA_CMSG_SPACE(sizeof(struct in6_pktinfo)));
217 cmsg->cmsg_level = IPPROTO_IPV6;
218 cmsg->cmsg_type = IPV6_PKTINFO;
219 cmsg->cmsg_len = WSA_CMSG_LEN(sizeof(struct in6_pktinfo));
220 struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)WSA_CMSG_DATA(cmsg);
221 memcpy(pktinfo->ipi6_addr.s6_addr, o->send.local_addr.ipv6, 16);
222 sum += WSA_CMSG_SPACE(sizeof(struct in6_pktinfo));
223 } break;
224 }
225  
226 o->send.msg.Control.len = sum;
227  
228 if (o->send.msg.Control.len == 0) {
229 o->send.msg.Control.buf = NULL;
230 }
231  
232 // send
233 int res = o->fnWSASendMsg(o->sock, &o->send.msg, 0, NULL, &o->send.olap.olap, NULL);
234 if (res == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING) {
235 report_error(o);
236 return;
237 }
238 } else {
239 // send
240 int res = WSASendTo(o->sock, &buf, 1, NULL, 0, &o->send.sysaddr.addr.generic, o->send.sysaddr.len, &o->send.olap.olap, NULL);
241 if (res == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING) {
242 report_error(o);
243 return;
244 }
245 }
246  
247 // set busy
248 o->send.data_busy = 1;
249 }
250  
251 static void start_recv (BDatagram *o)
252 {
253 DebugError_AssertNoError(&o->d_err);
254 ASSERT(!o->aborted)
255 ASSERT(o->recv.inited)
256 ASSERT(o->recv.data_have)
257 ASSERT(!o->recv.data_busy)
258 ASSERT(o->recv.started)
259  
260 WSABUF buf;
261 buf.buf = (char *)o->recv.data;
262 buf.len = (o->recv.mtu > ULONG_MAX ? ULONG_MAX : o->recv.mtu);
263  
264 memset(&o->recv.olap.olap, 0, sizeof(o->recv.olap.olap));
265  
266 if (o->fnWSARecvMsg) {
267 o->recv.msg.name = &o->recv.sysaddr.addr.generic;
268 o->recv.msg.namelen = sizeof(o->recv.sysaddr.addr);
269 o->recv.msg.lpBuffers = &buf;
270 o->recv.msg.dwBufferCount = 1;
271 o->recv.msg.Control.buf = (char *)&o->recv.cdata;
272 o->recv.msg.Control.len = sizeof(o->recv.cdata);
273 o->recv.msg.dwFlags = 0;
274  
275 // recv
276 int res = o->fnWSARecvMsg(o->sock, &o->recv.msg, NULL, &o->recv.olap.olap, NULL);
277 if (res == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING) {
278 BLog(BLOG_ERROR, "WSARecvMsg failed (%d)", WSAGetLastError());
279 report_error(o);
280 return;
281 }
282 } else {
283 o->recv.sysaddr.len = sizeof(o->recv.sysaddr.addr);
284  
285 // recv
286 DWORD flags = 0;
287 int res = WSARecvFrom(o->sock, &buf, 1, NULL, &flags, &o->recv.sysaddr.addr.generic, &o->recv.sysaddr.len, &o->recv.olap.olap, NULL);
288 if (res == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING) {
289 BLog(BLOG_ERROR, "WSARecvFrom failed (%d)", WSAGetLastError());
290 report_error(o);
291 return;
292 }
293 }
294  
295 // set busy
296 o->recv.data_busy = 1;
297 }
298  
299 static void send_job_handler (BDatagram *o)
300 {
301 DebugObject_Access(&o->d_obj);
302 DebugError_AssertNoError(&o->d_err);
303 ASSERT(!o->aborted)
304 ASSERT(o->send.inited)
305 ASSERT(o->send.data_len >= 0)
306 ASSERT(!o->send.data_busy)
307 ASSERT(o->send.have_addrs)
308  
309 // send
310 start_send(o);
311 return;
312 }
313  
314 static void recv_job_handler (BDatagram *o)
315 {
316 DebugObject_Access(&o->d_obj);
317 DebugError_AssertNoError(&o->d_err);
318 ASSERT(!o->aborted)
319 ASSERT(o->recv.inited)
320 ASSERT(o->recv.data_have)
321 ASSERT(!o->recv.data_busy)
322 ASSERT(o->recv.started)
323  
324 // recv
325 start_recv(o);
326 return;
327 }
328  
329 static void send_if_handler_send (BDatagram *o, uint8_t *data, int data_len)
330 {
331 DebugObject_Access(&o->d_obj);
332 DebugError_AssertNoError(&o->d_err);
333 ASSERT(!o->aborted)
334 ASSERT(o->send.inited)
335 ASSERT(o->send.data_len == -1)
336 ASSERT(data_len >= 0)
337 ASSERT(data_len <= o->send.mtu)
338  
339 // remember data
340 o->send.data = data;
341 o->send.data_len = data_len;
342 o->send.data_busy = 0;
343  
344 // if have no addresses, wait
345 if (!o->send.have_addrs) {
346 return;
347 }
348  
349 // send
350 start_send(o);
351 return;
352 }
353  
354 static void recv_if_handler_recv (BDatagram *o, uint8_t *data)
355 {
356 DebugObject_Access(&o->d_obj);
357 DebugError_AssertNoError(&o->d_err);
358 ASSERT(!o->aborted)
359 ASSERT(o->recv.inited)
360 ASSERT(!o->recv.data_have)
361  
362 // remember data
363 o->recv.data = data;
364 o->recv.data_have = 1;
365 o->recv.data_busy = 0;
366  
367 // if recv not started yet, wait
368 if (!o->recv.started) {
369 return;
370 }
371  
372 // recv
373 start_recv(o);
374 return;
375 }
376  
377 static void send_olap_handler (BDatagram *o, int event, DWORD bytes)
378 {
379 DebugObject_Access(&o->d_obj);
380 DebugError_AssertNoError(&o->d_err);
381 ASSERT(!o->aborted)
382 ASSERT(o->send.inited)
383 ASSERT(o->send.data_len >= 0)
384 ASSERT(o->send.data_busy)
385 ASSERT(event == BREACTOR_IOCP_EVENT_SUCCEEDED || event == BREACTOR_IOCP_EVENT_FAILED)
386  
387 // set not busy
388 o->send.data_busy = 0;
389  
390 if (event == BREACTOR_IOCP_EVENT_FAILED) {
391 report_error(o);
392 return;
393 }
394  
395 ASSERT(bytes >= 0)
396 ASSERT(bytes <= o->send.data_len)
397  
398 if (bytes < o->send.data_len) {
399 BLog(BLOG_ERROR, "sent too little");
400 }
401  
402 // if recv wasn't started yet, start it
403 if (!o->recv.started) {
404 // set recv started
405 o->recv.started = 1;
406  
407 // continue receiving
408 if (o->recv.inited && o->recv.data_have) {
409 ASSERT(!o->recv.data_busy)
410  
411 BPending_Set(&o->recv.job);
412 }
413 }
414  
415 // set no data
416 o->send.data_len = -1;
417  
418 // done
419 PacketPassInterface_Done(&o->send.iface);
420 }
421  
422 static void recv_olap_handler (BDatagram *o, int event, DWORD bytes)
423 {
424 DebugObject_Access(&o->d_obj);
425 DebugError_AssertNoError(&o->d_err);
426 ASSERT(!o->aborted)
427 ASSERT(o->recv.inited)
428 ASSERT(o->recv.data_have)
429 ASSERT(o->recv.data_busy)
430 ASSERT(event == BREACTOR_IOCP_EVENT_SUCCEEDED || event == BREACTOR_IOCP_EVENT_FAILED)
431  
432 // set not busy
433 o->recv.data_busy = 0;
434  
435 if (event == BREACTOR_IOCP_EVENT_FAILED) {
436 BLog(BLOG_ERROR, "receiving failed");
437 report_error(o);
438 return;
439 }
440  
441 ASSERT(bytes >= 0)
442 ASSERT(bytes <= o->recv.mtu)
443  
444 if (o->fnWSARecvMsg) {
445 o->recv.sysaddr.len = o->recv.msg.namelen;
446 }
447  
448 // read remote address
449 addr_sys_to_socket(&o->recv.remote_addr, o->recv.sysaddr);
450  
451 // read local address
452 BIPAddr_InitInvalid(&o->recv.local_addr);
453 if (o->fnWSARecvMsg) {
454 for (WSACMSGHDR *cmsg = WSA_CMSG_FIRSTHDR(&o->recv.msg); cmsg; cmsg = WSA_CMSG_NXTHDR(&o->recv.msg, cmsg)) {
455 if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
456 struct in_pktinfo *pktinfo = (struct in_pktinfo *)WSA_CMSG_DATA(cmsg);
457 BIPAddr_InitIPv4(&o->recv.local_addr, pktinfo->ipi_addr.s_addr);
458 }
459 else if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
460 struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)WSA_CMSG_DATA(cmsg);
461 BIPAddr_InitIPv6(&o->recv.local_addr, pktinfo->ipi6_addr.s6_addr);
462 }
463 }
464 }
465  
466 // set have addresses
467 o->recv.have_addrs = 1;
468  
469 // set no data
470 o->recv.data_have = 0;
471  
472 // done
473 PacketRecvInterface_Done(&o->recv.iface, bytes);
474 }
475  
476 int BDatagram_AddressFamilySupported (int family)
477 {
478 return (family == BADDR_TYPE_IPV4 || family == BADDR_TYPE_IPV6);
479 }
480  
481 int BDatagram_Init (BDatagram *o, int family, BReactor *reactor, void *user,
482 BDatagram_handler handler)
483 {
484 ASSERT(BDatagram_AddressFamilySupported(family))
485 ASSERT(handler)
486 BNetwork_Assert();
487  
488 // init arguments
489 o->reactor = reactor;
490 o->user = user;
491 o->handler = handler;
492  
493 // init socket
494 if ((o->sock = WSASocket(family_socket_to_sys(family), SOCK_DGRAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET) {
495 BLog(BLOG_ERROR, "WSASocket failed");
496 goto fail0;
497 }
498  
499 DWORD out_bytes;
500  
501 // obtain WSASendMsg
502 GUID guid1 = WSAID_WSASENDMSG;
503 if (WSAIoctl(o->sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid1, sizeof(guid1), &o->fnWSASendMsg, sizeof(o->fnWSASendMsg), &out_bytes, NULL, NULL) != 0) {
504 o->fnWSASendMsg = NULL;
505 }
506  
507 // obtain WSARecvMsg
508 GUID guid2 = WSAID_WSARECVMSG;
509 if (WSAIoctl(o->sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid2, sizeof(guid2), &o->fnWSARecvMsg, sizeof(o->fnWSARecvMsg), &out_bytes, NULL, NULL) != 0) {
510 BLog(BLOG_ERROR, "failed to obtain WSARecvMsg");
511 o->fnWSARecvMsg = NULL;
512 }
513  
514 // associate with IOCP
515 if (!CreateIoCompletionPort((HANDLE)o->sock, BReactor_GetIOCPHandle(o->reactor), 0, 0)) {
516 BLog(BLOG_ERROR, "CreateIoCompletionPort failed");
517 goto fail1;
518 }
519  
520 // enable receiving pktinfo
521 set_pktinfo(o->sock, family);
522  
523 // set not aborted
524 o->aborted = 0;
525  
526 // init send olap
527 BReactorIOCPOverlapped_Init(&o->send.olap, o->reactor, o, (BReactorIOCPOverlapped_handler)send_olap_handler);
528  
529 // set have no send addrs
530 o->send.have_addrs = 0;
531  
532 // set send not inited
533 o->send.inited = 0;
534  
535 // init recv olap
536 BReactorIOCPOverlapped_Init(&o->recv.olap, o->reactor, o, (BReactorIOCPOverlapped_handler)recv_olap_handler);
537  
538 // set recv not started
539 o->recv.started = 0;
540  
541 // set have no recv addrs
542 o->recv.have_addrs = 0;
543  
544 // set recv not inited
545 o->recv.inited = 0;
546  
547 DebugError_Init(&o->d_err, BReactor_PendingGroup(o->reactor));
548 DebugObject_Init(&o->d_obj);
549 return 1;
550  
551 fail1:
552 if (closesocket(o->sock) == SOCKET_ERROR) {
553 BLog(BLOG_ERROR, "closesocket failed");
554 }
555 fail0:
556 return 0;
557 }
558  
559 void BDatagram_Free (BDatagram *o)
560 {
561 DebugObject_Free(&o->d_obj);
562 DebugError_Free(&o->d_err);
563 ASSERT(!o->recv.inited)
564 ASSERT(!o->send.inited)
565  
566 if (!o->aborted) {
567 datagram_abort(o);
568 }
569 }
570  
571 int BDatagram_Bind (BDatagram *o, BAddr addr)
572 {
573 DebugObject_Access(&o->d_obj);
574 DebugError_AssertNoError(&o->d_err);
575 ASSERT(!o->aborted)
576 ASSERT(BDatagram_AddressFamilySupported(addr.type))
577  
578 // translate address
579 struct BDatagram_sys_addr sysaddr;
580 addr_socket_to_sys(&sysaddr, addr);
581  
582 // bind
583 if (bind(o->sock, &sysaddr.addr.generic, sysaddr.len) < 0) {
584 BLog(BLOG_ERROR, "bind failed");
585 return 0;
586 }
587  
588 // if recv wasn't started yet, start it
589 if (!o->recv.started) {
590 // set recv started
591 o->recv.started = 1;
592  
593 // continue receiving
594 if (o->recv.inited && o->recv.data_have) {
595 ASSERT(!o->recv.data_busy)
596  
597 BPending_Set(&o->recv.job);
598 }
599 }
600  
601 return 1;
602 }
603  
604 void BDatagram_SetSendAddrs (BDatagram *o, BAddr remote_addr, BIPAddr local_addr)
605 {
606 DebugObject_Access(&o->d_obj);
607 DebugError_AssertNoError(&o->d_err);
608 ASSERT(!o->aborted)
609 ASSERT(BDatagram_AddressFamilySupported(remote_addr.type))
610 ASSERT(local_addr.type == BADDR_TYPE_NONE || BDatagram_AddressFamilySupported(local_addr.type))
611  
612 // set addresses
613 o->send.remote_addr = remote_addr;
614 o->send.local_addr = local_addr;
615  
616 // set have addresses
617 o->send.have_addrs = 1;
618  
619 // start sending
620 if (o->send.inited && o->send.data_len >= 0 && !o->send.data_busy) {
621 BPending_Set(&o->send.job);
622 }
623 }
624  
625 int BDatagram_GetLastReceiveAddrs (BDatagram *o, BAddr *remote_addr, BIPAddr *local_addr)
626 {
627 DebugObject_Access(&o->d_obj);
628  
629 if (!o->recv.have_addrs) {
630 return 0;
631 }
632  
633 *remote_addr = o->recv.remote_addr;
634 *local_addr = o->recv.local_addr;
635 return 1;
636 }
637  
638 int BDatagram_GetLocalAddr (BDatagram *o, BAddr *local_addr)
639 {
640 DebugObject_Access(&o->d_obj);
641  
642 struct BDatagram_sys_addr sysaddr;
643 socklen_t addr_size = sizeof(sysaddr.addr.generic);
644 if (getsockname(o->sock, &sysaddr.addr.generic, &addr_size) != 0) {
645 BLog(BLOG_ERROR, "BDatagram_GetLocalAddr: getsockname failed");
646 return 0;
647 }
648 sysaddr.len = addr_size;
649  
650 BAddr addr;
651 addr_sys_to_socket(&addr, sysaddr);
652  
653 if (addr.type == BADDR_TYPE_NONE) {
654 BLog(BLOG_ERROR, "BDatagram_GetLocalAddr: Unsupported address family "
655 "from getsockname: %d", sysaddr.addr.generic.sa_family);
656 return 0;
657 }
658  
659 *local_addr = addr;
660 return 1;
661 }
662  
663 int BDatagram_SetReuseAddr (BDatagram *o, int reuse)
664 {
665 DebugObject_Access(&o->d_obj);
666 ASSERT(reuse == 0 || reuse == 1)
667  
668 if (setsockopt(o->sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0) {
669 return 0;
670 }
671  
672 return 1;
673 }
674  
675 void BDatagram_SendAsync_Init (BDatagram *o, int mtu)
676 {
677 DebugObject_Access(&o->d_obj);
678 DebugError_AssertNoError(&o->d_err);
679 ASSERT(!o->aborted)
680 ASSERT(!o->send.inited)
681 ASSERT(mtu >= 0)
682  
683 // init arguments
684 o->send.mtu = mtu;
685  
686 // init interface
687 PacketPassInterface_Init(&o->send.iface, o->send.mtu, (PacketPassInterface_handler_send)send_if_handler_send, o, BReactor_PendingGroup(o->reactor));
688  
689 // init job
690 BPending_Init(&o->send.job, BReactor_PendingGroup(o->reactor), (BPending_handler)send_job_handler, o);
691  
692 // set have no data
693 o->send.data_len = -1;
694  
695 // set inited
696 o->send.inited = 1;
697 }
698  
699 void BDatagram_SendAsync_Free (BDatagram *o)
700 {
701 DebugObject_Access(&o->d_obj);
702 ASSERT(o->send.inited)
703  
704 // abort if busy
705 if (o->send.data_len >= 0 && o->send.data_busy && !o->aborted) {
706 datagram_abort(o);
707 }
708  
709 // free job
710 BPending_Free(&o->send.job);
711  
712 // free interface
713 PacketPassInterface_Free(&o->send.iface);
714  
715 // set not inited
716 o->send.inited = 0;
717 }
718  
719 PacketPassInterface * BDatagram_SendAsync_GetIf (BDatagram *o)
720 {
721 DebugObject_Access(&o->d_obj);
722 ASSERT(o->send.inited)
723  
724 return &o->send.iface;
725 }
726  
727 void BDatagram_RecvAsync_Init (BDatagram *o, int mtu)
728 {
729 DebugObject_Access(&o->d_obj);
730 DebugError_AssertNoError(&o->d_err);
731 ASSERT(!o->aborted)
732 ASSERT(!o->recv.inited)
733 ASSERT(mtu >= 0)
734  
735 // init arguments
736 o->recv.mtu = mtu;
737  
738 // init interface
739 PacketRecvInterface_Init(&o->recv.iface, o->recv.mtu, (PacketRecvInterface_handler_recv)recv_if_handler_recv, o, BReactor_PendingGroup(o->reactor));
740  
741 // init job
742 BPending_Init(&o->recv.job, BReactor_PendingGroup(o->reactor), (BPending_handler)recv_job_handler, o);
743  
744 // set have no data
745 o->recv.data_have = 0;
746  
747 // set inited
748 o->recv.inited = 1;
749 }
750  
751 void BDatagram_RecvAsync_Free (BDatagram *o)
752 {
753 DebugObject_Access(&o->d_obj);
754 ASSERT(o->recv.inited)
755  
756 // abort if busy
757 if (o->recv.data_have && o->recv.data_busy && !o->aborted) {
758 datagram_abort(o);
759 }
760  
761 // free job
762 BPending_Free(&o->recv.job);
763  
764 // free interface
765 PacketRecvInterface_Free(&o->recv.iface);
766  
767 // set not inited
768 o->recv.inited = 0;
769 }
770  
771 PacketRecvInterface * BDatagram_RecvAsync_GetIf (BDatagram *o)
772 {
773 DebugObject_Access(&o->d_obj);
774 ASSERT(o->recv.inited)
775  
776 return &o->recv.iface;
777 }