Static analyzer bug fixes
[silc.git] / apps / silcd / packet_receive.c
index 5a49ca314e2cc1bd7fdd2eb7091a417955f26211..56435eb6b69420dadddc9d62d9aa711e57be3b95 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2007 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
@@ -186,6 +186,12 @@ static void silc_server_notify_process(SilcServer server,
        }
 
        client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
+
+       if (idata->conn_type == SILC_CONN_SERVER)
+         server->stat.cell_clients++;
+       SILC_LOG_DEBUG(("stat.clients %d->%d", server->stat.clients,
+                       server->stat.clients + 1));
+       server->stat.clients++;
       }
     }
 
@@ -326,6 +332,8 @@ static void silc_server_notify_process(SilcServer server,
       tmp_len = 128;
 
     /* Update statistics */
+    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)
@@ -353,6 +361,20 @@ static void silc_server_notify_process(SilcServer server,
     /* Remove this client from watcher list if it is */
     silc_server_del_from_watcher_list(server, client);
 
+    /* It's possible router doesn't accept our local client in the network
+       and sends SIGNOFF to our local client */
+    if (SILC_IS_LOCAL(client)) {
+      SILC_LOG_DEBUG(("SIGNOFF from router to local client, disconnect"));
+      if (client->data.sconn) {
+       silc_server_connection_free(client->data.sconn);
+       client->data.sconn = NULL;
+      }
+      silc_packet_set_context(client->connection, NULL);
+      silc_server_disconnect_remote(server, client->connection,
+                                   SILC_STATUS_ERR_RESOURCE_LIMIT,
+                                   "Router prevented registration");
+    }
+
     client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
     client->mode = 0;
     client->router = NULL;
@@ -1246,6 +1268,8 @@ static void silc_server_notify_process(SilcServer server,
            }
 
            /* Update statistics */
+           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)
@@ -1492,6 +1516,8 @@ static void silc_server_notify_process(SilcServer server,
       }
 
       /* Update statistics */
+      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)
@@ -1500,7 +1526,8 @@ static void silc_server_notify_process(SilcServer server,
       SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
 
       if (SILC_IS_LOCAL(client)) {
-       server->stat.my_clients--;
+       if (!client->local_detached)
+         server->stat.my_clients--;
        silc_schedule_task_del_by_context(server->schedule, client);
        silc_idlist_del_data(client);
        client->mode = 0;
@@ -1650,7 +1677,7 @@ static void silc_server_notify_process(SilcServer server,
       SilcStatus error;
 
       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-      if (!tmp && tmp_len != 1)
+      if (!tmp || tmp_len != 1)
        goto out;
       error = (SilcStatus)tmp[0];
 
@@ -2236,6 +2263,16 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     char *newusername;
     newusername = silc_calloc(strlen(username) + strlen(hostname) + 2,
                              sizeof(*newusername));
+    if (!newusername) {
+      silc_free(username);
+      silc_free(realname);
+      silc_free(nickname);
+      silc_server_disconnect_remote(server, sock,
+                                   SILC_STATUS_ERR_OPERATION_ALLOWED, NULL);
+      silc_server_free_sock_user_data(server, sock, NULL);
+      silc_packet_free(packet);
+      return NULL;
+    }
     strncat(newusername, username, strlen(username));
     strncat(newusername, "@", 1);
     strncat(newusername, hostname, strlen(hostname));
@@ -2249,6 +2286,9 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   if (!silc_id_create_client_id(server, server->id, server->rng,
                                server->md5hash, nicknamec,
                                strlen(nicknamec), &client_id)) {
+    silc_free(username);
+    silc_free(realname);
+    silc_free(nickname);
     silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_BAD_NICKNAME, NULL);
     silc_server_free_sock_user_data(server, sock, NULL);
@@ -2685,6 +2725,8 @@ static void silc_server_new_id_real(SilcServer server,
 
       if (idata->conn_type == SILC_CONN_SERVER)
        server->stat.cell_clients++;
+      SILC_LOG_DEBUG(("stat.clients %d->%d", server->stat.clients,
+                     server->stat.clients + 1));
       server->stat.clients++;
 
       /* Check if anyone is watching this nickname */
@@ -2886,7 +2928,7 @@ static void silc_server_new_channel_process(SilcServer server,
   SilcChannelID channel_id;
   char *channel_name, *channel_namec = NULL;
   SilcUInt32 name_len;
-  unsigned char *id, cid[32];
+  unsigned char cid[32];
   SilcUInt32 id_len, cipher_len;
   SilcServerEntry server_entry;
   SilcChannelEntry channel;
@@ -2920,8 +2962,6 @@ static void silc_server_new_channel_process(SilcServer server,
   if (!channel_namec)
     return;
 
-  id = silc_channel_get_id(payload, &id_len);
-
   server_entry = (SilcServerEntry)idata;
 
   if (idata->conn_type == SILC_CONN_ROUTER) {
@@ -3740,6 +3780,9 @@ void silc_server_resume_client(SilcServer server,
        server user count as-is (incremented by the current client entry) as
        we decremented the count already during detach, thus we'd be undoing
        that operation. */
+    detached_client->local_detached = FALSE;
+    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)
@@ -3951,6 +3994,23 @@ void silc_server_resume_client(SilcServer server,
                              FALSE, TRUE);
     }
 
+    /* If the client has a locally-connected previous owner, then we
+       will need to notify them that the resume has completed.  Note
+       that if the previous owner was a router, this case is already
+       handled above by the broadcast, so we shouldn't attempt to
+       send another notification in that case.   Additionally, if
+       the previous owner was the server that sent the packet, then
+       we'll not send the notification as it will have already done
+       the necessary work locally. */
+    if (server->server_type == SILC_ROUTER &&
+       idata->conn_type == SILC_CONN_SERVER &&
+       detached_client->router &&
+       SILC_IS_LOCAL(detached_client->router) &&
+       detached_client->router->server_type != SILC_ROUTER)
+      silc_server_packet_send(server, detached_client->router->connection,
+                             SILC_PACKET_RESUME_CLIENT, 0,
+                             buffer->data, silc_buffer_len(buffer));
+
     /* Client is detached, and now it is resumed.  Remove the detached
        mode and mark that it is resumed. */
 
@@ -4008,8 +4068,12 @@ void silc_server_resume_client(SilcServer server,
                                       detached_client, &id_cache))
        silc_idcache_move(server->local_list->clients,
                          server->global_list->clients, id_cache);
-    }
+      }
 
+    /* We don't own this client anymore, if we ever did, as we were just
+     * told that someone else resumed it.  Thus, it is most definitely no
+     * a detached client.*/
+    detached_client->local_detached = FALSE;
     /* Change the owner of the client */
     detached_client->router = server_entry;