BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file BConnection_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 #include <string.h>
31 #include <stddef.h>
32 #include <unistd.h>
33 #include <errno.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/un.h>
37  
38 #include <misc/nonblocking.h>
39 #include <misc/strdup.h>
40 #include <base/BLog.h>
41  
42 #include "BConnection.h"
43  
44 #include <generated/blog_channel_BConnection.h>
45  
46 #define MAX_UNIX_SOCKET_PATH 200
47  
48 #define SEND_STATE_NOT_INITED 0
49 #define SEND_STATE_READY 1
50 #define SEND_STATE_BUSY 2
51  
52 #define RECV_STATE_NOT_INITED 0
53 #define RECV_STATE_READY 1
54 #define RECV_STATE_BUSY 2
55 #define RECV_STATE_INITED_CLOSED 3
56 #define RECV_STATE_NOT_INITED_CLOSED 4
57  
58 struct sys_addr {
59 socklen_t len;
60 union {
61 struct sockaddr generic;
62 struct sockaddr_in ipv4;
63 struct sockaddr_in6 ipv6;
64 } addr;
65 };
66  
67 struct unix_addr {
68 socklen_t len;
69 union {
70 struct sockaddr_un addr;
71 uint8_t bytes[offsetof(struct sockaddr_un, sun_path) + MAX_UNIX_SOCKET_PATH + 1];
72 } u;
73 };
74  
75 static int build_unix_address (struct unix_addr *out, const char *socket_path);
76 static void addr_socket_to_sys (struct sys_addr *out, BAddr addr);
77 static void addr_sys_to_socket (BAddr *out, struct sys_addr addr);
78 static void listener_fd_handler (BListener *o, int events);
79 static void listener_default_job_handler (BListener *o);
80 static void connector_fd_handler (BConnector *o, int events);
81 static void connector_job_handler (BConnector *o);
82 static void connection_report_error (BConnection *o);
83 static void connection_send (BConnection *o);
84 static void connection_recv (BConnection *o);
85 static void connection_fd_handler (BConnection *o, int events);
86 static void connection_send_job_handler (BConnection *o);
87 static void connection_recv_job_handler (BConnection *o);
88 static void connection_send_if_handler_send (BConnection *o, uint8_t *data, int data_len);
89 static void connection_recv_if_handler_recv (BConnection *o, uint8_t *data, int data_len);
90  
91 static int build_unix_address (struct unix_addr *out, const char *socket_path)
92 {
93 ASSERT(socket_path);
94  
95 if (strlen(socket_path) > MAX_UNIX_SOCKET_PATH) {
96 return 0;
97 }
98  
99 out->len = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path) + 1;
100 out->u.addr.sun_family = AF_UNIX;
101 strcpy(out->u.addr.sun_path, socket_path);
102  
103 return 1;
104 }
105  
106 static void addr_socket_to_sys (struct sys_addr *out, BAddr addr)
107 {
108 switch (addr.type) {
109 case BADDR_TYPE_IPV4: {
110 out->len = sizeof(out->addr.ipv4);
111 memset(&out->addr.ipv4, 0, sizeof(out->addr.ipv4));
112 out->addr.ipv4.sin_family = AF_INET;
113 out->addr.ipv4.sin_port = addr.ipv4.port;
114 out->addr.ipv4.sin_addr.s_addr = addr.ipv4.ip;
115 } break;
116  
117 case BADDR_TYPE_IPV6: {
118 out->len = sizeof(out->addr.ipv6);
119 memset(&out->addr.ipv6, 0, sizeof(out->addr.ipv6));
120 out->addr.ipv6.sin6_family = AF_INET6;
121 out->addr.ipv6.sin6_port = addr.ipv6.port;
122 out->addr.ipv6.sin6_flowinfo = 0;
123 memcpy(out->addr.ipv6.sin6_addr.s6_addr, addr.ipv6.ip, 16);
124 out->addr.ipv6.sin6_scope_id = 0;
125 } break;
126  
127 default: ASSERT(0);
128 }
129 }
130  
131 static void addr_sys_to_socket (BAddr *out, struct sys_addr addr)
132 {
133 switch (addr.addr.generic.sa_family) {
134 case AF_INET: {
135 ASSERT(addr.len == sizeof(struct sockaddr_in))
136 BAddr_InitIPv4(out, addr.addr.ipv4.sin_addr.s_addr, addr.addr.ipv4.sin_port);
137 } break;
138  
139 case AF_INET6: {
140 ASSERT(addr.len == sizeof(struct sockaddr_in6))
141 BAddr_InitIPv6(out, addr.addr.ipv6.sin6_addr.s6_addr, addr.addr.ipv6.sin6_port);
142 } break;
143  
144 default: {
145 BAddr_InitNone(out);
146 } break;
147 }
148 }
149  
150 static void listener_fd_handler (BListener *o, int events)
151 {
152 DebugObject_Access(&o->d_obj);
153  
154 // set default job
155 BPending_Set(&o->default_job);
156  
157 // call handler
158 o->handler(o->user);
159 return;
160 }
161  
162 static void listener_default_job_handler (BListener *o)
163 {
164 DebugObject_Access(&o->d_obj);
165  
166 BLog(BLOG_ERROR, "discarding connection");
167  
168 // accept
169 int newfd = accept(o->fd, NULL, NULL);
170 if (newfd < 0) {
171 BLog(BLOG_ERROR, "accept failed");
172 return;
173 }
174  
175 // close new fd
176 if (close(newfd) < 0) {
177 BLog(BLOG_ERROR, "close failed");
178 }
179 }
180  
181 static void connector_fd_handler (BConnector *o, int events)
182 {
183 DebugObject_Access(&o->d_obj);
184 ASSERT(o->fd >= 0)
185 ASSERT(!o->connected)
186 ASSERT(o->have_bfd)
187  
188 // free BFileDescriptor
189 BReactor_RemoveFileDescriptor(o->reactor, &o->bfd);
190  
191 // set have no BFileDescriptor
192 o->have_bfd = 0;
193  
194 // read connection result
195 int result;
196 socklen_t result_len = sizeof(result);
197 if (getsockopt(o->fd, SOL_SOCKET, SO_ERROR, &result, &result_len) < 0) {
198 BLog(BLOG_ERROR, "getsockopt failed");
199 goto fail0;
200 }
201 ASSERT_FORCE(result_len == sizeof(result))
202  
203 if (result != 0) {
204 BLog(BLOG_ERROR, "connection failed");
205 goto fail0;
206 }
207  
208 // set connected
209 o->connected = 1;
210  
211 fail0:
212 // call handler
213 o->handler(o->user, !o->connected);
214 return;
215 }
216  
217 static void connector_job_handler (BConnector *o)
218 {
219 DebugObject_Access(&o->d_obj);
220 ASSERT(o->fd >= 0)
221 ASSERT(o->connected)
222 ASSERT(!o->have_bfd)
223  
224 // call handler
225 o->handler(o->user, 0);
226 return;
227 }
228  
229 static void connection_report_error (BConnection *o)
230 {
231 DebugError_AssertNoError(&o->d_err);
232 ASSERT(o->handler)
233  
234 // report error
235 DEBUGERROR(&o->d_err, o->handler(o->user, BCONNECTION_EVENT_ERROR));
236 return;
237 }
238  
239 static void connection_send (BConnection *o)
240 {
241 DebugError_AssertNoError(&o->d_err);
242 ASSERT(o->send.state == SEND_STATE_BUSY)
243  
244 // limit
245 if (!o->is_hupd) {
246 if (!BReactorLimit_Increment(&o->send.limit)) {
247 // wait for fd
248 o->wait_events |= BREACTOR_WRITE;
249 BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events);
250 return;
251 }
252 }
253  
254 // send
255 int bytes = write(o->fd, o->send.busy_data, o->send.busy_data_len);
256 if (bytes < 0) {
257 if (!o->is_hupd && (errno == EAGAIN || errno == EWOULDBLOCK)) {
258 // wait for fd
259 o->wait_events |= BREACTOR_WRITE;
260 BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events);
261 return;
262 }
263  
264 BLog(BLOG_ERROR, "send failed");
265 connection_report_error(o);
266 return;
267 }
268  
269 ASSERT(bytes > 0)
270 ASSERT(bytes <= o->send.busy_data_len)
271  
272 // set ready
273 o->send.state = SEND_STATE_READY;
274  
275 // done
276 StreamPassInterface_Done(&o->send.iface, bytes);
277 }
278  
279 static void connection_recv (BConnection *o)
280 {
281 DebugError_AssertNoError(&o->d_err);
282 ASSERT(o->recv.state == RECV_STATE_BUSY)
283  
284 // limit
285 if (!o->is_hupd) {
286 if (!BReactorLimit_Increment(&o->recv.limit)) {
287 // wait for fd
288 o->wait_events |= BREACTOR_READ;
289 BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events);
290 return;
291 }
292 }
293  
294 // recv
295 int bytes = read(o->fd, o->recv.busy_data, o->recv.busy_data_avail);
296 if (bytes < 0) {
297 if (!o->is_hupd && (errno == EAGAIN || errno == EWOULDBLOCK)) {
298 // wait for fd
299 o->wait_events |= BREACTOR_READ;
300 BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events);
301 return;
302 }
303  
304 BLog(BLOG_ERROR, "recv failed");
305 connection_report_error(o);
306 return;
307 }
308  
309 if (bytes == 0) {
310 // set recv inited closed
311 o->recv.state = RECV_STATE_INITED_CLOSED;
312  
313 // report recv closed
314 o->handler(o->user, BCONNECTION_EVENT_RECVCLOSED);
315 return;
316 }
317  
318 ASSERT(bytes > 0)
319 ASSERT(bytes <= o->recv.busy_data_avail)
320  
321 // set not busy
322 o->recv.state = RECV_STATE_READY;
323  
324 // done
325 StreamRecvInterface_Done(&o->recv.iface, bytes);
326 }
327  
328 static void connection_fd_handler (BConnection *o, int events)
329 {
330 DebugObject_Access(&o->d_obj);
331 DebugError_AssertNoError(&o->d_err);
332 ASSERT(!o->is_hupd)
333  
334 // clear handled events
335 o->wait_events &= ~events;
336 BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events);
337  
338 int have_send = 0;
339 int have_recv = 0;
340  
341 // if we got a HUP event, stop monitoring the file descriptor
342 if ((events & BREACTOR_HUP)) {
343 BReactor_RemoveFileDescriptor(o->reactor, &o->bfd);
344 o->is_hupd = 1;
345 }
346  
347 if ((events & BREACTOR_WRITE) || ((events & (BREACTOR_ERROR|BREACTOR_HUP)) && o->send.state == SEND_STATE_BUSY)) {
348 ASSERT(o->send.state == SEND_STATE_BUSY)
349 have_send = 1;
350 }
351  
352 if ((events & BREACTOR_READ) || ((events & (BREACTOR_ERROR|BREACTOR_HUP)) && o->recv.state == RECV_STATE_BUSY)) {
353 ASSERT(o->recv.state == RECV_STATE_BUSY)
354 have_recv = 1;
355 }
356  
357 if (have_send) {
358 if (have_recv) {
359 BPending_Set(&o->recv.job);
360 }
361  
362 connection_send(o);
363 return;
364 }
365  
366 if (have_recv) {
367 connection_recv(o);
368 return;
369 }
370  
371 if (!o->is_hupd) {
372 BLog(BLOG_ERROR, "fd error event");
373 connection_report_error(o);
374 return;
375 }
376 }
377  
378 static void connection_send_job_handler (BConnection *o)
379 {
380 DebugObject_Access(&o->d_obj);
381 DebugError_AssertNoError(&o->d_err);
382 ASSERT(o->send.state == SEND_STATE_BUSY)
383  
384 connection_send(o);
385 return;
386 }
387  
388 static void connection_recv_job_handler (BConnection *o)
389 {
390 DebugObject_Access(&o->d_obj);
391 DebugError_AssertNoError(&o->d_err);
392 ASSERT(o->recv.state == RECV_STATE_BUSY)
393  
394 connection_recv(o);
395 return;
396 }
397  
398 static void connection_send_if_handler_send (BConnection *o, uint8_t *data, int data_len)
399 {
400 DebugObject_Access(&o->d_obj);
401 DebugError_AssertNoError(&o->d_err);
402 ASSERT(o->send.state == SEND_STATE_READY)
403 ASSERT(data_len > 0)
404  
405 // remember data
406 o->send.busy_data = data;
407 o->send.busy_data_len = data_len;
408  
409 // set busy
410 o->send.state = SEND_STATE_BUSY;
411  
412 connection_send(o);
413 return;
414 }
415  
416 static void connection_recv_if_handler_recv (BConnection *o, uint8_t *data, int data_avail)
417 {
418 DebugObject_Access(&o->d_obj);
419 DebugError_AssertNoError(&o->d_err);
420 ASSERT(o->recv.state == RECV_STATE_READY)
421 ASSERT(data_avail > 0)
422  
423 // remember data
424 o->recv.busy_data = data;
425 o->recv.busy_data_avail = data_avail;
426  
427 // set busy
428 o->recv.state = RECV_STATE_BUSY;
429  
430 connection_recv(o);
431 return;
432 }
433  
434 int BConnection_AddressSupported (BAddr addr)
435 {
436 BAddr_Assert(&addr);
437  
438 return (addr.type == BADDR_TYPE_IPV4 || addr.type == BADDR_TYPE_IPV6);
439 }
440  
441 int BListener_InitFrom (BListener *o, struct BLisCon_from from,
442 BReactor *reactor, void *user,
443 BListener_handler handler)
444 {
445 ASSERT(from.type == BLISCON_FROM_ADDR || from.type == BLISCON_FROM_UNIX)
446 ASSERT(from.type != BLISCON_FROM_UNIX || from.u.from_unix.socket_path)
447 ASSERT(handler)
448 BNetwork_Assert();
449  
450 // init arguments
451 o->reactor = reactor;
452 o->user = user;
453 o->handler = handler;
454  
455 // init socket path
456 o->unix_socket_path = NULL;
457 if (from.type == BLISCON_FROM_UNIX) {
458 o->unix_socket_path = b_strdup(from.u.from_unix.socket_path);
459 if (!o->unix_socket_path) {
460 BLog(BLOG_ERROR, "b_strdup failed");
461 goto fail0;
462 }
463 }
464  
465 struct unix_addr unixaddr;
466 struct sys_addr sysaddr;
467  
468 if (from.type == BLISCON_FROM_UNIX) {
469 // build address
470 if (!build_unix_address(&unixaddr, o->unix_socket_path)) {
471 BLog(BLOG_ERROR, "build_unix_address failed");
472 goto fail1;
473 }
474  
475 // init fd
476 if ((o->fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
477 BLog(BLOG_ERROR, "socket failed");
478 goto fail1;
479 }
480 } else {
481 // check address
482 if (!BConnection_AddressSupported(from.u.from_addr.addr)) {
483 BLog(BLOG_ERROR, "address not supported");
484 goto fail1;
485 }
486  
487 // convert address
488 addr_socket_to_sys(&sysaddr, from.u.from_addr.addr);
489  
490 // init fd
491 if ((o->fd = socket(sysaddr.addr.generic.sa_family, SOCK_STREAM, 0)) < 0) {
492 BLog(BLOG_ERROR, "socket failed");
493 goto fail1;
494 }
495 }
496  
497 // set non-blocking
498 if (!badvpn_set_nonblocking(o->fd)) {
499 BLog(BLOG_ERROR, "badvpn_set_nonblocking failed");
500 goto fail2;
501 }
502  
503 if (from.type == BLISCON_FROM_UNIX) {
504 // unlink existing socket
505 if (unlink(o->unix_socket_path) < 0 && errno != ENOENT) {
506 BLog(BLOG_ERROR, "unlink existing socket failed");
507 goto fail2;
508 }
509  
510 // bind
511 if (bind(o->fd, (struct sockaddr *)&unixaddr.u.addr, unixaddr.len) < 0) {
512 BLog(BLOG_ERROR, "bind failed");
513 goto fail2;
514 }
515 } else {
516 // set SO_REUSEADDR
517 int optval = 1;
518 if (setsockopt(o->fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) {
519 BLog(BLOG_ERROR, "setsockopt(SO_REUSEADDR) failed");
520 }
521  
522 // bind
523 if (bind(o->fd, &sysaddr.addr.generic, sysaddr.len) < 0) {
524 BLog(BLOG_ERROR, "bind failed");
525 goto fail2;
526 }
527 }
528  
529 // listen
530 if (listen(o->fd, BCONNECTION_LISTEN_BACKLOG) < 0) {
531 BLog(BLOG_ERROR, "listen failed");
532 goto fail3;
533 }
534  
535 // init BFileDescriptor
536 BFileDescriptor_Init(&o->bfd, o->fd, (BFileDescriptor_handler)listener_fd_handler, o);
537 if (!BReactor_AddFileDescriptor(o->reactor, &o->bfd)) {
538 BLog(BLOG_ERROR, "BReactor_AddFileDescriptor failed");
539 goto fail3;
540 }
541 BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, BREACTOR_READ);
542  
543 // init default job
544 BPending_Init(&o->default_job, BReactor_PendingGroup(o->reactor), (BPending_handler)listener_default_job_handler, o);
545  
546 DebugObject_Init(&o->d_obj);
547 return 1;
548  
549 fail3:
550 if (from.type == BLISCON_FROM_UNIX) {
551 if (unlink(o->unix_socket_path) < 0) {
552 BLog(BLOG_ERROR, "unlink socket failed");
553 }
554 }
555 fail2:
556 if (close(o->fd) < 0) {
557 BLog(BLOG_ERROR, "close failed");
558 }
559 fail1:
560 free(o->unix_socket_path);
561 fail0:
562 return 0;
563 }
564  
565 void BListener_Free (BListener *o)
566 {
567 DebugObject_Free(&o->d_obj);
568  
569 // free default job
570 BPending_Free(&o->default_job);
571  
572 // free BFileDescriptor
573 BReactor_RemoveFileDescriptor(o->reactor, &o->bfd);
574  
575 // free fd
576 if (close(o->fd) < 0) {
577 BLog(BLOG_ERROR, "close failed");
578 }
579  
580 // unlink unix socket
581 if (o->unix_socket_path) {
582 if (unlink(o->unix_socket_path) < 0) {
583 BLog(BLOG_ERROR, "unlink socket failed");
584 }
585 }
586  
587 // free unix socket path
588 if (o->unix_socket_path) {
589 free(o->unix_socket_path);
590 }
591 }
592  
593 int BConnector_InitFrom (BConnector *o, struct BLisCon_from from, BReactor *reactor, void *user,
594 BConnector_handler handler)
595 {
596 ASSERT(from.type == BLISCON_FROM_ADDR || from.type == BLISCON_FROM_UNIX)
597 ASSERT(from.type != BLISCON_FROM_UNIX || from.u.from_unix.socket_path)
598 ASSERT(handler)
599 BNetwork_Assert();
600  
601 // init arguments
602 o->reactor = reactor;
603 o->user = user;
604 o->handler = handler;
605  
606 struct unix_addr unixaddr;
607 struct sys_addr sysaddr;
608  
609 if (from.type == BLISCON_FROM_UNIX) {
610 // build address
611 if (!build_unix_address(&unixaddr, from.u.from_unix.socket_path)) {
612 BLog(BLOG_ERROR, "build_unix_address failed");
613 goto fail0;
614 }
615 } else {
616 // check address
617 if (!BConnection_AddressSupported(from.u.from_addr.addr)) {
618 BLog(BLOG_ERROR, "address not supported");
619 goto fail0;
620 }
621  
622 // convert address
623 addr_socket_to_sys(&sysaddr, from.u.from_addr.addr);
624 }
625  
626 // init job
627 BPending_Init(&o->job, BReactor_PendingGroup(o->reactor), (BPending_handler)connector_job_handler, o);
628  
629 if (from.type == BLISCON_FROM_UNIX) {
630 // init fd
631 if ((o->fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
632 BLog(BLOG_ERROR, "socket failed");
633 goto fail1;
634 }
635 } else {
636 // init fd
637 if ((o->fd = socket(sysaddr.addr.generic.sa_family, SOCK_STREAM, 0)) < 0) {
638 BLog(BLOG_ERROR, "socket failed");
639 goto fail1;
640 }
641 }
642  
643 // set fd non-blocking
644 if (!badvpn_set_nonblocking(o->fd)) {
645 BLog(BLOG_ERROR, "badvpn_set_nonblocking failed");
646 goto fail2;
647 }
648  
649 // connect fd
650 int connect_res;
651 if (from.type == BLISCON_FROM_UNIX) {
652 connect_res = connect(o->fd, (struct sockaddr *)&unixaddr.u.addr, unixaddr.len);
653 } else {
654 connect_res = connect(o->fd, &sysaddr.addr.generic, sysaddr.len);
655 }
656 if (connect_res < 0 && errno != EINPROGRESS) {
657 BLog(BLOG_ERROR, "connect failed");
658 goto fail2;
659 }
660  
661 // set not connected
662 o->connected = 0;
663  
664 // set have no BFileDescriptor
665 o->have_bfd = 0;
666  
667 if (connect_res < 0) {
668 // init BFileDescriptor
669 BFileDescriptor_Init(&o->bfd, o->fd, (BFileDescriptor_handler)connector_fd_handler, o);
670 if (!BReactor_AddFileDescriptor(o->reactor, &o->bfd)) {
671 BLog(BLOG_ERROR, "BReactor_AddFileDescriptor failed");
672 goto fail2;
673 }
674 BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, BREACTOR_WRITE);
675  
676 // set have BFileDescriptor
677 o->have_bfd = 1;
678 } else {
679 // set connected
680 o->connected = 1;
681  
682 // set job
683 BPending_Set(&o->job);
684 }
685  
686 DebugObject_Init(&o->d_obj);
687 return 1;
688  
689 fail2:
690 if (close(o->fd) < 0) {
691 BLog(BLOG_ERROR, "close failed");
692 }
693 fail1:
694 BPending_Free(&o->job);
695 fail0:
696 return 0;
697 }
698  
699 void BConnector_Free (BConnector *o)
700 {
701 DebugObject_Free(&o->d_obj);
702  
703 // free BFileDescriptor
704 if (o->have_bfd) {
705 BReactor_RemoveFileDescriptor(o->reactor, &o->bfd);
706 }
707  
708 // close fd
709 if (o->fd != -1) {
710 if (close(o->fd) < 0) {
711 BLog(BLOG_ERROR, "close failed");
712 }
713 }
714  
715 // free job
716 BPending_Free(&o->job);
717 }
718  
719 int BConnection_Init (BConnection *o, struct BConnection_source source, BReactor *reactor, void *user,
720 BConnection_handler handler)
721 {
722 switch (source.type) {
723 case BCONNECTION_SOURCE_TYPE_LISTENER: {
724 BListener *listener = source.u.listener.listener;
725 DebugObject_Access(&listener->d_obj);
726 ASSERT(BPending_IsSet(&listener->default_job))
727 } break;
728 case BCONNECTION_SOURCE_TYPE_CONNECTOR: {
729 BConnector *connector = source.u.connector.connector;
730 DebugObject_Access(&connector->d_obj);
731 ASSERT(connector->fd >= 0)
732 ASSERT(connector->connected)
733 ASSERT(!connector->have_bfd)
734 ASSERT(!BPending_IsSet(&connector->job))
735 } break;
736 case BCONNECTION_SOURCE_TYPE_PIPE: {
737 ASSERT(source.u.pipe.pipefd >= 0)
738 } break;
739 default: ASSERT(0);
740 }
741 ASSERT(handler)
742 BNetwork_Assert();
743  
744 // init arguments
745 o->reactor = reactor;
746 o->user = user;
747 o->handler = handler;
748  
749 switch (source.type) {
750 case BCONNECTION_SOURCE_TYPE_LISTENER: {
751 BListener *listener = source.u.listener.listener;
752  
753 // unset listener's default job
754 BPending_Unset(&listener->default_job);
755  
756 // accept
757 struct sys_addr sysaddr;
758 sysaddr.len = sizeof(sysaddr.addr);
759 if ((o->fd = accept(listener->fd, &sysaddr.addr.generic, &sysaddr.len)) < 0) {
760 BLog(BLOG_ERROR, "accept failed");
761 goto fail0;
762 }
763 o->close_fd = 1;
764  
765 // set non-blocking
766 if (!badvpn_set_nonblocking(o->fd)) {
767 BLog(BLOG_ERROR, "badvpn_set_nonblocking failed");
768 goto fail1;
769 }
770  
771 // return address
772 if (source.u.listener.out_addr) {
773 addr_sys_to_socket(source.u.listener.out_addr, sysaddr);
774 }
775 } break;
776  
777 case BCONNECTION_SOURCE_TYPE_CONNECTOR: {
778 BConnector *connector = source.u.connector.connector;
779  
780 // grab fd from connector
781 o->fd = connector->fd;
782 connector->fd = -1;
783 o->close_fd = 1;
784 } break;
785  
786 case BCONNECTION_SOURCE_TYPE_PIPE: {
787 // use user-provided fd
788 o->fd = source.u.pipe.pipefd;
789 o->close_fd = !!source.u.pipe.close_it;
790  
791 // set non-blocking
792 if (!badvpn_set_nonblocking(o->fd)) {
793 BLog(BLOG_ERROR, "badvpn_set_nonblocking failed");
794 goto fail1;
795 }
796 } break;
797 }
798  
799 // set not HUPd
800 o->is_hupd = 0;
801  
802 // init BFileDescriptor
803 BFileDescriptor_Init(&o->bfd, o->fd, (BFileDescriptor_handler)connection_fd_handler, o);
804 if (!BReactor_AddFileDescriptor(o->reactor, &o->bfd)) {
805 BLog(BLOG_ERROR, "BReactor_AddFileDescriptor failed");
806 goto fail1;
807 }
808  
809 // set no wait events
810 o->wait_events = 0;
811  
812 // init limits
813 BReactorLimit_Init(&o->send.limit, o->reactor, BCONNECTION_SEND_LIMIT);
814 BReactorLimit_Init(&o->recv.limit, o->reactor, BCONNECTION_RECV_LIMIT);
815  
816 // set send and recv not inited
817 o->send.state = SEND_STATE_NOT_INITED;
818 o->recv.state = RECV_STATE_NOT_INITED;
819  
820 DebugError_Init(&o->d_err, BReactor_PendingGroup(o->reactor));
821 DebugObject_Init(&o->d_obj);
822 return 1;
823  
824 fail1:
825 if (o->close_fd) {
826 if (close(o->fd) < 0) {
827 BLog(BLOG_ERROR, "close failed");
828 }
829 }
830 fail0:
831 return 0;
832 }
833  
834 void BConnection_Free (BConnection *o)
835 {
836 DebugObject_Free(&o->d_obj);
837 DebugError_Free(&o->d_err);
838 ASSERT(o->send.state == SEND_STATE_NOT_INITED)
839 ASSERT(o->recv.state == RECV_STATE_NOT_INITED || o->recv.state == RECV_STATE_NOT_INITED_CLOSED)
840  
841 // free limits
842 BReactorLimit_Free(&o->recv.limit);
843 BReactorLimit_Free(&o->send.limit);
844  
845 // free BFileDescriptor
846 if (!o->is_hupd) {
847 BReactor_RemoveFileDescriptor(o->reactor, &o->bfd);
848 }
849  
850 // close fd
851 if (o->close_fd) {
852 if (close(o->fd) < 0) {
853 BLog(BLOG_ERROR, "close failed");
854 }
855 }
856 }
857  
858 void BConnection_SetHandlers (BConnection *o, void *user, BConnection_handler handler)
859 {
860 DebugObject_Access(&o->d_obj);
861  
862 // set handlers
863 o->user = user;
864 o->handler = handler;
865 }
866  
867 int BConnection_SetSendBuffer (BConnection *o, int buf_size)
868 {
869 DebugObject_Access(&o->d_obj);
870  
871 if (setsockopt(o->fd, SOL_SOCKET, SO_SNDBUF, (void *)&buf_size, sizeof(buf_size)) < 0) {
872 BLog(BLOG_ERROR, "setsockopt failed");
873 return 0;
874 }
875  
876 return 1;
877 }
878  
879 int BConnection_GetLocalAddress (BConnection *o, BAddr *local_addr)
880 {
881 DebugObject_Access(&o->d_obj);
882  
883 struct sys_addr sysaddr;
884 sysaddr.len = sizeof(sysaddr.addr);
885 if (getsockname(o->fd, &sysaddr.addr.generic, &sysaddr.len) != 0) {
886 BLog(BLOG_ERROR, "BConnection_GetLocalAddress: getsockname failed");
887 return 0;
888 }
889  
890 BAddr addr;
891 addr_sys_to_socket(&addr, sysaddr);
892  
893 if (addr.type == BADDR_TYPE_NONE) {
894 BLog(BLOG_ERROR, "BConnection_GetLocalAddress: Unsupported address family "
895 "from getsockname: %d", (int)sysaddr.addr.generic.sa_family);
896 return 0;
897 }
898  
899 *local_addr = addr;
900 return 1;
901 }
902  
903 void BConnection_SendAsync_Init (BConnection *o)
904 {
905 DebugObject_Access(&o->d_obj);
906 DebugError_AssertNoError(&o->d_err);
907 ASSERT(o->send.state == SEND_STATE_NOT_INITED)
908  
909 // init interface
910 StreamPassInterface_Init(&o->send.iface, (StreamPassInterface_handler_send)connection_send_if_handler_send, o, BReactor_PendingGroup(o->reactor));
911  
912 // init job
913 BPending_Init(&o->send.job, BReactor_PendingGroup(o->reactor), (BPending_handler)connection_send_job_handler, o);
914  
915 // set ready
916 o->send.state = SEND_STATE_READY;
917 }
918  
919 void BConnection_SendAsync_Free (BConnection *o)
920 {
921 DebugObject_Access(&o->d_obj);
922 ASSERT(o->send.state == SEND_STATE_READY || o->send.state == SEND_STATE_BUSY)
923  
924 // update events
925 if (!o->is_hupd) {
926 o->wait_events &= ~BREACTOR_WRITE;
927 BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events);
928 }
929  
930 // free job
931 BPending_Free(&o->send.job);
932  
933 // free interface
934 StreamPassInterface_Free(&o->send.iface);
935  
936 // set not inited
937 o->send.state = SEND_STATE_NOT_INITED;
938 }
939  
940 StreamPassInterface * BConnection_SendAsync_GetIf (BConnection *o)
941 {
942 DebugObject_Access(&o->d_obj);
943 ASSERT(o->send.state == SEND_STATE_READY || o->send.state == SEND_STATE_BUSY)
944  
945 return &o->send.iface;
946 }
947  
948 void BConnection_RecvAsync_Init (BConnection *o)
949 {
950 DebugObject_Access(&o->d_obj);
951 DebugError_AssertNoError(&o->d_err);
952 ASSERT(o->recv.state == RECV_STATE_NOT_INITED)
953  
954 // init interface
955 StreamRecvInterface_Init(&o->recv.iface, (StreamRecvInterface_handler_recv)connection_recv_if_handler_recv, o, BReactor_PendingGroup(o->reactor));
956  
957 // init job
958 BPending_Init(&o->recv.job, BReactor_PendingGroup(o->reactor), (BPending_handler)connection_recv_job_handler, o);
959  
960 // set ready
961 o->recv.state = RECV_STATE_READY;
962 }
963  
964 void BConnection_RecvAsync_Free (BConnection *o)
965 {
966 DebugObject_Access(&o->d_obj);
967 ASSERT(o->recv.state == RECV_STATE_READY || o->recv.state == RECV_STATE_BUSY || o->recv.state == RECV_STATE_INITED_CLOSED)
968  
969 // update events
970 if (!o->is_hupd) {
971 o->wait_events &= ~BREACTOR_READ;
972 BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events);
973 }
974  
975 // free job
976 BPending_Free(&o->recv.job);
977  
978 // free interface
979 StreamRecvInterface_Free(&o->recv.iface);
980  
981 // set not inited
982 o->recv.state = RECV_STATE_NOT_INITED;
983 }
984  
985 StreamRecvInterface * BConnection_RecvAsync_GetIf (BConnection *o)
986 {
987 DebugObject_Access(&o->d_obj);
988 ASSERT(o->recv.state == RECV_STATE_READY || o->recv.state == RECV_STATE_BUSY || o->recv.state == RECV_STATE_INITED_CLOSED)
989  
990 return &o->recv.iface;
991 }