Cleaned up WHOIS command.
authorPekka Riikonen <priikone@silcnet.org>
Thu, 14 Dec 2000 17:18:05 +0000 (17:18 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Thu, 14 Dec 2000 17:18:05 +0000 (17:18 +0000)
Saves received information on WHOIS command reply now.

CHANGES
apps/silcd/command.c
apps/silcd/command_reply.c
apps/silcd/packet_receive.c
apps/silcd/packet_send.c
apps/silcd/packet_send.h
apps/silcd/route.c
apps/silcd/route.h
apps/silcd/server.c
apps/silcd/server_internal.h

diff --git a/CHANGES b/CHANGES
index b956e377d2e0c4e9b0e2a17506fe6618ee23a2b6..a0696db738e8fe1486c4abcc8fe8f4056b60e7d5 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,28 @@ Thu Dec 14 15:55:35 EET 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Add route cache for received ID for fast routing.
 
+       * Added silc_server_packet_route to route received packet on router
+         that is not destined to us.
+
+       * Renamed silc_server_get_route to silc_server_route_get.
+
+       * Added id_string and id_string_len fields into SilcServer to
+         include encoded ServerID for fast comparing without excess
+         encoding of the ID's.
+
+       * Cleaned up WHOIS command on server side. Added following static
+         functions:
+
+         silc_server_command_whois_parse
+         silc_server_command_whois_check
+         silc_server_command_whois_send_reply
+         silc_server_command_whois_from_client
+         silc_server_command_whois_from_server
+
+       * Added macro SILC_SERVER_COMMAND_CHECK_ARGC to check mandatory
+         arguments in command replies. All command functions should be
+         updated to use this macro.
+
 Sun Dec 10 23:52:00 EET 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Minor typo fixes on command reply handling on server.
index 2ae14d7f42beddb91284ca483265f14fa3a31b95..e25d6ea81316c914a2cf396d1686710335275894 100644 (file)
@@ -78,6 +78,26 @@ SilcServerCommand silc_command_list[] =
   { NULL, 0 },
 };
 
+#define SILC_SERVER_COMMAND_CHECK_ARGC(command, context, min, max)           \
+do {                                                                         \
+  unsigned int _argc = silc_argument_get_arg_num(cmd->args);                 \
+                                                                             \
+  SILC_LOG_DEBUG(("Start"));                                                 \
+                                                                             \
+  if (_argc < min) {                                                         \
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,           \
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); \
+    silc_server_command_free(cmd);                                           \
+    return;                                                                  \
+  }                                                                          \
+  if (_argc > max) {                                                         \
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,           \
+                                         SILC_STATUS_ERR_TOO_MANY_PARAMS);   \
+    silc_server_command_free(cmd);                                           \
+    return;                                                                  \
+  }                                                                          \
+} while(0)
+
 /* Returns TRUE if the connection is registered. Unregistered connections
    usually cannot send commands hence the check. */
 
@@ -284,60 +304,40 @@ silc_server_command_send_status_data(SilcServerCommandContext cmd,
   silc_buffer_free(buffer);
 }
 
-/* Server side of command WHOIS. Processes user's query and sends found 
-   results as command replies back to the client. */
-
-SILC_SERVER_CMD_FUNC(whois)
+static int
+silc_server_command_whois_parse(SilcServerCommandContext cmd,
+                               SilcClientID **client_id,
+                               char **nickname,
+                               char **server_name,
+                               int *count)
 {
-  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
-  SilcServer server = cmd->server;
-  char *tmp, *nick = NULL, *server_name = NULL;
-  unsigned int i, argc, count = 0, len, clients_count;
-  int use_id = FALSE;
-  SilcClientID *client_id = NULL;
-  SilcBuffer packet, idp;
-  SilcClientEntry *clients = NULL, entry;
-  SilcCommandStatus status;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  argc = silc_argument_get_arg_num(cmd->args);
-  if (argc < 1) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
-                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-  if (argc > 3) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
-                                         SILC_STATUS_ERR_TOO_MANY_PARAMS);
-    goto out;
-  }
+  unsigned char *tmp;
+  unsigned int len;
+  unsigned int argc = silc_argument_get_arg_num(cmd->args);
 
   /* If client ID is in the command it must be used instead of nickname */
   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
   if (!tmp) {
-
     /* No ID, get the nickname@server string and parse it. */
     tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
     if (tmp) {
       if (strchr(tmp, '@')) {
        len = strcspn(tmp, "@");
-       nick = silc_calloc(len + 1, sizeof(char));
-       memcpy(nick, tmp, len);
-       server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
-       memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
+       *nickname = silc_calloc(len + 1, sizeof(char));
+       memcpy(*nickname, tmp, len);
+       *server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
+       memcpy(*server_name, tmp + len + 1, strlen(tmp) - len - 1);
       } else {
-       nick = strdup(tmp);
+       *nickname = strdup(tmp);
       }
     } else {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
                                            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-      goto out;
+      return FALSE;
     }
   } else {
     /* Command includes ID, use that */
-    client_id = silc_id_payload_parse_id(tmp, len);
-    use_id = TRUE;
+    *client_id = silc_id_payload_parse_id(tmp, len);
   }
 
   /* Get the max count of reply messages allowed */
@@ -346,74 +346,70 @@ SILC_SERVER_CMD_FUNC(whois)
     if (!tmp) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
                                            SILC_STATUS_ERR_TOO_MANY_PARAMS);
-      if (nick)
-       silc_free(nick);
-      if (server_name)
-       silc_free(server_name);
-      goto out;
+      if (*nickname)
+       silc_free(*nickname);
+      if (*server_name)
+       silc_free(*server_name);
+
+      return FALSE;
     }
-    count = atoi(tmp);
+    *count = atoi(tmp);
   }
 
-  /* Protocol dictates that we must always send the received WHOIS request
-     to our router if we are normal server, so let's do it now unless we
-     are standalone. We will not send any replies to the client until we
-     have received reply from the router. */
-  if (!server->standalone) {
-    SilcBuffer tmpbuf;
+  return TRUE;
+}
 
-    silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
-    tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+static char
+silc_server_command_whois_check(SilcServerCommandContext cmd,
+                               SilcClientEntry *clients,
+                               unsigned int clients_count)
+{
+  SilcServer server = cmd->server;
+  int i;
+  SilcClientEntry entry;
 
-    /* Send WHOIS command to our router */
-    silc_server_packet_send(server, (SilcSocketConnection)
-                           server->router->connection,
-                           SILC_PACKET_COMMAND, cmd->packet->flags,
-                           tmpbuf->data, tmpbuf->len, TRUE);
-    return;
-  } else {
-    /* We are standalone, let's just do local search and send reply to
-       requesting client. */
+  for (i = 0; i < clients_count; i++) {
+    entry = clients[i];
 
-    /* Get all clients matching that nickname */
-    if (!use_id) {
-      clients = silc_idlist_get_clients_by_nickname(server->local_list, 
-                                                   nick, server_name,
-                                                   &clients_count);
-    } else {
-      entry = silc_idlist_find_client_by_id(server->local_list, client_id);
-      if (entry) {
-       clients = silc_calloc(1, sizeof(*clients));
-       clients[0] = entry;
-       clients_count = 1;
-      }
-    }
-    
-    /* If we are router then we will check our global list as well. */
-    if (server->server_type == SILC_ROUTER) {
-      entry =
-       silc_idlist_find_client_by_nickname(server->global_list,
-                                           nick, server_name);
-      if (!entry) {
-       silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
-                                            SILC_STATUS_ERR_NO_SUCH_NICK,
-                                            3, tmp, strlen(tmp));
-       goto out;
-      }
-      goto ok;
-    }
+    if (!entry->nickname || !entry->username || !entry->userinfo) {
+      SilcBuffer tmpbuf;
       
-#if 0
-    silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
-                                        SILC_STATUS_ERR_NO_SUCH_NICK,
-                                        3, tmp, strlen(tmp));
-    goto out;
-#endif
+      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+      /* Send WHOIS command to fastest route for the client ID */
+      silc_server_packet_send(server,
+                             silc_server_route_get(server, entry->id, 
+                                                   SILC_ID_CLIENT),
+                             SILC_PACKET_COMMAND, cmd->packet->flags,
+                             tmpbuf->data, tmpbuf->len, TRUE);
+      
+      /* Reprocess this packet after received reply */
+      silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
+                                 silc_command_get_ident(cmd->payload),
+                                 silc_server_command_whois, (void *)cmd);
+      cmd->pending = TRUE;
+      
+      silc_buffer_free(tmpbuf);
+      return FALSE;
+    }
   }
 
-  /* We are standalone and will send reply to client */
- ok:
+  return TRUE;
+}
+
+static void
+silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
+                                    SilcClientEntry *clients,
+                                    unsigned int clients_count)
+{
+  SilcServer server = cmd->server;
+  char *tmp;
+  int i, count = 0, len;
+  SilcBuffer packet, idp;
+  SilcClientEntry entry;
+  SilcCommandStatus status;
+
   status = SILC_STATUS_OK;
   if (clients_count > 1)
     status = SILC_STATUS_LIST_START;
@@ -494,14 +490,218 @@ SILC_SERVER_CMD_FUNC(whois)
     silc_buffer_free(packet);
     silc_buffer_free(idp);
   }
+}
+
+static int
+silc_server_command_whois_from_client(SilcServerCommandContext cmd)
+{
+  SilcServer server = cmd->server;
+  char *nick = NULL, *server_name = NULL;
+  int count = 0, clients_count;
+  SilcClientID *client_id = NULL;
+  SilcClientEntry *clients = NULL, entry;
+  int ret = 0;
+
+  /* Parse the whois request */
+  if (!silc_server_command_whois_parse(cmd, &client_id, &nick, 
+                                      &server_name, &count))
+    return 0;
+
+  /* Protocol dictates that we must always send the received WHOIS request
+     to our router if we are normal server, so let's do it now unless we
+     are standalone. We will not send any replies to the client until we
+     have received reply from the router. */
+  if (server->server_type == SILC_SERVER && 
+      !cmd->pending && !server->standalone) {
+    SilcBuffer tmpbuf;
+
+    silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+    tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+    /* Send WHOIS command to our router */
+    silc_server_packet_send(server, (SilcSocketConnection)
+                           server->router->connection,
+                           SILC_PACKET_COMMAND, cmd->packet->flags,
+                           tmpbuf->data, tmpbuf->len, TRUE);
+
+    /* Reprocess this packet after received reply from router */
+    silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
+                               silc_command_get_ident(cmd->payload),
+                               silc_server_command_whois, (void *)cmd);
+    cmd->pending = TRUE;
+
+    silc_buffer_free(tmpbuf);
+    ret = -1;
+    goto out;
+  }
+
+  /* We are ready to process the command request. Let's search for the
+     requested client and send reply to the requesting client. */
+
+  /* Get all clients matching that ID or nickname from local list */
+  if (client_id) {
+    entry = silc_idlist_find_client_by_id(server->local_list, client_id);
+    if (entry) {
+      clients = silc_calloc(1, sizeof(*clients));
+      clients[0] = entry;
+      clients_count = 1;
+    }
+  } else {
+    clients = silc_idlist_get_clients_by_nickname(server->local_list, 
+                                                 nick, server_name,
+                                                 &clients_count);
+  }
+  
+  /* If we are router we will check our global list as well. */
+  if (!clients && server->server_type == SILC_ROUTER) {
+    if (client_id) {
+      entry = silc_idlist_find_client_by_id(server->global_list, client_id);
+      if (entry) {
+       clients = silc_calloc(1, sizeof(*clients));
+       clients[0] = entry;
+       clients_count = 1;
+      }
+    } else {
+      clients = silc_idlist_get_clients_by_nickname(server->global_list, 
+                                                   nick, server_name,
+                                                   &clients_count);
+    }
+  }
+  
+  if (!clients) {
+    /* Such a client really does not exist in the SILC network. */
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
+                                        SILC_STATUS_ERR_NO_SUCH_NICK,
+                                        3, nick, strlen(nick));
+    goto out;
+  }
 
-  silc_free(clients);
+  /* Router always finds the client entry if it exists in the SILC network.
+     However, it might be incomplete entry and does not include all the
+     mandatory fields that WHOIS command reply requires. Check for these and
+     make query from the server who owns the client if some fields are 
+     missing. */
+  if (server->server_type == SILC_ROUTER &&
+      !silc_server_command_whois_check(cmd, clients, clients_count)) {
+    ret = -1;
+    goto out;
+  }
 
+  /* Send the command reply to the client */
+  silc_server_command_whois_send_reply(cmd, clients, clients_count);
+
+ out:
+  if (clients)
+    silc_free(clients);
   if (client_id)
     silc_free(client_id);
+  if (nick)
+    silc_free(nick);
+  if (server_name)
+    silc_free(server_name);
+
+  return ret;
+}
+
+static int
+silc_server_command_whois_from_server(SilcServerCommandContext cmd)
+{
+  SilcServer server = cmd->server;
+  char *nick = NULL, *server_name = NULL;
+  int count = 0, clients_count;
+  SilcClientID *client_id = NULL;
+  SilcClientEntry *clients = NULL, entry;
+  int ret = 0;
+
+  /* Parse the whois request */
+  if (!silc_server_command_whois_parse(cmd, &client_id, &nick, 
+                                      &server_name, &count))
+    return 0;
+
+  /* Process the command request. Let's search for the requested client and
+     send reply to the requesting server. */
+
+  if (client_id) {
+    entry = silc_idlist_find_client_by_id(server->local_list, client_id);
+    if (entry) {
+      clients = silc_calloc(1, sizeof(*clients));
+      clients[0] = entry;
+      clients_count = 1;
+    }
+  } else {
+    clients = silc_idlist_get_clients_by_nickname(server->local_list, 
+                                                 nick, server_name,
+                                                 &clients_count);
+  }
+  
+  /* If we are router we will check our global list as well. */
+  if (!clients && server->server_type == SILC_ROUTER) {
+    if (client_id) {
+      entry = silc_idlist_find_client_by_id(server->global_list, client_id);
+      if (entry) {
+       clients = silc_calloc(1, sizeof(*clients));
+       clients[0] = entry;
+       clients_count = 1;
+      }
+    } else {
+      clients = silc_idlist_get_clients_by_nickname(server->global_list, 
+                                                   nick, server_name,
+                                                   &clients_count);
+    }
+  }
+
+  if (!clients) {
+    /* Such a client really does not exist in the SILC network. */
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
+                                        SILC_STATUS_ERR_NO_SUCH_NICK,
+                                        3, nick, strlen(nick));
+    goto out;
+  }
+
+  /* Router always finds the client entry if it exists in the SILC network.
+     However, it might be incomplete entry and does not include all the
+     mandatory fields that WHOIS command reply requires. Check for these and
+     make query from the server who owns the client if some fields are 
+     missing. */
+  if (!cmd->pending && server->server_type == SILC_ROUTER &&
+      !silc_server_command_whois_check(cmd, clients, clients_count)) {
+    ret = -1;
+    goto out;
+  }
+
+  /* Send the command reply to the client */
+  silc_server_command_whois_send_reply(cmd, clients, clients_count);
 
  out:
-  silc_server_command_free(cmd);
+  if (clients)
+    silc_free(clients);
+  if (client_id)
+    silc_free(client_id);
+  if (nick)
+    silc_free(nick);
+  if (server_name)
+    silc_free(server_name);
+
+  return ret;
+}
+
+/* Server side of command WHOIS. Processes user's query and sends found 
+   results as command replies back to the client. */
+
+SILC_SERVER_CMD_FUNC(whois)
+{
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  int ret;
+
+  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_WHOIS, cmd, 1, 3);
+
+  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
+    ret = silc_server_command_whois_from_client(cmd);
+  else
+    ret = silc_server_command_whois_from_server(cmd);
+
+  if (!ret)
+    silc_server_command_free(cmd);
 }
 
 SILC_SERVER_CMD_FUNC(whowas)
@@ -954,7 +1154,7 @@ SILC_SERVER_CMD_FUNC(invite)
   if (dest)
     dest_sock = (SilcSocketConnection)dest->connection;
   else
-    dest_sock = silc_server_get_route(server, dest_id, SILC_ID_CLIENT);
+    dest_sock = silc_server_route_get(server, dest_id, SILC_ID_CLIENT);
 
   /* Check whether the requested client is already on the channel. */
   /* XXX if we are normal server we don't know about global clients on
index f72bed1e22db21cf04caa2f93976c11307079f4e..74ba0d6dbb6e1658a011464ad821c4f9aa2f032a 100644 (file)
@@ -123,10 +123,12 @@ void silc_server_command_reply_free(SilcServerCommandReplyContext cmd)
 static char
 silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
 {
+  SilcServer server = cmd->server;
   int len, id_len;
   unsigned char *id_data;
   char *nickname, *username, *realname;
   SilcClientID *client_id;
+  SilcClientEntry client;
 
   id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
   nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
@@ -137,6 +139,31 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
 
   client_id = silc_id_payload_parse_id(id_data, id_len);
 
+  /* Check if we have this client cached already. */
+
+  client = silc_idlist_find_client_by_id(server->local_list, client_id);
+  if (!client && server->server_type == SILC_ROUTER)
+    client = silc_idlist_find_client_by_id(server->global_list, client_id);
+
+  if (!client) {
+    /* We don't have that client anywhere, add it. The client is added
+       to global list since server or router didn't have it in the lists
+       so it must be global. */
+    silc_idlist_add_client(server->global_list, strdup(nickname),
+                          username, realname, client_id, NULL, NULL);
+  } else {
+    /* We have the client already, update the data */
+
+    if (client->username)
+      silc_free(client->username);
+    if (client->userinfo)
+      silc_free(client->userinfo);
+    
+    client->username = strdup(username);
+    client->userinfo = strdup(realname);
+  }
+
+  silc_free(client_id);
 
   return TRUE;
 }
@@ -150,13 +177,17 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
 SILC_SERVER_CMD_REPLY_FUNC(whois)
 {
   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
-  SilcServer server = cmd->server;
   SilcCommandStatus status;
 
   SILC_LOG_DEBUG(("Start"));
 
   COMMAND_CHECK_STATUS_LIST;
 
+  if (!silc_server_command_reply_whois_save(cmd))
+    goto out;
+
+  /* XXX */
+
   /* Process one identify reply */
   if (status == SILC_STATUS_OK) {
 
index 3d4abebcf1c36ab3657b110a5bc78ce1b976ca3e..e8583b015ecc25a3d38c38e6b186183bc2a111f7 100644 (file)
@@ -108,7 +108,7 @@ void silc_server_private_message(SilcServer server,
   /* We are router and we will perform route lookup for the destination 
      and send the message to fastest route. */
   if (server->server_type == SILC_ROUTER && !server->standalone) {
-    dst_sock = silc_server_get_route(server, id, SILC_ID_CLIENT);
+    dst_sock = silc_server_route_get(server, id, SILC_ID_CLIENT);
     router = (SilcServerEntry)dst_sock->user_data;
     idata = (SilcIDListData)router;
 
index 6877f6128beeeb6574ac64d2eda51bf5cc2549bd..5e478577eb88fb9304b922b768116aef920d1dee 100644 (file)
@@ -267,6 +267,33 @@ void silc_server_packet_broadcast(SilcServer server,
   silc_free(id);
 }
 
+/* Routes received packet to `sock'. This is used to route the packets that
+   router receives but are not destined to it. */
+
+void silc_server_packet_route(SilcServer server,
+                             SilcSocketConnection sock,
+                             SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+  SilcIDListData idata;
+
+  SILC_LOG_DEBUG(("Routing received packet"));
+
+  idata = (SilcIDListData)sock->user_data;
+
+  silc_buffer_push(buffer, buffer->data - buffer->head);
+  silc_packet_send_prepare(sock, 0, 0, buffer->len); 
+  silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
+  silc_packet_encrypt(idata->send_key, idata->hmac, 
+                     sock->outbuf, sock->outbuf->len);
+
+  SILC_LOG_HEXDUMP(("Routed packet, len %d", sock->outbuf->len),
+                  sock->outbuf->data, sock->outbuf->len);
+
+  /* Now actually send the packet */
+  silc_server_packet_send_real(server, sock, TRUE);
+}
+
 /* Internal routine to actually create the channel packet and send it
    to network. This is common function in channel message sending. If
    `channel_message' is TRUE this encrypts the message as it is strictly
index 793605475e275806fde65655bbaf075ad69c439d..bf0df60dc5561762bf2f809ec0937ddfca7a4ade 100644 (file)
@@ -49,6 +49,9 @@ void silc_server_packet_forward(SilcServer server,
 void silc_server_packet_broadcast(SilcServer server,
                                  SilcSocketConnection sock,
                                  SilcPacketContext *packet);
+void silc_server_packet_route(SilcServer server,
+                             SilcSocketConnection sock,
+                             SilcPacketContext *packet);
 void silc_server_packet_send_to_channel(SilcServer server,
                                        SilcChannelEntry channel,
                                        SilcPacketType type,
index 149683a479a6bea7a4e89c3c9584283b7e024714..09d9926279d0cc92c8af3719463c57ce9975ec1f 100644 (file)
@@ -62,7 +62,7 @@ SilcServerEntry silc_server_route_check(unsigned int dest,
    If we are normal server then this just returns our primary route. If
    we are router we will do route lookup. */
 
-SilcSocketConnection silc_server_get_route(SilcServer server, void *id,
+SilcSocketConnection silc_server_route_get(SilcServer server, void *id,
                                           SilcIdType id_type)
 {
   if (server->server_type == SILC_ROUTER) {
index b04118d798b681f8c186482c20e3ce250046a352..235f9271498c76aa835f995ea491863cdd7fef7a 100644 (file)
@@ -73,7 +73,7 @@ void silc_server_route_add(unsigned int index, unsigned int dest,
                           SilcServerEntry router);
 SilcServerEntry silc_server_route_check(unsigned int dest, 
                                        unsigned short port);
-SilcSocketConnection silc_server_get_route(SilcServer server, void *id,
+SilcSocketConnection silc_server_route_get(SilcServer server, void *id,
                                           SilcIdType id_type);
 
 #endif
index 1b71f80adc19afd97c936e1a8a819c30841cd88c..2b1575fd531898b1d2f2fe021946f52c9e9b53c8 100644 (file)
@@ -249,6 +249,8 @@ int silc_server_init(SilcServer server)
     }
     
     server->id = id;
+    server->id_string = silc_id_id2str(id, SILC_ID_SERVER);
+    server->id_string_len = silc_id_get_len(SILC_ID_SERVER);
     server->id_type = SILC_ID_SERVER;
     server->server_name = server->config->server_info->server_name;
 
@@ -1134,14 +1136,13 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real)
   SilcServer server = (SilcServer)parse_ctx->context;
   SilcSocketConnection sock = parse_ctx->sock;
   SilcPacketContext *packet = parse_ctx->packet;
-  SilcBuffer buffer = packet->buffer;
   int ret;
 
   SILC_LOG_DEBUG(("Start"));
 
   /* Decrypt the received packet */
   ret = silc_packet_decrypt(parse_ctx->cipher, parse_ctx->hmac, 
-                           buffer, packet);
+                           packet->buffer, packet);
   if (ret < 0)
     goto out;
 
@@ -1157,12 +1158,29 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real)
   if (ret == SILC_PACKET_NONE)
     goto out;
 
-  /* Broadcast packet if it is marked as broadcast packet and it is
-     originated from router and we are router. */
-  if (server->server_type == SILC_ROUTER && 
-      sock->type == SILC_SOCKET_TYPE_ROUTER &&
-      packet->flags & SILC_PACKET_FLAG_BROADCAST) {
-    silc_server_packet_broadcast(server, server->router->connection, packet);
+  if (server->server_type == SILC_ROUTER) {
+    /* Route the packet if it is not destined to us. Other ID types but
+       server are handled separately after processing them. */
+    if (packet->dst_id_type == SILC_ID_SERVER &&
+       sock->type != SILC_SOCKET_TYPE_CLIENT &&
+       SILC_ID_SERVER_COMPARE(packet->dst_id, server->id_string)) {
+      
+      /* Route the packet to fastest route for the destination ID */
+      void *id = silc_id_str2id(packet->dst_id, packet->dst_id_type);
+      silc_server_packet_route(server,
+                              silc_server_route_get(server, id,
+                                                    packet->dst_id_type),
+                              packet);
+      silc_free(id);
+      goto out;
+    }
+    
+    /* Broadcast packet if it is marked as broadcast packet and it is
+       originated from router and we are router. */
+    if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
+       packet->flags & SILC_PACKET_FLAG_BROADCAST) {
+      silc_server_packet_broadcast(server, server->router->connection, packet);
+    }
   }
 
   /* Parse the incoming packet type */
index 429988c4a001d667ac1e6778080954e4bed5e6cb..bd1abf16c3321d62806807cb4eeb0044f007a095 100644 (file)
@@ -55,6 +55,8 @@ struct SilcServerStruct {
   int standalone;
   int listenning;
   SilcServerID *id;
+  unsigned char *id_string;
+  unsigned int id_string_len;
   SilcIdType id_type;
 
   /* Server's own ID entry. */