#include "IOSockets.h"
#include "IOLog.h"
#include "IODNSLookup.h"
+#include "IOSSLBackend.h"
#ifdef WIN32
#define _WIN32_WINNT 0x501
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
+#include <fcntl.h>
#endif
#include "compat/inet.h"
#include <stdio.h>
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);
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();
}
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;
fcntl_flags = fcntl(sockfd, F_GETFD);
fcntl(sockfd, F_SETFD, fcntl_flags|FD_CLOEXEC);
}
- #else
+ #elif defined(FIONBIO)
{
unsigned long ulong = 1;
ioctlsocket(sockfd, FIONBIO, &ulong);
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));
} 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));
}
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);
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);
}
iosocket_activate(new_iosock);
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:
}
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) {
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);
}
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)
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;
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)
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
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;
- socket_lookup_clear(iosock);
engine->update(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;
+ 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) {\r
+ if((iosock->socket_flags & (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_READHS)) == (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_READHS)) {\r
+ ssl_rehandshake = 1;\r
+ } else if (errno != EAGAIN || errno != EWOULDBLOCK) {
iosock->socket_flags |= IOSOCKETFLAG_DEAD;
callback_event.type = IOSOCKETEVENT_CLOSED;
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) {
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);
iosocket_close(iosocket);
} else if((iosock->socket_flags & IOSOCKETFLAG_PARENT_DNSENGINE)) {
- //TODO: IODNS callback
+ iodns_socket_callback(iosock, readable, writeable);
}
}