1 /* IOSockets.c - IOMultiplexer v2
2 * Copyright (C) 2014 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 #define _IOHandler_internals
18 #include "IOInternal.h"
19 #include "IOHandler.h"
20 #include "IOSockets.h"
22 #include "IODNSLookup.h"
25 #define _WIN32_WINNT 0x501
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <netinet/ip.h>
33 #include <arpa/inet.h>
37 #include "compat/inet.h"
46 #define EWOULDBLOCK EAGAIN
49 struct _IOSocket *iosocket_first = NULL;
50 struct _IOSocket *iosocket_last = NULL;
52 struct IOEngine *engine = NULL;
54 static void iosocket_activate(struct _IOSocket *iosock);
55 static void iosocket_deactivate(struct _IOSocket *iosock);
56 static void iosocket_increase_buffer(struct IOSocketBuffer *iobuf, size_t required);
57 static int iosocket_parse_address(const char *hostname, struct IODNSAddress *addr, int records);
58 static int iosocket_lookup_hostname(struct _IOSocket *iosock, const char *hostname, int records, int bindaddr);
59 static int iosocket_lookup_apply(struct _IOSocket *iosock, int noip6);
60 static void socket_lookup_clear(struct _IOSocket *iosock);
61 static void iosocket_connect_finish(struct _IOSocket *iosock);
62 static void iosocket_listen_finish(struct _IOSocket *iosock);
63 static int iosocket_try_write(struct _IOSocket *iosock);
64 static void iosocket_trigger_event(struct IOSocketEvent *event);
67 static int close(int fd) {
68 return closesocket(fd);
72 static void iosockets_init_engine() {
74 if(!engine && engine_kevent.init && engine_kevent.init())
75 engine = &engine_kevent;
76 if(!engine && engine_epoll.init && engine_epoll.init())
77 engine = &engine_epoll;
78 if(!engine && engine_win32.init && engine_win32.init())
79 engine = &engine_win32;
82 if(engine_select.init())
83 engine = &engine_select;
85 iolog_trigger(IOLOG_FATAL, "found no useable IO engine");
89 iolog_trigger(IOLOG_DEBUG, "using %s IOSockets engine", engine->name);
92 void _init_sockets() {
97 iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
99 iolog_trigger(IOLOG_ERROR, "WSAStartup returned error code: %d", iResult);
103 iosockets_init_engine();
107 struct _IOSocket *_create_socket() {
108 struct _IOSocket *iosock = calloc(1, sizeof(*iosock));
110 iolog_trigger(IOLOG_ERROR, "could not allocate memory for _IOSocket in %s:%d", __FILE__, __LINE__);
114 iosocket_last->next = iosock;
116 iosocket_first = iosock;
117 iosock->prev = iosocket_last;
118 iosocket_last = iosock;
122 void _free_socket(struct _IOSocket *iosock) {
123 iosocket_deactivate(iosock);
125 iosock->prev->next = iosock->next;
127 iosocket_first = iosock->next;
129 iosock->next->prev = iosock->prev;
131 iosocket_last = iosock->prev;
133 if(iosock->bind.addr.addresslen)
134 free(iosock->bind.addr.address);
135 if(iosock->dest.addr.addresslen)
136 free(iosock->dest.addr.address);
137 if(iosock->bind.addrlookup || iosock->dest.addrlookup)
138 socket_lookup_clear(iosock);
139 if(iosock->readbuf.buffer)
140 free(iosock->readbuf.buffer);
141 if(iosock->writebuf.buffer)
142 free(iosock->writebuf.buffer);
147 static void iosocket_activate(struct _IOSocket *iosock) {
148 if((iosock->socket_flags & IOSOCKETFLAG_ACTIVE))
150 iosock->socket_flags |= IOSOCKETFLAG_ACTIVE;
154 static void iosocket_deactivate(struct _IOSocket *iosock) {
155 if(!(iosock->socket_flags & IOSOCKETFLAG_ACTIVE))
157 iosock->socket_flags &= ~IOSOCKETFLAG_ACTIVE;
158 engine->remove(iosock);
161 static void iosocket_increase_buffer(struct IOSocketBuffer *iobuf, size_t required) {
162 if(iobuf->buflen >= required) return;
165 new_buf = realloc(iobuf->buffer, required + 2);
167 new_buf = malloc(required + 2);
169 iobuf->buffer = new_buf;
170 iobuf->buflen = required;
174 static int iosocket_parse_address(const char *hostname, struct IODNSAddress *addr, int records) {
176 if((records & IOSOCKET_ADDR_IPV4)) {
177 struct sockaddr_in ip4addr;
178 ret = inet_pton(AF_INET, hostname, &(ip4addr.sin_addr));
180 addr->addresslen = sizeof(ip4addr);
181 addr->address = malloc(addr->addresslen);
183 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
186 memcpy(addr->address, &ip4addr, sizeof(ip4addr));
190 if((records & IOSOCKET_ADDR_IPV6)) {
191 struct sockaddr_in6 ip6addr;
192 ret = inet_pton(AF_INET6, hostname, &(ip6addr.sin6_addr));
194 addr->addresslen = sizeof(ip6addr);
195 addr->address = malloc(addr->addresslen);
197 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
200 memcpy(addr->address, &ip6addr, sizeof(ip6addr));
207 static int iosocket_lookup_hostname(struct _IOSocket *iosock, const char *hostname, int records, int bindaddr) {
208 struct IOSocketDNSLookup *lookup = calloc(1, sizeof(*lookup));
210 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocketDNSLookup in %s:%d", __FILE__, __LINE__);
214 struct _IODNSQuery *query = _create_dnsquery();
220 query->parent = lookup;
221 query->flags |= IODNSFLAG_PARENT_SOCKET;
222 lookup->iosocket = iosock;
223 lookup->query = query;
224 strncpy(lookup->hostname, hostname, sizeof(lookup->hostname));
225 lookup->hostname[sizeof(lookup->hostname)-1] = 0;
227 lookup->bindlookup = 1;
228 iosock->bind.addrlookup = lookup;
230 lookup->bindlookup = 0;
231 iosock->dest.addrlookup = lookup;
235 if((records & IOSOCKET_ADDR_IPV4))
236 dnsrecords |= IODNS_RECORD_A;
237 if((records & IOSOCKET_ADDR_IPV6))
238 dnsrecords |= IODNS_RECORD_AAAA;
240 query->request.host = strdup(hostname);
241 query->type = (dnsrecords & IODNS_FORWARD);
243 _start_dnsquery(query);
247 void iosocket_lookup_callback(struct IOSocketDNSLookup *lookup, struct IODNSEvent *event) {
248 lookup->query = NULL;
249 struct _IOSocket *iosock = lookup->iosocket;
253 if(event->type == IODNSEVENT_SUCCESS)
254 lookup->result = event->result;
256 lookup->result = NULL;
258 if(lookup->bindlookup) {
259 iosock->socket_flags &= ~IOSOCKETFLAG_PENDING_BINDDNS;
260 iosock->socket_flags |= IOSOCKETFLAG_DNSDONE_BINDDNS;
262 iosock->socket_flags &= ~IOSOCKETFLAG_PENDING_DESTDNS;
263 iosock->socket_flags |= IOSOCKETFLAG_DNSDONE_DESTDNS;
266 int dns_finished = 0;
267 if((iosock->socket_flags & (IOSOCKETFLAG_PENDING_BINDDNS | IOSOCKETFLAG_PENDING_DESTDNS)) == 0)
272 ret = iosocket_lookup_apply(iosock, 0);
273 if(ret) { //if ret=0 an error occured in iosocket_lookup_apply and we should stop here.
274 if((iosock->socket_flags & IOSOCKETFLAG_LISTENING)) {
275 socket_lookup_clear(iosock);
276 iosocket_listen_finish(iosock);
278 iosocket_connect_finish(iosock);
283 static int iosocket_lookup_apply(struct _IOSocket *iosock, int noip6) {
285 struct IOSocketDNSLookup *bind_lookup = ((iosock->socket_flags & IOSOCKETFLAG_DNSDONE_BINDDNS) ? iosock->bind.addrlookup : NULL);
286 struct IOSocketDNSLookup *dest_lookup = ((iosock->socket_flags & IOSOCKETFLAG_DNSDONE_DESTDNS) ? iosock->dest.addrlookup : NULL);
288 iolog_trigger(IOLOG_DEBUG, "all pending lookups finished. trying to apply lookup results...");
290 if(!bind_lookup && !dest_lookup) {
291 iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
292 sprintf(errbuf, "Internal Error");
293 iolog_trigger(IOLOG_ERROR, "trying to apply lookup results without any lookups processed in %s:%d", __FILE__, __LINE__);
294 goto iosocket_lookup_apply_end;
297 struct IODNSResult *result;
298 int bind_numip4 = 0, bind_numip6 = 0;
299 int dest_numip4 = 0, dest_numip6 = 0;
302 for(result = bind_lookup->result; result; result = result->next) {
303 if((result->type & IODNS_RECORD_A))
305 if((result->type & IODNS_RECORD_AAAA))
310 for(result = dest_lookup->result; result; result = result->next) {
311 if((result->type & IODNS_RECORD_A))
313 if((result->type & IODNS_RECORD_AAAA))
319 if(bind_lookup && (bind_numip6 == 0 && bind_numip4 == 0)) {
320 iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
321 sprintf(errbuf, "could not lookup bind address (%s)", bind_lookup->hostname);
322 goto iosocket_lookup_apply_end;
323 } else if(dest_lookup && (dest_numip6 == 0 && dest_numip4 == 0)) {
324 iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
325 sprintf(errbuf, "could not lookup destination address (%s)", dest_lookup->hostname);
326 goto iosocket_lookup_apply_end;
327 } else if(bind_lookup && dest_lookup) {
328 if(bind_numip6 > 0 && dest_numip6 > 0)
330 if(bind_numip4 > 0 && dest_numip4 > 0)
332 } else if(bind_lookup) {
337 } else if(dest_lookup) {
345 if(useip6 && !noip6) {
346 usetype = IODNS_RECORD_AAAA;
347 iosock->socket_flags |= IOSOCKETFLAG_IPV6SOCKET;
349 iosock->socket_flags |= IOSOCKETFLAG_RECONNECT_IPV4;
351 usetype = IODNS_RECORD_A;
352 iosock->socket_flags &= ~(IOSOCKETFLAG_IPV6SOCKET | IOSOCKETFLAG_RECONNECT_IPV4);
354 iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
355 sprintf(errbuf, "could not lookup adresses of the same IP family for bind and destination host. (bind: %d ip4, %d ip6 | dest: %d ip4, %d ip6)", bind_numip4, bind_numip6, dest_numip4, dest_numip6);
356 goto iosocket_lookup_apply_end;
359 #define IOSOCKET_APPLY_COPYADDR(type) \
360 iosock->type.addr.addresslen = result->result.addr.addresslen; \
361 iosock->type.addr.address = malloc(result->result.addr.addresslen); \
362 if(!iosock->type.addr.address) { \
363 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__); \
364 iosock->type.addr.addresslen = 0; \
365 iosock->socket_flags |= IOSOCKETFLAG_DNSERROR; \
366 sprintf(errbuf, "could not allocate memory for dns information"); \
367 goto iosocket_lookup_apply_end; \
369 memcpy(iosock->type.addr.address, result->result.addr.address, result->result.addr.addresslen);
373 int usenum = ((usetype == IODNS_RECORD_AAAA) ? bind_numip6 : bind_numip4);
374 usenum = rand() % usenum;
375 for(result = bind_lookup->result; result; result = result->next) {
376 if((result->type & usetype)) {
378 inet_ntop(((usetype == IODNS_RECORD_AAAA) ? AF_INET6 : AF_INET), ((usetype == IODNS_RECORD_AAAA) ? (void *)(&((struct sockaddr_in6 *)result->result.addr.address)->sin6_addr) : (void *)(&((struct sockaddr_in *)result->result.addr.address)->sin_addr)), errbuf, sizeof(errbuf));
379 iolog_trigger(IOLOG_DEBUG, "using IPv%s Address (%s) as bind address", ((usetype == IODNS_RECORD_AAAA) ? "6" : "4"), errbuf);
380 IOSOCKET_APPLY_COPYADDR(bind)
387 iosock->bind.addr.addresslen = 0;
390 int usenum = ((usetype == IODNS_RECORD_AAAA) ? dest_numip6 : dest_numip4);
391 usenum = rand() % usenum;
392 for(result = dest_lookup->result; result; result = result->next) {
393 if((result->type & usetype)) {
395 inet_ntop(((usetype == IODNS_RECORD_AAAA) ? AF_INET6 : AF_INET), ((usetype == IODNS_RECORD_AAAA) ? (void *)(&((struct sockaddr_in6 *)result->result.addr.address)->sin6_addr) : (void *)(&((struct sockaddr_in *)result->result.addr.address)->sin_addr)), errbuf, sizeof(errbuf));
396 iolog_trigger(IOLOG_DEBUG, "using IPv%s Address (%s) as dest address", ((usetype == IODNS_RECORD_AAAA) ? "6" : "4"), errbuf);
397 IOSOCKET_APPLY_COPYADDR(dest)
404 iosock->dest.addr.addresslen = 0;
406 iosocket_lookup_apply_end:
408 if((iosock->socket_flags & IOSOCKETFLAG_DNSERROR)) {
409 // TODO: trigger error
410 iolog_trigger(IOLOG_ERROR, "error while trying to apply dns lookup information: %s", errbuf);
412 if((iosock->socket_flags & IOSOCKETFLAG_PARENT_PUBLIC)) {
414 struct IOSocket *iosocket = iosock->parent;
416 struct IOSocketEvent callback_event;
417 callback_event.type = IOSOCKETEVENT_DNSFAILED;
418 callback_event.socket = iosocket;
419 callback_event.data.recv_str = errbuf;
420 iosocket_trigger_event(&callback_event);
422 iosocket_close(iosocket);
424 // TODO: IODNS Callback
431 static void socket_lookup_clear(struct _IOSocket *iosock) {
432 struct IOSocketDNSLookup *bind_lookup = ((iosock->socket_flags & IOSOCKETFLAG_DNSDONE_BINDDNS) ? iosock->bind.addrlookup : NULL);
433 struct IOSocketDNSLookup *dest_lookup = ((iosock->socket_flags & IOSOCKETFLAG_DNSDONE_DESTDNS) ? iosock->dest.addrlookup : NULL);
435 if(bind_lookup->result)
436 iodns_free_result(bind_lookup->result);
438 iosock->bind.addrlookup = NULL;
441 if(dest_lookup->result)
442 iodns_free_result(dest_lookup->result);
444 iosock->dest.addrlookup = NULL;
448 static void iosocket_prepare_fd(int sockfd) {
451 #if defined(SO_NOSIGPIPE)
454 setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
457 signal(SIGPIPE, SIG_IGN);
461 // make sockfd unblocking
465 fcntl_flags = fcntl(sockfd, F_GETFL);
466 fcntl(sockfd, F_SETFL, fcntl_flags|O_NONBLOCK);
467 fcntl_flags = fcntl(sockfd, F_GETFD);
468 fcntl(sockfd, F_SETFD, fcntl_flags|FD_CLOEXEC);
470 #elif defined(FIONBIO)
472 unsigned long ulong = 1;
473 ioctlsocket(sockfd, FIONBIO, &ulong);
478 static void iosocket_connect_finish(struct _IOSocket *iosock) {
480 if((iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET))
481 sockfd = socket(AF_INET6, SOCK_STREAM, 0);
483 sockfd = socket(AF_INET, SOCK_STREAM, 0);
485 iolog_trigger(IOLOG_ERROR, "could not create socket in %s:%d", __FILE__, __LINE__);
486 // TODO: trigger error
491 // set port and bind address
492 if((iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET)) {
493 struct sockaddr_in6 *ip6 = (void*) iosock->dest.addr.address;
494 ip6->sin6_family = AF_INET6;
495 ip6->sin6_port = htons(iosock->port);
497 if(iosock->bind.addr.addresslen) {
498 struct sockaddr_in6 *ip6bind = (void*) iosock->bind.addr.address;
499 ip6bind->sin6_family = AF_INET6;
500 ip6bind->sin6_port = htons(0);
502 bind(sockfd, (struct sockaddr*)ip6bind, sizeof(*ip6bind));
505 struct sockaddr_in *ip4 = (void*) iosock->dest.addr.address;
506 ip4->sin_family = AF_INET;
507 ip4->sin_port = htons(iosock->port);
509 if(iosock->bind.addr.addresslen) {
510 struct sockaddr_in *ip4bind = (void*) iosock->bind.addr.address;
511 ip4bind->sin_family = AF_INET;
512 ip4bind->sin_port = htons(0);
514 bind(sockfd, (struct sockaddr*)ip4bind, sizeof(*ip4bind));
518 iosocket_prepare_fd(sockfd);
520 int ret = connect(sockfd, iosock->dest.addr.address, iosock->dest.addr.addresslen); //returns EINPROGRESS here (nonblocking)
521 iolog_trigger(IOLOG_DEBUG, "connecting socket (connect: %d)", ret);
524 iosock->socket_flags |= IOSOCKETFLAG_CONNECTING;
526 iosocket_activate(iosock);
529 static void iosocket_listen_finish(struct _IOSocket *iosock) {
531 if((iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET))
532 sockfd = socket(AF_INET6, SOCK_STREAM, 0);
534 sockfd = socket(AF_INET, SOCK_STREAM, 0);
536 iolog_trigger(IOLOG_ERROR, "could not create socket in %s:%d", __FILE__, __LINE__);
537 // TODO: trigger error
542 // set port and bind address
543 if((iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET)) {
544 struct sockaddr_in6 *ip6bind = (void*) iosock->bind.addr.address;
545 ip6bind->sin6_family = AF_INET6;
546 ip6bind->sin6_port = htons(0);
549 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
551 bind(sockfd, (struct sockaddr*)ip6bind, sizeof(*ip6bind));
553 struct sockaddr_in *ip4bind = (void*) iosock->bind.addr.address;
554 ip4bind->sin_family = AF_INET;
555 ip4bind->sin_port = htons(0);
558 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
560 bind(sockfd, (struct sockaddr*)ip4bind, sizeof(*ip4bind));
563 iosocket_prepare_fd(sockfd);
568 iosocket_activate(iosock);
571 struct _IOSocket *iosocket_accept_client(struct _IOSocket *iosock) {
572 struct IOSocket *new_iosocket = calloc(1, sizeof(*new_iosocket));
574 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocket in %s:%d", __FILE__, __LINE__);
575 close(accept(iosock->fd, NULL, 0)); // simply drop connection
578 struct _IOSocket *new_iosock = _create_socket();
581 close(accept(iosock->fd, NULL, 0)); // simply drop connection
584 new_iosocket->iosocket = new_iosock;
585 new_iosocket->status = IOSOCKET_CONNECTED;
586 new_iosock->parent = new_iosocket;
587 new_iosock->socket_flags |= IOSOCKETFLAG_PARENT_PUBLIC | IOSOCKETFLAG_INCOMING | (iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET);
589 struct sockaddr_storage addr;
590 socklen_t addrlen = sizeof(addr);
593 new_iosock->fd = accept(iosock->fd, (struct sockaddr *)&addr, &addrlen);
595 //copy remote address
596 new_iosock->dest.addr.address = malloc(addrlen);
597 if(!new_iosock->dest.addr.address) {
598 close(new_iosock->fd);
601 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
604 memcpy(new_iosock->dest.addr.address, &addr, addrlen);
605 new_iosock->dest.addr.addresslen = addrlen;
608 new_iosock->bind.addr.address = malloc(iosock->bind.addr.addresslen);
609 if(!new_iosock->bind.addr.address) {
610 close(new_iosock->fd);
613 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
616 memcpy(new_iosock->bind.addr.address, iosock->bind.addr.address, iosock->bind.addr.addresslen);
617 new_iosock->bind.addr.addresslen = iosock->bind.addr.addresslen;
619 //prepare new socket fd
620 iosocket_prepare_fd(new_iosock->fd);
622 if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {
623 new_iosocket->ssl = 1;
624 new_iosock->socket_flags |= IOSOCKETFLAG_SSLSOCKET;
625 //TODO: SSL Handshake
628 iosocket_activate(new_iosock);
632 /* public functions */
634 struct IOSocket *iosocket_connect(const char *hostname, unsigned int port, int ssl, const char *bindhost, iosocket_callback *callback) {
635 return iosocket_connect_flags(hostname, port, ssl, bindhost, callback, (IOSOCKET_ADDR_IPV4 | IOSOCKET_ADDR_IPV6));
638 struct IOSocket *iosocket_connect_flags(const char *hostname, unsigned int port, int ssl, const char *bindhost, iosocket_callback *callback, int flags) {
639 struct IOSocket *iodescriptor = calloc(1, sizeof(*iodescriptor));
641 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocket in %s:%d", __FILE__, __LINE__);
645 struct _IOSocket *iosock = _create_socket();
651 iodescriptor->iosocket = iosock;
652 iodescriptor->status = IOSOCKET_CONNECTING;
653 iodescriptor->callback = callback;
654 iosock->parent = iodescriptor;
655 iosock->socket_flags |= IOSOCKETFLAG_PARENT_PUBLIC;
658 iodescriptor->ssl = 1;
659 iosock->socket_flags |= IOSOCKETFLAG_SSLSOCKET;
663 switch(iosocket_parse_address(bindhost, &iosock->bind.addr, flags)) {
668 /* start dns lookup */
669 iosock->socket_flags |= IOSOCKETFLAG_PENDING_BINDDNS;
670 iosocket_lookup_hostname(iosock, bindhost, flags, 1);
677 switch(iosocket_parse_address(hostname, &iosock->dest.addr, flags)) {
682 /* start dns lookup */
683 iosock->socket_flags |= IOSOCKETFLAG_PENDING_DESTDNS;
684 iosocket_lookup_hostname(iosock, hostname, flags, 0);
690 if((iosock->socket_flags & (IOSOCKETFLAG_PENDING_BINDDNS | IOSOCKETFLAG_PENDING_DESTDNS)) == 0) {
691 iosocket_connect_finish(iosock);
696 struct IOSocket *iosocket_listen(const char *hostname, unsigned int port, iosocket_callback *callback) {
697 return iosocket_listen_flags(hostname, port, callback, (IOSOCKET_ADDR_IPV4 | IOSOCKET_ADDR_IPV6));
700 struct IOSocket *iosocket_listen_flags(const char *hostname, unsigned int port, iosocket_callback *callback, int flags) {
701 struct IOSocket *iodescriptor = calloc(1, sizeof(*iodescriptor));
703 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocket in %s:%d", __FILE__, __LINE__);
707 struct _IOSocket *iosock = _create_socket();
713 iodescriptor->iosocket = iosock;
714 iodescriptor->status = IOSOCKET_LISTENING;
715 iodescriptor->listening = 1;
716 iodescriptor->callback = callback;
717 iosock->parent = iodescriptor;
718 iosock->socket_flags |= IOSOCKETFLAG_PARENT_PUBLIC | IOSOCKETFLAG_LISTENING;
722 iodescriptor->ssl = 1;
723 iosock->socket_flags |= IOSOCKETFLAG_SSLSOCKET;
727 switch(iosocket_parse_address(hostname, &iosock->bind.addr, flags)) {
732 /* start dns lookup */
733 iosock->socket_flags |= IOSOCKETFLAG_PENDING_BINDDNS;
734 iosocket_lookup_hostname(iosock, hostname, flags, 1);
740 if((iosock->socket_flags & IOSOCKETFLAG_PENDING_BINDDNS) == 0) {
741 iosocket_listen_finish(iosock);
746 struct IOSocket *iosocket_listen_ssl(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iosocket_callback *callback) {
747 return iosocket_listen_ssl_flags(hostname, port, certfile, keyfile, callback, (IOSOCKET_ADDR_IPV4 | IOSOCKET_ADDR_IPV6));
750 struct IOSocket *iosocket_listen_ssl_flags(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iosocket_callback *callback, int flags) {
755 void iosocket_close(struct IOSocket *iosocket) {
756 struct _IOSocket *iosock = iosocket->iosocket;
758 iolog_trigger(IOLOG_WARNING, "called iosocket_close for destroyed IOSocket in %s:%d", __FILE__, __LINE__);
762 iosock->socket_flags |= IOSOCKETFLAG_SHUTDOWN;
764 if(iosock->writebuf.bufpos) {
765 //try to send everything before closing
769 flags = fcntl(iosock->fd, F_GETFL);
770 fcntl(iosock->fd, F_SETFL, flags & ~O_NONBLOCK);
771 flags = fcntl(iosock->fd, F_GETFD);
772 fcntl(iosock->fd, F_SETFD, flags|FD_CLOEXEC);
775 iosocket_deactivate(iosock);
777 iosocket_try_write(iosock);
780 if(iosock->sslnode) {
785 _free_socket(iosock);
786 iosocket->iosocket = NULL;
787 iosocket->status = IOSOCKET_CLOSED;
791 static int iosocket_try_write(struct _IOSocket *iosock) {
792 if(!iosock->writebuf.bufpos) return 0;
793 iolog_trigger(IOLOG_DEBUG, "write writebuf (%d bytes) to socket (fd: %d)", iosock->writebuf.bufpos, iosock->fd);
795 if(iosock->sslnode) {
796 /* res = iohandler_ssl_write(iofd, iofd->writebuf.buffer, iofd->writebuf.bufpos); */
799 res = send(iosock->fd, iosock->writebuf.buffer, iosock->writebuf.bufpos, 0);
801 if (errno != EAGAIN && errno != EWOULDBLOCK)
802 iolog_trigger(IOLOG_ERROR, "could not write to socket (fd: %d): %d - %s", iosock->fd, errno, strerror(errno));
806 iosock->writebuf.bufpos -= res;
807 if((iosock->socket_flags & (IOSOCKETFLAG_ACTIVE & IOSOCKETFLAG_SHUTDOWN)) == IOSOCKETFLAG_ACTIVE)
808 engine->update(iosock);
813 void iosocket_send(struct IOSocket *iosocket, const char *data, size_t datalen) {
814 struct _IOSocket *iosock = iosocket->iosocket;
816 iolog_trigger(IOLOG_WARNING, "called iosocket_close for destroyed IOSocket in %s:%d", __FILE__, __LINE__);
819 if(iosock->socket_flags & IOSOCKETFLAG_SHUTDOWN) {
820 iolog_trigger(IOLOG_ERROR, "could not write to socket (socket is closing)");
823 iolog_trigger(IOLOG_DEBUG, "add %d to writebuf (fd: %d): %s", datalen, iosock->fd, data);
824 if(iosock->writebuf.buflen < iosock->writebuf.bufpos + datalen) {
825 iolog_trigger(IOLOG_DEBUG, "increase writebuf (curr: %d) to %d (+%d bytes)", iosock->writebuf.buflen, iosock->writebuf.bufpos + datalen, (iosock->writebuf.bufpos + datalen - iosock->writebuf.buflen));
826 iosocket_increase_buffer(&iosock->writebuf, iosock->writebuf.bufpos + datalen);
827 if(iosock->writebuf.buflen < iosock->writebuf.bufpos + datalen) {
828 iolog_trigger(IOLOG_ERROR, "increase writebuf (curr: %d) to %d (+%d bytes) FAILED", iosock->writebuf.buflen, iosock->writebuf.bufpos + datalen, (iosock->writebuf.bufpos + datalen - iosock->writebuf.buflen));
832 memcpy(iosock->writebuf.buffer + iosock->writebuf.bufpos, data, datalen);
833 iosock->writebuf.bufpos += datalen;
834 if((iosock->socket_flags & IOSOCKETFLAG_ACTIVE))
835 engine->update(iosock);
838 void iosocket_write(struct IOSocket *iosocket, const char *line) {
839 size_t linelen = strlen(line);
840 iosocket_send(iosocket, line, linelen);
843 void iosocket_printf(struct IOSocket *iosocket, const char *text, ...) {
845 char sendBuf[IOSOCKET_PRINTF_LINE_LEN];
848 va_start(arg_list, text);
849 pos = vsnprintf(sendBuf, IOSOCKET_PRINTF_LINE_LEN - 2, text, arg_list);
851 if (pos < 0 || pos > (IOSOCKET_PRINTF_LINE_LEN - 2)) pos = IOSOCKET_PRINTF_LINE_LEN - 2;
853 sendBuf[pos+1] = '\0';
854 iosocket_send(iosocket, sendBuf, pos+1);
859 static void iosocket_trigger_event(struct IOSocketEvent *event) {
860 if(!event->socket->callback)
862 iolog_trigger(IOLOG_DEBUG, "triggering event");
863 event->socket->callback(event);
866 void iosocket_events_callback(struct _IOSocket *iosock, int readable, int writeable) {
867 if((iosock->socket_flags & IOSOCKETFLAG_PARENT_PUBLIC)) {
868 struct IOSocket *iosocket = iosock->parent;
869 struct IOSocketEvent callback_event;
870 callback_event.type = IOSOCKETEVENT_IGNORE;
871 callback_event.socket = iosocket;
873 if((iosock->socket_flags & IOSOCKETFLAG_SSL_HANDSHAKE)) {
875 } else if((iosock->socket_flags & IOSOCKETFLAG_LISTENING)) {
877 //new client connected
878 struct _IOSocket *new_iosock = iosocket_accept_client(iosock);
882 if(!(new_iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {
883 callback_event.type = IOSOCKETEVENT_ACCEPT;
884 callback_event.data.accept_socket = new_iosock->parent;
888 } else if((iosock->socket_flags & IOSOCKETFLAG_CONNECTING)) {
889 if(readable) { //could not connect
890 if((iosock->socket_flags & (IOSOCKETFLAG_IPV6SOCKET | IOSOCKETFLAG_RECONNECT_IPV4)) == (IOSOCKETFLAG_IPV6SOCKET | IOSOCKETFLAG_RECONNECT_IPV4)) {
891 iolog_trigger(IOLOG_DEBUG, "connecting to IPv6 host (%s) failed. trying to connect using IPv4.", iosock->dest.addrlookup->hostname);
892 iosocket_deactivate(iosock);
893 if(iosocket_lookup_apply(iosock, 1)) { //if ret=0 an error occured in iosocket_lookup_apply and we should stop here.
894 iosocket_connect_finish(iosock);
895 socket_lookup_clear(iosock);
898 callback_event.type = IOSOCKETEVENT_NOTCONNECTED;
900 socklen_t arglen = sizeof(callback_event.data.errid);
901 if (getsockopt(iosock->fd, SOL_SOCKET, SO_ERROR, &callback_event.data.errid, &arglen) < 0)
902 callback_event.data.errid = errno;
904 iosock->socket_flags |= IOSOCKETFLAG_DEAD;
906 } else if(writeable) { //connection established
907 iosocket->status = IOSOCKET_CONNECTED;
908 if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {
909 //TODO: SSL Handshake
913 callback_event.type = IOSOCKETEVENT_CONNECTED;
914 iosock->socket_flags &= ~IOSOCKETFLAG_CONNECTING;
915 socket_lookup_clear(iosock);
916 engine->update(iosock);
919 iosocket_increase_buffer(&iosock->readbuf, 1024);
924 if(iosock->readbuf.buflen - iosock->readbuf.bufpos >= 128)
925 iosocket_increase_buffer(&iosock->readbuf, iosock->readbuf.buflen + 1024);
926 if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {
929 bytes = recv(iosock->fd, iosock->readbuf.buffer + iosock->readbuf.bufpos, iosock->readbuf.buflen - iosock->readbuf.bufpos, 0);
932 if (errno != EAGAIN || errno != EWOULDBLOCK) {
933 iosock->socket_flags |= IOSOCKETFLAG_DEAD;
935 callback_event.type = IOSOCKETEVENT_CLOSED;
936 callback_event.data.errid = errno;
940 iolog_trigger(IOLOG_DEBUG, "received %d bytes (fd: %d). readbuf position: %d", bytes, iosock->fd, iosock->readbuf.bufpos);
941 iosock->readbuf.bufpos += bytes;
942 callback_event.type = IOSOCKETEVENT_RECV;
944 if(iosocket->parse_delimiter) {
945 int j, used_bytes = 0;
946 for(i = 0; i < iosock->readbuf.bufpos; i++) {
947 int is_delimiter = 0;
948 for(j = 0; j < IOSOCKET_PARSE_DELIMITERS_COUNT; j++) {
949 if(iosock->readbuf.buffer[i] == iosocket->delimiters[j]) {
955 iosock->readbuf.buffer[i] = 0;
956 callback_event.data.recv_str = iosock->readbuf.buffer + used_bytes;
957 iolog_trigger(IOLOG_DEBUG, "parsed line (%d bytes): %s", i - used_bytes, iosock->readbuf.buffer + used_bytes);
959 if(iosock->readbuf.buffer[i-1] != 0 || iosocket->parse_empty)
960 iosocket_trigger_event(&callback_event);
962 #ifdef IOSOCKET_PARSE_LINE_LIMIT
963 else if(i + 1 - used_bytes >= IOSOCKET_PARSE_LINE_LIMIT) {
964 iosock->readbuf.buffer[i] = 0;
965 callback_event.data.recv_str = iosock->readbuf.buffer + used_bytes;
966 iolog_trigger(IOLOG_DEBUG, "parsed and stripped line (%d bytes): %s", i - used_bytes, iosock->readbuf.buffer + used_bytes);
967 for(; i < iosock->readbuf.bufpos; i++) { //skip the rest of the line
969 if(iosock->readbuf.buffer[i] == iosocket->delimiters[j])
973 iosocket_trigger_event(&callback_event);
978 if(used_bytes == iosock->readbuf.bufpos) {
979 iosock->readbuf.bufpos = 0;
980 iolog_trigger(IOLOG_DEBUG, "readbuf fully processed (set buffer position to 0)");
982 iolog_trigger(IOLOG_DEBUG, "readbuf rest: %d bytes (used %d bytes)", iosock->readbuf.bufpos - used_bytes, used_bytes);
983 memmove(iosock->readbuf.buffer, iosock->readbuf.buffer + used_bytes, iosock->readbuf.bufpos - used_bytes);
984 iosock->readbuf.bufpos -= used_bytes;
987 callback_event.type = IOSOCKETEVENT_IGNORE;
989 callback_event.data.recv_buf = &iosock->readbuf;
994 bytes = iosocket_try_write(iosock);
996 iosock->socket_flags |= IOSOCKETFLAG_DEAD;
998 callback_event.type = IOSOCKETEVENT_CLOSED;
999 callback_event.data.errid = errno;
1004 if(callback_event.type != IOSOCKETEVENT_IGNORE)
1005 iosocket_trigger_event(&callback_event);
1006 if((iosock->socket_flags & IOSOCKETFLAG_DEAD))
1007 iosocket_close(iosocket);
1009 } else if((iosock->socket_flags & IOSOCKETFLAG_PARENT_DNSENGINE)) {
1010 //TODO: IODNS callback
1014 void iosocket_loop(int usec) {
1015 struct timeval timeout;
1016 timeout.tv_sec = usec / 1000000;
1017 timeout.tv_usec = usec % 1000000;
1018 engine->loop(&timeout);