silcd: handle SIGNOFF notify for local clients correctly
[silc.git] / apps / silcd / server.c
index ab1d737457b504aa9628839b6574a043c9a1ad3c..e18c7de0c4674804e4b5d5b0fc2235f2cc223acb 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2008 Pekka Riikonen
+  Copyright (C) 1997 - 2009 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -228,12 +228,17 @@ SILC_TASK_CALLBACK(silc_server_packet_error_timeout)
   SilcPacketStream stream = context;
   SilcIDListData idata = silc_packet_get_context(stream);
 
-  if (!idata)
+  if (!idata || !silc_packet_stream_is_valid(stream)) {
+    silc_packet_stream_unref(stream);
     return;
+  }
 
   if (server->router_conn && server->router_conn->sock == stream &&
       !server->router && server->standalone) {
+    if (idata->sconn && idata->sconn->callback)
+      (*idata->sconn->callback)(server, NULL, idata->sconn->callback_context);
     silc_server_create_connections(server);
+    silc_server_free_sock_user_data(server, stream, NULL);
   } else {
     /* If backup disconnected then mark that resuming will not be allowed */
      if (server->server_type == SILC_ROUTER && !server->backup_router &&
@@ -249,6 +254,9 @@ SILC_TASK_CALLBACK(silc_server_packet_error_timeout)
   }
 
   silc_server_close_connection(server, stream);
+
+  /* Release our stream reference */
+  silc_packet_stream_unref(stream);
 }
 
 /* Packet engine callback to indicate error */
@@ -265,7 +273,7 @@ static void silc_server_packet_error(SilcPacketEngine engine,
   const char *ip;
   SilcUInt16 port;
 
-  SILC_LOG_DEBUG(("Packet error, sock %p", stream));
+  SILC_LOG_DEBUG(("Packet error %d, sock %p", error, stream));
 
   if (!idata || !sock)
     return;
@@ -280,9 +288,17 @@ static void silc_server_packet_error(SilcPacketEngine engine,
   if (!silc_packet_stream_is_valid(stream))
     return;
 
+  /* We must take reference of the stream */
+  silc_packet_stream_ref(stream);
+
+  /* In case we get here many times, register only one timeout */
+  silc_schedule_task_del_by_all(server->schedule, 0,
+                               silc_server_packet_error_timeout, stream);
+
+  /* Close connection with random timeout */
   silc_schedule_task_add_timeout(server->schedule,
                                 silc_server_packet_error_timeout, stream,
-                                silc_rng_get_byte(server->rng) % 5, 0);
+                                silc_rng_get_byte(server->rng) % 10, 0);
 }
 
 /* Packet stream callbacks */
@@ -302,9 +318,16 @@ static void silc_server_packet_parse_type(SilcServer server,
 {
   SilcPacketType type = packet->type;
   SilcIDListData idata = silc_packet_get_context(sock);
+#ifdef SILC_DEBUG
+  const char *ip;
+  SilcUInt16 port;
+
+  silc_socket_stream_get_info(silc_packet_stream_get_stream(sock),
+                             NULL, NULL, &ip, &port);
+#endif /* SILC_DEBUG */
 
-  SILC_LOG_DEBUG(("Received %s packet [flags %d]",
-                 silc_get_packet_name(type), packet->flags));
+  SILC_LOG_DEBUG(("Received %s packet [flags %d] from %s:%d",
+                 silc_get_packet_name(type), packet->flags, ip, port));
 
   /* Parse the packet type */
   switch (type) {
@@ -2337,6 +2360,8 @@ silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success,
       entry->data.conn_type = SILC_CONN_CLIENT;
 
       /* Statistics */
+      SILC_LOG_DEBUG(("stat.clients %d->%d", server->stat.clients,
+                     server->stat.clients + 1));
       server->stat.my_clients++;
       server->stat.clients++;
       server->stat.cell_clients++;
@@ -2602,6 +2627,8 @@ silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success,
   /* Add connection to server->conns so that we know we have connection
      to this peer. */
   sconn = silc_calloc(1, sizeof(*sconn));
+  if (!sconn)
+    goto out;
   sconn->server = server;
   sconn->sock = sock;
   sconn->remote_host = strdup(hostname);
@@ -2995,6 +3022,10 @@ static void silc_server_rekey(SilcServer server, SilcPacketStream sock,
     silc_packet_free(packet);
     return;
   }
+  if (idata->conn_type == SILC_CONN_UNKNOWN) {
+    silc_packet_free(packet);
+    return;
+  }
 
   SILC_LOG_DEBUG(("Executing rekey protocol with %s:%d [%s], sock %p",
                  idata->sconn->remote_host, idata->sconn->remote_port,
@@ -3082,7 +3113,8 @@ void silc_server_disconnect_remote(SilcServer server,
   if (!sock)
     return;
 
-  SILC_LOG_DEBUG(("Disconnecting remote host, sock %p", sock));
+  SILC_LOG_DEBUG(("Disconnecting remote host, sock %p, status %d", sock,
+                 status));
 
   va_start(ap, status);
   cp = va_arg(ap, char *);
@@ -3146,6 +3178,8 @@ void silc_server_free_client_data(SilcServer server,
   /* Local detached clients aren't counted. */
   if (!client->local_detached)
     server->stat.my_clients--;
+  SILC_LOG_DEBUG(("stat.clients %d->%d", server->stat.clients,
+                 server->stat.clients - 1));
   SILC_VERIFY(server->stat.clients > 0);
   server->stat.clients--;
   if (server->stat.cell_clients)
@@ -3207,11 +3241,13 @@ void silc_server_free_sock_user_data(SilcServer server,
     if (idata->sconn && idata->sconn->op) {
       SILC_LOG_DEBUG(("Abort active protocol"));
       silc_async_abort(idata->sconn->op, NULL, NULL);
+      idata->sconn->op = NULL;
     }
     if (idata->conn_type == SILC_CONN_UNKNOWN &&
         ((SilcUnknownEntry)idata)->op) {
       SILC_LOG_DEBUG(("Abort active protocol"));
       silc_async_abort(((SilcUnknownEntry)idata)->op, NULL, NULL);
+      ((SilcUnknownEntry)idata)->op = NULL;
     }
   }
 
@@ -5022,10 +5058,14 @@ void silc_server_save_users_on_channel(SilcServer server,
       }
 
       client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
+
+      SILC_LOG_DEBUG(("stat.clients %d->%d", server->stat.clients,
+                     server->stat.clients + 1));
+      server->stat.clients++;
     }
 
     if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
-      SILC_LOG_ERROR(("Attempting to add unregistered client to channel ",
+      SILC_LOG_ERROR(("Attempting to add unregistered client to channel "
                      "%s", channel->channel_name));
       continue;
     }