4a7da99c6b8618c6df169a7ff65ce3775e3e0034
[NextIRCd.git] / src / IOHandler / IOSockets.c
1 /* IOSockets.c - IOMultiplexer v2
2  * Copyright (C) 2014  Philipp Kreil (pk910)
3  * 
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.
8  * 
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.
13  * 
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/>. 
16  */
17 #define _IOHandler_internals
18 #include "IOInternal.h"
19 #include "IOHandler.h"
20 #include "IOSockets.h"
21 #include "IOLog.h"
22 #include "IODNSLookup.h"
23
24 #ifdef WIN32
25 #define _WIN32_WINNT 0x501
26 #include <windows.h>
27 #include <winsock2.h>
28 #include <ws2tcpip.h>
29 #else
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <netinet/ip.h> 
33 #include <arpa/inet.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #endif
37 #include "compat/inet.h"
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <signal.h>
42 #include <errno.h>
43 #include <stdarg.h>
44
45 #ifndef EWOULDBLOCK
46 #define EWOULDBLOCK EAGAIN
47 #endif
48
49 struct _IOSocket *iosocket_first = NULL;
50 struct _IOSocket *iosocket_last = NULL;
51
52 struct IOEngine *engine = NULL;
53
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);
65
66 #ifdef WIN32
67 static int close(int fd) {
68         return closesocket(fd);
69 }
70 #endif
71
72 static void iosockets_init_engine() {
73         //try other engines
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;
80         
81         if (!engine) {
82                 if(engine_select.init())
83                         engine = &engine_select;
84                 else {
85                         iolog_trigger(IOLOG_FATAL, "found no useable IO engine");
86                         return;
87                 }
88         }
89         iolog_trigger(IOLOG_DEBUG, "using %s IOSockets engine", engine->name);
90 }
91
92 void _init_sockets() {
93         #ifdef WIN32
94         WSADATA wsaData;
95     int iResult;
96         //Initialize Winsock
97     iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
98     if(iResult != 0){
99         iolog_trigger(IOLOG_ERROR, "WSAStartup returned error code: %d", iResult);
100     }
101         #endif
102         
103         iosockets_init_engine();\r
104         iossl_init();
105 }
106
107
108 struct _IOSocket *_create_socket() {
109         struct _IOSocket *iosock = calloc(1, sizeof(*iosock));
110         if(!iosock) {
111                 iolog_trigger(IOLOG_ERROR, "could not allocate memory for _IOSocket in %s:%d", __FILE__, __LINE__);
112                 return NULL;
113         }
114         if(iosocket_last)
115                 iosocket_last->next = iosock;
116         else
117                 iosocket_first = iosock;
118         iosock->prev = iosocket_last;
119         iosocket_last = iosock;
120         return iosock;
121 }
122
123 void _free_socket(struct _IOSocket *iosock) {
124         iosocket_deactivate(iosock);
125         if(iosock->prev)
126                 iosock->prev->next = iosock->next;
127         else
128                 iosocket_first = iosock->next;
129         if(iosock->next)
130                 iosock->next->prev = iosock->prev;
131         else
132                 iosocket_last = iosock->prev;
133         
134         if(iosock->bind.addr.addresslen)
135                 free(iosock->bind.addr.address);
136         if(iosock->dest.addr.addresslen)
137                 free(iosock->dest.addr.address);
138         if(iosock->bind.addrlookup || iosock->dest.addrlookup)
139                 socket_lookup_clear(iosock);
140         if(iosock->readbuf.buffer)
141                 free(iosock->readbuf.buffer);
142         if(iosock->writebuf.buffer)
143                 free(iosock->writebuf.buffer);
144         if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET))\r
145                 iossl_disconnect(iosock);\r
146         
147         free(iosock);
148 }
149
150 static void iosocket_activate(struct _IOSocket *iosock) {
151         if((iosock->socket_flags & IOSOCKETFLAG_ACTIVE))
152                 return;
153         iosock->socket_flags |= IOSOCKETFLAG_ACTIVE;
154         engine->add(iosock);
155 }
156
157 static void iosocket_deactivate(struct _IOSocket *iosock) {
158         if(!(iosock->socket_flags & IOSOCKETFLAG_ACTIVE))
159                 return;
160         iosock->socket_flags &= ~IOSOCKETFLAG_ACTIVE;
161         engine->remove(iosock);
162 }
163
164 static void iosocket_increase_buffer(struct IOSocketBuffer *iobuf, size_t required) {
165         if(iobuf->buflen >= required) return;
166         char *new_buf;
167         if(iobuf->buffer)
168                 new_buf = realloc(iobuf->buffer, required + 2);
169         else
170                 new_buf = malloc(required + 2);
171         if(new_buf) {
172                 iobuf->buffer = new_buf;
173                 iobuf->buflen = required;
174         }
175 }
176
177 static int iosocket_parse_address(const char *hostname, struct IODNSAddress *addr, int records) {
178         int ret;
179         if((records & IOSOCKET_ADDR_IPV4)) {
180                 struct sockaddr_in ip4addr;
181                 ret = inet_pton(AF_INET, hostname, &(ip4addr.sin_addr));
182                 if(ret == 1) {
183                         addr->addresslen = sizeof(ip4addr);
184                         addr->address = malloc(addr->addresslen);
185                         if(!addr->address) {
186                                 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
187                                 return -1;
188                         }
189                         memcpy(addr->address, &ip4addr, sizeof(ip4addr));
190                         return 1;
191                 }
192         }
193         if((records & IOSOCKET_ADDR_IPV6)) {
194                 struct sockaddr_in6 ip6addr;
195                 ret = inet_pton(AF_INET6, hostname, &(ip6addr.sin6_addr));
196                 if(ret == 1) {
197                         addr->addresslen = sizeof(ip6addr);
198                         addr->address = malloc(addr->addresslen);
199                         if(!addr->address) {
200                                 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
201                                 return -1;
202                         }
203                         memcpy(addr->address, &ip6addr, sizeof(ip6addr));
204                         return 1;
205                 }
206         }
207         return 0;
208 }
209
210 static int iosocket_lookup_hostname(struct _IOSocket *iosock, const char *hostname, int records, int bindaddr) {
211         struct IOSocketDNSLookup *lookup = calloc(1, sizeof(*lookup));
212         if(!lookup) {
213                 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocketDNSLookup in %s:%d", __FILE__, __LINE__);
214                 return 0;
215         }
216         
217         struct _IODNSQuery *query = _create_dnsquery();
218         if(!query) {
219                 free(lookup);
220                 return 0;
221         }
222         
223         query->parent = lookup;
224         query->flags |= IODNSFLAG_PARENT_SOCKET;
225         lookup->iosocket = iosock;
226         lookup->query = query;
227         strncpy(lookup->hostname, hostname, sizeof(lookup->hostname));
228         lookup->hostname[sizeof(lookup->hostname)-1] = 0;
229         if(bindaddr) {
230                 lookup->bindlookup = 1;
231                 iosock->bind.addrlookup = lookup;
232         } else {
233                 lookup->bindlookup = 0;
234                 iosock->dest.addrlookup = lookup;
235         }
236         
237         int dnsrecords = 0;
238         if((records & IOSOCKET_ADDR_IPV4))
239                 dnsrecords |= IODNS_RECORD_A;
240         if((records & IOSOCKET_ADDR_IPV6))
241                 dnsrecords |= IODNS_RECORD_AAAA;
242         
243         query->request.host = strdup(hostname);
244         query->type = (dnsrecords & IODNS_FORWARD);
245         
246         _start_dnsquery(query);
247         return 1;
248 }
249
250 void iosocket_lookup_callback(struct IOSocketDNSLookup *lookup, struct IODNSEvent *event) {
251         lookup->query = NULL;
252         struct _IOSocket *iosock = lookup->iosocket;
253         if(iosock == NULL)
254                 return;
255         
256         if(event->type == IODNSEVENT_SUCCESS)
257                 lookup->result = event->result;
258         else
259                 lookup->result = NULL;
260         
261         if(lookup->bindlookup) {
262                 iosock->socket_flags &= ~IOSOCKETFLAG_PENDING_BINDDNS;
263                 iosock->socket_flags |= IOSOCKETFLAG_DNSDONE_BINDDNS;
264         } else {
265                 iosock->socket_flags &= ~IOSOCKETFLAG_PENDING_DESTDNS;
266                 iosock->socket_flags |= IOSOCKETFLAG_DNSDONE_DESTDNS;
267         }
268         
269         int dns_finished = 0;
270         if((iosock->socket_flags & (IOSOCKETFLAG_PENDING_BINDDNS | IOSOCKETFLAG_PENDING_DESTDNS)) == 0)
271                 dns_finished = 1;
272         
273         if(dns_finished) {
274                 int ret;
275                 ret = iosocket_lookup_apply(iosock, 0);
276                 if(ret) { //if ret=0 an error occured in iosocket_lookup_apply and we should stop here.
277                         if((iosock->socket_flags & IOSOCKETFLAG_LISTENING)) {
278                                 socket_lookup_clear(iosock);
279                                 iosocket_listen_finish(iosock);
280                         } else
281                                 iosocket_connect_finish(iosock);
282                 }
283         }
284 }
285
286 static int iosocket_lookup_apply(struct _IOSocket *iosock, int noip6) {
287         char errbuf[512];
288         struct IOSocketDNSLookup *bind_lookup = ((iosock->socket_flags & IOSOCKETFLAG_DNSDONE_BINDDNS) ? iosock->bind.addrlookup : NULL);
289         struct IOSocketDNSLookup *dest_lookup = ((iosock->socket_flags & IOSOCKETFLAG_DNSDONE_DESTDNS) ? iosock->dest.addrlookup : NULL);
290         
291         iolog_trigger(IOLOG_DEBUG, "all pending lookups finished. trying to apply lookup results...");
292         
293         if(!bind_lookup && !dest_lookup) {
294                 iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
295                 sprintf(errbuf, "Internal Error");
296                 iolog_trigger(IOLOG_ERROR, "trying to apply lookup results without any lookups processed in %s:%d", __FILE__, __LINE__);
297                 goto iosocket_lookup_apply_end;
298         }
299         
300         struct IODNSResult *result;
301         int bind_numip4 = 0, bind_numip6 = 0;
302         int dest_numip4 = 0, dest_numip6 = 0;
303         
304         if(bind_lookup) {
305                 for(result = bind_lookup->result; result; result = result->next) {
306                         if((result->type & IODNS_RECORD_A))
307                                 bind_numip4++;
308                         if((result->type & IODNS_RECORD_AAAA))
309                                 bind_numip6++;
310                 }
311         }
312         if(dest_lookup) {
313                 for(result = dest_lookup->result; result; result = result->next) {
314                         if((result->type & IODNS_RECORD_A))
315                                 dest_numip4++;
316                         if((result->type & IODNS_RECORD_AAAA))
317                                 dest_numip6++;
318                 }
319         }
320         int useip6 = 0;
321         int useip4 = 0;
322         if(bind_lookup && (bind_numip6 == 0 && bind_numip4 == 0)) {
323                 iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
324                 sprintf(errbuf, "could not lookup bind address (%s)", bind_lookup->hostname);
325                 goto iosocket_lookup_apply_end;
326         } else if(dest_lookup && (dest_numip6 == 0 && dest_numip4 == 0)) {
327                 iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
328                 sprintf(errbuf, "could not lookup destination address (%s)", dest_lookup->hostname);
329                 goto iosocket_lookup_apply_end;
330         } else if(bind_lookup && dest_lookup) {
331                 if(bind_numip6 > 0 && dest_numip6 > 0)
332                         useip6 = 1;
333                 if(bind_numip4 > 0 && dest_numip4 > 0)
334                         useip4 = 1;
335         } else if(bind_lookup) {
336                 if(bind_numip6)
337                         useip6 = 1;
338                 if(bind_numip4)
339                         useip4 = 1;
340         } else if(dest_lookup) {
341                 if(dest_numip6)
342                         useip6 = 1;
343                 if(dest_numip4)
344                         useip4 = 1;
345         }
346         
347         int usetype = 0;
348         if(useip6 && !noip6) {
349                 usetype = IODNS_RECORD_AAAA;
350                 iosock->socket_flags |= IOSOCKETFLAG_IPV6SOCKET;
351                 if(useip4)
352                         iosock->socket_flags |= IOSOCKETFLAG_RECONNECT_IPV4;
353         } else if(useip4) {
354                 usetype = IODNS_RECORD_A;
355                 iosock->socket_flags &= ~(IOSOCKETFLAG_IPV6SOCKET | IOSOCKETFLAG_RECONNECT_IPV4);
356         } else {
357                 iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
358                 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);
359                 goto iosocket_lookup_apply_end;
360         }
361         
362         #define IOSOCKET_APPLY_COPYADDR(type) \
363         iosock->type.addr.addresslen = result->result.addr.addresslen; \
364         iosock->type.addr.address = malloc(result->result.addr.addresslen); \
365         if(!iosock->type.addr.address) { \
366                 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__); \
367                 iosock->type.addr.addresslen = 0; \
368                 iosock->socket_flags |= IOSOCKETFLAG_DNSERROR; \
369                 sprintf(errbuf, "could not allocate memory for dns information"); \
370                 goto iosocket_lookup_apply_end; \
371         } \
372         memcpy(iosock->type.addr.address, result->result.addr.address, result->result.addr.addresslen);
373         
374         
375         if(bind_lookup) {
376                 int usenum = ((usetype == IODNS_RECORD_AAAA) ? bind_numip6 : bind_numip4);
377                 usenum = rand() % usenum;
378                 for(result = bind_lookup->result; result; result = result->next) {
379                         if((result->type & usetype)) {
380                                 if(usenum == 0) {
381                                         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));
382                                         iolog_trigger(IOLOG_DEBUG, "using IPv%s Address (%s) as bind address", ((usetype == IODNS_RECORD_AAAA) ? "6" : "4"), errbuf);
383                                         IOSOCKET_APPLY_COPYADDR(bind)
384                                         break;
385                                 }
386                                 usenum--;
387                         }
388                 }
389         } else
390                 iosock->bind.addr.addresslen = 0;
391         
392         if(dest_lookup) {
393                 int usenum = ((usetype == IODNS_RECORD_AAAA) ? dest_numip6 : dest_numip4);
394                 usenum = rand() % usenum;
395                 for(result = dest_lookup->result; result; result = result->next) {
396                         if((result->type & usetype)) {
397                                 if(usenum == 0) {
398                                         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));
399                                         iolog_trigger(IOLOG_DEBUG, "using IPv%s Address (%s) as dest address", ((usetype == IODNS_RECORD_AAAA) ? "6" : "4"), errbuf);
400                                         IOSOCKET_APPLY_COPYADDR(dest)
401                                         break;
402                                 }
403                                 usenum--;
404                         }
405                 }
406         } else
407                 iosock->dest.addr.addresslen = 0;
408         
409         iosocket_lookup_apply_end:
410         
411         if((iosock->socket_flags & IOSOCKETFLAG_DNSERROR)) {
412                 // TODO: trigger error
413                 iolog_trigger(IOLOG_ERROR, "error while trying to apply dns lookup information: %s", errbuf);
414                 
415                 if((iosock->socket_flags & IOSOCKETFLAG_PARENT_PUBLIC)) {
416                         //trigger event
417                         struct IOSocket *iosocket = iosock->parent;
418                         
419                         struct IOSocketEvent callback_event;
420                         callback_event.type = IOSOCKETEVENT_DNSFAILED;
421                         callback_event.socket = iosocket;
422                         callback_event.data.recv_str = errbuf;
423                         iosocket_trigger_event(&callback_event);
424                         
425                         iosocket_close(iosocket);
426                 } else {
427                         // TODO: IODNS Callback
428                 }
429                 return 0;
430         } else
431                 return 1;
432 }
433
434 static void socket_lookup_clear(struct _IOSocket *iosock) {
435         struct IOSocketDNSLookup *bind_lookup = ((iosock->socket_flags & IOSOCKETFLAG_DNSDONE_BINDDNS) ? iosock->bind.addrlookup : NULL);
436         struct IOSocketDNSLookup *dest_lookup = ((iosock->socket_flags & IOSOCKETFLAG_DNSDONE_DESTDNS) ? iosock->dest.addrlookup : NULL);
437         if(bind_lookup) {
438                 if(bind_lookup->result)
439                         iodns_free_result(bind_lookup->result);
440                 free(bind_lookup);
441                 iosock->bind.addrlookup = NULL;
442         }
443         if(dest_lookup) {
444                 if(dest_lookup->result)
445                         iodns_free_result(dest_lookup->result);
446                 free(dest_lookup);
447                 iosock->dest.addrlookup = NULL;
448         }
449 }
450
451 static void iosocket_prepare_fd(int sockfd) {
452         // prevent SIGPIPE
453         #ifndef WIN32
454         #if defined(SO_NOSIGPIPE)
455         {
456                 int set = 1;
457                 setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
458         }
459         #else
460         signal(SIGPIPE, SIG_IGN);
461         #endif
462         #endif
463         
464         // make sockfd unblocking
465         #if defined(F_GETFL)
466         {
467                 int fcntl_flags;
468                 fcntl_flags = fcntl(sockfd, F_GETFL);
469                 fcntl(sockfd, F_SETFL, fcntl_flags|O_NONBLOCK);
470                 fcntl_flags = fcntl(sockfd, F_GETFD);
471                 fcntl(sockfd, F_SETFD, fcntl_flags|FD_CLOEXEC);
472         }
473         #elif defined(FIONBIO)
474         {
475                 unsigned long ulong = 1;
476                 ioctlsocket(sockfd, FIONBIO, &ulong);
477         }
478         #endif
479 }
480
481 static void iosocket_connect_finish(struct _IOSocket *iosock) {
482         int sockfd;
483         if((iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET))
484                 sockfd = socket(AF_INET6, SOCK_STREAM, 0);
485         else
486                 sockfd = socket(AF_INET, SOCK_STREAM, 0);
487         if(sockfd == -1) {
488                 iolog_trigger(IOLOG_ERROR, "could not create socket in %s:%d", __FILE__, __LINE__);
489                 // TODO: trigger error
490                 
491                 return;
492         }
493         
494         // set port and bind address
495         if((iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET)) {
496                 struct sockaddr_in6 *ip6 = (void*) iosock->dest.addr.address;
497                 ip6->sin6_family = AF_INET6;
498                 ip6->sin6_port = htons(iosock->port);
499                 
500                 if(iosock->bind.addr.addresslen) {
501                         struct sockaddr_in6 *ip6bind = (void*) iosock->bind.addr.address;
502                         ip6bind->sin6_family = AF_INET6;
503                         ip6bind->sin6_port = htons(0);
504                         
505                         bind(sockfd, (struct sockaddr*)ip6bind, sizeof(*ip6bind));
506                 }
507         } else {
508                 struct sockaddr_in *ip4 = (void*) iosock->dest.addr.address;
509                 ip4->sin_family = AF_INET;
510                 ip4->sin_port = htons(iosock->port);
511                 
512                 if(iosock->bind.addr.addresslen) {
513                         struct sockaddr_in *ip4bind = (void*) iosock->bind.addr.address;
514                         ip4bind->sin_family = AF_INET;
515                         ip4bind->sin_port = htons(0);
516                         
517                         bind(sockfd, (struct sockaddr*)ip4bind, sizeof(*ip4bind));
518                 }
519         }
520         
521         iosocket_prepare_fd(sockfd);
522         
523         int ret = connect(sockfd, iosock->dest.addr.address, iosock->dest.addr.addresslen); //returns EINPROGRESS here (nonblocking)
524         iolog_trigger(IOLOG_DEBUG, "connecting socket (connect: %d)", ret);
525         
526         iosock->fd = sockfd;
527         iosock->socket_flags |= IOSOCKETFLAG_CONNECTING;
528         
529         iosocket_activate(iosock);
530 }
531
532 static void iosocket_listen_finish(struct _IOSocket *iosock) {
533         int sockfd;
534         if((iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET))
535                 sockfd = socket(AF_INET6, SOCK_STREAM, 0);
536         else
537                 sockfd = socket(AF_INET, SOCK_STREAM, 0);
538         if(sockfd == -1) {
539                 iolog_trigger(IOLOG_ERROR, "could not create socket in %s:%d", __FILE__, __LINE__);
540                 // TODO: trigger error
541                 
542                 return;
543         }
544         
545         // set port and bind address
546         if((iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET)) {
547                 struct sockaddr_in6 *ip6bind = (void*) iosock->bind.addr.address;
548                 ip6bind->sin6_family = AF_INET6;
549                 ip6bind->sin6_port = htons(0);
550                 
551                 int opt = 1;
552                 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
553                 
554                 bind(sockfd, (struct sockaddr*)ip6bind, sizeof(*ip6bind));
555         } else {
556                 struct sockaddr_in *ip4bind = (void*) iosock->bind.addr.address;
557                 ip4bind->sin_family = AF_INET;
558                 ip4bind->sin_port = htons(0);
559                 
560                 int opt = 1;
561                 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
562                 
563                 bind(sockfd, (struct sockaddr*)ip4bind, sizeof(*ip4bind));
564         }
565         
566         iosocket_prepare_fd(sockfd);
567         
568         listen(sockfd, 1);
569         iosock->fd = sockfd;
570         
571         iosocket_activate(iosock);
572 }
573
574 struct _IOSocket *iosocket_accept_client(struct _IOSocket *iosock) {
575         struct IOSocket *new_iosocket = calloc(1, sizeof(*new_iosocket));
576         if(!new_iosocket) {
577                 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocket in %s:%d", __FILE__, __LINE__);
578                 close(accept(iosock->fd, NULL, 0)); // simply drop connection
579                 return NULL;
580         }
581         struct _IOSocket *new_iosock = _create_socket();
582         if(!new_iosock) {
583                 free(new_iosocket);
584                 close(accept(iosock->fd, NULL, 0)); // simply drop connection
585                 return NULL;
586         }
587         new_iosocket->iosocket = new_iosock;
588         new_iosocket->status = IOSOCKET_CONNECTED;
589         new_iosock->parent = new_iosocket;
590         new_iosock->socket_flags |= IOSOCKETFLAG_PARENT_PUBLIC | IOSOCKETFLAG_INCOMING | (iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET);
591         
592         struct sockaddr_storage addr;
593         socklen_t addrlen = sizeof(addr);
594         
595         //accept client
596         new_iosock->fd = accept(iosock->fd, (struct sockaddr *)&addr, &addrlen);
597         
598         //copy remote address
599         new_iosock->dest.addr.address = malloc(addrlen);
600         if(!new_iosock->dest.addr.address) {
601                 close(new_iosock->fd);
602                 free(new_iosock);
603                 free(new_iosock);
604                 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
605                 return NULL;
606         }
607         memcpy(new_iosock->dest.addr.address, &addr, addrlen);
608         new_iosock->dest.addr.addresslen = addrlen;
609         
610         //copy local address
611         new_iosock->bind.addr.address = malloc(iosock->bind.addr.addresslen);
612         if(!new_iosock->bind.addr.address) {
613                 close(new_iosock->fd);
614                 free(new_iosock);
615                 free(new_iosock);
616                 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
617                 return NULL;
618         }
619         memcpy(new_iosock->bind.addr.address, iosock->bind.addr.address, iosock->bind.addr.addresslen);
620         new_iosock->bind.addr.addresslen = iosock->bind.addr.addresslen;
621         
622         //prepare new socket fd
623         iosocket_prepare_fd(new_iosock->fd);
624         
625         if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {
626                 new_iosocket->ssl = 1;
627                 new_iosock->socket_flags |= IOSOCKETFLAG_SSLSOCKET;
628                 \r
629                 iossl_client_accepted(iosock, new_iosock);
630         }
631         
632         iosocket_activate(new_iosock);
633         return new_iosock;
634 }
635
636 /* public functions */
637
638 struct IOSocket *iosocket_connect(const char *hostname, unsigned int port, int ssl, const char *bindhost, iosocket_callback *callback) {
639         return iosocket_connect_flags(hostname, port, ssl, bindhost, callback, (IOSOCKET_ADDR_IPV4 | IOSOCKET_ADDR_IPV6));
640 }
641
642 struct IOSocket *iosocket_connect_flags(const char *hostname, unsigned int port, int ssl, const char *bindhost, iosocket_callback *callback, int flags) {
643         struct IOSocket *iodescriptor = calloc(1, sizeof(*iodescriptor));
644         if(!iodescriptor) {
645                 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocket in %s:%d", __FILE__, __LINE__);
646                 return NULL;
647         }
648         
649         struct _IOSocket *iosock = _create_socket();
650         if(!iosock) {
651                 free(iodescriptor);
652                 return NULL;
653         }
654         
655         iodescriptor->iosocket = iosock;
656         iodescriptor->status = IOSOCKET_CONNECTING;
657         iodescriptor->callback = callback;
658         iosock->parent = iodescriptor;
659         iosock->socket_flags |= IOSOCKETFLAG_PARENT_PUBLIC;
660         iosock->port = port;
661         if(ssl) {
662                 iodescriptor->ssl = 1;
663                 iosock->socket_flags |= IOSOCKETFLAG_SSLSOCKET;
664         }
665         
666         if(bindhost) {
667                 switch(iosocket_parse_address(bindhost, &iosock->bind.addr, flags)) {
668                 case -1:
669                         free(iosock);
670                         return NULL;
671                 case 0:
672                         /* start dns lookup */
673                         iosock->socket_flags |= IOSOCKETFLAG_PENDING_BINDDNS;
674                         iosocket_lookup_hostname(iosock, bindhost, flags, 1);
675                         break;
676                 case 1:
677                         /* valid address */
678                         break;
679                 }
680         }
681         switch(iosocket_parse_address(hostname, &iosock->dest.addr, flags)) {
682         case -1:
683                 free(iosock);
684                 return NULL;
685         case 0:
686                 /* start dns lookup */
687                 iosock->socket_flags |= IOSOCKETFLAG_PENDING_DESTDNS;
688                 iosocket_lookup_hostname(iosock, hostname, flags, 0);
689                 break;
690         case 1:
691                 /* valid address */
692                 break;
693         }
694         if((iosock->socket_flags & (IOSOCKETFLAG_PENDING_BINDDNS | IOSOCKETFLAG_PENDING_DESTDNS)) == 0) {
695                 iosocket_connect_finish(iosock);
696         }
697         return iodescriptor;
698 }
699
700 struct IOSocket *iosocket_listen(const char *hostname, unsigned int port, iosocket_callback *callback) {
701         return iosocket_listen_flags(hostname, port, callback, (IOSOCKET_ADDR_IPV4 | IOSOCKET_ADDR_IPV6));
702 }
703
704 struct IOSocket *iosocket_listen_flags(const char *hostname, unsigned int port, iosocket_callback *callback, int flags) {
705         struct IOSocket *iodescriptor = calloc(1, sizeof(*iodescriptor));
706         if(!iodescriptor) {
707                 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocket in %s:%d", __FILE__, __LINE__);
708                 return NULL;
709         }
710         
711         struct _IOSocket *iosock = _create_socket();
712         if(!iosock) {
713                 free(iodescriptor);
714                 return NULL;
715         }
716         
717         iodescriptor->iosocket = iosock;
718         iodescriptor->status = IOSOCKET_LISTENING;
719         iodescriptor->listening = 1;
720         iodescriptor->callback = callback;
721         iosock->parent = iodescriptor;
722         iosock->socket_flags |= IOSOCKETFLAG_PARENT_PUBLIC | IOSOCKETFLAG_LISTENING;
723         iosock->port = port;
724         
725         switch(iosocket_parse_address(hostname, &iosock->bind.addr, flags)) {
726         case -1:
727                 free(iosock);
728                 return NULL;
729         case 0:
730                 /* start dns lookup */
731                 iosock->socket_flags |= IOSOCKETFLAG_PENDING_BINDDNS;
732                 iosocket_lookup_hostname(iosock, hostname, flags, 1);
733                 break;
734         case 1:
735                 /* valid address */
736                 break;
737         }
738         if((iosock->socket_flags & IOSOCKETFLAG_PENDING_BINDDNS) == 0) {
739                 iosocket_listen_finish(iosock);
740         }
741         return iodescriptor;
742 }
743
744 struct IOSocket *iosocket_listen_ssl(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iosocket_callback *callback) {
745         return iosocket_listen_ssl_flags(hostname, port, certfile, keyfile, callback, (IOSOCKET_ADDR_IPV4 | IOSOCKET_ADDR_IPV6));
746 }
747
748 struct IOSocket *iosocket_listen_ssl_flags(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iosocket_callback *callback, int flags) {
749         struct IOSocket *iosocket = iosocket_listen_flags(hostname, port, callback, flags);\r
750         struct _IOSocket *iosock = iosocket->iosocket;\r
751         iosock->socket_flags |= IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_HANDSHAKE;\r
752         iossl_listen(iosock, certfile, keyfile);
753         return iosocket;
754 }
755
756 void iosocket_close(struct IOSocket *iosocket) {
757         struct _IOSocket *iosock = iosocket->iosocket;
758         if(iosock == NULL) {
759                 iolog_trigger(IOLOG_WARNING, "called iosocket_close for destroyed IOSocket in %s:%d", __FILE__, __LINE__);
760                 return;
761         }
762         
763         iosock->socket_flags |= IOSOCKETFLAG_SHUTDOWN;
764         
765         if(iosock->writebuf.bufpos) {
766                 //try to send everything before closing
767 #if defined(F_GETFL)
768                 {
769                         int flags;
770                         flags = fcntl(iosock->fd, F_GETFL);
771                         fcntl(iosock->fd, F_SETFL, flags & ~O_NONBLOCK);
772                         flags = fcntl(iosock->fd, F_GETFD);
773                         fcntl(iosock->fd, F_SETFD, flags|FD_CLOEXEC);
774                 }
775 #else
776                 iosocket_deactivate(iosock);
777 #endif
778                 iosocket_try_write(iosock);
779         }
780         //close IOSocket
781         if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET))
782                 iossl_disconnect(iosock);
783         if(iosock->fd)
784                 close(iosock->fd);
785         _free_socket(iosock);
786         iosocket->iosocket = NULL;
787         iosocket->status = IOSOCKET_CLOSED;
788         iogc_add(iosocket);
789 }
790
791 static int iosocket_try_write(struct _IOSocket *iosock) {
792         if(!iosock->writebuf.bufpos && !(iosock->socket_flags & IOSOCKETFLAG_SSL_WRITEHS)) \r
793                 return 0;
794         iolog_trigger(IOLOG_DEBUG, "write writebuf (%d bytes) to socket (fd: %d)", iosock->writebuf.bufpos, iosock->fd);
795         int res;
796         if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET))
797                 res = iossl_write(iosock, iosock->writebuf.buffer, iosock->writebuf.bufpos);
798         else
799                 res = send(iosock->fd, iosock->writebuf.buffer, iosock->writebuf.bufpos, 0);
800         if(res < 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));
803                 else
804                         res = 0;
805         } else {
806                 iosock->writebuf.bufpos -= res;
807                 if((iosock->socket_flags & (IOSOCKETFLAG_ACTIVE & IOSOCKETFLAG_SHUTDOWN)) == IOSOCKETFLAG_ACTIVE)
808                         engine->update(iosock);
809         }
810         return res;
811 }
812
813 void iosocket_send(struct IOSocket *iosocket, const char *data, size_t datalen) {
814         struct _IOSocket *iosock = iosocket->iosocket;
815         if(iosock == NULL) {
816                 iolog_trigger(IOLOG_WARNING, "called iosocket_close for destroyed IOSocket in %s:%d", __FILE__, __LINE__);
817                 return;
818         }
819         if(iosock->socket_flags & IOSOCKETFLAG_SHUTDOWN) {
820                 iolog_trigger(IOLOG_ERROR, "could not write to socket (socket is closing)");
821                 return;
822         }
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));
829                         return;
830                 }
831         }
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);
836 }
837
838 void iosocket_write(struct IOSocket *iosocket, const char *line) {
839         size_t linelen = strlen(line);
840         iosocket_send(iosocket, line, linelen);
841 }
842
843 void iosocket_printf(struct IOSocket *iosocket, const char *text, ...) {
844         va_list arg_list;
845         char sendBuf[IOSOCKET_PRINTF_LINE_LEN];
846         int pos;
847         sendBuf[0] = '\0';
848         va_start(arg_list, text);
849         pos = vsnprintf(sendBuf, IOSOCKET_PRINTF_LINE_LEN - 1, text, arg_list);
850         va_end(arg_list);
851         if (pos < 0 || pos > (IOSOCKET_PRINTF_LINE_LEN - 1)) pos = IOSOCKET_PRINTF_LINE_LEN - 1;
852         sendBuf[pos] = '\0';
853         iosocket_send(iosocket, sendBuf, pos);
854 }
855
856
857
858 static void iosocket_trigger_event(struct IOSocketEvent *event) {
859         if(!event->socket->callback) 
860                 return;
861         iolog_trigger(IOLOG_DEBUG, "triggering event");
862         event->socket->callback(event);
863 }
864
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;
871                 
872                 if((iosock->socket_flags & IOSOCKETFLAG_SSL_HANDSHAKE)) {
873                         if(readable || writeable) {
874                                 if((iosock->socket_flags & IOSOCKETFLAG_INCOMING)) 
875                                         iossl_server_handshake(iosock);
876                                 else
877                                         iossl_client_handshake(iosock);
878                                 engine->update(iosock);\r
879                         } else if((iosock->socket_flags & IOSOCKETFLAG_LISTENING)) {\r
880                                 //TODO: SSL init error\r
881                         } else if((iosock->socket_flags & IOSOCKETFLAG_INCOMING)) {\r
882                                 if((iosock->socket_flags & IOSOCKETFLAG_SSL_ESTABLISHED)) {\r
883                                         //incoming SSL connection accepted\r
884                                         iosock->socket_flags &= ~IOSOCKETFLAG_SSL_HANDSHAKE;\r
885                                         callback_event.type = IOSOCKETEVENT_ACCEPT;\r
886                                         callback_event.data.accept_socket = iosock->parent;\r
887                                 } else {\r
888                                         //incoming SSL connection failed, simply drop\r
889                                         iosock->socket_flags |= IOSOCKETFLAG_DEAD;\r
890                                         iolog_trigger(IOLOG_ERROR, "SSL Handshake failed for incoming connection. Dropping fd %d", iosock->fd);\r
891                                 }
892                         } else {
893                                 // SSL Backend finished
894                                 if((iosock->socket_flags & IOSOCKETFLAG_SSL_ESTABLISHED)) {\r
895                                         iosocket->status = IOSOCKET_CONNECTED;\r
896                                         iosock->socket_flags &= ~IOSOCKETFLAG_SSL_HANDSHAKE;\r
897                                         callback_event.type = IOSOCKETEVENT_CONNECTED;\r
898                                         engine->update(iosock);\r
899                                         \r
900                                         //initialize readbuf\r
901                                         iosocket_increase_buffer(&iosock->readbuf, 1024);
902                                 } else {
903                                         callback_event.type = IOSOCKETEVENT_NOTCONNECTED;\r
904                                         iosock->socket_flags |= IOSOCKETFLAG_DEAD;
905                                 }
906                         }
907                 } else if((iosock->socket_flags & IOSOCKETFLAG_LISTENING)) {
908                         if(readable) {
909                                 //new client connected
910                                 struct _IOSocket *new_iosock = iosocket_accept_client(iosock);
911                                 if(!new_iosock)
912                                         return;
913                                 
914                                 if(!(new_iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {
915                                         callback_event.type = IOSOCKETEVENT_ACCEPT;
916                                         callback_event.data.accept_socket = new_iosock->parent;
917                                 }
918                         }
919                         
920                 } else if((iosock->socket_flags & IOSOCKETFLAG_CONNECTING)) {
921                         if(readable) { //could not connect
922                                 if((iosock->socket_flags & (IOSOCKETFLAG_IPV6SOCKET | IOSOCKETFLAG_RECONNECT_IPV4)) == (IOSOCKETFLAG_IPV6SOCKET | IOSOCKETFLAG_RECONNECT_IPV4)) {
923                                         iolog_trigger(IOLOG_DEBUG, "connecting to IPv6 host (%s) failed. trying to connect using IPv4.", iosock->dest.addrlookup->hostname);
924                                         iosocket_deactivate(iosock);
925                                         if(iosocket_lookup_apply(iosock, 1)) { //if ret=0 an error occured in iosocket_lookup_apply and we should stop here.
926                                                 iosocket_connect_finish(iosock);
927                                                 socket_lookup_clear(iosock);
928                                         }
929                                 } else {
930                                         callback_event.type = IOSOCKETEVENT_NOTCONNECTED;
931                                         /*
932                                         socklen_t arglen = sizeof(callback_event.data.errid);
933                                         if (getsockopt(iosock->fd, SOL_SOCKET, SO_ERROR, &callback_event.data.errid, &arglen) < 0)
934                                                 callback_event.data.errid = errno;
935                                         */
936                                         iosock->socket_flags |= IOSOCKETFLAG_DEAD;
937                                 }
938                         } else if(writeable) { //connection established
939                                 iosock->socket_flags &= ~IOSOCKETFLAG_CONNECTING;
940                                 socket_lookup_clear(iosock);
941                                 if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {\r
942                                         iolog_trigger(IOLOG_DEBUG, "SSL client socket connected. Stating SSL handshake...");
943                                         iossl_connect(iosock);
944                                         engine->update(iosock);
945                                         return;
946                                 }
947                                 iosocket->status = IOSOCKET_CONNECTED;
948                                 
949                                 callback_event.type = IOSOCKETEVENT_CONNECTED;
950                                 engine->update(iosock);
951                                 
952                                 //initialize readbuf
953                                 iosocket_increase_buffer(&iosock->readbuf, 1024);
954                         }
955                 } else {\r
956                         int ssl_rehandshake = 0;\r
957                         if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {\r
958                                 if((iosock->socket_flags & IOSOCKETFLAG_SSL_READHS))\r
959                                         ssl_rehandshake = 1;\r
960                                 else if((iosock->socket_flags & IOSOCKETFLAG_SSL_WRITEHS))\r
961                                         ssl_rehandshake = 2;\r
962                         }
963                         if((readable && ssl_rehandshake == 0) || ssl_rehandshake == 1) {
964                                 int bytes;
965                                 if(iosock->readbuf.buflen - iosock->readbuf.bufpos >= 128)
966                                         iosocket_increase_buffer(&iosock->readbuf, iosock->readbuf.buflen + 1024);
967                                 if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET))
968                                         bytes = iossl_read(iosock, iosock->readbuf.buffer + iosock->readbuf.bufpos, iosock->readbuf.buflen - iosock->readbuf.bufpos);
969                                 else 
970                                         bytes = recv(iosock->fd, iosock->readbuf.buffer + iosock->readbuf.bufpos, iosock->readbuf.buflen - iosock->readbuf.bufpos, 0);
971                                         
972                                 if(bytes <= 0) {\r
973                                         if((iosock->socket_flags & (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_READHS)) == (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_READHS)) {\r
974                                                 ssl_rehandshake = 1;\r
975                                         } else if (errno != EAGAIN || errno != EWOULDBLOCK) {
976                                                 iosock->socket_flags |= IOSOCKETFLAG_DEAD;
977                                                 
978                                                 callback_event.type = IOSOCKETEVENT_CLOSED;
979                                                 callback_event.data.errid = errno;
980                                         }
981                                 } else {
982                                         int i;
983                                         iolog_trigger(IOLOG_DEBUG, "received %d bytes (fd: %d). readbuf position: %d", bytes, iosock->fd, iosock->readbuf.bufpos);
984                                         iosock->readbuf.bufpos += bytes;
985                                         callback_event.type = IOSOCKETEVENT_RECV;
986                                         
987                                         if(iosocket->parse_delimiter) {
988                                                 int j, used_bytes = 0;
989                                                 for(i = 0; i < iosock->readbuf.bufpos; i++) {
990                                                         int is_delimiter = 0;
991                                                         for(j = 0; j < IOSOCKET_PARSE_DELIMITERS_COUNT; j++) {
992                                                                 if(iosock->readbuf.buffer[i] == iosocket->delimiters[j]) {
993                                                                         is_delimiter = 1;
994                                                                         break;
995                                                                 }
996                                                         }
997                                                         if(is_delimiter) {
998                                                                 iosock->readbuf.buffer[i] = 0;
999                                                                 callback_event.data.recv_str = iosock->readbuf.buffer + used_bytes;
1000                                                                 iolog_trigger(IOLOG_DEBUG, "parsed line (%d bytes): %s", i - used_bytes, iosock->readbuf.buffer + used_bytes);
1001                                                                 used_bytes = i+1;
1002                                                                 if(iosock->readbuf.buffer[i-1] != 0 || iosocket->parse_empty)
1003                                                                         iosocket_trigger_event(&callback_event);
1004                                                         }
1005                                                         #ifdef IOSOCKET_PARSE_LINE_LIMIT
1006                                                         else if(i + 1 - used_bytes >= IOSOCKET_PARSE_LINE_LIMIT) {
1007                                                                 iosock->readbuf.buffer[i] = 0;
1008                                                                 callback_event.data.recv_str = iosock->readbuf.buffer + used_bytes;
1009                                                                 iolog_trigger(IOLOG_DEBUG, "parsed and stripped line (%d bytes): %s", i - used_bytes, iosock->readbuf.buffer + used_bytes);
1010                                                                 for(; i < iosock->readbuf.bufpos; i++) { //skip the rest of the line
1011                                                                         is_delimiter = 0;
1012                                                                         if(iosock->readbuf.buffer[i] == iosocket->delimiters[j])
1013                                                                                 break;
1014                                                                 }
1015                                                                 used_bytes = i+1;
1016                                                                 iosocket_trigger_event(&callback_event);
1017                                                         }
1018                                                         #endif
1019                                                 }
1020                                                 if(used_bytes) {
1021                                                         if(used_bytes == iosock->readbuf.bufpos) {
1022                                                                 iosock->readbuf.bufpos = 0;
1023                                                                 iolog_trigger(IOLOG_DEBUG, "readbuf fully processed (set buffer position to 0)");
1024                                                         } else {
1025                                                                 iolog_trigger(IOLOG_DEBUG, "readbuf rest: %d bytes (used %d bytes)", iosock->readbuf.bufpos - used_bytes, used_bytes);
1026                                                                 memmove(iosock->readbuf.buffer, iosock->readbuf.buffer + used_bytes, iosock->readbuf.bufpos - used_bytes);
1027                                                                 iosock->readbuf.bufpos -= used_bytes;
1028                                                         }
1029                                                 }
1030                                                 callback_event.type = IOSOCKETEVENT_IGNORE;
1031                                         } else
1032                                                 callback_event.data.recv_buf = &iosock->readbuf;
1033                                 }
1034                         }
1035                         if((writeable && ssl_rehandshake == 0) || ssl_rehandshake == 2) {
1036                                 int bytes;
1037                                 bytes = iosocket_try_write(iosock);
1038                                 if(bytes < 0) {\r
1039                                         if((iosock->socket_flags & (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_WRITEHS)) == (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_WRITEHS)) {\r
1040                                                 ssl_rehandshake = 1;\r
1041                                         } else {
1042                                                 iosock->socket_flags |= IOSOCKETFLAG_DEAD;
1043                                                 
1044                                                 callback_event.type = IOSOCKETEVENT_CLOSED;
1045                                                 callback_event.data.errid = errno;\r
1046                                         }
1047                                 }
1048                         }\r
1049                         if(ssl_rehandshake) {
1050                                 engine->update(iosock);\r
1051                         }
1052                 }
1053                 if(callback_event.type != IOSOCKETEVENT_IGNORE)
1054                         iosocket_trigger_event(&callback_event);
1055                 if((iosock->socket_flags & IOSOCKETFLAG_DEAD))
1056                         iosocket_close(iosocket);
1057                 
1058         } else if((iosock->socket_flags & IOSOCKETFLAG_PARENT_DNSENGINE)) {
1059                 //TODO: IODNS callback
1060         }
1061 }
1062
1063 void iosocket_loop(int usec) {
1064         struct timeval timeout;
1065         timeout.tv_sec = usec / 1000000;
1066         timeout.tv_usec = usec % 1000000;
1067         engine->loop(&timeout);
1068 }