updates
[silc.git] / apps / silcd / packet_send.c
index 3b72d89a77679f52819af78be81954aa71f7651d..41d5c22cf193cb251d0237041180ef2477212032 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
@@ -319,7 +346,7 @@ silc_server_packet_send_to_channel_real(SilcServer server,
    the channel. Usually this is used to send notify messages to the
    channel, things like notify about new user joining to the channel. 
    If `route' is FALSE then the packet is sent only locally and will not
-   be routed anywhere. */
+   be routed anywhere (for router locally means cell wide). */
 
 void silc_server_packet_send_to_channel(SilcServer server,
                                        SilcChannelEntry channel,
@@ -381,9 +408,10 @@ void silc_server_packet_send_to_channel(SilcServer server,
     client = chl->client;
 
     /* If client has router set it is not locally connected client and
-       we will route the message to the router set in the client. */
-    if (route && client && client->router && 
-       server->server_type == SILC_ROUTER) {
+       we will route the message to the router set in the client. Though,
+       send locally connected server in all cases. */
+    if (server->server_type == SILC_ROUTER && client && client->router && 
+       ((!route && client->router->router == server->id_entry) || route)) {
       int k;
 
       /* Check if we have sent the packet to this route already */
@@ -559,8 +587,8 @@ void silc_server_packet_relay_to_channel(SilcServer server,
       sock = (SilcSocketConnection)client->connection;
       idata = (SilcIDListData)client;
 
-      SILC_LOG_DEBUG(("Sending packet to client %s", 
-                     sock->hostname ? sock->hostname : sock->ip));
+      SILC_LOG_DEBUG(("Sending packet to client %s (%s)", 
+                     sock->hostname, sock->ip));
 
       /* Send the packet */
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
@@ -589,7 +617,6 @@ void silc_server_packet_send_local_channel(SilcServer server,
                                           unsigned int data_len,
                                           int force_send)
 {
-  SilcClientEntry client;
   SilcChannelClientEntry chl;
   SilcSocketConnection sock = NULL;
 
@@ -598,13 +625,11 @@ void silc_server_packet_send_local_channel(SilcServer server,
   /* Send the message to clients on the channel's client list. */
   silc_list_start(channel->user_list);
   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
-    client = chl->client;
-
-    if (client) {
-      sock = (SilcSocketConnection)client->connection;
+    if (chl->client) {
+      sock = (SilcSocketConnection)chl->client->connection;
 
       /* Send the packet to the client */
-      silc_server_packet_send_dest(server, sock, type, flags, client->id,
+      silc_server_packet_send_dest(server, sock, type, flags, chl->client->id,
                                   SILC_ID_CLIENT, data, data_len,
                                   force_send);
     }
@@ -1087,3 +1112,77 @@ void silc_server_send_new_channel_user(SilcServer server,
   silc_free(chid);
   silc_buffer_free(packet);
 }
+
+/* Send Channel Key payload to distribute the new channel key. Normal server
+   sends this to router when new client joins to existing channel. Router
+   sends this to the local server who forwarded join command in case where
+   the channel did not exist yet.  Both normal and router servers uses this
+   also to send this to locally connected clients on the channel. This
+   must not be broadcasted packet. */
+
+void silc_server_send_channel_key(SilcServer server,
+                                 SilcChannelEntry channel,
+                                 unsigned char route)
+{
+  SilcBuffer packet;
+  unsigned char *chid;
+  unsigned int tmp_len;
+  SILC_LOG_DEBUG(("Start"));
+  chid = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+  if (!chid)
+    return;
+  /* Encode channel key packet */
+  tmp_len = strlen(channel->channel_key->cipher->name);
+  packet = silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN, chid, tmp_len,
+                                           channel->channel_key->cipher->name,
+                                           channel->key_len / 8, channel->key);
+  silc_server_packet_send_to_channel(server, channel, SILC_PACKET_CHANNEL_KEY,
+                                     route, packet->data, packet->len, FALSE);
+  silc_buffer_free(packet);
+  silc_free(chid);
+}
+
+/* Generic function to send any command. The arguments must be sent already
+   encoded into correct form in correct order. */
+
+void silc_server_send_command(SilcServer server, 
+                             SilcSocketConnection sock,
+                             SilcCommand command, 
+                             unsigned int argc, ...)
+{
+  SilcBuffer packet;
+  va_list ap;
+
+  va_start(ap, argc);
+
+  packet = silc_command_payload_encode_vap(command, 0, argc, ap);
+  silc_server_packet_send(server, sock, SILC_PACKET_COMMAND, 0,
+                         packet->data, packet->len, TRUE);
+  silc_buffer_free(packet);
+}
+
+/* Function used to send REMOVE_ID packet. The packet is used to notify
+   routers that certain ID should be removed. After that the ID will become
+   invalid.  If the argument `broadcast' is TRUE then the packet is sent as
+   broadcast packet. */
+
+void silc_server_send_remove_id(SilcServer server,
+                               SilcSocketConnection sock,
+                               int broadcast,
+                               void *id, unsigned int id_len,
+                               SilcIdType id_type)
+{
+  SilcBuffer idp;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  idp = silc_id_payload_encode(id, id_type);
+  silc_server_packet_send(server, sock, SILC_PACKET_REMOVE_ID, 
+                         broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, 
+                         idp->data, idp->len, FALSE);
+  silc_buffer_free(idp);
+}