Added support for removing unconfigured client connections in
authorPekka Riikonen <priikone@silcnet.org>
Mon, 16 Sep 2002 10:21:28 +0000 (10:21 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Mon, 16 Sep 2002 10:21:28 +0000 (10:21 +0000)
rehash in server.
Added support for aborting automatically pending commands that
never receives the reply (to avoid memory leaks).
Preliminary support for handling Rrequested Attributes in WHOIS.

CHANGES
TODO
apps/silcd/command.c
apps/silcd/command.h
apps/silcd/command_reply.c
apps/silcd/idlist.c
apps/silcd/idlist.h
apps/silcd/server.c
apps/silcd/server.h
apps/silcd/server_backup.c
apps/silcd/server_internal.h

diff --git a/CHANGES b/CHANGES
index 0c4b060a2023b6807e8a8527657b375702de2329..e0861f008d37ab6d0a97595080a34d23412b26c9 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,25 @@
+Mon Sep 16 12:02:54 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
+
+       * Added 'app_context' to silc_schedule_init.  It is an
+         application specific context that is delivered to application
+         in task callback functions.  Affected files are
+         lib/silcutil/silcutil.[ch].
+
+Sun Sep 15 22:16:19 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
+
+       * Added support for removing explicitly added client connections
+         in rehash and closing the client connections if they were
+         unconfigured in the rehash.  Affected file silcd/server.c.
+
+       * Added support for aborting automatically pending commands
+         that never receives the reply (to avoid memory leaks).
+         Added also silc_server_command_pending_timed to set the
+         specific timeout for pending command.  Affected files are
+         silcd/command[_reply].[ch].
+
+       * Added SILC_STATUS_ERR_TIMEDOUT status.  Updated protocol
+         specs and lib/silccore/silcstatus.h.
+
 Sun Sep 15 12:25:10 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Changed the silc_get_time to accept time value as argument
diff --git a/TODO b/TODO
index 3b78256bd2001810e7803d90c6468b9851c10344..a1e9ed62453bba1e6617b0685db11f5103c9317c 100644 (file)
--- a/TODO
+++ b/TODO
@@ -36,10 +36,6 @@ TODO/bugs In SILC Server
 
        o Testing
 
- o Close unconfigured client connections in rehash.  When client
-   connections are removed from the config file and rehashed the 
-   connections matching those removed, should be closed.
-
  o Add a timeout to handling incoming JOIN commands.  It should be 
    enforced that JOIN command is executed only once in a second or two
    seconds.  Now it is possible to accept n incoming JOIN commands
index 086836c5645b65fc17cd9b6e1a8574d3d001f671..d5353d81579bce89bd25763b054245d0ef17f3e3 100644 (file)
@@ -325,6 +325,46 @@ silc_server_command_dup(SilcServerCommandContext ctx)
   return ctx;
 }
 
+/* Timeout for pending command.  If reply to pending command never arrives
+   this is called to free resources. */
+
+SILC_TASK_CALLBACK(silc_server_command_pending_timeout)
+{
+  SilcServer server = app_context;
+  SilcServerCommandPending *reply = context;
+  SilcServerCommandReplyContext cmdr;
+  SilcBuffer tmpreply;
+  int i;
+
+  SILC_LOG_DEBUG(("Timeout pending command"));
+
+  /* Allocate temporary and bogus command reply context */
+  cmdr = silc_calloc(1, sizeof(*cmdr));
+  cmdr->server = server;
+  cmdr->ident = reply->ident;
+      
+  /* Check for pending commands and mark to be exeucted */
+  cmdr->callbacks = 
+    silc_server_command_pending_check(server, reply->reply_cmd,
+                                     reply->ident, &cmdr->callbacks_count);
+
+  /* Create bogus command reply with an error inside */
+  tmpreply =
+    silc_command_reply_payload_encode_va(reply->reply_cmd,
+                                        SILC_STATUS_ERR_TIMEDOUT, 0,
+                                        reply->ident, 0);
+  cmdr->payload = silc_command_payload_parse(tmpreply->data, tmpreply->len);
+  silc_buffer_free(tmpreply);
+
+  /* Call all callbacks. Same as SILC_SERVER_PENDING_EXEC macro. */
+  for (i = 0; i < cmdr->callbacks_count; i++)
+    if (cmdr->callbacks[i].callback)
+      (*cmdr->callbacks[i].callback)(cmdr->callbacks[i].context, cmdr);
+
+  silc_server_command_pending_del(server, reply->reply_cmd, reply->ident);
+  silc_server_command_reply_free(cmdr);
+}
+
 /* Add new pending command to be executed when reply to a command has been
    received. The `reply_cmd' is the command that will call the `callback'
    with `context' when reply has been received.  It can be SILC_COMMAND_NONE
@@ -339,6 +379,20 @@ bool silc_server_command_pending(SilcServer server,
                                 SilcUInt16 ident,
                                 SilcCommandCb callback,
                                 void *context)
+{
+  return silc_server_command_pending_timed(server, reply_cmd, ident, callback,
+                                          context, 0);
+}
+
+/* Same as silc_server_command_pending with specific timeout for pending
+   commands.  If the `timeout' is zero default timeout is used. */
+
+bool silc_server_command_pending_timed(SilcServer server,
+                                      SilcCommand reply_cmd,
+                                      SilcUInt16 ident,
+                                      SilcCommandCb callback,
+                                      void *context,
+                                      SilcUInt16 timeout)
 {
   SilcServerCommandPending *reply;
 
@@ -357,6 +411,11 @@ bool silc_server_command_pending(SilcServer server,
   reply->ident = ident;
   reply->context = context;
   reply->callback = callback;
+  reply->timeout =
+    silc_schedule_task_add(server->schedule, 0,
+                          silc_server_command_pending_timeout, reply,
+                          timeout ? timeout : 10, 0,
+                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
   silc_dlist_add(server->pending_commands, reply);
 
   return TRUE;
@@ -376,6 +435,8 @@ void silc_server_command_pending_del(SilcServer server,
                                        r->reply_check))
         && r->ident == ident) {
       silc_dlist_del(server->pending_commands, r);
+      if (r->timeout)
+       silc_schedule_task_del(server->schedule, r->timeout);
       silc_free(r);
     }
   }
@@ -386,7 +447,6 @@ void silc_server_command_pending_del(SilcServer server,
 
 SilcServerCommandPendingCallbacks
 silc_server_command_pending_check(SilcServer server,
-                                 SilcServerCommandReplyContext ctx,
                                  SilcCommand command, 
                                  SilcUInt16 ident,
                                  SilcUInt32 *callbacks_count)
@@ -403,7 +463,6 @@ silc_server_command_pending_check(SilcServer server,
       callbacks[i].context = r->context;
       callbacks[i].callback = r->callback;
       r->reply_check = TRUE;
-      ctx->ident = ident;
       i++;
     }
   }
@@ -477,6 +536,7 @@ silc_server_command_pending_error_check(SilcServerCommandContext cmd,
     SilcBuffer buffer;
 
     /* Send the same command reply payload */
+    silc_command_set_command(cmdr->payload, silc_command_get(cmd->payload));
     silc_command_set_ident(cmdr->payload, 
                           silc_command_get_ident(cmd->payload));
     buffer = silc_command_payload_encode_payload(cmdr->payload);
@@ -523,7 +583,8 @@ silc_server_command_whois_parse(SilcServerCommandContext cmd,
                                char **server_name,
                                int *count,
                                ResolveError *error_client,
-                               SilcUInt32 *error_client_count)
+                               SilcUInt32 *error_client_count,
+                               SilcDList *attrs)
 {
   unsigned char *tmp;
   SilcUInt32 len;
@@ -571,23 +632,30 @@ silc_server_command_whois_parse(SilcServerCommandContext cmd,
   else
     *count = 0;
 
+  /* Get requested attributes if set */
+  tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
+  if (tmp && attrs)
+    *attrs = silc_attribute_payload_parse_list(tmp, len);
+
   return TRUE;
 }
 
 /* Resolve context used by both WHOIS and IDENTIFY commands */
 typedef struct {
-  SilcServerEntry router;
+  SilcSocketConnection sock;
   SilcUInt16 ident;
   unsigned char **res_argv;
   SilcUInt32 *res_argv_lens;
   SilcUInt32 *res_argv_types;
   SilcUInt32 res_argc;
+  SilcUInt32 res_timeout;
 } *SilcServerResolveContext;
 
 static bool
 silc_server_command_whois_check(SilcServerCommandContext cmd,
                                SilcClientEntry *clients,
-                               SilcUInt32 clients_count)
+                               SilcUInt32 clients_count,
+                               SilcDList attrs)
 {
   SilcServer server = cmd->server;
   SilcClientEntry entry;
@@ -603,31 +671,46 @@ silc_server_command_whois_check(SilcServerCommandContext cmd,
     if (!entry)
       continue;
 
-    if ((entry->nickname && entry->username && entry->userinfo) ||
-       !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
-      if (!entry->router)
-       continue;
-
-      /* If we are normal server, and we've not resolved this client from
-        router and it is global client, we'll check whether it is on some
-        channel.  If not then we cannot be sure about its validity, and
-        we'll resolve it from router. */
-      if (cmd->server->server_type != SILC_SERVER || cmd->pending ||
-         entry->connection || silc_hash_table_count(entry->channels))
-       continue;
+    /* If requested attributes is set then we always resolve the client
+       information, if not then check whether the entry is complete or not
+       and decide whether we need to resolve or not.  Usually attributes
+       are not present so the this test is performed all the time. */
+    if (!attrs) {
+      if ((entry->nickname && entry->username && entry->userinfo) ||
+         !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
+       if (!entry->router)
+         continue;
+
+       /* If we are normal server, and we've not resolved this client from
+          router and it is global client, we'll check whether it is on some
+          channel.  If not then we cannot be sure about its validity, and
+          we'll resolve it from router. */
+       if (cmd->server->server_type != SILC_SERVER || cmd->pending ||
+           entry->connection || silc_hash_table_count(entry->channels))
+         continue;
+      }
     }
 
+    /* When requested attributes is present and local client is detached
+       we cannot send the command to the client, we'll reply on behalf of
+       the client instead. */
+    if (attrs && SILC_IS_LOCAL(entry) && entry->mode & SILC_UMODE_DETACHED)
+      continue;
+
     /* We need to resolve this entry since it is not complete */
 
     if (!cmd->pending && entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
       /* The entry is being resolved (and we are not the resolver) so attach
         to the command reply and we're done with this one. */
-      silc_server_command_pending(server, SILC_COMMAND_NONE, 
+      silc_server_command_pending(server, SILC_COMMAND_NONE,
                                  entry->resolve_cmd_ident,
                                  silc_server_command_whois,
                                  silc_server_command_dup(cmd));
       no_res = FALSE;
     } else {
+      SilcBuffer idp;
+      SilcSocketConnection sock;
+
       if (entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
        /* We've resolved this and it still is not ready.  We'll return
           and are that this will be handled again after it is resolved. */
@@ -640,28 +723,72 @@ silc_server_command_whois_check(SilcServerCommandContext cmd,
        }
        silc_free(resolve);
        return FALSE;
-      } else {
-       /* We'll resolve this client */
-       SilcBuffer idp;
+      }
 
-       r = NULL;
-       for (k = 0; k < resolve_count; k++) {
-         if (resolve[k].router == entry->router) {
-           r = &resolve[k];
-           break;
-         }
-       }
+      /* We'll resolve this client now */
 
-       if (!r) {
-         resolve = silc_realloc(resolve, sizeof(*resolve) * 
-                                (resolve_count + 1));
-         r = &resolve[resolve_count];
-         memset(r, 0, sizeof(*r));
-         r->router = entry->router;
-         r->ident = ++server->cmd_ident;
-         resolve_count++;
+      sock = (SILC_IS_LOCAL(entry) ? entry->connection :
+             entry->router->connection);
+      if (!sock)
+       continue;
+
+      r = NULL;
+      for (k = 0; k < resolve_count; k++) {
+       if (resolve[k].sock == sock) {
+         r = &resolve[k];
+         break;
        }
+      }
+
+      if (!r) {
+       resolve = silc_realloc(resolve, sizeof(*resolve) * 
+                              (resolve_count + 1));
+       r = &resolve[resolve_count];
+       memset(r, 0, sizeof(*r));
+       r->sock = sock;
+       r->ident = ++server->cmd_ident;
+       if (SILC_IS_LOCAL(entry))
+         r->res_timeout = 2;
+       else
+         r->res_timeout = 0;
+       resolve_count++;
+      }
+
+      r->res_argv = silc_realloc(r->res_argv, sizeof(*r->res_argv) *
+                                (r->res_argc + 1));
+      r->res_argv_lens = silc_realloc(r->res_argv_lens, 
+                                     sizeof(*r->res_argv_lens) *
+                                     (r->res_argc + 1));
+      r->res_argv_types = silc_realloc(r->res_argv_types, 
+                                      sizeof(*r->res_argv_types) *
+                                      (r->res_argc + 1));
+      idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+      r->res_argv[r->res_argc] = silc_calloc(idp->len, 
+                                            sizeof(**r->res_argv));
+      memcpy(r->res_argv[r->res_argc], idp->data, idp->len);
+      r->res_argv_lens[r->res_argc] = idp->len;
+      r->res_argv_types[r->res_argc] = r->res_argc + 4;
+      r->res_argc++;
+      silc_buffer_free(idp);
 
+      entry->resolve_cmd_ident = r->ident;
+      entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
+      entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
+    }
+  }
+
+  /* Do the resolving */
+  for (i = 0; i < resolve_count; i++) {
+    SilcBuffer res_cmd;
+    unsigned char *attrs_buf;
+    SilcUInt32 attrs_buf_len;
+
+    r = &resolve[i];
+
+    /* If attributes were present put them to this resolving as well */
+    if (attrs) {
+      attrs_buf = silc_argument_get_arg_type(cmd->args, 3, &attrs_buf_len);
+      if (attrs_buf) {
        r->res_argv = silc_realloc(r->res_argv, sizeof(*r->res_argv) *
                                   (r->res_argc + 1));
        r->res_argv_lens = silc_realloc(r->res_argv_lens, 
@@ -670,44 +797,28 @@ silc_server_command_whois_check(SilcServerCommandContext cmd,
        r->res_argv_types = silc_realloc(r->res_argv_types, 
                                         sizeof(*r->res_argv_types) *
                                         (r->res_argc + 1));
-       idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
-       r->res_argv[r->res_argc] = silc_calloc(idp->len, 
-                                              sizeof(**r->res_argv));
-       memcpy(r->res_argv[r->res_argc], idp->data, idp->len);
-       r->res_argv_lens[r->res_argc] = idp->len;
-       r->res_argv_types[r->res_argc] = r->res_argc + 4;
+       r->res_argv[r->res_argc] = silc_memdup(attrs_buf, attrs_buf_len);
+       r->res_argv_lens[r->res_argc] = attrs_buf_len;
+       r->res_argv_types[r->res_argc] = 3;
        r->res_argc++;
-       silc_buffer_free(idp);
-
-       entry->resolve_cmd_ident = r->ident;
-       entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
-       entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
       }
     }
-  }
 
-  /* Do the resolving */
-  for (i = 0; i < resolve_count; i++) {
-    SilcBuffer res_cmd;
-
-    r = &resolve[i];
-
-    /* Send WHOIS request. We send WHOIS since we're doing the requesting
-       now anyway so make it a good one. */
+    /* Send WHOIS command */
     res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
                                          r->res_argc, r->res_argv, 
                                          r->res_argv_lens,
                                          r->res_argv_types, 
                                          r->ident);
-    silc_server_packet_send(server, r->router->connection,
-                           SILC_PACKET_COMMAND, cmd->packet->flags,
-                           res_cmd->data, res_cmd->len, FALSE);
+    silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND,
+                           cmd->packet->flags, res_cmd->data,
+                           res_cmd->len, FALSE);
 
     /* Reprocess this packet after received reply */
-    silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
-                               r->ident,
-                               silc_server_command_whois,
-                               silc_server_command_dup(cmd));
+    silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS, r->ident,
+                                     silc_server_command_whois,
+                                     silc_server_command_dup(cmd),
+                                     r->res_timeout);
     cmd->pending = TRUE;
 
     silc_buffer_free(res_cmd);
@@ -937,13 +1048,15 @@ silc_server_command_whois_process(SilcServerCommandContext cmd)
   SilcClientID **client_id = NULL;
   SilcUInt32 client_id_count = 0, clients_count = 0, error_client_count = 0;
   ResolveError error_client = NULL;
+  SilcDList attrs = NULL;
   int i, ret = 0;
   bool check_global = FALSE;
 
   /* Parse the whois request */
-  if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count, 
+  if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count,
                                       &nick, &server_name, &count,
-                                      &error_client, &error_client_count))
+                                      &error_client, &error_client_count,
+                                      &attrs))
     return 0;
 
   /* Send the WHOIS request to the router only if it included nickname.
@@ -967,43 +1080,43 @@ silc_server_command_whois_process(SilcServerCommandContext cmd)
   if (client_id_count) {
     /* Check all Client ID's received in the command packet */
     for (i = 0; i < client_id_count; i++) {
-      entry = silc_idlist_find_client_by_id(server->local_list, 
+      entry = silc_idlist_find_client_by_id(server->local_list,
                                            client_id[i], TRUE, NULL);
       if (!entry && check_global)
-       entry = silc_idlist_find_client_by_id(server->global_list, 
+       entry = silc_idlist_find_client_by_id(server->global_list,
                                              client_id[i], TRUE, NULL);
       if (entry) {
-       clients = silc_realloc(clients, sizeof(*clients) * 
+       clients = silc_realloc(clients, sizeof(*clients) *
                               (clients_count + 1));
        clients[clients_count++] = entry;
       } else {
        /* If we are normal server and did not send the request first to router
           do it now, since we do not have the Client ID information. */
        if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
-           server->server_type == SILC_SERVER && !cmd->pending && 
+           server->server_type == SILC_SERVER && !cmd->pending &&
            !server->standalone) {
          silc_server_command_whois_send_router(cmd);
          ret = -1;
          goto out;
        }
 
-       ADD_ERROR(error_client, error_client_count, client_id[i], 
+       ADD_ERROR(error_client, error_client_count, client_id[i],
                  SILC_ID_CLIENT, 0, SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
       }
     }
   } else if (nick) {
     /* Find by nickname */
-    if (!silc_idlist_get_clients_by_hash(server->local_list, 
+    if (!silc_idlist_get_clients_by_hash(server->local_list,
                                         nick, server->md5hash,
                                         &clients, &clients_count))
-      silc_idlist_get_clients_by_nickname(server->local_list, 
+      silc_idlist_get_clients_by_nickname(server->local_list,
                                          nick, server_name,
                                          &clients, &clients_count);
     if (check_global) {
-      if (!silc_idlist_get_clients_by_hash(server->global_list, 
+      if (!silc_idlist_get_clients_by_hash(server->global_list,
                                           nick, server->md5hash,
                                           &clients, &clients_count))
-       silc_idlist_get_clients_by_nickname(server->global_list, 
+       silc_idlist_get_clients_by_nickname(server->global_list,
                                            nick, server_name,
                                            &clients, &clients_count);
     }
@@ -1013,7 +1126,7 @@ silc_server_command_whois_process(SilcServerCommandContext cmd)
     /* If we are normal server and did not send the request first to router
        do it now, since we do not have the information. */
     if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
-       server->server_type == SILC_SERVER && !cmd->pending && 
+       server->server_type == SILC_SERVER && !cmd->pending &&
        !server->standalone) {
       silc_server_command_whois_send_router(cmd);
       ret = -1;
@@ -1037,7 +1150,7 @@ silc_server_command_whois_process(SilcServerCommandContext cmd)
      mandatory fields that WHOIS command reply requires. Check for these and
      make query from the server who owns the client if some fields are 
      missing. */
-  if (!silc_server_command_whois_check(cmd, clients, clients_count)) {
+  if (!silc_server_command_whois_check(cmd, clients, clients_count, attrs)) {
     ret = -1;
     goto out;
   }
@@ -1057,6 +1170,8 @@ silc_server_command_whois_process(SilcServerCommandContext cmd)
   silc_free(error_client);
   silc_free(nick);
   silc_free(server_name);
+  if (attrs)
+    silc_attribute_payload_list_free(attrs);
 
   return ret;
 }
@@ -1707,7 +1822,7 @@ silc_server_command_identify_check_client(SilcServerCommandContext cmd,
 
        r = NULL;
        for (k = 0; k < resolve_count; k++) {
-         if (resolve[k].router == entry->router) {
+         if (resolve[k].sock == entry->router->connection) {
            r = &resolve[k];
            break;
          }
@@ -1718,7 +1833,7 @@ silc_server_command_identify_check_client(SilcServerCommandContext cmd,
                                 (resolve_count + 1));
          r = &resolve[resolve_count];
          memset(r, 0, sizeof(*r));
-         r->router = entry->router;
+         r->sock = entry->router->connection;
          r->ident = ++server->cmd_ident;
          resolve_count++;
        }
@@ -1760,9 +1875,9 @@ silc_server_command_identify_check_client(SilcServerCommandContext cmd,
                                          r->res_argv_lens,
                                          r->res_argv_types, 
                                          r->ident);
-    silc_server_packet_send(server, r->router->connection,
-                           SILC_PACKET_COMMAND, cmd->packet->flags,
-                           res_cmd->data, res_cmd->len, FALSE);
+    silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND,
+                           cmd->packet->flags, res_cmd->data,
+                           res_cmd->len, FALSE);
 
     /* Reprocess this packet after received reply */
     silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
@@ -2727,7 +2842,6 @@ SILC_SERVER_CMD_FUNC(invite)
 }
 
 typedef struct {
-  SilcServer server;
   SilcSocketConnection sock;
   char *signoff;
 } *QuitInternal;
@@ -2737,17 +2851,19 @@ typedef struct {
 
 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
 {
+  SilcServer server = app_context;
   QuitInternal q = (QuitInternal)context;
 
   /* Free all client specific data, such as client entry and entires
      on channels this client may be on. */
-  silc_server_free_client_data(q->server, q->sock, q->sock->user_data,
+  silc_server_free_client_data(server, q->sock, q->sock->user_data,
                               TRUE, q->signoff);
   q->sock->user_data = NULL;
 
   /* Close the connection on our side */
-  silc_server_close_connection(q->server, q->sock);
+  silc_server_close_connection(server, q->sock);
 
+  silc_socket_free(q->sock);
   silc_free(q->signoff);
   silc_free(q);
 }
@@ -2774,8 +2890,7 @@ SILC_SERVER_CMD_FUNC(quit)
     tmp = NULL;
 
   q = silc_calloc(1, sizeof(*q));
-  q->server = server;
-  q->sock = sock;
+  q->sock = silc_socket_dup(sock);
   q->signoff = tmp ? strdup(tmp) : NULL;
 
   /* We quit the connection with little timeout */
@@ -4990,25 +5105,26 @@ SILC_SERVER_CMD_FUNC(oper)
 
 SILC_TASK_CALLBACK(silc_server_command_detach_cb)
 {
+  SilcServer server = app_context;
   QuitInternal q = (QuitInternal)context;
   SilcClientID *client_id = (SilcClientID *)q->sock;
   SilcClientEntry client;
   SilcSocketConnection sock;
 
-  client = silc_idlist_find_client_by_id(q->server->local_list, client_id,
+  client = silc_idlist_find_client_by_id(server->local_list, client_id,
                                         TRUE, NULL);
   if (client && client->connection) {
     sock = client->connection;
 
     /* If there is pending outgoing data for the client then purge it
        to the network before closing connection. */
-    silc_server_packet_queue_purge(q->server, sock);
+    silc_server_packet_queue_purge(server, sock);
 
     /* Close the connection on our side */
     client->router = NULL;
     client->connection = NULL;
     sock->user_data = NULL;
-    silc_server_close_connection(q->server, sock);
+    silc_server_close_connection(server, sock);
   }
 
   silc_free(client_id);
@@ -5017,15 +5133,16 @@ SILC_TASK_CALLBACK(silc_server_command_detach_cb)
 
 SILC_TASK_CALLBACK(silc_server_command_detach_timeout)
 {
+  SilcServer server = app_context;
   QuitInternal q = (QuitInternal)context;
   SilcClientID *client_id = (SilcClientID *)q->sock;
   SilcClientEntry client;
 
-  client = silc_idlist_find_client_by_id(q->server->local_list, client_id,
+  client = silc_idlist_find_client_by_id(server->local_list, client_id,
                                         TRUE, NULL);
   if (client && client->mode & SILC_UMODE_DETACHED) {
     SILC_LOG_DEBUG(("Detach timeout"));
-    silc_server_free_client_data(q->server, NULL, client, TRUE,
+    silc_server_free_client_data(server, NULL, client, TRUE,
                                 "Detach timeout");
   }
 
@@ -5075,14 +5192,12 @@ SILC_SERVER_CMD_FUNC(detach)
                                   SILC_NOTIFY_TYPE_UMODE_CHANGE);
 
   q = silc_calloc(1, sizeof(*q));
-  q->server = server;
   q->sock = silc_id_dup(client->id, SILC_ID_CLIENT);
   silc_schedule_task_add(server->schedule, 0, silc_server_command_detach_cb,
                         q, 0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
 
   if (server->config->detach_timeout) {
     q = silc_calloc(1, sizeof(*q));
-    q->server = server;
     q->sock = silc_id_dup(client->id, SILC_ID_CLIENT);
     silc_schedule_task_add(server->schedule, 0, 
                           silc_server_command_detach_timeout,
index 2e3273d6142c9bc029539f3ccd0f0e94689241c6..9cd04d79171152ca71cd5b48637173f51a0dc41a 100644 (file)
@@ -61,12 +61,12 @@ typedef struct {
 /* Structure holding pending commands. If command is pending it will be
    executed after command reply has been received and executed. */
 typedef struct SilcServerCommandPendingStruct {
-  SilcServer server;
   SilcCommand reply_cmd;
   SilcUInt16 ident;
   unsigned int reply_check : 8;
   SilcCommandCb callback;
   void *context;
+  SilcTask timeout;
   struct SilcServerCommandPendingStruct *next;
 } SilcServerCommandPending;
 
@@ -111,12 +111,17 @@ bool silc_server_command_pending(SilcServer server,
                                 SilcUInt16 ident,
                                 SilcCommandCb callback,
                                 void *context);
+bool silc_server_command_pending_timed(SilcServer server,
+                                      SilcCommand reply_cmd,
+                                      SilcUInt16 ident,
+                                      SilcCommandCb callback,
+                                      void *context,
+                                      SilcUInt16 timeout);
 void silc_server_command_pending_del(SilcServer server,
                                     SilcCommand reply_cmd,
                                     SilcUInt16 ident);
 SilcServerCommandPendingCallbacks
 silc_server_command_pending_check(SilcServer server,
-                                 SilcServerCommandReplyContext ctx,
                                  SilcCommand command, 
                                  SilcUInt16 ident,
                                  SilcUInt32 *callbacks_count);
index ecf6f3c22ff8614c6801093b7cee17d2ed9cc8c6..bff81fa6644965d02569106e54f6924721fe894d 100644 (file)
@@ -66,7 +66,6 @@ void silc_server_command_reply_process(SilcServer server,
   SilcServerCommandReplyContext ctx;
   SilcCommandPayload payload;
   SilcCommand command;
-  SilcUInt16 ident;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -85,13 +84,12 @@ void silc_server_command_reply_process(SilcServer server,
   ctx->sock = silc_socket_dup(sock);
   ctx->payload = payload;
   ctx->args = silc_command_get_args(ctx->payload);
-  ident = silc_command_get_ident(ctx->payload);
+  ctx->ident = silc_command_get_ident(ctx->payload);
       
   /* Check for pending commands and mark to be exeucted */
   ctx->callbacks = 
-    silc_server_command_pending_check(server, ctx, 
-                                     silc_command_get(ctx->payload), 
-                                     ident, &ctx->callbacks_count);
+    silc_server_command_pending_check(server, silc_command_get(ctx->payload), 
+                                     ctx->ident, &ctx->callbacks_count);
 
   /* Execute command reply */
   command = silc_command_get(ctx->payload);
index 883319034af96adfdf022ebde913794e5ea572c1..900092bfbdf7cebd6b0eab200b404cbbb07cb910 100644 (file)
@@ -90,13 +90,13 @@ void silc_idlist_del_data(void *entry)
 
 SILC_TASK_CALLBACK_GLOBAL(silc_idlist_purge)
 {
+  SilcServer server = app_context;
   SilcIDListPurge i = (SilcIDListPurge)context;
 
   SILC_LOG_DEBUG(("Purging cache"));
 
   silc_idcache_purge(i->cache);
-  silc_schedule_task_add(i->schedule, 0, 
-                        silc_idlist_purge,
+  silc_schedule_task_add(server->schedule, 0, silc_idlist_purge,
                         (void *)i, i->timeout, 0,
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
 }
index 64171f7d9adacefcd50d4a8ae5fd7bfcf6fdb530..ac417a795db7694deb26ca0bedfd2056211ed294 100644 (file)
@@ -30,13 +30,11 @@ typedef struct SilcChannelEntryStruct *SilcChannelEntry;
    the cache. */
 typedef struct {
   SilcIDCache cache;
-  SilcSchedule schedule;
   SilcUInt32 timeout;
 } *SilcIDListPurge;
 
 /* Channel key re-key context. */
 typedef struct {
-  void *context;
   SilcChannelEntry channel;
   SilcUInt32 key_len;
   SilcTask task;
index f5e6b7fcffb001cc904539011cb935ff6cf5f77f..d75fdd803526407382be26878b938fb64ef393cf 100644 (file)
@@ -320,7 +320,8 @@ bool silc_server_init(SilcServer server)
   silc_pkcs_private_key_set(server->pkcs, server->private_key);
 
   /* Initialize the scheduler */
-  server->schedule = silc_schedule_init(server->config->param.connections_max);
+  server->schedule = silc_schedule_init(server->config->param.connections_max,
+                                       server);
   if (!server->schedule)
     goto err;
 
@@ -474,27 +475,23 @@ bool silc_server_init(SilcServer server)
   /* Clients local list */
   server->purge_i = purge = silc_calloc(1, sizeof(*purge));
   purge->cache = server->local_list->clients;
-  purge->schedule = server->schedule;
   purge->timeout = 600;
-  silc_schedule_task_add(purge->schedule, 0,
-                        silc_idlist_purge,
+  silc_schedule_task_add(server->schedule, 0, silc_idlist_purge,
                         (void *)purge, purge->timeout, 0,
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
 
   /* Clients global list */
   server->purge_g = purge = silc_calloc(1, sizeof(*purge));
   purge->cache = server->global_list->clients;
-  purge->schedule = server->schedule;
   purge->timeout = 300;
-  silc_schedule_task_add(purge->schedule, 0,
-                        silc_idlist_purge,
+  silc_schedule_task_add(server->schedule, 0, silc_idlist_purge,
                         (void *)purge, purge->timeout, 0,
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
 
   /* If we are normal server we'll retrieve network statisticial information
      once in a while from the router. */
   if (server->server_type == SILC_SERVER)
-    silc_schedule_task_add(purge->schedule, 0, silc_server_get_stats,
+    silc_schedule_task_add(server->schedule, 0, silc_server_get_stats,
                           server, 10, 0, SILC_TASK_TIMEOUT,
                           SILC_TASK_PRI_LOW);
 
@@ -618,14 +615,15 @@ bool silc_server_rehash(SilcServer server)
 
       /* Check whether new config has this one too */
       for (newptr = newconfig->routers; newptr; newptr = newptr->next) {
-       if (!strcmp(newptr->host, ptr->host) && newptr->port == ptr->port &&
+       if (silc_string_compare(newptr->host, ptr->host) && 
+           newptr->port == ptr->port &&
            newptr->initiator == ptr->initiator) {
          found = TRUE;
          break;
        }
       }
 
-      if (!found) {
+      if (!found && ptr->host) {
        /* Remove this connection */
        SilcSocketConnection sock;
        sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
@@ -649,13 +647,13 @@ bool silc_server_rehash(SilcServer server)
 
       /* Check whether new config has this one too */
       for (newptr = newconfig->servers; newptr; newptr = newptr->next) {
-       if (!strcmp(newptr->host, ptr->host)) {
+       if (silc_string_compare(newptr->host, ptr->host)) {
          found = TRUE;
          break;
        }
       }
 
-      if (!found) {
+      if (!found && ptr->host) {
        /* Remove this connection */
        SilcSocketConnection sock;
        sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_SERVER,
@@ -669,6 +667,36 @@ bool silc_server_rehash(SilcServer server)
     }
   }
 
+  if (server->config->clients) {
+    SilcServerConfigClient *ptr;
+    SilcServerConfigClient *newptr;
+    bool found;
+
+    for (ptr = server->config->clients; ptr; ptr = ptr->next) {
+      found = FALSE;
+
+      /* Check whether new config has this one too */
+      for (newptr = newconfig->clients; newptr; newptr = newptr->next) {
+       if (silc_string_compare(newptr->host, ptr->host)) {
+         found = TRUE;
+         break;
+       }
+      }
+
+      if (!found && ptr->host) {
+       /* Remove this connection */
+       SilcSocketConnection sock;
+       sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_CLIENT,
+                                              ptr->host, 0);
+       if (sock)
+         silc_schedule_task_add(server->schedule, sock->sock,
+                                silc_server_rehash_close_connection,
+                                server, 0, 1, SILC_TASK_TIMEOUT,
+                                SILC_TASK_PRI_NORMAL);
+      }
+    }
+  }
+
   /* Go through all configured routers after rehash */
   silc_schedule_task_add(server->schedule, 0,
                         silc_server_connect_to_router,
@@ -860,8 +888,8 @@ void silc_server_start_key_exchange(SilcServer server,
 
 SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
 {
+  SilcServer server = app_context;
   SilcServerConnection sconn = (SilcServerConnection)context;
-  SilcServer server = sconn->server;
   SilcServerConfigRouter *conn = sconn->conn.ref_ptr;
   SilcServerConfigConnParams *param =
                (conn->param ? conn->param : &server->config->param);
@@ -916,8 +944,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
 
 SILC_TASK_CALLBACK(silc_server_connect_router)
 {
+  SilcServer server = app_context;
   SilcServerConnection sconn = (SilcServerConnection)context;
-  SilcServer server = sconn->server;
   SilcServerConfigRouter *rconn;
   int sock;
 
@@ -1030,7 +1058,6 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
 
       /* Allocate connection object for hold connection specific stuff. */
       sconn = silc_calloc(1, sizeof(*sconn));
-      sconn->server = server;
       sconn->remote_host = strdup(ptr->host);
       sconn->remote_port = ptr->port;
       sconn->backup = ptr->backup_router;
@@ -1248,7 +1275,6 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   SilcSocketConnection sock = ctx->sock;
   SilcServerEntry id_entry = NULL;
   SilcBuffer packet;
-  SilcServerHBContext hb_context;
   unsigned char *id_string;
   SilcUInt32 id_len;
   SilcIDListData idata;
@@ -1352,15 +1378,12 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
 
   /* Perform keepalive. The `hb_context' will be freed automatically
      when finally calling the silc_socket_free function. */
-  hb_context = silc_calloc(1, sizeof(*hb_context));
-  hb_context->server = server;
-  silc_socket_set_heartbeat(sock, param->keepalive_secs, hb_context,
+  silc_socket_set_heartbeat(sock, param->keepalive_secs, server,
                            silc_server_perform_heartbeat,
                            server->schedule);
 
   /* Register re-key timeout */
   idata->rekey->timeout = param->key_exchange_rekey;
-  idata->rekey->context = (void *)server;
   silc_schedule_task_add(server->schedule, sock->sock,
                         silc_server_rekey_callback,
                         (void *)sock, idata->rekey->timeout, 0,
@@ -1750,7 +1773,6 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
     (SilcServerConnAuthInternalContext *)protocol->context;
   SilcServer server = (SilcServer)ctx->server;
   SilcSocketConnection sock = ctx->sock;
-  SilcServerHBContext hb_context;
   SilcUnknownEntry entry = (SilcUnknownEntry)sock->user_data;
   void *id_entry;
   SilcUInt32 hearbeat_timeout = server->config->param.keepalive_secs;
@@ -2063,9 +2085,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
 
   /* Perform keepalive. The `hb_context' will be freed automatically
      when finally calling the silc_socket_free function. */
-  hb_context = silc_calloc(1, sizeof(*hb_context));
-  hb_context->server = server;
-  silc_socket_set_heartbeat(sock, hearbeat_timeout, hb_context,
+  silc_socket_set_heartbeat(sock, hearbeat_timeout, server,
                            silc_server_perform_heartbeat,
                            server->schedule);
 
@@ -2341,7 +2361,7 @@ bool silc_server_packet_parse(SilcPacketParserContext *parser_context,
       (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,
+    silc_server_packet_parse_real(server->schedule, server, 0, sock->sock,
                                  parser_context);
 
     /* Reprocess data since we'll return FALSE here.  This is because
@@ -2372,7 +2392,7 @@ bool silc_server_packet_parse(SilcPacketParserContext *parser_context,
   case SILC_SOCKET_TYPE_SERVER:
   case SILC_SOCKET_TYPE_ROUTER:
     /* Packets from servers are parsed immediately */
-    silc_server_packet_parse_real(server->schedule, 0, sock->sock,
+    silc_server_packet_parse_real(server->schedule, server, 0, sock->sock,
                                  parser_context);
     break;
   default:
@@ -2449,13 +2469,12 @@ void silc_server_packet_parse_type(SilcServer server,
     if (sock->protocol) {
       SilcServerFailureContext f;
       f = silc_calloc(1, sizeof(*f));
-      f->server = server;
-      f->sock = sock;
+      f->sock = silc_socket_dup(sock);
 
       /* We will wait 5 seconds to process this failure packet */
       silc_schedule_task_add(server->schedule, sock->sock,
-                        silc_server_failure_callback, (void *)f, 5, 0,
-                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+                            silc_server_failure_callback, (void *)f, 5, 0,
+                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
     }
     break;
 
@@ -2831,7 +2850,6 @@ void silc_server_create_connection(SilcServer server,
 
   /* Allocate connection object for hold connection specific stuff. */
   sconn = silc_calloc(1, sizeof(*sconn));
-  sconn->server = server;
   sconn->remote_host = strdup(remote_host);
   sconn->remote_port = port;
   sconn->no_reconnect = TRUE;
@@ -2957,20 +2975,15 @@ void silc_server_disconnect_remote(SilcServer server,
   silc_server_close_connection(server, sock);
 }
 
-typedef struct {
-  SilcServer server;
-  SilcClientEntry client;
-} *FreeClientInternal;
-
 SILC_TASK_CALLBACK(silc_server_free_client_data_timeout)
 {
-  FreeClientInternal i = (FreeClientInternal)context;
+  SilcServer server = app_context;
+  SilcClientEntry client = context;
 
-  assert(!silc_hash_table_count(i->client->channels));
+  assert(!silc_hash_table_count(client->channels));
 
-  silc_idlist_del_data(i->client);
-  silc_idcache_purge_by_context(i->server->local_list->clients, i->client);
-  silc_free(i);
+  silc_idlist_del_data(client);
+  silc_idcache_purge_by_context(server->local_list->clients, client);
 }
 
 /* Frees client data and notifies about client's signoff. */
@@ -2983,16 +2996,6 @@ void silc_server_free_client_data(SilcServer server,
 {
   SILC_LOG_DEBUG(("Freeing client data"));
 
-#if 1
-  if (!client->router && !client->connection &&
-      !(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
-    SILC_LOG_ERROR(("****** freeing data for already unregistered client -s"));
-    SILC_LOG_ERROR(("****** Contact Pekka"));
-    SILC_LOG_ERROR(("****** freeing data for already unregistered client -e"));
-    return;
-  }
-#endif
-
   /* If there is pending outgoing data for the client then purge it
      to the network before removing the client entry. */
   silc_server_packet_queue_purge(server, sock);
@@ -3034,12 +3037,9 @@ void silc_server_free_client_data(SilcServer server,
      into history (for WHOWAS command) for 5 minutes, unless we're
      shutting down server. */
   if (!server->server_shutdown) {
-    FreeClientInternal i = silc_calloc(1, sizeof(*i));
-    i->server = server;
-    i->client = client;
     silc_schedule_task_add(server->schedule, 0,
                           silc_server_free_client_data_timeout,
-                          (void *)i, 300, 0,
+                          client, 300, 0,
                           SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
     client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
     client->data.status &= ~SILC_IDLIST_STATUS_LOCAL;
@@ -3693,8 +3693,8 @@ silc_server_create_new_channel_with_id(SilcServer server,
 
 SILC_TASK_CALLBACK(silc_server_channel_key_rekey)
 {
+  SilcServer server = app_context;
   SilcServerChannelRekey rekey = (SilcServerChannelRekey)context;
-  SilcServer server = (SilcServer)rekey->context;
 
   rekey->task = NULL;
 
@@ -3768,7 +3768,6 @@ bool silc_server_create_channel_key(SilcServer server,
   if (server->server_type == SILC_ROUTER) {
     if (!channel->rekey)
       channel->rekey = silc_calloc(1, sizeof(*channel->rekey));
-    channel->rekey->context = (void *)server;
     channel->rekey->channel = channel;
     channel->rekey->key_len = key_len;
     if (channel->rekey->task)
@@ -3882,7 +3881,6 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
   if (server->server_type == SILC_ROUTER) {
     if (!channel->rekey)
       channel->rekey = silc_calloc(1, sizeof(*channel->rekey));
-    channel->rekey->context = (void *)server;
     channel->rekey->channel = channel;
     if (channel->rekey->task)
       silc_schedule_task_del(server->schedule, channel->rekey->task);
@@ -3911,13 +3909,13 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
 void silc_server_perform_heartbeat(SilcSocketConnection sock,
                                   void *hb_context)
 {
-  SilcServerHBContext hb = (SilcServerHBContext)hb_context;
+  SilcServer server = hb_context;
 
   SILC_LOG_DEBUG(("Sending heartbeat to %s:%d (%s)", sock->hostname, 
                 sock->port, sock->ip));
 
   /* Send the heartbeat */
-  silc_server_send_heartbeat(hb->server, sock);
+  silc_server_send_heartbeat(server, sock);
 }
 
 /* Returns assembled of all servers in the given ID list. The packet's
@@ -4507,13 +4505,15 @@ void silc_server_announce_channels(SilcServer server,
 
 SILC_TASK_CALLBACK(silc_server_failure_callback)
 {
+  SilcServer server = app_context;
   SilcServerFailureContext f = (SilcServerFailureContext)context;
 
   if (f->sock->protocol) {
     f->sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
-    silc_protocol_execute(f->sock->protocol, f->server->schedule, 0, 0);
+    silc_protocol_execute(f->sock->protocol, server->schedule, 0, 0);
   }
 
+  silc_socket_free(f->sock);
   silc_free(f);
 }
 
@@ -4996,9 +4996,9 @@ SilcClientEntry silc_server_get_client_resolve(SilcServer server,
 
 SILC_TASK_CALLBACK(silc_server_rekey_callback)
 {
+  SilcServer server = app_context;
   SilcSocketConnection sock = (SilcSocketConnection)context;
   SilcIDListData idata = (SilcIDListData)sock->user_data;
-  SilcServer server = (SilcServer)idata->rekey->context;
   SilcProtocol protocol;
   SilcServerRekeyInternalContext *proto_ctx;
 
index 3fec0d75d71d56a339909a7edf24a7ae32933d72..5757fefc31f488b45f5027f649d8cf7be7c1d5de 100644 (file)
@@ -50,9 +50,6 @@ typedef struct {
   SilcUInt32 retry_count;
   SilcUInt32 retry_timeout;
 
-  /* Back pointer to server */
-  SilcServer server;
-
   SilcServerConnectRouterCallback callback;
   void *callback_context;
 } *SilcServerConnection;
index ae8d0a762a049c922d1efff04126d61a95888b38..196ab565c3324d3acb19e93a2d132150d113e530 100644 (file)
@@ -541,8 +541,8 @@ void silc_server_backup_resume_router(SilcServer server,
 
 SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
 {
+  SilcServer server = app_context;
   SilcServerConnection sconn = (SilcServerConnection)context;
-  SilcServer server = sconn->server;
   int sock;
   const char *server_ip;
 
@@ -578,7 +578,6 @@ void silc_server_backup_reconnect(SilcServer server,
   SilcServerConnection sconn;
 
   sconn = silc_calloc(1, sizeof(*sconn));
-  sconn->server = server;
   sconn->remote_host = strdup(ip);
   sconn->remote_port = port;
   sconn->callback = callback;
index 35eb1d8986a2b7977d26af7e665dc8a7041bb941..64141a70ce58902254d8848040aa2ba976b519ee 100644 (file)
@@ -146,16 +146,10 @@ struct SilcServerStruct {
 #endif
 };
 
-/* Server's heartbeat context */
-typedef struct {
-  SilcServer server;
-} *SilcServerHBContext;
-
 /* Failure context. This is allocated when failure packet is received.
    Failure packets are processed with timeout and data is saved in this
    structure. */
 typedef struct {
-  SilcServer server;
   SilcSocketConnection sock;
   SilcUInt32 failure;
 } *SilcServerFailureContext;