diff --git a/docs/c-api/net.h/struct_mg_connection.md b/docs/c-api/net.h/struct_mg_connection.md
index 9b301e9ce3b0196a45d55280fd918b6ff298ab7a..8b376fc3a25697c76957790b45fffece4120eb52 100644
--- a/docs/c-api/net.h/struct_mg_connection.md
+++ b/docs/c-api/net.h/struct_mg_connection.md
@@ -14,8 +14,8 @@ signature: |
     size_t recv_mbuf_limit;  /* Max size of recv buffer */
     struct mbuf recv_mbuf;   /* Received data */
     struct mbuf send_mbuf;   /* Data scheduled for sending */
-    time_t last_io_time;              /* Timestamp of the last socket IO */
-    double ev_timer_time;             /* Timestamp of the future MG_EV_TIMER */
+    time_t last_io_time;     /* Timestamp of the last socket IO */
+    double ev_timer_time;    /* Timestamp of the future MG_EV_TIMER */
   #if MG_ENABLE_SSL
     void *ssl_if_data; /* SSL library data. */
   #endif
diff --git a/examples/tun/Makefile b/examples/tun/Makefile
deleted file mode 100644
index 986cfcab634d683e9cae4b52b3a07ff508626d0f..0000000000000000000000000000000000000000
--- a/examples/tun/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-PROG = tun
-MODULE_CFLAGS =
-include ../examples.mk
diff --git a/examples/tun/tun.c b/examples/tun/tun.c
deleted file mode 100644
index f4ce21b5bfe161c084968a441eeafd0cbc21f1b0..0000000000000000000000000000000000000000
--- a/examples/tun/tun.c
+++ /dev/null
@@ -1,72 +0,0 @@
-#include "mongoose.h"
-
-static const char *s_local_port = ":8001";
-static const char *s_dispatcher = "ws://foo:bar@localhost:8000";
-
-void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
-  struct http_message *hm = (struct http_message *) ev_data;
-  int i;
-  switch (ev) {
-    case MG_EV_ACCEPT:
-      fprintf(stderr, "HTTP accept. nc=%p\n", nc);
-      break;
-    case MG_EV_RECV:
-      fprintf(stderr, "recvd: %d bytes\n", *(int *) ev_data);
-      break;
-    case MG_EV_HTTP_REQUEST:
-      fprintf(stderr, "HTTP got request. nc=%p path=%.*s\n", nc,
-              (int) hm->uri.len, hm->uri.p);
-
-      mg_printf(nc, "%s",
-                "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
-
-      for (i = 0; i < 10; i++) {
-        mg_printf_http_chunk(nc, "OK %d\n", i);
-      }
-      mg_send_http_chunk(nc, "", 0); /* Send empty chunk, the end of response */
-      nc->flags |= MG_F_SEND_AND_CLOSE;
-      break;
-    case MG_EV_CLOSE:
-      fprintf(stderr, "HTTP close\n");
-    default:
-      break;
-  }
-}
-
-int main(int argc, char **argv) {
-  struct mg_mgr mgr;
-  struct mg_connection *nc;
-  int i;
-
-  mg_mgr_init(&mgr, NULL);
-
-  /* Parse command line arguments */
-  for (i = 1; i < argc; i++) {
-    if (strcmp(argv[i], "-D") == 0) {
-      mgr.hexdump_file = argv[++i];
-    } else if (strcmp(argv[i], "-l") == 0) {
-      s_local_port = argv[++i];
-    } else if (strcmp(argv[i], "-d") == 0) {
-      s_dispatcher = argv[++i];
-    }
-  }
-
-  if ((nc = mg_bind(&mgr, s_dispatcher, ev_handler)) == NULL) {
-    fprintf(stderr, "Cannot create tunneled listening socket on [%s]\n",
-            s_dispatcher);
-    exit(EXIT_FAILURE);
-  }
-  mg_set_protocol_http_websocket(nc);
-  fprintf(stderr, "Tun listener: %p\n", nc);
-
-  if ((nc = mg_bind(&mgr, s_local_port, ev_handler)) == NULL) {
-    fprintf(stderr, "Cannot bind to local port %s\n", s_local_port);
-    exit(EXIT_FAILURE);
-  }
-  mg_set_protocol_http_websocket(nc);
-  fprintf(stderr, "Local listening connection: %p\n", nc);
-
-  for (;;) {
-    mg_mgr_poll(&mgr, 1000);
-  }
-}
diff --git a/mongoose.c b/mongoose.c
index 7cf2dcdccc6a829d717634f4dce4cc15cb4c140a..1daa5563713baab434021135220002a609f803bf 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -1871,6 +1871,8 @@ int mg_tun_parse_frame(void *data, size_t len, struct mg_tun_frame *frame);
 void mg_tun_send_frame(struct mg_connection *ws, uint32_t stream_id,
                        uint8_t type, uint8_t flags, struct mg_str msg);
 
+void mg_tun_destroy_client(struct mg_tun_client *client);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
@@ -3783,10 +3785,13 @@ int mg_tun_if_create_conn(struct mg_connection *nc) {
 
 void mg_tun_if_destroy_conn(struct mg_connection *nc) {
   struct mg_tun_client *client = (struct mg_tun_client *) nc->iface->data;
-  uint32_t stream_id = (uint32_t)(uintptr_t) nc->mgr_data;
-  struct mg_str msg = {NULL, 0};
 
-  if (client->disp) {
+  if (nc->flags & MG_F_LISTENING) {
+    mg_tun_destroy_client(client);
+  } else if (client->disp) {
+    uint32_t stream_id = (uint32_t)(uintptr_t) nc->mgr_data;
+    struct mg_str msg = {NULL, 0};
+
     LOG(LL_DEBUG, ("closing %zu:", stream_id));
     mg_tun_send_frame(client->disp, stream_id, MG_TUN_DATA_FRAME,
                       MG_TUN_F_END_STREAM, msg);
@@ -11191,7 +11196,8 @@ static void mg_tun_close_all(struct mg_tun_client *client) {
   for (nc = client->mgr->active_connections; nc != NULL; nc = nc->next) {
     if (nc->iface == client->iface && !(nc->flags & MG_F_LISTENING)) {
       LOG(LL_DEBUG, ("Closing tunneled connection %p", nc));
-      mg_close_conn(nc);
+      nc->flags |= MG_F_CLOSE_IMMEDIATELY;
+      /* mg_close_conn(nc); */
     }
   }
 }
@@ -11257,10 +11263,16 @@ static void mg_tun_client_handler(struct mg_connection *nc, int ev,
     }
     case MG_EV_CLOSE: {
       LOG(LL_DEBUG, ("Closing all tunneled connections"));
-      mg_tun_close_all(client);
-      client->disp = NULL;
-      LOG(LL_INFO, ("Dispatcher connection is no more, reconnecting"));
-      mg_tun_reconnect(client);
+      /*
+       * The client might have been already freed when the listening socket is
+       * closed.
+       */
+      if (client != NULL) {
+        mg_tun_close_all(client);
+        client->disp = NULL;
+        LOG(LL_INFO, ("Dispatcher connection is no more, reconnecting"));
+        mg_tun_reconnect(client);
+      }
       break;
     }
     default:
@@ -11329,6 +11341,14 @@ static struct mg_tun_client *mg_tun_create_client(struct mg_mgr *mgr,
   return client;
 }
 
+void mg_tun_destroy_client(struct mg_tun_client *client) {
+  /* the dispatcher connection handler will in turn close all tunnels */
+  client->disp->flags |= MG_F_CLOSE_IMMEDIATELY;
+  /* this is used as a signal to other tun handlers that the party is over */
+  client->disp->user_data = client->iface->data = NULL;
+  MG_FREE(client);
+}
+
 static struct mg_connection *mg_tun_do_bind(struct mg_tun_client *client,
                                             mg_event_handler_t handler,
                                             struct mg_bind_opts opts) {
diff --git a/mongoose.h b/mongoose.h
index 71cbf96b677b8c1be9f799208c196d8c8e5b5b74..1ba48c4783ff7f29b13476df5edf5760d0c091a0 100644
--- a/mongoose.h
+++ b/mongoose.h
@@ -3086,8 +3086,8 @@ struct mg_connection {
   size_t recv_mbuf_limit;  /* Max size of recv buffer */
   struct mbuf recv_mbuf;   /* Received data */
   struct mbuf send_mbuf;   /* Data scheduled for sending */
-  time_t last_io_time;              /* Timestamp of the last socket IO */
-  double ev_timer_time;             /* Timestamp of the future MG_EV_TIMER */
+  time_t last_io_time;     /* Timestamp of the last socket IO */
+  double ev_timer_time;    /* Timestamp of the future MG_EV_TIMER */
 #if MG_ENABLE_SSL
   void *ssl_if_data; /* SSL library data. */
 #endif