+Tue Mar 20 21:05:57 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * The client entry's data.registered must be TRUE even with
+ global client entry on global client list. The data.registered
+ is used to check whether the client is anymore in the network,
+ for example with WHOWAS command so it must be valid.
+
+ * Fixed the WHOWAS command in the server. It now actually works
+ in router environment. Added function into silcd/command_reply.c
+ silc_server_command_reply_whowas_save.
+
+ * Added silc_idlist_purge function to the silcd/idlist.c
+ to peridiocally purge the ID Cache.
+
+ * Fixed INFO command in the server. It works now in router
+ environment. Added <server name> argument to the INFO command
+ reply. Updated the protocol specs.
+
+ * Fixed minor bug in silc_idcache_purge to not purge if the
+ expire value is zero.
+
+ * Fixed various bugs in WHOIS and IDENTIFY command handling as
+ they were buggy because of the WHOWAS information.
+
+ * Fixed local command MSG to handle the async resolving of
+ the remote client properly. It used to fail the first MSG.
+ Affected file silc/local_command.c.
+
+ * Added `data_len' field to SilcIDCache context.
+
Tue Mar 20 16:29:00 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
* Update TODO. Todo in commands in the server.
o LIST is not implemented
o RESTART is not implemented
o INVITE is probably not working correctly
- o INFO works only with local server. It must work with any
- server in the network, implement the sending to other servers.
o PING works only with local server. It must work with any
server in the network, implement the sending to other servers.
o MOTD works only with local server. It must work with any
Some of the modes may still not be implemented or is implemented
the wrong way. Also, setting ban and invite lists does not
work at all and requires some thinking how to do them.
+ o In servers all command reply funtions should still call the
+ pending command reply even if the reply was error. In client
+ it is not called but in server, I think, it must be called.
+ When implementing this check that all commands handle the
+ situation correctly when it is called as pending command
+ (it should most likely the that cmd->pending == TRUE/FALSE).
o Packet processing can be made faster. All packet function in the
packet_receive.c has same prototypes. Instead of calling those from
unsigned int idle, mode;
SilcBuffer channels;
- if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
+ if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
+ status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
char *tmp;
tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
3, NULL);
char buf[1024], *nickname, *username, *realname;
int len;
- if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
+ if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
+ status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
char *tmp;
tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
3, NULL);
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, NULL,
- silc_client_local_command_msg, context);
+ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
+ NULL, silc_client_local_command_msg, context);
return;
}
for (i = 0; i < clients_count; i++) {
entry = clients[i];
+ if (entry->data.registered == FALSE)
+ continue;
+
if (!entry->nickname || !entry->username || !entry->userinfo) {
SilcBuffer tmpbuf;
unsigned short old_ident;
for (i = 0; i < clients_count; i++) {
entry = clients[i];
- if (entry->connection && entry->data.registered == FALSE) {
- if (clients_count == 1)
+ if (entry->data.registered == FALSE) {
+ if (clients_count == 1) {
+ SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
- SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, entry->nickname,
- strlen(entry->nickname));
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+ 2, idp->data, idp->len);
+ silc_buffer_free(idp);
+ }
continue;
}
}
}
} else {
- clients = silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients_count);
+ clients = silc_idlist_get_clients_by_hash(server->local_list,
+ nick, server->md5hash,
+ &clients_count);
if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->local_list,
- nick, server->md5hash,
- &clients_count);
+ clients = silc_idlist_get_clients_by_nickname(server->local_list,
+ nick, server_name,
+ &clients_count);
}
/* Check global list as well */
}
}
} else {
- clients = silc_idlist_get_clients_by_nickname(server->global_list,
- nick, server_name,
- &clients_count);
+ clients = silc_idlist_get_clients_by_hash(server->global_list,
+ nick, server->md5hash,
+ &clients_count);
if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->global_list,
- nick, server->md5hash,
- &clients_count);
+ clients = silc_idlist_get_clients_by_nickname(server->global_list,
+ nick, server_name,
+ &clients_count);
}
}
}
}
} else {
- clients = silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients_count);
+ clients = silc_idlist_get_clients_by_hash(server->local_list,
+ nick, server->md5hash,
+ &clients_count);
if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->local_list,
- nick, server->md5hash,
- &clients_count);
+ clients = silc_idlist_get_clients_by_nickname(server->local_list,
+ nick, server_name,
+ &clients_count);
}
/* If we are router we will check our global list as well. */
}
}
} else {
- clients = silc_idlist_get_clients_by_nickname(server->global_list,
- nick, server_name,
- &clients_count);
+ clients = silc_idlist_get_clients_by_hash(server->global_list,
+ nick, server->md5hash,
+ &clients_count);
if (!clients)
- clients = silc_idlist_get_clients_by_hash(server->global_list,
- nick, server->md5hash,
- &clients_count);
+ clients = silc_idlist_get_clients_by_nickname(server->global_list,
+ nick, server_name,
+ &clients_count);
}
}
return TRUE;
}
+static char
+silc_server_command_whowas_check(SilcServerCommandContext cmd,
+ SilcClientEntry *clients,
+ unsigned int clients_count)
+{
+ SilcServer server = cmd->server;
+ int i;
+ SilcClientEntry entry;
+
+ for (i = 0; i < clients_count; i++) {
+ entry = clients[i];
+
+ if (!entry->nickname || !entry->username) {
+ SilcBuffer tmpbuf;
+ unsigned short old_ident;
+
+ if (!entry->router)
+ continue;
+
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ /* Send WHOWAS command */
+ silc_server_packet_send(server, entry->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply */
+ silc_server_command_pending(server, SILC_COMMAND_WHOWAS,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_destructor,
+ silc_server_command_whowas,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+
+ silc_command_set_ident(cmd->payload, old_ident);
+
+ silc_buffer_free(tmpbuf);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
static void
silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
SilcClientEntry *clients,
SilcCommandStatus status;
unsigned short ident = silc_command_get_ident(cmd->payload);
char found = FALSE;
+ char nh[256], uh[256];
status = SILC_STATUS_OK;
if (clients_count > 1)
idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
tmp = silc_argument_get_first_arg(cmd->args, NULL);
- {
- char nh[256], uh[256];
-
- memset(uh, 0, sizeof(uh));
- memset(nh, 0, sizeof(nh));
+ memset(uh, 0, sizeof(uh));
+ memset(nh, 0, sizeof(nh));
- strncat(nh, entry->nickname, strlen(entry->nickname));
- if (!strchr(entry->nickname, '@')) {
- strncat(nh, "@", 1);
- len = entry->router ? strlen(entry->router->server_name) :
- strlen(server->server_name);
- strncat(nh, entry->router ? entry->router->server_name :
- server->server_name, len);
- }
+ strncat(nh, entry->nickname, strlen(entry->nickname));
+ if (!strchr(entry->nickname, '@')) {
+ strncat(nh, "@", 1);
+ len = entry->router ? strlen(entry->router->server_name) :
+ strlen(server->server_name);
+ strncat(nh, entry->router ? entry->router->server_name :
+ server->server_name, len);
+ }
- strncat(uh, entry->username, strlen(entry->username));
- if (!strchr(entry->username, '@')) {
- strncat(uh, "@", 1);
- strcat(uh, "*private*");
- }
+ strncat(uh, entry->username, strlen(entry->username));
+ if (!strchr(entry->username, '@')) {
+ strncat(uh, "@", 1);
+ strcat(uh, "*private*");
+ }
+ if (entry->userinfo)
packet =
silc_command_reply_payload_encode_va(SILC_COMMAND_WHOWAS,
status, ident, 4,
4, uh, strlen(uh),
5, entry->userinfo,
strlen(entry->userinfo));
- }
-
+ else
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_WHOWAS,
+ status, ident, 3,
+ 2, idp->data, idp->len,
+ 3, nh, strlen(nh),
+ 4, uh, strlen(uh));
+
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
0, packet->data, packet->len, FALSE);
silc_server_command_pending(server, SILC_COMMAND_WHOWAS,
silc_command_get_ident(cmd->payload),
silc_server_command_destructor,
- silc_server_command_whois,
+ silc_server_command_whowas,
silc_server_command_dup(cmd));
cmd->pending = TRUE;
&clients_count);
}
- if (!clients) {
- /* Such client(s) really does not exist in the SILC network. */
- silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
- SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, nick, strlen(nick));
+ if (!silc_server_command_whowas_check(cmd, clients, clients_count)) {
+ ret = -1;
goto out;
}
for (i = 0; i < clients_count; i++) {
entry = clients[i];
+ if (entry->data.registered == FALSE)
+ continue;
+
if (!entry->nickname) {
SilcBuffer tmpbuf;
unsigned short old_ident;
for (i = 0; i < clients_count; i++) {
entry = clients[i];
- if (entry->connection && entry->data.registered == FALSE) {
- if (clients_count == 1)
+ if (entry->data.registered == FALSE) {
+ if (clients_count == 1) {
+ SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, entry->nickname,
- strlen(entry->nickname));
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+ 2, idp->data, idp->len);
+ silc_buffer_free(idp);
+ }
continue;
}
/* Update client cache */
silc_idcache_add(server->local_list->clients, client->nickname,
- SILC_ID_CLIENT, client->id, (void *)client, TRUE, FALSE);
+ strlen(client->nickname), SILC_ID_CLIENT, client->id,
+ (void *)client, TRUE, FALSE);
nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
SilcBuffer packet, idp;
- char info_string[256], *dest_server;
+ char *dest_server, *server_info = NULL, *server_name;
+ unsigned short ident = silc_command_get_ident(cmd->payload);
+ SilcServerEntry entry = NULL;
SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 1, 1);
if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
/* Send our reply */
+ char info_string[256];
+
memset(info_string, 0, sizeof(info_string));
snprintf(info_string, sizeof(info_string),
"location: %s server: %s admin: %s <%s>",
server->config->admin_info->admin_name,
server->config->admin_info->admin_email);
- idp = silc_id_payload_encode(server->id, SILC_ID_SERVER);
-
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
- SILC_STATUS_OK, 0, 2,
- 2, idp->data, idp->len,
- 3, info_string,
- strlen(info_string));
- silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
- packet->data, packet->len, FALSE);
-
- silc_buffer_free(packet);
- silc_buffer_free(idp);
+ server_info = info_string;
+ entry = server->id_entry;
} else {
- /* Send this command to the requested server */
+ /* Check whether we have this server cached */
+ entry = silc_idlist_find_server_by_name(server->global_list,
+ dest_server, NULL);
+ if (!entry) {
+ entry = silc_idlist_find_server_by_name(server->local_list,
+ dest_server, NULL);
+ }
- if (server->server_type == SILC_SERVER && !server->standalone) {
+ if (server->server_type == SILC_ROUTER && entry && !entry->server_info) {
+ /* Send to the server */
+ SilcBuffer tmpbuf;
+ unsigned short old_ident;
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ silc_server_packet_send(server, entry->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply from router */
+ silc_server_command_pending(server, SILC_COMMAND_INFO,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_destructor,
+ silc_server_command_info,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+ silc_command_set_ident(cmd->payload, old_ident);
+ silc_buffer_free(tmpbuf);
+ return;
}
- if (server->server_type == SILC_ROUTER) {
+ if (!entry && !cmd->pending && !server->standalone) {
+ /* Send to the primary router */
+ SilcBuffer tmpbuf;
+ unsigned short old_ident;
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ silc_server_packet_send(server, server->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply from router */
+ silc_server_command_pending(server, SILC_COMMAND_INFO,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_destructor,
+ silc_server_command_info,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+ silc_command_set_ident(cmd->payload, old_ident);
+ silc_buffer_free(tmpbuf);
+ return;
}
}
-
+
+ if (!entry) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
+ SILC_STATUS_ERR_NO_SUCH_SERVER);
+ goto out;
+ }
+
+ idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
+ if (!server_info)
+ server_info = entry->server_info;
+ server_name = dest_server;
+
+ /* Send the reply */
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
+ SILC_STATUS_OK, ident, 3,
+ 2, idp->data, idp->len,
+ 3, server_name,
+ strlen(server_name),
+ 4, server_info,
+ strlen(server_info));
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, FALSE);
+
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
+
out:
silc_server_command_free(cmd);
}
they are never sent by server. More maybe added later if need appears. */
SilcServerCommandReply silc_command_reply_list[] =
{
- SILC_SERVER_CMD_REPLY(join, JOIN),
SILC_SERVER_CMD_REPLY(whois, WHOIS),
+ SILC_SERVER_CMD_REPLY(whowas, WHOWAS),
SILC_SERVER_CMD_REPLY(identify, IDENTIFY),
+ SILC_SERVER_CMD_REPLY(info, INFO),
+ SILC_SERVER_CMD_REPLY(join, JOIN),
SILC_SERVER_CMD_REPLY(users, USERS),
{ NULL, 0 },
if (!client)
return FALSE;
+ client->data.registered = TRUE;
client->mode = mode;
} else {
/* We have the client already, update the data */
if (cache) {
cache->data = nick;
+ cache->data_len = strlen(nick);
silc_idcache_sort_by_data(global ? server->global_list->clients :
server->local_list->clients);
}
silc_server_command_reply_free(cmd);
}
+/* Caches the received WHOWAS information for a short period of time. */
+
+static char
+silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
+{
+ SilcServer server = cmd->server;
+ int len, id_len;
+ unsigned char *id_data;
+ char *nickname, *username, *realname;
+ SilcClientID *client_id;
+ SilcClientEntry client;
+ SilcIDCacheEntry cache = NULL;
+ char *nick;
+ int global = FALSE;
+
+ id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
+ nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
+ username = silc_argument_get_arg_type(cmd->args, 4, &len);
+ if (!id_data || !nickname || !username)
+ return FALSE;
+
+ realname = silc_argument_get_arg_type(cmd->args, 5, &len);
+
+ client_id = silc_id_payload_parse_id(id_data, id_len);
+ if (!client_id)
+ return FALSE;
+
+ /* Check if we have this client cached already. */
+
+ client = silc_idlist_find_client_by_id(server->local_list, client_id,
+ &cache);
+ if (!client) {
+ client = silc_idlist_find_client_by_id(server->global_list,
+ client_id, &cache);
+ global = TRUE;
+ }
+
+ if (!client) {
+ /* If router did not find such Client ID in its lists then this must
+ be bogus client or some router in the net is buggy. */
+ if (server->server_type == SILC_ROUTER)
+ return FALSE;
+
+ /* Take hostname out of nick string if it includes it. */
+ if (strchr(nickname, '@')) {
+ int len = strcspn(nickname, "@");
+ nick = silc_calloc(len + 1, sizeof(char));
+ memcpy(nick, nickname, len);
+ } else {
+ nick = strdup(nickname);
+ }
+
+ /* We don't have that client anywhere, add it. The client is added
+ to global list since server didn't have it in the lists so it must be
+ global. */
+ client = silc_idlist_add_client(server->global_list, nick,
+ strdup(username),
+ strdup(realname),
+ silc_id_dup(client_id, SILC_ID_CLIENT),
+ cmd->sock->user_data, NULL);
+ if (!client)
+ return FALSE;
+
+ client->data.registered = FALSE;
+ client = silc_idlist_find_client_by_id(server->global_list,
+ client_id, &cache);
+ cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
+ } else {
+ /* We have the client already, update the data */
+
+ /* Take hostname out of nick string if it includes it. */
+ if (strchr(nickname, '@')) {
+ int len = strcspn(nickname, "@");
+ nick = silc_calloc(len + 1, sizeof(char));
+ memcpy(nick, nickname, len);
+ } else {
+ nick = strdup(nickname);
+ }
+
+ if (client->nickname)
+ silc_free(client->nickname);
+ if (client->username)
+ silc_free(client->username);
+
+ client->nickname = nick;
+ client->username = strdup(username);
+
+ if (cache) {
+ cache->data = nick;
+ cache->data_len = strlen(nick);
+ silc_idcache_sort_by_data(global ? server->global_list->clients :
+ server->local_list->clients);
+ }
+ }
+
+ silc_free(client_id);
+
+ return TRUE;
+}
+
+/* Received reply for WHOWAS command. Cache the client information only for
+ a short period of time. */
+
+SILC_SERVER_CMD_REPLY_FUNC(whowas)
+{
+ SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
+ SilcCommandStatus status;
+
+ COMMAND_CHECK_STATUS_LIST;
+
+ if (!silc_server_command_reply_whowas_save(cmd))
+ goto out;
+
+ /* Execute any pending commands */
+ SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
+
+ out:
+ SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOWAS);
+ silc_server_command_reply_free(cmd);
+}
+
/* Caches the received IDENTIFY information. */
static char
/* We don't have that client anywhere, add it. The client is added
to global list since server didn't have it in the lists so it must be
global. */
- silc_idlist_add_client(server->global_list, nick,
- username ? strdup(username) : NULL, NULL,
- client_id, cmd->sock->user_data, NULL);
+ client = silc_idlist_add_client(server->global_list, nick,
+ username ? strdup(username) : NULL, NULL,
+ client_id, cmd->sock->user_data, NULL);
+ client->data.registered = TRUE;
} else {
/* We have the client already, update the data */
if (nickname && cache) {
cache->data = nick;
+ cache->data_len = strlen(nick);
silc_idcache_sort_by_data(global ? server->global_list->clients :
server->local_list->clients);
}
silc_server_command_reply_free(cmd);
}
+/* Received reply fro INFO command. Cache the server and its information */
+
+SILC_SERVER_CMD_REPLY_FUNC(info)
+{
+ SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
+ SilcServer server = cmd->server;
+ SilcCommandStatus status;
+ SilcServerEntry entry;
+ SilcServerID *server_id;
+ unsigned int tmp_len;
+ unsigned char *tmp, *name;
+
+ COMMAND_CHECK_STATUS;
+
+ /* Get Server ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ if (!tmp)
+ goto out;
+ server_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!server_id)
+ goto out;
+
+ /* Get the info string */
+ name = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+ if (tmp_len > 256)
+ goto out;
+
+ entry = silc_idlist_find_server_by_id(server->local_list, server_id, NULL);
+ if (!entry) {
+ entry = silc_idlist_find_server_by_id(server->global_list, server_id,
+ NULL);
+ if (!entry) {
+ /* Add the server to global list */
+ server_id = silc_id_dup(server_id, SILC_ID_SERVER);
+ entry = silc_idlist_add_server(server->global_list, name, 0,
+ server_id, NULL, NULL);
+ if (!entry) {
+ silc_free(server_id);
+ goto out;
+ }
+ }
+ }
+
+ /* Get the info string */
+ tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
+ if (tmp_len > 256)
+ tmp = NULL;
+
+ entry->server_info = tmp ? strdup(tmp) : NULL;
+
+ /* Execute any pending commands */
+ SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
+
+ out:
+ SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
+ silc_server_command_reply_free(cmd);
+}
+
/* Received reply for forwarded JOIN command. Router has created or joined
the client to the channel. We save some channel information locally
for future use. */
void silc_server_command_reply_process(SilcServer server,
SilcSocketConnection sock,
SilcBuffer buffer);
-SILC_SERVER_CMD_REPLY_FUNC(join);
SILC_SERVER_CMD_REPLY_FUNC(whois);
+SILC_SERVER_CMD_REPLY_FUNC(whowas);
SILC_SERVER_CMD_REPLY_FUNC(identify);
+SILC_SERVER_CMD_REPLY_FUNC(info);
+SILC_SERVER_CMD_REPLY_FUNC(join);
SILC_SERVER_CMD_REPLY_FUNC(users);
#endif
silc_pkcs_public_key_free(idata->public_key);
}
+/* Purges ID cache */
+
+SILC_TASK_CALLBACK_GLOBAL(silc_idlist_purge)
+{
+ SilcIDListPurge i = (SilcIDListPurge)context;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ silc_idcache_purge(i->cache);
+ silc_task_register(i->timeout_queue, 0,
+ silc_idlist_purge,
+ (void *)i, 600, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+}
+
/******************************************************************************
Server entry functions
server->router = router;
server->connection = connection;
- if (!silc_idcache_add(id_list->servers, server->server_name, SILC_ID_SERVER,
- (void *)server->id, (void *)server, TRUE, FALSE)) {
+ if (!silc_idcache_add(id_list->servers, server->server_name,
+ server->server_name ? strlen(server->server_name) : 0,
+ SILC_ID_SERVER, (void *)server->id,
+ (void *)server, TRUE, FALSE)) {
silc_free(server);
return NULL;
}
if (ret_entry)
*ret_entry = id_cache;
+ SILC_LOG_DEBUG(("Found"));
+
return server;
}
server->id = new_id;
id_cache->id = (void *)new_id;
+ SILC_LOG_DEBUG(("Found"));
+
return server;
}
silc_list_init(client->channels, struct SilcChannelClientEntryStruct,
client_list);
- if (!silc_idcache_add(id_list->clients, nickname, SILC_ID_CLIENT,
- (void *)client->id, (void *)client, TRUE, FALSE)) {
+ if (!silc_idcache_add(id_list->clients, nickname,
+ nickname ? strlen(nickname) : 0,
+ SILC_ID_CLIENT, (void *)client->id,
+ (void *)client, TRUE, FALSE)) {
silc_free(client);
return NULL;
}
SilcClientEntry *clients;
int i;
+ SILC_LOG_DEBUG(("Start"));
+
if (!silc_idcache_find_by_data(id_list->clients, nickname, &list))
return NULL;
unsigned char hash[32];
int i;
+ SILC_LOG_DEBUG(("Start"));
+
silc_hash_make(md5hash, nickname, strlen(nickname), hash);
if (!silc_idcache_find_by_data(id_list->clients, hash, &list))
channel_list);
if (!silc_idcache_add(id_list->channels, channel->channel_name,
- SILC_ID_CHANNEL, (void *)channel->id,
- (void *)channel, TRUE, FALSE)) {
+ channel->channel_name ? strlen(channel->channel_name) :
+ 0, SILC_ID_CHANNEL,
+ (void *)channel->id, (void *)channel, TRUE, FALSE)) {
silc_free(channel);
return NULL;
}
typedef struct SilcClientEntryStruct *SilcClientEntry;
typedef struct SilcChannelEntryStruct *SilcChannelEntry;
+/* Context for holding cache information to periodically purge
+ the cache. */
+typedef struct {
+ SilcIDCache cache;
+ void *timeout_queue;
+} *SilcIDListPurge;
+
/*
Generic ID list data structure.
char *server_name;
int server_type;
SilcServerID *id;
+ char *server_info;
/* Pointer to the router */
SilcServerEntry router;
/* Prototypes */
void silc_idlist_add_data(void *entry, SilcIDListData idata);
void silc_idlist_del_data(void *entry);
+SILC_TASK_CALLBACK_GLOBAL(silc_idlist_purge);
SilcServerEntry
silc_idlist_add_server(SilcIDList id_list,
char *server_name, int server_type,
SilcChannelEntry channel;
SilcClientEntry client;
SilcChannelClientEntry chl;
+ SilcIDCacheEntry cache;
unsigned int mode;
unsigned char *tmp;
unsigned int tmp_len;
silc_free(client_id);
goto out;
}
+
+ client->data.registered = TRUE;
}
}
/* Get client entry */
client = silc_idlist_find_client_by_id(server->global_list,
- client_id, NULL);
+ client_id, &cache);
if (!client) {
client = silc_idlist_find_client_by_id(server->local_list,
- client_id, NULL);
+ client_id, &cache);
if (!client) {
silc_free(client_id);
goto out;
/* Remove the client from all channels */
silc_server_remove_from_channels(server, NULL, client, TRUE, tmp, TRUE);
+ client->data.registered = FALSE;
+ cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
+
+#if 0
/* Remove the client entry */
if (!silc_idlist_del_client(server->global_list, client))
silc_idlist_del_client(server->local_list, client);
+#endif
break;
case SILC_NOTIFY_TYPE_TOPIC_SET:
SilcServerID *server_id;
SilcIDListData idata;
unsigned char *server_name, *id_string;
- unsigned short id_len;
+ unsigned short id_len, name_len;
int ret;
SILC_LOG_DEBUG(("Creating new server"));
/* Parse the incoming packet */
ret = silc_buffer_unformat(buffer,
SILC_STR_UI16_NSTRING_ALLOC(&id_string, &id_len),
- SILC_STR_UI16_STRING_ALLOC(&server_name),
+ SILC_STR_UI16_NSTRING_ALLOC(&server_name,
+ &name_len),
SILC_STR_END);
if (ret == -1) {
if (id_string)
return NULL;
}
+ if (name_len > 256)
+ server_name[255] = '\0';
+
/* Get Server ID */
server_id = silc_id_str2id(id_string, id_len, SILC_ID_SERVER);
if (!server_id) {
list. The client is put to global list and we will take the hash
value of the Client ID and save it to the ID Cache system for fast
searching in the future. */
- hash = silc_calloc(sizeof(((SilcClientID *)id)->hash),
+ hash = silc_calloc(sizeof(((SilcClientID *)id)->hash),
sizeof(unsigned char));
memcpy(hash, ((SilcClientID *)id)->hash,
sizeof(((SilcClientID *)id)->hash));
entry = silc_idlist_add_client(id_list, hash, NULL, NULL, id,
router, NULL);
entry->nickname = NULL;
+ entry->data.registered = TRUE;
if (sock->type == SILC_SOCKET_TYPE_SERVER)
server->stat.cell_clients++;
int *sock = NULL, sock_count = 0, i;
SilcServerID *id;
SilcServerEntry id_entry;
+ SilcIDListPurge purge;
SILC_LOG_DEBUG(("Initializing server"));
assert(server);
if (server->config->servers)
server->server_type = SILC_ROUTER;
+ /* Register the ID Cache purge task. This periodically purges the ID cache
+ and removes the expired cache entries. */
+
+ /* Clients local list */
+ purge = silc_calloc(1, sizeof(*purge));
+ purge->cache = server->local_list->clients;
+ purge->timeout_queue = server->timeout_queue;
+ silc_task_register(purge->timeout_queue, 0,
+ silc_idlist_purge,
+ (void *)purge, 600, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+
+ /* Clients global list */
+ purge = silc_calloc(1, sizeof(*purge));
+ purge->cache = server->global_list->clients;
+ purge->timeout_queue = server->timeout_queue;
+ silc_task_register(purge->timeout_queue, 0,
+ silc_idlist_purge,
+ (void *)purge, 300, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+
SILC_LOG_DEBUG(("Server initialized"));
/* We are done here, return succesfully */
silc_free(client_id);
continue;
}
+
+ client->data.registered = TRUE;
}
silc_free(client_id);
silc_free(cid);
}
- silc_buffer_push(buffer, buffer->data - buffer->head);
+ if (buffer)
+ silc_buffer_push(buffer, buffer->data - buffer->head);
+
return buffer;
}
[Cipher]
-rc6:../lib/silcsim/modules/rc6.sim.so:16:16
-twofish:../lib/silcsim/modules/twofish.sim.so:16:16
-mars:../lib/silcsim/modules/mars.sim.so:16:16
+aes-256-cbc:../lib/silcsim/modules/aes.sim.so:32:16
+aes-192-cbc:../lib/silcsim/modules/aes.sim.so:24:16
+aes-128-cbc:../lib/silcsim/modules/aes.sim.so:16:16
+twofish-256-cbc:../lib/silcsim/modules/twofish.sim.so:32:16
+twofish-192-cbc:../lib/silcsim/modules/twofish.sim.so:24:16
+twofish-128-cbc:../lib/silcsim/modules/twofish.sim.so:16:16
+mars-256-cbc:../lib/silcsim/modules/mars.sim.so:32:16
+mars-192-cbc:../lib/silcsim/modules/mars.sim.so:24:16
+mars-128-cbc:../lib/silcsim/modules/mars.sim.so:16:16
none:../lib/silcsim/modules/none.sim.so:0:0
-[Hash]
+[Hash]
md5::64:16
sha1::64:20
[hmac]
hmac-sha1-96:sha1:12
hmac-md5-96:md5:12
-hmac-sha1:sha1:20
+hmac-sha1:sha1:20
hmac-md5:md5:16
#[PKCS]
Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
[ServerInfo]
-lassi.kuo.fi.ssh.com:10.2.1.7:Kuopio, Finland:1334
+silc:212.146.42.253:Kuopio, Finland:1334
[ListenPort]
-10.2.1.7:10.2.1.7:1334
+212.146.42.253:212.146.42.253:1334
[Logging]
infologfile:silcd2.log:10000
:::1336:1
[AdminConnection]
-*:silc:silc:passwd:testi
+*:priikone:*:passwd:testi
[ServerConnection]
-10.2.1.7:passwd:priikone:1333:1:1
+212.146.42.253:passwd:priikone:1336:1:1
[RouterConnection]
-10.2.1.7:passwd:priikone:1335:1:1:0
+212.146.42.253:passwd:priikone:1335:1:1:0
[DenyConnection]
[RedirectClient]
Reply messages to the command:
- Max Arguments: 3
+ Max Arguments: 4
Arguments: (1) <Status Payload> (2) <Server ID>
- (3) <string>
+ (3) <server name> (4) <string>
This command replies with the Server ID of the server and a
string which tells the information about the server.
conn->local_entry->id = conn->local_id;
/* Put it to the ID cache */
- silc_idcache_add(conn->client_cache, conn->nickname, SILC_ID_CLIENT,
- conn->local_id, (void *)conn->local_entry, TRUE, FALSE);
+ silc_idcache_add(conn->client_cache, conn->nickname, strlen(conn->nickname),
+ SILC_ID_CLIENT, conn->local_id, (void *)conn->local_entry,
+ TRUE, FALSE);
/* Notify application of successful connection. We do it here now that
we've received the Client ID and are allowed to send traffic. */
conn->current_channel = channel;
/* Put it to the ID cache */
- silc_idcache_add(conn->channel_cache, channel_name, SILC_ID_CHANNEL,
- (void *)channel->id, (void *)channel, TRUE, FALSE);
+ silc_idcache_add(conn->channel_cache, channel_name, strlen(channel_name),
+ SILC_ID_CHANNEL, (void *)channel->id, (void *)channel,
+ TRUE, FALSE);
return channel;
}
/* Save the client to cache */
silc_idcache_add(conn->client_cache, remote_client->nickname,
- SILC_ID_CLIENT, remote_client->id, remote_client,
- TRUE, TRUE);
+ strlen(remote_client->nickname), SILC_ID_CLIENT,
+ remote_client->id, remote_client, TRUE, TRUE);
} else {
remote_client = (SilcClientEntry)id_cache->context;
}
/* Add client to cache */
silc_idcache_add(conn->client_cache, client_entry->nickname,
+ strlen(client_entry->nickname),
SILC_ID_CLIENT, client_id, (void *)client_entry,
TRUE, FALSE);
} else {
client_entry->realname = strdup(realname);
id_cache->data = client_entry->nickname;
+ id_cache->data_len = strlen(client_entry->nickname);
silc_idcache_sort_by_data(conn->client_cache);
silc_free(client_id);
/* Add client to cache */
silc_idcache_add(conn->client_cache, client_entry->nickname,
+ strlen(client_entry->nickname),
SILC_ID_CLIENT, client_id, (void *)client_entry,
TRUE, FALSE);
} else {
client_entry->username = strdup(username);
id_cache->data = client_entry->nickname;
+ id_cache->data_len = strlen(client_entry->nickname);
silc_idcache_sort_by_data(conn->client_cache);
silc_free(client_id);
/* XXX save server id */
- /* Get server info */
+ /* Get server name */
tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
if (!tmp)
goto out;
+ /* Get server info */
+ tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
+ if (!tmp)
+ goto out;
+
client->ops->say(cmd->client, conn, "Info: %s", tmp);
/* Notify application */
/* No, we don't have it, add entry for it. */
client_entry = silc_calloc(1, sizeof(*client_entry));
client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
- silc_idcache_add(conn->client_cache, NULL, SILC_ID_CLIENT,
+ silc_idcache_add(conn->client_cache, NULL, 0, SILC_ID_CLIENT,
client_entry->id, (void *)client_entry, FALSE, FALSE);
} else {
/* Yes, we have it already */
break;
if (cache->cache[i].data &&
- !memcmp(cache->cache[i].data, data, strlen(cache->cache[i].data)))
+ !memcmp(cache->cache[i].data, data, cache->cache[i].data_len))
silc_idcache_list_add(list, &(cache->cache[i]));
}
for (i = i; i < cache->cache_count; i++)
if (cache->cache[i].data &&
- !memcmp(cache->cache[i].data, data, strlen(cache->cache[i].data))) {
+ !memcmp(cache->cache[i].data, data, cache->cache[i].data_len)) {
if (ret)
*ret = &(cache->cache[i]);
return TRUE;
however, it is not mandatory. */
int silc_idcache_add(SilcIDCache cache, unsigned char *data,
- SilcIdType id_type, void *id, void *context, int sort,
- int expire)
+ unsigned int data_len, SilcIdType id_type, void *id,
+ void *context, int sort, int expire)
{
int i;
unsigned int count;
for (i = 0; i < count; i++) {
if (c[i].data == NULL && c[i].id == NULL) {
c[i].data = data;
+ c[i].data_len = data_len;
c[i].type = id_type;
c[i].id = id;
c[i].expire = (expire ? (curtime + SILC_ID_CACHE_EXPIRE) : 0);
c[i].id = NULL;
}
c[count].data = data;
+ c[count].data_len = data_len;
c[count].type = id_type;
c[count].id = id;
c[count].expire = (expire ? (curtime + SILC_ID_CACHE_EXPIRE) : 0);
c = cache->cache;
for (i = 0; i < cache->cache_count; i++) {
- if (c[i].data && c[i].expire < curtime) {
+ if (c[i].data && c[i].expire && c[i].expire < curtime) {
/* Call the destructor */
if (cache->destructor)
allocate any of these fields nor free them.
unsigned char *data
+ unsigned int data_len;
The data that is usually used to find the data from the cache.
For example for Client ID's this is nickname.
*/
typedef struct {
unsigned char *data;
+ unsigned int data_len;
SilcIdType type;
void *id;
unsigned long expire;
#define SILC_ID_CACHE_ANY ((void *)1)
#define SILC_ID_CACHE_EXPIRE 3600
+#define SILC_ID_CACHE_EXPIRE_DEF (time(NULL) + SILC_ID_CACHE_EXPIRE)
/* Prototypes */
SilcIDCache silc_idcache_alloc(unsigned int count,
int silc_idcache_find_by_context(SilcIDCache cache, void *context,
SilcIDCacheEntry *ret);
int silc_idcache_add(SilcIDCache cache, unsigned char *data,
- SilcIdType id_type, void *id, void *context, int sort,
- int expire);
+ unsigned int data_len, SilcIdType id_type, void *id,
+ void *context, int sort, int expire);
int silc_idcache_del(SilcIDCache cache, SilcIDCacheEntry old);
int silc_idcache_del_by_data(SilcIDCache cache, unsigned char *data);
int silc_idcache_del_by_id(SilcIDCache cache, SilcIdType type, void *id);