Debug message changes.
[silc.git] / apps / silcd / packet_send.c
index ed048624a40663f49f5c771971ebdbe7c821e24c..ae0f1c7bc7f7efa7dd46b4ee25650a1e23a475a3 100644 (file)
@@ -1,6 +1,6 @@
 /*
 
-  packet_send.c
+  packet_send.c 
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
@@ -8,9 +8,8 @@
 
   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
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-  
+  the Free Software Foundation; version 2 of the License.
+
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -96,9 +95,15 @@ void silc_server_packet_send(SilcServer server,
   if (SILC_IS_DISCONNECTING(sock))
     return;
 
-  /* If entry is disabled do not sent anything. */
-  if (idata && idata->status & SILC_IDLIST_STATUS_DISABLED)
+  /* If entry is disabled do not sent anything.  Allow hearbeat and
+     rekeys, though */
+  if ((idata && idata->status & SILC_IDLIST_STATUS_DISABLED &&
+       type != SILC_PACKET_HEARTBEAT && type != SILC_PACKET_REKEY && 
+       type != SILC_PACKET_REKEY_DONE) ||
+      sock->user_data == server->id_entry) {
+    SILC_LOG_DEBUG(("Connection is disabled"));
     return;
+  }
 
   /* Get data used in the packet sending, keys and stuff */
   switch(sock->type) {
@@ -157,8 +162,11 @@ void silc_server_packet_send_dest(SilcServer server,
   idata = (SilcIDListData)sock->user_data;
 
   /* If entry is disabled do not sent anything. */
-  if (idata && idata->status & SILC_IDLIST_STATUS_DISABLED)
+  if ((idata && idata->status & SILC_IDLIST_STATUS_DISABLED) ||
+      sock->user_data == server->id_entry) {
+    SILC_LOG_DEBUG(("Connection is disabled"));
     return;
+  }
 
   SILC_LOG_DEBUG(("Sending %s packet", silc_get_packet_name(type)));
 
@@ -207,10 +215,8 @@ void silc_server_packet_send_dest(SilcServer server,
   silc_server_packet_send_real(server, sock, force_send);
 
  out:
-  if (packetdata.src_id)
-    silc_free(packetdata.src_id);
-  if (packetdata.dst_id)
-    silc_free(packetdata.dst_id);
+  silc_free(packetdata.src_id);
+  silc_free(packetdata.dst_id);
 }
 
 /* Assembles a new packet to be sent out to network. This doesn't actually
@@ -253,6 +259,20 @@ void silc_server_packet_send_srcdest(SilcServer server,
   /* Get data used in the packet sending, keys and stuff */
   idata = (SilcIDListData)sock->user_data;
 
+  /* If entry is disabled do not sent anything. */
+  if ((idata && idata->status & SILC_IDLIST_STATUS_DISABLED) ||
+      sock->user_data == server->id_entry) {
+    SILC_LOG_DEBUG(("Connection is disabled"));
+    return;
+  }
+
+  if (idata) {
+    cipher = idata->send_key;
+    hmac = idata->hmac_send;
+    sequence = idata->psn_send++;
+    block_len = silc_cipher_get_block_len(cipher);
+  }
+
   if (dst_id) {
     dst_id_data = silc_id_id2str(dst_id, dst_id_type);
     dst_id_len = silc_id_get_len(dst_id, dst_id_type);
@@ -263,13 +283,6 @@ void silc_server_packet_send_srcdest(SilcServer server,
     src_id_len = silc_id_get_len(src_id, src_id_type);
   }
 
-  if (idata) {
-    cipher = idata->send_key;
-    hmac = idata->hmac_send;
-    sequence = idata->psn_send++;
-    block_len = silc_cipher_get_block_len(cipher);
-  }
-
   /* Set the packet context pointers */
   packetdata.type = type;
   packetdata.flags = flags;
@@ -303,10 +316,8 @@ void silc_server_packet_send_srcdest(SilcServer server,
   silc_server_packet_send_real(server, sock, force_send);
 
  out:
-  if (packetdata.src_id)
-    silc_free(packetdata.src_id);
-  if (packetdata.dst_id)
-    silc_free(packetdata.dst_id);
+  silc_free(packetdata.src_id);
+  silc_free(packetdata.dst_id);
 }
 
 /* Broadcast received packet to our primary route. This function is used
@@ -413,7 +424,11 @@ void silc_server_packet_send_clients(SilcServer server,
   bool gone = FALSE;
   int k;
 
-  SILC_LOG_DEBUG(("Sending packet to list of clients"));
+  if (!silc_hash_table_count(clients))
+    return;
+
+  SILC_LOG_DEBUG(("Sending packet to %d clients",
+                 silc_hash_table_count(clients)));
 
   /* Send to all clients in table */
   silc_hash_table_list(clients, &htl);
@@ -596,7 +611,8 @@ void silc_server_packet_send_to_channel(SilcServer server,
     goto out;
   }
 
-  SILC_LOG_DEBUG(("Sending packet to channel %s", channel->channel_name));
+  SILC_LOG_DEBUG(("Sending %s to channel %s",
+                 silc_get_packet_name(type), channel->channel_name));
 
   routed = silc_calloc(silc_hash_table_count(channel->user_list), 
                       sizeof(*routed));
@@ -636,6 +652,10 @@ void silc_server_packet_send_to_channel(SilcServer server,
        gone = TRUE;
       }
 
+      SILC_LOG_DEBUG(("Sending packet to client %s",
+                     client->nickname ? client->nickname :
+                     (unsigned char *)""));
+
       /* Send the packet */
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                              idata->send_key, 
@@ -661,6 +681,10 @@ void silc_server_packet_send_to_channel(SilcServer server,
     if (!sock || (sender && sock == sender))
       continue;
 
+    SILC_LOG_DEBUG(("Sending packet to client %s",
+                   client->nickname ? client->nickname :
+                   (unsigned char *)""));
+
     /* Send the packet */
     silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                            idata->send_key, 
@@ -745,11 +769,11 @@ void silc_server_packet_relay_to_channel(SilcServer server,
   bool gone = FALSE;
   int k;
 
-  SILC_LOG_DEBUG(("Relaying packet to channel"));
-
   if (!silc_server_client_on_channel(sender_entry, channel, &chl_sender))
     return;
 
+  SILC_LOG_DEBUG(("Relaying packet to channel %s", channel->channel_name));
+
   /* This encrypts the packet, if needed. It will be encrypted if
      it came from the router thus it needs to be encrypted with the
      channel key. If the channel key does not exist, then we know we
@@ -782,7 +806,7 @@ void silc_server_packet_relay_to_channel(SilcServer server,
       sock = (SilcSocketConnection)router->connection;
       idata = (SilcIDListData)router;
 
-      SILC_LOG_DEBUG(("Sending channel message to router for routing"));
+      SILC_LOG_DEBUG(("Sending message to router for routing"));
 
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
                                              idata->send_key, 
@@ -950,7 +974,8 @@ void silc_server_packet_send_local_channel(SilcServer server,
   SilcHashTableList htl;
   SilcSocketConnection sock = NULL;
 
-  SILC_LOG_DEBUG(("Start"));
+  SILC_LOG_DEBUG(("Send packet to local clients on channel %s",
+                 channel->channel_name));
 
   /* Send the message to clients on the channel's client list. */
   silc_hash_table_list(channel->user_list, &htl);
@@ -1467,6 +1492,16 @@ void silc_server_send_notify_dest(SilcServer server,
                               broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
                               dest_id, dest_id_type,
                               packet->data, packet->len, FALSE);
+
+  /* Send to backup routers if this is being broadcasted to primary
+     router.  The silc_server_backup_send checks further whether to
+     actually send it or not. */
+  if ((broadcast && sock && sock == SILC_PRIMARY_ROUTE(server)) ||
+      (broadcast && !sock && !SILC_PRIMARY_ROUTE(server)))
+    silc_server_backup_send_dest(server, NULL, SILC_PACKET_NOTIFY, 0,
+                                dest_id, dest_id_type,
+                                packet->data, packet->len, FALSE, TRUE);
+
   silc_buffer_free(packet);
   va_end(ap);
 }
@@ -1901,3 +1936,183 @@ void silc_server_packet_queue_purge(SilcServer server,
     silc_buffer_clear(sock->outbuf);
   }
 }
+
+/* Send packet to clients that are known to be operators.  If server
+   is router and `route' is TRUE then the packet would go to all operators
+   in the SILC network.  If `route' is FALSE then only local operators
+   (local for server and cell wide for router).  If `local' is TRUE then
+   only locally connected operators receive the packet.  If `local' is
+   TRUE then `route' is ignored.  If server is normal server and `route'
+   is FALSE it is equivalent to `local' being TRUE. */
+
+void silc_server_send_opers(SilcServer server,
+                           SilcPacketType type,
+                           SilcPacketFlags flags,
+                           bool route, bool local,
+                           unsigned char *data, 
+                           SilcUInt32 data_len,
+                           bool force_send)
+{
+  SilcIDCacheList list = NULL;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcClientEntry client = NULL;
+  SilcSocketConnection sock;
+  SilcServerEntry *routed = NULL;
+  SilcUInt32 routed_count = 0;
+  bool gone = FALSE;
+  int k;
+
+  SILC_LOG_DEBUG(("Sending %s packet to operators",
+                 silc_get_packet_name(type)));
+
+  /* If local was requested send only locally connected operators. */
+  if (local || (server->server_type == SILC_SERVER && !route)) {
+    if (!silc_idcache_get_all(server->local_list->clients, &list) ||
+       !silc_idcache_list_first(list, &id_cache))
+      return;
+    while (id_cache) {
+      client = (SilcClientEntry)id_cache->context;
+      if (!client->router && SILC_IS_LOCAL(client) &&
+         (client->mode & SILC_UMODE_SERVER_OPERATOR ||
+          client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
+
+       /* Send the packet to locally connected operator */
+       silc_server_packet_send_dest(server, client->connection, type, flags,
+                                    client->id, SILC_ID_CLIENT,
+                                    data, data_len, force_send);
+      }
+
+      if (!silc_idcache_list_next(list, &id_cache))
+       break;
+    }
+    silc_idcache_list_free(list);
+    return;
+  }
+
+  if (!silc_idcache_get_all(server->local_list->clients, &list) ||
+      !silc_idcache_list_first(list, &id_cache))
+    return;
+  while (id_cache) {
+    client = (SilcClientEntry)id_cache->context;
+    if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) &&
+       !(client->mode & SILC_UMODE_ROUTER_OPERATOR))
+      goto next;
+
+    if (server->server_type != SILC_SERVER && client->router && 
+       ((!route && client->router->router == server->id_entry) || route)) {
+
+      /* Check if we have sent the packet to this route already */
+      for (k = 0; k < routed_count; k++)
+       if (routed[k] == client->router)
+         break;
+      if (k < routed_count)
+       goto next;
+
+      /* Route only once to router */
+      sock = (SilcSocketConnection)client->router->connection;
+      if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+       if (gone)
+         goto next;
+       gone = TRUE;
+      }
+
+      /* Send the packet */
+      silc_server_packet_send_dest(server, sock, type, flags,
+                                  client->id, SILC_ID_CLIENT,
+                                  data, data_len, force_send);
+
+      /* Mark this route routed already */
+      routed = silc_realloc(routed, sizeof(*routed) * (routed_count + 1));
+      routed[routed_count++] = client->router;
+      goto next;
+    }
+
+    if (client->router || !client->connection)
+      goto next;
+
+    /* Send to locally connected client */
+    sock = (SilcSocketConnection)client->connection;
+    silc_server_packet_send_dest(server, sock, type, flags,
+                                client->id, SILC_ID_CLIENT,
+                                data, data_len, force_send);
+
+  next:
+    if (!silc_idcache_list_next(list, &id_cache))
+      break;
+  }
+  silc_idcache_list_free(list);
+
+  if (!silc_idcache_get_all(server->global_list->clients, &list) ||
+      !silc_idcache_list_first(list, &id_cache))
+    return;
+  while (id_cache) {
+    client = (SilcClientEntry)id_cache->context;
+    if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) &&
+       !(client->mode & SILC_UMODE_ROUTER_OPERATOR))
+      goto nextg;
+
+    if (server->server_type != SILC_SERVER && client->router && 
+       ((!route && client->router->router == server->id_entry) || route)) {
+
+      /* Check if we have sent the packet to this route already */
+      for (k = 0; k < routed_count; k++)
+       if (routed[k] == client->router)
+         break;
+      if (k < routed_count)
+       goto nextg;
+
+      /* Route only once to router */
+      sock = (SilcSocketConnection)client->router->connection;
+      if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+       if (gone)
+         goto nextg;
+       gone = TRUE;
+      }
+
+      /* Send the packet */
+      silc_server_packet_send_dest(server, sock, type, flags,
+                                  client->id, SILC_ID_CLIENT,
+                                  data, data_len, force_send);
+
+      /* Mark this route routed already */
+      routed = silc_realloc(routed, sizeof(*routed) * (routed_count + 1));
+      routed[routed_count++] = client->router;
+      goto nextg;
+    }
+
+    if (client->router || !client->connection)
+      goto nextg;
+
+    /* Send to locally connected client */
+    sock = (SilcSocketConnection)client->connection;
+    silc_server_packet_send_dest(server, sock, type, flags,
+                                client->id, SILC_ID_CLIENT,
+                                data, data_len, force_send);
+
+  nextg:
+    if (!silc_idcache_list_next(list, &id_cache))
+      break;
+  }
+  silc_idcache_list_free(list);
+  silc_free(routed);
+}
+
+/* Send a notify packet to operators */
+
+void silc_server_send_opers_notify(SilcServer server,
+                                  bool route,
+                                  bool local,
+                                  SilcNotifyType type,
+                                  SilcUInt32 argc, ...)
+{
+  va_list ap;
+  SilcBuffer packet;
+
+  va_start(ap, argc);
+  packet = silc_notify_payload_encode(type, argc, ap);
+  silc_server_send_opers(server, SILC_PACKET_NOTIFY, 0,
+                        route, local, packet->data, packet->len,
+                        FALSE);
+  silc_buffer_free(packet);
+  va_end(ap);
+}