X-Git-Url: http://git.pk910.de/?p=NeonServV5.git;a=blobdiff_plain;f=src%2FIOHandler.c;h=b2a391bf11e68388112f107a56747f84f6e8cde2;hp=81d8d0982fd70c9d8db824427baed4acf7fba361;hb=f83bd22fe2dcb3ca0ddb9321944ee0b9c9b61ea6;hpb=04c00b8d06569ade0bac58d01d65f2051d697549 diff --git a/src/IOHandler.c b/src/IOHandler.c index 81d8d09..b2a391b 100644 --- a/src/IOHandler.c +++ b/src/IOHandler.c @@ -73,20 +73,30 @@ extern struct IOEngine engine_kevent; extern struct IOEngine engine_epoll; extern struct IOEngine engine_win32; +int iohandler_settings = 0; struct IOEngine *engine = NULL; +void iohandler_set(int setting, int value) { + if(value) + iohandler_settings |= setting; + else + iohandler_settings &= ~setting; +} + static void iohandler_init_engine() { if(engine) return; IOTHREAD_MUTEX_INIT(io_thread_sync); IOTHREAD_MUTEX_INIT(io_poll_sync); //try other engines - if(!engine && engine_kevent.init && engine_kevent.init()) - engine = &engine_kevent; - if(!engine && engine_epoll.init && engine_epoll.init()) - engine = &engine_epoll; - if(!engine && engine_win32.init && engine_win32.init()) - engine = &engine_win32; + if(!(iohandler_settings & IOHANDLER_SETTING_HIGH_PRECISION_TIMER)) { + if(!engine && engine_kevent.init && engine_kevent.init()) + engine = &engine_kevent; + if(!engine && engine_epoll.init && engine_epoll.init()) + engine = &engine_epoll; + if(!engine && engine_win32.init && engine_win32.init()) + engine = &engine_win32; + } if (!engine) { if(engine_select.init()) @@ -185,8 +195,13 @@ struct IODescriptor *iohandler_add(int sockfd, enum IOType type, struct timeval descriptor->type = type; descriptor->state = (type == IOTYPE_STDIN ? IO_CONNECTED : IO_CLOSED); descriptor->callback = callback; - if(timeout) + if(timeout) { descriptor->timeout = *timeout; + if(descriptor->timeout.tv_usec > 1000000) { + descriptor->timeout.tv_usec -= 1000000; + descriptor->timeout.tv_sec++; + } + } if(type != IOTYPE_TIMER) { descriptor->readbuf.buffer = malloc(IO_READ_BUFLEN + 2); descriptor->readbuf.bufpos = 0; @@ -220,9 +235,20 @@ void iohandler_set_timeout(struct IODescriptor *descriptor, struct timeval *time descriptor->next->prev = descriptor->prev; if(descriptor == timer_priority) timer_priority = descriptor->next; - if(timeout) + if(timeout && timeout->tv_sec == 0 && descriptor->constant_timeout) { + descriptor->timeout.tv_usec += (descriptor->constant_timeout % 1000) * 1000; + descriptor->timeout.tv_sec += (descriptor->constant_timeout / 1000); + if(descriptor->timeout.tv_usec > 1000000) { + descriptor->timeout.tv_sec += (descriptor->timeout.tv_usec / 1000000); + descriptor->timeout.tv_usec %= 1000000; + } + } else if(timeout) { descriptor->timeout = *timeout; - else { + if(descriptor->timeout.tv_usec > 1000000) { + descriptor->timeout.tv_usec -= 1000000; + descriptor->timeout.tv_sec++; + } + } else { descriptor->timeout.tv_sec = 0; descriptor->timeout.tv_usec = 0; } @@ -249,7 +275,31 @@ struct IODescriptor *iohandler_timer(struct timeval timeout, iohandler_callback return descriptor; } +struct IODescriptor *iohandler_constant_timer(int msec, iohandler_callback *callback) { + struct IODescriptor *descriptor; + struct timeval timeout; + gettimeofday(&timeout, NULL); + timeout.tv_usec += (msec % 1000) * 1000; + timeout.tv_sec += (msec / 1000); + if(timeout.tv_usec > 1000000) { + timeout.tv_sec += (timeout.tv_usec / 1000000); + timeout.tv_usec %= 1000000; + } + descriptor = iohandler_add(-1, IOTYPE_TIMER, &timeout, callback); + if(!descriptor) { + iohandler_log(IOLOG_ERROR, "could not allocate memory for IODescriptor in %s:%d", __FILE__, __LINE__); + return NULL; + } + descriptor->constant_timeout = msec; + iohandler_log(IOLOG_DEBUG, "added timer descriptor (sec: %d; usec: %d)", timeout.tv_sec, timeout.tv_usec); + return descriptor; +} + struct IODescriptor *iohandler_connect(const char *hostname, unsigned int port, int ssl, const char *bindhost, iohandler_callback *callback) { + return iohandler_connect_flags(hostname, port, ssl, bindhost, callback, IOHANDLER_CONNECT_IPV4 | IOHANDLER_CONNECT_IPV6); +} + +struct IODescriptor *iohandler_connect_flags(const char *hostname, unsigned int port, int ssl, const char *bindhost, iohandler_callback *callback, int flags) { //non-blocking connect int sockfd, result; struct addrinfo hints, *res; @@ -284,7 +334,7 @@ struct IODescriptor *iohandler_connect(const char *hostname, unsigned int port, freeaddrinfo(res); } - if(ip6) { + if(ip6 && (flags & IOHANDLER_CONNECT_IPV6)) { sockfd = socket(AF_INET6, SOCK_STREAM, 0); if(sockfd == -1) { iohandler_log(IOLOG_ERROR, "could not create socket in %s:%d", __FILE__, __LINE__); @@ -313,7 +363,7 @@ struct IODescriptor *iohandler_connect(const char *hostname, unsigned int port, } dstaddr = (struct sockaddr*)ip6; dstaddrlen = sizeof(*ip6); - } else if(ip4) { + } else if(ip4 && (flags & IOHANDLER_CONNECT_IPV4)) { sockfd = socket(AF_INET, SOCK_STREAM, 0); if(sockfd == -1) { iohandler_log(IOLOG_ERROR, "could not create socket in %s:%d", __FILE__, __LINE__); @@ -384,6 +434,10 @@ struct IODescriptor *iohandler_connect(const char *hostname, unsigned int port, } struct IODescriptor *iohandler_listen(const char *hostname, unsigned int port, iohandler_callback *callback) { + return iohandler_listen_flags(hostname, port, callback, IOHANDLER_LISTEN_IPV4 | IOHANDLER_LISTEN_IPV6); +} + +struct IODescriptor *iohandler_listen_flags(const char *hostname, unsigned int port, iohandler_callback *callback, int flags) { int sockfd; struct addrinfo hints, *res; struct sockaddr_in *ip4 = NULL; @@ -415,7 +469,7 @@ struct IODescriptor *iohandler_listen(const char *hostname, unsigned int port, i freeaddrinfo(res); } - if(ip6) { + if(ip6 && (flags & IOHANDLER_LISTEN_IPV6)) { sockfd = socket(AF_INET6, SOCK_STREAM, 0); if(sockfd == -1) return NULL; @@ -426,7 +480,7 @@ struct IODescriptor *iohandler_listen(const char *hostname, unsigned int port, i ip6->sin6_port = htons(port); bind(sockfd, (struct sockaddr*)ip6, sizeof(*ip6)); - } else if(ip4) { + } else if(ip4 && (flags && IOHANDLER_LISTEN_IPV4)) { sockfd = socket(AF_INET, SOCK_STREAM, 0); if(sockfd == -1) return NULL; @@ -453,11 +507,11 @@ struct IODescriptor *iohandler_listen(const char *hostname, unsigned int port, i //make sockfd unblocking #if defined(F_GETFL) { - int flags; - flags = fcntl(sockfd, F_GETFL); - fcntl(sockfd, F_SETFL, flags|O_NONBLOCK); - flags = fcntl(sockfd, F_GETFD); - fcntl(sockfd, F_SETFD, flags|FD_CLOEXEC); + int flag; + flag = fcntl(sockfd, F_GETFL); + fcntl(sockfd, F_SETFL, flag|O_NONBLOCK); + flag = fcntl(sockfd, F_GETFD); + fcntl(sockfd, F_SETFD, flag|FD_CLOEXEC); } #else /* I hope you're using the Win32 backend or something else that @@ -476,6 +530,21 @@ struct IODescriptor *iohandler_listen(const char *hostname, unsigned int port, i return descriptor; } +struct IODescriptor *iohandler_listen_ssl(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iohandler_callback *callback) { + return iohandler_listen_ssl_flags(hostname, port, certfile, keyfile, callback, IOHANDLER_LISTEN_IPV4 | IOHANDLER_LISTEN_IPV6); +} + +struct IODescriptor *iohandler_listen_ssl_flags(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iohandler_callback *callback, int flags) { + struct IODescriptor *descriptor = iohandler_listen_flags(hostname, port, callback, flags); + if(!descriptor) + return NULL; + //SSL Server Socket + iohandler_ssl_listen(descriptor, certfile, keyfile); + if(descriptor->sslnode) + descriptor->ssl = 1; + return descriptor; +} + void iohandler_write(struct IODescriptor *iofd, const char *line) { size_t linelen = strlen(line); iohandler_send(iofd, line, linelen); @@ -580,9 +649,15 @@ void iohandler_events(struct IODescriptor *iofd, int readable, int writeable) { switch(iofd->state) { case IO_SSLWAIT: if(!readable && !writeable) { - callback_event.type = IOEVENT_SSLFAILED; - iofd->state = IO_CLOSED; - engine->update(iofd); + if(!iofd->ssl_server_hs) { + callback_event.type = IOEVENT_SSLFAILED; + iofd->state = IO_CLOSED; + engine->update(iofd); + } else + iohandler_close(iofd); + } else if(iofd->ssl_server_hs) { + iohandler_log(IOLOG_DEBUG, "triggering iohandler_ssl_server_handshake for %s (fd: %d)", iohandler_iotype_name(iofd->type), iofd->fd); + iohandler_ssl_server_handshake(iofd); } else { iohandler_log(IOLOG_DEBUG, "triggering iohandler_ssl_client_handshake for %s (fd: %d)", iohandler_iotype_name(iofd->type), iofd->fd); iohandler_ssl_client_handshake(iofd); @@ -597,6 +672,9 @@ void iohandler_events(struct IODescriptor *iofd, int readable, int writeable) { callback_event.data.accept_fd = accept(iofd->fd, NULL, 0); if(callback_event.data.accept_fd < 0) { iohandler_log(IOLOG_ERROR, "could not accept client (server fd: %d): %d - %s", iofd->fd, errno, strerror(errno)); + } else if(iofd->ssl) { + struct IODescriptor *client_iofd = iohandler_add(callback_event.data.accept_fd, IOTYPE_CLIENT, NULL, NULL); + iohandler_ssl_client_accepted(iofd, client_iofd); } else callback_event.type = IOEVENT_ACCEPT; } @@ -616,7 +694,14 @@ void iohandler_events(struct IODescriptor *iofd, int readable, int writeable) { iohandler_ssl_connect(iofd); return; } - callback_event.type = IOEVENT_CONNECTED; + if(iofd->ssl && iofd->ssl_server_hs) { + callback_event.type = IOEVENT_SSLACCEPT; + callback_event.iofd = iofd->data; + callback_event.data.accept_iofd = iofd; + iofd->data = NULL; + } + else + callback_event.type = IOEVENT_CONNECTED; iofd->state = IO_CONNECTED; engine->update(iofd); } @@ -706,11 +791,15 @@ void iohandler_events(struct IODescriptor *iofd, int readable, int writeable) { } void iohandler_poll() { + struct timeval timeout; + timeout.tv_sec = IO_MAX_TIMEOUT; + timeout.tv_usec = 0; + iohandler_poll_timeout(timeout); +} + +void iohandler_poll_timeout(struct timeval timeout) { if(engine) { IOSYNCHRONIZE(io_poll_sync); //quite senceless multithread support... better support will follow - struct timeval timeout; - timeout.tv_sec = IO_MAX_TIMEOUT; - timeout.tv_usec = 0; engine->loop(&timeout); IODESYNCHRONIZE(io_poll_sync); } @@ -767,6 +856,8 @@ char *iohandler_ioeventtype_name(enum IOEventType type) { return "IOEVENT_CLOSED"; case IOEVENT_ACCEPT: return "IOEVENT_ACCEPT"; + case IOEVENT_SSLACCEPT: + return "IOEVENT_SSLACCEPT"; case IOEVENT_TIMEOUT: return "IOEVENT_TIMEOUT"; default: