More SILC Server 1.1 porting. Added HTTP statistics access.
authorPekka Riikonen <priikone@silcnet.org>
Sat, 28 Apr 2007 15:10:28 +0000 (15:10 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sat, 28 Apr 2007 15:10:28 +0000 (15:10 +0000)
15 files changed:
apps/silcd/Makefile.am
apps/silcd/command.c
apps/silcd/command_reply.c
apps/silcd/idlist.c
apps/silcd/idlist.h
apps/silcd/packet_receive.c
apps/silcd/server.c
apps/silcd/server.h
apps/silcd/server_http.c [new file with mode: 0644]
apps/silcd/server_internal.h
apps/silcd/server_query.c
apps/silcd/server_util.c
apps/silcd/serverconfig.c
apps/silcd/serverconfig.h
apps/silcd/silcd.c

index 6dcf4b979f7846498f3877d819dab4d7b9487c79..b15b1d4ad74b9902092e4ad99f44d812bc07c77a 100644 (file)
@@ -33,7 +33,8 @@ silcd_SOURCES = \
        command.c \
        command_reply.c \
        server_util.c \
-       server_backup.c
+       server_backup.c \
+       server_http.c
 
 LIBS = $(SILC_COMMON_LIBS)
 LDADD =
index 12acc29cc35349c321f596fe58061cb9e86fd01e..f5c3824fa0fede2c7f7405a0d4e7427a1fcad8d7 100644 (file)
@@ -4592,11 +4592,13 @@ SILC_SERVER_CMD_FUNC(ban)
                       SILC_STR_END);
     silc_hash_table_list(channel->ban_list, &htl);
     while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2))
-      list = silc_argument_payload_encode_one(list, tmp2->data, silc_buffer_len(tmp2),
-                                             type);
+      list = silc_argument_payload_encode_one(list, tmp2->data,
+                                             silc_buffer_len(tmp2), type);
     silc_hash_table_list_reset(&htl);
   }
 
+  tmp_id = silc_argument_get_arg_type(cmd->args, 1, &id_len);
+
   /* Send BAN notify type to local servers (but not clients) and to
      network. */
   if (atype && tmp && len2) {
@@ -4606,7 +4608,7 @@ SILC_SERVER_CMD_FUNC(ban)
     if (server->server_type == SILC_ROUTER)
       silc_server_send_notify_to_channel(server, NULL, channel, FALSE, FALSE,
                                          SILC_NOTIFY_TYPE_BAN, 3,
-                                        id, id_len,
+                                        tmp_id, id_len,
                                         atype, 1,
                                         tmp ? blist.data : NULL,
                                         tmp ? silc_buffer_len(&blist) : 0);
@@ -4620,7 +4622,7 @@ SILC_SERVER_CMD_FUNC(ban)
   /* Send the reply back to the client */
   silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_BAN,
                                 SILC_STATUS_OK, 0, ident, 2,
-                                2, id, id_len,
+                                2, tmp_id, id_len,
                                 3, list ? list->data : NULL,
                                 list ? silc_buffer_len(list) : 0);
   silc_buffer_free(list);
index d2d8ec3cb8cbba90e877a618d7ca5cf9323c84e6..e6858ae43e0fca5192173ab51f14ecf23803a750 100644 (file)
@@ -150,11 +150,6 @@ silc_server_command_process_error(SilcServerCommandReplyContext cmd,
       if (!client)
        return;
 
-      if (client->data.public_key)
-       silc_hash_table_del_by_context(server->pk_hash,
-                                      client->data.public_key,
-                                      client);
-
       silc_server_remove_from_channels(server, NULL, client, TRUE,
                                       NULL, TRUE, FALSE);
       silc_idlist_del_data(client);
@@ -360,12 +355,12 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
 
            SILC_LOG_DEBUG(("Saved client public key from attributes"));
 
-           /* Add to public key hash table */
-           if (!silc_hash_table_find_by_context(server->pk_hash,
-                                                client->data.public_key,
-                                                client, NULL))
-             silc_hash_table_add(server->pk_hash,
-                                 client->data.public_key, client);
+           /* Add client's public key to repository */
+           if (!silc_server_get_public_key_by_client(server, client, NULL))
+             silc_skr_add_public_key_simple(server->repository,
+                                            client->data.public_key,
+                                            SILC_SKR_USAGE_IDENTIFICATION,
+                                            client, NULL);
 
            silc_free(pk.type);
            silc_free(pk.data);
@@ -551,6 +546,15 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
                     client);
   }
 
+  /* If client is global and is not on any channel then add that we'll
+     expire the entry after a while. */
+  if (global) {
+    silc_idlist_find_client_by_id(server->global_list, client->id,
+                                 FALSE, &cache);
+    if (!silc_hash_table_count(client->channels))
+      silc_dlist_add(server->expired_clients, client);
+  }
+
   return TRUE;
 }
 
@@ -1383,10 +1387,12 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey)
     }
 
     if (!client->data.public_key) {
-      if (!silc_hash_table_find_by_context(server->pk_hash, public_key,
-                                          client, NULL))
-       silc_hash_table_add(server->pk_hash, public_key, client);
-
+      /* Add client's public key to repository */
+      if (!silc_server_get_public_key_by_client(server, client, NULL))
+       silc_skr_add_public_key_simple(server->repository,
+                                      public_key,
+                                      SILC_SKR_USAGE_IDENTIFICATION,
+                                      client, NULL);
       client->data.public_key = public_key;
       public_key = NULL;
     }
index 24aa5934411da2e56c5b6c00e03b00a9e5f2178c..8088150e8c1ee1e880ee5ff9d9f9fa4e434d2400 100644 (file)
@@ -162,7 +162,8 @@ silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
 
 SilcServerEntry
 silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
-                               SilcBool registered, SilcIDCacheEntry *ret_entry)
+                               SilcBool registered,
+                               SilcIDCacheEntry *ret_entry)
 {
   SilcIDCacheEntry id_cache = NULL;
   SilcServerEntry server;
@@ -295,6 +296,16 @@ int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
   return FALSE;
 }
 
+/* ID Cache destructor */
+
+void silc_idlist_server_destructor(SilcIDCache cache,
+                                  SilcIDCacheEntry entry,
+                                  void *dest_context,
+                                  void *app_context)
+{
+  silc_free(entry->name);
+}
+
 /******************************************************************************
 
                           Client entry functions
@@ -390,15 +401,15 @@ void silc_idlist_client_destructor(SilcIDCache cache,
                                   void *dest_context,
                                   void *app_context)
 {
-  SilcServer server = app_context;
+  SilcServer server = dest_context;
   SilcClientEntry client;
 
   client = (SilcClientEntry)entry->context;
   if (client) {
-    /* Remove this client from the public key hash list */
+    /* Remove client's public key from repository, this will free it too. */
     if (client->data.public_key)
-      silc_hash_table_del_by_context(server->pk_hash,
-                                    client->data.public_key, client);
+      silc_skr_del_public_key(server->repository, client->data.public_key,
+                             client);
 
     assert(!silc_hash_table_count(client->channels));
     silc_free(client->nickname);
@@ -407,8 +418,6 @@ void silc_idlist_client_destructor(SilcIDCache cache,
     silc_free(client->userinfo);
     silc_free(client->id);
     silc_free(client->attrs);
-    if (client->data.public_key)
-      silc_pkcs_public_key_free(client->data.public_key);
     silc_hash_table_free(client->channels);
 
     memset(client, 'A', sizeof(*client));
@@ -625,7 +634,7 @@ silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
                                             NULL, NULL, NULL, TRUE);
 
   if (!silc_idcache_add(id_list->channels, channel_namec,
-                       (void *)channel->id, (void *)channel /*XXX, expire */)) {
+                       (void *)channel->id, (void *)channel)) {
     silc_hmac_free(channel->hmac);
     silc_hash_table_free(channel->user_list);
     silc_free(channel);
@@ -636,6 +645,16 @@ silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
   return channel;
 }
 
+/* ID Cache destructor */
+
+void silc_idlist_channel_destructor(SilcIDCache cache,
+                                   SilcIDCacheEntry entry,
+                                   void *dest_context,
+                                   void *app_context)
+{
+  silc_free(entry->name);
+}
+
 /* Foreach callbcak to free all users from the channel when deleting a
    channel entry. */
 
index e6d1ce47514c0851fedb143cd210ee7524d94397..fe9f6ced5adf9716128240b10c3aa47b8033ce44 100644 (file)
@@ -575,6 +575,10 @@ SilcServerEntry
 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
                              SilcServerID *new_id);
 int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry);
+void silc_idlist_server_destructor(SilcIDCache cache,
+                                  SilcIDCacheEntry entry,
+                                  void *dest_context,
+                                  void *app_context);
 SilcClientEntry
 silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
                       char *userinfo, SilcClientID *id,
@@ -604,6 +608,10 @@ silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
                        SilcChannelID *id, SilcServerEntry router,
                        SilcCipher send_key, SilcCipher receive_key,
                        SilcHmac hmac);
+void silc_idlist_channel_destructor(SilcIDCache cache,
+                                   SilcIDCacheEntry entry,
+                                   void *dest_context,
+                                   void *app_context);
 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry);
 SilcChannelEntry
 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
index c6ec4501980cc43f3b725f9b72b6bc7777343d44..f17e28546da22623d727fbc1ee90826b65544281 100644 (file)
@@ -316,10 +316,12 @@ static void silc_server_notify_process(SilcServer server,
     SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
     silc_schedule_task_del_by_context(server->schedule, client);
 
-    /* Remove from public key hash table. */
-    if (client->data.public_key)
-      silc_hash_table_del_by_context(server->pk_hash, client->data.public_key,
-                                     client);
+    /* Remove client's public key from repository, this will free it too. */
+    if (client->data.public_key) {
+      silc_skr_del_public_key(server->repository, client->data.public_key,
+                             client);
+      client->data.public_key = NULL;
+    }
 
     /* Remove the client from all channels. */
     silc_server_remove_from_channels(server, NULL, client, TRUE,
@@ -337,6 +339,7 @@ static void silc_server_notify_process(SilcServer server,
     client->mode = 0;
     client->router = NULL;
     client->connection = NULL;
+    silc_dlist_add(server->expired_clients, client);
     break;
 
   case SILC_NOTIFY_TYPE_TOPIC_SET:
@@ -1237,12 +1240,6 @@ static void silc_server_notify_process(SilcServer server,
            if (local)
              silc_server_del_from_watcher_list(server, client);
 
-           /* Remove from public key hash table. */
-           if (client->data.public_key)
-             silc_hash_table_del_by_context(server->pk_hash,
-                                             client->data.public_key,
-                                             client);
-
            /* Remove the client */
            silc_idlist_del_data(client);
            silc_idlist_del_client(local ? server->local_list :
@@ -1459,11 +1456,12 @@ static void silc_server_notify_process(SilcServer server,
        silc_server_check_watcher_list(server, client, NULL,
                                       SILC_NOTIFY_TYPE_KILLED);
 
-      /* Remove from public key hash table. */
-      if (client->data.public_key)
-       silc_hash_table_del_by_context(server->pk_hash,
-                                      client->data.public_key,
-                                      client);
+      /* Remove client's public key from repository, this will free it too. */
+      if (client->data.public_key) {
+       silc_skr_del_public_key(server->repository, client->data.public_key,
+                               client);
+       client->data.public_key = NULL;
+      }
 
       /* Update statistics */
       server->stat.clients--;
@@ -1483,6 +1481,7 @@ static void silc_server_notify_process(SilcServer server,
       client->mode = 0;
       client->router = NULL;
       client->connection = NULL;
+      silc_dlist_add(server->expired_clients, client);
       break;
     }
 
@@ -1639,11 +1638,6 @@ static void silc_server_notify_process(SilcServer server,
        if (!client)
          goto out;
 
-       if (client->data.public_key)
-         silc_hash_table_del_by_context(server->pk_hash,
-                                        client->data.public_key,
-                                        client);
-
        silc_server_remove_from_channels(server, NULL, client, TRUE,
                                         NULL, TRUE, FALSE);
        silc_idlist_del_data(client);
@@ -1891,7 +1885,6 @@ void silc_server_channel_message(SilcServer server,
   SilcChannelID id;
   SilcClientID cid;
   SilcID sid;
-  void *sender_id = NULL;
   SilcClientEntry sender_entry = NULL;
   SilcIDListData idata;
   SilcChannelClientEntry chl;
@@ -1998,9 +1991,9 @@ void silc_server_channel_message(SilcServer server,
 
   /* Distribute the packet to our local clients. This will send the
      packet for further routing as well, if needed. */
-  silc_server_packet_relay_to_channel(server, sock, channel, sender_id,
-                                     packet->src_id_type, sender_entry,
-                                     packet->buffer.data,
+  silc_server_packet_relay_to_channel(server, sock, channel,
+                                     SILC_ID_GET_ID(sid), sid.type,
+                                     sender_entry, packet->buffer.data,
                                      silc_buffer_len(&packet->buffer));
 
  out:
@@ -2123,12 +2116,30 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     username[username_len - 1] = '\0';
   }
 
+  /* Take nickname from NEW_CLIENT packet, if present */
+  if (silc_buffer_unformat(buffer,
+                          SILC_STR_UI16_NSTRING_ALLOC(&nickname,
+                                                      &nickname_len),
+                          SILC_STR_END)) {
+    if (nickname_len > 128) {
+      nickname_len = 128;
+      nickname[nickname_len - 1] = '\0';
+    }
+  }
+
+  /* Nickname is initially same as username, if not present in NEW_CLIENT */
+  if (!nickname) {
+    nickname = strdup(username);
+    nickname_len = strlen(nickname);
+  }
+
   /* Check for valid username string */
-  nicknamec = silc_identifier_check(username, username_len,
+  nicknamec = silc_identifier_check(nickname, nickname_len,
                                    SILC_STRING_UTF8, 128, &tmp_len);
   if (!nicknamec) {
     silc_free(username);
     silc_free(realname);
+    silc_free(nickname);
     SILC_LOG_ERROR(("Client %s (%s) sent bad username string '%s', closing "
                    "connection", hostname, ip, username));
     silc_server_disconnect_remote(server, sock,
@@ -2139,21 +2150,6 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     return NULL;
   }
 
-  /* Take nickname from NEW_CLIENT packet, if present */
-  if (silc_buffer_unformat(buffer,
-                          SILC_STR_UI16_NSTRING_ALLOC(&nickname,
-                                                      &nickname_len),
-                          SILC_STR_END)) {
-    if (nickname_len > 128) {
-      nickname_len = 128;
-      nickname[nickname_len - 1] = '\0';
-    }
-  }
-
-  /* Nickname is initially same as username, if not present in NEW_CLIENT */
-  if (!nickname)
-    nickname = strdup(username);
-
   /* Make sanity checks for the hostname of the client. If the hostname
      is provided in the `username' check that it is the same than the
      resolved hostname, or if not resolved the hostname that appears in
@@ -2167,6 +2163,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     host = silc_memdup(username + tlen + 1, strlen(username) - tlen - 1);
 
     if (strcmp(hostname, ip) && strcmp(hostname, host)) {
+      silc_free(nickname);
       silc_free(username);
       silc_free(host);
       silc_free(realname);
@@ -2184,6 +2181,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
                                        client->data.public_key);
     phostname = strdup(silc_pubkey->identifier.host);
     if (!strcmp(hostname, ip) && phostname && strcmp(phostname, host)) {
+      silc_free(nickname);
       silc_free(username);
       silc_free(host);
       silc_free(phostname);
@@ -2659,19 +2657,20 @@ static void silc_server_new_id_real(SilcServer server,
        silc_server_check_watcher_list(server, entry, NULL, 0);
 
       if (server->server_type == SILC_ROUTER) {
-       /* Add the client's public key to hash table or get the key with
+       /* Add the client's public key to repository or get the key with
           GETKEY command. */
         if (entry->data.public_key) {
-         if (!silc_hash_table_find_by_context(server->pk_hash,
-                                              entry->data.public_key,
-                                              entry, NULL))
-           silc_hash_table_add(server->pk_hash, entry->data.public_key,
-                               entry);
-       } else
+         if (!silc_server_get_public_key_by_client(server, entry, NULL))
+           silc_skr_add_public_key_simple(server->repository,
+                                          entry->data.public_key,
+                                          SILC_SKR_USAGE_IDENTIFICATION,
+                                          entry, NULL);
+       } else {
          silc_server_send_command(server, router_sock,
                                   SILC_COMMAND_GETKEY, ++server->cmd_ident,
                                   1, 1, buffer->data,
                                   silc_buffer_len(buffer));
+       }
       }
     }
     break;
@@ -3401,6 +3400,7 @@ void silc_server_resume_client(SilcServer server,
   SilcHashTableList htl;
   SilcChannelClientEntry chl;
   SilcServerResumeResolve r;
+  SilcPublicKey public_key;
   const char *cipher, *hostname, *ip;
 
   silc_socket_stream_get_info(silc_packet_stream_get_stream(sock),
@@ -3647,21 +3647,34 @@ void silc_server_resume_client(SilcServer server,
     silc_packet_set_context(sock, detached_client);
     detached_client->connection = sock;
 
-    if (detached_client->data.public_key)
-      silc_hash_table_del_by_context(server->pk_hash,
-                                    detached_client->data.public_key,
-                                    detached_client);
-    if (idata->public_key)
-      silc_hash_table_del_by_context(server->pk_hash,
-                                    idata->public_key, idata);
+    if (detached_client->data.public_key) {
+      /* Delete the detached client's public key from repository */
+      silc_skr_del_public_key(server->repository,
+                             detached_client->data.public_key,
+                             detached_client);
+      detached_client->data.public_key = NULL;
+    }
+
+    if (idata->public_key) {
+      /* Delete the resuming client's public key from repository.  It will
+        be added later again. */
+      public_key = silc_pkcs_public_key_copy(idata->public_key);
+      silc_skr_del_public_key(server->repository, idata->public_key, idata);
+      idata->public_key = public_key;
+    }
 
     /* Take new keys and stuff into use in the old entry */
     silc_idlist_del_data(detached_client);
     silc_idlist_add_data(detached_client, idata);
 
-    if (detached_client->data.public_key)
-      silc_hash_table_add(server->pk_hash,
-                         detached_client->data.public_key, detached_client);
+    if (detached_client->data.public_key) {
+      /* Add the resumed client's public key back to repository. */
+      if (!silc_server_get_public_key_by_client(server, detached_client, NULL))
+       silc_skr_add_public_key_simple(server->repository,
+                                      detached_client->data.public_key,
+                                      SILC_SKR_USAGE_IDENTIFICATION,
+                                      detached_client, NULL);
+    }
 
     detached_client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
     detached_client->data.status |= SILC_IDLIST_STATUS_RESUMED;
@@ -3889,15 +3902,19 @@ void silc_server_resume_client(SilcServer server,
     /* Client is detached, and now it is resumed.  Remove the detached
        mode and mark that it is resumed. */
 
-    if (detached_client->data.public_key)
-      silc_hash_table_del_by_context(server->pk_hash,
-                                    detached_client->data.public_key,
-                                    detached_client);
+    if (detached_client->data.public_key) {
+      /* Delete the detached client's public key from repository */
+      silc_skr_del_public_key(server->repository,
+                             detached_client->data.public_key,
+                             detached_client);
+      detached_client->data.public_key = NULL;
+    }
 
     silc_idlist_del_data(detached_client);
     detached_client->mode &= ~SILC_UMODE_DETACHED;
     detached_client->data.status |= SILC_IDLIST_STATUS_RESUMED;
     detached_client->data.status &= ~SILC_IDLIST_STATUS_LOCAL;
+    silc_dlist_del(server->expired_clients, detached_client);
 
     /* Check if anyone is watching this client */
     if (server->server_type == SILC_ROUTER)
index 6d17df06142142c5a6544a2e6b4455f23f9db19c..16d2298881a375e8e088cd4ed047529175e3df1e 100644 (file)
 #include "serverincludes.h"
 #include "server_internal.h"
 
-/************************* Types and definitions ***************************/
+/************************* Types and definitions ****************************/
 
 SILC_TASK_CALLBACK(silc_server_get_stats);
 SILC_TASK_CALLBACK(silc_server_connect_router);
 SILC_TASK_CALLBACK(silc_server_do_rekey);
+SILC_TASK_CALLBACK(silc_server_purge_expired_clients);
 static void silc_server_accept_new_connection(SilcNetStatus status,
                                              SilcStream stream,
                                              void *context);
@@ -109,6 +110,68 @@ static SilcBool silc_server_packet_receive(SilcPacketEngine engine,
       (idata->status & SILC_IDLIST_STATUS_REGISTERED))
     return FALSE;
 
+  /* Ignore packets from disabled connection */
+  if (idata->status & SILC_IDLIST_STATUS_DISABLED &&
+      packet->type != SILC_PACKET_HEARTBEAT &&
+      packet->type != SILC_PACKET_RESUME_ROUTER &&
+      packet->type != SILC_PACKET_REKEY)
+    return FALSE;
+
+  /* Check that the the current client ID is same as in the client's packet. */
+  if (idata->conn_type == SILC_CONN_CLIENT) {
+    SilcClientEntry client = (SilcClientEntry)silc_packet_get_context(stream);
+    SilcClientID client_id;
+
+    if (client->id && packet->src_id &&
+       silc_id_str2id(packet->src_id, packet->src_id_len,
+                      packet->src_id_type, &client_id, sizeof(client_id))) {
+      if (!SILC_ID_CLIENT_COMPARE(client->id, &client_id)) {
+       SILC_LOG_DEBUG(("Packet source is not same as sender"));
+       return FALSE;
+      }
+    }
+  }
+
+  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 &&
+       !(packet->flags & SILC_PACKET_FLAG_BROADCAST) &&
+       packet->dst_id_type == SILC_ID_SERVER &&
+       idata->conn_type != SILC_CONN_CLIENT &&
+       memcmp(packet->dst_id, server->id_string, server->id_string_len)) {
+      SilcPacketStream conn;
+      SilcServerID server_id;
+
+      silc_id_str2id(packet->dst_id, packet->dst_id_len, packet->dst_id_type,
+                    &server_id, sizeof(server_id));
+
+      conn = silc_server_route_get(server, &server_id, SILC_ID_SERVER);
+      if (!conn) {
+       SILC_LOG_WARNING(("Packet to unknown server ID %s, dropped (no route)",
+                         silc_id_render(&server_id, SILC_ID_SERVER)));
+       return FALSE;
+      }
+
+      silc_server_packet_route(server, conn, packet);
+      silc_packet_free(packet);
+      return TRUE;
+    }
+  }
+
+  /* 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 &&
+      idata->conn_type == SILC_CONN_ROUTER &&
+      packet->flags & SILC_PACKET_FLAG_BROADCAST) {
+    /* Broadcast to our primary route */
+    silc_server_packet_broadcast(server, SILC_PRIMARY_ROUTE(server), packet);
+
+    /* If we have backup routers then we need to feed all broadcast
+       data to those servers. */
+    silc_server_backup_broadcast(server, stream, packet);
+  }
+
   /* Process packet */
   silc_server_packet_parse_type(server, stream, packet);
 
@@ -122,7 +185,30 @@ static void silc_server_packet_eos(SilcPacketEngine engine,
                                   void *callback_context,
                                   void *stream_context)
 {
+  SilcServer server = callback_context;
+  SilcIDListData idata = silc_packet_get_context(stream);
+
   SILC_LOG_DEBUG(("End of stream received"));
+
+  if (!idata)
+    return;
+
+  if (server->router_conn && server->router_conn->sock == stream &&
+      !server->router && server->standalone) {
+    silc_server_create_connections(server);
+  } else {
+    /* If backup disconnected then mark that resuming will not be allowed */
+     if (server->server_type == SILC_ROUTER && !server->backup_router &&
+         idata->conn_type == SILC_CONN_SERVER) {
+      SilcServerEntry server_entry = (SilcServerEntry)idata;
+      if (server_entry->server_type == SILC_BACKUP_ROUTER)
+        server->backup_closed = TRUE;
+    }
+
+    silc_server_free_sock_user_data(server, stream, NULL);
+  }
+
+  silc_server_close_connection(server, stream);
 }
 
 /* Packet engine callback to indicate error */
@@ -133,7 +219,20 @@ static void silc_server_packet_error(SilcPacketEngine engine,
                                     void *callback_context,
                                     void *stream_context)
 {
+  SilcIDListData idata = silc_packet_get_context(stream);
+  SilcStream sock = silc_packet_stream_get_stream(stream);
+  const char *ip;
+  SilcUInt16 port;
 
+  if (!idata || !sock)
+    return;
+
+  if (!silc_socket_stream_get_info(sock, NULL, NULL, &ip, &port))
+    return;
+
+  SILC_LOG_ERROR(("Connection %s:%d [%s]: %s",
+                 SILC_CONNTYPE_STRING(idata->conn_type), ip, port,
+                 silc_packet_error_string(error)));
 }
 
 /* Packet stream callbacks */
@@ -229,6 +328,7 @@ static void silc_server_packet_parse_type(SilcServer server,
     {
       SilcStatus status;
       char *message = NULL;
+      const char *hostname, *ip;
 
       if (packet->flags & SILC_PACKET_FLAG_LIST)
        break;
@@ -241,12 +341,13 @@ static void silc_server_packet_parse_type(SilcServer server,
        message = silc_memdup(packet->buffer.data + 1,
                              silc_buffer_len(&packet->buffer) - 1);
 
-#if 0
-      SILC_LOG_INFO(("Disconnected by %s (%s): %s (%d) %s",
-                    sock->ip, sock->hostname,
+      if (!silc_socket_stream_get_info(sock, NULL, &hostname, &ip, NULL))
+       break;
+
+      SILC_LOG_INFO(("Disconnected by %s (%s): %s (%d) %s", ip, hostname,
                     silc_get_status_message(status), status,
                     message ? message : ""));
-#endif
+
       silc_free(message);
 
       /* Do not switch to backup in case of error */
@@ -443,6 +544,9 @@ SilcBool silc_server_alloc(SilcServer *new_server)
   server->conns = silc_dlist_init();
   if (!server->conns)
     return FALSE;
+  server->expired_clients = silc_dlist_init();
+  if (!server->expired_clients)
+    return FALSE;
 
   *new_server = server;
 
@@ -462,8 +566,6 @@ void silc_server_free(SilcServer server)
 
   silc_server_backup_free(server);
   silc_server_config_unref(&server->config_ref);
-  if (server->pk_hash)
-    silc_hash_table_free(server->pk_hash);
   if (server->rng)
     silc_rng_free(server->rng);
   if (server->public_key)
@@ -518,21 +620,26 @@ void silc_server_free(SilcServer server)
   silc_idcache_free(server->global_list->channels);
   silc_hash_table_free(server->watcher_list);
   silc_hash_table_free(server->watcher_list_pk);
-
   silc_hash_free(server->md5hash);
   silc_hash_free(server->sha1hash);
-  silc_hmac_unregister_all();
-  silc_hash_unregister_all();
-  silc_cipher_unregister_all();
-  silc_pkcs_unregister_all();
+
+  silc_dlist_uninit(server->listeners);
+  silc_dlist_uninit(server->conns);
+  silc_dlist_uninit(server->expired_clients);
+  silc_skr_free(server->repository);
+  silc_packet_engine_stop(server->packet_engine);
 
   silc_free(server->local_list);
   silc_free(server->global_list);
   silc_free(server->server_name);
-  silc_free(server->id_string);
   silc_free(server->purge_i);
   silc_free(server->purge_g);
   silc_free(server);
+
+  silc_hmac_unregister_all();
+  silc_hash_unregister_all();
+  silc_cipher_unregister_all();
+  silc_pkcs_unregister_all();
 }
 
 /* Creates a new server listener. */
@@ -687,9 +794,11 @@ SilcBool silc_server_init(SilcServer server)
     silc_idcache_alloc(0, SILC_ID_CLIENT, silc_idlist_client_destructor,
                       server);
   server->local_list->servers =
-    silc_idcache_alloc(0, SILC_ID_SERVER, NULL, NULL);
+    silc_idcache_alloc(0, SILC_ID_SERVER, silc_idlist_server_destructor,
+                      server);
   server->local_list->channels =
-    silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL, NULL);
+    silc_idcache_alloc(0, SILC_ID_CHANNEL, silc_idlist_channel_destructor,
+                      NULL);
 
   /* These are allocated for normal server as well as these hold some
      global information that the server has fetched from its router. For
@@ -698,9 +807,11 @@ SilcBool silc_server_init(SilcServer server)
     silc_idcache_alloc(0, SILC_ID_CLIENT, silc_idlist_client_destructor,
                       server);
   server->global_list->servers =
-    silc_idcache_alloc(0, SILC_ID_SERVER, NULL, NULL);
+    silc_idcache_alloc(0, SILC_ID_SERVER, silc_idlist_server_destructor,
+                      server);
   server->global_list->channels =
-    silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL, NULL);
+    silc_idcache_alloc(0, SILC_ID_CHANNEL, silc_idlist_channel_destructor,
+                      NULL);
 
   /* Init watcher lists */
   server->watcher_list =
@@ -716,15 +827,6 @@ SilcBool silc_server_init(SilcServer server)
   if (!server->watcher_list_pk)
     goto err;
 
-  /* Init public key list */
-  server->pk_hash =
-    silc_hash_table_alloc(0, silc_hash_public_key, NULL,
-                          silc_hash_public_key_compare, NULL,
-                          NULL, NULL, TRUE);
-
-  if (!server->pk_hash)
-    goto err;
-
   /* Create TCP listener */
   listener = silc_server_listen(
                   server,
@@ -751,6 +853,8 @@ SilcBool silc_server_init(SilcServer server)
   server->id = id;
   server->server_name = server->config->server_info->server_name;
   server->config->server_info->server_name = NULL;
+  silc_id_id2str(server->id, SILC_ID_SERVER, server->id_string,
+                sizeof(server->id_string), &server->id_string_len);
 
   /* Add ourselves to the server list. We don't have a router yet
      beacuse we haven't established a route yet. It will be done later.
@@ -770,19 +874,10 @@ SilcBool silc_server_init(SilcServer server)
   if (silc_server_init_secondary(server) == FALSE)
     goto err;
 
-  /* Create connections to configured routers. */
-  silc_server_create_connections(server);
-
   server->listenning = TRUE;
 
-  /* Allocate the entire socket list that is used in server. Eventually
-     all connections will have entry in this table (it is a table of
-     pointers to the actual object that is allocated individually
-     later). */
-  server->sockets = silc_calloc(server->config->param.connections_max,
-                               sizeof(*server->sockets));
-  if (!server->sockets)
-    goto err;
+  /* Create connections to configured routers. */
+  silc_server_create_connections(server);
 
   /* If server connections has been configured then we must be router as
      normal server cannot have server connections, only router connections. */
@@ -834,6 +929,14 @@ SilcBool silc_server_init(SilcServer server)
   if (!server->packet_engine)
     goto err;
 
+  /* Register client entry expiration timeout */
+  silc_schedule_task_add_timeout(server->schedule,
+                                silc_server_purge_expired_clients, server,
+                                600, 0);
+
+  /* Initialize HTTP server */
+  silc_server_http_init(server);
+
   SILC_LOG_DEBUG(("Server initialized"));
 
   /* We are done here, return succesfully */
@@ -1108,6 +1211,7 @@ void silc_server_stop(SilcServer server)
 {
   SilcDList list;
   SilcPacketStream ps;
+  SilcNetListener listener;
 
   SILC_LOG_INFO(("SILC Server shutting down"));
 
@@ -1135,6 +1239,12 @@ void silc_server_stop(SilcServer server)
   /* We are not connected to network anymore */
   server->standalone = TRUE;
 
+  silc_dlist_start(server->listeners);
+  while ((listener = silc_dlist_get(server->listeners)))
+    silc_net_close_listener(listener);
+
+  silc_server_http_uninit(server);
+
   silc_schedule_stop(server->schedule);
   silc_schedule_uninit(server->schedule);
   server->schedule = NULL;
@@ -1142,110 +1252,33 @@ void silc_server_stop(SilcServer server)
   SILC_LOG_DEBUG(("Server stopped"));
 }
 
-#if 0
-/* Parses whole packet, received earlier. */
+/* Purge expired client entries from the server */
 
-SILC_TASK_CALLBACK(silc_server_packet_parse_real)
+SILC_TASK_CALLBACK(silc_server_purge_expired_clients)
 {
-  SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
-  SilcServer server = (SilcServer)parse_ctx->context;
-  SilcPacketStream sock = parse_ctx->sock;
-  SilcPacket *packet = parse_ctx->packet;
-  SilcIDListData idata = (SilcIDListData)sock->user_data;
-  int ret;
-
-  if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock)) {
-    SILC_LOG_DEBUG(("Connection is disconnected"));
-    goto out;
-  }
-
-  server->stat.packets_received++;
-
-  /* Parse the packet */
-  if (parse_ctx->normal)
-    ret = silc_packet_parse(packet, idata ? idata->receive_key : NULL);
-  else
-    ret = silc_packet_parse_special(packet, idata ? idata->receive_key : NULL);
-
-  /* If entry is disabled ignore what we got. */
-  if (idata && idata->status & SILC_IDLIST_STATUS_DISABLED &&
-      ret != SILC_PACKET_HEARTBEAT && ret != SILC_PACKET_RESUME_ROUTER &&
-      ret != SILC_PACKET_REKEY && ret != SILC_PACKET_REKEY_DONE &&
-      ret != SILC_PACKET_KEY_EXCHANGE_1 && ret != SILC_PACKET_KEY_EXCHANGE_2) {
-    SILC_LOG_DEBUG(("Connection is disabled (packet %s dropped)",
-                   silc_get_packet_name(ret)));
-    goto out;
-  }
-
-  if (ret == SILC_PACKET_NONE) {
-    SILC_LOG_DEBUG(("Error parsing packet"));
-    goto out;
-  }
-
-  /* Check that the the current client ID is same as in the client's packet. */
-  if (sock->type == SILC_CONN_CLIENT) {
-    SilcClientEntry client = (SilcClientEntry)sock->user_data;
-    if (client && client->id && packet->src_id) {
-      void *id = silc_id_str2id(packet->src_id, packet->src_id_len,
-                               packet->src_id_type);
-      if (!id || !SILC_ID_CLIENT_COMPARE(client->id, id)) {
-       silc_free(id);
-       SILC_LOG_DEBUG(("Packet source is not same as sender"));
-       goto out;
-      }
-      silc_free(id);
-    }
-  }
-
-  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 && !(packet->flags & SILC_PACKET_FLAG_BROADCAST) &&
-       packet->dst_id_type == SILC_ID_SERVER &&
-       sock->type != SILC_CONN_CLIENT &&
-       memcmp(packet->dst_id, server->id_string, server->id_string_len)) {
-      SilcPacketStream conn;
+  SilcServer server = context;
+  SilcClientEntry client;
+  SilcIDList id_list;
 
-      /* Route the packet to fastest route for the destination ID */
-      void *id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
-                               packet->dst_id_type);
-      if (!id)
-       goto out;
+  SILC_LOG_DEBUG(("Expire timeout"));
 
-      conn = silc_server_route_get(server, id, packet->dst_id_type);
-      if (!conn) {
-       SILC_LOG_WARNING(("Packet to unknown server ID %s, dropped (no route)",
-                         silc_id_render(id, SILC_ID_SERVER)));
-       goto out;
-      }
-
-      silc_server_packet_route(server, conn, packet);
-      silc_free(id);
-      goto out;
-    }
-  }
+  silc_dlist_start(server->expired_clients);
+  while ((client = silc_dlist_get(server->expired_clients))) {
+    if (client->data.status & SILC_IDLIST_STATUS_REGISTERED)
+      continue;
 
-  /* Parse the incoming packet type */
-  silc_server_packet_parse_type(server, sock, packet);
+    id_list = (client->data.status & SILC_IDLIST_STATUS_LOCAL ?
+              server->local_list : server->global_list);
 
-  /* 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_CONN_ROUTER &&
-      packet->flags & SILC_PACKET_FLAG_BROADCAST) {
-    /* Broadcast to our primary route */
-    silc_server_packet_broadcast(server, SILC_PRIMARY_ROUTE(server), packet);
-
-    /* If we have backup routers then we need to feed all broadcast
-       data to those servers. */
-    silc_server_backup_broadcast(server, sock, packet);
+    silc_idlist_del_data(client);
+    silc_idlist_del_client(id_list, client);
+    silc_dlist_del(server->expired_clients, client);
   }
 
- out:
-  silc_packet_context_free(packet);
-  silc_free(parse_ctx);
+  silc_schedule_task_add_timeout(server->schedule,
+                                silc_server_purge_expired_clients, server,
+                                600, 0);
 }
-#endif /* 0 */
 
 
 /******************************* Connecting *********************************/
@@ -1980,7 +2013,7 @@ silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success,
   SilcUnknownEntry entry = silc_packet_get_context(sock);
   SilcIDListData idata = (SilcIDListData)entry;
   SilcServer server = entry->server;
-  SilcServerConfigConnParams *param;
+  SilcServerConfigConnParams *param = &server->config->param;
   SilcServerConnection sconn;
   void *id_entry;
   const char *hostname;
@@ -2091,7 +2124,8 @@ silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success,
       if (!silc_server_get_public_key_by_client(server, client, NULL))
        silc_skr_add_public_key_simple(server->repository,
                                       entry->data.public_key,
-                                      SILC_SKR_USAGE_IDENTIFICATION, client);
+                                      SILC_SKR_USAGE_IDENTIFICATION, client,
+                                      NULL);
 
       id_entry = (void *)client;
       break;
@@ -2316,6 +2350,7 @@ silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success,
   sconn->remote_port = port;
   silc_dlist_add(server->conns, sconn);
   idata->sconn = sconn;
+  idata->last_receive = time(NULL);
 
   /* Add the common data structure to the ID entry. */
   silc_idlist_add_data(id_entry, (SilcIDListData)entry);
@@ -2324,20 +2359,19 @@ silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success,
   /* Connection has been fully established now. Everything is ok. */
   SILC_LOG_DEBUG(("New connection authenticated"));
 
-
 #if 0
   /* Perform keepalive. */
   if (param->keepalive_secs)
     silc_socket_set_heartbeat(sock, param->keepalive_secs, server,
                              silc_server_perform_heartbeat,
                              server->schedule);
+#endif
 
   /* Perform Quality of Service */
   if (param->qos)
-    silc_socket_set_qos(sock, param->qos_rate_limit, param->qos_bytes_limit,
-                       param->qos_limit_sec, param->qos_limit_usec,
-                       server->schedule);
-#endif
+    silc_socket_stream_set_qos(silc_packet_stream_get_stream(sock),
+                              param->qos_rate_limit, param->qos_bytes_limit,
+                              param->qos_limit_sec, param->qos_limit_usec);
 
   silc_server_config_unref(&entry->cconfig);
   silc_server_config_unref(&entry->sconfig);
@@ -2434,15 +2468,13 @@ static void silc_server_accept_new_connection(SilcNetStatus status,
 
   /* Check for maximum allowed connections */
   server->stat.conn_attempts++;
-#if 0
-  if (silc_server_num_connections(server) >
+  if (silc_dlist_count(server->conns) >
       server->config->param.connections_max) {
     SILC_LOG_ERROR(("Refusing connection, server is full"));
     server->stat.conn_failures++;
     silc_stream_destroy(stream);
     return;
   }
-#endif
 
   /* Get hostname, IP and port */
   if (!silc_socket_stream_get_info(stream, NULL, (const char **)&hostname,
@@ -2723,7 +2755,7 @@ void silc_server_close_connection(SilcServer server,
   silc_socket_stream_get_info(silc_packet_stream_get_stream(sock),
                              NULL, &hostname, NULL, &port);
   SILC_LOG_INFO(("Closing connection %s:%d [%s] %s", hostname, port,
-                SILC_CONNTYPE_STRING(idata->conn_type),
+                idata ? SILC_CONNTYPE_STRING(idata->conn_type) : "",
                 tmp[0] ? tmp : ""));
 
   //  silc_socket_set_qos(sock, 0, 0, 0, 0, NULL);
@@ -2811,10 +2843,12 @@ void silc_server_free_client_data(SilcServer server,
   /* Remove this client from watcher list if it is */
   silc_server_del_from_watcher_list(server, client);
 
-  /* Remove this client from the public key hash list */
-  if (client->data.public_key)
-    silc_hash_table_del_by_context(server->pk_hash,
-                                   client->data.public_key, client);
+  /* Remove client's public key from repository, this will free it too. */
+  if (client->data.public_key) {
+    silc_skr_del_public_key(server->repository, client->data.public_key,
+                           client);
+    client->data.public_key = NULL;
+  }
 
   /* Update statistics */
   server->stat.my_clients--;
@@ -2863,6 +2897,7 @@ void silc_server_free_sock_user_data(SilcServer server,
       SilcClientEntry client_entry = (SilcClientEntry)idata;
       silc_server_free_client_data(server, sock, client_entry, TRUE,
                                   signoff_message);
+      silc_packet_set_context(sock, NULL);
       break;
     }
 
@@ -3052,6 +3087,8 @@ void silc_server_free_sock_user_data(SilcServer server,
        silc_server_announce_channels(server, time(0) - 300,
                                      backup_router->connection);
       }
+
+      silc_packet_set_context(sock, NULL);
       break;
     }
 
@@ -3063,6 +3100,7 @@ void silc_server_free_sock_user_data(SilcServer server,
 
       silc_idlist_del_data(idata);
       silc_free(entry);
+      silc_packet_set_context(sock, NULL);
       break;
     }
   }
@@ -3284,48 +3322,6 @@ SilcBool silc_server_remove_from_one_channel(SilcServer server,
   return TRUE;
 }
 
-#if 0
-/* Timeout callback. This is called if connection is idle or for some
-   other reason is not responding within some period of time. This
-   disconnects the remote end. */
-
-SILC_TASK_CALLBACK(silc_server_timeout_remote)
-{
-  SilcServer server = (SilcServer)context;
-  SilcPacketStream sock = server->sockets[fd];
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (!sock)
-    return;
-
-  SILC_LOG_ERROR(("No response from %s (%s), Connection timeout",
-                 sock->hostname, sock->ip));
-
-  /* If we have protocol active we must assure that we call the protocol's
-     final callback so that all the memory is freed. */
-  if (sock->protocol && sock->protocol->protocol &&
-      sock->protocol->protocol->type != SILC_PROTOCOL_SERVER_BACKUP) {
-    protocol = sock->protocol->protocol->type;
-    silc_protocol_cancel(sock->protocol, server->schedule);
-    sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
-    silc_protocol_execute_final(sock->protocol, server->schedule);
-    sock->protocol = NULL;
-    return;
-  }
-
-  silc_server_disconnect_remote(server, sock,
-                               protocol ==
-                               SILC_PROTOCOL_SERVER_CONNECTION_AUTH ?
-                               SILC_STATUS_ERR_AUTH_FAILED :
-                               SILC_STATUS_ERR_KEY_EXCHANGE_FAILED,
-                               "Connection timeout");
-
-  if (sock->user_data)
-    silc_server_free_sock_user_data(server, sock, NULL);
-}
-#endif /* 0 */
-
 /* Creates new channel. Sends NEW_CHANNEL packet to primary route. This
    function may be used only by router. In real SILC network all channels
    are created by routers thus this function is never used by normal
index 3b3bee771ec0cfbef784d20f18d38b9ed72c79ea..b3021e7839cb3307775f9198181fddaa17cd0829 100644 (file)
@@ -255,5 +255,7 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server,
                                               SilcBool get_secret,
                                               SilcBuffer *user_mode_list);
 void silc_server_stderr(SilcLogType type, char *message);
+void silc_server_http_init(SilcServer server);
+void silc_server_http_uninit(SilcServer server);
 
 #endif
diff --git a/apps/silcd/server_http.c b/apps/silcd/server_http.c
new file mode 100644 (file)
index 0000000..663057e
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+
+  server_http.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2007 Pekka Riikonen
+
+  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; 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
+  GNU General Public License for more details.
+
+*/
+
+#include "serverincludes.h"
+#include "server_internal.h"
+
+/************************* Types and definitions ****************************/
+
+#define HTTP_START1                                            \
+"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\""          \
+"\"http://www.w3.ohtml4/strict.dtd\">\n"                       \
+"<html>\n"                                                     \
+"<head>\n"                                                     \
+"<meta http-equiv=\"Content-Type\" content=\"text/html; "      \
+"charset=iso-8859-1\">\n"                                      \
+"<title>\n"
+
+#define HTTP_START2                            \
+"</title>\n"                                   \
+"</head>\n"                                    \
+"<body>\n"
+
+#define HTTP_END                               \
+"</body>\n"                                    \
+"</html>\n"
+
+#define HTTP_404 "404 Not Found"
+#define HTTP_404_B "<body><h1>404 Not Found</h1><p>The page you are looking for cannot be located</body>"
+
+#define STAT_OUTPUT(fmt, stat)                                 \
+do {                                                           \
+  silc_snprintf(buf, sizeof(buf), fmt "<br>", (int)stat);      \
+  silc_buffer_strformat(&page, buf, SILC_STRFMT_END);          \
+} while(0)
+
+
+/****************************** HTTP access *********************************/
+
+/* HTTP server callback.  We serve pages here. */
+
+static void silc_server_http_callback(SilcHttpServer httpd,
+                                     SilcHttpConnection conn,
+                                     const char *uri,
+                                     const char *method,
+                                     SilcBuffer data,
+                                     void *context)
+{
+  SilcServer server = context;
+  SilcBufferStruct page;
+  unsigned char buf[128];
+
+  SILC_LOG_DEBUG(("HTTP callback: %s %s", method, uri));
+
+  memset(&page, 0, sizeof(page));
+
+  if (!strcasecmp(method, "GET")) {
+
+    /* Index page */
+    if (!strcmp(uri, "/") || !strcmp(uri, "/index.html")) {
+      SILC_LOG_DEBUG(("Index"));
+
+      silc_buffer_strformat(&page, HTTP_START1, SILC_STRFMT_END);
+      silc_buffer_strformat(&page, "SILC ",
+                           server->server_type == SILC_ROUTER ?
+                           "Router " : "Server ", server->server_name,
+                           SILC_STRFMT_END);
+      silc_buffer_strformat(&page, HTTP_START2, SILC_STRFMT_END);
+
+      silc_buffer_strformat(&page, "<h1>SILC ",
+                           server->server_type == SILC_ROUTER ?
+                           "Router " : "Server ", server->server_name,
+                           "</h1><hr><p>",
+                           SILC_STRFMT_END);
+
+      silc_buffer_strformat(&page, "<b>Statistics:</b><p>", SILC_STRFMT_END);
+
+      STAT_OUTPUT("Clients    : %d", server->stat.my_clients);
+      STAT_OUTPUT("Servers    : %d", server->stat.my_servers);
+      STAT_OUTPUT("Routers    : %d", server->stat.my_routers);
+      STAT_OUTPUT("Channels   : %d", server->stat.my_channels);
+      STAT_OUTPUT("Joined users   : %d", server->stat.my_chanclients);
+      STAT_OUTPUT("Aways      : %d", server->stat.my_aways);
+      STAT_OUTPUT("Detached clients : %d", server->stat.my_detached);
+      STAT_OUTPUT("Server operators : %d", server->stat.my_server_ops);
+      STAT_OUTPUT("Router operators : %d", server->stat.my_router_ops);
+
+      silc_buffer_strformat(&page, "<p><b>Global Statistics:</b><p>",
+                           SILC_STRFMT_END);
+      STAT_OUTPUT("Cell clients  : %d", server->stat.cell_clients);
+      STAT_OUTPUT("Cell servers  : %d", server->stat.cell_servers);
+      STAT_OUTPUT("Cell channels : %d", server->stat.cell_channels);
+      STAT_OUTPUT("Cell joined users : %d", server->stat.cell_chanclients);
+      STAT_OUTPUT("All clients   : %d", server->stat.clients);
+      STAT_OUTPUT("All servers   : %d", server->stat.servers);
+      STAT_OUTPUT("All routers   : %d", server->stat.routers);
+      STAT_OUTPUT("All channels  : %d", server->stat.channels);
+      STAT_OUTPUT("All joined users  : %d", server->stat.chanclients);
+      STAT_OUTPUT("All aways     : %d", server->stat.aways);
+      STAT_OUTPUT("All detached clients : %d", server->stat.detached);
+      STAT_OUTPUT("All server operators : %d", server->stat.server_ops);
+      STAT_OUTPUT("All router operators : %d", server->stat.router_ops);
+
+      silc_buffer_strformat(&page, "<p><b>Internal Statistics:</b><p>",
+                           SILC_STRFMT_END);
+      STAT_OUTPUT("Connection attempts : %d", server->stat.conn_attempts);
+      STAT_OUTPUT("Connection failures : %d", server->stat.conn_failures);
+      STAT_OUTPUT("Authentication attempts : %d", server->stat.auth_attempts);
+      STAT_OUTPUT("Authentication failures : %d", server->stat.auth_failures);
+      STAT_OUTPUT("Packets sent  : %d", server->stat.packets_sent);
+      STAT_OUTPUT("Packets received  : %d", server->stat.packets_received);
+      STAT_OUTPUT("Commands sent : %d", server->stat.commands_sent);
+      STAT_OUTPUT("Commands received : %d", server->stat.commands_received);
+      STAT_OUTPUT("Connections   : %d", server->stat.conn_num);
+
+      silc_buffer_strformat(&page, HTTP_END, SILC_STRFMT_END);
+
+      silc_http_server_send(httpd, conn, &page);
+      silc_buffer_purge(&page);
+      return;
+    }
+  }
+
+  silc_http_server_send_error(httpd, conn, HTTP_404, HTTP_404_B);
+}
+
+void silc_server_http_init(SilcServer server)
+{
+  /* Allocate HTTP server */
+  server->httpd = silc_http_server_alloc(server->config->httpd_ip,
+                                        server->config->httpd_port,
+                                        server->schedule,
+                                        silc_server_http_callback,
+                                        server);
+}
+
+void silc_server_http_uninit(SilcServer server)
+{
+  if (server->httpd)
+    silc_http_server_free(server->httpd);
+}
index 0870b9da1b3b46842704e85298f7d733b8480ebc..afedb0bdc77ec68459ff5a798b4b8db9ec127baa 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2005 Pekka Riikonen
+  Copyright (C) 1997 - 2007 Pekka Riikonen
 
   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
@@ -70,33 +70,22 @@ typedef struct {
 
 */
 struct SilcServerStruct {
-  char *server_name;
-  SilcServerEntry id_entry;
-  SilcServerID *id;
-  unsigned char *id_string;
+  SilcSchedule schedule;            /* Server scheduler */
+  SilcDList listeners;              /* TCP listeners */
+  SilcPacketEngine packet_engine;    /* Packet engine */
+  SilcDList conns;                  /* Connections in server */
+  SilcSKR repository;               /* Public key repository */
+  SilcPublicKey public_key;         /* Server public key */
+  SilcPrivateKey private_key;       /* Server private key */
+  SilcDList expired_clients;        /* Expired client entries */
+  SilcHttpServer httpd;                     /* HTTP server */
+
+  char *server_name;                /* Server's name */
+  SilcServerEntry id_entry;         /* Server's local entry */
+  SilcServerID *id;                 /* Server's ID */
+  unsigned char id_string[32];      /* Server's ID as string */
   SilcUInt32 id_string_len;
-  SilcUInt32 starttime;
-
-  unsigned int server_type    : 2;   /* Server type (server.h) */
-  unsigned int standalone     : 1;   /* Set if server is standalone, and
-                                       does not have connection to network. */
-  unsigned int listenning     : 1;   /* Set if server is listenning for
-                                       incoming connections. */
-  unsigned int background     : 1;   /* Set when server is on background */
-  unsigned int backup_router  : 1;   /* Set if this is backup router */
-  unsigned int backup_primary : 1;   /* Set if we've switched our primary
-                                       router to a backup router. */
-  unsigned int backup_noswitch: 1;   /* Set if we've won't switch to
-                                       become primary (we are backup) */
-  unsigned int backup_closed  : 1;   /* Set if backup closed connection.
-                                       Do not allow resuming in this case. */
-  unsigned int wait_backup    : 1;   /* Set if we are waiting for backup
-                                       router to connect to us. */
-  unsigned int server_shutdown: 1;   /* Set when shutting down */
-  unsigned int no_reconnect   : 1;   /* If set, server won't reconnect to
-                                       router after disconnection. */
-  unsigned int no_conf        : 1;   /* Set when connecting without
-                                       configuration. */
+  SilcUInt32 starttime;                     /* Server start time */
 
   SilcServerEntry router;           /* Pointer to the primary router */
   unsigned long router_connect;             /* Time when router was connected */
@@ -107,27 +96,12 @@ struct SilcServerStruct {
   /* Current command identifier, 0 not used */
   SilcUInt16 cmd_ident;
 
-  /* SILC server scheduler */
-  SilcSchedule schedule;
-
   /* ID lists. */
   SilcIDList local_list;
   SilcIDList global_list;
   SilcHashTable watcher_list;
   SilcHashTable watcher_list_pk;
 
-  SilcDList listeners;              /* TCP listeners */
-  SilcPacketEngine packet_engine;    /* Packet engine */
-  SilcDList conns;
-  SilcSKR repository;
-
-  /* Table of connected sockets */
-  SilcPacketStream *sockets;
-
-  /* Server public key */
-  SilcPublicKey public_key;
-  SilcPrivateKey private_key;
-
   /* Hash objects for general hashing */
   SilcHash md5hash;
   SilcHash sha1hash;
@@ -150,8 +124,26 @@ struct SilcServerStruct {
   SilcIDListPurge purge_i;
   SilcIDListPurge purge_g;
 
-  /* Hash table for public keys of all clients */
-  SilcHashTable pk_hash;
+  unsigned int server_type    : 2;   /* Server type (server.h) */
+  unsigned int standalone     : 1;   /* Set if server is standalone, and
+                                       does not have connection to network. */
+  unsigned int listenning     : 1;   /* Set if server is listenning for
+                                       incoming connections. */
+  unsigned int background     : 1;   /* Set when server is on background */
+  unsigned int backup_router  : 1;   /* Set if this is backup router */
+  unsigned int backup_primary : 1;   /* Set if we've switched our primary
+                                       router to a backup router. */
+  unsigned int backup_noswitch: 1;   /* Set if we've won't switch to
+                                       become primary (we are backup) */
+  unsigned int backup_closed  : 1;   /* Set if backup closed connection.
+                                       Do not allow resuming in this case. */
+  unsigned int wait_backup    : 1;   /* Set if we are waiting for backup
+                                       router to connect to us. */
+  unsigned int server_shutdown: 1;   /* Set when shutting down */
+  unsigned int no_reconnect   : 1;   /* If set, server won't reconnect to
+                                       router after disconnection. */
+  unsigned int no_conf        : 1;   /* Set when connecting without
+                                       configuration. */
 };
 
 /* Failure context. This is allocated when failure packet is received.
index b0b00fb1215624a40a7cb59d142d989d65fa009a..b64183d8e900e71916772e3e2224baa355b0b76b 100644 (file)
@@ -661,22 +661,32 @@ typedef struct {
   SilcBool found;
 } *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
 
-void silc_server_public_key_hash_foreach(void *key, void *context,
-                                         void *user_context)
+/* SKR find callbcak */
+
+static void silc_server_query_skr_callback(SilcSKR skr,
+                                          SilcSKRFind find,
+                                          SilcSKRStatus status,
+                                          SilcDList keys,
+                                          void *context)
 {
-  SilcServerPublicKeyUser uc = user_context;
-  SilcClientEntry entry = context;
+  SilcServerPublicKeyUser uc = context;
+  SilcSKRKey key;
 
-  /* Nothing was found, just return */
-  if (!context)
-    return;
+  if (keys) {
+    (*uc->clients) = silc_realloc((*uc->clients),
+                                 sizeof((**uc->clients)) *
+                                 ((*uc->clients_count) +
+                                  silc_dlist_count(keys)));
 
-  uc->found = TRUE;
+    silc_dlist_start(keys);
+    while ((key = silc_dlist_get(keys)))
+      (*uc->clients)[(*uc->clients_count)++] = key->key_context;
 
-  (*uc->clients) = silc_realloc((*uc->clients),
-                                sizeof((**uc->clients)) *
-                               ((*uc->clients_count) + 1));
-  (*uc->clients)[(*uc->clients_count)++] = entry;
+    uc->found = TRUE;
+    silc_dlist_uninit(keys);
+  }
+
+  silc_skr_find_free(find);
 }
 
 /* If clients are set, limit the found clients using the attributes in
@@ -691,7 +701,7 @@ void silc_server_query_check_attributes(SilcServer server,
   SilcAttributePayload attr;
   SilcAttribute attribute;
   SilcAttributeObjPk pk;
-  SilcPublicKey publickey;
+  SilcPublicKey publickey, cmp_pubkey;
   SilcPKCSType type;
   SilcBool found = FALSE, no_clients = FALSE;
   int i;
@@ -733,19 +743,24 @@ void silc_server_query_check_attributes(SilcServer server,
          continue;
        }
 
-       /* If no clients were set on calling this function, we
-          just search for clients, otherwise we try to limit
-          the clients */
+       /* If no clients were set on calling this function, we just search
+          for clients, otherwise we try to limit the clients. */
        if (no_clients) {
          SilcServerPublicKeyUserStruct usercontext;
+         SilcSKRFind find;
 
          usercontext.clients = clients;
          usercontext.clients_count = clients_count;
          usercontext.found = FALSE;
 
-         silc_hash_table_find_foreach(server->pk_hash, publickey,
-                                      silc_server_public_key_hash_foreach,
-                                      &usercontext);
+         find = silc_skr_find_alloc();
+         if (!find)
+           continue;
+
+         silc_skr_find_set_public_key(find, publickey);
+         silc_skr_find_set_usage(find, SILC_SKR_USAGE_IDENTIFICATION);
+         silc_skr_find(server->repository, server->schedule,
+                       find, silc_server_query_skr_callback, &usercontext);
 
          if (usercontext.found == TRUE)
            found = TRUE;
@@ -756,11 +771,15 @@ void silc_server_query_check_attributes(SilcServer server,
            if (!entry->data.public_key)
              continue;
 
-           if (!silc_hash_table_find_by_context(server->pk_hash, publickey,
-                                                entry, NULL))
-             (*clients)[i] = NULL;
-           else
-             found = TRUE;
+           if (silc_server_get_public_key_by_client(server, entry,
+                                                    &cmp_pubkey)) {
+             if (silc_pkcs_public_key_compare(cmp_pubkey, publickey)) {
+               found = TRUE;
+               continue;
+             }
+           }
+
+           (*clients)[i] = NULL;
          }
        }
        silc_free(pk.type);
index 092c81717609c8af4c81bc0797487f477f1b9843..2f96514fecc6b1718a3c8b85f6ffe5f337f9d583 100644 (file)
@@ -209,10 +209,13 @@ SilcBool silc_server_remove_clients_by_server(SilcServer server,
       SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
       SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
 
-      if (client->data.public_key)
-       silc_hash_table_del_by_context(server->pk_hash,
-                                      client->data.public_key,
-                                      client);
+      /* Remove client's public key from repository, this will free it too. */
+      if (client->data.public_key) {
+       silc_skr_del_public_key(server->repository, client->data.public_key,
+                               client);
+       client->data.public_key = NULL;
+      }
+
       silc_server_remove_clients_channels(server, entry, clients,
                                          client, channels);
       silc_server_del_from_watcher_list(server, client);
@@ -223,6 +226,7 @@ SilcBool silc_server_remove_clients_by_server(SilcServer server,
        client->mode = 0;
        client->router = NULL;
        client->connection = NULL;
+       silc_dlist_add(server->expired_clients, client);
       } else {
        silc_idlist_del_data(client);
        silc_idlist_del_client(server->local_list, client);
@@ -266,10 +270,13 @@ SilcBool silc_server_remove_clients_by_server(SilcServer server,
       SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
       SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
 
-      if (client->data.public_key)
-       silc_hash_table_del_by_context(server->pk_hash,
-                                      client->data.public_key,
-                                      client);
+      /* Remove client's public key from repository, this will free it too. */
+      if (client->data.public_key) {
+       silc_skr_del_public_key(server->repository, client->data.public_key,
+                               client);
+       client->data.public_key = NULL;
+      }
+
       silc_server_remove_clients_channels(server, entry, clients,
                                          client, channels);
       silc_server_del_from_watcher_list(server, client);
@@ -280,6 +287,7 @@ SilcBool silc_server_remove_clients_by_server(SilcServer server,
        client->mode = 0;
        client->router = NULL;
        client->connection = NULL;
+       silc_dlist_add(server->expired_clients, client);
       } else {
        silc_idlist_del_data(client);
        silc_idlist_del_client(server->global_list, client);
@@ -1082,8 +1090,7 @@ static void find_callback(SilcSKR skr, SilcSKRFind find,
   silc_skr_find_free(find);
 }
 
-/* Get public key. For public key tables that has multiple keys in it the
-   silc_server_find_public_key must be used. */
+/* Get public key by key usage and key context. */
 
 SilcPublicKey silc_server_get_public_key(SilcServer server,
                                         SilcSKRKeyUsage usage,
@@ -1238,9 +1245,9 @@ SilcBool silc_server_connection_allowed(SilcServer server,
    of the checks fails FALSE is returned. */
 
 SilcBool silc_server_check_cmode_rights(SilcServer server,
-                                   SilcChannelEntry channel,
-                                   SilcChannelClientEntry client,
-                                   SilcUInt32 mode)
+                                       SilcChannelEntry channel,
+                                       SilcChannelClientEntry client,
+                                       SilcUInt32 mode)
 {
   SilcBool is_op = client->mode & SILC_CHANNEL_UMODE_CHANOP;
   SilcBool is_fo = client->mode & SILC_CHANNEL_UMODE_CHANFO;
@@ -1529,10 +1536,12 @@ void silc_server_kill_client(SilcServer server,
     SILC_OPER_STATS_UPDATE(remote_client, server, SILC_UMODE_SERVER_OPERATOR);
     SILC_OPER_STATS_UPDATE(remote_client, router, SILC_UMODE_ROUTER_OPERATOR);
 
-    if (remote_client->data.public_key)
-      silc_hash_table_del_by_context(server->pk_hash,
-                                     remote_client->data.public_key,
-                                     remote_client);
+    /* Remove client's public key from repository, this will free it too. */
+    if (remote_client->data.public_key) {
+      silc_skr_del_public_key(server->repository,
+                             remote_client->data.public_key, remote_client);
+      remote_client->data.public_key = NULL;
+    }
 
     if (SILC_IS_LOCAL(remote_client)) {
       server->stat.my_clients--;
@@ -1594,9 +1603,9 @@ silc_server_check_watcher_list_foreach(void *key, void *context,
    notify change of notify type indicated by `notify'. */
 
 SilcBool silc_server_check_watcher_list(SilcServer server,
-                                   SilcClientEntry client,
-                                   const char *new_nick,
-                                   SilcNotifyType notify)
+                                       SilcClientEntry client,
+                                       const char *new_nick,
+                                       SilcNotifyType notify)
 {
   unsigned char hash[16];
   WatcherNotifyContext n;
@@ -1645,7 +1654,7 @@ SilcBool silc_server_check_watcher_list(SilcServer server,
    is not watching any nicknames. */
 
 SilcBool silc_server_del_from_watcher_list(SilcServer server,
-                                      SilcClientEntry client)
+                                          SilcClientEntry client)
 {
   SilcHashTableList htl;
   void *key;
@@ -1788,8 +1797,10 @@ SilcBool silc_server_inviteban_match(SilcServer server, SilcHashTable list,
 
 /* Process invite or ban information */
 
-SilcBool silc_server_inviteban_process(SilcServer server, SilcHashTable list,
-                                  SilcUInt8 action, SilcArgumentPayload args)
+SilcBool silc_server_inviteban_process(SilcServer server,
+                                      SilcHashTable list,
+                                      SilcUInt8 action,
+                                      SilcArgumentPayload args)
 {
   unsigned char *tmp;
   SilcUInt32 type, len;
@@ -2179,10 +2190,10 @@ SilcStatus silc_server_set_channel_pk_list(SilcServer server,
    on the `channel' public key list. */
 
 SilcBool silc_server_verify_channel_auth(SilcServer server,
-                                    SilcChannelEntry channel,
-                                    SilcClientID *client_id,
-                                    const unsigned char *auth,
-                                    SilcUInt32 auth_len)
+                                        SilcChannelEntry channel,
+                                        SilcClientID *client_id,
+                                        const unsigned char *auth,
+                                        SilcUInt32 auth_len)
 {
   SilcAuthPayload ap;
   SilcPublicKey chpk;
index e19f2f22566beb5f0e4898a942874e5653c9cea2..7d00e4de4667a8f195d498715e83d8d650752586 100644 (file)
@@ -172,8 +172,8 @@ static SilcBool my_parse_authdata(SilcAuthMethod auth_meth, const char *p,
 
     /* Add the public key to repository */
     if (silc_skr_add_public_key(skr, public_key, usage,
-                               key_context ? key_context : (void *)usage) !=
-       SILC_SKR_OK) {
+                               key_context ? key_context : (void *)usage,
+                               NULL) != SILC_SKR_OK) {
       SILC_SERVER_LOG_ERROR(("Error while adding public key \"%s\"", p));
       return FALSE;
     }
@@ -321,6 +321,23 @@ SILC_CONFIG_CALLBACK(fetch_generic)
     CONFIG_IS_DOUBLE(config->debug_string);
     config->debug_string = (*(char *)val ? strdup((char *) val) : NULL);
   }
+  else if (!strcmp(name, "http_server")) {
+    config->httpd = *(SilcBool *)val;
+  }
+  else if (!strcmp(name, "http_server_ip")) {
+    CONFIG_IS_DOUBLE(config->httpd_ip);
+    config->httpd_ip = (*(char *)val ? strdup((char *) val) : NULL);
+  }
+  else if (!strcmp(name, "http_server_port")) {
+    int port = *(int *)val;
+    if ((port <= 0) || (port > 65535)) {
+      SILC_SERVER_LOG_ERROR(("Error while parsing config file: "
+                            "Invalid port number!"));
+      got_errno = SILC_CONFIG_EPRINTLINE;
+      goto got_err;
+    }
+    config->httpd_port = (SilcUInt16)port;
+  }
   else
     return SILC_CONFIG_EINTERNAL;
 
@@ -1183,6 +1200,9 @@ static const SilcConfigTable table_general[] = {
   { "qos_limit_usec",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
   { "channel_join_limit",      SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
   { "debug_string",                    SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
+  { "http_server",             SILC_CONFIG_ARG_TOGGLE, fetch_generic,  NULL },
+  { "http_server_ip",                  SILC_CONFIG_ARG_STRE,   fetch_generic,  NULL },
+  { "http_server_port",                SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
   { 0, 0, 0, 0 }
 };
 
@@ -1569,6 +1589,7 @@ void silc_server_config_destroy(SilcServerConfig config)
   silc_free(config->param.version_protocol);
   silc_free(config->param.version_software);
   silc_free(config->param.version_software_vendor);
+  silc_free(config->httpd_ip);
 
   /* Destroy Logging channels */
   if (config->logging_info)
index aa7956cbd273cf1ec1b797cab7df69694fe1e79b..7ef873e0797a56131c750d81dcf5c496f16b2eff 100644 (file)
@@ -177,6 +177,9 @@ typedef struct {
   SilcBool logging_quick;
   long logging_flushdelay;
   char *debug_string;
+  SilcBool httpd;
+  char *httpd_ip;
+  SilcUInt16 httpd_port;
 
   /* Other configuration sections */
   SilcServerConfigCipher *cipher;
index 344ebc60ce6d125bb08f9532209fb9ba2664b4f4..5bee97205e76a9181cb0d2d1d2f0cdc64c1837bb 100644 (file)
@@ -327,24 +327,27 @@ SILC_TASK_CALLBACK(dump_stats)
     fprintf(fdd, "  primary router         : %s\n",
       silcd->router->server_name ? silcd->router->server_name : "");
 
-#if 0
-  /* Dump socket connections */
+  /* Dump connections */
   {
-    int i;
     SilcPacketStream s;
-
-    fprintf(fdd, "\nDumping socket connections\n");
-    for (i = 0; i < silcd->config->param.connections_max; i++) {
-      s = silcd->sockets[i];
-      if (!s)
-        continue;
-      fprintf(fdd, "  %d: host %s ip %s port %d type %d flags 0x%x\n",
-             s->sock, s->hostname ? s->hostname : "N/A",
-             s->ip ? s->ip : "N/A", s->port, s->type,
-             (unsigned int)s->flags);
+    SilcDList conns = silc_packet_engine_get_streams(silcd->packet_engine);
+
+    fprintf(fdd, "\nDumping connections\n");
+    silc_dlist_start(conns);
+    while ((s = silc_dlist_get(conns))) {
+      const char *hostname, *ip;
+      SilcUInt16 port;
+      SilcSocket sock;
+      SilcIDListData idata = silc_packet_get_context(s);
+      if (!silc_socket_stream_get_info(silc_packet_stream_get_stream(s), 
+                                      &sock, &hostname, &ip, &port))
+       continue;
+      fprintf(fdd, "  %d: host %s ip %s port %d type %d\n",
+             sock, hostname ? hostname : "N/A",
+             ip ? ip : "N/A", port, idata ? idata->conn_type : 0);
     }
+    silc_dlist_uninit(conns);
   }
-#endif
 
   /* Dump lists */
   {