X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=src%2FIOHandler%2FIOSockets.c;h=d67da512dfb0ae654179fe6eb1b2b378d29e6df0;hb=d2ac212695ab026aebc171d0d7c615f29c03a77c;hp=480d1ba39ae9bfecd10c2e79707eadd35137b31e;hpb=85880e098735c6edd527c4621328ef3494e26be7;p=NextIRCd.git diff --git a/src/IOHandler/IOSockets.c b/src/IOHandler/IOSockets.c index 480d1ba..d67da51 100644 --- a/src/IOHandler/IOSockets.c +++ b/src/IOHandler/IOSockets.c @@ -20,11 +20,15 @@ #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 #include +#include #include #else #include @@ -51,8 +55,6 @@ 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); @@ -92,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(); + iossl_init(); } @@ -140,24 +143,32 @@ void _free_socket(struct _IOSocket *iosock) { free(iosock->readbuf.buffer); if(iosock->writebuf.buffer) free(iosock->writebuf.buffer); + if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) + iossl_disconnect(iosock); 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; @@ -475,6 +486,29 @@ static void iosocket_prepare_fd(int sockfd) { #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)) @@ -494,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); @@ -506,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); @@ -543,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)); @@ -552,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)); @@ -564,6 +598,7 @@ static void iosocket_listen_finish(struct _IOSocket *iosock) { listen(sockfd, 1); iosock->fd = sockfd; + iosocket_update_parent(iosock); iosocket_activate(iosock); } @@ -583,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); @@ -622,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 + + 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; } @@ -717,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: @@ -748,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); + struct _IOSocket *iosock = iosocket->iosocket; + iosock->socket_flags |= IOSOCKETFLAG_SSLSOCKET; + iossl_listen(iosock, certfile, keyfile); + return iosocket; } void iosocket_close(struct IOSocket *iosocket) { @@ -777,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); @@ -789,13 +826,13 @@ void iosocket_close(struct IOSocket *iosocket) { } static int iosocket_try_write(struct _IOSocket *iosock) { - if(!iosock->writebuf.bufpos) return 0; + if(!iosock->writebuf.bufpos && !(iosock->socket_flags & IOSOCKETFLAG_SSL_WRITEHS)) + 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) @@ -804,7 +841,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; @@ -846,15 +883,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) @@ -871,7 +929,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); + } else if((iosock->socket_flags & IOSOCKETFLAG_LISTENING)) { + //TODO: SSL init error + } else if((iosock->socket_flags & IOSOCKETFLAG_INCOMING)) { + if((iosock->socket_flags & IOSOCKETFLAG_SSL_ESTABLISHED)) { + //incoming SSL connection accepted + iosock->socket_flags &= ~IOSOCKETFLAG_SSL_HANDSHAKE; + callback_event.type = IOSOCKETEVENT_ACCEPT; + 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); + } else { + //incoming SSL connection failed, simply drop + iosock->socket_flags |= IOSOCKETFLAG_DEAD; + iolog_trigger(IOLOG_ERROR, "SSL Handshake failed for incoming connection. Dropping fd %d", iosock->fd); + } + } else { + // SSL Backend finished + if((iosock->socket_flags & IOSOCKETFLAG_SSL_ESTABLISHED)) { + iosocket->status = IOSOCKET_CONNECTED; + iosock->socket_flags &= ~IOSOCKETFLAG_SSL_HANDSHAKE; + callback_event.type = IOSOCKETEVENT_CONNECTED; + engine->update(iosock); + + //initialize readbuf + iosocket_increase_buffer(&iosock->readbuf, 1024); + } else { + callback_event.type = IOSOCKETEVENT_NOTCONNECTED; + iosock->socket_flags |= IOSOCKETFLAG_DEAD; + } + } } else if((iosock->socket_flags & IOSOCKETFLAG_LISTENING)) { if(readable) { //new client connected @@ -904,32 +1000,56 @@ void iosocket_events_callback(struct _IOSocket *iosock, int readable, int writea 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)) { + 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; - socket_lookup_clear(iosock); engine->update(iosock); + iosocket_update_parent(iosock); + //initialize readbuf iosocket_increase_buffer(&iosock->readbuf, 1024); } - } else { - if(readable) { + } else { + int ssl_rehandshake = 0; + if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) { + if((iosock->socket_flags & IOSOCKETFLAG_SSL_READHS)) + ssl_rehandshake = 1; + else if((iosock->socket_flags & IOSOCKETFLAG_SSL_WRITEHS)) + ssl_rehandshake = 2; + } + 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) { + + if(bytes <= 0) { + if((iosock->socket_flags & (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_READHS)) == (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_READHS)) { + ssl_rehandshake = 1; + } else if (errno != EAGAIN || errno != EWOULDBLOCK) { iosock->socket_flags |= IOSOCKETFLAG_DEAD; callback_event.type = IOSOCKETEVENT_CLOSED; @@ -939,6 +1059,7 @@ void iosocket_events_callback(struct _IOSocket *iosock, int readable, int writea 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) { @@ -987,19 +1108,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) { + if((iosock->socket_flags & (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_WRITEHS)) == (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_WRITEHS)) { + ssl_rehandshake = 1; + } else { + iosock->socket_flags |= IOSOCKETFLAG_DEAD; + + callback_event.type = IOSOCKETEVENT_CLOSED; + callback_event.data.errid = errno; + } } + } + if(ssl_rehandshake) { + engine->update(iosock); } - } if(callback_event.type != IOSOCKETEVENT_IGNORE) iosocket_trigger_event(&callback_event); @@ -1007,7 +1136,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); } }