[IOMultiplexerV2] fixed win32 EWOULDBLOCK error
[NextIRCd.git] / src / IOHandler / IOSockets.c
index 1973ea475ff17a5c3b1d3efc37f980d1ab4c899f..7c3c50a8f7e8b8770afd72a77f12acaed628d27d 100644 (file)
 #include "IOSockets.h"
 #include "IOLog.h"
 #include "IODNSLookup.h"
+#include "IOSSLBackend.h"
 
 #ifdef WIN32
+#ifdef _WIN32_WINNT
+#undef _WIN32_WINNT
+#endif
 #define _WIN32_WINNT 0x501
-#include <windows.h>
 #include <winsock2.h>
+#include <windows.h>
 #include <ws2tcpip.h>
 #else
 #include <sys/socket.h>
@@ -32,6 +36,7 @@
 #include <netinet/ip.h> 
 #include <arpa/inet.h>
 #include <unistd.h>
+#include <fcntl.h>
 #endif
 #include "compat/inet.h"
 #include <stdio.h>
@@ -42,7 +47,7 @@
 #include <stdarg.h>
 
 #ifndef EWOULDBLOCK
-#define EWOULDBLOCK EAGAIN
+#define EWOULDBLOCK WSAEWOULDBLOCK
 #endif
 
 struct _IOSocket *iosocket_first = NULL;
@@ -50,15 +55,15 @@ struct _IOSocket *iosocket_last = NULL;
 
 struct IOEngine *engine = NULL;
 
-static void iosocket_activate(struct _IOSocket *iosock);
-static void iosocket_deactivate(struct _IOSocket *iosock);
 static void iosocket_increase_buffer(struct IOSocketBuffer *iobuf, size_t required);
 static int iosocket_parse_address(const char *hostname, struct IODNSAddress *addr, int records);
 static int iosocket_lookup_hostname(struct _IOSocket *iosock, const char *hostname, int records, int bindaddr);
 static int iosocket_lookup_apply(struct _IOSocket *iosock, int noip6);
+static void socket_lookup_clear(struct _IOSocket *iosock);
 static void iosocket_connect_finish(struct _IOSocket *iosock);
 static void iosocket_listen_finish(struct _IOSocket *iosock);
 static int iosocket_try_write(struct _IOSocket *iosock);
+static void iosocket_trigger_event(struct IOSocketEvent *event);
 
 #ifdef WIN32
 static int close(int fd) {
@@ -89,15 +94,16 @@ static void iosockets_init_engine() {
 void _init_sockets() {
        #ifdef WIN32
        WSADATA wsaData;
-    int iResult;
+       int iResult;
        //Initialize Winsock
-    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
-    if(iResult != 0){
-        iolog_trigger(IOLOG_ERROR, "WSAStartup returned error code: %d", iResult);
-    }
+       iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
+       if(iResult != 0){
+               iolog_trigger(IOLOG_ERROR, "WSAStartup returned error code: %d", iResult);
+       }
        #endif
        
-       iosockets_init_engine();
+       iosockets_init_engine();\r
+       iossl_init();
 }
 
 
@@ -131,28 +137,38 @@ void _free_socket(struct _IOSocket *iosock) {
                free(iosock->bind.addr.address);
        if(iosock->dest.addr.addresslen)
                free(iosock->dest.addr.address);
+       if(iosock->bind.addrlookup || iosock->dest.addrlookup)
+               socket_lookup_clear(iosock);
        if(iosock->readbuf.buffer)
                free(iosock->readbuf.buffer);
        if(iosock->writebuf.buffer)
                free(iosock->writebuf.buffer);
+       if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET))\r
+               iossl_disconnect(iosock);\r
        
        free(iosock);
 }
 
-static void iosocket_activate(struct _IOSocket *iosock) {
+void iosocket_activate(struct _IOSocket *iosock) {
        if((iosock->socket_flags & IOSOCKETFLAG_ACTIVE))
                return;
        iosock->socket_flags |= IOSOCKETFLAG_ACTIVE;
        engine->add(iosock);
 }
 
-static void iosocket_deactivate(struct _IOSocket *iosock) {
+void iosocket_deactivate(struct _IOSocket *iosock) {
        if(!(iosock->socket_flags & IOSOCKETFLAG_ACTIVE))
                return;
        iosock->socket_flags &= ~IOSOCKETFLAG_ACTIVE;
        engine->remove(iosock);
 }
 
+void iosocket_update(struct _IOSocket *iosock) {
+       if(!(iosock->socket_flags & IOSOCKETFLAG_ACTIVE))
+               return;
+       engine->update(iosock);
+}
+
 static void iosocket_increase_buffer(struct IOSocketBuffer *iobuf, size_t required) {
        if(iobuf->buflen >= required) return;
        char *new_buf;
@@ -266,9 +282,10 @@ void iosocket_lookup_callback(struct IOSocketDNSLookup *lookup, struct IODNSEven
                int ret;
                ret = iosocket_lookup_apply(iosock, 0);
                if(ret) { //if ret=0 an error occured in iosocket_lookup_apply and we should stop here.
-                       if((iosock->socket_flags & IOSOCKETFLAG_LISTENING))
+                       if((iosock->socket_flags & IOSOCKETFLAG_LISTENING)) {
+                               socket_lookup_clear(iosock);
                                iosocket_listen_finish(iosock);
-                       else
+                       else
                                iosocket_connect_finish(iosock);
                }
        }
@@ -285,7 +302,7 @@ static int iosocket_lookup_apply(struct _IOSocket *iosock, int noip6) {
                iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
                sprintf(errbuf, "Internal Error");
                iolog_trigger(IOLOG_ERROR, "trying to apply lookup results without any lookups processed in %s:%d", __FILE__, __LINE__);
-               goto iosocket_lookup_clear;
+               goto iosocket_lookup_apply_end;
        }
        
        struct IODNSResult *result;
@@ -313,41 +330,41 @@ static int iosocket_lookup_apply(struct _IOSocket *iosock, int noip6) {
        if(bind_lookup && (bind_numip6 == 0 && bind_numip4 == 0)) {
                iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
                sprintf(errbuf, "could not lookup bind address (%s)", bind_lookup->hostname);
-               goto iosocket_lookup_clear;
+               goto iosocket_lookup_apply_end;
        } else if(dest_lookup && (dest_numip6 == 0 && dest_numip4 == 0)) {
                iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
                sprintf(errbuf, "could not lookup destination address (%s)", dest_lookup->hostname);
-               goto iosocket_lookup_clear;
+               goto iosocket_lookup_apply_end;
        } else if(bind_lookup && dest_lookup) {
                if(bind_numip6 > 0 && dest_numip6 > 0)
                        useip6 = 1;
-               else if(bind_numip4 > 0 && dest_numip4 > 0)
+               if(bind_numip4 > 0 && dest_numip4 > 0)
                        useip4 = 1;
-               else {
-                       iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
-                       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);
-                       goto iosocket_lookup_clear;
-               }
        } else if(bind_lookup) {
                if(bind_numip6)
                        useip6 = 1;
-               else if(bind_numip4)
+               if(bind_numip4)
                        useip4 = 1;
        } else if(dest_lookup) {
                if(dest_numip6)
                        useip6 = 1;
-               else if(dest_numip4)
+               if(dest_numip4)
                        useip4 = 1;
        }
        
        int usetype = 0;
-       if(useip6) {
+       if(useip6 && !noip6) {
                usetype = IODNS_RECORD_AAAA;
                iosock->socket_flags |= IOSOCKETFLAG_IPV6SOCKET;
+               if(useip4)
+                       iosock->socket_flags |= IOSOCKETFLAG_RECONNECT_IPV4;
        } else if(useip4) {
                usetype = IODNS_RECORD_A;
+               iosock->socket_flags &= ~(IOSOCKETFLAG_IPV6SOCKET | IOSOCKETFLAG_RECONNECT_IPV4);
        } else {
-               //should already be handled
+               iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
+               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);
+               goto iosocket_lookup_apply_end;
        }
        
        #define IOSOCKET_APPLY_COPYADDR(type) \
@@ -358,19 +375,19 @@ static int iosocket_lookup_apply(struct _IOSocket *iosock, int noip6) {
                iosock->type.addr.addresslen = 0; \
                iosock->socket_flags |= IOSOCKETFLAG_DNSERROR; \
                sprintf(errbuf, "could not allocate memory for dns information"); \
-               goto iosocket_lookup_clear; \
+               goto iosocket_lookup_apply_end; \
        } \
        memcpy(iosock->type.addr.address, result->result.addr.address, result->result.addr.addresslen);
        
        
        if(bind_lookup) {
-               int usenum = (useip6 ? bind_numip6 : bind_numip4);
+               int usenum = ((usetype == IODNS_RECORD_AAAA) ? bind_numip6 : bind_numip4);
                usenum = rand() % usenum;
                for(result = bind_lookup->result; result; result = result->next) {
                        if((result->type & usetype)) {
                                if(usenum == 0) {
-                                       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));
-                                       iolog_trigger(IOLOG_DEBUG, "using IPv%s Address (%s) as bind address", (useip6 ? "6" : "4"), errbuf);
+                                       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));
+                                       iolog_trigger(IOLOG_DEBUG, "using IPv%s Address (%s) as bind address", ((usetype == IODNS_RECORD_AAAA) ? "6" : "4"), errbuf);
                                        IOSOCKET_APPLY_COPYADDR(bind)
                                        break;
                                }
@@ -381,13 +398,13 @@ static int iosocket_lookup_apply(struct _IOSocket *iosock, int noip6) {
                iosock->bind.addr.addresslen = 0;
        
        if(dest_lookup) {
-               int usenum = (useip6 ? dest_numip6 : dest_numip4);
+               int usenum = ((usetype == IODNS_RECORD_AAAA) ? dest_numip6 : dest_numip4);
                usenum = rand() % usenum;
                for(result = dest_lookup->result; result; result = result->next) {
                        if((result->type & usetype)) {
                                if(usenum == 0) {
-                                       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));
-                                       iolog_trigger(IOLOG_DEBUG, "using IPv%s Address (%s) as dest address", (useip6 ? "6" : "4"), errbuf);
+                                       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));
+                                       iolog_trigger(IOLOG_DEBUG, "using IPv%s Address (%s) as dest address", ((usetype == IODNS_RECORD_AAAA) ? "6" : "4"), errbuf);
                                        IOSOCKET_APPLY_COPYADDR(dest)
                                        break;
                                }
@@ -397,24 +414,46 @@ static int iosocket_lookup_apply(struct _IOSocket *iosock, int noip6) {
        } else
                iosock->dest.addr.addresslen = 0;
        
-       iosocket_lookup_clear:
+       iosocket_lookup_apply_end:
+       
+       if((iosock->socket_flags & IOSOCKETFLAG_DNSERROR)) {
+               // TODO: trigger error
+               iolog_trigger(IOLOG_ERROR, "error while trying to apply dns lookup information: %s", errbuf);
+               
+               if((iosock->socket_flags & IOSOCKETFLAG_PARENT_PUBLIC)) {
+                       //trigger event
+                       struct IOSocket *iosocket = iosock->parent;
+                       
+                       struct IOSocketEvent callback_event;
+                       callback_event.type = IOSOCKETEVENT_DNSFAILED;
+                       callback_event.socket = iosocket;
+                       callback_event.data.recv_str = errbuf;
+                       iosocket_trigger_event(&callback_event);
+                       
+                       iosocket_close(iosocket);
+               } else {
+                       // TODO: IODNS Callback
+               }
+               return 0;
+       } else
+               return 1;
+}
+
+static void socket_lookup_clear(struct _IOSocket *iosock) {
+       struct IOSocketDNSLookup *bind_lookup = ((iosock->socket_flags & IOSOCKETFLAG_DNSDONE_BINDDNS) ? iosock->bind.addrlookup : NULL);
+       struct IOSocketDNSLookup *dest_lookup = ((iosock->socket_flags & IOSOCKETFLAG_DNSDONE_DESTDNS) ? iosock->dest.addrlookup : NULL);
        if(bind_lookup) {
                if(bind_lookup->result)
                        iodns_free_result(bind_lookup->result);
                free(bind_lookup);
+               iosock->bind.addrlookup = NULL;
        }
        if(dest_lookup) {
                if(dest_lookup->result)
                        iodns_free_result(dest_lookup->result);
                free(dest_lookup);
+               iosock->dest.addrlookup = NULL;
        }
-       
-       if((iosock->socket_flags & IOSOCKETFLAG_DNSERROR)) {
-               // TODO: trigger error
-               
-               return 0;
-       } else
-               return 1;
 }
 
 static void iosocket_prepare_fd(int sockfd) {
@@ -439,13 +478,37 @@ static void iosocket_prepare_fd(int sockfd) {
                fcntl_flags = fcntl(sockfd, F_GETFD);
                fcntl(sockfd, F_SETFD, fcntl_flags|FD_CLOEXEC);
        }
-       #else
-       /* I hope you're using the Win32 backend or something else that
-        * automatically marks the file descriptor non-blocking...
-        */
+       #elif defined(FIONBIO)
+       {
+               unsigned long ulong = 1;
+               ioctlsocket(sockfd, FIONBIO, &ulong);
+       }
        #endif
 }
 
+static void iosocket_update_parent(struct _IOSocket *iosock) {
+       if((iosock->socket_flags & IOSOCKETFLAG_PARENT_PUBLIC)) {
+               struct IOSocket *iosocket = iosock->parent;
+               iosocket->ipv6 = ((iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET) ? 1 : 0);
+               if(!(iosock->socket_flags & IOSOCKETFLAG_LISTENING))
+                       iosocket->remoteaddr = &iosock->dest.addr;
+               iosocket->localaddr = &iosock->bind.addr;
+               if(iosock->bind.addr.addresslen && (iosock->socket_flags & IOSOCKETFLAG_DYNAMIC_BIND)) {
+                       free(iosock->bind.addr.address);
+                       iosock->bind.addr.addresslen = 0;
+               }
+               if(!iosock->bind.addr.addresslen) {
+                       iosock->socket_flags |= IOSOCKETFLAG_DYNAMIC_BIND;
+                       if(iosocket->ipv6)
+                               iosock->bind.addr.addresslen = sizeof(struct sockaddr_in6);
+                       else
+                               iosock->bind.addr.addresslen = sizeof(struct sockaddr_in);
+                       iosock->bind.addr.address = malloc(iosock->bind.addr.addresslen);
+                       getsockname(iosock->fd, (struct sockaddr *)iosock->bind.addr.address, (socklen_t *)&iosock->bind.addr.addresslen);
+               }
+       }
+} 
+
 static void iosocket_connect_finish(struct _IOSocket *iosock) {
        int sockfd;
        if((iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET))
@@ -465,7 +528,7 @@ static void iosocket_connect_finish(struct _IOSocket *iosock) {
                ip6->sin6_family = AF_INET6;
                ip6->sin6_port = htons(iosock->port);
                
-               if(iosock->bind.addr.addresslen) {
+               if(iosock->bind.addr.addresslen && !(iosock->socket_flags & IOSOCKETFLAG_DYNAMIC_BIND)) {
                        struct sockaddr_in6 *ip6bind = (void*) iosock->bind.addr.address;
                        ip6bind->sin6_family = AF_INET6;
                        ip6bind->sin6_port = htons(0);
@@ -477,7 +540,7 @@ static void iosocket_connect_finish(struct _IOSocket *iosock) {
                ip4->sin_family = AF_INET;
                ip4->sin_port = htons(iosock->port);
                
-               if(iosock->bind.addr.addresslen) {
+               if(iosock->bind.addr.addresslen && !(iosock->socket_flags & IOSOCKETFLAG_DYNAMIC_BIND)) {
                        struct sockaddr_in *ip4bind = (void*) iosock->bind.addr.address;
                        ip4bind->sin_family = AF_INET;
                        ip4bind->sin_port = htons(0);
@@ -488,7 +551,9 @@ static void iosocket_connect_finish(struct _IOSocket *iosock) {
        
        iosocket_prepare_fd(sockfd);
        
-       connect(sockfd, iosock->dest.addr.address, iosock->dest.addr.addresslen); //returns EINPROGRESS here (nonblocking)
+       int ret = connect(sockfd, iosock->dest.addr.address, iosock->dest.addr.addresslen); //returns EINPROGRESS here (nonblocking)
+       iolog_trigger(IOLOG_DEBUG, "connecting socket (connect: %d)", ret);
+       
        iosock->fd = sockfd;
        iosock->socket_flags |= IOSOCKETFLAG_CONNECTING;
        
@@ -512,7 +577,7 @@ static void iosocket_listen_finish(struct _IOSocket *iosock) {
        if((iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET)) {
                struct sockaddr_in6 *ip6bind = (void*) iosock->bind.addr.address;
                ip6bind->sin6_family = AF_INET6;
-               ip6bind->sin6_port = htons(0);
+               ip6bind->sin6_port = htons(iosock->port);
                
                int opt = 1;
                setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
@@ -521,7 +586,7 @@ static void iosocket_listen_finish(struct _IOSocket *iosock) {
        } else {
                struct sockaddr_in *ip4bind = (void*) iosock->bind.addr.address;
                ip4bind->sin_family = AF_INET;
-               ip4bind->sin_port = htons(0);
+               ip4bind->sin_port = htons(iosock->port);
                
                int opt = 1;
                setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
@@ -533,6 +598,7 @@ static void iosocket_listen_finish(struct _IOSocket *iosock) {
        
        listen(sockfd, 1);
        iosock->fd = sockfd;
+       iosocket_update_parent(iosock);
        
        iosocket_activate(iosock);
 }
@@ -552,6 +618,7 @@ struct _IOSocket *iosocket_accept_client(struct _IOSocket *iosock) {
        }
        new_iosocket->iosocket = new_iosock;
        new_iosocket->status = IOSOCKET_CONNECTED;
+       new_iosocket->data = iosock;
        new_iosock->parent = new_iosocket;
        new_iosock->socket_flags |= IOSOCKETFLAG_PARENT_PUBLIC | IOSOCKETFLAG_INCOMING | (iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET);
        
@@ -591,9 +658,14 @@ struct _IOSocket *iosocket_accept_client(struct _IOSocket *iosock) {
        if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {
                new_iosocket->ssl = 1;
                new_iosock->socket_flags |= IOSOCKETFLAG_SSLSOCKET;
-               //TODO: SSL Handshake
+               \r
+               iossl_client_accepted(iosock, new_iosock);
+       } else {
+               //initialize readbuf
+               iosocket_increase_buffer(&iosock->readbuf, 1024);
        }
        
+       iosocket_update_parent(new_iosock);
        iosocket_activate(new_iosock);
        return new_iosock;
 }
@@ -686,12 +758,6 @@ struct IOSocket *iosocket_listen_flags(const char *hostname, unsigned int port,
        iosock->parent = iodescriptor;
        iosock->socket_flags |= IOSOCKETFLAG_PARENT_PUBLIC | IOSOCKETFLAG_LISTENING;
        iosock->port = port;
-       /*
-       if(ssl) {
-               iodescriptor->ssl = 1;
-               iosock->socket_flags |= IOSOCKETFLAG_SSLSOCKET;
-       }
-       */
        
        switch(iosocket_parse_address(hostname, &iosock->bind.addr, flags)) {
        case -1:
@@ -717,8 +783,11 @@ struct IOSocket *iosocket_listen_ssl(const char *hostname, unsigned int port, co
 }
 
 struct IOSocket *iosocket_listen_ssl_flags(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iosocket_callback *callback, int flags) {
-       //TODO: SSL
-       return NULL;
+       struct IOSocket *iosocket = iosocket_listen_flags(hostname, port, callback, flags);\r
+       struct _IOSocket *iosock = iosocket->iosocket;\r
+       iosock->socket_flags |= IOSOCKETFLAG_SSLSOCKET;\r
+       iossl_listen(iosock, certfile, keyfile);
+       return iosocket;
 }
 
 void iosocket_close(struct IOSocket *iosocket) {
@@ -746,9 +815,8 @@ void iosocket_close(struct IOSocket *iosocket) {
                iosocket_try_write(iosock);
        }
        //close IOSocket
-       if(iosock->sslnode) {
-               //TODO: SSL
-       }
+       if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET))
+               iossl_disconnect(iosock);
        if(iosock->fd)
                close(iosock->fd);
        _free_socket(iosock);
@@ -757,14 +825,40 @@ void iosocket_close(struct IOSocket *iosocket) {
        iogc_add(iosocket);
 }
 
+struct IODNSAddress *iosocket_get_remote_addr(struct IOSocket *iosocket) {
+       struct _IOSocket *iosock = iosocket->iosocket;
+       if(iosock == NULL) {
+               iolog_trigger(IOLOG_WARNING, "called iosocket_get_remote_addr for destroyed IOSocket in %s:%d", __FILE__, __LINE__);
+               return NULL;
+       }
+       if(iosock->socket_flags & IOSOCKETFLAG_PENDING_DESTDNS)
+               return NULL;
+       if(!iosock->dest.addr.addresslen)
+               return NULL;
+       return &iosock->dest.addr;
+}
+
+struct IODNSAddress *iosocket_get_local_addr(struct IOSocket *iosocket) {
+       struct _IOSocket *iosock = iosocket->iosocket;
+       if(iosock == NULL) {
+               iolog_trigger(IOLOG_WARNING, "called iosocket_get_local_addr for destroyed IOSocket in %s:%d", __FILE__, __LINE__);
+               return NULL;
+       }
+       if(iosock->socket_flags & IOSOCKETFLAG_PENDING_BINDDNS)
+               return NULL;
+       if(!iosock->bind.addr.addresslen)
+               return NULL;
+       return &iosock->bind.addr;
+}
+
 static int iosocket_try_write(struct _IOSocket *iosock) {
-       if(!iosock->writebuf.bufpos) return 0;
+       if(!iosock->writebuf.bufpos && !(iosock->socket_flags & IOSOCKETFLAG_SSL_WRITEHS)) \r
+               return 0;
        iolog_trigger(IOLOG_DEBUG, "write writebuf (%d bytes) to socket (fd: %d)", iosock->writebuf.bufpos, iosock->fd);
        int res;
-       if(iosock->sslnode) {
-               /* res = iohandler_ssl_write(iofd, iofd->writebuf.buffer, iofd->writebuf.bufpos); */
-               // TODO
-       } else
+       if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET))
+               res = iossl_write(iosock, iosock->writebuf.buffer, iosock->writebuf.bufpos);
+       else
                res = send(iosock->fd, iosock->writebuf.buffer, iosock->writebuf.bufpos, 0);
        if(res < 0) {
                if (errno != EAGAIN && errno != EWOULDBLOCK)
@@ -773,7 +867,7 @@ static int iosocket_try_write(struct _IOSocket *iosock) {
                        res = 0;
        } else {
                iosock->writebuf.bufpos -= res;
-               if((iosock->socket_flags & (IOSOCKETFLAG_ACTIVE & IOSOCKETFLAG_SHUTDOWN)) == IOSOCKETFLAG_ACTIVE)
+               if((iosock->socket_flags & (IOSOCKETFLAG_ACTIVE | IOSOCKETFLAG_SHUTDOWN)) == IOSOCKETFLAG_ACTIVE)
                        engine->update(iosock);
        }
        return res;
@@ -815,15 +909,36 @@ void iosocket_printf(struct IOSocket *iosocket, const char *text, ...) {
        int pos;
        sendBuf[0] = '\0';
        va_start(arg_list, text);
-       pos = vsnprintf(sendBuf, IOSOCKET_PRINTF_LINE_LEN - 2, text, arg_list);
+       pos = vsnprintf(sendBuf, IOSOCKET_PRINTF_LINE_LEN - 1, text, arg_list);
        va_end(arg_list);
-       if (pos < 0 || pos > (IOSOCKET_PRINTF_LINE_LEN - 2)) pos = IOSOCKET_PRINTF_LINE_LEN - 2;
-       sendBuf[pos] = '\n';
-       sendBuf[pos+1] = '\0';
-       iosocket_send(iosocket, sendBuf, pos+1);
+       if (pos < 0 || pos > (IOSOCKET_PRINTF_LINE_LEN - 1)) pos = IOSOCKET_PRINTF_LINE_LEN - 1;
+       sendBuf[pos] = '\0';
+       iosocket_send(iosocket, sendBuf, pos);
 }
 
 
+int iosocket_wants_reads(struct _IOSocket *iosock) {
+       if((iosock->socket_flags & (IOSOCKETFLAG_SSL_READHS | IOSOCKETFLAG_SSL_WRITEHS)))
+               return ((iosock->socket_flags & IOSOCKETFLAG_SSL_WANTWRITE) ? 0 : 1);
+       if(!(iosock->socket_flags & IOSOCKETFLAG_OVERRIDE_WANT_RW))
+               return 1;
+       else if((iosock->socket_flags & IOSOCKETFLAG_OVERRIDE_WANT_R))
+               return 1;
+       return 0;
+}
+int iosocket_wants_writes(struct _IOSocket *iosock) {
+       if((iosock->socket_flags & (IOSOCKETFLAG_SSL_READHS | IOSOCKETFLAG_SSL_WRITEHS)))
+               return ((iosock->socket_flags & IOSOCKETFLAG_SSL_WANTWRITE) ? 1 : 0);
+       if(!(iosock->socket_flags & IOSOCKETFLAG_OVERRIDE_WANT_RW)) {
+               if(iosock->writebuf.bufpos || (iosock->socket_flags & IOSOCKETFLAG_CONNECTING))
+                       return 1;
+               else
+                       return 0;
+       } else if((iosock->socket_flags & IOSOCKETFLAG_OVERRIDE_WANT_W))
+               return 1;
+       return 0;
+}
+
 
 static void iosocket_trigger_event(struct IOSocketEvent *event) {
        if(!event->socket->callback) 
@@ -840,7 +955,45 @@ void iosocket_events_callback(struct _IOSocket *iosock, int readable, int writea
                callback_event.socket = iosocket;
                
                if((iosock->socket_flags & IOSOCKETFLAG_SSL_HANDSHAKE)) {
-                       //TODO: SSL
+                       if(readable || writeable) {
+                               if((iosock->socket_flags & IOSOCKETFLAG_INCOMING)) 
+                                       iossl_server_handshake(iosock);
+                               else
+                                       iossl_client_handshake(iosock);
+                               engine->update(iosock);\r
+                       } else if((iosock->socket_flags & IOSOCKETFLAG_LISTENING)) {\r
+                               //TODO: SSL init error\r
+                       } else if((iosock->socket_flags & IOSOCKETFLAG_INCOMING)) {\r
+                               if((iosock->socket_flags & IOSOCKETFLAG_SSL_ESTABLISHED)) {\r
+                                       //incoming SSL connection accepted\r
+                                       iosock->socket_flags &= ~IOSOCKETFLAG_SSL_HANDSHAKE;\r
+                                       callback_event.type = IOSOCKETEVENT_ACCEPT;\r
+                                       callback_event.data.accept_socket = iosock->parent;
+                                       struct _IOSocket *parent_socket = iosocket->data;
+                                       callback_event.socket = parent_socket->parent;
+                                       
+                                       //initialize readbuf
+                                       iosocket_increase_buffer(&iosock->readbuf, 1024);\r
+                               } else {\r
+                                       //incoming SSL connection failed, simply drop\r
+                                       iosock->socket_flags |= IOSOCKETFLAG_DEAD;\r
+                                       iolog_trigger(IOLOG_ERROR, "SSL Handshake failed for incoming connection. Dropping fd %d", iosock->fd);\r
+                               }
+                       } else {
+                               // SSL Backend finished
+                               if((iosock->socket_flags & IOSOCKETFLAG_SSL_ESTABLISHED)) {\r
+                                       iosocket->status = IOSOCKET_CONNECTED;\r
+                                       iosock->socket_flags &= ~IOSOCKETFLAG_SSL_HANDSHAKE;\r
+                                       callback_event.type = IOSOCKETEVENT_CONNECTED;\r
+                                       engine->update(iosock);\r
+                                       \r
+                                       //initialize readbuf\r
+                                       iosocket_increase_buffer(&iosock->readbuf, 1024);
+                               } else {
+                                       callback_event.type = IOSOCKETEVENT_NOTCONNECTED;\r
+                                       iosock->socket_flags |= IOSOCKETFLAG_DEAD;
+                               }
+                       }
                } else if((iosock->socket_flags & IOSOCKETFLAG_LISTENING)) {
                        if(readable) {
                                //new client connected
@@ -856,48 +1009,89 @@ void iosocket_events_callback(struct _IOSocket *iosock, int readable, int writea
                        
                } else if((iosock->socket_flags & IOSOCKETFLAG_CONNECTING)) {
                        if(readable) { //could not connect
-                               callback_event.type = IOSOCKETEVENT_NOTCONNECTED;
-                               /*
-                               socklen_t arglen = sizeof(callback_event.data.errid);
-                               if (getsockopt(iosock->fd, SOL_SOCKET, SO_ERROR, &callback_event.data.errid, &arglen) < 0)
-                                       callback_event.data.errid = errno;
-                               */
-                               iosock->socket_flags |= IOSOCKETFLAG_DEAD;
+                               if((iosock->socket_flags & (IOSOCKETFLAG_IPV6SOCKET | IOSOCKETFLAG_RECONNECT_IPV4)) == (IOSOCKETFLAG_IPV6SOCKET | IOSOCKETFLAG_RECONNECT_IPV4)) {
+                                       iolog_trigger(IOLOG_DEBUG, "connecting to IPv6 host (%s) failed. trying to connect using IPv4.", iosock->dest.addrlookup->hostname);
+                                       iosocket_deactivate(iosock);
+                                       if(iosocket_lookup_apply(iosock, 1)) { //if ret=0 an error occured in iosocket_lookup_apply and we should stop here.
+                                               iosocket_connect_finish(iosock);
+                                               socket_lookup_clear(iosock);
+                                       }
+                               } else {
+                                       callback_event.type = IOSOCKETEVENT_NOTCONNECTED;
+                                       /*
+                                       socklen_t arglen = sizeof(callback_event.data.errid);
+                                       if (getsockopt(iosock->fd, SOL_SOCKET, SO_ERROR, &callback_event.data.errid, &arglen) < 0)
+                                               callback_event.data.errid = errno;
+                                       */
+                                       iosock->socket_flags |= IOSOCKETFLAG_DEAD;
+                               }
                        } else if(writeable) { //connection established
-                               iosocket->status = IOSOCKET_CONNECTED;
-                               if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {
-                                       //TODO: SSL Handshake
+                               iosock->socket_flags &= ~IOSOCKETFLAG_CONNECTING;
+                               socket_lookup_clear(iosock);
+                               if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {\r
+                                       iolog_trigger(IOLOG_DEBUG, "SSL client socket connected. Stating SSL handshake...");
+                                       iossl_connect(iosock);
+                                       engine->update(iosock);
                                        return;
                                }
+                               iosocket->status = IOSOCKET_CONNECTED;
                                
                                callback_event.type = IOSOCKETEVENT_CONNECTED;
-                               iosock->socket_flags &= ~IOSOCKETFLAG_CONNECTING;
                                engine->update(iosock);
                                
+                               iosocket_update_parent(iosock);
+                               
                                //initialize readbuf
                                iosocket_increase_buffer(&iosock->readbuf, 1024);
                        }
-               } else {
-                       if(readable) {
+               } else {\r
+                       int ssl_rehandshake = 0;\r
+                       if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {\r
+                               if((iosock->socket_flags & IOSOCKETFLAG_SSL_READHS))\r
+                                       ssl_rehandshake = 1;\r
+                               else if((iosock->socket_flags & IOSOCKETFLAG_SSL_WRITEHS))\r
+                                       ssl_rehandshake = 2;\r
+                       }
+                       iosocketevents_callback_retry_read:
+                       if((readable && ssl_rehandshake == 0) || ssl_rehandshake == 1) {
                                int bytes;
-                               if(iosock->readbuf.buflen - iosock->readbuf.bufpos >= 128)
-                                       iosocket_increase_buffer(&iosock->readbuf, iosock->readbuf.buflen + 1024);
-                               if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {
-                                       //TODO: SSL read
-                               } else 
+                               if(iosock->readbuf.buflen - iosock->readbuf.bufpos <= 128) {
+                                       int addsize;
+                                       if(iosock->readbuf.buflen >= 2048)
+                                               addsize = 1024;
+                                       else
+                                               addsize = iosock->readbuf.buflen;
+                                       if(addsize == 0) {
+                                               iolog_trigger(IOLOG_WARNING, "readbuf length is 0 when trying to read from fd %d", iosock->fd);
+                                               addsize = 512;
+                                       }
+                                       iosocket_increase_buffer(&iosock->readbuf, iosock->readbuf.buflen + addsize);
+                               }
+                               if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET))
+                                       bytes = iossl_read(iosock, iosock->readbuf.buffer + iosock->readbuf.bufpos, iosock->readbuf.buflen - iosock->readbuf.bufpos);
+                               else 
                                        bytes = recv(iosock->fd, iosock->readbuf.buffer + iosock->readbuf.bufpos, iosock->readbuf.buflen - iosock->readbuf.bufpos, 0);
-                                       
+                               
                                if(bytes <= 0) {
-                                       if (errno != EAGAIN || errno != EWOULDBLOCK) {
+                                       int errcode;
+                                       #ifdef WIN32
+                                       errcode = WSAGetLastError();
+                                       #else
+                                       errcode = errno;
+                                       #endif\r
+                                       if((iosock->socket_flags & (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_READHS)) == (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_READHS)) {\r
+                                               ssl_rehandshake = 1;\r
+                                       } else if (errcode != EAGAIN && errcode != EWOULDBLOCK) {
                                                iosock->socket_flags |= IOSOCKETFLAG_DEAD;
                                                
                                                callback_event.type = IOSOCKETEVENT_CLOSED;
-                                               callback_event.data.errid = errno;
+                                               callback_event.data.errid = errcode;
                                        }
                                } else {
                                        int i;
                                        iolog_trigger(IOLOG_DEBUG, "received %d bytes (fd: %d). readbuf position: %d", bytes, iosock->fd, iosock->readbuf.bufpos);
                                        iosock->readbuf.bufpos += bytes;
+                                       int retry_read = (iosock->readbuf.bufpos == iosock->readbuf.buflen);
                                        callback_event.type = IOSOCKETEVENT_RECV;
                                        
                                        if(iosocket->parse_delimiter) {
@@ -946,19 +1140,27 @@ void iosocket_events_callback(struct _IOSocket *iosock, int readable, int writea
                                                callback_event.type = IOSOCKETEVENT_IGNORE;
                                        } else
                                                callback_event.data.recv_buf = &iosock->readbuf;
+                                       if(retry_read)
+                                               goto iosocketevents_callback_retry_read;
                                }
                        }
-                       if(writeable) {
+                       if((writeable && ssl_rehandshake == 0) || ssl_rehandshake == 2) {
                                int bytes;
                                bytes = iosocket_try_write(iosock);
-                               if(bytes < 0) {
-                                       iosock->socket_flags |= IOSOCKETFLAG_DEAD;
-                                       
-                                       callback_event.type = IOSOCKETEVENT_CLOSED;
-                                       callback_event.data.errid = errno;
+                               if(bytes < 0) {\r
+                                       if((iosock->socket_flags & (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_WRITEHS)) == (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_WRITEHS)) {\r
+                                               ssl_rehandshake = 1;\r
+                                       } else {
+                                               iosock->socket_flags |= IOSOCKETFLAG_DEAD;
+                                               
+                                               callback_event.type = IOSOCKETEVENT_CLOSED;
+                                               callback_event.data.errid = errno;\r
+                                       }
                                }
+                       }\r
+                       if(ssl_rehandshake) {
+                               engine->update(iosock);\r
                        }
-                       
                }
                if(callback_event.type != IOSOCKETEVENT_IGNORE)
                        iosocket_trigger_event(&callback_event);
@@ -966,7 +1168,7 @@ void iosocket_events_callback(struct _IOSocket *iosock, int readable, int writea
                        iosocket_close(iosocket);
                
        } else if((iosock->socket_flags & IOSOCKETFLAG_PARENT_DNSENGINE)) {
-               //TODO: IODNS callback
+               iodns_socket_callback(iosock, readable, writeable);
        }
 }