BadVPN – Blame information for rev 1
?pathlinks?
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 | } |