1 /* IOHandler.c - IOMultiplexer
2 * Copyright (C) 2012 Philipp Kreil (pk910)
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "IOHandler.h"
18 #include "IODNSHandler.h"
20 #include "IODNSEngine.h"
21 #include "IOHandler_SSL.h"
26 #define _WIN32_WINNT 0x501
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <netinet/tcp.h>
43 #define EWOULDBLOCK EAGAIN
47 iohandler_log_callback *iolog_backend = NULL;
49 struct IOLowlevelDescriptor *first_descriptor = NULL;
50 struct IOLowlevelDescriptor *timer_priority = NULL;
51 struct IODescriptorStartup *first_iostartup = NULL;
54 static pthread_mutex_t io_thread_sync;
55 static pthread_mutex_t io_poll_sync;
58 #define IOSTARTUP_SRCLOOKUP 0x01
59 #define IOSTARTUP_DSTLOOKUP 0x02
60 #define IOSTARTUP_LOOKUPS 0x03
62 struct IODescriptorStartup {
63 struct IODescriptor *iofd;
64 struct IODNSQuery *iodns; /* dns queries for src and dst address */
65 struct timeval timeout;
67 unsigned int flags : 6;
68 unsigned int port : 16;
69 unsigned int iptype : 8;
70 unsigned int listening : 1;
74 struct IODNSResult *srcaddr;
75 struct IODNSResult *use_srcaddr;
78 struct IODNSResult *dstaddr;
79 struct IODNSResult *use_dstaddr;
84 struct IODescriptorStartup *next, *prev;
87 void iohandler_log(enum IOLogType type, char *text, ...) {
89 char logBuf[MAXLOG+1];
92 va_start(arg_list, text);
93 pos = vsnprintf(logBuf, MAXLOG - 1, text, arg_list);
95 if (pos < 0 || pos > (MAXLOG - 1)) pos = MAXLOG - 1;
100 iolog_backend(type, logBuf);
104 extern struct IOEngine engine_select; /* select system call (should always be useable) */
105 extern struct IOEngine engine_kevent;
106 extern struct IOEngine engine_epoll;
107 extern struct IOEngine engine_win32;
109 int iohandler_settings = 0;
110 struct IOEngine *engine = NULL;
112 void iohandler_set(int setting, int value) {
114 iohandler_settings |= setting;
116 iohandler_settings &= ~setting;
119 static void iohandler_init_engine() {
121 IOTHREAD_MUTEX_INIT(io_thread_sync);
122 IOTHREAD_MUTEX_INIT(io_poll_sync);
125 if(!(iohandler_settings & IOHANDLER_SETTING_HIGH_PRECISION_TIMER)) {
126 if(!engine && engine_kevent.init && engine_kevent.init())
127 engine = &engine_kevent;
128 if(!engine && engine_epoll.init && engine_epoll.init())
129 engine = &engine_epoll;
130 if(!engine && engine_win32.init && engine_win32.init())
131 engine = &engine_win32;
135 if(engine_select.init())
136 engine = &engine_select;
138 iohandler_log(IOLOG_FATAL, "found no useable IO engine");
142 iohandler_log(IOLOG_DEBUG, "using %s IO engine", engine->name);
143 iohandler_ssl_init();
146 static void iohandler_initialize_iobuf(struct IODescriptor *iofd) {
147 if(!iofd->readbuf.buffer) {
148 iofd->readbuf.buffer = malloc(IO_READ_BUFLEN + 2);
149 iofd->readbuf.bufpos = 0;
150 iofd->readbuf.buflen = IO_READ_BUFLEN;
151 iofd->writebuf.buffer = malloc(IO_READ_BUFLEN + 2);
152 iofd->writebuf.bufpos = 0;
153 iofd->writebuf.buflen = IO_READ_BUFLEN;
157 static void iohandler_trigger_event(struct IOEvent *event) {
158 if(!event->iofd->callback) return;
159 iohandler_log(IOLOG_DEBUG, "triggering event (%s) for %s (fd: %d)", iohandler_ioeventtype_name(event->type), iohandler_iotype_name(event->iofd->type), event->iofd->fd);
160 event->iofd->callback(event);
163 static void iohandler_increase_iobuf(struct IOBuffer *iobuf, size_t required) {
164 if(iobuf->buflen >= required) return;
165 char *new_buf = realloc(iobuf->buffer, required + 2);
167 iobuf->buffer = new_buf;
168 iobuf->buflen = required;
172 static void iohandler_append_iostartup(struct IODescriptorStartup *iostartup) {
173 iostartup->prev = NULL;
174 iostartup->next = first_iostartup;
175 first_iostartup = iostartup;
178 static void iohandler_remove_iostartup(struct IODescriptorStartup *iostartup) {
180 iostartup->prev->next = iostartup->next;
182 first_iostartup = iostartup->next;
184 iostartup->next->prev = iostartup->prev;
186 iodns_abort(iostartup->iodns);
187 if(iostartup->srchost)
188 free(iostartup->srchost);
189 if(iostartup->dsthost)
190 free(iostartup->dsthost);
191 if(iostartup->srcaddr)
192 iodns_free_result(iostartup->srcaddr);
193 if(iostartup->dstaddr)
194 iodns_free_result(iostartup->dstaddr);
195 if(iostartup->iofd) {
196 if(iostartup->iofd->readbuf.buffer)
197 free(iostartup->iofd->readbuf.buffer);
198 if(iostartup->iofd->writebuf.buffer)
199 free(iostartup->iofd->writebuf.buffer);
200 free(iostartup->iofd);
205 static void iohandler_append(struct IOLowlevelDescriptor *iold) {
206 IOSYNCHRONIZE(io_thread_sync);
207 struct timeval *timeout = ((iold->timeout.tv_sec || iold->timeout.tv_usec) ? &iold->timeout : NULL);
209 struct IOLowlevelDescriptor *iold2;
210 int set_priority = 1;
212 iold2 = timer_priority;
214 iold2 = first_descriptor;
216 for(;;iold2 = iold2->next) {
217 if(timeval_is_smaler(timeout, (&iold2->timeout))) {
218 iold->prev = iold2->prev;
221 iold2->prev->next = iold;
224 timer_priority = iold;
227 if(iold2 == timer_priority)
229 if(iold2->next == NULL) {
234 timer_priority = iold;
241 first_descriptor = iold;
242 timer_priority = iold;
246 iold->next = first_descriptor;
248 first_descriptor->prev = iold;
249 first_descriptor = iold;
251 IODESYNCHRONIZE(io_thread_sync);
254 static void iohandler_remove(struct IOLowlevelDescriptor *iold) {
255 //remove IOLowlevelDescriptor from the list
256 IOSYNCHRONIZE(io_thread_sync);
258 iold->prev->next = iold->next;
260 first_descriptor = iold->next;
262 iold->next->prev = iold->prev;
263 if(iold == timer_priority)
264 timer_priority = iold->next;
266 struct IODescriptor *iofd = IOLOWLEVEL_GET_IOFD(iold);
268 if(iofd->readbuf.buffer)
269 free(iofd->readbuf.buffer);
270 if(iofd->writebuf.buffer)
271 free(iofd->writebuf.buffer);
272 iohandler_log(IOLOG_DEBUG, "removed IODescriptor (%d) of type `%s`", iold->fd, iohandler_iotype_name(iofd->type));
277 IODESYNCHRONIZE(io_thread_sync);
281 struct IODescriptor *iohandler_add_iofd(int sockfd, enum IOType type, struct timeval *timeout, iohandler_callback *callback) {
282 //just add a new IODescriptor
284 iohandler_init_engine();
290 struct IODescriptor *iofd = calloc(1, sizeof(*iofd));
292 iohandler_log(IOLOG_ERROR, "could not allocate memory for IODescriptor in %s:%d", __FILE__, __LINE__);
296 struct IOLowlevelDescriptor *iold = calloc(1, sizeof(*iofd));
298 iohandler_log(IOLOG_ERROR, "could not allocate memory for IOLowlevelDescriptor in %s:%d", __FILE__, __LINE__);
303 iold->fd = (type == IOTYPE_STDIN ? fileno(stdin) : sockfd);
304 iold->flags = IOFLAGS_HAVE_IOFD | IOFLAGS_WANT_READ;
305 iold->data.iofd = iofd;
307 iofd->fd.iold = iold;
308 iofd->flags = IOFDFLAGS_HAVE_IOLD;
310 iofd->state = (type == IOTYPE_STDIN ? IO_CONNECTED : IO_CLOSED);
311 iofd->callback = callback;
314 iold->timeout = *timeout;
315 if(iold->timeout.tv_usec > 1000000) {
316 iold->timeout.tv_usec -= 1000000;
317 iold->timeout.tv_sec++;
321 if(type != IOTYPE_TIMER)
322 iohandler_initialize_iobuf(iofd);
327 //add IOLowlevelDescriptor to the list
328 iohandler_append(iold);
330 iohandler_log(IOLOG_DEBUG, "added custom socket descriptor (%d) as type `%s`", sockfd, iohandler_iotype_name(type));
334 struct IOLowlevelDescriptor *iohandler_lowlevel_add(int fd, int want_read, int want_write, iolowlevel_callback *callback) {
338 void iohandler_lowlevel_update(struct IOLowlevelDescriptor *iolow, int want_read, int want_write) {
342 void iohandler_lowlevel_del(struct IOLowlevelDescriptor *iolow) {
346 void iohandler_set_timeout(struct IODescriptor *iofd, struct timeval *timeout) {
347 struct IOLowlevelDescriptor *iold = IODESCRIPTOR_GET_IOLD(iofd);
349 if(!timeout && !(iold->flags & IOFLAGS_HAVE_TIMEOUT))
350 return; //nothing to do
353 iold->prev->next = iold->next;
355 first_descriptor = iold->next;
357 iold->next->prev = iold->prev;
358 if(iold == timer_priority)
359 timer_priority = iold->next;
361 if(timeout && timeout->tv_sec == 0 && iofd->constant_timeout) { // autoreload timer
362 iold->timeout.tv_usec += (iofd->constant_timeout % 1000) * 1000;
363 iold->timeout.tv_sec += (iofd->constant_timeout / 1000);
364 if(iold->timeout.tv_usec > 1000000) {
365 iold->timeout.tv_sec += (iold->timeout.tv_usec / 1000000);
366 iold->timeout.tv_usec %= 1000000;
368 iold->flags |= IOFLAGS_HAVE_TIMEOUT;
369 } else if(timeout) { // normal timer
370 iold->timeout = *timeout;
371 if(iold->timeout.tv_usec > 1000000) {
372 iold->timeout.tv_usec -= 1000000;
373 iold->timeout.tv_sec++;
375 iold->flags |= IOFLAGS_HAVE_TIMEOUT;
377 iold->flags &= ~IOFLAGS_HAVE_TIMEOUT;
378 iohandler_append(iold);
380 struct IODescriptorStartup *iostartup = iofd->fd.iostartup;
383 iostartup->timeout = *timeout;
384 if(iostartup->timeout.tv_usec > 1000000) {
385 iostartup->timeout.tv_usec -= 1000000;
386 iostartup->timeout.tv_sec++;
389 iostartup->timeout.tv_sec = 0;
390 iostartup->timeout.tv_usec = 0;
395 struct IODescriptor *iohandler_timer(struct timeval timeout, iohandler_callback *callback) {
396 struct IODescriptor *descriptor;
397 descriptor = iohandler_add_iofd(-1, IOTYPE_TIMER, &timeout, callback);
399 iohandler_log(IOLOG_ERROR, "could not create IODescriptor in %s:%d", __FILE__, __LINE__);
402 iohandler_log(IOLOG_DEBUG, "added timer descriptor (sec: %d; usec: %d)", timeout.tv_sec, timeout.tv_usec);
406 struct IODescriptor *iohandler_constant_timer(int msec, iohandler_callback *callback) {
407 struct IODescriptor *descriptor;
408 struct timeval timeout;
409 gettimeofday(&timeout, NULL);
410 timeout.tv_usec += (msec % 1000) * 1000;
411 timeout.tv_sec += (msec / 1000);
412 if(timeout.tv_usec > 1000000) {
413 timeout.tv_sec += (timeout.tv_usec / 1000000);
414 timeout.tv_usec %= 1000000;
416 descriptor = iohandler_add_iofd(-1, IOTYPE_TIMER, &timeout, callback);
418 iohandler_log(IOLOG_ERROR, "could not allocate memory for IODescriptor in %s:%d", __FILE__, __LINE__);
421 descriptor->constant_timeout = msec;
422 iohandler_log(IOLOG_DEBUG, "added timer descriptor (sec: %d; usec: %d)", timeout.tv_sec, timeout.tv_usec);
426 static void iohandler_process_iostartup(struct IODescriptorStartup *iostartup) {
427 struct IODescriptor *iofd = iostartup->iofd;
428 struct IOLowlevelDescriptor *iold;
429 struct IOEvent callback_event;
430 struct sockaddr_in ip4;
431 struct sockaddr_in6 ip6;
432 int addr_family, sockfd, opt;
435 if(iostartup->use_srcaddr)
436 iostartup->iptype = iostartup->use_srcaddr->type;
437 else if(iostartup->use_dstaddr)
438 iostartup->iptype = iostartup->use_dstaddr->type;
440 addr_family = ((iostartup->iptype & IODNS_RECORD_AAAA) ? AF_INET6 : AF_INET);
442 sockfd = socket(addr_family, SOCK_STREAM, 0);
444 callback_event.type = IOEVENT_SOCKET_ERROR;
445 goto iohandler_process_iostartup_fail;
450 #if defined(SO_NOSIGPIPE)
452 setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&opt, sizeof(opt));
454 signal(SIGPIPE, SIG_IGN);
457 //make sockfd unblocking
459 opt = fcntl(sockfd, F_GETFL);
460 fcntl(sockfd, F_SETFL, opt|O_NONBLOCK);
461 opt = fcntl(sockfd, F_GETFD);
462 fcntl(sockfd, F_SETFD, opt|FD_CLOEXEC);
465 if(iostartup->listening) {
467 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof(opt));
469 if((iostartup->iptype & IODNS_RECORD_AAAA)) {
470 struct sockaddr_in6 *ip6ptr = iostartup->use_srcaddr->address;
471 ip6ptr->sin6_family = addr_family;
472 ip6ptr->sin6_port = htons(iostartup->port);
474 struct sockaddr_in *ip4ptr = iostartup->use_srcaddr->address;
475 ip4ptr->sin_family = addr_family;
476 ip4ptr->sin_port = htons(iostartup->port);
481 if(iostartup->listening || iostartup->use_srcaddr) {
482 if((iostartup->iptype & IODNS_RECORD_AAAA)) {
483 memset(&ip6, 0, sizeof(ip6));
484 if(iostartup->use_srcaddr) {
485 struct sockaddr_in6 *ip6ptr = iostartup->use_srcaddr->address;
486 ip6.sin6_addr = ip6ptr->sin6_addr;
488 inet_pton(AF_INET6, "::1", &ip6.sin6_addr);
489 ip6.sin6_family = addr_family;
490 ip6.sin6_port = htons((iostartup->listening ? iostartup->port : 0));
491 opt = bind(sockfd, (struct sockaddr*)&ip6, sizeof(ip6));
493 memset(&ip6, 0, sizeof(ip6));
494 if(iostartup->use_srcaddr) {
495 struct sockaddr_in4 *ip4ptr = iostartup->use_srcaddr->address;
496 ip6.sin6_addr = ip4ptr->sin_addr;
498 ip4.sin_addr = INADDR_ANY;
499 ip4.sin_family = addr_family;
500 ip4.sin_port = htons((iostartup->listening ? iostartup->port : 0));
501 opt = bind(sockfd, (struct sockaddr*)&ip4, sizeof(ip4));
504 callback_event.type = IOEVENT_BIND_ERROR;
505 goto iohandler_process_iostartup_fail;
509 iold = calloc(1, sizeof(*iold));
511 iold->flags = IOFLAGS_HAVE_IOFD | IOFLAGS_WANT_READ;
512 iold->data.iofd = iofd;
514 if(iostartup->listening) {
516 iofd->state = IO_LISTENING;
518 connect(sockfd, iostartup->use_dstaddr->address, iostartup->use_dstaddr->addresslen);
519 iofd->state = IO_CONNECTING;
522 iofd->fd.iold = iold;
523 iofd->flags = IOFDFLAGS_HAVE_IOLD;
525 iostartup->iofd = NULL;
526 iohandler_remove_iostartup(iostartup);
529 iohandler_process_iostartup_fail:
532 callback_event.iofd = iostartup->iofd;
533 iostartup->iofd->flags |= IOFDFLAGS_FREE_LOCK;
534 iohandler_trigger_event(&callback_event);
535 iostartup->iofd->flags &= ~IOFDFLAGS_FREE_LOCK;
536 if(iostartup->iofd->flags & IOFDFLAGS_WANT_FREE)
537 iohandler_remove_iostartup(iostartup);
539 iohandler_close(iostartup->iofd);
542 static IODNS_CALLBACK(iohandler_dns_callback) {
543 struct IODNSQuery *query = event->query;
544 struct IODescriptorStartup *iostartup = query->data;
545 int trigger_dns_fail = 0;
546 iostartup->iodns = NULL;
548 switch((iostartup->flags & IOSTARTUP_LOOKUPS)) {
549 case IOSTARTUP_SRCLOOKUP:
550 if(event->type == IODNSEVENT_FAILED) {
551 trigger_dns_fail = 1;
554 if(iostartup->dsthost) {
555 iostartup->iodns = iodns_getaddrinfo(iostartup->dsthost, iostartup->iptype, iohandler_dns_callback);
556 iostartup->flags |= IOSTARTUP_DSTLOOKUP;
557 iostartup->iodns->data = iostartup;
560 case IOSTARTUP_DSTLOOKUP:
561 if(event->type == IODNSEVENT_FAILED) {
562 trigger_dns_fail = 1;
571 if(iostartup->iptype & IODNS_RECORD_AAAA) {
572 struct IODNSResult *result;
573 if(iostartup->srcaddr) {
574 for(result = iostartup->srcaddr; result; result = result->next) {
575 if(result->type == IODNS_RECORD_AAAA) {
576 iostartup->use_srcaddr = result;
581 if(!iostartup->srcaddr || iostartup->use_srcaddr) {
582 for(result = iostartup->dstaddr; result; result = result->next) {
583 if(result->type == IODNS_RECORD_AAAA) {
584 iostartup->use_dstaddr = result;
589 if((iostartup->srcaddr && !iostartup->use_srcaddr) || (iostartup->dstaddr && !iostartup->use_dstaddr)) {
590 iostartup->use_srcaddr = NULL;
591 iostartup->use_dstaddr = NULL;
594 if((iostartup->iptype & IODNS_RECORD_A) && !(iostartup->use_dstaddr || iostartup->use_srcaddr)) {
595 struct IODNSResult *result;
596 if(iostartup->srcaddr) {
597 for(result = iostartup->srcaddr; result; result = result->next) {
598 if(result->type == IODNS_RECORD_A) {
599 iostartup->use_srcaddr = result;
604 if(!iostartup->srcaddr || iostartup->use_srcaddr) {
605 for(result = iostartup->srcaddr; result; result = result->next) {
606 if(result->type == IODNS_RECORD_A) {
607 iostartup->use_dstaddr = result;
612 if((iostartup->srcaddr && !iostartup->use_srcaddr) || (iostartup->dstaddr && !iostartup->use_dstaddr)) {
613 iostartup->use_srcaddr = NULL;
614 iostartup->use_dstaddr = NULL;
617 if(!(iostartup->use_dstaddr || iostartup->use_srcaddr))
618 trigger_dns_fail = 1;
620 if(trigger_dns_fail) {
621 struct IOEvent callback_event;
622 callback_event.type = IOEVENT_DNS_FAILED;
623 callback_event.iofd = iostartup->iofd;
624 iostartup->iofd->flags |= IOFDFLAGS_FREE_LOCK;
625 iohandler_trigger_event(&callback_event);
626 iostartup->iofd->flags &= ~IOFDFLAGS_FREE_LOCK;
627 if(iostartup->iofd->flags & IOFDFLAGS_WANT_FREE)
628 iohandler_remove_iostartup(iostartup);
630 iohandler_close(iostartup->iofd);
634 iohandler_process_iostartup(iostartup);
637 struct IODescriptor *iohandler_connect(const char *hostname, unsigned int port, int ssl, const char *bindhost, iohandler_callback *callback) {
638 return iohandler_connect_flags(hostname, port, ssl, bindhost, callback, IOHANDLER_CONNECT_IPV4 | IOHANDLER_CONNECT_IPV6);
641 struct IODescriptor *iohandler_connect_flags(const char *hostname, unsigned int port, int ssl, const char *bindhost, iohandler_callback *callback, int flags) {
643 iohandler_init_engine();
644 if(!engine) return NULL;
647 //non-blocking connect
648 struct IODescriptorStartup *iostartup;
649 struct IODescriptor *iofd;
651 iofd = calloc(1, sizeof(*iofd));
656 iostartup = calloc(1, sizeof(*iostartup));
662 iostartup->iofd = iofd;
663 iofd->fd.iostartup = iostartup;
665 iofd->type = IOTYPE_CLIENT;
666 iofd->state = IO_PENDING;
667 iofd->callback = callback;
669 iostartup->srchost = (bindhost ? strdup(bindhost) : NULL);
670 iostartup->dsthost = strdup(hostname);
671 iostartup->port = port;
672 iostartup->iptype = ((flags & IOHANDLER_CONNECT_IPV6) ? IODNS_RECORD_AAAA : 0) | ((flags & IOHANDLER_CONNECT_IPV4) ? IODNS_RECORD_A : 0);
673 iostartup->ssl = (ssl == 0 ? 0 : 1);
677 iostartup->iodns = iodns_getaddrinfo(bindhost, iostartup->iptype, iohandler_dns_callback);
678 iostartup->flags |= IOSTARTUP_SRCLOOKUP;
680 iostartup->iodns = iodns_getaddrinfo(hostname, iostartup->iptype, iohandler_dns_callback);
681 iostartup->flags |= IOSTARTUP_DSTLOOKUP;
683 iostartup->iodns->data = iostartup;
685 iohandler_append_iostartup(iostartup);
687 //Some Flags for later use
688 iofd->read_lines = 1;
690 iohandler_log(IOLOG_DEBUG, "added client socket connecting to %s:%d (DNS LOOKUP)", hostname, port);
695 struct IODescriptor *iohandler_listen(const char *hostname, unsigned int port, iohandler_callback *callback) {
696 return iohandler_listen_flags(hostname, port, callback, IOHANDLER_LISTEN_IPV4 | IOHANDLER_LISTEN_IPV6);
699 struct IODescriptor *iohandler_listen_flags(const char *hostname, unsigned int port, iohandler_callback *callback, int flags) {
701 iohandler_init_engine();
702 if(!engine) return NULL;
705 //non-blocking listening socket
706 struct IODescriptorStartup *iostartup;
707 struct IODescriptor *iofd;
709 iofd = calloc(1, sizeof(*iofd));
714 iostartup = calloc(1, sizeof(*iostartup));
720 iostartup->iofd = iofd;
721 iofd->fd.iostartup = iostartup;
723 iofd->type = IOTYPE_SERVER;
724 iofd->state = IO_PENDING;
725 iofd->callback = callback;
727 iostartup->srchost = (hostname ? strdup(hostname) : NULL);
728 iostartup->port = port;
729 iostartup->iptype = ((flags & IOHANDLER_LISTEN_IPV6) ? IODNS_RECORD_AAAA : 0) | ((flags & IOHANDLER_LISTEN_IPV4) ? IODNS_RECORD_A : 0);
731 iostartup->listening = 1;
735 iostartup->iodns = iodns_getaddrinfo(hostname, iostartup->iptype, iohandler_dns_callback);
736 iostartup->flags |= IOSTARTUP_SRCLOOKUP;
737 iostartup->iodns->data = iostartup;
738 iohandler_append_iostartup(iostartup);
740 iohandler_process_iostartup(iostartup);
742 iohandler_log(IOLOG_DEBUG, "added server socket listening on %s:%d", hostname, port);
746 struct IODescriptor *iohandler_listen_ssl(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iohandler_callback *callback) {
747 return iohandler_listen_ssl_flags(hostname, port, certfile, keyfile, callback, IOHANDLER_LISTEN_IPV4 | IOHANDLER_LISTEN_IPV6);
750 struct IODescriptor *iohandler_listen_ssl_flags(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iohandler_callback *callback, int flags) {
752 iohandler_init_engine();
753 if(!engine) return NULL;
756 //non-blocking listening socket
757 struct IODescriptorStartup *iostartup;
758 struct IODescriptor *iofd;
760 iofd = calloc(1, sizeof(*iofd));
765 iostartup = calloc(1, sizeof(*iostartup));
771 iostartup->iofd = iofd;
772 iofd->fd.iostartup = iostartup;
774 iofd->type = IOTYPE_SERVER;
775 iofd->state = IO_PENDING;
776 iofd->callback = callback;
778 iostartup->srchost = (hostname ? strdup(hostname) : NULL);
779 iostartup->port = port;
780 iostartup->iptype = ((flags & IOHANDLER_LISTEN_IPV6) ? IODNS_RECORD_AAAA : 0) | ((flags & IOHANDLER_LISTEN_IPV4) ? IODNS_RECORD_A : 0);
782 iostartup->ssl_certfile = strdup(certfile);
783 iostartup->ssl_keyfile = strdup(keyfile);
784 iostartup->listening = 1;
788 iostartup->iodns = iodns_getaddrinfo(hostname, iostartup->iptype, iohandler_dns_callback);
789 iohandler_append_iostartup(iostartup);
791 iohandler_process_iostartup(iostartup);
793 iohandler_log(IOLOG_DEBUG, "added SSL server socket listening on %s:%d", hostname, port);
797 void iohandler_write(struct IODescriptor *iofd, const char *line) {
798 size_t linelen = strlen(line);
799 iohandler_send(iofd, line, linelen);
802 void iohandler_send(struct IODescriptor *iofd, const char *data, size_t datalen) {
803 if(iofd->type == IOTYPE_TIMER || iofd->state == IO_CLOSED) {
804 iohandler_log(IOLOG_ERROR, "could not write to socket (%s)", (iofd->type == IOTYPE_TIMER ? "IOTYPE_TIMER" : "IO_CLOSED"));
807 iohandler_log(IOLOG_DEBUG, "add %d to writebuf (fd: %d): %s", datalen, iofd->fd, data);
808 if(iofd->writebuf.buflen < iofd->writebuf.bufpos + datalen) {
809 iohandler_log(IOLOG_DEBUG, "increase writebuf (curr: %d) to %d (+%d bytes)", iofd->writebuf.buflen, iofd->writebuf.bufpos + datalen, (iofd->writebuf.bufpos + datalen - iofd->writebuf.buflen));
810 iohandler_increase_iobuf(&iofd->writebuf, iofd->writebuf.bufpos + datalen);
811 if(iofd->writebuf.buflen < iofd->writebuf.bufpos + datalen) {
812 iohandler_log(IOLOG_ERROR, "increase writebuf (curr: %d) to %d (+%d bytes) FAILED", iofd->writebuf.buflen, iofd->writebuf.bufpos + datalen, (iofd->writebuf.bufpos + datalen - iofd->writebuf.buflen));
816 memcpy(iofd->writebuf.buffer + iofd->writebuf.bufpos, data, datalen);
817 iofd->writebuf.bufpos += datalen;
818 struct IOLowlevelDescriptor *iold = IODESCRIPTOR_GET_IOLD(iofd);
820 iold->flags |= IOFLAGS_WANT_WRITE;
821 engine->update(iold);
825 void iohandler_printf(struct IODescriptor *iofd, const char *text, ...) {
827 char sendBuf[IO_LINE_LEN];
830 va_start(arg_list, text);
831 pos = vsnprintf(sendBuf, IO_LINE_LEN - 2, text, arg_list);
833 if (pos < 0 || pos > (IO_LINE_LEN - 2)) pos = IO_LINE_LEN - 2;
835 sendBuf[pos+1] = '\0';
836 iohandler_send(iofd, sendBuf, pos+1);
839 static int iohandler_try_write(struct IODescriptor *iofd) {
840 struct IOLowlevelDescriptor *iold = IODESCRIPTOR_GET_IOLD(iofd);
841 if(!iofd->writebuf.bufpos || !iold) return 0;
842 iohandler_log(IOLOG_DEBUG, "write writebuf (%d bytes) to socket (fd: %d)", iofd->writebuf.bufpos, iofd->fd);
845 res = iohandler_ssl_write(iofd, iofd->writebuf.buffer, iofd->writebuf.bufpos);
847 res = send(iofd->fd.iold->fd, iofd->writebuf.buffer, iofd->writebuf.bufpos, 0);
849 if (errno != EAGAIN && errno != EWOULDBLOCK)
850 iohandler_log(IOLOG_ERROR, "could not write to socket (fd: %d): %d - %s", iofd->fd.iold->fd, errno, strerror(errno));
854 iofd->writebuf.bufpos -= res;
855 if(iofd->writebuf.bufpos)
856 iold->flags |= IOFLAGS_WANT_WRITE;
858 iold->flags &= ~IOFLAGS_WANT_WRITE;
859 engine->update(iold);
864 void iohandler_close(struct IODescriptor *iofd) {
865 struct IOLowlevelDescriptor *iold = IODESCRIPTOR_GET_IOLD(iofd);
866 int engine_remove = 1;
867 iofd->state = IO_CLOSED;
869 if(iofd->writebuf.bufpos) {
870 //try to send everything before closing
874 flags = fcntl(iofd->fd, F_GETFL);
875 fcntl(iofd->fd, F_SETFL, flags & ~O_NONBLOCK);
876 flags = fcntl(iofd->fd, F_GETFD);
877 fcntl(iofd->fd, F_SETFD, flags|FD_CLOEXEC);
881 engine->remove(iofd);
883 iohandler_try_write(iofd);
886 iohandler_ssl_disconnect(iofd);
887 if((iofd->type == IOTYPE_SERVER || iofd->type == IOTYPE_CLIENT || iofd->type == IOTYPE_STDIN))
890 engine->remove(iold);
891 if(iofd->flags & IOFDFLAGS_FREE_LOCK)
892 iofd->flags |= IOFDFLAGS_WANT_FREE;
894 iohandler_remove(iold);
896 if(iofd->flags & IOFDFLAGS_FREE_LOCK)
897 iofd->flags |= IOFDFLAGS_WANT_FREE;
899 iohandler_remove_iostartup(iofd->fd.iostartup);
903 void iohandler_update(struct IODescriptor *iofd) {
904 iohandler_log(IOLOG_DEBUG, "external call to iohandler_update");
905 struct IOLowlevelDescriptor *iold = IODESCRIPTOR_GET_IOLD(iofd);
907 engine->update(iold);
910 void iohandler_events(struct IODescriptor *iofd, int readable, int writeable) {
911 struct IOLowlevelDescriptor *iold = IODESCRIPTOR_GET_IOLD(iofd);
912 struct IOEvent callback_event;
913 callback_event.type = IOEVENT_IGNORE;
914 callback_event.iofd = iofd;
918 switch(iofd->state) {
920 if(!readable && !writeable) {
921 if(!(iofd->flags & IOFDFLAGS_SSL_SERVER_HS)) {
922 callback_event.type = IOEVENT_SSLFAILED;
923 iofd->state = IO_CLOSED;
924 engine->update(iold);
927 } else if((iofd->flags & IOFDFLAGS_SSL_SERVER_HS)) {
928 iohandler_log(IOLOG_DEBUG, "triggering iohandler_ssl_server_handshake for %s (fd: %d)", iohandler_iotype_name(iofd->type), iofd->fd);
929 iohandler_ssl_server_handshake(iofd);
931 iohandler_log(IOLOG_DEBUG, "triggering iohandler_ssl_client_handshake for %s (fd: %d)", iohandler_iotype_name(iofd->type), iofd->fd);
932 iohandler_ssl_client_handshake(iofd);
936 if(iofd->type == IOTYPE_TIMER) // Timers will be removed by IOEngine
937 callback_event.type = IOEVENT_TIMEOUT;
943 int accept_fd = accept(iold->fd, NULL, 0);
945 iohandler_log(IOLOG_ERROR, "could not accept client (server fd: %d): %d - %s", iofd->fd, errno, strerror(errno));
947 struct IODescriptor *client_iofd = iohandler_add(accept_fd, IOTYPE_CLIENT, NULL, NULL);
949 iohandler_ssl_client_accepted(iofd, client_iofd);
951 callback_event.type = IOEVENT_ACCEPT;
952 callback_event.data.accept_iofd = client_iofd;
958 if(readable) { //could not connect
959 callback_event.type = IOEVENT_NOTCONNECTED;
961 //arglen = sizeof(callback_event.data.errid);
962 //if (getsockopt(iofd->fd, SOL_SOCKET, SO_ERROR, &callback_event.data.errid, &arglen) < 0)
963 // callback_event.data.errid = errno;
964 iofd->state = IO_CLOSED;
965 engine->update(iold);
967 } else if(writeable) {
968 if(iofd->ssl && !(iofd->flags & IOFDFLAGS_SSL_ACTIVE)) {
969 iohandler_log(IOLOG_DEBUG, "triggering iohandler_ssl_connect for %s (fd: %d)", iohandler_iotype_name(iofd->type), iofd->fd);
970 iohandler_ssl_connect(iofd);
973 if(iofd->ssl && (iofd->flags & IOFDFLAGS_SSL_SERVER_HS)) {
974 callback_event.type = IOEVENT_SSLACCEPT;
975 callback_event.iofd = iofd->data;
976 callback_event.data.accept_iofd = iofd;
980 callback_event.type = IOEVENT_CONNECTED;
981 iofd->state = IO_CONNECTED;
982 engine->update(iold);
987 if(iofd->read_lines) {
990 if((iofd->flags & IOFDFLAGS_SSL_ACTIVE))
991 bytes = iohandler_ssl_read(iofd, iofd->readbuf.buffer + iofd->readbuf.bufpos, iofd->readbuf.buflen - iofd->readbuf.bufpos);
993 if(iofd->type == IOTYPE_STDIN)
997 bytes = read(iold->fd, iofd->readbuf.buffer + iofd->readbuf.bufpos, iofd->readbuf.buflen - iofd->readbuf.bufpos);
1000 bytes = recv(iold->fd, iofd->readbuf.buffer + iofd->readbuf.bufpos, iofd->readbuf.buflen - iofd->readbuf.bufpos, 0);
1003 if (errno != EAGAIN || errno != EWOULDBLOCK) {
1004 iofd->state = IO_CLOSED;
1005 engine->update(iold);
1006 callback_event.type = IOEVENT_CLOSED;
1007 callback_event.data.errid = errno;
1011 int i, used_bytes = 0;
1012 iohandler_log(IOLOG_DEBUG, "received %d bytes (fd: %d). readbuf position: %d", bytes, iold->fd, iofd->readbuf.bufpos);
1013 iofd->readbuf.bufpos += bytes;
1014 callback_event.type = IOEVENT_RECV;
1015 for(i = 0; i < iofd->readbuf.bufpos; i++) {
1016 if(iofd->readbuf.buffer[i] == '\r' && iofd->readbuf.buffer[i+1] == '\n')
1017 iofd->readbuf.buffer[i] = 0;
1018 else if(iofd->readbuf.buffer[i] == '\n' || iofd->readbuf.buffer[i] == '\r') {
1019 iofd->readbuf.buffer[i] = 0;
1020 callback_event.data.recv_str = iofd->readbuf.buffer + used_bytes;
1021 iohandler_log(IOLOG_DEBUG, "parsed line (%d bytes): %s", i - used_bytes, iofd->readbuf.buffer + used_bytes);
1023 iofd->flags |= IOFDFLAGS_FREE_LOCK;
1024 iohandler_trigger_event(&callback_event);
1025 iofd->flags &= ~IOFDFLAGS_FREE_LOCK;
1026 if(iofd->flags & IOFDFLAGS_WANT_FREE)
1028 } else if(i + 1 - used_bytes >= IO_LINE_LEN) { //512 max
1029 iofd->readbuf.buffer[i] = 0;
1030 callback_event.data.recv_str = iofd->readbuf.buffer + used_bytes;
1031 iohandler_log(IOLOG_DEBUG, "parsed and stripped line (%d bytes): %s", i - used_bytes, iofd->readbuf.buffer + used_bytes);
1032 for(; i < iofd->readbuf.bufpos; i++) { //skip the rest of the line
1033 if(iofd->readbuf.buffer[i] == '\n' || (iofd->readbuf.buffer[i] == '\r' && iofd->readbuf.buffer[i+1] != '\n')) {
1038 iofd->flags |= IOFDFLAGS_FREE_LOCK;
1039 iohandler_trigger_event(&callback_event);
1040 iofd->flags &= ~IOFDFLAGS_FREE_LOCK;
1041 if(iofd->flags & IOFDFLAGS_WANT_FREE)
1046 if(used_bytes == iofd->readbuf.bufpos) {
1047 iofd->readbuf.bufpos = 0;
1048 iohandler_log(IOLOG_DEBUG, "readbuf fully processed (set buffer position to 0)");
1050 iohandler_log(IOLOG_DEBUG, "readbuf rest: %d bytes (used %d bytes)", iofd->readbuf.bufpos - used_bytes, used_bytes);
1051 memmove(iofd->readbuf.buffer, iofd->readbuf.buffer + used_bytes, iofd->readbuf.bufpos - used_bytes);
1052 iofd->readbuf.bufpos -= used_bytes;
1055 callback_event.type = IOEVENT_IGNORE;
1058 callback_event.type = IOEVENT_READABLE;
1062 bytes = iohandler_try_write(iofd);
1064 iofd->state = IO_CLOSED;
1065 engine->update(iold);
1066 callback_event.type = IOEVENT_CLOSED;
1067 callback_event.data.errid = errno;
1073 /* nothing to do for pending descriptors */
1076 iofd->flags |= IOFDFLAGS_FREE_LOCK;
1077 if(callback_event.type == IOEVENT_IGNORE && !readable && !writeable)
1078 callback_event.type = IOEVENT_TIMEOUT;
1079 if(callback_event.type != IOEVENT_IGNORE)
1080 iohandler_trigger_event(&callback_event);
1081 iofd->flags &= ~IOFDFLAGS_FREE_LOCK;
1082 if(iofd->flags & IOFDFLAGS_WANT_FREE)
1083 iohandler_remove(iold);
1084 else if(remove_iofd)
1085 iohandler_close(iofd);
1088 void iohandler_poll() {
1089 struct timeval timeout;
1090 timeout.tv_sec = IO_MAX_TIMEOUT;
1091 timeout.tv_usec = 0;
1092 iohandler_poll_timeout(timeout);
1095 void iohandler_poll_timeout(struct timeval timeout) {
1098 IOSYNCHRONIZE(io_poll_sync); //quite senceless multithread support... better support will follow
1099 engine->loop(&timeout);
1100 IODESYNCHRONIZE(io_poll_sync);
1104 //debugging functions
1105 char *iohandler_iotype_name(enum IOType type) {
1107 case IOTYPE_UNKNOWN:
1108 return "IOTYPE_UNKNOWN";
1110 return "IOTYPE_SERVER";
1112 return "IOTYPE_CLIENT";
1114 return "IOTYPE_STDIN";
1116 return "IOTYPE_TIMER";
1118 return "(UNDEFINED)";
1122 char *iohandler_iostatus_name(enum IOStatus status) {
1127 return "IO_LISTENING";
1129 return "IO_CONNECTING";
1131 return "IO_CONNECTED";
1133 return "IO_SSLWAIT";
1135 return "(UNDEFINED)";
1139 char *iohandler_ioeventtype_name(enum IOEventType type) {
1141 case IOEVENT_IGNORE:
1142 return "IOEVENT_IGNORE";
1143 case IOEVENT_READABLE:
1144 return "IOEVENT_READABLE";
1146 return "IOEVENT_RECV";
1147 case IOEVENT_CONNECTED:
1148 return "IOEVENT_CONNECTED";
1149 case IOEVENT_NOTCONNECTED:
1150 return "IOEVENT_NOTCONNECTED";
1151 case IOEVENT_CLOSED:
1152 return "IOEVENT_CLOSED";
1153 case IOEVENT_ACCEPT:
1154 return "IOEVENT_ACCEPT";
1155 case IOEVENT_SSLACCEPT:
1156 return "IOEVENT_SSLACCEPT";
1157 case IOEVENT_TIMEOUT:
1158 return "IOEVENT_TIMEOUT";
1160 return "(UNDEFINED)";