Merge remote-tracking branch 'origin/development'
authorpk910 <philipp@zoelle1.de>
Thu, 18 Oct 2012 23:04:15 +0000 (01:04 +0200)
committerpk910 <philipp@zoelle1.de>
Thu, 18 Oct 2012 23:04:15 +0000 (01:04 +0200)
configure.ac
src/ClientSocket.c
src/IOHandler.c
src/IOHandler.h
src/IOHandler_SSL.c
src/IOHandler_SSL.h
src/IRCParser.c
src/modules/NeonServ.mod/cmd_neonserv_users.c
src/test/Makefile
src/timeq.c

index 409d0a2b0312327419da2541f8faba7f5a818cd4..56d1e7f1ec3209fdf73519ff8ec9511c4db809a3 100644 (file)
@@ -1,6 +1,6 @@
 # Process this file with autoconf to produce a configure script.
 
-AC_PREREQ([2.67])
+AC_PREREQ([2.63])
 AC_INIT([NeonServ], [5.6], [bugs@pk910.de], [neonserv], [http://neonserv.krypton-bouncer.de])
 AC_PREFIX_DEFAULT([~/neonserv])
 AC_CANONICAL_TARGET
index d8faf26d4a0ec7c56ae3475f083b300300517df3..a624a305498337f8f2ff690144e78df2005a51c1 100644 (file)
@@ -100,9 +100,10 @@ struct ClientSocket* create_socket(char *host, int port, char *bindto, char *pas
 void connect_socket(struct ClientSocket *client) {
     client->iofd = iohandler_connect(client->host, client->port, ((client->flags & SOCKET_FLAG_SSL) ? 1 : 0), client->bind, socket_callback);
     client->iofd->data = client;
+    client->flags |= SOCKET_FLAG_RECONNECT;
 }
 
-int close_socket(struct ClientSocket *client) {
+static int _close_socket(struct ClientSocket *client) {
     if(client == NULL) return 0;
     if((client->flags & SOCKET_FLAG_CONNECTED)) {
         iohandler_printf(client->iofd, "QUIT :[NeonServ %s.%d] disconnect requested.\n", NEONSERV_VERSION, patchlevel);
@@ -122,6 +123,12 @@ int close_socket(struct ClientSocket *client) {
     return 1;
 }
 
+int close_socket(struct ClientSocket *client) { //external call (don't reconnect)
+    if(client == NULL) return 0;
+    client->flags &= ~SOCKET_FLAG_RECONNECT;
+    return _close_socket(client);
+}
+
 int destroy_socket(struct ClientSocket *client) {
     if(client == NULL) return 0;
     close_socket(client);
@@ -235,7 +242,7 @@ static IOHANDLER_CALLBACK(socket_callback) {
         break;
     case IOEVENT_NOTCONNECTED:
     case IOEVENT_CLOSED:
-        close_socket(client);
+        _close_socket(client);
         if(client->flags & SOCKET_FLAG_RECONNECT) {
             struct timeval timeout;
             gettimeofday(&timeout, NULL);
index db9a5998d2f5dc486ad39fa69eb0d050d50cfca0..52b27b35b3d8faa1138bc06f28e811394b5d5721 100644 (file)
@@ -250,6 +250,10 @@ struct IODescriptor *iohandler_timer(struct timeval timeout, iohandler_callback
 }
 
 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 +288,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 +317,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 +388,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 +423,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 +434,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 +461,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 +484,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 +603,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 +626,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 +648,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);
             }
@@ -771,6 +810,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:
index ea7b44396a6d8ea481338f63286e18a5021a982b..95429859ba61cf7c01006056ae2fd8a532f63098 100644 (file)
@@ -68,6 +68,7 @@ enum IOEventType {
     IOEVENT_NOTCONNECTED, /* client socket could not connect (errid valid) */
     IOEVENT_CLOSED, /* client socket lost connection (errid valid) */
     IOEVENT_ACCEPT, /* server socket accepted new connection (accept_fd valid) */
+    IOEVENT_SSLACCEPT, /* SSL server socket accepted new connection (accept_iofd valid) */
     IOEVENT_TIMEOUT, /* timer timed out */
     IOEVENT_SSLFAILED /* failed to initialize SSL session */
 };
@@ -88,6 +89,7 @@ struct IODescriptor {
     void *data;
     int read_lines : 1;
     int ssl : 1;
+    int ssl_server_hs : 1;
     int ssl_active : 1;
     int ssl_hs_read : 1;
     int ssl_hs_write : 1;
@@ -103,13 +105,24 @@ struct IOEvent {
         char *recv_str;
         int accept_fd;
         int errid;
+        struct IODescriptor *accept_iofd;
     } data;
 };
 
+#define IOHANDLER_LISTEN_IPV4 0x01
+#define IOHANDLER_LISTEN_IPV6 0x02 /* overrides IOHANDLER_LISTEN_IPV4 */
+
+#define IOHANDLER_CONNECT_IPV4 0x01
+#define IOHANDLER_CONNECT_IPV6 0x02 /* overrides IOHANDLER_CONNECT_IPV4 */
+
 struct IODescriptor *iohandler_add(int sockfd, enum IOType type, struct timeval *timeout, iohandler_callback *callback);
 struct IODescriptor *iohandler_timer(struct timeval timeout, iohandler_callback *callback);
 struct IODescriptor *iohandler_connect(const char *hostname, unsigned int port, int ssl, const char *bind, iohandler_callback *callback);
+struct IODescriptor *iohandler_connect_flags(const char *hostname, unsigned int port, int ssl, const char *bindhost, iohandler_callback *callback, int flags);
 struct IODescriptor *iohandler_listen(const char *hostname, unsigned int port, iohandler_callback *callback);
+struct IODescriptor *iohandler_listen_flags(const char *hostname, unsigned int port, iohandler_callback *callback, int flags);
+struct IODescriptor *iohandler_listen_ssl(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iohandler_callback *callback);
+struct IODescriptor *iohandler_listen_ssl_flags(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iohandler_callback *callback, int flags);
 void iohandler_write(struct IODescriptor *iofd, const char *line);
 void iohandler_send(struct IODescriptor *iofd, const char *data, size_t datalen);
 void iohandler_printf(struct IODescriptor *iofd, const char *text, ...);
index d9e1d1994862207a4979a667e92b055ea7418679..5d87cecb62afb47f9280d71cc4a34ff76e2c1e38 100644 (file)
 void iohandler_ssl_init() {
 #ifdef HAVE_SSL
     SSL_library_init();
+    OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
     SSL_load_error_strings();
 #endif
 }
 
+static void iohandler_ssl_error() {
+    unsigned long e;
+    while((e = ERR_get_error())) {
+        iohandler_log(IOLOG_ERROR, "SSLv23 ERROR %lu: %s", e, ERR_error_string(e, NULL));
+    }
+}
+
 void iohandler_ssl_connect(struct IODescriptor *iofd) {
 #ifdef HAVE_SSL
     iofd->state = IO_SSLWAIT;
+    iofd->ssl_server_hs = 0;
     struct IOSSLNode *sslnode = malloc(sizeof(*sslnode));
     sslnode->sslContext = SSL_CTX_new(SSLv23_client_method());
-    if(!sslnode->sslContext)
+    if(!sslnode->sslContext) {
+        iohandler_ssl_error();
+        iohandler_log(IOLOG_ERROR, "SSL: could not create client SSL CTX");
         goto ssl_connect_err;
+    }
     sslnode->sslHandle = SSL_new(sslnode->sslContext);
-    if(!sslnode->sslHandle) 
+    if(!sslnode->sslHandle) {
+        iohandler_ssl_error();
+        iohandler_log(IOLOG_ERROR, "SSL: could not create client SSL Handle");
         goto ssl_connect_err;
-    if(!SSL_set_fd(sslnode->sslHandle, iofd->fd))
+    }
+    if(!SSL_set_fd(sslnode->sslHandle, iofd->fd)) {
+        iohandler_ssl_error();
+        iohandler_log(IOLOG_ERROR, "SSL: could not set client fd in SSL Handle");
         goto ssl_connect_err;
+    }
     SSL_set_connect_state(sslnode->sslHandle);
     iofd->sslnode = sslnode;
     iohandler_ssl_client_handshake(iofd);
@@ -46,6 +64,42 @@ ssl_connect_err:
 #endif    
 }
 
+void iohandler_ssl_listen(struct IODescriptor *iofd, const char *certfile, const char *keyfile) {
+#ifdef HAVE_SSL
+    struct IOSSLNode *sslnode = malloc(sizeof(*sslnode));
+    sslnode->sslContext = SSL_CTX_new(SSLv23_server_method());
+    if(!sslnode->sslContext) {
+        iohandler_ssl_error();
+        iohandler_log(IOLOG_ERROR, "SSL: could not create server SSL CTX");
+        goto ssl_listen_err;
+    }
+    /* load certificate */
+    if(SSL_CTX_use_certificate_file(sslnode->sslContext, certfile, SSL_FILETYPE_PEM) <= 0) {
+        iohandler_ssl_error();
+        iohandler_log(IOLOG_ERROR, "SSL: could not load server certificate (%s)", certfile);
+        goto ssl_listen_err;
+    }
+    /* load keyfile */
+    if(SSL_CTX_use_PrivateKey_file(sslnode->sslContext, keyfile, SSL_FILETYPE_PEM) <= 0) {
+        iohandler_ssl_error();
+        iohandler_log(IOLOG_ERROR, "SSL: could not load server keyfile (%s)", keyfile);
+        goto ssl_listen_err;
+    }
+    /* check certificate and keyfile */
+    if(!SSL_CTX_check_private_key(sslnode->sslContext)) {
+        iohandler_ssl_error();
+        iohandler_log(IOLOG_ERROR, "SSL: server certificate (%s) and keyfile (%s) doesn't match!", certfile, keyfile);
+        goto ssl_listen_err;
+    }
+    iofd->sslnode = sslnode;
+    return;
+ssl_listen_err:
+    free(sslnode);
+    iofd->sslnode = NULL;
+    iohandler_events(iofd, 0, 0);
+#endif    
+}
+
 void iohandler_ssl_client_handshake(struct IODescriptor *iofd) {
 #ifdef HAVE_SSL
     // Perform an SSL handshake.
@@ -75,6 +129,62 @@ void iohandler_ssl_client_handshake(struct IODescriptor *iofd) {
 #endif
 }
 
+void iohandler_ssl_client_accepted(struct IODescriptor *iofd, struct IODescriptor *client_iofd) {
+#ifdef HAVE_SSL
+    struct IOSSLNode *sslnode = malloc(sizeof(*sslnode));
+    sslnode->sslHandle = SSL_new(sslnode->sslContext);
+    if(!sslnode->sslHandle) {
+        iohandler_ssl_error();
+        iohandler_log(IOLOG_ERROR, "SSL: could not create client SSL Handle");
+        goto ssl_accept_err;
+    }
+    if(!SSL_set_fd(sslnode->sslHandle, client_iofd->fd)) {
+        iohandler_ssl_error();
+        iohandler_log(IOLOG_ERROR, "SSL: could not set client fd in SSL Handle");
+        goto ssl_accept_err;
+    }
+    client_iofd->state = IO_SSLWAIT;
+    client_iofd->ssl_server_hs = 1;
+    client_iofd->ssl = 1;
+    client_iofd->sslnode = sslnode;
+    client_iofd->callback = iofd->callback;
+    client_iofd->data = iofd;
+    return;
+ssl_accept_err:
+    iohandler_close(client_iofd);
+    free(sslnode);
+#endif
+}
+
+void iohandler_ssl_server_handshake(struct IODescriptor *iofd) {
+#ifdef HAVE_SSL
+    // Perform an SSL handshake.
+    int ret = SSL_accept(iofd->sslnode->sslHandle);
+    iofd->ssl_hs_read = 0;
+    iofd->ssl_hs_write = 0;
+    switch(SSL_get_error(iofd->sslnode->sslHandle, ret)) {
+        case SSL_ERROR_NONE:
+            iofd->state = IO_CONNECTING;
+            iofd->ssl_active = 1;
+            iohandler_log(IOLOG_DEBUG, "SSL handshake for %s (fd: %d) successful", iohandler_iotype_name(iofd->type), iofd->fd);
+            iohandler_events(iofd, 0, 1); //perform IOEVENT_CONNECTED event
+            break;
+        case SSL_ERROR_WANT_READ:
+            iofd->ssl_hs_read = 1;
+            iohandler_log(IOLOG_DEBUG, "SSL_do_handshake for %s (fd: %d) returned SSL_ERROR_WANT_READ", iohandler_iotype_name(iofd->type), iofd->fd);
+            break;
+        case SSL_ERROR_WANT_WRITE:
+            iofd->ssl_hs_write = 1;
+            iohandler_log(IOLOG_DEBUG, "SSL_do_handshake for %s (fd: %d) returned SSL_ERROR_WANT_WRITE", iohandler_iotype_name(iofd->type), iofd->fd);
+            break;
+        default:
+            iohandler_log(IOLOG_ERROR, "SSL_do_handshake for %s (fd: %d) failed with ", iohandler_iotype_name(iofd->type), iofd->fd);
+            iohandler_events(iofd, 0, 0);
+            break;
+    }
+#endif
+}
+
 void iohandler_ssl_disconnect(struct IODescriptor *iofd) {
 #ifdef HAVE_SSL
     if(!iofd->sslnode) return;
index b1ccf0b792179db4d291e15e0ace889a95553bd0..c74324527ed382c808870ab81f66c71c62073478 100644 (file)
@@ -36,7 +36,10 @@ struct IOSSLNode {
 
 void iohandler_ssl_init();
 void iohandler_ssl_connect(struct IODescriptor *iofd);
+void iohandler_ssl_listen(struct IODescriptor *iofd, const char *certfile, const char *keyfile);
 void iohandler_ssl_client_handshake(struct IODescriptor *iofd);
+void iohandler_ssl_client_accepted(struct IODescriptor *iofd, struct IODescriptor *client_iofd);
+void iohandler_ssl_server_handshake(struct IODescriptor *iofd);
 void iohandler_ssl_disconnect(struct IODescriptor *iofd);
 int iohandler_ssl_read(struct IODescriptor *iofd, char *buffer, int len);
 int iohandler_ssl_write(struct IODescriptor *iofd, char *buffer, int len);
index 5010b7f768e2a5fa82783771e1390e69451a96ea..143148b5e12ea71145b6529390ac1be167de6823 100644 (file)
@@ -640,6 +640,7 @@ static IRC_CMD(raw_privmsg) {
     if(from == NULL || argc < 2) return 0;
     struct UserNode *user = getUserByMask(from);
     if(user == NULL) {
+        if(stricmplen(from, "***!", 4) == 0) return 1; /* ZNC Playback */
         user = createTempUserMask(from);
                if(!user) return 0;
         user->flags |= USERFLAG_ISTMPUSER;
@@ -684,6 +685,7 @@ static IRC_CMD(raw_privmsg) {
 }
 
 static IRC_CMD(raw_notice) {
+    if(from == NULL && argc && !stricmp(argv[0], "AUTH")) return 1; //NOTICE AUTH is NOT a parse error ;)
     if(from == NULL || argc < 2) return 0;
     struct UserNode *user = getUserByMask(from);
     if(user == NULL) {
index 73aa173b20585199f2c7e8d973d5b04e95b2568a..1ab7d478acbfaf5d6196158b12a17e464b87b45a 100644 (file)
@@ -86,7 +86,7 @@ static void neonserv_cmd_users_async1(struct ClientSocket *client, struct Client
     table_add(table, content);
     while ((row = mysql_fetch_row(res)) != NULL) {
         caccess = atoi(row[0]);
-        if((!usermask || !match(usermask, row[1])) && caccess >= min_access && caccess <= max_access) {
+        if((!usermask || !match(usermask, row[1])) && (min_access > 1 && caccess >= min_access) && (max_access < 500 && caccess <= max_access)) {
             content[0] = row[0];
             content[1] = row[1];
             is_here = 0;
index df861f03223aa2e08b077656afdccb74e85cd993..37fa3d8b23c7731ae78738ab47c387144faf5696 100644 (file)
@@ -1,7 +1,7 @@
 
 CC      = gcc
-CFLAGS  = -g -O0 -Wall -Wshadow -Werror
-LDFLAGS = -lws2_32
+CFLAGS  = -g -O0 -Wall -Wshadow -Werror -DHAVE_PTHREAD_H
+LDFLAGS = -lws2_32 -lpthread
 
 OBJ     = ../IOEngine_epoll.o ../IOEngine_kevent.o ../IOEngine_select.o ../IOEngine_win32.o ../IOHandler.o ../IOHandler_SSL.o iotest.o
 
index c18227a9d9b837aec76a18033a0e8a9579969170..ec9ea3e4017803440e5c5c63637e9b8aaa7ffbab 100644 (file)
@@ -30,6 +30,10 @@ static IOHANDLER_CALLBACK(timeq_callback) {
     struct timeq_entry *entry = event->iofd->data;
     switch(event->type) {
     case IOEVENT_TIMEOUT:
+        if(entry->name) {
+            free(entry->name);
+            entry->name = NULL;
+        }
         entry->callback(entry->data);
         entry->iofd = NULL;
         timeq_del(entry);