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>
36 #include "compat/inet.h"
45 #define EWOULDBLOCK EAGAIN
48 struct _IOSocket *iosocket_first = NULL;
49 struct _IOSocket *iosocket_last = NULL;
51 struct IOEngine *engine = NULL;
53 static void iosocket_activate(struct _IOSocket *iosock);
54 static void iosocket_deactivate(struct _IOSocket *iosock);
55 static void iosocket_increase_buffer(struct IOSocketBuffer *iobuf, size_t required);
56 static int iosocket_parse_address(const char *hostname, struct IODNSAddress *addr, int records);
57 static int iosocket_lookup_hostname(struct _IOSocket *iosock, const char *hostname, int records, int bindaddr);
58 static int iosocket_lookup_apply(struct _IOSocket *iosock, int noip6);
59 static void socket_lookup_clear(struct _IOSocket *iosock);
60 static void iosocket_connect_finish(struct _IOSocket *iosock);
61 static void iosocket_listen_finish(struct _IOSocket *iosock);
62 static int iosocket_try_write(struct _IOSocket *iosock);
63 static void iosocket_trigger_event(struct IOSocketEvent *event);
66 static int close(int fd) {
67 return closesocket(fd);
71 static void iosockets_init_engine() {
73 if(!engine && engine_kevent.init && engine_kevent.init())
74 engine = &engine_kevent;
75 if(!engine && engine_epoll.init && engine_epoll.init())
76 engine = &engine_epoll;
77 if(!engine && engine_win32.init && engine_win32.init())
78 engine = &engine_win32;
81 if(engine_select.init())
82 engine = &engine_select;
84 iolog_trigger(IOLOG_FATAL, "found no useable IO engine");
88 iolog_trigger(IOLOG_DEBUG, "using %s IOSockets engine", engine->name);
91 void _init_sockets() {
96 iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
98 iolog_trigger(IOLOG_ERROR, "WSAStartup returned error code: %d", iResult);
102 iosockets_init_engine();
106 struct _IOSocket *_create_socket() {
107 struct _IOSocket *iosock = calloc(1, sizeof(*iosock));
109 iolog_trigger(IOLOG_ERROR, "could not allocate memory for _IOSocket in %s:%d", __FILE__, __LINE__);
113 iosocket_last->next = iosock;
115 iosocket_first = iosock;
116 iosock->prev = iosocket_last;
117 iosocket_last = iosock;
121 void _free_socket(struct _IOSocket *iosock) {
122 iosocket_deactivate(iosock);
124 iosock->prev->next = iosock->next;
126 iosocket_first = iosock->next;
128 iosock->next->prev = iosock->prev;
130 iosocket_last = iosock->prev;
132 if(iosock->bind.addr.addresslen)
133 free(iosock->bind.addr.address);
134 if(iosock->dest.addr.addresslen)
135 free(iosock->dest.addr.address);
136 if(iosock->bind.addrlookup || iosock->dest.addrlookup)
137 socket_lookup_clear(iosock);
138 if(iosock->readbuf.buffer)
139 free(iosock->readbuf.buffer);
140 if(iosock->writebuf.buffer)
141 free(iosock->writebuf.buffer);
146 static void iosocket_activate(struct _IOSocket *iosock) {
147 if((iosock->socket_flags & IOSOCKETFLAG_ACTIVE))
149 iosock->socket_flags |= IOSOCKETFLAG_ACTIVE;
153 static void iosocket_deactivate(struct _IOSocket *iosock) {
154 if(!(iosock->socket_flags & IOSOCKETFLAG_ACTIVE))
156 iosock->socket_flags &= ~IOSOCKETFLAG_ACTIVE;
157 engine->remove(iosock);
160 static void iosocket_increase_buffer(struct IOSocketBuffer *iobuf, size_t required) {
161 if(iobuf->buflen >= required) return;
164 new_buf = realloc(iobuf->buffer, required + 2);
166 new_buf = malloc(required + 2);
168 iobuf->buffer = new_buf;
169 iobuf->buflen = required;
173 static int iosocket_parse_address(const char *hostname, struct IODNSAddress *addr, int records) {
175 if((records & IOSOCKET_ADDR_IPV4)) {
176 struct sockaddr_in ip4addr;
177 ret = inet_pton(AF_INET, hostname, &(ip4addr.sin_addr));
179 addr->addresslen = sizeof(ip4addr);
180 addr->address = malloc(addr->addresslen);
182 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
185 memcpy(addr->address, &ip4addr, sizeof(ip4addr));
189 if((records & IOSOCKET_ADDR_IPV6)) {
190 struct sockaddr_in6 ip6addr;
191 ret = inet_pton(AF_INET6, hostname, &(ip6addr.sin6_addr));
193 addr->addresslen = sizeof(ip6addr);
194 addr->address = malloc(addr->addresslen);
196 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
199 memcpy(addr->address, &ip6addr, sizeof(ip6addr));
206 static int iosocket_lookup_hostname(struct _IOSocket *iosock, const char *hostname, int records, int bindaddr) {
207 struct IOSocketDNSLookup *lookup = calloc(1, sizeof(*lookup));
209 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocketDNSLookup in %s:%d", __FILE__, __LINE__);
213 struct _IODNSQuery *query = _create_dnsquery();
219 query->parent = lookup;
220 query->flags |= IODNSFLAG_PARENT_SOCKET;
221 lookup->iosocket = iosock;
222 lookup->query = query;
223 strncpy(lookup->hostname, hostname, sizeof(lookup->hostname));
224 lookup->hostname[sizeof(lookup->hostname)-1] = 0;
226 lookup->bindlookup = 1;
227 iosock->bind.addrlookup = lookup;
229 lookup->bindlookup = 0;
230 iosock->dest.addrlookup = lookup;
234 if((records & IOSOCKET_ADDR_IPV4))
235 dnsrecords |= IODNS_RECORD_A;
236 if((records & IOSOCKET_ADDR_IPV6))
237 dnsrecords |= IODNS_RECORD_AAAA;
239 query->request.host = strdup(hostname);
240 query->type = (dnsrecords & IODNS_FORWARD);
242 _start_dnsquery(query);
246 void iosocket_lookup_callback(struct IOSocketDNSLookup *lookup, struct IODNSEvent *event) {
247 lookup->query = NULL;
248 struct _IOSocket *iosock = lookup->iosocket;
252 if(event->type == IODNSEVENT_SUCCESS)
253 lookup->result = event->result;
255 lookup->result = NULL;
257 if(lookup->bindlookup) {
258 iosock->socket_flags &= ~IOSOCKETFLAG_PENDING_BINDDNS;
259 iosock->socket_flags |= IOSOCKETFLAG_DNSDONE_BINDDNS;
261 iosock->socket_flags &= ~IOSOCKETFLAG_PENDING_DESTDNS;
262 iosock->socket_flags |= IOSOCKETFLAG_DNSDONE_DESTDNS;
265 int dns_finished = 0;
266 if((iosock->socket_flags & (IOSOCKETFLAG_PENDING_BINDDNS | IOSOCKETFLAG_PENDING_DESTDNS)) == 0)
271 ret = iosocket_lookup_apply(iosock, 0);
272 if(ret) { //if ret=0 an error occured in iosocket_lookup_apply and we should stop here.
273 if((iosock->socket_flags & IOSOCKETFLAG_LISTENING)) {
274 socket_lookup_clear(iosock);
275 iosocket_listen_finish(iosock);
277 iosocket_connect_finish(iosock);
282 static int iosocket_lookup_apply(struct _IOSocket *iosock, int noip6) {
284 struct IOSocketDNSLookup *bind_lookup = ((iosock->socket_flags & IOSOCKETFLAG_DNSDONE_BINDDNS) ? iosock->bind.addrlookup : NULL);
285 struct IOSocketDNSLookup *dest_lookup = ((iosock->socket_flags & IOSOCKETFLAG_DNSDONE_DESTDNS) ? iosock->dest.addrlookup : NULL);
287 iolog_trigger(IOLOG_DEBUG, "all pending lookups finished. trying to apply lookup results...");
289 if(!bind_lookup && !dest_lookup) {
290 iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
291 sprintf(errbuf, "Internal Error");
292 iolog_trigger(IOLOG_ERROR, "trying to apply lookup results without any lookups processed in %s:%d", __FILE__, __LINE__);
293 goto iosocket_lookup_apply_end;
296 struct IODNSResult *result;
297 int bind_numip4 = 0, bind_numip6 = 0;
298 int dest_numip4 = 0, dest_numip6 = 0;
301 for(result = bind_lookup->result; result; result = result->next) {
302 if((result->type & IODNS_RECORD_A))
304 if((result->type & IODNS_RECORD_AAAA))
309 for(result = dest_lookup->result; result; result = result->next) {
310 if((result->type & IODNS_RECORD_A))
312 if((result->type & IODNS_RECORD_AAAA))
318 if(bind_lookup && (bind_numip6 == 0 && bind_numip4 == 0)) {
319 iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
320 sprintf(errbuf, "could not lookup bind address (%s)", bind_lookup->hostname);
321 goto iosocket_lookup_apply_end;
322 } else if(dest_lookup && (dest_numip6 == 0 && dest_numip4 == 0)) {
323 iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
324 sprintf(errbuf, "could not lookup destination address (%s)", dest_lookup->hostname);
325 goto iosocket_lookup_apply_end;
326 } else if(bind_lookup && dest_lookup) {
327 if(bind_numip6 > 0 && dest_numip6 > 0)
329 if(bind_numip4 > 0 && dest_numip4 > 0)
331 } else if(bind_lookup) {
336 } else if(dest_lookup) {
344 if(useip6 && !noip6) {
345 usetype = IODNS_RECORD_AAAA;
346 iosock->socket_flags |= IOSOCKETFLAG_IPV6SOCKET;
348 iosock->socket_flags |= IOSOCKETFLAG_RECONNECT_IPV4;
350 usetype = IODNS_RECORD_A;
351 iosock->socket_flags &= ~(IOSOCKETFLAG_IPV6SOCKET | IOSOCKETFLAG_RECONNECT_IPV4);
353 iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
354 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);
355 goto iosocket_lookup_apply_end;
358 #define IOSOCKET_APPLY_COPYADDR(type) \
359 iosock->type.addr.addresslen = result->result.addr.addresslen; \
360 iosock->type.addr.address = malloc(result->result.addr.addresslen); \
361 if(!iosock->type.addr.address) { \
362 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__); \
363 iosock->type.addr.addresslen = 0; \
364 iosock->socket_flags |= IOSOCKETFLAG_DNSERROR; \
365 sprintf(errbuf, "could not allocate memory for dns information"); \
366 goto iosocket_lookup_apply_end; \
368 memcpy(iosock->type.addr.address, result->result.addr.address, result->result.addr.addresslen);
372 int usenum = ((usetype == IODNS_RECORD_AAAA) ? bind_numip6 : bind_numip4);
373 usenum = rand() % usenum;
374 for(result = bind_lookup->result; result; result = result->next) {
375 if((result->type & usetype)) {
377 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));
378 iolog_trigger(IOLOG_DEBUG, "using IPv%s Address (%s) as bind address", ((usetype == IODNS_RECORD_AAAA) ? "6" : "4"), errbuf);
379 IOSOCKET_APPLY_COPYADDR(bind)
386 iosock->bind.addr.addresslen = 0;
389 int usenum = ((usetype == IODNS_RECORD_AAAA) ? dest_numip6 : dest_numip4);
390 usenum = rand() % usenum;
391 for(result = dest_lookup->result; result; result = result->next) {
392 if((result->type & usetype)) {
394 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));
395 iolog_trigger(IOLOG_DEBUG, "using IPv%s Address (%s) as dest address", ((usetype == IODNS_RECORD_AAAA) ? "6" : "4"), errbuf);
396 IOSOCKET_APPLY_COPYADDR(dest)
403 iosock->dest.addr.addresslen = 0;
405 iosocket_lookup_apply_end:
407 if((iosock->socket_flags & IOSOCKETFLAG_DNSERROR)) {
408 // TODO: trigger error
409 iolog_trigger(IOLOG_ERROR, "error while trying to apply dns lookup information: %s", errbuf);
411 if((iosock->socket_flags & IOSOCKETFLAG_PARENT_PUBLIC)) {
413 struct IOSocket *iosocket = iosock->parent;
415 struct IOSocketEvent callback_event;
416 callback_event.type = IOSOCKETEVENT_DNSFAILED;
417 callback_event.socket = iosocket;
418 callback_event.data.recv_str = errbuf;
419 iosocket_trigger_event(&callback_event);
421 iosocket_close(iosocket);
423 // TODO: IODNS Callback
430 static void socket_lookup_clear(struct _IOSocket *iosock) {
431 struct IOSocketDNSLookup *bind_lookup = ((iosock->socket_flags & IOSOCKETFLAG_DNSDONE_BINDDNS) ? iosock->bind.addrlookup : NULL);
432 struct IOSocketDNSLookup *dest_lookup = ((iosock->socket_flags & IOSOCKETFLAG_DNSDONE_DESTDNS) ? iosock->dest.addrlookup : NULL);
434 if(bind_lookup->result)
435 iodns_free_result(bind_lookup->result);
437 iosock->bind.addrlookup = NULL;
440 if(dest_lookup->result)
441 iodns_free_result(dest_lookup->result);
443 iosock->dest.addrlookup = NULL;
447 static void iosocket_prepare_fd(int sockfd) {
450 #if defined(SO_NOSIGPIPE)
453 setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
456 signal(SIGPIPE, SIG_IGN);
460 // make sockfd unblocking
464 fcntl_flags = fcntl(sockfd, F_GETFL);
465 fcntl(sockfd, F_SETFL, fcntl_flags|O_NONBLOCK);
466 fcntl_flags = fcntl(sockfd, F_GETFD);
467 fcntl(sockfd, F_SETFD, fcntl_flags|FD_CLOEXEC);
471 unsigned long ulong = 1;
472 ioctlsocket(sockfd, FIONBIO, &ulong);
477 static void iosocket_connect_finish(struct _IOSocket *iosock) {
479 if((iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET))
480 sockfd = socket(AF_INET6, SOCK_STREAM, 0);
482 sockfd = socket(AF_INET, SOCK_STREAM, 0);
484 iolog_trigger(IOLOG_ERROR, "could not create socket in %s:%d", __FILE__, __LINE__);
485 // TODO: trigger error
490 // set port and bind address
491 if((iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET)) {
492 struct sockaddr_in6 *ip6 = (void*) iosock->dest.addr.address;
493 ip6->sin6_family = AF_INET6;
494 ip6->sin6_port = htons(iosock->port);
496 if(iosock->bind.addr.addresslen) {
497 struct sockaddr_in6 *ip6bind = (void*) iosock->bind.addr.address;
498 ip6bind->sin6_family = AF_INET6;
499 ip6bind->sin6_port = htons(0);
501 bind(sockfd, (struct sockaddr*)ip6bind, sizeof(*ip6bind));
504 struct sockaddr_in *ip4 = (void*) iosock->dest.addr.address;
505 ip4->sin_family = AF_INET;
506 ip4->sin_port = htons(iosock->port);
508 if(iosock->bind.addr.addresslen) {
509 struct sockaddr_in *ip4bind = (void*) iosock->bind.addr.address;
510 ip4bind->sin_family = AF_INET;
511 ip4bind->sin_port = htons(0);
513 bind(sockfd, (struct sockaddr*)ip4bind, sizeof(*ip4bind));
517 iosocket_prepare_fd(sockfd);
519 int ret = connect(sockfd, iosock->dest.addr.address, iosock->dest.addr.addresslen); //returns EINPROGRESS here (nonblocking)
520 iolog_trigger(IOLOG_DEBUG, "connecting socket (connect: %d)", ret);
523 iosock->socket_flags |= IOSOCKETFLAG_CONNECTING;
525 iosocket_activate(iosock);
528 static void iosocket_listen_finish(struct _IOSocket *iosock) {
530 if((iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET))
531 sockfd = socket(AF_INET6, SOCK_STREAM, 0);
533 sockfd = socket(AF_INET, SOCK_STREAM, 0);
535 iolog_trigger(IOLOG_ERROR, "could not create socket in %s:%d", __FILE__, __LINE__);
536 // TODO: trigger error
541 // set port and bind address
542 if((iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET)) {
543 struct sockaddr_in6 *ip6bind = (void*) iosock->bind.addr.address;
544 ip6bind->sin6_family = AF_INET6;
545 ip6bind->sin6_port = htons(0);
548 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
550 bind(sockfd, (struct sockaddr*)ip6bind, sizeof(*ip6bind));
552 struct sockaddr_in *ip4bind = (void*) iosock->bind.addr.address;
553 ip4bind->sin_family = AF_INET;
554 ip4bind->sin_port = htons(0);
557 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
559 bind(sockfd, (struct sockaddr*)ip4bind, sizeof(*ip4bind));
562 iosocket_prepare_fd(sockfd);
567 iosocket_activate(iosock);
570 struct _IOSocket *iosocket_accept_client(struct _IOSocket *iosock) {
571 struct IOSocket *new_iosocket = calloc(1, sizeof(*new_iosocket));
573 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocket in %s:%d", __FILE__, __LINE__);
574 close(accept(iosock->fd, NULL, 0)); // simply drop connection
577 struct _IOSocket *new_iosock = _create_socket();
580 close(accept(iosock->fd, NULL, 0)); // simply drop connection
583 new_iosocket->iosocket = new_iosock;
584 new_iosocket->status = IOSOCKET_CONNECTED;
585 new_iosock->parent = new_iosocket;
586 new_iosock->socket_flags |= IOSOCKETFLAG_PARENT_PUBLIC | IOSOCKETFLAG_INCOMING | (iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET);
588 struct sockaddr_storage addr;
589 socklen_t addrlen = sizeof(addr);
592 new_iosock->fd = accept(iosock->fd, (struct sockaddr *)&addr, &addrlen);
594 //copy remote address
595 new_iosock->dest.addr.address = malloc(addrlen);
596 if(!new_iosock->dest.addr.address) {
597 close(new_iosock->fd);
600 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
603 memcpy(new_iosock->dest.addr.address, &addr, addrlen);
604 new_iosock->dest.addr.addresslen = addrlen;
607 new_iosock->bind.addr.address = malloc(iosock->bind.addr.addresslen);
608 if(!new_iosock->bind.addr.address) {
609 close(new_iosock->fd);
612 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
615 memcpy(new_iosock->bind.addr.address, iosock->bind.addr.address, iosock->bind.addr.addresslen);
616 new_iosock->bind.addr.addresslen = iosock->bind.addr.addresslen;
618 //prepare new socket fd
619 iosocket_prepare_fd(new_iosock->fd);
621 if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {
622 new_iosocket->ssl = 1;
623 new_iosock->socket_flags |= IOSOCKETFLAG_SSLSOCKET;
624 //TODO: SSL Handshake
627 iosocket_activate(new_iosock);
631 /* public functions */
633 struct IOSocket *iosocket_connect(const char *hostname, unsigned int port, int ssl, const char *bindhost, iosocket_callback *callback) {
634 return iosocket_connect_flags(hostname, port, ssl, bindhost, callback, (IOSOCKET_ADDR_IPV4 | IOSOCKET_ADDR_IPV6));
637 struct IOSocket *iosocket_connect_flags(const char *hostname, unsigned int port, int ssl, const char *bindhost, iosocket_callback *callback, int flags) {
638 struct IOSocket *iodescriptor = calloc(1, sizeof(*iodescriptor));
640 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocket in %s:%d", __FILE__, __LINE__);
644 struct _IOSocket *iosock = _create_socket();
650 iodescriptor->iosocket = iosock;
651 iodescriptor->status = IOSOCKET_CONNECTING;
652 iodescriptor->callback = callback;
653 iosock->parent = iodescriptor;
654 iosock->socket_flags |= IOSOCKETFLAG_PARENT_PUBLIC;
657 iodescriptor->ssl = 1;
658 iosock->socket_flags |= IOSOCKETFLAG_SSLSOCKET;
662 switch(iosocket_parse_address(bindhost, &iosock->bind.addr, flags)) {
667 /* start dns lookup */
668 iosock->socket_flags |= IOSOCKETFLAG_PENDING_BINDDNS;
669 iosocket_lookup_hostname(iosock, bindhost, flags, 1);
676 switch(iosocket_parse_address(hostname, &iosock->dest.addr, flags)) {
681 /* start dns lookup */
682 iosock->socket_flags |= IOSOCKETFLAG_PENDING_DESTDNS;
683 iosocket_lookup_hostname(iosock, hostname, flags, 0);
689 if((iosock->socket_flags & (IOSOCKETFLAG_PENDING_BINDDNS | IOSOCKETFLAG_PENDING_DESTDNS)) == 0) {
690 iosocket_connect_finish(iosock);
695 struct IOSocket *iosocket_listen(const char *hostname, unsigned int port, iosocket_callback *callback) {
696 return iosocket_listen_flags(hostname, port, callback, (IOSOCKET_ADDR_IPV4 | IOSOCKET_ADDR_IPV6));
699 struct IOSocket *iosocket_listen_flags(const char *hostname, unsigned int port, iosocket_callback *callback, int flags) {
700 struct IOSocket *iodescriptor = calloc(1, sizeof(*iodescriptor));
702 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocket in %s:%d", __FILE__, __LINE__);
706 struct _IOSocket *iosock = _create_socket();
712 iodescriptor->iosocket = iosock;
713 iodescriptor->status = IOSOCKET_LISTENING;
714 iodescriptor->listening = 1;
715 iodescriptor->callback = callback;
716 iosock->parent = iodescriptor;
717 iosock->socket_flags |= IOSOCKETFLAG_PARENT_PUBLIC | IOSOCKETFLAG_LISTENING;
721 iodescriptor->ssl = 1;
722 iosock->socket_flags |= IOSOCKETFLAG_SSLSOCKET;
726 switch(iosocket_parse_address(hostname, &iosock->bind.addr, flags)) {
731 /* start dns lookup */
732 iosock->socket_flags |= IOSOCKETFLAG_PENDING_BINDDNS;
733 iosocket_lookup_hostname(iosock, hostname, flags, 1);
739 if((iosock->socket_flags & IOSOCKETFLAG_PENDING_BINDDNS) == 0) {
740 iosocket_listen_finish(iosock);
745 struct IOSocket *iosocket_listen_ssl(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iosocket_callback *callback) {
746 return iosocket_listen_ssl_flags(hostname, port, certfile, keyfile, callback, (IOSOCKET_ADDR_IPV4 | IOSOCKET_ADDR_IPV6));
749 struct IOSocket *iosocket_listen_ssl_flags(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iosocket_callback *callback, int flags) {
754 void iosocket_close(struct IOSocket *iosocket) {
755 struct _IOSocket *iosock = iosocket->iosocket;
757 iolog_trigger(IOLOG_WARNING, "called iosocket_close for destroyed IOSocket in %s:%d", __FILE__, __LINE__);
761 iosock->socket_flags |= IOSOCKETFLAG_SHUTDOWN;
763 if(iosock->writebuf.bufpos) {
764 //try to send everything before closing
768 flags = fcntl(iosock->fd, F_GETFL);
769 fcntl(iosock->fd, F_SETFL, flags & ~O_NONBLOCK);
770 flags = fcntl(iosock->fd, F_GETFD);
771 fcntl(iosock->fd, F_SETFD, flags|FD_CLOEXEC);
774 iosocket_deactivate(iosock);
776 iosocket_try_write(iosock);
779 if(iosock->sslnode) {
784 _free_socket(iosock);
785 iosocket->iosocket = NULL;
786 iosocket->status = IOSOCKET_CLOSED;
790 static int iosocket_try_write(struct _IOSocket *iosock) {
791 if(!iosock->writebuf.bufpos) return 0;
792 iolog_trigger(IOLOG_DEBUG, "write writebuf (%d bytes) to socket (fd: %d)", iosock->writebuf.bufpos, iosock->fd);
794 if(iosock->sslnode) {
795 /* res = iohandler_ssl_write(iofd, iofd->writebuf.buffer, iofd->writebuf.bufpos); */
798 res = send(iosock->fd, iosock->writebuf.buffer, iosock->writebuf.bufpos, 0);
800 if (errno != EAGAIN && errno != EWOULDBLOCK)
801 iolog_trigger(IOLOG_ERROR, "could not write to socket (fd: %d): %d - %s", iosock->fd, errno, strerror(errno));
805 iosock->writebuf.bufpos -= res;
806 if((iosock->socket_flags & (IOSOCKETFLAG_ACTIVE & IOSOCKETFLAG_SHUTDOWN)) == IOSOCKETFLAG_ACTIVE)
807 engine->update(iosock);
812 void iosocket_send(struct IOSocket *iosocket, const char *data, size_t datalen) {
813 struct _IOSocket *iosock = iosocket->iosocket;
815 iolog_trigger(IOLOG_WARNING, "called iosocket_close for destroyed IOSocket in %s:%d", __FILE__, __LINE__);
818 if(iosock->socket_flags & IOSOCKETFLAG_SHUTDOWN) {
819 iolog_trigger(IOLOG_ERROR, "could not write to socket (socket is closing)");
822 iolog_trigger(IOLOG_DEBUG, "add %d to writebuf (fd: %d): %s", datalen, iosock->fd, data);
823 if(iosock->writebuf.buflen < iosock->writebuf.bufpos + datalen) {
824 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));
825 iosocket_increase_buffer(&iosock->writebuf, iosock->writebuf.bufpos + datalen);
826 if(iosock->writebuf.buflen < iosock->writebuf.bufpos + datalen) {
827 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));
831 memcpy(iosock->writebuf.buffer + iosock->writebuf.bufpos, data, datalen);
832 iosock->writebuf.bufpos += datalen;
833 if((iosock->socket_flags & IOSOCKETFLAG_ACTIVE))
834 engine->update(iosock);
837 void iosocket_write(struct IOSocket *iosocket, const char *line) {
838 size_t linelen = strlen(line);
839 iosocket_send(iosocket, line, linelen);
842 void iosocket_printf(struct IOSocket *iosocket, const char *text, ...) {
844 char sendBuf[IOSOCKET_PRINTF_LINE_LEN];
847 va_start(arg_list, text);
848 pos = vsnprintf(sendBuf, IOSOCKET_PRINTF_LINE_LEN - 2, text, arg_list);
850 if (pos < 0 || pos > (IOSOCKET_PRINTF_LINE_LEN - 2)) pos = IOSOCKET_PRINTF_LINE_LEN - 2;
852 sendBuf[pos+1] = '\0';
853 iosocket_send(iosocket, sendBuf, pos+1);
858 static void iosocket_trigger_event(struct IOSocketEvent *event) {
859 if(!event->socket->callback)
861 iolog_trigger(IOLOG_DEBUG, "triggering event");
862 event->socket->callback(event);
865 void iosocket_events_callback(struct _IOSocket *iosock, int readable, int writeable) {
866 if((iosock->socket_flags & IOSOCKETFLAG_PARENT_PUBLIC)) {
867 struct IOSocket *iosocket = iosock->parent;
868 struct IOSocketEvent callback_event;
869 callback_event.type = IOSOCKETEVENT_IGNORE;
870 callback_event.socket = iosocket;
872 if((iosock->socket_flags & IOSOCKETFLAG_SSL_HANDSHAKE)) {
874 } else if((iosock->socket_flags & IOSOCKETFLAG_LISTENING)) {
876 //new client connected
877 struct _IOSocket *new_iosock = iosocket_accept_client(iosock);
881 if(!(new_iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {
882 callback_event.type = IOSOCKETEVENT_ACCEPT;
883 callback_event.data.accept_socket = new_iosock->parent;
887 } else if((iosock->socket_flags & IOSOCKETFLAG_CONNECTING)) {
888 if(readable) { //could not connect
889 if((iosock->socket_flags & (IOSOCKETFLAG_IPV6SOCKET | IOSOCKETFLAG_RECONNECT_IPV4)) == (IOSOCKETFLAG_IPV6SOCKET | IOSOCKETFLAG_RECONNECT_IPV4)) {
890 iolog_trigger(IOLOG_DEBUG, "connecting to IPv6 host (%s) failed. trying to connect using IPv4.", iosock->dest.addrlookup->hostname);
891 iosocket_deactivate(iosock);
892 if(iosocket_lookup_apply(iosock, 1)) { //if ret=0 an error occured in iosocket_lookup_apply and we should stop here.
893 iosocket_connect_finish(iosock);
894 socket_lookup_clear(iosock);
897 callback_event.type = IOSOCKETEVENT_NOTCONNECTED;
899 socklen_t arglen = sizeof(callback_event.data.errid);
900 if (getsockopt(iosock->fd, SOL_SOCKET, SO_ERROR, &callback_event.data.errid, &arglen) < 0)
901 callback_event.data.errid = errno;
903 iosock->socket_flags |= IOSOCKETFLAG_DEAD;
905 } else if(writeable) { //connection established
906 iosocket->status = IOSOCKET_CONNECTED;
907 if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {
908 //TODO: SSL Handshake
912 callback_event.type = IOSOCKETEVENT_CONNECTED;
913 iosock->socket_flags &= ~IOSOCKETFLAG_CONNECTING;
914 socket_lookup_clear(iosock);
915 engine->update(iosock);
918 iosocket_increase_buffer(&iosock->readbuf, 1024);
923 if(iosock->readbuf.buflen - iosock->readbuf.bufpos >= 128)
924 iosocket_increase_buffer(&iosock->readbuf, iosock->readbuf.buflen + 1024);
925 if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {
928 bytes = recv(iosock->fd, iosock->readbuf.buffer + iosock->readbuf.bufpos, iosock->readbuf.buflen - iosock->readbuf.bufpos, 0);
931 if (errno != EAGAIN || errno != EWOULDBLOCK) {
932 iosock->socket_flags |= IOSOCKETFLAG_DEAD;
934 callback_event.type = IOSOCKETEVENT_CLOSED;
935 callback_event.data.errid = errno;
939 iolog_trigger(IOLOG_DEBUG, "received %d bytes (fd: %d). readbuf position: %d", bytes, iosock->fd, iosock->readbuf.bufpos);
940 iosock->readbuf.bufpos += bytes;
941 callback_event.type = IOSOCKETEVENT_RECV;
943 if(iosocket->parse_delimiter) {
944 int j, used_bytes = 0;
945 for(i = 0; i < iosock->readbuf.bufpos; i++) {
946 int is_delimiter = 0;
947 for(j = 0; j < IOSOCKET_PARSE_DELIMITERS_COUNT; j++) {
948 if(iosock->readbuf.buffer[i] == iosocket->delimiters[j]) {
954 iosock->readbuf.buffer[i] = 0;
955 callback_event.data.recv_str = iosock->readbuf.buffer + used_bytes;
956 iolog_trigger(IOLOG_DEBUG, "parsed line (%d bytes): %s", i - used_bytes, iosock->readbuf.buffer + used_bytes);
958 if(iosock->readbuf.buffer[i-1] != 0 || iosocket->parse_empty)
959 iosocket_trigger_event(&callback_event);
961 #ifdef IOSOCKET_PARSE_LINE_LIMIT
962 else if(i + 1 - used_bytes >= IOSOCKET_PARSE_LINE_LIMIT) {
963 iosock->readbuf.buffer[i] = 0;
964 callback_event.data.recv_str = iosock->readbuf.buffer + used_bytes;
965 iolog_trigger(IOLOG_DEBUG, "parsed and stripped line (%d bytes): %s", i - used_bytes, iosock->readbuf.buffer + used_bytes);
966 for(; i < iosock->readbuf.bufpos; i++) { //skip the rest of the line
968 if(iosock->readbuf.buffer[i] == iosocket->delimiters[j])
972 iosocket_trigger_event(&callback_event);
977 if(used_bytes == iosock->readbuf.bufpos) {
978 iosock->readbuf.bufpos = 0;
979 iolog_trigger(IOLOG_DEBUG, "readbuf fully processed (set buffer position to 0)");
981 iolog_trigger(IOLOG_DEBUG, "readbuf rest: %d bytes (used %d bytes)", iosock->readbuf.bufpos - used_bytes, used_bytes);
982 memmove(iosock->readbuf.buffer, iosock->readbuf.buffer + used_bytes, iosock->readbuf.bufpos - used_bytes);
983 iosock->readbuf.bufpos -= used_bytes;
986 callback_event.type = IOSOCKETEVENT_IGNORE;
988 callback_event.data.recv_buf = &iosock->readbuf;
993 bytes = iosocket_try_write(iosock);
995 iosock->socket_flags |= IOSOCKETFLAG_DEAD;
997 callback_event.type = IOSOCKETEVENT_CLOSED;
998 callback_event.data.errid = errno;
1003 if(callback_event.type != IOSOCKETEVENT_IGNORE)
1004 iosocket_trigger_event(&callback_event);
1005 if((iosock->socket_flags & IOSOCKETFLAG_DEAD))
1006 iosocket_close(iosocket);
1008 } else if((iosock->socket_flags & IOSOCKETFLAG_PARENT_DNSENGINE)) {
1009 //TODO: IODNS callback
1013 void iosocket_loop(int usec) {
1014 struct timeval timeout;
1015 timeout.tv_sec = usec / 1000000;
1016 timeout.tv_usec = usec % 1000000;
1017 engine->loop(&timeout);