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 iosocket_connect_finish(struct _IOSocket *iosock);
60 static void iosocket_listen_finish(struct _IOSocket *iosock);
61 static int iosocket_try_write(struct _IOSocket *iosock);
64 static int close(int fd) {
65 return closesocket(fd);
69 static void iosockets_init_engine() {
71 if(!engine && engine_kevent.init && engine_kevent.init())
72 engine = &engine_kevent;
73 if(!engine && engine_epoll.init && engine_epoll.init())
74 engine = &engine_epoll;
75 if(!engine && engine_win32.init && engine_win32.init())
76 engine = &engine_win32;
79 if(engine_select.init())
80 engine = &engine_select;
82 iolog_trigger(IOLOG_FATAL, "found no useable IO engine");
86 iolog_trigger(IOLOG_DEBUG, "using %s IOSockets engine", engine->name);
89 void _init_sockets() {
94 iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
96 iolog_trigger(IOLOG_ERROR, "WSAStartup returned error code: %d", iResult);
100 iosockets_init_engine();
104 struct _IOSocket *_create_socket() {
105 struct _IOSocket *iosock = calloc(1, sizeof(*iosock));
107 iolog_trigger(IOLOG_ERROR, "could not allocate memory for _IOSocket in %s:%d", __FILE__, __LINE__);
111 iosocket_last->next = iosock;
113 iosocket_first = iosock;
114 iosock->prev = iosocket_last;
115 iosocket_last = iosock;
119 void _free_socket(struct _IOSocket *iosock) {
120 iosocket_deactivate(iosock);
122 iosock->prev->next = iosock->next;
124 iosocket_first = iosock->next;
126 iosock->next->prev = iosock->prev;
128 iosocket_last = iosock->prev;
130 if(iosock->bind.addr.addresslen)
131 free(iosock->bind.addr.address);
132 if(iosock->dest.addr.addresslen)
133 free(iosock->dest.addr.address);
134 if(iosock->readbuf.buffer)
135 free(iosock->readbuf.buffer);
136 if(iosock->writebuf.buffer)
137 free(iosock->writebuf.buffer);
142 static void iosocket_activate(struct _IOSocket *iosock) {
143 if((iosock->socket_flags & IOSOCKETFLAG_ACTIVE))
145 iosock->socket_flags |= IOSOCKETFLAG_ACTIVE;
149 static void iosocket_deactivate(struct _IOSocket *iosock) {
150 if(!(iosock->socket_flags & IOSOCKETFLAG_ACTIVE))
152 iosock->socket_flags &= ~IOSOCKETFLAG_ACTIVE;
153 engine->remove(iosock);
156 static void iosocket_increase_buffer(struct IOSocketBuffer *iobuf, size_t required) {
157 if(iobuf->buflen >= required) return;
160 new_buf = realloc(iobuf->buffer, required + 2);
162 new_buf = malloc(required + 2);
164 iobuf->buffer = new_buf;
165 iobuf->buflen = required;
169 static int iosocket_parse_address(const char *hostname, struct IODNSAddress *addr, int records) {
171 if((records & IOSOCKET_ADDR_IPV4)) {
172 struct sockaddr_in ip4addr;
173 ret = inet_pton(AF_INET, hostname, &(ip4addr.sin_addr));
175 addr->addresslen = sizeof(ip4addr);
176 addr->address = malloc(addr->addresslen);
178 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
181 memcpy(addr->address, &ip4addr, sizeof(ip4addr));
185 if((records & IOSOCKET_ADDR_IPV6)) {
186 struct sockaddr_in6 ip6addr;
187 ret = inet_pton(AF_INET6, hostname, &(ip6addr.sin6_addr));
189 addr->addresslen = sizeof(ip6addr);
190 addr->address = malloc(addr->addresslen);
192 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
195 memcpy(addr->address, &ip6addr, sizeof(ip6addr));
202 static int iosocket_lookup_hostname(struct _IOSocket *iosock, const char *hostname, int records, int bindaddr) {
203 struct IOSocketDNSLookup *lookup = calloc(1, sizeof(*lookup));
205 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocketDNSLookup in %s:%d", __FILE__, __LINE__);
209 struct _IODNSQuery *query = _create_dnsquery();
215 query->parent = lookup;
216 query->flags |= IODNSFLAG_PARENT_SOCKET;
217 lookup->iosocket = iosock;
218 lookup->query = query;
219 strncpy(lookup->hostname, hostname, sizeof(lookup->hostname));
220 lookup->hostname[sizeof(lookup->hostname)-1] = 0;
222 lookup->bindlookup = 1;
223 iosock->bind.addrlookup = lookup;
225 lookup->bindlookup = 0;
226 iosock->dest.addrlookup = lookup;
230 if((records & IOSOCKET_ADDR_IPV4))
231 dnsrecords |= IODNS_RECORD_A;
232 if((records & IOSOCKET_ADDR_IPV6))
233 dnsrecords |= IODNS_RECORD_AAAA;
235 query->request.host = strdup(hostname);
236 query->type = (dnsrecords & IODNS_FORWARD);
238 _start_dnsquery(query);
242 void iosocket_lookup_callback(struct IOSocketDNSLookup *lookup, struct IODNSEvent *event) {
243 lookup->query = NULL;
244 struct _IOSocket *iosock = lookup->iosocket;
248 if(event->type == IODNSEVENT_SUCCESS)
249 lookup->result = event->result;
251 lookup->result = NULL;
253 if(lookup->bindlookup) {
254 iosock->socket_flags &= ~IOSOCKETFLAG_PENDING_BINDDNS;
255 iosock->socket_flags |= IOSOCKETFLAG_DNSDONE_BINDDNS;
257 iosock->socket_flags &= ~IOSOCKETFLAG_PENDING_DESTDNS;
258 iosock->socket_flags |= IOSOCKETFLAG_DNSDONE_DESTDNS;
261 int dns_finished = 0;
262 if((iosock->socket_flags & (IOSOCKETFLAG_PENDING_BINDDNS | IOSOCKETFLAG_PENDING_DESTDNS)) == 0)
267 ret = iosocket_lookup_apply(iosock, 0);
268 if(ret) { //if ret=0 an error occured in iosocket_lookup_apply and we should stop here.
269 if((iosock->socket_flags & IOSOCKETFLAG_LISTENING))
270 iosocket_listen_finish(iosock);
272 iosocket_connect_finish(iosock);
277 static int iosocket_lookup_apply(struct _IOSocket *iosock, int noip6) {
279 struct IOSocketDNSLookup *bind_lookup = ((iosock->socket_flags & IOSOCKETFLAG_DNSDONE_BINDDNS) ? iosock->bind.addrlookup : NULL);
280 struct IOSocketDNSLookup *dest_lookup = ((iosock->socket_flags & IOSOCKETFLAG_DNSDONE_DESTDNS) ? iosock->dest.addrlookup : NULL);
282 iolog_trigger(IOLOG_DEBUG, "all pending lookups finished. trying to apply lookup results...");
284 if(!bind_lookup && !dest_lookup) {
285 iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
286 sprintf(errbuf, "Internal Error");
287 iolog_trigger(IOLOG_ERROR, "trying to apply lookup results without any lookups processed in %s:%d", __FILE__, __LINE__);
288 goto iosocket_lookup_clear;
291 struct IODNSResult *result;
292 int bind_numip4 = 0, bind_numip6 = 0;
293 int dest_numip4 = 0, dest_numip6 = 0;
296 for(result = bind_lookup->result; result; result = result->next) {
297 if((result->type & IODNS_RECORD_A))
299 if((result->type & IODNS_RECORD_AAAA))
304 for(result = dest_lookup->result; result; result = result->next) {
305 if((result->type & IODNS_RECORD_A))
307 if((result->type & IODNS_RECORD_AAAA))
313 if(bind_lookup && (bind_numip6 == 0 && bind_numip4 == 0)) {
314 iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
315 sprintf(errbuf, "could not lookup bind address (%s)", bind_lookup->hostname);
316 goto iosocket_lookup_clear;
317 } else if(dest_lookup && (dest_numip6 == 0 && dest_numip4 == 0)) {
318 iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
319 sprintf(errbuf, "could not lookup destination address (%s)", dest_lookup->hostname);
320 goto iosocket_lookup_clear;
321 } else if(bind_lookup && dest_lookup) {
322 if(bind_numip6 > 0 && dest_numip6 > 0)
324 else if(bind_numip4 > 0 && dest_numip4 > 0)
327 iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
328 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);
329 goto iosocket_lookup_clear;
331 } else if(bind_lookup) {
336 } else if(dest_lookup) {
345 usetype = IODNS_RECORD_AAAA;
346 iosock->socket_flags |= IOSOCKETFLAG_IPV6SOCKET;
348 usetype = IODNS_RECORD_A;
350 //should already be handled
353 #define IOSOCKET_APPLY_COPYADDR(type) \
354 iosock->type.addr.addresslen = result->result.addr.addresslen; \
355 iosock->type.addr.address = malloc(result->result.addr.addresslen); \
356 if(!iosock->type.addr.address) { \
357 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__); \
358 iosock->type.addr.addresslen = 0; \
359 iosock->socket_flags |= IOSOCKETFLAG_DNSERROR; \
360 sprintf(errbuf, "could not allocate memory for dns information"); \
361 goto iosocket_lookup_clear; \
363 memcpy(iosock->type.addr.address, result->result.addr.address, result->result.addr.addresslen);
367 int usenum = (useip6 ? bind_numip6 : bind_numip4);
368 usenum = rand() % usenum;
369 for(result = bind_lookup->result; result; result = result->next) {
370 if((result->type & usetype)) {
372 inet_ntop((useip6 ? AF_INET6 : AF_INET), (useip6 ? (void *)(&((struct sockaddr_in6 *)result->result.addr.address)->sin6_addr) : (void *)(&((struct sockaddr_in *)result->result.addr.address)->sin_addr)), errbuf, sizeof(errbuf));
373 iolog_trigger(IOLOG_DEBUG, "using IPv%s Address (%s) as bind address", (useip6 ? "6" : "4"), errbuf);
374 IOSOCKET_APPLY_COPYADDR(bind)
381 iosock->bind.addr.addresslen = 0;
384 int usenum = (useip6 ? dest_numip6 : dest_numip4);
385 usenum = rand() % usenum;
386 for(result = dest_lookup->result; result; result = result->next) {
387 if((result->type & usetype)) {
389 inet_ntop((useip6 ? AF_INET6 : AF_INET), (useip6 ? (void *)(&((struct sockaddr_in6 *)result->result.addr.address)->sin6_addr) : (void *)(&((struct sockaddr_in *)result->result.addr.address)->sin_addr)), errbuf, sizeof(errbuf));
390 iolog_trigger(IOLOG_DEBUG, "using IPv%s Address (%s) as dest address", (useip6 ? "6" : "4"), errbuf);
391 IOSOCKET_APPLY_COPYADDR(dest)
398 iosock->dest.addr.addresslen = 0;
400 iosocket_lookup_clear:
402 if(bind_lookup->result)
403 iodns_free_result(bind_lookup->result);
407 if(dest_lookup->result)
408 iodns_free_result(dest_lookup->result);
412 if((iosock->socket_flags & IOSOCKETFLAG_DNSERROR)) {
413 // TODO: trigger error
420 static void iosocket_prepare_fd(int sockfd) {
423 #if defined(SO_NOSIGPIPE)
426 setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
429 signal(SIGPIPE, SIG_IGN);
433 // make sockfd unblocking
437 fcntl_flags = fcntl(sockfd, F_GETFL);
438 fcntl(sockfd, F_SETFL, fcntl_flags|O_NONBLOCK);
439 fcntl_flags = fcntl(sockfd, F_GETFD);
440 fcntl(sockfd, F_SETFD, fcntl_flags|FD_CLOEXEC);
443 /* I hope you're using the Win32 backend or something else that
444 * automatically marks the file descriptor non-blocking...
449 static void iosocket_connect_finish(struct _IOSocket *iosock) {
451 if((iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET))
452 sockfd = socket(AF_INET6, SOCK_STREAM, 0);
454 sockfd = socket(AF_INET, SOCK_STREAM, 0);
456 iolog_trigger(IOLOG_ERROR, "could not create socket in %s:%d", __FILE__, __LINE__);
457 // TODO: trigger error
462 // set port and bind address
463 if((iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET)) {
464 struct sockaddr_in6 *ip6 = (void*) iosock->dest.addr.address;
465 ip6->sin6_family = AF_INET6;
466 ip6->sin6_port = htons(iosock->port);
468 if(iosock->bind.addr.addresslen) {
469 struct sockaddr_in6 *ip6bind = (void*) iosock->bind.addr.address;
470 ip6bind->sin6_family = AF_INET6;
471 ip6bind->sin6_port = htons(0);
473 bind(sockfd, (struct sockaddr*)ip6bind, sizeof(*ip6bind));
476 struct sockaddr_in *ip4 = (void*) iosock->dest.addr.address;
477 ip4->sin_family = AF_INET;
478 ip4->sin_port = htons(iosock->port);
480 if(iosock->bind.addr.addresslen) {
481 struct sockaddr_in *ip4bind = (void*) iosock->bind.addr.address;
482 ip4bind->sin_family = AF_INET;
483 ip4bind->sin_port = htons(0);
485 bind(sockfd, (struct sockaddr*)ip4bind, sizeof(*ip4bind));
489 iosocket_prepare_fd(sockfd);
491 connect(sockfd, iosock->dest.addr.address, iosock->dest.addr.addresslen); //returns EINPROGRESS here (nonblocking)
493 iosock->socket_flags |= IOSOCKETFLAG_CONNECTING;
495 iosocket_activate(iosock);
498 static void iosocket_listen_finish(struct _IOSocket *iosock) {
500 if((iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET))
501 sockfd = socket(AF_INET6, SOCK_STREAM, 0);
503 sockfd = socket(AF_INET, SOCK_STREAM, 0);
505 iolog_trigger(IOLOG_ERROR, "could not create socket in %s:%d", __FILE__, __LINE__);
506 // TODO: trigger error
511 // set port and bind address
512 if((iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET)) {
513 struct sockaddr_in6 *ip6bind = (void*) iosock->bind.addr.address;
514 ip6bind->sin6_family = AF_INET6;
515 ip6bind->sin6_port = htons(0);
518 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
520 bind(sockfd, (struct sockaddr*)ip6bind, sizeof(*ip6bind));
522 struct sockaddr_in *ip4bind = (void*) iosock->bind.addr.address;
523 ip4bind->sin_family = AF_INET;
524 ip4bind->sin_port = htons(0);
527 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
529 bind(sockfd, (struct sockaddr*)ip4bind, sizeof(*ip4bind));
532 iosocket_prepare_fd(sockfd);
537 iosocket_activate(iosock);
540 struct _IOSocket *iosocket_accept_client(struct _IOSocket *iosock) {
541 struct IOSocket *new_iosocket = calloc(1, sizeof(*new_iosocket));
543 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocket in %s:%d", __FILE__, __LINE__);
544 close(accept(iosock->fd, NULL, 0)); // simply drop connection
547 struct _IOSocket *new_iosock = _create_socket();
550 close(accept(iosock->fd, NULL, 0)); // simply drop connection
553 new_iosocket->iosocket = new_iosock;
554 new_iosocket->status = IOSOCKET_CONNECTED;
555 new_iosock->parent = new_iosocket;
556 new_iosock->socket_flags |= IOSOCKETFLAG_PARENT_PUBLIC | IOSOCKETFLAG_INCOMING | (iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET);
558 struct sockaddr_storage addr;
559 socklen_t addrlen = sizeof(addr);
562 new_iosock->fd = accept(iosock->fd, (struct sockaddr *)&addr, &addrlen);
564 //copy remote address
565 new_iosock->dest.addr.address = malloc(addrlen);
566 if(!new_iosock->dest.addr.address) {
567 close(new_iosock->fd);
570 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
573 memcpy(new_iosock->dest.addr.address, &addr, addrlen);
574 new_iosock->dest.addr.addresslen = addrlen;
577 new_iosock->bind.addr.address = malloc(iosock->bind.addr.addresslen);
578 if(!new_iosock->bind.addr.address) {
579 close(new_iosock->fd);
582 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
585 memcpy(new_iosock->bind.addr.address, iosock->bind.addr.address, iosock->bind.addr.addresslen);
586 new_iosock->bind.addr.addresslen = iosock->bind.addr.addresslen;
588 //prepare new socket fd
589 iosocket_prepare_fd(new_iosock->fd);
591 if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {
592 new_iosocket->ssl = 1;
593 new_iosock->socket_flags |= IOSOCKETFLAG_SSLSOCKET;
594 //TODO: SSL Handshake
597 iosocket_activate(new_iosock);
601 /* public functions */
603 struct IOSocket *iosocket_connect(const char *hostname, unsigned int port, int ssl, const char *bindhost, iosocket_callback *callback) {
604 return iosocket_connect_flags(hostname, port, ssl, bindhost, callback, (IOSOCKET_ADDR_IPV4 | IOSOCKET_ADDR_IPV6));
607 struct IOSocket *iosocket_connect_flags(const char *hostname, unsigned int port, int ssl, const char *bindhost, iosocket_callback *callback, int flags) {
608 struct IOSocket *iodescriptor = calloc(1, sizeof(*iodescriptor));
610 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocket in %s:%d", __FILE__, __LINE__);
614 struct _IOSocket *iosock = _create_socket();
620 iodescriptor->iosocket = iosock;
621 iodescriptor->status = IOSOCKET_CONNECTING;
622 iodescriptor->callback = callback;
623 iosock->parent = iodescriptor;
624 iosock->socket_flags |= IOSOCKETFLAG_PARENT_PUBLIC;
627 iodescriptor->ssl = 1;
628 iosock->socket_flags |= IOSOCKETFLAG_SSLSOCKET;
632 switch(iosocket_parse_address(bindhost, &iosock->bind.addr, flags)) {
637 /* start dns lookup */
638 iosock->socket_flags |= IOSOCKETFLAG_PENDING_BINDDNS;
639 iosocket_lookup_hostname(iosock, bindhost, flags, 1);
646 switch(iosocket_parse_address(hostname, &iosock->dest.addr, flags)) {
651 /* start dns lookup */
652 iosock->socket_flags |= IOSOCKETFLAG_PENDING_DESTDNS;
653 iosocket_lookup_hostname(iosock, hostname, flags, 0);
659 if((iosock->socket_flags & (IOSOCKETFLAG_PENDING_BINDDNS | IOSOCKETFLAG_PENDING_DESTDNS)) == 0) {
660 iosocket_connect_finish(iosock);
665 struct IOSocket *iosocket_listen(const char *hostname, unsigned int port, iosocket_callback *callback) {
666 return iosocket_listen_flags(hostname, port, callback, (IOSOCKET_ADDR_IPV4 | IOSOCKET_ADDR_IPV6));
669 struct IOSocket *iosocket_listen_flags(const char *hostname, unsigned int port, iosocket_callback *callback, int flags) {
670 struct IOSocket *iodescriptor = calloc(1, sizeof(*iodescriptor));
672 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocket in %s:%d", __FILE__, __LINE__);
676 struct _IOSocket *iosock = _create_socket();
682 iodescriptor->iosocket = iosock;
683 iodescriptor->status = IOSOCKET_LISTENING;
684 iodescriptor->listening = 1;
685 iodescriptor->callback = callback;
686 iosock->parent = iodescriptor;
687 iosock->socket_flags |= IOSOCKETFLAG_PARENT_PUBLIC | IOSOCKETFLAG_LISTENING;
691 iodescriptor->ssl = 1;
692 iosock->socket_flags |= IOSOCKETFLAG_SSLSOCKET;
696 switch(iosocket_parse_address(hostname, &iosock->bind.addr, flags)) {
701 /* start dns lookup */
702 iosock->socket_flags |= IOSOCKETFLAG_PENDING_BINDDNS;
703 iosocket_lookup_hostname(iosock, hostname, flags, 1);
709 if((iosock->socket_flags & IOSOCKETFLAG_PENDING_BINDDNS) == 0) {
710 iosocket_listen_finish(iosock);
715 struct IOSocket *iosocket_listen_ssl(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iosocket_callback *callback) {
716 return iosocket_listen_ssl_flags(hostname, port, certfile, keyfile, callback, (IOSOCKET_ADDR_IPV4 | IOSOCKET_ADDR_IPV6));
719 struct IOSocket *iosocket_listen_ssl_flags(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iosocket_callback *callback, int flags) {
724 void iosocket_close(struct IOSocket *iosocket) {
725 struct _IOSocket *iosock = iosocket->iosocket;
727 iolog_trigger(IOLOG_WARNING, "called iosocket_close for destroyed IOSocket in %s:%d", __FILE__, __LINE__);
731 iosock->socket_flags |= IOSOCKETFLAG_SHUTDOWN;
733 if(iosock->writebuf.bufpos) {
734 //try to send everything before closing
738 flags = fcntl(iosock->fd, F_GETFL);
739 fcntl(iosock->fd, F_SETFL, flags & ~O_NONBLOCK);
740 flags = fcntl(iosock->fd, F_GETFD);
741 fcntl(iosock->fd, F_SETFD, flags|FD_CLOEXEC);
744 iosocket_deactivate(iosock);
746 iosocket_try_write(iosock);
749 if(iosock->sslnode) {
754 _free_socket(iosock);
755 iosocket->iosocket = NULL;
756 iosocket->status = IOSOCKET_CLOSED;
760 static int iosocket_try_write(struct _IOSocket *iosock) {
761 if(!iosock->writebuf.bufpos) return 0;
762 iolog_trigger(IOLOG_DEBUG, "write writebuf (%d bytes) to socket (fd: %d)", iosock->writebuf.bufpos, iosock->fd);
764 if(iosock->sslnode) {
765 /* res = iohandler_ssl_write(iofd, iofd->writebuf.buffer, iofd->writebuf.bufpos); */
768 res = send(iosock->fd, iosock->writebuf.buffer, iosock->writebuf.bufpos, 0);
770 if (errno != EAGAIN && errno != EWOULDBLOCK)
771 iolog_trigger(IOLOG_ERROR, "could not write to socket (fd: %d): %d - %s", iosock->fd, errno, strerror(errno));
775 iosock->writebuf.bufpos -= res;
776 if((iosock->socket_flags & (IOSOCKETFLAG_ACTIVE & IOSOCKETFLAG_SHUTDOWN)) == IOSOCKETFLAG_ACTIVE)
777 engine->update(iosock);
782 void iosocket_send(struct IOSocket *iosocket, const char *data, size_t datalen) {
783 struct _IOSocket *iosock = iosocket->iosocket;
785 iolog_trigger(IOLOG_WARNING, "called iosocket_close for destroyed IOSocket in %s:%d", __FILE__, __LINE__);
788 if(iosock->socket_flags & IOSOCKETFLAG_SHUTDOWN) {
789 iolog_trigger(IOLOG_ERROR, "could not write to socket (socket is closing)");
792 iolog_trigger(IOLOG_DEBUG, "add %d to writebuf (fd: %d): %s", datalen, iosock->fd, data);
793 if(iosock->writebuf.buflen < iosock->writebuf.bufpos + datalen) {
794 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));
795 iosocket_increase_buffer(&iosock->writebuf, iosock->writebuf.bufpos + datalen);
796 if(iosock->writebuf.buflen < iosock->writebuf.bufpos + datalen) {
797 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));
801 memcpy(iosock->writebuf.buffer + iosock->writebuf.bufpos, data, datalen);
802 iosock->writebuf.bufpos += datalen;
803 if((iosock->socket_flags & IOSOCKETFLAG_ACTIVE))
804 engine->update(iosock);
807 void iosocket_write(struct IOSocket *iosocket, const char *line) {
808 size_t linelen = strlen(line);
809 iosocket_send(iosocket, line, linelen);
812 void iosocket_printf(struct IOSocket *iosocket, const char *text, ...) {
814 char sendBuf[IOSOCKET_PRINTF_LINE_LEN];
817 va_start(arg_list, text);
818 pos = vsnprintf(sendBuf, IOSOCKET_PRINTF_LINE_LEN - 2, text, arg_list);
820 if (pos < 0 || pos > (IOSOCKET_PRINTF_LINE_LEN - 2)) pos = IOSOCKET_PRINTF_LINE_LEN - 2;
822 sendBuf[pos+1] = '\0';
823 iosocket_send(iosocket, sendBuf, pos+1);
828 static void iosocket_trigger_event(struct IOSocketEvent *event) {
829 if(!event->socket->callback)
831 iolog_trigger(IOLOG_DEBUG, "triggering event");
832 event->socket->callback(event);
835 void iosocket_events_callback(struct _IOSocket *iosock, int readable, int writeable) {
836 if((iosock->socket_flags & IOSOCKETFLAG_PARENT_PUBLIC)) {
837 struct IOSocket *iosocket = iosock->parent;
838 struct IOSocketEvent callback_event;
839 callback_event.type = IOSOCKETEVENT_IGNORE;
840 callback_event.socket = iosocket;
842 if((iosock->socket_flags & IOSOCKETFLAG_SSL_HANDSHAKE)) {
844 } else if((iosock->socket_flags & IOSOCKETFLAG_LISTENING)) {
846 //new client connected
847 struct _IOSocket *new_iosock = iosocket_accept_client(iosock);
851 if(!(new_iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {
852 callback_event.type = IOSOCKETEVENT_ACCEPT;
853 callback_event.data.accept_socket = new_iosock->parent;
857 } else if((iosock->socket_flags & IOSOCKETFLAG_CONNECTING)) {
858 if(readable) { //could not connect
859 callback_event.type = IOSOCKETEVENT_NOTCONNECTED;
861 socklen_t arglen = sizeof(callback_event.data.errid);
862 if (getsockopt(iosock->fd, SOL_SOCKET, SO_ERROR, &callback_event.data.errid, &arglen) < 0)
863 callback_event.data.errid = errno;
865 iosock->socket_flags |= IOSOCKETFLAG_DEAD;
866 } else if(writeable) { //connection established
867 iosocket->status = IOSOCKET_CONNECTED;
868 if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {
869 //TODO: SSL Handshake
873 callback_event.type = IOSOCKETEVENT_CONNECTED;
874 iosock->socket_flags &= ~IOSOCKETFLAG_CONNECTING;
875 engine->update(iosock);
878 iosocket_increase_buffer(&iosock->readbuf, 1024);
883 if(iosock->readbuf.buflen - iosock->readbuf.bufpos >= 128)
884 iosocket_increase_buffer(&iosock->readbuf, iosock->readbuf.buflen + 1024);
885 if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {
888 bytes = recv(iosock->fd, iosock->readbuf.buffer + iosock->readbuf.bufpos, iosock->readbuf.buflen - iosock->readbuf.bufpos, 0);
891 if (errno != EAGAIN || errno != EWOULDBLOCK) {
892 iosock->socket_flags |= IOSOCKETFLAG_DEAD;
894 callback_event.type = IOSOCKETEVENT_CLOSED;
895 callback_event.data.errid = errno;
899 iolog_trigger(IOLOG_DEBUG, "received %d bytes (fd: %d). readbuf position: %d", bytes, iosock->fd, iosock->readbuf.bufpos);
900 iosock->readbuf.bufpos += bytes;
901 callback_event.type = IOSOCKETEVENT_RECV;
903 if(iosocket->parse_delimiter) {
904 int j, used_bytes = 0;
905 for(i = 0; i < iosock->readbuf.bufpos; i++) {
906 int is_delimiter = 0;
907 for(j = 0; j < IOSOCKET_PARSE_DELIMITERS_COUNT; j++) {
908 if(iosock->readbuf.buffer[i] == iosocket->delimiters[j]) {
914 iosock->readbuf.buffer[i] = 0;
915 callback_event.data.recv_str = iosock->readbuf.buffer + used_bytes;
916 iolog_trigger(IOLOG_DEBUG, "parsed line (%d bytes): %s", i - used_bytes, iosock->readbuf.buffer + used_bytes);
918 if(iosock->readbuf.buffer[i-1] != 0 || iosocket->parse_empty)
919 iosocket_trigger_event(&callback_event);
921 #ifdef IOSOCKET_PARSE_LINE_LIMIT
922 else if(i + 1 - used_bytes >= IOSOCKET_PARSE_LINE_LIMIT) {
923 iosock->readbuf.buffer[i] = 0;
924 callback_event.data.recv_str = iosock->readbuf.buffer + used_bytes;
925 iolog_trigger(IOLOG_DEBUG, "parsed and stripped line (%d bytes): %s", i - used_bytes, iosock->readbuf.buffer + used_bytes);
926 for(; i < iosock->readbuf.bufpos; i++) { //skip the rest of the line
928 if(iosock->readbuf.buffer[i] == iosocket->delimiters[j])
932 iosocket_trigger_event(&callback_event);
937 if(used_bytes == iosock->readbuf.bufpos) {
938 iosock->readbuf.bufpos = 0;
939 iolog_trigger(IOLOG_DEBUG, "readbuf fully processed (set buffer position to 0)");
941 iolog_trigger(IOLOG_DEBUG, "readbuf rest: %d bytes (used %d bytes)", iosock->readbuf.bufpos - used_bytes, used_bytes);
942 memmove(iosock->readbuf.buffer, iosock->readbuf.buffer + used_bytes, iosock->readbuf.bufpos - used_bytes);
943 iosock->readbuf.bufpos -= used_bytes;
946 callback_event.type = IOSOCKETEVENT_IGNORE;
948 callback_event.data.recv_buf = &iosock->readbuf;
953 bytes = iosocket_try_write(iosock);
955 iosock->socket_flags |= IOSOCKETFLAG_DEAD;
957 callback_event.type = IOSOCKETEVENT_CLOSED;
958 callback_event.data.errid = errno;
963 if(callback_event.type != IOSOCKETEVENT_IGNORE)
964 iosocket_trigger_event(&callback_event);
965 if((iosock->socket_flags & IOSOCKETFLAG_DEAD))
966 iosocket_close(iosocket);
968 } else if((iosock->socket_flags & IOSOCKETFLAG_PARENT_DNSENGINE)) {
969 //TODO: IODNS callback
973 void iosocket_loop(int usec) {
974 struct timeval timeout;
975 timeout.tv_sec = usec / 1000000;
976 timeout.tv_usec = usec % 1000000;
977 engine->loop(&timeout);