Added statistics updating and statisics dumping with SIGUSR1.
[silc.git] / apps / silcd / packet_receive.c
index 9a0a7ba802671f962dc7216466d5dc2f1b7e9b57..a2a756a0c4bb2ae80ce88950a1c7e6b3c7fa18e3 100644 (file)
@@ -86,7 +86,7 @@ void silc_server_notify(SilcServer server,
      we will broadcast it. The sending socket really cannot be router or
      the router is buggy. If this packet is coming from router then it must
      have the broadcast flag set already and we won't do anything. */
-  if (!server->standalone && server->server_type == SILC_ROUTER &&
+  if (server->server_type == SILC_ROUTER &&
       sock->type == SILC_SOCKET_TYPE_SERVER &&
       !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
     SILC_LOG_DEBUG(("Broadcasting received Notify packet"));
@@ -97,12 +97,13 @@ void silc_server_notify(SilcServer server,
       if (!channel_id)
        goto out;
 
-      silc_server_packet_send_dest(server, server->router->connection, 
-                                  packet->type,
-                                  packet->flags | SILC_PACKET_FLAG_BROADCAST, 
-                                  channel_id, SILC_ID_CHANNEL,
-                                  packet->buffer->data, packet->buffer->len, 
-                                  FALSE);
+      if (!server->standalone)
+       silc_server_packet_send_dest(server, server->router->connection, 
+                                    packet->type, packet->flags | 
+                                    SILC_PACKET_FLAG_BROADCAST, 
+                                    channel_id, SILC_ID_CHANNEL,
+                                    packet->buffer->data, 
+                                    packet->buffer->len, FALSE);
       silc_server_backup_send_dest(server, (SilcServerEntry)sock->user_data, 
                                   packet->type, packet->flags,
                                   channel_id, SILC_ID_CHANNEL,
@@ -110,11 +111,12 @@ void silc_server_notify(SilcServer server,
                                   FALSE, TRUE);
     } else {
       /* Packet is destined to client or server */
-      silc_server_packet_send(server, server->router->connection, 
-                             packet->type,
-                             packet->flags | SILC_PACKET_FLAG_BROADCAST, 
-                             packet->buffer->data, packet->buffer->len, 
-                             FALSE);
+      if (!server->standalone)
+       silc_server_packet_send(server, server->router->connection, 
+                               packet->type,
+                               packet->flags | SILC_PACKET_FLAG_BROADCAST, 
+                               packet->buffer->data, packet->buffer->len, 
+                               FALSE);
       silc_server_backup_send(server, (SilcServerEntry)sock->user_data,
                              packet->type, packet->flags,
                              packet->buffer->data, packet->buffer->len, 
@@ -231,6 +233,13 @@ void silc_server_notify(SilcServer server,
     channel->user_count++;
     channel->disabled = FALSE;
 
+    /* Update statistics */
+    if (server->server_type == SILC_ROUTER) {
+      if (sock->type != SILC_SOCKET_TYPE_ROUTER)
+       server->stat.cell_chanclients++;
+      server->stat.chanclients++;
+    }
+
     break;
 
   case SILC_NOTIFY_TYPE_LEAVE:
@@ -554,6 +563,20 @@ void silc_server_notify(SilcServer server,
        SILC_LOG_DEBUG(("CMODE change is not allowed"));
        goto out;
       }
+    } else {
+      if (server->server_type == SILC_ROUTER &&
+         channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH &&
+         !(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
+       SILC_LOG_DEBUG(("Enforcing sender to change channel mode"));
+       silc_server_send_notify_cmode(server, sock, FALSE, channel,
+                                     channel->mode, server->id,
+                                     SILC_ID_SERVER,
+                                     channel->cipher,
+                                     channel->hmac_name,
+                                     channel->passphrase,
+                                     channel->founder_key);
+       goto out;
+      }
     }
 
     /* Send the same notify to the channel */
@@ -744,7 +767,7 @@ void silc_server_notify(SilcServer server,
        if (!silc_server_client_on_channel(client, channel, &chl))
          goto out;
        
-       if (client != client2) {
+       if (client != client2 && server->server_type == SILC_ROUTER) {
          /* Sender must be operator */
          if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
              !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
@@ -752,7 +775,6 @@ void silc_server_notify(SilcServer server,
            goto out;
          }
 
-         /* Check that target is on channel */
          if (!silc_server_client_on_channel(client2, channel, &chl))
            goto out;
 
@@ -764,7 +786,29 @@ void silc_server_notify(SilcServer server,
        }
       }
 
+      /* Get target channel entry */
+      if (!silc_server_client_on_channel(client2, channel, &chl))
+       goto out;
+
       if (mode & SILC_CHANNEL_UMODE_CHANFO &&
+         !(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && !client &&
+         server->server_type == SILC_ROUTER) {
+       /* Get the founder of the channel and if found then this client
+          cannot be the founder since there already is one. */
+       silc_hash_table_list(channel->user_list, &htl);
+       while (silc_hash_table_get(&htl, NULL, (void *)&chl2))
+         if (chl2->mode & SILC_CHANNEL_UMODE_CHANFO) {
+           mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+           silc_server_force_cumode_change(server, sock, channel, chl, mode);
+           notify_sent = TRUE;
+           break;
+         }
+       silc_hash_table_list_reset(&htl);
+       if (!(mode & SILC_CHANNEL_UMODE_CHANFO))
+         break;
+      }
+
+      if (client && mode & SILC_CHANNEL_UMODE_CHANFO &&
          !(chl->mode & SILC_CHANNEL_UMODE_CHANFO) && 
          server->server_type == SILC_ROUTER) {
        /* Check whether this client is allowed to be channel founder on
@@ -813,7 +857,7 @@ void silc_server_notify(SilcServer server,
 
        /* Now match the public key we have cached and public key sent.
           They must match. */
-       if (client && client->data.public_key && 
+       if (client->data.public_key && 
            !silc_pkcs_public_key_compare(channel->founder_key,
                                          client->data.public_key)) {
          mode &= ~SILC_CHANNEL_UMODE_CHANFO;
@@ -1158,7 +1202,9 @@ void silc_server_notify(SilcServer server,
     silc_idlist_del_server(local ? server->local_list :
                           server->global_list, server_entry);
 
-    /* XXX update statistics */
+    /* Update statistics */
+    if (server->server_type == SILC_ROUTER)
+      server->stat.servers--;
 
     break;
 
@@ -1393,6 +1439,24 @@ void silc_server_notify(SilcServer server,
     if (mode & SILC_UMODE_DETACHED)
       client->data.status &= ~SILC_IDLIST_STATUS_RESUMED;
 
+    /* Update statistics */
+    if (server->server_type == SILC_ROUTER) {
+      if (mode & SILC_UMODE_GONE) {
+       if (!client->mode & SILC_UMODE_GONE)
+         server->stat.aways++;
+      } else {
+       if (client->mode & SILC_UMODE_GONE)
+         server->stat.aways--;
+      }
+      if (mode & SILC_UMODE_DETACHED) {
+       if (!client->mode & SILC_UMODE_DETACHED)
+         server->stat.detached++;
+      } else {
+       if (client->mode & SILC_UMODE_DETACHED)
+         server->stat.detached--;
+      }
+    }
+
     /* Change the mode */
     client->mode = mode;
 
@@ -1850,6 +1914,10 @@ void silc_server_channel_message(SilcServer server,
       SILC_LOG_DEBUG(("Channel is silenced from operators"));
       goto out;
     }
+    if (chl->mode & SILC_CHANNEL_UMODE_QUIET) {
+      SILC_LOG_DEBUG(("Sender is quieted on the channel"));
+      goto out;
+    }
 
     /* If the packet is coming from router, but the client entry is local 
        entry to us then some router is rerouting this to us and it is not 
@@ -2105,7 +2173,15 @@ SilcClientEntry silc_server_new_client(SilcServer server,
                            server->router->connection, 
                            server->server_type == SILC_ROUTER ? TRUE : FALSE,
                            client->id, SILC_ID_CLIENT, id_len);
-  
+
+  /* Distribute to backup routers */
+  if (server->server_type == SILC_ROUTER) {
+    SilcBuffer idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+    silc_server_backup_send(server, NULL, SILC_PACKET_NEW_ID, 0,
+                           idp->data, idp->len, FALSE, TRUE);
+    silc_buffer_free(idp);
+  }
+
   /* Send the new client ID to the client. */
   silc_server_send_new_id(server, sock, FALSE, client->id, SILC_ID_CLIENT,
                          silc_id_get_len(client->id, SILC_ID_CLIENT));
@@ -2258,8 +2334,16 @@ SilcServerEntry silc_server_new_server(SilcServer server,
                            TRUE, new_server->id, SILC_ID_SERVER, 
                            silc_id_get_len(server_id, SILC_ID_SERVER));
 
-  if (server->server_type == SILC_ROUTER)
+  if (server->server_type == SILC_ROUTER) {
+    /* Distribute to backup routers */
+    SilcBuffer idp = silc_id_payload_encode(new_server->id, SILC_ID_SERVER);
+    silc_server_backup_send(server, NULL, SILC_PACKET_NEW_ID, 0,
+                           idp->data, idp->len, FALSE, TRUE);
+    silc_buffer_free(idp);
+
+    /* Statistics */
     server->stat.cell_servers++;
+  }
 
   /* Check whether this router connection has been replaced by an
      backup router. If it has been then we'll disable the server and will
@@ -2478,14 +2562,15 @@ static void silc_server_new_id_real(SilcServer server,
 
   /* If the sender of this packet is server and we are router we need to
      broadcast this packet to other routers in the network. */
-  if (broadcast && !server->standalone && server->server_type == SILC_ROUTER &&
+  if (broadcast && server->server_type == SILC_ROUTER &&
       sock->type == SILC_SOCKET_TYPE_SERVER &&
       !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
     SILC_LOG_DEBUG(("Broadcasting received New ID packet"));
-    silc_server_packet_send(server, server->router->connection,
-                           packet->type, 
-                           packet->flags | SILC_PACKET_FLAG_BROADCAST,
-                           buffer->data, buffer->len, FALSE);
+    if (!server->standalone)
+      silc_server_packet_send(server, server->router->connection,
+                             packet->type, 
+                             packet->flags | SILC_PACKET_FLAG_BROADCAST,
+                             buffer->data, buffer->len, FALSE);
     silc_server_backup_send(server, (SilcServerEntry)sock->user_data, 
                            packet->type, packet->flags,
                            packet->buffer->data, packet->buffer->len, 
@@ -2525,14 +2610,16 @@ void silc_server_new_id_list(SilcServer server, SilcSocketConnection sock,
   /* If the sender of this packet is server and we are router we need to
      broadcast this packet to other routers in the network. Broadcast
      this list packet instead of multiple New ID packets. */
-  if (!server->standalone && server->server_type == SILC_ROUTER &&
+  if (server->server_type == SILC_ROUTER &&
       sock->type == SILC_SOCKET_TYPE_SERVER &&
       !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
     SILC_LOG_DEBUG(("Broadcasting received New ID List packet"));
-    silc_server_packet_send(server, server->router->connection,
-                           packet->type, 
-                           packet->flags | SILC_PACKET_FLAG_BROADCAST,
-                           packet->buffer->data, packet->buffer->len, FALSE);
+    if (!server->standalone)
+      silc_server_packet_send(server, server->router->connection,
+                             packet->type, 
+                             packet->flags | SILC_PACKET_FLAG_BROADCAST,
+                             packet->buffer->data, 
+                             packet->buffer->len, FALSE);
     silc_server_backup_send(server, (SilcServerEntry)sock->user_data, 
                            packet->type, packet->flags,
                            packet->buffer->data, packet->buffer->len, 
@@ -2694,12 +2781,6 @@ void silc_server_new_channel(SilcServer server,
       }
       channel->disabled = TRUE;
 
-#if 0
-      /* CMODE change notify is expected */
-      /* Get the mode and set it to the channel */
-      channel->mode = silc_channel_get_mode(payload);
-#endif
-
       /* Send the new channel key to the server */
       id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
       id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
@@ -2712,7 +2793,6 @@ void silc_server_new_channel(SilcServer server,
       silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0, 
                              chk->data, chk->len, FALSE);
       silc_buffer_free(chk);
-
     } else {
       /* The channel exist by that name, check whether the ID's match.
         If they don't then we'll force the server to use the ID we have.
@@ -2767,6 +2847,10 @@ void silc_server_new_channel(SilcServer server,
 
       silc_free(channel_id);
 
+      /* Update statistics */
+      server->stat.channels++;
+      server->stat.cell_channels++;
+
       /* Since the channel is coming from server and we also know about it
         then send the JOIN notify to the server so that it see's our
         users on the channel "joining" the channel. */
@@ -2823,14 +2907,16 @@ void silc_server_new_channel_list(SilcServer server,
   /* If the sender of this packet is server and we are router we need to
      broadcast this packet to other routers in the network. Broadcast
      this list packet instead of multiple New Channel packets. */
-  if (!server->standalone && server->server_type == SILC_ROUTER &&
+  if (server->server_type == SILC_ROUTER &&
       sock->type == SILC_SOCKET_TYPE_SERVER &&
       !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
     SILC_LOG_DEBUG(("Broadcasting received New Channel List packet"));
-    silc_server_packet_send(server, server->router->connection,
-                           packet->type, 
-                           packet->flags | SILC_PACKET_FLAG_BROADCAST,
-                           packet->buffer->data, packet->buffer->len, FALSE);
+    if (!server->standalone)
+      silc_server_packet_send(server, server->router->connection,
+                             packet->type, 
+                             packet->flags | SILC_PACKET_FLAG_BROADCAST,
+                             packet->buffer->data, 
+                             packet->buffer->len, FALSE);
     silc_server_backup_send(server, (SilcServerEntry)sock->user_data, 
                            packet->type, packet->flags,
                            packet->buffer->data, packet->buffer->len, 
@@ -3314,6 +3400,7 @@ void silc_server_resume_client(SilcServer server,
     server->stat.clients--;
     if (server->stat.cell_clients)
       server->stat.cell_clients--;
+    silc_server_del_from_watcher_list(server, client);
     silc_idlist_del_client(server->local_list, client);
     client = detached_client;
 
@@ -3529,14 +3616,15 @@ void silc_server_resume_client(SilcServer server,
 
     /* If the sender of this packet is server and we are router we need to
        broadcast this packet to other routers in the network. */
-    if (!server->standalone && server->server_type == SILC_ROUTER &&
+    if (server->server_type == SILC_ROUTER &&
        sock->type == SILC_SOCKET_TYPE_SERVER &&
        !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
       SILC_LOG_DEBUG(("Broadcasting received Resume Client packet"));
-      silc_server_packet_send(server, server->router->connection,
-                             packet->type, 
-                             packet->flags | SILC_PACKET_FLAG_BROADCAST,
-                             buffer->data, buffer->len, FALSE);
+      if (!server->standalone)
+       silc_server_packet_send(server, server->router->connection,
+                               packet->type, 
+                               packet->flags | SILC_PACKET_FLAG_BROADCAST,
+                               buffer->data, buffer->len, FALSE);
       silc_server_backup_send(server, (SilcServerEntry)sock->user_data, 
                              packet->type, packet->flags,
                              packet->buffer->data, packet->buffer->len,