updates.
[silc.git] / apps / silcd / server.c
index f7918f7d4458ff2c71c1fc1738f47731ffea472c..46900b2fd7ef08b37aaef5980be4658389c0e8a8 100644 (file)
@@ -181,8 +181,12 @@ int silc_server_init(SilcServer server)
 
     tmp = silc_net_create_server(server->config->listen_port->port,
                                 server->config->listen_port->listener_ip);
-    if (tmp < 0)
+    if (tmp < 0) {
+      SILC_LOG_ERROR(("Could not create server listener: %s on %d",
+                     server->config->listen_port->listener_ip,
+                     server->config->listen_port->port));
       goto err0;
+    }
 
     sock = silc_realloc(sock, (sizeof(int *) * (sock_count + 1)));
     sock[sock_count] = tmp;
@@ -1271,8 +1275,6 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       silc_ske_free(ctx->ske);
     silc_free(ctx->dest_id);
     silc_free(ctx);
-    if (sock)
-      sock->protocol = NULL;
     silc_schedule_task_del_by_callback(server->schedule,
                                       silc_server_failure_callback);
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
@@ -1505,11 +1507,11 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
 
     if (ret == -1)
       SILC_LOG_ERROR(("Error receiving packet from connection "
-                     "%s:%d [%s]", sock->hostname, sock->port,  
+                     "%s:%d [%s] %s", sock->hostname, sock->port,  
                      (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
                       sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
                       sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
-                      "Router")));
+                      "Router"), strerror(errno)));
     return;
   }    
 
@@ -1650,7 +1652,7 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real)
 /* Parser callback called by silc_packet_receive_process. This merely
    registers timeout that will handle the actual parsing when appropriate. */
 
-void silc_server_packet_parse(SilcPacketParserContext *parser_context,
+bool silc_server_packet_parse(SilcPacketParserContext *parser_context,
                              void *context)
 {
   SilcServer server = (SilcServer)context;
@@ -1660,6 +1662,31 @@ void silc_server_packet_parse(SilcPacketParserContext *parser_context,
   if (idata)
     idata->psn_receive = parser_context->packet->sequence + 1;
 
+  /* If protocol for this connection is key exchange or rekey then we'll
+     process all packets synchronously, since there might be packets in
+     queue that we are not able to decrypt without first processing the
+     packets before them. */
+  if (sock->protocol && sock->protocol->protocol && 
+      (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE ||
+       sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY)) {
+    silc_server_packet_parse_real(server->schedule, 0, sock->sock,
+                                 parser_context);
+
+    /* Reprocess data since we'll return FALSE here.  This is because
+       the idata->receive_key might have become valid in the last packet
+       and we want to call this processor with valid cipher. */
+    if (idata)
+      silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ? 
+                                 TRUE : FALSE, idata->receive_key, 
+                                 idata->hmac_receive, idata->psn_receive, 
+                                 silc_server_packet_parse, server);
+    else
+      silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ? 
+                                 TRUE : FALSE, NULL, NULL, 0, 
+                                 silc_server_packet_parse, server);
+    return FALSE;
+  }
+
   switch (sock->type) {
   case SILC_SOCKET_TYPE_UNKNOWN:
   case SILC_SOCKET_TYPE_CLIENT:
@@ -1672,16 +1699,15 @@ void silc_server_packet_parse(SilcPacketParserContext *parser_context,
     break;
   case SILC_SOCKET_TYPE_SERVER:
   case SILC_SOCKET_TYPE_ROUTER:
-    /* Packets from servers are parsed as soon as possible */
-    silc_schedule_task_add(server->schedule, sock->sock,
-                          silc_server_packet_parse_real,
-                          (void *)parser_context, 0, 1,
-                          SILC_TASK_TIMEOUT,
-                          SILC_TASK_PRI_NORMAL);
+    /* Packets from servers are parsed immediately */
+    silc_server_packet_parse_real(server->schedule, 0, sock->sock,
+                                 parser_context);
     break;
   default:
-    return;
+    return TRUE;
   }
+
+  return TRUE;
 }
 
 /* Parses the packet type and calls what ever routines the packet type
@@ -2148,6 +2174,9 @@ SILC_TASK_CALLBACK(silc_server_close_connection_final)
 void silc_server_close_connection(SilcServer server,
                                  SilcSocketConnection sock)
 {
+  if (!server->sockets[sock->sock])
+    return;
+
   SILC_LOG_INFO(("Closing connection %s:%d [%s]", sock->hostname,
                   sock->port,
                   (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
@@ -2454,8 +2483,8 @@ void silc_server_remove_from_channels(SilcServer server,
        silc_schedule_task_del_by_context(server->schedule, channel->rekey);
       if (silc_idlist_del_channel(server->local_list, channel))
        server->stat.my_channels--;
-      else if (silc_idlist_del_channel(server->global_list, channel))
-       server->stat.my_channels--;
+      else 
+        silc_idlist_del_channel(server->global_list, channel);
       continue;
     }
 
@@ -2492,7 +2521,7 @@ void silc_server_remove_from_channels(SilcServer server,
        SilcChannelClientEntry chl2;
        SilcHashTableList htl2;
 
-       channel->id = NULL;
+       channel->disabled = TRUE;
 
        silc_hash_table_list(channel->user_list, &htl2);
        while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) {
@@ -2506,8 +2535,8 @@ void silc_server_remove_from_channels(SilcServer server,
       /* Remove the channel entry */
       if (silc_idlist_del_channel(server->local_list, channel))
        server->stat.my_channels--;
-      else if (silc_idlist_del_channel(server->global_list, channel))
-       server->stat.my_channels--;
+      else 
+        silc_idlist_del_channel(server->global_list, channel);
       continue;
     }
 
@@ -2574,8 +2603,8 @@ int silc_server_remove_from_one_channel(SilcServer server,
       silc_schedule_task_del_by_context(server->schedule, channel->rekey);
     if (silc_idlist_del_channel(server->local_list, channel))
       server->stat.my_channels--;
-    else if (silc_idlist_del_channel(server->global_list, channel))
-      server->stat.my_channels--;
+    else 
+      silc_idlist_del_channel(server->global_list, channel);
     silc_buffer_free(clidp);
     return FALSE;
   }
@@ -2612,7 +2641,7 @@ int silc_server_remove_from_one_channel(SilcServer server,
       SilcChannelClientEntry chl2;
       SilcHashTableList htl2;
       
-      channel->id = NULL;
+      channel->disabled = TRUE;
       
       silc_hash_table_list(channel->user_list, &htl2);
       while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) {
@@ -2626,8 +2655,8 @@ int silc_server_remove_from_one_channel(SilcServer server,
     /* Remove the channel entry */
     if (silc_idlist_del_channel(server->local_list, channel))
       server->stat.my_channels--;
-    else if (silc_idlist_del_channel(server->global_list, channel))
-      server->stat.my_channels--;
+    else 
+      silc_idlist_del_channel(server->global_list, channel);
     return FALSE;
   }
 
@@ -2848,8 +2877,10 @@ bool silc_server_create_channel_key(SilcServer server,
   }
 
   if (!channel->channel_key)
-    if (!silc_cipher_alloc(SILC_DEFAULT_CIPHER, &channel->channel_key))
+    if (!silc_cipher_alloc(SILC_DEFAULT_CIPHER, &channel->channel_key)) {
+      channel->channel_key = NULL;
       return FALSE;
+    }
 
   if (key_len)
     len = key_len;
@@ -2970,6 +3001,7 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
 
   /* Create new cipher */
   if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
+    channel->channel_key = NULL;
     channel = NULL;
     goto out;
   }
@@ -3345,7 +3377,7 @@ void silc_server_announce_get_channels(SilcServer server,
        (*channel_ids)[i] = NULL;
        silc_server_announce_get_channel_users(server, channel,
                                               channel_users,
-                                              channel_users_modes[i]);
+                                              &(*channel_users_modes)[i]);
        (*channel_ids)[i] = channel->id;
        i++;