+Mon Feb 19 14:26:49 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Changed SILC_SERVER_COMMAND_EXEC_PENDING macro to the name
+ SILC_SERVER_PENDING_EXEC and added an new macro
+ SILC_SERVER_PENDING_DESTRUCTOR which is called to free the
+ data or when error occurs while processing the pending command.
+
+ Added new argument `destructor' into silc_server_command_pending
+ and to the SilcServerCommandPending object. This destructor is
+ now called after calling the pending callback or if error occurs
+ immediately. If error occurs the actual pending callback won't
+ be called at all - only the destructor. The destructor may be
+ NULL if destructor is not needed.
+
+ All this applies for client library code as well. Similar
+ changes were made there as well for the pending commands.
+
+ In the client, the application must now allocate the
+ SilcClientCommandContext with the silc_client_command_alloc
+ function.
+
+ * Added reference counter to the SilcServerCommandContext. Added
+ function silc_server_command_alloc and silc_server_command_dup
+ functions.
+
+ Same type of functions added to the client library for the same
+ purpose as well.
+
+ * Removed the cmd_ident from IDListData away since it is now
+ global for all connections. It is the command identifier used
+ in command sending and with pending commands. The affected file
+ is silcd/idlist.h.
+
Mon Feb 19 00:50:57 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
* Changed the client operation API: channel_message operation's
/*
* $Id$
* $Log$
+ * Revision 1.5 2001/02/19 13:47:30 priikone
+ * updates.
+ *
* Revision 1.4 2001/02/16 00:33:23 priikone
* updates.
*
if (!client_entry) {
/* Client entry not found, it was requested thus mark this to be
pending command. */
- silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 0,
+ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 0, NULL,
silc_client_local_command_msg, context);
return;
}
/* Allocate command context. This and its internals must be free'd
by the command routine receiving it. */
- ctx = silc_calloc(1, sizeof(*ctx));
+ ctx = silc_client_command_alloc();
ctx->client = client;
ctx->conn = app->conn;
ctx->command = cmd;
unsigned int arg_type,
unsigned char *arg,
unsigned int arg_len);
-static void silc_server_command_free(SilcServerCommandContext cmd);
void silc_server_command_send_users(SilcServer server,
SilcSocketConnection sock,
SilcChannelEntry channel,
/* Allocate command context. This must be free'd by the
command routine receiving it. */
- ctx = silc_calloc(1, sizeof(*ctx));
+ ctx = silc_server_command_alloc();
ctx->server = server;
ctx->sock = sock;
ctx->packet = silc_packet_context_dup(packet); /* Save original packet */
}
}
+/* Allocate Command Context */
+
+SilcServerCommandContext silc_server_command_alloc()
+{
+ SilcServerCommandContext ctx = silc_calloc(1, sizeof(*ctx));
+ ctx->users++;
+ return ctx;
+}
+
+/* Free's the command context allocated before executing the command */
+
+void silc_server_command_free(SilcServerCommandContext ctx)
+{
+ ctx->users--;
+ SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
+ ctx->users));
+ if (ctx->users < 1) {
+ if (ctx->payload)
+ silc_command_free_payload(ctx->payload);
+ if (ctx->packet)
+ silc_packet_context_free(ctx->packet);
+ silc_free(ctx);
+ }
+}
+
+/* Duplicate Command Context by adding reference counter. The context won't
+ be free'd untill it hits zero. */
+
+SilcServerCommandContext
+silc_server_command_dup(SilcServerCommandContext ctx)
+{
+ ctx->users++;
+ SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
+ ctx->users));
+ return ctx;
+}
+
/* 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. If `ident' is non-zero
void silc_server_command_pending(SilcServer server,
SilcCommand reply_cmd,
unsigned short ident,
+ SilcServerPendingDestructor destructor,
SilcCommandCb callback,
void *context)
{
reply->ident = ident;
reply->context = context;
reply->callback = callback;
+ reply->destructor = destructor;
silc_dlist_add(server->pending_commands, reply);
}
if (r->reply_cmd == command && r->ident == ident) {
ctx->context = r->context;
ctx->callback = r->callback;
+ ctx->destructor = r->destructor;
ctx->ident = ident;
return TRUE;
}
return FALSE;
}
-/* Free's the command context allocated before executing the command */
+/* Destructor function for pending callbacks. This is called when using
+ pending commands to free the context given for the pending command. */
-static void silc_server_command_free(SilcServerCommandContext cmd)
+static void silc_server_command_destructor(void *context)
{
- if (cmd) {
- if (cmd->payload)
- silc_command_free_payload(cmd->payload);
- if (cmd->packet)
- silc_packet_context_free(cmd->packet);
- silc_free(cmd);
- }
+ silc_server_command_free((SilcServerCommandContext)context);
}
/* Sends simple status message as command reply packet */
/* Reprocess this packet after received reply */
silc_server_command_pending(server, SILC_COMMAND_WHOIS,
silc_command_get_ident(cmd->payload),
- silc_server_command_whois, (void *)cmd);
+ silc_server_command_destructor,
+ silc_server_command_whois,
+ silc_server_command_dup(cmd));
cmd->pending = TRUE;
silc_command_set_ident(cmd->payload, old_ident);
}
}
-static int
+static void
silc_server_command_whois_from_client(SilcServerCommandContext cmd)
{
SilcServer server = cmd->server;
SilcClientEntry *clients = NULL, entry;
SilcClientID **client_id = NULL;
unsigned int client_id_count = 0;
- int i, ret = 0;
+ int i;
/* Protocol dictates that we must always send the received WHOIS request
to our router if we are normal server, so let's do it now unless we
/* Reprocess this packet after received reply from router */
silc_server_command_pending(server, SILC_COMMAND_WHOIS,
silc_command_get_ident(cmd->payload),
- silc_server_command_whois, (void *)cmd);
+ silc_server_command_destructor,
+ silc_server_command_whois,
+ silc_server_command_dup(cmd));
cmd->pending = TRUE;
silc_command_set_ident(cmd->payload, old_ident);
silc_buffer_free(tmpbuf);
- ret = -1;
goto out;
}
if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count,
&nick, &server_name, &count,
SILC_COMMAND_WHOIS))
- return 0;
+ return;
/* Get all clients matching that ID or nickname from local list */
if (client_id_count) {
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)) {
- ret = -1;
+ if (!silc_server_command_whois_check(cmd, clients, clients_count))
goto out;
- }
/* Send the command reply to the client */
silc_server_command_whois_send_reply(cmd, clients, clients_count);
silc_free(nick);
if (server_name)
silc_free(server_name);
-
- return ret;
}
-static int
+static void
silc_server_command_whois_from_server(SilcServerCommandContext cmd)
{
SilcServer server = cmd->server;
SilcClientEntry *clients = NULL, entry;
SilcClientID **client_id = NULL;
unsigned int client_id_count = 0;
- int i, ret = 0;
+ int i;
/* Parse the whois request */
if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count,
&nick, &server_name, &count,
SILC_COMMAND_WHOIS))
- return 0;
+ return;
/* Process the command request. Let's search for the requested client and
send reply to the requesting server. */
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)) {
- ret = -1;
+ if (!silc_server_command_whois_check(cmd, clients, clients_count))
goto out;
- }
/* Send the command reply to the client */
silc_server_command_whois_send_reply(cmd, clients, clients_count);
silc_free(nick);
if (server_name)
silc_free(server_name);
-
- return ret;
}
/* Server side of command WHOIS. Processes user's query and sends found
SILC_SERVER_CMD_FUNC(whois)
{
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- int ret;
SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_WHOIS, cmd, 1, 3328);
if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
- ret = silc_server_command_whois_from_client(cmd);
+ silc_server_command_whois_from_client(cmd);
else
- ret = silc_server_command_whois_from_server(cmd);
+ silc_server_command_whois_from_server(cmd);
- if (!ret)
- silc_server_command_free(cmd);
+ silc_server_command_free(cmd);
}
SILC_SERVER_CMD_FUNC(whowas)
/* Reprocess this packet after received reply */
silc_server_command_pending(server, SILC_COMMAND_WHOIS,
silc_command_get_ident(cmd->payload),
- silc_server_command_identify, (void *)cmd);
+ silc_server_command_destructor,
+ silc_server_command_identify,
+ silc_server_command_dup(cmd));
+
cmd->pending = TRUE;
/* Put old data back to the Command Payload we just changed */
}
}
-static int
+static void
silc_server_command_identify_from_client(SilcServerCommandContext cmd)
{
SilcServer server = cmd->server;
SilcClientEntry *clients = NULL, entry;
SilcClientID **client_id = NULL;
unsigned int client_id_count = 0;
- int i, ret = 0;
+ int i;
/* Protocol dictates that we must always send the received IDENTIFY request
to our router if we are normal server, so let's do it now unless we
/* Reprocess this packet after received reply from router */
silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
silc_command_get_ident(cmd->payload),
- silc_server_command_identify, (void *)cmd);
+ silc_server_command_destructor,
+ silc_server_command_identify,
+ silc_server_command_dup(cmd));
cmd->pending = TRUE;
silc_command_set_ident(cmd->payload, old_ident);
silc_buffer_free(tmpbuf);
- ret = -1;
goto out;
}
if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count,
&nick, &server_name, &count,
SILC_COMMAND_IDENTIFY))
- return 0;
+ return;
/* Get all clients matching that ID or nickname from local list */
if (client_id_count) {
/* Check that all mandatory fields are present and request those data
from the server who owns the client if necessary. */
- if (!silc_server_command_identify_check(cmd, clients, clients_count)) {
- ret = -1;
+ if (!silc_server_command_identify_check(cmd, clients, clients_count))
goto out;
- }
/* Send the command reply to the client */
silc_server_command_identify_send_reply(cmd, clients, clients_count);
silc_free(nick);
if (server_name)
silc_free(server_name);
-
- return ret;
}
-static int
+static void
silc_server_command_identify_from_server(SilcServerCommandContext cmd)
{
SilcServer server = cmd->server;
SilcClientEntry *clients = NULL, entry;
SilcClientID **client_id = NULL;
unsigned int client_id_count = 0;
- int i, ret = 0;
+ int i;
/* Parse the IDENTIFY request */
if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count,
&nick, &server_name, &count,
SILC_COMMAND_IDENTIFY))
- return 0;
+ return;
/* Process the command request. Let's search for the requested client and
send reply to the requesting server. */
/* Check that all mandatory fields are present and request those data
from the server who owns the client if necessary. */
- if (!silc_server_command_identify_check(cmd, clients, clients_count)) {
- ret = -1;
+ if (!silc_server_command_identify_check(cmd, clients, clients_count))
goto out;
- }
/* Send the command reply */
silc_server_command_identify_send_reply(cmd, clients, clients_count);
silc_free(nick);
if (server_name)
silc_free(server_name);
-
- return ret;
}
SILC_SERVER_CMD_FUNC(identify)
{
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- int ret;
SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_IDENTIFY, cmd, 1, 3328);
if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
- ret = silc_server_command_identify_from_client(cmd);
+ silc_server_command_identify_from_client(cmd);
else
- ret = silc_server_command_identify_from_server(cmd);
+ silc_server_command_identify_from_server(cmd);
- if (!ret)
- silc_server_command_free(cmd);
+ silc_server_command_free(cmd);
}
/* Checks string for bad characters and returns TRUE if they are found. */
packet->sock = sock;
packet->type = SILC_PACKET_COMMAND;
- cmd = silc_calloc(1, sizeof(*cmd));
+ cmd = silc_server_command_alloc();
cmd->payload = silc_command_payload_parse(buffer);
if (!cmd->payload) {
silc_free(cmd);
will process it after we've received the automatic USERS command
reply. */
silc_server_command_pending(server, SILC_COMMAND_USERS, 0,
- silc_server_command_users, (void *)cmd);
+ silc_server_command_destructor,
+ silc_server_command_users,
+ silc_server_command_dup(cmd));
cmd->pending = TRUE;
- silc_buffer_free(buffer);
- silc_buffer_free(idp);
- return;
+ goto out;
}
/* Process USERS command. */
silc_server_command_users((void *)cmd);
-
+
+ out:
silc_buffer_free(buffer);
silc_buffer_free(idp);
silc_packet_context_free(packet);
/* Reprocess this packet after received reply from router */
silc_server_command_pending(server, SILC_COMMAND_JOIN,
silc_command_get_ident(cmd->payload),
- silc_server_command_join, context);
+ silc_server_command_destructor,
+ silc_server_command_join,
+ silc_server_command_dup(cmd));
cmd->pending = TRUE;
- return;
+ goto out;
}
/* We are router and the channel does not seem exist so we will check
/* Reprocess this packet after received reply */
silc_server_command_pending(server, SILC_COMMAND_USERS,
silc_command_get_ident(cmd->payload),
- silc_server_command_users, (void *)cmd);
+ silc_server_command_destructor,
+ silc_server_command_users,
+ silc_server_command_dup(cmd));
cmd->pending = TRUE;
silc_command_set_ident(cmd->payload, ident);
silc_buffer_free(tmpbuf);
silc_free(id);
- return;
+ goto out;
}
/* We are router and we will check the global list as well. */
#ifndef COMMAND_H
#define COMMAND_H
-#include "command_reply.h"
-
/*
Structure holding one command and pointer to its function.
SilcArgumentPayload args;
SilcPacketContext *packet;
int pending; /* Command is being re-processed when TRUE */
+ int users; /* Reference counter */
} *SilcServerCommandContext;
+/* Pending Command callback destructor. This is called after calling the
+ pending callback or if error occurs while processing the pending command.
+ If error occurs then the callback won't be called at all, and only this
+ destructor is called. The `context' is the context given for the function
+ silc_server_command_pending. */
+typedef void (*SilcServerPendingDestructor)(void *context);
+
/* 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;
SilcCommandCb callback;
+ SilcServerPendingDestructor destructor;
void *context;
unsigned short ident;
struct SilcServerCommandPendingStruct *next;
} SilcServerCommandPending;
+#include "command_reply.h"
+
/* Macros */
/* Macro used for command declaration in command list structure */
void silc_server_command_##func(void *context)
/* Executed pending command */
-#define SILC_SERVER_COMMAND_EXEC_PENDING(ctx, cmd) \
+#define SILC_SERVER_PENDING_EXEC(ctx, cmd) \
do { \
- if (ctx->callback) { \
+ if (ctx->callback) \
(*ctx->callback)(ctx->context); \
- silc_server_command_pending_del(ctx->server, cmd, ctx->ident); \
- } \
+} while(0)
+
+/* Execute destructor for pending command */
+#define SILC_SERVER_PENDING_DESTRUCTOR(ctx, cmd) \
+do { \
+ silc_server_command_pending_del(ctx->server, cmd, ctx->ident); \
+ if (ctx->destructor) \
+ (*ctx->destructor)(ctx->context); \
} while(0)
/* Prototypes */
void silc_server_command_process(SilcServer server,
SilcSocketConnection sock,
SilcPacketContext *packet);
+SilcServerCommandContext silc_server_command_alloc();
+void silc_server_command_free(SilcServerCommandContext ctx);
+SilcServerCommandContext
+silc_server_command_dup(SilcServerCommandContext ctx);
void silc_server_command_pending(SilcServer server,
SilcCommand reply_cmd,
unsigned short ident,
+ SilcServerPendingDestructor destructor,
SilcCommandCb callback,
void *context);
void silc_server_command_pending_del(SilcServer server,
goto out;
/* Execute any pending commands */
- SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_WHOIS);
+ SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
out:
+ SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
silc_server_command_reply_free(cmd);
}
goto out;
/* Execute any pending commands */
- SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
+ SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
out:
+ SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
silc_server_command_reply_free(cmd);
}
silc_buffer_free(keyp);
/* Execute any pending commands */
- SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_JOIN);
+ SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
out:
+ SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
silc_server_command_reply_free(cmd);
}
silc_buffer_free(client_mode_list);
/* Execute any pending commands */
- SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_USERS);
+ SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
out:
+ SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
if (channel_id)
silc_free(channel_id);
silc_server_command_reply_free(cmd);
#ifndef COMMAND_REPLY_H
#define COMMAND_REPLY_H
+#include "command.h"
+
/* Structure holding one command reply and pointer to its function. */
typedef struct {
SilcCommandCb cb;
SilcArgumentPayload args;
/* If defined this executes the pending command. */
- void *context;
+ SilcServerPendingDestructor destructor;
SilcCommandCb callback;
+ void *context;
unsigned short ident;
} *SilcServerCommandReplyContext;
SilcPKCS pkcs;
SilcPublicKey public_key;
- unsigned short cmd_ident; /* Current command identifier, 0 not used */
long last_receive; /* Time last received data */
long last_sent; /* Time last sent data */
unsigned char registered; /* Boolean whether connection is registered */
unsigned int id_string_len;
SilcIdType id_type;
+ /* Current command identifier, 0 not used */
+ unsigned short cmd_ident;
+
/* Server's own ID entry. */
SilcServerEntry id_entry;
Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
[ServerInfo]
-lassi.kuo.fi.ssh.com:212.146.8.245:Kuopio, Finland:1334
+lassi.kuo.fi.ssh.com:10.2.1.7:Kuopio, Finland:1334
[ListenPort]
-212.146.8.245:212.146.8.245:1334
+10.2.1.7:10.2.1.7:1334
[Logging]
infologfile:silcd2.log:10000
[AdminConnection]
[ServerConnection]
-212.146.8.245:passwd:priikone:1333:1:1
+10.2.1.7:passwd:priikone:1333:1:1
[RouterConnection]
-212.146.8.245:passwd:priikone:1335:1:1:0
+10.2.1.7:passwd:priikone:1335:1:1:0
[DenyConnection]
[RedirectClient]
{
SilcPacketContext *p = (SilcPacketContext *)context;
silc_client_notify_by_server(p->context, p->sock, p);
- silc_packet_context_free(p);
+}
+
+/* Destructor for the pending command callback */
+
+static void silc_client_notify_by_server_destructor(void *context)
+{
+ silc_packet_context_free((SilcPacketContext *)context);
+}
+
+/* Resolve client information from server by Client ID. */
+
+static void silc_client_notify_by_server_resolve(SilcClient client,
+ SilcClientConnection conn,
+ SilcPacketContext *packet,
+ SilcClientID *client_id)
+{
+ SilcPacketContext *p = silc_packet_context_dup(packet);
+ SilcBuffer idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
+
+ p->context = (void *)client;
+ p->sock = conn->sock;
+
+ silc_client_send_command(client, conn, SILC_COMMAND_WHOIS, ++conn->cmd_ident,
+ 1, 3, idp->data, idp->len);
+ silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
+ silc_client_notify_by_server_destructor,
+ silc_client_notify_by_server_pending, p);
+ silc_buffer_free(idp);
}
/* Received notify message from server */
goto out;
/* Find Client entry and if not found query it */
- client_entry = silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
+ client_entry = silc_idlist_get_client_by_id(client, conn, client_id);
if (!client_entry) {
- SilcPacketContext *p = silc_packet_context_dup(packet);
- p->context = (void *)client;
- p->sock = sock;
- silc_client_command_pending(conn, SILC_COMMAND_WHOIS, SILC_IDLIST_IDENT,
- silc_client_notify_by_server_pending, p);
+ silc_client_notify_by_server_resolve(client, conn, packet, client_id);
goto out;
}
goto out;
/* Find Client entry and if not found query it */
- client_entry = silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
+ client_entry = silc_idlist_get_client_by_id(client, conn, client_id);
if (!client_entry) {
- SilcPacketContext *p = silc_packet_context_dup(packet);
- p->context = (void *)client;
- p->sock = sock;
- silc_client_command_pending(conn, SILC_COMMAND_WHOIS, SILC_IDLIST_IDENT,
- silc_client_notify_by_server_pending, p);
+ silc_client_notify_by_server_resolve(client, conn, packet, client_id);
goto out;
}
/* If nickname or username hasn't been resolved, do so */
if (!client_entry->nickname || !client_entry->username) {
- SilcPacketContext *p = silc_packet_context_dup(packet);
- SilcBuffer idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
- silc_client_send_command(client, conn, SILC_COMMAND_WHOIS,
- SILC_IDLIST_IDENT, 1,
- 3, idp->data, idp->len);
- p->context = (void *)client;
- p->sock = sock;
- silc_client_command_pending(conn, SILC_COMMAND_WHOIS, SILC_IDLIST_IDENT,
- silc_client_notify_by_server_pending, p);
+ silc_client_notify_by_server_resolve(client, conn, packet, client_id);
goto out;
}
/* Find Client entry */
client_entry =
- silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+ silc_idlist_get_client_by_id(client, conn, client_id);
if (!client_entry)
goto out;
/* Find Client entry */
client_entry =
- silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+ silc_idlist_get_client_by_id(client, conn, client_id);
if (!client_entry)
goto out;
/* Find Client entry */
client_entry =
- silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+ silc_idlist_get_client_by_id(client, conn, client_id);
if (!client_entry)
goto out;
/* Find Client entry and if not found query it */
client_entry2 =
- silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
+ silc_idlist_get_client_by_id(client, conn, client_id);
if (!client_entry2) {
- SilcPacketContext *p = silc_packet_context_dup(packet);
- p->context = (void *)client;
- p->sock = sock;
- silc_client_command_pending(conn, SILC_COMMAND_WHOIS, SILC_IDLIST_IDENT,
- silc_client_notify_by_server_pending, p);
+ silc_client_notify_by_server_resolve(client, conn, packet, client_id);
goto out;
}
silc_free(client_id);
/* Find old Client entry */
client_entry =
- silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+ silc_idlist_get_client_by_id(client, conn, client_id);
if (!client_entry)
goto out;
/* Find Client entry */
client_entry =
- silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+ silc_idlist_get_client_by_id(client, conn, client_id);
if (!client_entry)
goto out;
/* Find Client entry */
client_entry =
- silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+ silc_idlist_get_client_by_id(client, conn, client_id);
if (!client_entry)
goto out;
/* Find target Client entry */
client_entry2 =
- silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+ silc_idlist_get_client_by_id(client, conn, client_id);
if (!client_entry2)
goto out;
void silc_client_command_pending(SilcClientConnection conn,
SilcCommand reply_cmd,
unsigned short ident,
+ SilcClientPendingDestructor destructor,
SilcCommandCb callback,
void *context)
{
reply->ident = ident;
reply->context = context;
reply->callback = callback;
+ reply->destructor = destructor;
silc_dlist_add(conn->pending_commands, reply);
}
if (r->reply_cmd == command && r->ident == ident) {
ctx->context = r->context;
ctx->callback = r->callback;
+ ctx->destructor = r->destructor;
ctx->ident = ident;
return TRUE;
}
return FALSE;
}
+/* Allocate Command Context */
+
+SilcClientCommandContext silc_client_command_alloc()
+{
+ SilcClientCommandContext ctx = silc_calloc(1, sizeof(*ctx));
+ ctx->users++;
+ return ctx;
+}
+
/* Free command context and its internals */
-void silc_client_command_free(SilcClientCommandContext cmd)
+void silc_client_command_free(SilcClientCommandContext ctx)
{
- int i;
+ ctx->users--;
+ SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users + 1,
+ ctx->users));
+ if (ctx->users < 1) {
+ int i;
- if (cmd) {
- for (i = 0; i < cmd->argc; i++)
- silc_free(cmd->argv[i]);
- silc_free(cmd);
+ for (i = 0; i < ctx->argc; i++)
+ silc_free(ctx->argv[i]);
+ silc_free(ctx);
}
}
+/* Duplicate Command Context by adding reference counter. The context won't
+ be free'd untill it hits zero. */
+
+SilcClientCommandContext
+silc_client_command_dup(SilcClientCommandContext ctx)
+{
+ ctx->users++;
+ SILC_LOG_DEBUG(("Command context %p refcnt %d->%d", ctx, ctx->users - 1,
+ ctx->users));
+ return ctx;
+}
+
+/* Pending command destructor. */
+
+static void silc_client_command_destructor(void *context)
+{
+ silc_client_command_free((SilcClientCommandContext)context);
+}
+
/* Command WHOIS. This command is used to query information about
specific user. */
/* Client entry not found, it was requested thus mark this to be
pending command. */
silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 0,
- silc_client_command_invite, context);
- return;
+ silc_client_command_destructor,
+ silc_client_command_invite,
+ silc_client_command_dup(cmd));
+ goto out;
}
/* Find channel entry */
/* Client entry not found, it was requested thus mark this to be
pending command. */
silc_client_command_pending(conn, SILC_COMMAND_CUMODE, 0,
- silc_client_command_cumode, context);
- return;
+ silc_client_command_destructor,
+ silc_client_command_cumode,
+ silc_client_command_dup(cmd));
+ goto out;
}
while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
same context and reprocesses the command. When reprocessing we actually
display the information on the screen. */
silc_client_command_pending(conn, SILC_COMMAND_USERS, 0,
- silc_client_command_users, context);
+ silc_client_command_destructor,
+ silc_client_command_users,
+ silc_client_command_dup(cmd));
cmd->pending = TRUE;
- return;
+ goto out;
}
if (cmd->pending) {
#ifndef COMMAND_H
#define COMMAND_H
-#include "command_reply.h"
-
/*
Structure holding one command and pointer to its function.
unsigned int *argv_lens;
unsigned int *argv_types;
int pending; /* Command is being re-processed when TRUE */
+ int users; /* Reference counter */
} *SilcClientCommandContext;
+/* Pending Command callback destructor. This is called after calling the
+ pending callback or if error occurs while processing the pending command.
+ If error occurs then the callback won't be called at all, and only this
+ destructor is called. The `context' is the context given for the function
+ silc_client_command_pending. */
+typedef void (*SilcClientPendingDestructor)(void *context);
+
/* Structure holding pending commands. If command is pending it will be
executed after command reply has been executed. */
typedef struct SilcClientCommandPendingStruct {
SilcCommand reply_cmd;
SilcCommandCb callback;
+ SilcClientPendingDestructor destructor;
void *context;
unsigned short ident;
struct SilcClientCommandPendingStruct *next;
/* List of pending commands */
extern SilcClientCommandPending *silc_command_pending;
+#include "command_reply.h"
+
/* Macros */
/* Macro used for command declaration in command list structure */
void silc_client_command_##func(void *context)
/* Executed pending command callback */
-#define SILC_CLIENT_COMMAND_EXEC_PENDING(ctx, cmd) \
+#define SILC_CLIENT_PENDING_EXEC(ctx, cmd) \
+do { \
+ if ((ctx)->callback) \
+ (*ctx->callback)(ctx->context); \
+} while(0)
+
+/* Execute destructor for pending command */
+#define SILC_CLIENT_PENDING_DESTRUCTOR(ctx, cmd) \
do { \
- if ((ctx)->callback) { \
- (*ctx->callback)(ctx->context); \
- silc_client_command_pending_del((ctx)->sock->user_data, (cmd), \
- (ctx)->ident); \
- } \
+ silc_client_command_pending_del((ctx)->sock->user_data, (cmd), \
+ (ctx)->ident); \
+ if (ctx->destructor) \
+ (*ctx->destructor)(ctx->context); \
} while(0)
/* Prototypes */
-void silc_client_command_free(SilcClientCommandContext cmd);
void silc_client_send_command(SilcClient client, SilcClientConnection conn,
SilcCommand command, unsigned short ident,
unsigned int argc, ...);
SilcClientCommand *silc_client_command_find(const char *name);
+SilcClientCommandContext silc_client_command_alloc();
+void silc_client_command_free(SilcClientCommandContext ctx);
+SilcClientCommandContext
+silc_client_command_dup(SilcClientCommandContext ctx);
void silc_client_command_pending(SilcClientConnection conn,
SilcCommand reply_cmd,
unsigned short ident,
+ SilcClientPendingDestructor destructor,
SilcCommandCb callback,
void *context);
void silc_client_command_pending_del(SilcClientConnection conn,
}
/* Execute any pending command callbacks */
- SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_WHOIS);
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
out:
+ SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
silc_client_command_reply_free(cmd);
}
}
/* Execute any pending command callbacks */
- SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
out:
+ SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
silc_client_command_reply_free(cmd);
}
COMMAND_REPLY((ARGS, conn->local_entry));
/* Execute any pending command callbacks */
- SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_NICK);
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
out:
+ SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
silc_client_command_reply_free(cmd);
}
cmd->client->ops->say(cmd->client, conn,
"%s", silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
+ SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
silc_client_command_reply_free(cmd);
return;
}
COMMAND_REPLY((ARGS, channel, topic));
/* Execute any pending command callbacks */
- SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_TOPIC);
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
out:
+ SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
silc_client_command_reply_free(cmd);
}
cmd->client->ops->say(cmd->client, conn,
"%s", silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
+ SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
silc_client_command_reply_free(cmd);
return;
}
COMMAND_REPLY((ARGS));
/* Execute any pending command callbacks */
- SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_INVITE);
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
+ SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
silc_client_command_reply_free(cmd);
}
cmd->client->ops->say(cmd->client, conn,
"%s", silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
+ SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
silc_client_command_reply_free(cmd);
return;
}
COMMAND_REPLY((ARGS, NULL, (char *)tmp));
/* Execute any pending command callbacks */
- SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_INFO);
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
out:
+ SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
silc_client_command_reply_free(cmd);
}
COMMAND_REPLY((ARGS));
/* Execute any pending command callbacks */
- SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_PING);
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
out:
+ SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
silc_client_command_reply_free(cmd);
}
NULL, NULL, topic));
/* Execute any pending command callbacks */
- SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_JOIN);
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
out:
+ SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
silc_client_command_reply_free(cmd);
}
COMMAND_REPLY((ARGS, motd));
/* Execute any pending command callbacks */
- SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_MOTD);
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
out:
+ SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
silc_client_command_reply_free(cmd);
}
COMMAND_REPLY((ARGS, tmp));
/* Execute any pending command callbacks */
- SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_CMODE);
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
out:
+ SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
silc_client_command_reply_free(cmd);
}
silc_free(client_id);
/* Execute any pending command callbacks */
- SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_CUMODE);
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
out:
+ SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
silc_client_command_reply_free(cmd);
}
cmd->client->ops->say(cmd->client, conn,
"%s", silc_client_command_status_message(status));
COMMAND_REPLY_ERROR;
- return;
+ goto out;
}
/* Notify application */
COMMAND_REPLY((ARGS));
/* Execute any pending command callbacks */
- SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_LEAVE);
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
+ out:
+ SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
silc_client_command_reply_free(cmd);
}
command reply we will reprocess this command reply by re-calling this
USERS command reply callback. */
silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
- silc_client_command_reply_users, cmd);
+ NULL, silc_client_command_reply_users, cmd);
silc_buffer_free(res_cmd);
if (channel_id)
client_mode_list->head));
/* Execute any pending command callbacks */
- SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_USERS);
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
silc_buffer_free(client_id_list);
silc_buffer_free(client_mode_list);
out:
if (channel_id)
silc_free(channel_id);
+ SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
silc_client_command_reply_free(cmd);
}
SilcPacketContext *packet;
/* If defined this executes the pending command. */
- void *context;
+ SilcClientPendingDestructor destructor;
SilcCommandCb callback;
+ void *context;
unsigned short ident;
} *SilcClientCommandReplyContext;
/* No ID found. Do query from the server. The query is done by
sending simple IDENTIFY command to the server. */
- ctx = silc_calloc(1, sizeof(*ctx));
+ ctx = silc_client_command_alloc();
ctx->client = client;
ctx->conn = conn;
ctx->command = silc_client_command_find("IDENTIFY");
return entry;
}
-/* Finds client entry from cache by Client ID. If the entry is not found
- from the cache this function can query it from the server. */
+/* Finds client entry from cache by Client ID. */
SilcClientEntry silc_idlist_get_client_by_id(SilcClient client,
SilcClientConnection conn,
- SilcClientID *client_id,
- int query)
+ SilcClientID *client_id)
{
SilcIDCacheEntry id_cache;
/* Find ID from cache */
if (!silc_idcache_find_by_id_one(conn->client_cache, client_id,
- SILC_ID_CLIENT, &id_cache)) {
- if (!query) {
- return NULL;
- } else {
- SilcBuffer idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
- silc_client_send_command(client, conn, SILC_COMMAND_WHOIS,
- SILC_IDLIST_IDENT, 1,
- 3, idp->data, idp->len);
- return NULL;
- }
- }
+ SILC_ID_CLIENT, &id_cache))
+ return NULL;
return (SilcClientEntry)id_cache->context;
}
unsigned int num);
SilcClientEntry silc_idlist_get_client_by_id(SilcClient client,
SilcClientConnection conn,
- SilcClientID *client_id,
- int query);
+ SilcClientID *client_id);
SilcChannelEntry silc_idlist_get_channel(SilcClient client,
SilcClientConnection conn,
char *channel);
SilcPacketContext *silc_packet_context_dup(SilcPacketContext *ctx)
{
ctx->users++;
- SILC_LOG_DEBUG(("Packet context %p rfcnt %d->%d", ctx, ctx->users - 1,
+ SILC_LOG_DEBUG(("Packet context %p refcnt %d->%d", ctx, ctx->users - 1,
ctx->users));
return ctx;
}
void silc_packet_context_free(SilcPacketContext *ctx)
{
ctx->users--;
- SILC_LOG_DEBUG(("Packet context %p rfcnt %d->%d", ctx, ctx->users + 1,
+ SILC_LOG_DEBUG(("Packet context %p refcnt %d->%d", ctx, ctx->users + 1,
ctx->users));
if (ctx->users < 1)
{