updates.
authorPekka Riikonen <priikone@silcnet.org>
Fri, 16 Feb 2001 23:28:53 +0000 (23:28 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Fri, 16 Feb 2001 23:28:53 +0000 (23:28 +0000)
15 files changed:
CHANGES
apps/silc/client_ops.c
apps/silcd/idlist.c
apps/silcd/idlist.h
apps/silcd/packet_receive.c
apps/silcd/packet_receive.h
apps/silcd/packet_send.c
apps/silcd/server.c
apps/silcd/server.h
doc/draft-riikonen-silc-pp-01.nroff
lib/silcclient/client.c
lib/silccore/id.h
lib/silccore/silcnotify.h
lib/silccore/silcpacket.h
lib/silcutil/silcbufutil.h

diff --git a/CHANGES b/CHANGES
index 313cda5ecccd384c2e8207fb898ef69f431e79da..2d24b196216d5ead6009deb785091d737d5f5684 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,67 @@
+Sat Feb 17 01:06:44 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Added new function into the silcd/server.[ch] files:
+         silc_server_create_new_channel_with_id to create new channel with
+         already existing Channel ID.
+
+       * Added new packet type SILC_PACKET_SET_MODE_LIST into the file
+         lib/silccore/silcpacket.h.  This packet is used t send list of
+         Set Mode payloads inside one packet.  Server uses this to set
+         the modes for the channels and clients on those channels, that it
+         announced to the router when it connected to it.  The protocol
+         specification has been updated accordingly.
+
+       * The silc_server_new_channel did not handle the packet coming
+         from normal server as it normally does not send that.  However,
+         when it announces its channels it does send it.  Implemented
+         the support for that.
+
+       * Added SILC_ID_CHANNEL_COMPARE macro to compare to Channel ID's
+         into the file lib/silccore/id.h.
+
+Fri Feb 16 23:57:29 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Fixed memory leaks in the functions silc_idlist_del_client,
+         silc_idlist_del_channel and silc_idlist_del_server in the file
+         silcd/idlist.c.  All of those leaked like a sieve.
+
+       * Fixed some small memory leaks in the client's function
+         silc_client_notify_by_server.
+
+       * Added functions into silcd/server.c: silc_server_announce_clients,
+         silc_server_announce_channels and silc_server_announce_server.
+         These functions are used by normal and router server to announce
+         to its primary router about clients, channels and servers (when
+         router) that we own.  This is done after we've connected to the
+         router.
+
+         These functions effectively implements the following packet types:
+         SILC_PACKET_NEW_CHANNEL_LIST, SILC_PACKET_NEW_CHANNEL_USER_LIST
+         and SILC_PACKET_NEW_ID_LIST.
+
+       * Added new functions into the silcd/packet_receive.[ch]:
+         silc_server_new_id_list, silc_server_new_channel_list and
+         silc_server_new_channel_user_list to handle the incoming 
+         NEW_ID_LIST, NEW_CHANNEL_LIST and NEW_CHANNEL_USER_LIST packets.
+
+       * Added support of changing Channel ID in the function
+         silc_server_replace_id.  If the server that announces a channel
+         to the router already exists in the router (with same name but
+         with different Channel ID), router is responsible to send
+         Replace ID packet to the server and force the server to change
+         the Channel ID to the one router has.
+
+       * Added new notify type SILC_NOTIFY_TYPE_CHANNEL_CHANGE to notify
+         client that the Channel ID has been changed by the router.  The
+         normal server sends this to the client.  Client must start using
+         the new Channel ID as the channel's ID.
+
+         Implemented handling of this new type into lib/silcclient/client.c
+         into the function silc_client_notify_by_server.
+
+       * Added new function silc_idlist_replace_channel_id into the files
+         silcd/idlist.[ch] to replace the Channel ID.
+
 Fri Feb 16 14:14:00 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Call silc_server_command_identify_check always when processing
index 4097e9f8454ef75604547821dd0afcbe62f90903..cb73029339a7706440659f7e7ad9924c670d539b 100644 (file)
@@ -219,6 +219,9 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
     }
     return;
 
+  case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
+    break;
+
   default:
     break;
   }
index 1d6b9540a320563df5f4162e84703773618df480..6323af367cead87a754cc6c4f17318b821ea5709 100644 (file)
@@ -172,6 +172,9 @@ void silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
       silc_free(entry->server_name);
     if (entry->id)
       silc_free(entry->id);
+
+    memset(entry, 'F', sizeof(*entry));
+    silc_free(entry);
   }
 }
 
@@ -238,6 +241,9 @@ void silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
       silc_free(entry->userinfo);
     if (entry->id)
       silc_free(entry->id);
+
+    memset(entry, 'F', sizeof(*entry));
+    silc_free(entry);
   }
 }
 
@@ -528,16 +534,19 @@ int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
       memset(entry->key, 0, entry->key_len / 8);
       silc_free(entry->key);
     }
-    memset(entry->iv, 0, sizeof(entry->iv));
     
     silc_list_start(entry->user_list);
     while ((chl = silc_list_get(entry->user_list)) != SILC_LIST_END) {
       silc_list_del(entry->user_list, chl);
       silc_free(chl);
     }
+
+    memset(entry, 'F', sizeof(*entry));
+    silc_free(entry);
+    return TRUE;
   }
 
-  return TRUE;
+  return FALSE;
 }
 
 /* Finds channel by channel name. Channel names are unique and they
@@ -601,3 +610,30 @@ silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
 
   return channel;
 }
+
+/* Replaces old Channel ID with new one. This is done when router forces
+   normal server to change Channel ID. */
+
+SilcChannelEntry
+silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
+                              SilcChannelID *new_id)
+{
+  SilcIDCacheEntry id_cache = NULL;
+  SilcChannelEntry channel;
+
+  if (!old_id || !new_id)
+    return NULL;
+
+  SILC_LOG_DEBUG(("Replacing Channel ID"));
+
+  if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id, 
+                                  SILC_ID_CHANNEL, &id_cache))
+    return NULL;
+
+  channel = (SilcChannelEntry)id_cache->context;
+  silc_free(channel->id);
+  channel->id = new_id;
+  id_cache->id = (void *)new_id;
+
+  return channel;
+}
index cbdf64f8dd45d0229b09ca9dcf6e1422ffb27b09..4940b6c8cdbe0d7b455e6913c45a509ebc61bd7b 100644 (file)
@@ -503,5 +503,8 @@ silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
 SilcChannelEntry
 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
                               SilcIDCacheEntry *ret_entry);
+SilcChannelEntry
+silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
+                              SilcChannelID *new_id);
 
 #endif
index c3978f7004a692937db87209c1129234bfa866f3..9321add3326ad09bd97862424c46e38531c8ae6a 100644 (file)
@@ -385,18 +385,21 @@ void silc_server_replace_id(SilcServer server,
 
   case SILC_ID_SERVER:
     SILC_LOG_DEBUG(("Old Server ID id(%s)", 
-                   silc_id_render(id, SILC_ID_CLIENT)));
+                   silc_id_render(id, SILC_ID_SERVER)));
     SILC_LOG_DEBUG(("New Server ID id(%s)", 
-                   silc_id_render(id2, SILC_ID_CLIENT)));
+                   silc_id_render(id2, SILC_ID_SERVER)));
     if (silc_idlist_replace_server_id(server->local_list, id, id2) == NULL)
       if (server->server_type == SILC_ROUTER)
        silc_idlist_replace_server_id(server->global_list, id, id2);
     break;
 
   case SILC_ID_CHANNEL:
-    /* XXX Hmm... Basically this cannot occur. Channel ID's cannot be
-       re-generated. */
-    silc_free(id2);
+    SILC_LOG_DEBUG(("Old Channel ID id(%s)", 
+                   silc_id_render(id, SILC_ID_CHANNEL)));
+    SILC_LOG_DEBUG(("New Channel ID id(%s)", 
+                   silc_id_render(id2, SILC_ID_CHANNEL)));
+    if (silc_idlist_replace_channel_id(server->local_list, id, id2) == NULL)
+      silc_idlist_replace_channel_id(server->global_list, id, id2);
     break;
 
   default:
@@ -777,6 +780,245 @@ void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
   silc_id_payload_free(idp);
 }
 
+/* Receoved New Id List packet, list of New ID payloads inside one
+   packet. Process the New ID payloads one by one. */
+
+void silc_server_new_id_list(SilcServer server, SilcSocketConnection sock,
+                            SilcPacketContext *packet)
+{
+  SilcPacketContext *new_id;
+  SilcBuffer idp;
+  unsigned short id_len;
+
+  SILC_LOG_DEBUG(("Processing New ID List"));
+
+  if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+      packet->src_id_type != SILC_ID_SERVER)
+    return;
+
+  /* Make copy of the original packet context, except for the actual
+     data buffer, which we will here now fetch from the original buffer. */
+  new_id = silc_packet_context_alloc();
+  new_id->type = SILC_PACKET_NEW_ID;
+  new_id->flags = packet->flags;
+  new_id->src_id = packet->src_id;
+  new_id->src_id_len = packet->src_id_len;
+  new_id->src_id_type = packet->src_id_type;
+  new_id->dst_id = packet->dst_id;
+  new_id->dst_id_len = packet->dst_id_len;
+  new_id->dst_id_type = packet->dst_id_type;
+
+  idp = silc_buffer_alloc(256);
+  new_id->buffer = idp;
+
+  while (packet->buffer->len) {
+    SILC_GET16_MSB(id_len, packet->buffer->data + 2);
+    if ((id_len > packet->buffer->len) ||
+       (id_len > idp->truelen))
+      break;
+
+    silc_buffer_pull_tail(idp, 4 + id_len);
+    silc_buffer_put(idp, packet->buffer->data, 4 + id_len);
+
+    /* Process the New ID */
+    silc_server_new_id(server, sock, new_id);
+
+    silc_buffer_push_tail(idp, 4 + id_len);
+    silc_buffer_pull(packet->buffer, 4 + id_len);
+  }
+
+  silc_buffer_free(idp);
+  silc_free(new_id);
+}
+
+/* Received New Channel packet. Information about new channels in the 
+   network are distributed using this packet. Save the information about
+   the new channel. This usually comes from router but also normal server
+   can send this to notify channels it has when it connects to us. */
+
+void silc_server_new_channel(SilcServer server,
+                            SilcSocketConnection sock,
+                            SilcPacketContext *packet)
+{
+  unsigned char *id;
+  SilcChannelID *channel_id;
+  unsigned short channel_id_len;
+  char *channel_name;
+  int ret;
+
+  SILC_LOG_DEBUG(("Processing New Channel"));
+
+  if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+      packet->src_id_type != SILC_ID_SERVER ||
+      server->server_type == SILC_SERVER)
+    return;
+
+  /* Parse payload */
+  ret = silc_buffer_unformat(packet->buffer, 
+                            SILC_STR_UI16_STRING_ALLOC(&channel_name),
+                            SILC_STR_UI16_NSTRING_ALLOC(&id, &channel_id_len),
+                            SILC_STR_END);
+  if (ret == -1) {
+    if (channel_name)
+      silc_free(channel_name);
+    if (id)
+      silc_free(id);
+    return;
+  }
+    
+  /* Decode the channel ID */
+  channel_id = silc_id_str2id(id, channel_id_len, SILC_ID_CHANNEL);
+  if (!channel_id)
+    return;
+
+  if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+    /* Add the server to global list as it is coming from router. It 
+       cannot be our own channel as it is coming from router. */
+
+    SILC_LOG_DEBUG(("New channel id(%s) from [Router] %s",
+                   silc_id_render(channel_id, SILC_ID_CHANNEL), 
+                   sock->hostname));
+    
+    silc_idlist_add_channel(server->global_list, channel_name, 0, channel_id, 
+                           server->router->connection, NULL);
+
+    server->stat.channels++;
+  } else {
+    /* The channel is coming from our server, thus it is in our cell
+       we will add it to our local list. */
+    SilcChannelEntry channel;
+    SilcBuffer chk;
+
+    SILC_LOG_DEBUG(("New channel id(%s) from [Server] %s",
+                   silc_id_render(channel_id, SILC_ID_CHANNEL), 
+                   sock->hostname));
+    
+    /* Check that we don't already have this channel */
+    channel = silc_idlist_find_channel_by_name(server->local_list, 
+                                              channel_name, NULL);
+    if (!channel)
+      channel = silc_idlist_find_channel_by_name(server->global_list, 
+                                                channel_name, NULL);
+
+    /* If the channel does not exist, then create it. We create the channel
+       with the channel ID provided by the server. This creates a new
+       key to the channel as well that we will send to the server. */
+    if (!channel) {
+      channel = silc_server_create_new_channel_with_id(server, NULL,
+                                                      channel_name,
+                                                      channel_id);
+      if (!channel)
+       return;
+
+      /* Send the new channel key to the server */
+      chk = silc_channel_key_payload_encode(channel_id_len, id,
+                                           strlen(channel->channel_key->
+                                                  cipher->name),
+                                           channel->channel_key->cipher->name,
+                                           channel->key_len / 8, 
+                                           channel->key);
+      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.
+        We also create a new key for the channel. */
+
+      if (SILC_ID_CHANNEL_COMPARE(channel_id, channel->id)) {
+       /* They don't match, send Replace ID packet to the server to
+          force the ID change. */
+       SILC_LOG_DEBUG(("Forcing the server to change Channel ID"));
+       silc_server_send_replace_id(server, sock, FALSE, 
+                                   channel_id, SILC_ID_CHANNEL,
+                                   SILC_ID_CHANNEL_LEN,
+                                   channel->id, SILC_ID_CHANNEL,
+                                   SILC_ID_CHANNEL_LEN);
+      }
+
+      /* Create new key for the channel and send it to the server and
+        everybody else possibly on the channel. */
+
+      silc_server_create_channel_key(server, channel, 0);
+
+      /* Send to the channel */
+      silc_server_send_channel_key(server, sock, channel, FALSE);
+
+      /* Send to the server */
+      chk = silc_channel_key_payload_encode(channel_id_len, id,
+                                           strlen(channel->channel_key->
+                                                  cipher->name),
+                                           channel->channel_key->cipher->name,
+                                           channel->key_len / 8, 
+                                           channel->key);
+      silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0, 
+                             chk->data, chk->len, FALSE);
+      silc_buffer_free(chk);
+    }
+  }
+
+  silc_free(id);
+}
+
+/* Received New Channel List packet, list of New Channel List payloads inside
+   one packet. Process the New Channel payloads one by one. */
+
+void silc_server_new_channel_list(SilcServer server,
+                                 SilcSocketConnection sock,
+                                 SilcPacketContext *packet)
+{
+  SilcPacketContext *new;
+  SilcBuffer buffer;
+  unsigned short len1, len2;
+
+  SILC_LOG_DEBUG(("Processing New Channel List"));
+
+  if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+      packet->src_id_type != SILC_ID_SERVER ||
+      server->server_type == SILC_SERVER)
+    return;
+
+  /* Make copy of the original packet context, except for the actual
+     data buffer, which we will here now fetch from the original buffer. */
+  new = silc_packet_context_alloc();
+  new->type = SILC_PACKET_NEW_CHANNEL;
+  new->flags = packet->flags;
+  new->src_id = packet->src_id;
+  new->src_id_len = packet->src_id_len;
+  new->src_id_type = packet->src_id_type;
+  new->dst_id = packet->dst_id;
+  new->dst_id_len = packet->dst_id_len;
+  new->dst_id_type = packet->dst_id_type;
+
+  buffer = silc_buffer_alloc(512);
+  new->buffer = buffer;
+
+  while (packet->buffer->len) {
+    SILC_GET16_MSB(len1, packet->buffer->data);
+    if ((len1 > packet->buffer->len) ||
+       (len1 > buffer->truelen))
+      break;
+
+    SILC_GET16_MSB(len2, packet->buffer->data + 2 + len1);
+    if ((len2 > packet->buffer->len) ||
+       (len2 > buffer->truelen))
+      break;
+
+    silc_buffer_pull_tail(buffer, 4 + len1 + len2);
+    silc_buffer_put(buffer, packet->buffer->data, 4 + len1 + len2);
+
+    /* Process the New Channel */
+    silc_server_new_channel(server, sock, new);
+
+    silc_buffer_push_tail(buffer, 4 + len1 + len2);
+    silc_buffer_pull(packet->buffer, 4 + len1 + len2);
+  }
+
+  silc_buffer_free(buffer);
+  silc_free(new);
+}
+
 /* Received Remove Channel User packet to remove a user from a channel. 
    Routers notify other routers that user has left a channel. Client must
    not send this packet. Normal server may send this packet but must not
@@ -798,6 +1040,7 @@ void silc_server_remove_channel_user(SilcServer server,
   SILC_LOG_DEBUG(("Removing user from channel"));
 
   if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+      packet->src_id_type != SILC_ID_SERVER ||
       server->server_type == SILC_SERVER)
     return;
 
@@ -859,57 +1102,62 @@ void silc_server_remove_channel_user(SilcServer server,
     silc_free(channel_id);
 }
 
-/* Received New Channel packet. Information about new channels in the 
-   network are distributed using this packet. Save the information about
-   the new channel. */
+/* Received New Channel User List packet, list of New Channel User payloads
+   inside one packet.  Process the payloads one by one. */
 
-void silc_server_new_channel(SilcServer server,
-                            SilcSocketConnection sock,
-                            SilcPacketContext *packet)
+void silc_server_new_channel_user_list(SilcServer server,
+                                      SilcSocketConnection sock,
+                                      SilcPacketContext *packet)
 {
-  unsigned char *id;
-  SilcChannelID *channel_id;
-  unsigned short channel_id_len;
-  char *channel_name;
-  int ret;
+  SilcPacketContext *new;
+  SilcBuffer buffer;
+  unsigned short len1, len2;
 
-  SILC_LOG_DEBUG(("Processing New Channel"));
+  SILC_LOG_DEBUG(("Processing New Channel User List"));
 
-  if (sock->type != SILC_SOCKET_TYPE_ROUTER ||
-      server->server_type == SILC_SERVER ||
-      packet->src_id_type != SILC_ID_SERVER)
+  if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+      packet->src_id_type != SILC_ID_SERVER ||
+      server->server_type == SILC_SERVER)
     return;
 
-  /* Parse payload */
-  ret = silc_buffer_unformat(packet->buffer, 
-                            SILC_STR_UI16_STRING_ALLOC(&channel_name),
-                            SILC_STR_UI16_NSTRING_ALLOC(&id, &channel_id_len),
-                            SILC_STR_END);
-  if (ret == -1) {
-    if (channel_name)
-      silc_free(channel_name);
-    if (id)
-      silc_free(id);
-    return;
-  }
-    
-  /* Decode the channel ID */
-  channel_id = silc_id_str2id(id, channel_id_len, SILC_ID_CHANNEL);
-  if (!channel_id)
-    return;
-  silc_free(id);
+  /* Make copy of the original packet context, except for the actual
+     data buffer, which we will here now fetch from the original buffer. */
+  new = silc_packet_context_alloc();
+  new->type = SILC_PACKET_NEW_CHANNEL_USER;
+  new->flags = packet->flags;
+  new->src_id = packet->src_id;
+  new->src_id_len = packet->src_id_len;
+  new->src_id_type = packet->src_id_type;
+  new->dst_id = packet->dst_id;
+  new->dst_id_len = packet->dst_id_len;
+  new->dst_id_type = packet->dst_id_type;
+
+  buffer = silc_buffer_alloc(256);
+  new->buffer = buffer;
+
+  while (packet->buffer->len) {
+    SILC_GET16_MSB(len1, packet->buffer->data);
+    if ((len1 > packet->buffer->len) ||
+       (len1 > buffer->truelen))
+      break;
 
-  SILC_LOG_DEBUG(("New channel id(%s) from [Router] %s",
-                 silc_id_render(channel_id, SILC_ID_CHANNEL), 
-                 sock->hostname));
+    SILC_GET16_MSB(len2, packet->buffer->data + 2 + len1);
+    if ((len2 > packet->buffer->len) ||
+       (len2 > buffer->truelen))
+      break;
+
+    silc_buffer_pull_tail(buffer, 4 + len1 + len2);
+    silc_buffer_put(buffer, packet->buffer->data, 4 + len1 + len2);
 
-  /* Add the new channel. Add it always to global list since if we receive
-     this packet then it cannot be created by ourselves but some other 
-     router hence global channel. */
-  silc_idlist_add_channel(server->global_list, channel_name, 0, channel_id, 
-                         server->router->connection, NULL);
+    /* Process the New Channel User */
+    silc_server_new_channel_user(server, sock, new);
+
+    silc_buffer_push_tail(buffer, 4 + len1 + len2);
+    silc_buffer_pull(packet->buffer, 4 + len1 + len2);
+  }
 
-  server->stat.channels++;
+  silc_buffer_free(buffer);
+  silc_free(new);
 }
 
 /* Received notify packet. Server can receive notify packets from router. 
index 4b822a6df9f715d247e15b5be7a8dab2e6df6b78..2d0d3f3c91ffd9b9bea6dbb6e46f5c16cfaa7fec 100644 (file)
@@ -46,18 +46,26 @@ SilcServerEntry silc_server_new_server(SilcServer server,
                                       SilcPacketContext *packet);
 void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
                        SilcPacketContext *packet);
+void silc_server_new_id_list(SilcServer server, SilcSocketConnection sock,
+                            SilcPacketContext *packet);
 void silc_server_remove_channel_user(SilcServer server,
                                     SilcSocketConnection sock,
                                     SilcPacketContext *packet);
 void silc_server_new_channel(SilcServer server,
                             SilcSocketConnection sock,
                             SilcPacketContext *packet);
-void silc_server_notify(SilcServer server,
-                       SilcSocketConnection sock,
-                       SilcPacketContext *packet);
+void silc_server_new_channel_list(SilcServer server,
+                                 SilcSocketConnection sock,
+                                 SilcPacketContext *packet);
 void silc_server_new_channel_user(SilcServer server,
                                  SilcSocketConnection sock,
                                  SilcPacketContext *packet);
+void silc_server_new_channel_user_list(SilcServer server,
+                                      SilcSocketConnection sock,
+                                      SilcPacketContext *packet);
+void silc_server_notify(SilcServer server,
+                       SilcSocketConnection sock,
+                       SilcPacketContext *packet);
 void silc_server_remove_id(SilcServer server,
                           SilcSocketConnection sock,
                           SilcPacketContext *packet);
index 83fef72fad60cc225d3ad6be3e78b8d7e2b1e1c6..05f0454e77eaa0984af80b31a95b3b3458449bec 100644 (file)
@@ -1050,6 +1050,7 @@ void silc_server_send_new_channel(SilcServer server,
                     SILC_STR_UI_XNSTRING(cid, channel_id_len),
                     SILC_STR_END);
 
+
   silc_server_packet_send(server, sock, SILC_PACKET_NEW_CHANNEL, 
                          broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, 
                          packet->data, packet->len, FALSE);
index 6a6733c6a39c8b19e2cab17b0c1bfbadfd94b666..86b0e6f57d23b86361624054d72dc1fc71efc058 100644 (file)
@@ -860,6 +860,14 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
                            silc_server_perform_heartbeat,
                            server->timeout_queue);
 
+  /* If we are router then announce our possible servers. */
+  if (server->server_type == SILC_ROUTER)
+    silc_server_announce_servers(server);
+
+  /* Announce our clients and channels to the router */
+  silc_server_announce_clients(server);
+  silc_server_announce_channels(server);
+
  out:
   /* Free the temporary connection data context */
   if (sconn)
@@ -1646,6 +1654,15 @@ void silc_server_packet_parse_type(SilcServer server,
     silc_server_new_id(server, sock, packet);
     break;
 
+  case SILC_PACKET_NEW_ID_LIST:
+    /*
+     * Received list of ID's. This packet is used by servers and routers
+     * to notify their primary router about clients and servers they have.
+     */
+    SILC_LOG_DEBUG(("New ID List packet"));
+    silc_server_new_id_list(server, sock, packet);
+    break;
+
   case SILC_PACKET_NEW_CLIENT:
     /*
      * Received new client packet. This includes client information that
@@ -1693,6 +1710,8 @@ void silc_server_packet_parse_type(SilcServer server,
      * existing server or router connects to us and distributes information
      * of all channels it has.
      */
+    SILC_LOG_DEBUG(("New Channel List packet"));
+    silc_server_new_channel_list(server, sock, packet);
     break;
 
   case SILC_PACKET_NEW_CHANNEL_USER_LIST:
@@ -1701,6 +1720,8 @@ void silc_server_packet_parse_type(SilcServer server,
      * when existing server or router connects to us and distributes 
      * information of all channel users it has.
      */
+    SILC_LOG_DEBUG(("New Channel User List packet"));
+    silc_server_new_channel_user_list(server, sock, packet);
     break;
 
   case SILC_PACKET_REPLACE_ID:
@@ -2219,6 +2240,51 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
   return entry;
 }
 
+/* Same as above but creates the channel with Channel ID `channel_id. */
+
+SilcChannelEntry 
+silc_server_create_new_channel_with_id(SilcServer server, 
+                                      char *cipher, 
+                                      char *channel_name,
+                                      SilcChannelID *channel_id)
+{
+  SilcChannelEntry entry;
+  SilcCipher key;
+
+  SILC_LOG_DEBUG(("Creating new channel"));
+
+  if (!cipher)
+    cipher = "twofish";
+
+  /* Allocate cipher */
+  silc_cipher_alloc(cipher, &key);
+
+  channel_name = strdup(channel_name);
+
+  /* Create the channel */
+  entry = silc_idlist_add_channel(server->local_list, channel_name, 
+                                 SILC_CHANNEL_MODE_NONE, channel_id, 
+                                 NULL, key);
+  if (!entry) {
+    silc_free(channel_name);
+    return NULL;
+  }
+
+  /* Now create the actual key material */
+  silc_server_create_channel_key(server, entry, 16);
+
+  /* Notify other routers about the new channel. We send the packet
+     to our primary route. */
+  if (server->standalone == FALSE) {
+    silc_server_send_new_channel(server, server->router->connection, TRUE, 
+                                channel_name, entry->id, SILC_ID_CHANNEL_LEN);
+  }
+
+  server->stat.my_channels++;
+
+  return entry;
+}
+
 /* Generates new channel key. This is used to create the initial channel key
    but also to re-generate new key for channel. If `key_len' is provided
    it is the bytes of the key length. */
@@ -2360,3 +2426,264 @@ void silc_server_perform_heartbeat(SilcSocketConnection sock,
   /* Send the heartbeat */
   silc_server_send_heartbeat(hb->server, sock);
 }
+
+/* Returns assembled of all servers in the given ID list. The packet's
+   form is dictated by the New ID payload. */
+
+static void silc_server_announce_get_servers(SilcServer server,
+                                            SilcIDList id_list,
+                                            SilcBuffer *servers)
+{
+  SilcIDCacheList list;
+  SilcIDCacheEntry id_cache;
+  SilcServerEntry entry;
+  SilcBuffer idp;
+
+  /* Go through all clients in the list */
+  if (silc_idcache_find_by_id(id_list->clients, SILC_ID_CACHE_ANY, 
+                             SILC_ID_SERVER, &list)) {
+    if (silc_idcache_list_first(list, &id_cache)) {
+      while (id_cache) {
+       entry = (SilcServerEntry)id_cache->context;
+
+       idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
+
+       *servers = silc_buffer_realloc(*servers, 
+                                      (*servers ? 
+                                       (*servers)->truelen + idp->len : 
+                                       idp->len));
+       silc_buffer_pull_tail(*servers, ((*servers)->end - (*servers)->data));
+       silc_buffer_put(*servers, idp->data, idp->len);
+       silc_buffer_pull(*servers, idp->len);
+       silc_buffer_free(idp);
+
+       if (!silc_idcache_list_next(list, &id_cache))
+         break;
+      }
+    }
+
+    silc_idcache_list_free(list);
+  }
+}
+
+/* This function is used by router to announce existing servers to our
+   primary router when we've connected to it. */
+
+void silc_server_announce_servers(SilcServer server)
+{
+  SilcBuffer servers = NULL;
+
+  SILC_LOG_DEBUG(("Announcing servers"));
+
+  /* Get servers in local list */
+  silc_server_announce_get_servers(server, server->local_list, &servers);
+
+  /* Get servers in global list */
+  silc_server_announce_get_servers(server, server->global_list, &servers);
+
+  if (servers) {
+    silc_buffer_push(servers, servers->data - servers->head);
+    SILC_LOG_HEXDUMP(("servers"), servers->data, servers->len);
+
+    /* Send the packet */
+    silc_server_packet_send(server, server->router->connection,
+                           SILC_PACKET_NEW_ID_LIST, 0,
+                           servers->data, servers->len, TRUE);
+
+    silc_buffer_free(servers);
+  }
+}
+
+/* Returns assembled packet of all clients in the given ID list. The
+   packet's form is dictated by the New ID Payload. */
+
+static void silc_server_announce_get_clients(SilcServer server,
+                                            SilcIDList id_list,
+                                            SilcBuffer *clients)
+{
+  SilcIDCacheList list;
+  SilcIDCacheEntry id_cache;
+  SilcClientEntry client;
+  SilcBuffer idp;
+
+  /* Go through all clients in the list */
+  if (silc_idcache_find_by_id(id_list->clients, SILC_ID_CACHE_ANY, 
+                             SILC_ID_CLIENT, &list)) {
+    if (silc_idcache_list_first(list, &id_cache)) {
+      while (id_cache) {
+       client = (SilcClientEntry)id_cache->context;
+
+       idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+
+       *clients = silc_buffer_realloc(*clients, 
+                                      (*clients ? 
+                                       (*clients)->truelen + idp->len : 
+                                       idp->len));
+       silc_buffer_pull_tail(*clients, ((*clients)->end - (*clients)->data));
+       silc_buffer_put(*clients, idp->data, idp->len);
+       silc_buffer_pull(*clients, idp->len);
+       silc_buffer_free(idp);
+
+       if (!silc_idcache_list_next(list, &id_cache))
+         break;
+      }
+    }
+
+    silc_idcache_list_free(list);
+  }
+}
+
+/* This function is used to announce our existing clients to our router
+   when we've connected to it. */
+
+void silc_server_announce_clients(SilcServer server)
+{
+  SilcBuffer clients = NULL;
+
+  SILC_LOG_DEBUG(("Announcing clients"));
+
+  /* Get clients in local list */
+  silc_server_announce_get_clients(server, server->local_list,
+                                  &clients);
+
+  /* As router we announce our global list as well */
+  if (server->server_type == SILC_ROUTER)
+    silc_server_announce_get_clients(server, server->global_list,
+                                    &clients);
+
+  if (clients) {
+    silc_buffer_push(clients, clients->data - clients->head);
+    SILC_LOG_HEXDUMP(("clients"), clients->data, clients->len);
+
+    /* Send the packet */
+    silc_server_packet_send(server, server->router->connection,
+                           SILC_PACKET_NEW_ID_LIST, 0,
+                           clients->data, clients->len, TRUE);
+
+    silc_buffer_free(clients);
+  }
+}
+
+/* Returns assembled packets for all channels and users on those channels
+   from the given ID List. The packets are in the form dictated by the
+   New Channel and New Channel User payloads. */
+
+static void silc_server_announce_get_channels(SilcServer server,
+                                             SilcIDList id_list,
+                                             SilcBuffer *channels,
+                                             SilcBuffer *channel_users)
+{
+  SilcIDCacheList list;
+  SilcIDCacheEntry id_cache;
+  SilcChannelEntry channel;
+  SilcChannelClientEntry chl;
+  unsigned char *cid;
+  unsigned short name_len;
+  int len;
+
+  /* Go through all channels in the list */
+  if (silc_idcache_find_by_id(id_list->channels, SILC_ID_CACHE_ANY, 
+                             SILC_ID_CHANNEL, &list)) {
+    if (silc_idcache_list_first(list, &id_cache)) {
+      while (id_cache) {
+       channel = (SilcChannelEntry)id_cache->context;
+       
+       cid = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+       name_len = strlen(channel->channel_name);
+
+       len = 4 + name_len + SILC_ID_CHANNEL_LEN;
+       *channels = 
+         silc_buffer_realloc(*channels, 
+                             (*channels ? (*channels)->truelen + len : len));
+       silc_buffer_pull_tail(*channels, 
+                             ((*channels)->end - (*channels)->data));
+       silc_buffer_format(*channels,
+                          SILC_STR_UI_SHORT(name_len),
+                          SILC_STR_UI_XNSTRING(channel->channel_name, 
+                                               name_len),
+                          SILC_STR_UI_SHORT(SILC_ID_CHANNEL_LEN),
+                          SILC_STR_UI_XNSTRING(cid, SILC_ID_CHANNEL_LEN),
+                          SILC_STR_END);
+       silc_buffer_pull(*channels, len);
+
+       /* Now find all users on the channel */
+       silc_list_start(channel->user_list);
+       while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+         unsigned char *clid;
+
+         clid = silc_id_id2str(chl->client->id, SILC_ID_CLIENT);
+         
+         len = 4 + SILC_ID_CHANNEL_LEN + SILC_ID_CLIENT_LEN;
+         *channel_users = 
+           silc_buffer_realloc(*channel_users, 
+                               (*channel_users ? 
+                                (*channel_users)->truelen + len : len));
+         silc_buffer_pull_tail(*channel_users, 
+                               ((*channel_users)->end - 
+                                (*channel_users)->data));
+         silc_buffer_format(*channel_users,
+                            SILC_STR_UI_SHORT(SILC_ID_CHANNEL_LEN),
+                            SILC_STR_UI_XNSTRING(cid, SILC_ID_CHANNEL_LEN),
+                            SILC_STR_UI_SHORT(SILC_ID_CLIENT_LEN),
+                            SILC_STR_UI_XNSTRING(clid, SILC_ID_CLIENT_LEN),
+                            SILC_STR_END);
+         silc_buffer_pull(*channel_users, len);
+         silc_free(clid);
+       }
+
+       silc_free(cid);
+
+       if (!silc_idcache_list_next(list, &id_cache))
+         break;
+      }
+    }
+
+    silc_idcache_list_free(list);
+  }
+}
+
+/* This function is used to announce our existing channels to our router
+   when we've connected to it. This also announces the users on the
+   channels to the router. */
+
+void silc_server_announce_channels(SilcServer server)
+{
+  SilcBuffer channels = NULL, channel_users = NULL;
+
+  SILC_LOG_DEBUG(("Announcing channels and channel users"));
+
+  /* Get channels and channel users in local list */
+  silc_server_announce_get_channels(server, server->local_list,
+                                   &channels, &channel_users);
+
+  /* Get channels and channel users in global list */
+  silc_server_announce_get_channels(server, server->global_list,
+                                   &channels, &channel_users);
+
+  if (channels) {
+    silc_buffer_push(channels, channels->data - channels->head);
+    SILC_LOG_HEXDUMP(("channels"), channels->data, channels->len);
+
+    /* Send the packet */
+    silc_server_packet_send(server, server->router->connection,
+                           SILC_PACKET_NEW_CHANNEL_LIST, 0,
+                           channels->data, channels->len,
+                           FALSE);
+
+    silc_buffer_free(channels);
+  }
+
+  if (channel_users) {
+    silc_buffer_push(channel_users, channel_users->data - channel_users->head);
+    SILC_LOG_HEXDUMP(("channel users"), channel_users->data, 
+                    channel_users->len);
+
+    /* Send the packet */
+    silc_server_packet_send(server, server->router->connection,
+                           SILC_PACKET_NEW_CHANNEL_USER_LIST, 0,
+                           channel_users->data, channel_users->len,
+                           FALSE);
+
+    silc_buffer_free(channel_users);
+  }
+}
index 3a041fc63712446b7fefef3ef5bc7cb23d70b380..f8b7c6f779d0f12923a3504adebffe30e827a2c9 100644 (file)
@@ -111,6 +111,11 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
                                                SilcServerID *router_id,
                                                char *cipher, 
                                                char *channel_name);
+SilcChannelEntry 
+silc_server_create_new_channel_with_id(SilcServer server, 
+                                      char *cipher, 
+                                      char *channel_name,
+                                      SilcChannelID *channel_id);
 void silc_server_create_channel_key(SilcServer server, 
                                    SilcChannelEntry channel,
                                    unsigned int key_len);
@@ -119,5 +124,8 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
                                              SilcChannelEntry channel);
 void silc_server_perform_heartbeat(SilcSocketConnection sock,
                                   void *hb_context);
+void silc_server_announce_servers(SilcServer server);
+void silc_server_announce_clients(SilcServer server);
+void silc_server_announce_channels(SilcServer server);
 
 #endif
index 110daec46c99e9e2e1dc932d60bde7a4c7aed475..708dfe16c63404ff5a45d1ed6caaf0c7e070450b 100644 (file)
@@ -105,6 +105,7 @@ Table of Contents
       2.3.25 Remove ID Payload .................................. 37
       2.3.26 Remove Channel User Payload ........................ 38
       2.3.27 Set Mode Payload ................................... XXX
+      2.3.28 Set Mode List Payload .............................. XXX
   2.4 SILC ID Types ............................................. 39
   2.5 Packet Encryption And Decryption .......................... 39
       2.5.1 Normal Packet Encryption And Decryption ............. 39
@@ -766,7 +767,17 @@ List of SILC Packet types are defined as follows.
           Payload of the packet:  See section 2.3.27 Set Mode Payload
 
 
-     32   SILC_PACKET_HEARTBEAT
+     32   SILC_PACKET_SET_MODE_LIST
+
+          This packet is used to distribute list of Set Mode payloads
+          from server to routers.  This is equivalent to the packet
+          SILC_PACKET_SET_MODE except that it may include several
+          payloads.  Client must not send this packet.
+
+          Payload of the packet:  See section 2.3.28 Set Mode List
+                                  Payload
+
+     33   SILC_PACKET_HEARTBEAT
 
           This packet is used by clients, servers and routers to keep the
           connection alive.  It is recommended that all servers implement
@@ -774,7 +785,7 @@ List of SILC Packet types are defined as follows.
           This packet does not have a payload.
 
 
-     33 - 199
+     34 - 199
 
          Currently undefined commands.
 
@@ -1200,7 +1211,7 @@ ID's sent in arguments are sent inside ID Payload.
       only to the clients who is joined on the channel where the target 
       client is on.
 
-      Max Arguments: 3
+      Max Arguments:  3
           Arguments:  (1) <Client ID>  (2) <mode mask>
                       (3) <Target Client ID>
 
@@ -1217,6 +1228,21 @@ ID's sent in arguments are sent inside ID Payload.
           Arguments:  (1) <motd>
 
       The <motd> is the Message of the Day.
+
+
+10    SILC_NOTIFY_TYPE_CHANNEL_CHANGE
+
+      Sent when channel's ID has changed for a reason or another.  This 
+      is sent by noral server to the client.  Client must change the 
+      old Channel ID to the new one.  This type must be sent only to the
+      clients who is joined on the channel.
+
+      Max Arguments:  2
+          Arguments:  (1) <Old Channel ID>  (2) <New Channel ID>
+
+      The <Old Channel ID> is the channel's old ID and the <New Channel ID>
+      is the new one that must replace the old one.
+
 .in 3
 
 Notify types starting from 16384 are reserved for private notify
@@ -1992,7 +2018,7 @@ o Client ID (variable length) - The Client ID of the client
 2.3.22 New Channel List Payload
 
 This payload is used to distribute list of new channels from server
-to routers.  It might convenient to send list of new channels when
+to routers.  It might be convenient to send list of new channels when
 existing server connects to router, instead of sending them one
 by one.
 
@@ -2010,14 +2036,14 @@ packet.  They must not be sent in any other packet type.
 .ti 0
 2.3.23 New Channel User List Payload
 
-This payload is used to distribute list of channel users on specific
-channel from server to routers.  It might convenient to send list of
-channel users when existing server connects to router, instead of
-sending them one by one.
+This payload is used to distribute list of channel users on a channel
+from server to routers.  It might convenient to send list of channel
+users when existing server connects to router, instead of sending them
+one by one.  One list may include users for several different channels.
 
 There is no specific payload for this packet type.  The packet type
 uses same payload as described in 2.3.20 New Channel User Payload.
-To form a list several payloads is put in the packet each after each.
+To form a list several payloads is put in the packet one after another.
 The payload is variable in length but can be calculated by calculating
 the length of the fields together.  This forms one New Channel User
 Payload in the list.
@@ -2235,6 +2261,26 @@ o Argument Nums (2 bytes) - Indicates the number of Argument
 .in 3
 
 
+.ti 0
+2.3.28 Set Mode List Payload
+
+This paylaod is used to distribute list of Set Mode payloads inside
+one packet.  When server announces channels and client's on those 
+channels to its primary router when it connects to it, it is convenient
+to send list of Set Mode payloads to set the modes for the channel
+and clients on those channel.  One list may include several mode
+types.
+
+There is no specific payload for this packet type.  The packet type
+uses same payload as described in 2.3.27 Set Mode Payload.  To form a
+list several payloads are put in the packet one after another.  The
+payload is variable in length but can be calculated by calculating the
+length of the fields together.  This forms one Set Mode payload in the
+list.
+
+The list of payloads may only be sent with packet SILC_PACKET_SET_MODE_LIST.
+They must not be sent in any other packet type.
+
 
 .ti 0
 2.4 SILC ID Types
index fd17296d46772b06367d5b1ad416904939e35c3f..c19f206ebe43d92ba80f6b68397c5acfb08e92d8 100644 (file)
@@ -1605,6 +1605,7 @@ void silc_client_notify_by_server(SilcClient client,
                                  silc_client_notify_by_server_pending, p);
       goto out;
     }
+    silc_free(client_id);
 
     /* Get old Client ID */
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
@@ -1775,6 +1776,45 @@ void silc_client_notify_by_server(SilcClient client,
     /* Notify application */
     client->ops->notify(client, conn, type, tmp);
     break;
+
+  case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
+    /*
+     * Router has enforced a new ID to a channel. Let's change the old
+     * ID to the one provided here.
+     */
+
+    /* Get the old ID */
+    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+    if (!tmp)
+      goto out;
+    channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+    if (!channel_id)
+      goto out;
+    
+    /* Get the channel entry */
+    if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+                                    SILC_ID_CHANNEL, &id_cache))
+      break;
+
+    channel = (SilcChannelEntry)id_cache->context;
+
+    /* Free the old ID */
+    silc_free(channel_id);
+    silc_free(channel->id);
+
+    /* Get the new ID */
+    tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+    if (!tmp)
+      goto out;
+    channel->id = silc_id_payload_parse_id(tmp, tmp_len);
+    if (!channel->id)
+      goto out;
+
+    id_cache->id = (void *)channel->id;
+
+    /* Notify application */
+    client->ops->notify(client, conn, type, channel, channel);
+    break;
     
   default:
     break;
index abd89e0d0b81fd12440c41b71271df813d0d2a4d..2cb84f00e730f3db0a89bb6ae802d0b17228dbe6 100644 (file)
@@ -100,6 +100,10 @@ typedef struct {
 #define SILC_ID_SERVER_COMPARE(id1, id2) \
   SILC_ID_COMPARE(id1, id2, SILC_ID_SERVER_LEN)
 
+/* Compares Channel ID's */
+#define SILC_ID_CHANNEL_COMPARE(id1, id2) \
+  SILC_ID_COMPARE(id1, id2, SILC_ID_CHANNEL_LEN)
+
 /* Compares IP addresses from the ID's. */
 #define SILC_ID_COMPARE_IP(id1, id2) \
   SILC_ID_COMPARE(id1, id2, 4)
index 3362d7fc3df95464014de1df8ccd580f20bfffb4..3c85ed2a3a4a90244fda86eda37c60454c1d3684 100644 (file)
@@ -40,6 +40,7 @@ typedef unsigned short SilcNotifyType;
 #define SILC_NOTIFY_TYPE_CMODE_CHANGE    7 /* "has changed channel mode" */
 #define SILC_NOTIFY_TYPE_CUMODE_CHANGE   8 /* "has change mode" */
 #define SILC_NOTIFY_TYPE_MOTD            9 /* message of the day */
+#define SILC_NOTIFY_TYPE_CHANNEL_CHANGE  10 /* Channel's ID has changed */
 
 /* Prototypes */
 SilcNotifyPayload silc_notify_payload_parse(SilcBuffer buffer);
index 1a22736e95e9ca9a31741b728fcfc50f5ae155f5..17edad0237dccf60a4e5b03593e32f7dba0fcb1d 100644 (file)
@@ -223,7 +223,8 @@ typedef void (*SilcPacketParserCallback)(SilcPacketParserContext
 #define SILC_PACKET_REKEY                29
 #define SILC_PACKET_REKEY_DONE           30
 #define SILC_PACKET_SET_MODE             31      /* Set mode */
-#define SILC_PACKET_HEARTBEAT            32      /* Heartbeat */
+#define SILC_PACKET_SET_MODE_LIST        32      /* List of Set Mode's */
+#define SILC_PACKET_HEARTBEAT            33      /* Heartbeat */
 /* #define SILC_PACKET_MAX               255 */
 
 /* Macros */
index 6b41270aad5536d2881eaa33e4c4963dff4dac86..9bd0cd6e264454410aa1abddbd6b4c4a5f14cf19 100644 (file)
@@ -79,6 +79,9 @@ SilcBuffer silc_buffer_realloc(SilcBuffer sb, unsigned int newsize)
 {
   SilcBuffer sb_new;
 
+  if (!sb)
+    return silc_buffer_alloc(newsize);
+
   sb_new = silc_buffer_alloc(newsize);
   silc_buffer_pull_tail(sb_new, SILC_BUFFER_END(sb_new));
   silc_buffer_put(sb_new, sb->head, sb->truelen);