From 622dbba14878964ca76301bdf9c8f59f3312fbc7 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Tue, 3 Apr 2001 14:07:01 +0000 Subject: [PATCH] updates. --- CHANGES | 45 +++ TODO | 60 ++-- apps/silc/client_ops.c | 25 ++ apps/silcd/command.c | 487 ++++++++++++-------------- apps/silcd/command.h | 3 +- apps/silcd/command_reply.c | 77 ++-- apps/silcd/idlist.c | 57 +-- apps/silcd/idlist.h | 17 +- apps/silcd/packet_receive.c | 41 ++- apps/silcd/packet_send.c | 36 +- apps/silcd/packet_send.h | 11 +- apps/silcd/protocol.c | 2 + apps/silcd/server.c | 129 +++++-- apps/silcd/server.h | 3 +- doc/draft-riikonen-silc-pp-02.nroff | 13 +- doc/draft-riikonen-silc-spec-02.nroff | 92 ++--- lib/silcclient/client_notify.c | 66 +++- lib/silcclient/command.c | 164 ++++----- lib/silcclient/command.h | 3 +- lib/silcclient/command_reply.c | 28 -- lib/silcclient/command_reply.h | 1 - lib/silcclient/idlist.c | 7 +- lib/silcclient/protocol.c | 60 +++- lib/silccore/silcchannel.c | 6 +- lib/silccore/silccommand.h | 3 +- lib/silccore/silcnotify.c | 29 ++ lib/silccore/silcnotify.h | 3 + lib/silccore/silcpayload.c | 12 +- lib/silccore/silcpayload.h | 4 +- lib/silccrypt/silchmac.c | 1 + lib/silcske/payload.c | 4 +- lib/silcutil/silctask.c | 223 ++++-------- lib/silcutil/silctask.h | 105 ------ 33 files changed, 932 insertions(+), 885 deletions(-) diff --git a/CHANGES b/CHANGES index 14b5f3fa..7976d137 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,48 @@ +Tue Apr 3 16:39:19 EEST 2001 Pekka Riikonen + + * Implemented the sending of the SERVER_SIGNOFF notify in the + server. Affected file is silcd/server.c. + + * Added silc_server_send_notify_args into silcd/packet_send.[ch]. + Added also silc_notify_payload_encode_args into the + lib/silccore/silcnotify.[ch]. + + * Implemented ther SERVER_SIGNOFF notify handling in the server. + Affected file silcd/packet_receive.c. + + * Implemented the SERVER_SIGNOFF notify handling in the client + library. Affected file lib/silcclient/client_notify.c. Also, + implemnted the printing of the SERVER_SIGNOFF info to the + application. Affected file silc/client_ops.c. + + * The silc_idlist_del_server now returns TRUE or FALSE to indicate + if the deleting was successful. Affected file silcd/idlist.[ch]. + + * Added support for public key authentication in the connection + authentication protocol in the client library. Affected file + lib/silcclient/protocol.c. + + * Changed the server's silc_idlist_get_clients_by_* interface + to support already allocated array so that new entries may be + added to pre-allocated array. Affected file silcd/idlist.[ch]. + This fixes some bugs with WHOIS, WHOWAS and IDENTIFY commands + and command replies. + + * All command reply functions in the server now calls the + pending command callback even if error occured. This way the + error will be delivered to the client as well. Affected files + silcd/command.c and silcd/command_reply.c. + + * Fixed INFO command to return local server's info if no server + was provided. Affected file lib/silcclient/command.c. + + * Removed RESTART command for good. Updated the code and the + protocol specs. + + * Rewrote parts of the task system. It is a bit simpler now. + Removed unsued task priorities. The affected files are + lib/silcutil/silctask.[ch]. + Mon Apr 2 20:02:33 EEST 2001 Pekka Riikonen * Moved the USERS printing from the library to the application. diff --git a/TODO b/TODO index 13beb86d..f0871b35 100644 --- a/TODO +++ b/TODO @@ -8,8 +8,8 @@ TODO General datatype should be defined. -TODO In SILC Client Library -=========================== +TODO/bugs In SILC Client Library +================================ o Client library crashes if for example server timeouts protocol execution and disconnects the client. The client, on the other hand @@ -18,10 +18,6 @@ TODO In SILC Client Library the SilcSocketConnection reference counter at all. This must be fixed. - o I guess, public key authentication (when connecting to a server) - is not working currently. It is just matter of loading the keys - from file and using them (see corresponding code in server). - o Add client library parameters or options that handle what kind of messages the library should print out (using `say' client operation, for example) and what is left for the application to print. The @@ -33,38 +29,27 @@ TODO In SILC Client Library fix it. -TODO In SILC Server -=================== - - o TODO in commands (command.c and command_reply.c): - - o RESTART is not implemented - 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 check that cmd->pending == TRUE/FALSE). - - o TODO in notify types (packet_receive.c): +TODO/bugs In SILC Server +======================== - o SERVER_SIGNOFF notify type is not implemented + o When server quits and all clients of that server are removed from all + channels the channel keys are re-generated for all clients. This is + a bug and should be done only once per channel after all clients of + the server has been removed. o Acceptance of incoming connections (client and server connections) should be checked before key exchange protocol. Currently it is checked at the authentication phase after KE, that is ok, but it should - be checked before starting KE, as well. + be checked before starting KE, as well. This should be done so that + is first checks denied connections, then client connections and then + server connections. There is no use to execute the SKE if the connection + will not be allowed. o DNS/IP lookup blocks the server. This must be fixed. Check the resolver stuff (resolver(3), resolver(5)). Either we have to do the own resolver stuff (through scheduler, if possible without writing too much own stuff) or use threads. - o Packet processing can be made faster. All packet function in the - packet_receive.c has same prototypes. Instead of calling those from - huge switch() make a table of callback functions that can be called - directly by the packet type. - o Server says that it is able to listen on multiple ports but currently that is bogus. It can, but internals are for single server. @@ -74,11 +59,12 @@ TODO In SILC Server as well, IP/MASK, and not just plain IP. o Connection classes should be actually implemented in serverconfig.c. - They can be defined but they are totally ignored currently. + They can be defined but they are totally ignored currently. And they + should be redefined also. -TODO In SILC Libraries -====================== +TODO/bugs In SILC Libraries +=========================== o Implement PFS (Perfect Forward Secrecy) flag in SKE (and in client and server, actually). If PFS is set, re-key must cause new key exchange. @@ -92,21 +78,17 @@ TODO In SILC Libraries not in distribution), but it is not used yet, and it requires some tweaking on the Makefiles (we want static lib not shared). - o Rewrite the task system. I made it too complex and too "neat" and - it really should be rewritten. We don't need priorities really, one - priority is enough. This will simplify a lot the task system. - - o SIM support for SILC PKCS API needs to made so that they could be - used as SIM's. At the same time some work is required on prime - generation as the way it is done now sucks. Read from code for - more (silcpkcs.h). - o Random Number Generator needs some tweaking. Reading /dev/random may block resulting slow initialization of RNG. Some other things in the RNG may block as well. Also, I have some pending changes to the RNG that needs to be commited (from Schneier's Yarrow-160 paper). They should make the RNG even better. + o SIM support for SILC PKCS API needs to made so that they could be + used as SIM's. At the same time some work is required on prime + generation as the way it is done now sucks. Read from code for + more (silcpkcs.h). + TODO in the protocol before SILC 0.x ==================================== diff --git a/apps/silc/client_ops.c b/apps/silc/client_ops.c index 074cdfe2..647aa5b1 100644 --- a/apps/silc/client_ops.c +++ b/apps/silc/client_ops.c @@ -321,6 +321,31 @@ void silc_notify(SilcClient client, SilcClientConnection conn, } break; + case SILC_NOTIFY_TYPE_SERVER_SIGNOFF: + { + SilcClientEntry *clients; + unsigned int clients_count; + int i; + + (void)va_arg(vp, void *); + clients = va_arg(vp, SilcClientEntry *); + clients_count = va_arg(vp, unsigned int); + + for (i = 0; i < clients_count; i++) { + if (clients[i]->server) + snprintf(message, sizeof(message), "Server signoff: %s@%s %s%s%s", + clients[i]->nickname, clients[i]->server, + tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : ""); + else + snprintf(message, sizeof(message), "Server signoff: %s %s%s%s", + clients[i]->nickname, + tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : ""); + silc_print(client, "*** %s", message); + memset(message, 0, sizeof(message)); + } + return; + } + default: break; } diff --git a/apps/silcd/command.c b/apps/silcd/command.c index 75afbfd9..d72636f4 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -62,8 +62,7 @@ SilcServerCommand silc_command_list[] = SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG_STRICT | SILC_CF_REG), SILC_SERVER_CMD(cumode, CUMODE, SILC_CF_LAG | SILC_CF_REG), SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG_STRICT | SILC_CF_REG), - SILC_SERVER_CMD(restart, RESTART, - SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER), + SILC_SERVER_CMD(ban, BAN, SILC_CF_LAG_STRICT | SILC_CF_REG), SILC_SERVER_CMD(close, CLOSE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER), SILC_SERVER_CMD(shutdown, SHUTDOWN, SILC_CF_LAG | SILC_CF_REG | @@ -72,7 +71,6 @@ SilcServerCommand silc_command_list[] = SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER), SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG_STRICT | SILC_CF_REG), SILC_SERVER_CMD(users, USERS, SILC_CF_LAG | SILC_CF_REG), - SILC_SERVER_CMD(ban, BAN, SILC_CF_LAG_STRICT | SILC_CF_REG), { NULL, 0 }, }; @@ -488,7 +486,7 @@ silc_server_command_whois_check(SilcServerCommandContext cmd, for (i = 0; i < clients_count; i++) { entry = clients[i]; - if (entry->data.registered == FALSE) + if (!entry || entry->data.registered == FALSE) continue; if (!entry->nickname || !entry->username || !entry->userinfo) { @@ -717,37 +715,33 @@ silc_server_command_whois_from_client(SilcServerCommandContext cmd) } } } else { - clients = silc_idlist_get_clients_by_hash(server->local_list, - nick, server->md5hash, - &clients_count); - if (!clients) - clients = silc_idlist_get_clients_by_nickname(server->local_list, - nick, server_name, - &clients_count); + 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, + nick, server_name, + &clients, &clients_count); } /* Check global list as well */ - if (!clients) { - 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->global_list, - client_id[i], NULL); - if (entry) { - clients = silc_realloc(clients, sizeof(*clients) * - (clients_count + 1)); - clients[clients_count++] = entry; - } + 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->global_list, + client_id[i], NULL); + if (entry) { + clients = silc_realloc(clients, sizeof(*clients) * + (clients_count + 1)); + clients[clients_count++] = entry; } - } else { - clients = silc_idlist_get_clients_by_hash(server->global_list, - nick, server->md5hash, - &clients_count); - if (!clients) - clients = silc_idlist_get_clients_by_nickname(server->global_list, - nick, server_name, - &clients_count); } + } else { + 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, + nick, server_name, + &clients, &clients_count); } if (!clients) { @@ -828,17 +822,16 @@ silc_server_command_whois_from_server(SilcServerCommandContext cmd) } } } else { - clients = silc_idlist_get_clients_by_hash(server->local_list, - nick, server->md5hash, - &clients_count); - if (!clients) - clients = silc_idlist_get_clients_by_nickname(server->local_list, - nick, server_name, - &clients_count); + 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, + nick, server_name, + &clients, &clients_count); } /* If we are router we will check our global list as well. */ - if (!clients && server->server_type == SILC_ROUTER) { + if (server->server_type == SILC_ROUTER) { if (client_id_count) { /* Check all Client ID's received in the command packet */ for (i = 0; i < client_id_count; i++) { @@ -851,13 +844,12 @@ silc_server_command_whois_from_server(SilcServerCommandContext cmd) } } } else { - clients = silc_idlist_get_clients_by_hash(server->global_list, - nick, server->md5hash, - &clients_count); - if (!clients) - clients = silc_idlist_get_clients_by_nickname(server->global_list, - nick, server_name, - &clients_count); + 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, + nick, server_name, + &clients, &clients_count); } } @@ -1165,24 +1157,20 @@ silc_server_command_whowas_from_client(SilcServerCommandContext cmd) return 0; /* Get all clients matching that nickname from local list */ - clients = silc_idlist_get_clients_by_nickname(server->local_list, - nick, server_name, - &clients_count); - if (!clients) - clients = silc_idlist_get_clients_by_hash(server->local_list, - nick, server->md5hash, - &clients_count); + if (!silc_idlist_get_clients_by_nickname(server->local_list, + nick, server_name, + &clients, &clients_count)) + silc_idlist_get_clients_by_hash(server->local_list, + nick, server->md5hash, + &clients, &clients_count); /* Check global list as well */ - if (!clients) { - clients = silc_idlist_get_clients_by_nickname(server->global_list, - nick, server_name, - &clients_count); - if (!clients) - clients = silc_idlist_get_clients_by_hash(server->global_list, - nick, server->md5hash, - &clients_count); - } + if (!silc_idlist_get_clients_by_nickname(server->global_list, + nick, server_name, + &clients, &clients_count)) + silc_idlist_get_clients_by_hash(server->global_list, + nick, server->md5hash, + &clients, &clients_count); if (!silc_server_command_whowas_check(cmd, clients, clients_count)) { ret = -1; @@ -1219,23 +1207,21 @@ silc_server_command_whowas_from_server(SilcServerCommandContext cmd) /* Process the command request. Let's search for the requested client and send reply to the requesting server. */ - clients = silc_idlist_get_clients_by_nickname(server->local_list, - nick, server_name, - &clients_count); - if (!clients) - clients = silc_idlist_get_clients_by_hash(server->local_list, - nick, server->md5hash, - &clients_count); + if (!silc_idlist_get_clients_by_nickname(server->local_list, + nick, server_name, + &clients, &clients_count)) + silc_idlist_get_clients_by_hash(server->local_list, + nick, server->md5hash, + &clients, &clients_count); /* If we are router we will check our global list as well. */ - if (!clients && server->server_type == SILC_ROUTER) { - clients = silc_idlist_get_clients_by_nickname(server->global_list, - nick, server_name, - &clients_count); - if (!clients) - clients = silc_idlist_get_clients_by_hash(server->global_list, - nick, server->md5hash, - &clients_count); + if (server->server_type == SILC_ROUTER) { + if (!silc_idlist_get_clients_by_nickname(server->global_list, + nick, server_name, + &clients, &clients_count)) + silc_idlist_get_clients_by_hash(server->global_list, + nick, server->md5hash, + &clients, &clients_count); } if (!clients) { @@ -1301,7 +1287,7 @@ silc_server_command_identify_check(SilcServerCommandContext cmd, for (i = 0; i < clients_count; i++) { entry = clients[i]; - if (entry->data.registered == FALSE) + if (!entry || entry->data.registered == FALSE) continue; if (!entry->nickname) { @@ -1508,37 +1494,33 @@ silc_server_command_identify_from_client(SilcServerCommandContext cmd) } } } else { - clients = silc_idlist_get_clients_by_hash(server->local_list, - nick, server->md5hash, - &clients_count); - if (!clients) - clients = silc_idlist_get_clients_by_nickname(server->local_list, - nick, server_name, - &clients_count); + 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, + nick, server_name, + &clients, &clients_count); } /* Check global list as well */ - if (!clients) { - 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->global_list, - client_id[i], NULL); - if (entry) { - clients = silc_realloc(clients, sizeof(*clients) * - (clients_count + 1)); - clients[clients_count++] = entry; - } + 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->global_list, + client_id[i], NULL); + if (entry) { + clients = silc_realloc(clients, sizeof(*clients) * + (clients_count + 1)); + clients[clients_count++] = entry; } - } else { - clients = silc_idlist_get_clients_by_hash(server->global_list, - nick, server->md5hash, - &clients_count); - if (!clients) - clients = silc_idlist_get_clients_by_nickname(server->global_list, - nick, server_name, - &clients_count); } + } else { + 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, + nick, server_name, + &clients, &clients_count); } if (!clients) { @@ -1616,17 +1598,16 @@ silc_server_command_identify_from_server(SilcServerCommandContext cmd) } } } else { - clients = silc_idlist_get_clients_by_hash(server->local_list, - nick, server->md5hash, - &clients_count); - if (!clients) - clients = silc_idlist_get_clients_by_nickname(server->local_list, - nick, server_name, - &clients_count); + 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, + nick, server_name, + &clients, &clients_count); } /* If we are router we will check our global list as well. */ - if (!clients && server->server_type == SILC_ROUTER) { + if (server->server_type == SILC_ROUTER) { if (client_id_count) { /* Check all Client ID's received in the command packet */ for (i = 0; i < client_id_count; i++) { @@ -1639,13 +1620,12 @@ silc_server_command_identify_from_server(SilcServerCommandContext cmd) } } } else { - clients = silc_idlist_get_clients_by_hash(server->global_list, - nick, server->md5hash, - &clients_count); - if (!clients) - clients = silc_idlist_get_clients_by_nickname(server->global_list, - nick, server_name, - &clients_count); + 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, + nick, server_name, + &clients, &clients_count); } } @@ -4363,10 +4343,139 @@ SILC_SERVER_CMD_FUNC(connect) silc_server_command_free(cmd); } -SILC_SERVER_CMD_FUNC(restart) +/* Server side of command BAN. This is used to manage the ban list of the + channel. To add clients and remove clients from the ban list. */ + +SILC_SERVER_CMD_FUNC(ban) { SilcServerCommandContext cmd = (SilcServerCommandContext)context; + SilcServer server = cmd->server; + SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data; + SilcBuffer packet; + SilcChannelEntry channel; + SilcChannelClientEntry chl; + SilcChannelID *channel_id = NULL; + unsigned char *id, *add, *del; + unsigned int id_len, tmp_len; + unsigned short ident = silc_command_get_ident(cmd->payload); + + if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT) + goto out; + + SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_BAN, cmd, 0, 3); + + /* Get Channel ID */ + id = silc_argument_get_arg_type(cmd->args, 1, &id_len); + if (id) { + channel_id = silc_id_payload_parse_id(id, id_len); + if (!channel_id) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN, + SILC_STATUS_ERR_NO_CHANNEL_ID); + goto out; + } + } + + /* Get channel entry. The server must know about the channel since the + client is expected to be on the channel. */ + channel = silc_idlist_find_channel_by_id(server->local_list, + channel_id, NULL); + if (!channel) { + channel = silc_idlist_find_channel_by_id(server->global_list, + channel_id, NULL); + if (!channel) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN, + SILC_STATUS_ERR_NO_SUCH_CHANNEL); + goto out; + } + } + + /* Check whether this client is on the channel */ + if (!silc_server_client_on_channel(client, channel)) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN, + SILC_STATUS_ERR_NOT_ON_CHANNEL); + goto out; + } + + /* Get entry to the channel user list */ + silc_list_start(channel->user_list); + while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) + if (chl->client == client) + break; + + /* The client must be at least channel operator. */ + if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN, + SILC_STATUS_ERR_NO_CHANNEL_PRIV); + goto out; + } + + /* Get the new ban and add it to the ban list */ + add = silc_argument_get_arg_type(cmd->args, 2, &tmp_len); + if (add) { + if (!channel->ban_list) + channel->ban_list = silc_calloc(tmp_len + 2, sizeof(*channel->ban_list)); + else + channel->ban_list = silc_realloc(channel->ban_list, + sizeof(*channel->ban_list) * + (tmp_len + + strlen(channel->ban_list) + 2)); + if (add[tmp_len - 1] == ',') + add[tmp_len - 1] = '\0'; + + strncat(channel->ban_list, add, tmp_len); + strncat(channel->ban_list, ",", 1); + } + + /* Get the ban to be removed and remove it from the list */ + del = silc_argument_get_arg_type(cmd->args, 3, &tmp_len); + if (del && channel->ban_list) { + char *start, *end, *n; + + if (!strncmp(channel->ban_list, del, strlen(channel->ban_list) - 1)) { + silc_free(channel->ban_list); + channel->ban_list = NULL; + } else { + start = strstr(channel->ban_list, del); + if (start && strlen(start) >= tmp_len) { + end = start + tmp_len; + n = silc_calloc(strlen(channel->ban_list) - tmp_len, sizeof(*n)); + strncat(n, channel->ban_list, start - channel->ban_list); + strncat(n, end + 1, ((channel->ban_list + strlen(channel->ban_list)) - + end) - 1); + silc_free(channel->ban_list); + channel->ban_list = n; + } + } + } + + /* Send the BAN notify type to our primary router. */ + if (!server->standalone && (add || del)) + silc_server_send_notify_ban(server, server->router->connection, + server->server_type == SILC_ROUTER ? + TRUE : FALSE, channel, add, del); + + /* Send the reply back to the client */ + if (channel->ban_list) + packet = + silc_command_reply_payload_encode_va(SILC_COMMAND_BAN, + SILC_STATUS_OK, ident, 2, + 2, id, id_len, + 3, channel->ban_list, + strlen(channel->ban_list) - 1); + else + packet = + silc_command_reply_payload_encode_va(SILC_COMMAND_BAN, + SILC_STATUS_OK, ident, 1, + 2, id, id_len); + + silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, + packet->data, packet->len, FALSE); + + silc_buffer_free(packet); + out: + if (channel_id) + silc_free(channel_id); silc_server_command_free(cmd); } @@ -4471,7 +4580,7 @@ SILC_SERVER_CMD_FUNC(leave) SilcServer server = cmd->server; SilcSocketConnection sock = cmd->sock; SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data; - SilcChannelID *id; + SilcChannelID *id = NULL; SilcChannelEntry channel; unsigned int len; unsigned char *tmp; @@ -4540,6 +4649,8 @@ SILC_SERVER_CMD_FUNC(leave) silc_free(id); out: + if (id) + silc_free(id); silc_server_command_free(cmd); } @@ -4646,139 +4757,3 @@ SILC_SERVER_CMD_FUNC(users) out: silc_server_command_free(cmd); } - -/* Server side of command BAN. This is used to manage the ban list of the - channel. To add clients and remove clients from the ban list. */ - -SILC_SERVER_CMD_FUNC(ban) -{ - SilcServerCommandContext cmd = (SilcServerCommandContext)context; - SilcServer server = cmd->server; - SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data; - SilcBuffer packet; - SilcChannelEntry channel; - SilcChannelClientEntry chl; - SilcChannelID *channel_id = NULL; - unsigned char *id, *add, *del; - unsigned int id_len, tmp_len; - unsigned short ident = silc_command_get_ident(cmd->payload); - - if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT) - goto out; - - SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_BAN, cmd, 0, 3); - - /* Get Channel ID */ - id = silc_argument_get_arg_type(cmd->args, 1, &id_len); - if (id) { - channel_id = silc_id_payload_parse_id(id, id_len); - if (!channel_id) { - silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN, - SILC_STATUS_ERR_NO_CHANNEL_ID); - goto out; - } - } - - /* Get channel entry. The server must know about the channel since the - client is expected to be on the channel. */ - channel = silc_idlist_find_channel_by_id(server->local_list, - channel_id, NULL); - if (!channel) { - channel = silc_idlist_find_channel_by_id(server->global_list, - channel_id, NULL); - if (!channel) { - silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN, - SILC_STATUS_ERR_NO_SUCH_CHANNEL); - goto out; - } - } - - /* Check whether this client is on the channel */ - if (!silc_server_client_on_channel(client, channel)) { - silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN, - SILC_STATUS_ERR_NOT_ON_CHANNEL); - goto out; - } - - /* Get entry to the channel user list */ - silc_list_start(channel->user_list); - while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) - if (chl->client == client) - break; - - /* The client must be at least channel operator. */ - if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) { - silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN, - SILC_STATUS_ERR_NO_CHANNEL_PRIV); - goto out; - } - - /* Get the new ban and add it to the ban list */ - add = silc_argument_get_arg_type(cmd->args, 2, &tmp_len); - if (add) { - if (!channel->ban_list) - channel->ban_list = silc_calloc(tmp_len + 2, sizeof(*channel->ban_list)); - else - channel->ban_list = silc_realloc(channel->ban_list, - sizeof(*channel->ban_list) * - (tmp_len + - strlen(channel->ban_list) + 2)); - if (add[tmp_len - 1] == ',') - add[tmp_len - 1] = '\0'; - - strncat(channel->ban_list, add, tmp_len); - strncat(channel->ban_list, ",", 1); - } - - /* Get the ban to be removed and remove it from the list */ - del = silc_argument_get_arg_type(cmd->args, 3, &tmp_len); - if (del && channel->ban_list) { - char *start, *end, *n; - - if (!strncmp(channel->ban_list, del, strlen(channel->ban_list) - 1)) { - silc_free(channel->ban_list); - channel->ban_list = NULL; - } else { - start = strstr(channel->ban_list, del); - if (start && strlen(start) >= tmp_len) { - end = start + tmp_len; - n = silc_calloc(strlen(channel->ban_list) - tmp_len, sizeof(*n)); - strncat(n, channel->ban_list, start - channel->ban_list); - strncat(n, end + 1, ((channel->ban_list + strlen(channel->ban_list)) - - end) - 1); - silc_free(channel->ban_list); - channel->ban_list = n; - } - } - } - - /* Send the BAN notify type to our primary router. */ - if (!server->standalone && (add || del)) - silc_server_send_notify_ban(server, server->router->connection, - server->server_type == SILC_ROUTER ? - TRUE : FALSE, channel, add, del); - - /* Send the reply back to the client */ - if (channel->ban_list) - packet = - silc_command_reply_payload_encode_va(SILC_COMMAND_BAN, - SILC_STATUS_OK, ident, 2, - 2, id, id_len, - 3, channel->ban_list, - strlen(channel->ban_list) - 1); - else - packet = - silc_command_reply_payload_encode_va(SILC_COMMAND_BAN, - SILC_STATUS_OK, ident, 1, - 2, id, id_len); - - silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, - packet->data, packet->len, FALSE); - - silc_buffer_free(packet); - - out: - if (channel_id) - silc_free(channel_id); - silc_server_command_free(cmd); -} diff --git a/apps/silcd/command.h b/apps/silcd/command.h index f8b7a5fe..b33221db 100644 --- a/apps/silcd/command.h +++ b/apps/silcd/command.h @@ -148,12 +148,11 @@ SILC_SERVER_CMD_FUNC(cmode); SILC_SERVER_CMD_FUNC(cumode); SILC_SERVER_CMD_FUNC(kick); SILC_SERVER_CMD_FUNC(ignore); -SILC_SERVER_CMD_FUNC(restart); +SILC_SERVER_CMD_FUNC(ban); SILC_SERVER_CMD_FUNC(close); SILC_SERVER_CMD_FUNC(shutdown); SILC_SERVER_CMD_FUNC(silcoper); SILC_SERVER_CMD_FUNC(leave); SILC_SERVER_CMD_FUNC(users); -SILC_SERVER_CMD_FUNC(ban); #endif diff --git a/apps/silcd/command_reply.c b/apps/silcd/command_reply.c index 588c1a0c..88211f55 100644 --- a/apps/silcd/command_reply.c +++ b/apps/silcd/command_reply.c @@ -23,27 +23,26 @@ #include "server_internal.h" #include "command_reply.h" +/* All functions that call the COMMAND_CHECK_STATUS or the + COMMAND_CHECK_STATUS_LIST macros must have out: goto label. */ + #define COMMAND_CHECK_STATUS \ do { \ SILC_LOG_DEBUG(("Start")); \ SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \ - if (status != SILC_STATUS_OK) { \ - silc_server_command_reply_free(cmd); \ - return; \ - } \ + if (status != SILC_STATUS_OK) \ + goto out; \ } while(0) #define COMMAND_CHECK_STATUS_LIST \ do { \ SILC_LOG_DEBUG(("Start")); \ SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \ - if (status != SILC_STATUS_OK && \ + if (status != SILC_STATUS_OK && \ status != SILC_STATUS_LIST_START && \ status != SILC_STATUS_LIST_ITEM && \ - status != SILC_STATUS_LIST_END) { \ - silc_server_command_reply_free(cmd); \ - return; \ - } \ + status != SILC_STATUS_LIST_END) \ + goto out; \ } while(0) /* Server command reply list. Not all commands have reply function as @@ -250,10 +249,15 @@ SILC_SERVER_CMD_REPLY_FUNC(whois) if (!silc_server_command_reply_whois_save(cmd)) goto out; - /* Execute any pending commands */ - SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS); + /* Pending callbacks are not executed if this was an list entry */ + if (status != SILC_STATUS_OK && + status != SILC_STATUS_LIST_END) { + silc_server_command_reply_free(cmd); + return; + } out: + SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS); SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS); silc_server_command_reply_free(cmd); } @@ -370,10 +374,15 @@ SILC_SERVER_CMD_REPLY_FUNC(whowas) if (!silc_server_command_reply_whowas_save(cmd)) goto out; - /* Execute any pending commands */ - SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS); + /* Pending callbacks are not executed if this was an list entry */ + if (status != SILC_STATUS_OK && + status != SILC_STATUS_LIST_END) { + silc_server_command_reply_free(cmd); + return; + } out: + SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS); SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOWAS); silc_server_command_reply_free(cmd); } @@ -492,10 +501,15 @@ SILC_SERVER_CMD_REPLY_FUNC(identify) if (!silc_server_command_reply_identify_save(cmd)) goto out; - /* Execute any pending commands */ - SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY); + /* Pending callbacks are not executed if this was an list entry */ + if (status != SILC_STATUS_OK && + status != SILC_STATUS_LIST_END) { + silc_server_command_reply_free(cmd); + return; + } out: + SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY); SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY); silc_server_command_reply_free(cmd); } @@ -550,10 +564,8 @@ SILC_SERVER_CMD_REPLY_FUNC(info) entry->server_info = tmp ? strdup(tmp) : NULL; - /* Execute any pending commands */ - SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_INFO); - out: + SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_INFO); SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO); silc_server_command_reply_free(cmd); } @@ -565,7 +577,7 @@ SILC_SERVER_CMD_REPLY_FUNC(motd) SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context; SilcServer server = cmd->server; SilcCommandStatus status; - SilcServerEntry entry; + SilcServerEntry entry = NULL; SilcServerID *server_id; unsigned int tmp_len; unsigned char *tmp; @@ -595,14 +607,13 @@ SILC_SERVER_CMD_REPLY_FUNC(motd) entry->motd = tmp; - /* Execute any pending commands */ - SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_MOTD); - - entry->motd = NULL; - out: + SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_MOTD); SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD); silc_server_command_reply_free(cmd); + + if (entry) + entry->motd = NULL; } /* Received reply for forwarded JOIN command. Router has created or joined @@ -623,7 +634,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join) unsigned char *id_string; char *channel_name, *tmp; unsigned int mode, created; - SilcBuffer keyp = NULL, client_id_list, client_mode_list; + SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL; COMMAND_CHECK_STATUS; @@ -794,17 +805,17 @@ SILC_SERVER_CMD_REPLY_FUNC(join) client_id, client_id_list, client_mode_list, list_count); - silc_buffer_free(client_id_list); - silc_buffer_free(client_mode_list); - - /* Execute any pending commands */ - SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN); - out: + SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN); SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN); if (client_id) silc_free(client_id); silc_server_command_reply_free(cmd); + + if (client_id_list) + silc_buffer_free(client_id_list); + if (client_mode_list) + silc_buffer_free(client_mode_list); } SILC_SERVER_CMD_REPLY_FUNC(users) @@ -872,10 +883,8 @@ SILC_SERVER_CMD_REPLY_FUNC(users) silc_buffer_free(client_id_list); silc_buffer_free(client_mode_list); - /* Execute any pending commands */ - SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS); - out: + SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS); SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS); if (channel_id) silc_free(channel_id); diff --git a/apps/silcd/idlist.c b/apps/silcd/idlist.c index 02f9f41e..ed4f5065 100644 --- a/apps/silcd/idlist.c +++ b/apps/silcd/idlist.c @@ -248,13 +248,14 @@ silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id, /* Removes and free's server entry from ID list */ -void silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry) +int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry) { if (entry) { /* Remove from cache */ if (entry->id) - silc_idcache_del_by_id(id_list->servers, SILC_ID_SERVER, - (void *)entry->id); + if (!silc_idcache_del_by_id(id_list->servers, SILC_ID_SERVER, + (void *)entry->id)) + return FALSE; /* Free data */ if (entry->server_name) @@ -264,7 +265,10 @@ void silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry) memset(entry, 'F', sizeof(*entry)); silc_free(entry); + return TRUE; } + + return FALSE; } /****************************************************************************** @@ -346,35 +350,36 @@ int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry) /* Returns all clients matching requested nickname. Number of clients is returned to `clients_count'. Caller must free the returned table. */ -SilcClientEntry * -silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname, - char *server, unsigned int *clients_count) +int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname, + char *server, + SilcClientEntry **clients, + unsigned int *clients_count) { SilcIDCacheList list = NULL; SilcIDCacheEntry id_cache = NULL; - SilcClientEntry *clients; int i; SILC_LOG_DEBUG(("Start")); if (!silc_idcache_find_by_data(id_list->clients, nickname, &list)) - return NULL; + return FALSE; - clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients)); + *clients = silc_realloc(*clients, + (silc_idcache_list_count(list) + *clients_count) * + sizeof(**clients)); i = 0; silc_idcache_list_first(list, &id_cache); - clients[i++] = (SilcClientEntry)id_cache->context; + (*clients)[i++] = (SilcClientEntry)id_cache->context; while (silc_idcache_list_next(list, &id_cache)) - clients[i++] = (SilcClientEntry)id_cache->context; + (*clients)[i++] = (SilcClientEntry)id_cache->context; silc_idcache_list_free(list); - if (clients_count) - *clients_count = i; + *clients_count += i; - return clients; + return TRUE; } /* Returns all clients matching requested nickname. Number of clients is @@ -384,14 +389,13 @@ silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname, list may have hash. Thus, this is not fully reliable function. Instead this should probably check the hash from the list of client ID's. */ -SilcClientEntry * -silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname, - SilcHash md5hash, - unsigned int *clients_count) +int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname, + SilcHash md5hash, + SilcClientEntry **clients, + unsigned int *clients_count) { SilcIDCacheList list = NULL; SilcIDCacheEntry id_cache = NULL; - SilcClientEntry *clients; unsigned char hash[32]; int i; @@ -400,23 +404,24 @@ silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname, silc_hash_make(md5hash, nickname, strlen(nickname), hash); if (!silc_idcache_find_by_data(id_list->clients, hash, &list)) - return NULL; + return FALSE; - clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients)); + *clients = silc_realloc(*clients, + (silc_idcache_list_count(list) + *clients_count) * + sizeof(**clients)); i = 0; silc_idcache_list_first(list, &id_cache); - clients[i++] = (SilcClientEntry)id_cache->context; + (*clients)[i++] = (SilcClientEntry)id_cache->context; while (silc_idcache_list_next(list, &id_cache)) - clients[i++] = (SilcClientEntry)id_cache->context; + (*clients)[i++] = (SilcClientEntry)id_cache->context; silc_idcache_list_free(list); - if (clients_count) - *clients_count = i; + *clients_count += i; - return clients; + return TRUE; } /* Finds client by nickname hash. */ diff --git a/apps/silcd/idlist.h b/apps/silcd/idlist.h index f36a6a63..0fd6207b 100644 --- a/apps/silcd/idlist.h +++ b/apps/silcd/idlist.h @@ -520,20 +520,21 @@ silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname, SilcServerEntry silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id, SilcServerID *new_id); -void silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry); +int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry); SilcClientEntry silc_idlist_add_client(SilcIDList id_list, unsigned char *nickname, unsigned int nickname_len, char *username, char *userinfo, SilcClientID *id, SilcServerEntry router, void *connection); int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry); -SilcClientEntry * -silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname, - char *server, unsigned int *clients_count); -SilcClientEntry * -silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname, - SilcHash md5hash, - unsigned int *clients_count); +int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname, + char *server, + SilcClientEntry **clients, + unsigned int *clients_count); +int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname, + SilcHash md5hash, + SilcClientEntry **clients, + unsigned int *clients_count); SilcClientEntry silc_idlist_find_client_by_hash(SilcIDList id_list, char *nickname, SilcHash md5hash, SilcIDCacheEntry *ret_entry); diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index 8e50b857..65ceb85d 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -39,8 +39,10 @@ void silc_server_notify(SilcServer server, SilcArgumentPayload args; SilcChannelID *channel_id, *channel_id2; SilcClientID *client_id, *client_id2; + SilcServerID *server_id; SilcChannelEntry channel; SilcClientEntry client; + SilcServerEntry server_entry; SilcChannelClientEntry chl; SilcIDCacheEntry cache; unsigned int mode; @@ -680,7 +682,43 @@ void silc_server_notify(SilcServer server, break; case SILC_NOTIFY_TYPE_SERVER_SIGNOFF: - SILC_LOG_DEBUG(("SERVER SIGNOFF notify (not-impl XXX)")); + /* + * Remove the server entry and all clients that this server owns. + */ + + SILC_LOG_DEBUG(("SERVER SIGNOFF notify")); + + /* Get Server ID */ + tmp = silc_argument_get_arg_type(args, 1, &tmp_len); + if (!tmp) + goto out; + server_id = silc_id_payload_parse_id(tmp, tmp_len); + if (!server_id) + goto out; + + /* Get server entry */ + server_entry = silc_idlist_find_server_by_id(server->global_list, + server_id, NULL); + if (!server_entry) { + server_entry = silc_idlist_find_server_by_id(server->local_list, + server_id, NULL); + if (!server_entry) { + silc_free(server_id); + goto out; + } + } + silc_free(server_id); + + /* Free all client entries that this server owns as they will + become invalid now as well. */ + silc_server_remove_clients_by_server(server, server_entry, TRUE); + + /* Remove the server entry */ + if (!silc_idlist_del_server(server->global_list, server_entry)) + silc_idlist_del_server(server->local_list, server_entry); + + /* XXX update statistics */ + break; case SILC_NOTIFY_TYPE_KICKED: @@ -1301,6 +1339,7 @@ SilcClientEntry silc_server_new_client(SilcServer server, cache->id = (void *)client_id; cache->type = SILC_ID_CLIENT; cache->data = username; + cache->data_len = strlen(username); silc_idcache_sort_by_data(server->local_list->clients); /* Notify our router about new client on the SILC network */ diff --git a/apps/silcd/packet_send.c b/apps/silcd/packet_send.c index 3ec4e53c..6b1a1a8d 100644 --- a/apps/silcd/packet_send.c +++ b/apps/silcd/packet_send.c @@ -860,6 +860,24 @@ void silc_server_send_notify(SilcServer server, silc_buffer_free(packet); } +/* Sends notify message and gets the arguments from the `args' Argument + Payloads. */ + +void silc_server_send_notify_args(SilcServer server, + SilcSocketConnection sock, + int broadcast, + SilcNotifyType type, + unsigned int argc, + SilcBuffer args) +{ + SilcBuffer packet; + + packet = silc_notify_payload_encode_args(type, argc, args); + silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 0, + packet->data, packet->len, FALSE); + silc_buffer_free(packet); +} + /* Send CHANNEL_CHANGE notify type. This tells the receiver to replace the `old_id' with the `new_id'. */ @@ -1025,24 +1043,6 @@ void silc_server_send_notify_signoff(SilcServer server, silc_buffer_free(idp); } -/* Sends SERVER_SIGNOFF notify type. This tells that `server_id' server - has quit SILC network. */ - -void silc_server_send_notify_server_signoff(SilcServer server, - SilcSocketConnection sock, - int broadcast, - SilcServerID *server_id, - unsigned int server_id_len) -{ - SilcBuffer idp; - - idp = silc_id_payload_encode((void *)server_id, SILC_ID_SERVER); - silc_server_send_notify(server, sock, broadcast, - SILC_NOTIFY_TYPE_SERVER_SIGNOFF, - 1, idp->data, idp->len); - silc_buffer_free(idp); -} - /* Sends TOPIC_SET notify type. This tells that `client_id' changed the `channel's topic to `topic'. The Notify packet is always destined to the channel. This function is used to send the topic set notifies diff --git a/apps/silcd/packet_send.h b/apps/silcd/packet_send.h index 22370969..3ec5de63 100644 --- a/apps/silcd/packet_send.h +++ b/apps/silcd/packet_send.h @@ -97,6 +97,12 @@ void silc_server_send_notify(SilcServer server, int broadcast, SilcNotifyType type, unsigned int argc, ...); +void silc_server_send_notify_args(SilcServer server, + SilcSocketConnection sock, + int broadcast, + SilcNotifyType type, + unsigned int argc, + SilcBuffer args); void silc_server_send_notify_channel_change(SilcServer server, SilcSocketConnection sock, int broadcast, @@ -144,11 +150,6 @@ void silc_server_send_notify_signoff(SilcServer server, SilcClientID *client_id, unsigned int client_id_len, char *message); -void silc_server_send_notify_server_signoff(SilcServer server, - SilcSocketConnection sock, - int broadcast, - SilcServerID *server_id, - unsigned int server_id_len); void silc_server_send_notify_topic_set(SilcServer server, SilcSocketConnection sock, int broadcast, diff --git a/apps/silcd/protocol.c b/apps/silcd/protocol.c index cea428ca..240771e2 100644 --- a/apps/silcd/protocol.c +++ b/apps/silcd/protocol.c @@ -875,6 +875,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth) silc_server_get_public_key_auth(server, ctx->auth_data, sign, &auth_data_len, ctx->ske); + auth_data = silc_calloc(auth_data_len, sizeof(*auth_data)); + memcpy(auth_data, sign, auth_data_len); break; } } diff --git a/apps/silcd/server.c b/apps/silcd/server.c index b96d5043..3003bbbf 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -2087,18 +2087,9 @@ void silc_server_free_sock_user_data(SilcServer server, { SilcServerEntry user_data = (SilcServerEntry)sock->user_data; - /* Send REMOVE_ID packet to routers. */ - if (!server->standalone && server->router) - silc_server_send_notify_server_signoff(server, - server->router->connection, - server->server_type == - SILC_SERVER ? - FALSE : TRUE, user_data->id, - SILC_ID_SERVER_LEN); - - /* Then also free all client entries that this server owns as - they will become invalid now as well. */ - silc_server_remove_clients_by_server(server, user_data); + /* Free all client entries that this server owns as they will + become invalid now as well. */ + silc_server_remove_clients_by_server(server, user_data, TRUE); /* If this was our primary router connection then we're lost to the outside world. */ @@ -2132,17 +2123,38 @@ void silc_server_free_sock_user_data(SilcServer server, /* This function is used to remove all client entries by the server `entry'. This is called when the connection is lost to the server. In this case - we must invalidate all the client entries owned by the server `entry'. */ + we must invalidate all the client entries owned by the server `entry'. + If the `server_signoff' is TRUE then the SERVER_SIGNOFF notify is + distributed to our local clients. */ int silc_server_remove_clients_by_server(SilcServer server, - SilcServerEntry entry) + SilcServerEntry entry, + int server_signoff) { SilcIDCacheList list = NULL; SilcIDCacheEntry id_cache = NULL; SilcClientEntry client = NULL; + SilcBuffer idp; + SilcClientEntry *clients = NULL; + unsigned int clients_c = 0; + unsigned char **argv = NULL; + unsigned int *argv_lens = NULL, *argv_types = NULL, argc = 0; + int i; SILC_LOG_DEBUG(("Start")); + if (server_signoff) { + idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER); + argv = silc_realloc(argv, sizeof(*argv) * (argc + 1)); + argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) * (argc + 1)); + argv_types = silc_realloc(argv_types, sizeof(*argv_types) * (argc + 1)); + argv[argc] = idp->data; + argv_lens[argc] = idp->len; + argv_types[argc] = argc + 1; + argc++; + silc_buffer_free(idp); + } + if (silc_idcache_find_by_id(server->local_list->clients, SILC_ID_CACHE_ANY, SILC_ID_CLIENT, &list)) { @@ -2151,15 +2163,37 @@ int silc_server_remove_clients_by_server(SilcServer server, client = (SilcClientEntry)id_cache->context; if (client->router != entry) { + if (server_signoff && client->connection) { + clients = silc_realloc(clients, + sizeof(*clients) * (clients_c + 1)); + clients[clients_c] = client; + clients_c++; + } + if (!silc_idcache_list_next(list, &id_cache)) break; else continue; } + if (server_signoff) { + idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT); + argv = silc_realloc(argv, sizeof(*argv) * (argc + 1)); + argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) * + (argc + 1)); + argv_types = silc_realloc(argv_types, sizeof(*argv_types) * + (argc + 1)); + argv[argc] = silc_calloc(idp->len, sizeof(*argv[0])); + memcpy(argv[argc], idp->data, idp->len); + argv_lens[argc] = idp->len; + argv_types[argc] = argc + 1; + argc++; + silc_buffer_free(idp); + } + /* Remove the client entry */ - silc_server_remove_from_channels(server, NULL, client, TRUE, - NULL, TRUE); + silc_server_remove_from_channels(server, NULL, client, FALSE, + NULL, FALSE); silc_idlist_del_client(server->local_list, client); if (!silc_idcache_list_next(list, &id_cache)) @@ -2177,15 +2211,37 @@ int silc_server_remove_clients_by_server(SilcServer server, client = (SilcClientEntry)id_cache->context; if (client->router != entry) { + if (server_signoff && client->connection) { + clients = silc_realloc(clients, + sizeof(*clients) * (clients_c + 1)); + clients[clients_c] = client; + clients_c++; + } + if (!silc_idcache_list_next(list, &id_cache)) break; else continue; } + if (server_signoff) { + idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT); + argv = silc_realloc(argv, sizeof(*argv) * (argc + 1)); + argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) * + (argc + 1)); + argv_types = silc_realloc(argv_types, sizeof(*argv_types) * + (argc + 1)); + argv[argc] = silc_calloc(idp->len, sizeof(*argv[0])); + memcpy(argv[argc], idp->data, idp->len); + argv_lens[argc] = idp->len; + argv_types[argc] = argc + 1; + argc++; + silc_buffer_free(idp); + } + /* Remove the client entry */ - silc_server_remove_from_channels(server, NULL, client, TRUE, - NULL, TRUE); + silc_server_remove_from_channels(server, NULL, client, FALSE, + NULL, FALSE); silc_idlist_del_client(server->global_list, client); if (!silc_idcache_list_next(list, &id_cache)) @@ -2194,7 +2250,40 @@ int silc_server_remove_clients_by_server(SilcServer server, } silc_idcache_list_free(list); } - + + /* Send the SERVER_SIGNOFF notify */ + if (server_signoff) { + SilcBuffer args; + + /* Send SERVER_SIGNOFF notify to our primary router */ + if (!server->standalone && server->router) { + args = silc_argument_payload_encode(1, argv, argv_lens, + argv_types); + silc_server_send_notify_args(server, + server->router->connection, + server->server_type == + SILC_SERVER ? FALSE : TRUE, + SILC_NOTIFY_TYPE_SERVER_SIGNOFF, + argc, args); + silc_buffer_free(args); + } + + args = silc_argument_payload_encode(argc, argv, argv_lens, + argv_types); + /* Send to local clients */ + for (i = 0; i < clients_c; i++) { + silc_server_send_notify_args(server, clients[i]->connection, + FALSE, SILC_NOTIFY_TYPE_SERVER_SIGNOFF, + argc, args); + } + + silc_free(clients); + silc_buffer_free(args); + silc_free(argv); + silc_free(argv_lens); + silc_free(argv_types); + } + return TRUE; } @@ -2353,7 +2442,7 @@ void silc_server_remove_from_channels(SilcServer server, silc_server_create_channel_key(server, channel, 0); /* Send the channel key to the channel. The key of course is not sent - to the client who was removed f rom the channel. */ + to the client who was removed from the channel. */ silc_server_send_channel_key(server, client->connection, channel, server->server_type == SILC_ROUTER ? FALSE : !server->standalone); diff --git a/apps/silcd/server.h b/apps/silcd/server.h index 0cd883a5..e0d277ba 100644 --- a/apps/silcd/server.h +++ b/apps/silcd/server.h @@ -104,7 +104,8 @@ void silc_server_free_sock_user_data(SilcServer server, int silc_server_channel_has_global(SilcChannelEntry channel); int silc_server_channel_has_local(SilcChannelEntry channel); int silc_server_remove_clients_by_server(SilcServer server, - SilcServerEntry entry); + SilcServerEntry entry, + int server_signoff); void silc_server_remove_from_channels(SilcServer server, SilcSocketConnection sock, SilcClientEntry client, diff --git a/doc/draft-riikonen-silc-pp-02.nroff b/doc/draft-riikonen-silc-pp-02.nroff index 5c08f6da..1e734c33 100644 --- a/doc/draft-riikonen-silc-pp-02.nroff +++ b/doc/draft-riikonen-silc-pp-02.nroff @@ -1282,10 +1282,15 @@ ID's sent in arguments are sent inside ID Payload. Sent when server quits SILC network. Those clients from this server that are on channels must be removed from the channel. - Max Arguments: 1 - Arguments: (1) - - The is the server's ID. + Max Arguments: 2000 + Arguments: (1) (n) [ [...] + + The is the server's ID. The rest of the arguments are + the Client ID's of the client's who are coming from this server and + are thus quitting the SILC network also. If the maximum number of + arguments are reached another SILC_NOTIFY_TYPE_SERVER_SIGNOFF notify + packet must be sent. When this notify packet is sent between routers + the Client ID's may be omitted. 12 SILC_NOTIFY_TYPE_KICKED diff --git a/doc/draft-riikonen-silc-spec-02.nroff b/doc/draft-riikonen-silc-spec-02.nroff index 40508c30..6c6f800d 100644 --- a/doc/draft-riikonen-silc-spec-02.nroff +++ b/doc/draft-riikonen-silc-spec-02.nroff @@ -3008,26 +3008,52 @@ List of all defined commands in SILC follows. SILC_STATUS_ERR_NO_CLIENT_ID - 20 SILC_COMMAND_RESTART + 20 SILC_COMMAND_BAN - Max Arguments: 0 - Arguments: None + Max Arguments: 3 + Arguments: (1) (2) [] + (3) [] + + This command is used to manage the ban list of the channel + indicated by the . A client that is banned from + channel is no longer able to join the channel. The client which + is executing this command must have at least channel operator + privileges on the channel. + + The and are used to add to and + remove from the ban list. The format of the and + the is of following format: + + [[@]!][]@[] + + The server must send the notify type SILC_NOTIFY_TYPE_BAN to its + primary router after adding to or removing from the ban list. + The wildcards may be used with this command. If adding or removing + from than one clients then the lists are an comma (`,') separated + list. + + If this command is executed without the ban arguments the command + merely replies with the current ban list. - This command may only be used by server operator to force a - server to restart itself. Reply messages to the command: - Max Arguments: 1 - Arguments: (1) + Max Arguments: 3 + Arguments: (1) (2) + (3) [] - This command replies only with Status Payload. + This command replies with the of the channel and + the current of the channel if it exists. Status messages: SILC_STATUS_OK SILC_STATUS_ERR_NOT_REGISTERED - SILC_STATUS_ERR_NO_SERVER_PRIV + SILC_STATUS_ERR_TOO_MANY_PARAMS + SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID + SILC_STATUS_ERR_NO_CHANNEL_ID + SILC_STATUS_ERR_NOT_ON_CHANNEL + SILC_STATUS_ERR_NO_CHANNEL_PRIV 21 SILC_COMMAND_CLOSE @@ -3200,54 +3226,6 @@ List of all defined commands in SILC follows. SILC_STATUS_ERR_NOT_ON_CHANNEL - 26 SILC_COMMAND_BAN - - Max Arguments: 3 - Arguments: (1) (2) [] - (3) [] - - This command is used to manage the ban list of the channel - indicated by the . A client that is banned from - channel is no longer able to join the channel. The client which - is executing this command must have at least channel operator - privileges on the channel. - - The and are used to add to and - remove from the ban list. The format of the and - the is of following format: - - [[@]!][]@[] - - The server must send the notify type SILC_NOTIFY_TYPE_BAN to its - primary router after adding to or removing from the ban list. - The wildcards may be used with this command. If adding or removing - from than one clients then the lists are an comma (`,') separated - list. - - If this command is executed without the ban arguments the command - merely replies with the current ban list. - - - Reply messages to the command: - - Max Arguments: 3 - Arguments: (1) (2) - (3) [] - - This command replies with the of the channel and - the current of the channel if it exists. - - Status messages: - - SILC_STATUS_OK - SILC_STATUS_ERR_NOT_REGISTERED - SILC_STATUS_ERR_TOO_MANY_PARAMS - SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID - SILC_STATUS_ERR_NO_CHANNEL_ID - SILC_STATUS_ERR_NOT_ON_CHANNEL - SILC_STATUS_ERR_NO_CHANNEL_PRIV - - 27 - 199 Currently undefined commands. diff --git a/lib/silcclient/client_notify.c b/lib/silcclient/client_notify.c index afb95fc0..14b3b591 100644 --- a/lib/silcclient/client_notify.c +++ b/lib/silcclient/client_notify.c @@ -688,9 +688,7 @@ void silc_client_notify_by_server(SilcClient client, /* Get comment */ tmp = silc_argument_get_arg_type(args, 2, &tmp_len); - /* Notify application. The channel entry is sent last as this notify - is for channel but application don't know it from the arguments - sent by server. */ + /* Notify application. */ client->ops->notify(client, conn, type, client_entry, tmp); if (client_entry != conn->local_entry) { @@ -713,6 +711,68 @@ void silc_client_notify_by_server(SilcClient client, break; + case SILC_NOTIFY_TYPE_SERVER_SIGNOFF: + { + /* + * A server quit the SILC network and some clients must be removed + * from channels as they quit as well. + */ + SilcClientEntry *clients = NULL; + unsigned int clients_count = 0; + int i; + + for (i = 1; i < silc_argument_get_arg_num(args); i++) { + /* Get Client ID */ + tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len); + if (tmp) { + client_id = silc_id_payload_parse_id(tmp, tmp_len); + if (!client_id) + goto out; + + /* Get the client entry */ + client_entry = silc_client_get_client_by_id(client, conn, client_id); + if (client_entry) { + clients = silc_realloc(clients, sizeof(*clients) * + (clients_count + 1)); + clients[clients_count] = client_entry; + clients_count++; + } + silc_free(client_id); + } + } + client_id = NULL; + + /* Notify application. We don't keep server entries so the server + entry is returned as NULL. The client's are returned as array + of SilcClientEntry pointers. */ + client->ops->notify(client, conn, type, NULL, clients, clients_count); + + for (i = 0; i < clients_count; i++) { + /* Remove client from all channels */ + client_entry = clients[i]; + if (client_entry == conn->local_entry) + continue; + + silc_client_remove_from_channels(client, conn, client_entry); + silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, + client_entry->id); + if (client_entry->nickname) + silc_free(client_entry->nickname); + if (client_entry->server) + silc_free(client_entry->server); + if (client_entry->id) + silc_free(client_entry->id); + if (client_entry->send_key) + silc_cipher_free(client_entry->send_key); + if (client_entry->receive_key) + silc_cipher_free(client_entry->receive_key); + silc_free(client_entry); + } + silc_free(clients); + + } + break; + default: break; } diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index 3a3e8d14..9f068e13 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -48,8 +48,7 @@ SilcClientCommand silc_command_list[] = SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 4), SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", SILC_CF_LAG | SILC_CF_REG, 5), SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 4), - SILC_CLIENT_CMD(restart, RESTART, "RESTART", - SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2), + SILC_CLIENT_CMD(ban, BAN, "BAN", SILC_CF_LAG | SILC_CF_REG, 3), SILC_CLIENT_CMD(close, CLOSE, "CLOSE", SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 3), SILC_CLIENT_CMD(shutdown, SHUTDOWN, "SHUTDOWN", @@ -58,7 +57,6 @@ SilcClientCommand silc_command_list[] = SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 3), SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2), SILC_CLIENT_CMD(users, USERS, "USERS", SILC_CF_LAG | SILC_CF_REG, 2), - SILC_CLIENT_CMD(ban, BAN, "BAN", SILC_CF_LAG | SILC_CF_REG, 3), { NULL, 0, NULL, 0, 0 }, }; @@ -808,7 +806,7 @@ SILC_CLIENT_CMD_FUNC(info) SilcClientCommandContext cmd = (SilcClientCommandContext)context; SilcClientConnection conn = cmd->conn; SilcBuffer buffer; - char *name; + char *name = NULL; if (!cmd->conn) { SILC_NOT_CONNECTED(cmd->client, cmd->conn); @@ -816,17 +814,21 @@ SILC_CLIENT_CMD_FUNC(info) goto out; } - if (cmd->argc < 2) - name = strdup(conn->remote_host); - else + if (cmd->argc == 2) name = strdup(cmd->argv[1]); /* Send the command */ - buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1, - 1, name, strlen(name)); + if (name) + buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1, + 1, name, strlen(name)); + else + buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0, + NULL, NULL, NULL, 0); silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); + if (name) + silc_free(name); /* Notify application */ COMMAND; @@ -1741,13 +1743,16 @@ SILC_CLIENT_CMD_FUNC(connect) silc_client_command_free(cmd); } -/* RESTART command. Restarts the server. You must be server operator - to be able to use this command. */ +/* Command BAN. This is used to manage the ban list of the channel. */ -SILC_CLIENT_CMD_FUNC(restart) +SILC_CLIENT_CMD_FUNC(ban) { SilcClientCommandContext cmd = (SilcClientCommandContext)context; - SilcBuffer buffer; + SilcClientConnection conn = cmd->conn; + SilcChannelEntry channel; + SilcBuffer buffer, chidp; + int type = 0; + char *name, *ban = NULL; if (!cmd->conn) { SILC_NOT_CONNECTED(cmd->client, cmd->conn); @@ -1755,12 +1760,58 @@ SILC_CLIENT_CMD_FUNC(restart) goto out; } - buffer = silc_command_payload_encode(SILC_COMMAND_RESTART, 0, - NULL, NULL, NULL, 0); - silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND, - NULL, 0, NULL, NULL, - buffer->data, buffer->len, TRUE); + if (cmd->argc < 2) { + cmd->client->ops->say(cmd->client, conn, + "Usage: /BAN " + "[+|-[[@[![@hostname>]]]]]"); + COMMAND_ERROR; + goto out; + } + + if (cmd->argv[1][0] == '*') { + if (!conn->current_channel) { + cmd->client->ops->say(cmd->client, conn, "You are not on any channel"); + COMMAND_ERROR; + goto out; + } + + channel = conn->current_channel; + } else { + name = cmd->argv[1]; + + channel = silc_client_get_channel(cmd->client, conn, name); + if (!channel) { + cmd->client->ops->say(cmd->client, conn, "You are on that channel"); + COMMAND_ERROR; + goto out; + } + } + + if (cmd->argc == 3) { + if (cmd->argv[2][0] == '+') + type = 2; + else + type = 3; + + ban = cmd->argv[2]; + ban++; + } + + chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL); + + /* Send the command */ + if (ban) + buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2, + 1, chidp->data, chidp->len, + type, ban, strlen(ban)); + else + buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1, + 1, chidp->data, chidp->len); + + silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, + 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); + silc_buffer_free(chidp); /* Notify application */ COMMAND; @@ -1998,80 +2049,3 @@ SILC_CLIENT_CMD_FUNC(users) out: silc_client_command_free(cmd); } - -/* Command BAN. This is used to manage the ban list of the channel. */ - -SILC_CLIENT_CMD_FUNC(ban) -{ - SilcClientCommandContext cmd = (SilcClientCommandContext)context; - SilcClientConnection conn = cmd->conn; - SilcChannelEntry channel; - SilcBuffer buffer, chidp; - int type = 0; - char *name, *ban = NULL; - - if (!cmd->conn) { - SILC_NOT_CONNECTED(cmd->client, cmd->conn); - COMMAND_ERROR; - goto out; - } - - if (cmd->argc < 2) { - cmd->client->ops->say(cmd->client, conn, - "Usage: /BAN " - "[+|-[[@[![@hostname>]]]]]"); - COMMAND_ERROR; - goto out; - } - - if (cmd->argv[1][0] == '*') { - if (!conn->current_channel) { - cmd->client->ops->say(cmd->client, conn, "You are not on any channel"); - COMMAND_ERROR; - goto out; - } - - channel = conn->current_channel; - } else { - name = cmd->argv[1]; - - channel = silc_client_get_channel(cmd->client, conn, name); - if (!channel) { - cmd->client->ops->say(cmd->client, conn, "You are on that channel"); - COMMAND_ERROR; - goto out; - } - } - - if (cmd->argc == 3) { - if (cmd->argv[2][0] == '+') - type = 2; - else - type = 3; - - ban = cmd->argv[2]; - ban++; - } - - chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL); - - /* Send the command */ - if (ban) - buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2, - 1, chidp->data, chidp->len, - type, ban, strlen(ban)); - else - buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1, - 1, chidp->data, chidp->len); - - silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, - 0, NULL, NULL, buffer->data, buffer->len, TRUE); - silc_buffer_free(buffer); - silc_buffer_free(chidp); - - /* Notify application */ - COMMAND; - - out: - silc_client_command_free(cmd); -} diff --git a/lib/silcclient/command.h b/lib/silcclient/command.h index 64af6d8c..485a17ea 100644 --- a/lib/silcclient/command.h +++ b/lib/silcclient/command.h @@ -147,12 +147,11 @@ SILC_CLIENT_CMD_FUNC(umode); SILC_CLIENT_CMD_FUNC(cmode); SILC_CLIENT_CMD_FUNC(cumode); SILC_CLIENT_CMD_FUNC(kick); -SILC_CLIENT_CMD_FUNC(restart); +SILC_CLIENT_CMD_FUNC(ban); SILC_CLIENT_CMD_FUNC(close); SILC_CLIENT_CMD_FUNC(shutdown); SILC_CLIENT_CMD_FUNC(silcoper); SILC_CLIENT_CMD_FUNC(leave); SILC_CLIENT_CMD_FUNC(users); -SILC_CLIENT_CMD_FUNC(ban); #endif diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c index be33b9ca..b748e280 100644 --- a/lib/silcclient/command_reply.c +++ b/lib/silcclient/command_reply.c @@ -57,7 +57,6 @@ SilcClientCommandReply silc_command_reply_list[] = SILC_CLIENT_CMD_REPLY(cmode, CMODE), SILC_CLIENT_CMD_REPLY(cumode, CUMODE), SILC_CLIENT_CMD_REPLY(kick, KICK), - SILC_CLIENT_CMD_REPLY(restart, RESTART), SILC_CLIENT_CMD_REPLY(close, CLOSE), SILC_CLIENT_CMD_REPLY(shutdown, SHUTDOWN), SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER), @@ -1395,33 +1394,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(connect) silc_client_command_reply_free(cmd); } -SILC_CLIENT_CMD_REPLY_FUNC(restart) -{ - SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context; - SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; - SilcCommandStatus status; - unsigned char *tmp; - - tmp = silc_argument_get_arg_type(cmd->args, 1, NULL); - SILC_GET16_MSB(status, tmp); - if (status != SILC_STATUS_OK) { - cmd->client->ops->say(cmd->client, conn, - "%s", silc_client_command_status_message(status)); - COMMAND_REPLY_ERROR; - goto out; - } - - /* Notify application */ - COMMAND_REPLY((ARGS)); - - /* Execute any pending command callbacks */ - SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_RESTART); - - out: - SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_RESTART); - silc_client_command_reply_free(cmd); -} - SILC_CLIENT_CMD_REPLY_FUNC(close) { SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context; diff --git a/lib/silcclient/command_reply.h b/lib/silcclient/command_reply.h index f1ebd1c3..30e66989 100644 --- a/lib/silcclient/command_reply.h +++ b/lib/silcclient/command_reply.h @@ -92,7 +92,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(umode); SILC_CLIENT_CMD_REPLY_FUNC(cmode); SILC_CLIENT_CMD_REPLY_FUNC(cumode); SILC_CLIENT_CMD_REPLY_FUNC(kick); -SILC_CLIENT_CMD_REPLY_FUNC(restart); SILC_CLIENT_CMD_REPLY_FUNC(close); SILC_CLIENT_CMD_REPLY_FUNC(shutdown); SILC_CLIENT_CMD_REPLY_FUNC(silcoper); diff --git a/lib/silcclient/idlist.c b/lib/silcclient/idlist.c index 875b808c..07e060cc 100644 --- a/lib/silcclient/idlist.c +++ b/lib/silcclient/idlist.c @@ -298,8 +298,6 @@ void silc_client_get_clients_by_list(SilcClient client, silc_free(client_id); silc_buffer_pull(client_id_list, idp_len); } - silc_buffer_push(client_id_list, client_id_list->data - - client_id_list->head); /* Query the client information from server if the list included clients that we don't know about. */ @@ -320,6 +318,8 @@ void silc_client_get_clients_by_list(SilcClient client, silc_client_command_get_clients_list_callback, (void *)in); + silc_buffer_push(client_id_list, client_id_list->data - + client_id_list->head); silc_buffer_free(res_cmd); silc_free(res_argv); silc_free(res_argv_lens); @@ -327,6 +327,9 @@ void silc_client_get_clients_by_list(SilcClient client, return; } + silc_buffer_push(client_id_list, client_id_list->data - + client_id_list->head); + /* We have the clients in cache, get them and call the completion */ silc_client_command_get_clients_list_callback((void *)in); } diff --git a/lib/silcclient/protocol.c b/lib/silcclient/protocol.c index 16124421..064c3b21 100644 --- a/lib/silcclient/protocol.c +++ b/lib/silcclient/protocol.c @@ -428,6 +428,53 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange) * Connection Authentication protocol functions */ +static int +silc_client_get_public_key_auth(SilcClient client, + char *filepath, + unsigned char *auth_data, + unsigned int *auth_data_len, + SilcSKE ske) +{ + int len; + SilcPKCS pkcs; + SilcBuffer auth; + SilcPublicKey pub_key; + + if (!silc_pkcs_load_public_key(filepath,&pub_key, SILC_PKCS_FILE_PEM)) + if (!silc_pkcs_load_public_key(filepath, &pub_key, SILC_PKCS_FILE_BIN)) + return FALSE; + + silc_pkcs_alloc(pub_key->name, &pkcs); + if (!silc_pkcs_public_key_set(pkcs, pub_key)) { + silc_pkcs_free(pkcs); + silc_pkcs_public_key_free(pub_key); + return FALSE; + } + + /* Make the authentication data. Protocol says it is HASH plus + KE Start Payload. */ + len = ske->hash_len + ske->start_payload_copy->len; + auth = silc_buffer_alloc(len); + silc_buffer_pull_tail(auth, len); + silc_buffer_format(auth, + SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len), + SILC_STR_UI_XNSTRING(ske->start_payload_copy->data, + ske->start_payload_copy->len), + SILC_STR_END); + + if (silc_pkcs_sign(pkcs, auth->data, auth->len, auth_data, auth_data_len)) { + silc_pkcs_free(pkcs); + silc_buffer_free(auth); + silc_pkcs_public_key_free(pub_key); + return TRUE; + } + + silc_pkcs_free(pkcs); + silc_buffer_free(auth); + silc_pkcs_public_key_free(pub_key); + return FALSE; +} + SILC_TASK_CALLBACK(silc_client_protocol_connection_auth) { SilcProtocol protocol = (SilcProtocol)context; @@ -474,8 +521,17 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth) break; case SILC_AUTH_PUBLIC_KEY: - /* XXX */ - break; + { + unsigned char sign[1024]; + + /* Public key authentication */ + silc_client_get_public_key_auth(client, ctx->auth_data, + sign, &auth_data_len, + ctx->ske); + auth_data = silc_calloc(auth_data_len, sizeof(*auth_data)); + memcpy(auth_data, sign, auth_data_len); + break; + } } payload_len = 4 + auth_data_len; diff --git a/lib/silccore/silcchannel.c b/lib/silccore/silcchannel.c index d9c19deb..1dc0f438 100644 --- a/lib/silccore/silcchannel.c +++ b/lib/silccore/silcchannel.c @@ -526,10 +526,8 @@ SilcBuffer silc_channel_key_payload_encode(unsigned short id_len, void silc_channel_key_payload_free(SilcChannelKeyPayload payload) { if (payload) { - if (payload->id) - silc_free(payload->id); - if (payload->cipher) - silc_free(payload->cipher); + silc_free(payload->id); + silc_free(payload->cipher); if (payload->key) { memset(payload->key, 0, payload->key_len); silc_free(payload->key); diff --git a/lib/silccore/silccommand.h b/lib/silccore/silccommand.h index acd3b1cb..16b384ed 100644 --- a/lib/silccore/silccommand.h +++ b/lib/silccore/silccommand.h @@ -79,13 +79,12 @@ typedef enum { #define SILC_COMMAND_CMODE 17 #define SILC_COMMAND_CUMODE 18 #define SILC_COMMAND_KICK 19 -#define SILC_COMMAND_RESTART 20 +#define SILC_COMMAND_BAN 20 #define SILC_COMMAND_CLOSE 21 #define SILC_COMMAND_SHUTDOWN 22 #define SILC_COMMAND_SILCOPER 23 #define SILC_COMMAND_LEAVE 24 #define SILC_COMMAND_USERS 25 -#define SILC_COMMAND_BAN 26 /* Reserved */ #define SILC_COMMAND_RESERVED 255 diff --git a/lib/silccore/silcnotify.c b/lib/silccore/silcnotify.c index e3c8169d..210a3e1f 100644 --- a/lib/silccore/silcnotify.c +++ b/lib/silccore/silcnotify.c @@ -135,6 +135,35 @@ SilcBuffer silc_notify_payload_encode(SilcNotifyType type, unsigned int argc, return buffer; } +/* Same as above but takes argument from the `args' Argument Payload. */ + +SilcBuffer silc_notify_payload_encode_args(SilcNotifyType type, + unsigned int argc, + SilcBuffer args) +{ + SilcBuffer buffer; + int len; + + len = 5 + (args ? args->len : 0); + buffer = silc_buffer_alloc(len); + silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer)); + silc_buffer_format(buffer, + SILC_STR_UI_SHORT(type), + SILC_STR_UI_SHORT(len), + SILC_STR_UI_CHAR(argc), + SILC_STR_END); + + if (args) { + silc_buffer_pull(buffer, 5); + silc_buffer_format(buffer, + SILC_STR_UI_XNSTRING(args->data, args->len), + SILC_STR_END); + silc_buffer_push(buffer, 5); + } + + return buffer; +} + /* Free's notify payload */ void silc_notify_payload_free(SilcNotifyPayload payload) diff --git a/lib/silccore/silcnotify.h b/lib/silccore/silcnotify.h index 08a2fc91..ca64ca14 100644 --- a/lib/silccore/silcnotify.h +++ b/lib/silccore/silcnotify.h @@ -50,6 +50,9 @@ typedef unsigned short SilcNotifyType; SilcNotifyPayload silc_notify_payload_parse(SilcBuffer buffer); SilcBuffer silc_notify_payload_encode(SilcNotifyType type, unsigned int argc, va_list ap); +SilcBuffer silc_notify_payload_encode_args(SilcNotifyType type, + unsigned int argc, + SilcBuffer args); void silc_notify_payload_free(SilcNotifyPayload payload); SilcNotifyType silc_notify_get_type(SilcNotifyPayload payload); unsigned int silc_notify_get_arg_num(SilcNotifyPayload payload); diff --git a/lib/silccore/silcpayload.c b/lib/silccore/silcpayload.c index 8d4f4248..c919a94a 100644 --- a/lib/silccore/silcpayload.c +++ b/lib/silccore/silcpayload.c @@ -125,8 +125,9 @@ void *silc_id_payload_parse_id(unsigned char *data, unsigned int len) SilcBuffer buffer; SilcIdType type; unsigned short idlen; - unsigned char *id; + unsigned char *id_data; int ret; + void *id; buffer = silc_buffer_alloc(len); silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer)); @@ -145,14 +146,16 @@ void *silc_id_payload_parse_id(unsigned char *data, unsigned int len) goto err; ret = silc_buffer_unformat(buffer, - SILC_STR_UI_XNSTRING_ALLOC(&id, idlen), + SILC_STR_UI_XNSTRING_ALLOC(&id_data, idlen), SILC_STR_END); if (ret == -1) goto err; silc_buffer_free(buffer); - return silc_id_str2id(id, idlen, type); + id = silc_id_str2id(id_data, idlen, type); + silc_free(id_data); + return id; err: silc_buffer_free(buffer); @@ -192,6 +195,7 @@ void silc_id_payload_free(SilcIDPayload payload) { if (payload) { silc_free(payload->id); + silc_free(payload); } } @@ -401,6 +405,8 @@ void silc_argument_payload_free(SilcArgumentPayload payload) silc_free(payload->argv[i]); silc_free(payload->argv); + silc_free(payload->argv_lens); + silc_free(payload->argv_types); silc_free(payload); } } diff --git a/lib/silccore/silcpayload.h b/lib/silccore/silcpayload.h index a1d4fb66..06cd2a0c 100644 --- a/lib/silccore/silcpayload.h +++ b/lib/silccore/silcpayload.h @@ -27,8 +27,6 @@ typedef struct SilcArgumentPayloadStruct *SilcArgumentPayload; /* Prototypes */ SilcIDPayload silc_id_payload_parse(SilcBuffer buffer); -SilcArgumentPayload silc_argument_payload_parse(SilcBuffer buffer, - unsigned int argc); SilcIDPayload silc_id_payload_parse_data(unsigned char *data, unsigned int len); void *silc_id_payload_parse_id(unsigned char *data, unsigned int len); @@ -38,6 +36,8 @@ SilcIdType silc_id_payload_get_type(SilcIDPayload payload); void *silc_id_payload_get_id(SilcIDPayload payload); unsigned char *silc_id_payload_get_data(SilcIDPayload payload); unsigned int silc_id_payload_get_len(SilcIDPayload payload); +SilcArgumentPayload silc_argument_payload_parse(SilcBuffer buffer, + unsigned int argc); SilcBuffer silc_argument_payload_encode(unsigned int argc, unsigned char **argv, unsigned int *argv_lens, diff --git a/lib/silccrypt/silchmac.c b/lib/silccrypt/silchmac.c index d3484983..4e6971bc 100644 --- a/lib/silccrypt/silchmac.c +++ b/lib/silccrypt/silchmac.c @@ -250,6 +250,7 @@ void silc_hmac_make_internal(SilcHmac hmac, unsigned char *data, hash->hash->final(hash_context, mac); memcpy(return_hash, mac, hmac->hmac->len); memset(mac, 0, sizeof(mac)); + silc_free(hash_context); } /* Create the HMAC. This is thee make_hmac function pointer. This diff --git a/lib/silcske/payload.c b/lib/silcske/payload.c index ea9313f1..ce14c9fa 100644 --- a/lib/silcske/payload.c +++ b/lib/silcske/payload.c @@ -250,7 +250,7 @@ SilcSKEStatus silc_ske_payload_ke_decode(SilcSKE ske, { SilcSKEStatus status = SILC_SKE_STATUS_ERROR; SilcSKEKEPayload *payload; - unsigned char *x; + unsigned char *x = NULL; unsigned short x_len; unsigned int tot_len = 0, len2; int ret; @@ -331,6 +331,8 @@ SilcSKEStatus silc_ske_payload_ke_decode(SilcSKE ske, silc_free(payload->pk_data); if (payload->sign_data) silc_free(payload->sign_data); + if (x) + silc_free(x); silc_free(payload); ske->status = status; return status; diff --git a/lib/silcutil/silctask.c b/lib/silcutil/silctask.c index 688594c9..45ecdbff 100644 --- a/lib/silcutil/silctask.c +++ b/lib/silcutil/silctask.c @@ -35,10 +35,6 @@ void silc_task_queue_alloc(SilcTaskQueue *new, int valid) /* Set the pointers */ (*new)->valid = valid; (*new)->task = NULL; - (*new)->register_task = silc_task_register; - (*new)->unregister_task = silc_task_unregister; - (*new)->set_iotype = silc_task_set_iotype; - (*new)->reset_iotype = silc_task_reset_iotype; } /* Free's a task queue. */ @@ -75,8 +71,7 @@ SilcTask silc_task_add(SilcTaskQueue queue, SilcTask new, but after tasks with higher priority. */ prev = task->prev; while(prev != task) { - if (prev->priority > SILC_TASK_PRI_LOW && - prev->priority <= SILC_TASK_PRI_REALTIME) + if (prev->priority > SILC_TASK_PRI_LOW) break; prev = prev->prev; } @@ -100,49 +95,6 @@ SilcTask silc_task_add(SilcTaskQueue queue, SilcTask new, next->prev = new; } break; - case SILC_TASK_PRI_HIGH: - /* High priority. The task is added before lower priority tasks - but after tasks with higher priority. */ - prev = task->prev; - while(prev != task) { - if (prev->priority > SILC_TASK_PRI_NORMAL && - prev->priority <= SILC_TASK_PRI_REALTIME) - break; - prev = prev->prev; - } - if (prev == task) { - /* There are only lower priorities in the list, we will - sit before them and become the first task in the queue. */ - prev = task->prev; - new->prev = prev; - new->next = task; - task->prev = new; - prev->next = new; - - /* We are now the first task in queue */ - queue->task = new; - } else { - /* Found a spot from the list, add the task to the list. */ - next = prev->next; - new->prev = prev; - new->next = next; - prev->next = new; - next->prev = new; - } - break; - case SILC_TASK_PRI_REALTIME: - /* Highest priority. The task is added at the head of the list. - The last registered task is added to the very head of the list - thus we get the LIFO (Last-In-First-Out) order. */ - prev = task->prev; - new->prev = prev; - new->next = task; - prev->next = new; - task->prev = new; - - /* We are the first task in the queue */ - queue->task = new; - break; default: silc_free(new); return NULL; @@ -151,32 +103,6 @@ SilcTask silc_task_add(SilcTaskQueue queue, SilcTask new, return new; } -#if 0 -void dump_tasks(SilcTaskQueue queue) -{ - SilcTask first, prev; - - if (!queue->task) - return; - - first = queue->task; - - fprintf(stderr, "\nqueue->task:\t%p\t%d\n", queue->task, - queue->task->timeout.tv_sec); - - prev = first->prev; - while (1) { - if (first == prev) - break; - - fprintf(stderr, "task :\t%p\t%d\n", prev, prev->timeout.tv_sec); - - prev = prev->prev; - } - fprintf(stderr, "\n"); -} -#endif - /* Return the timeout task with smallest timeout. */ static SilcTask silc_task_get_first(SilcTaskQueue queue, SilcTask first) @@ -291,92 +217,48 @@ SilcTask silc_task_add_timeout(SilcTaskQueue queue, SilcTask new, queue->task = new; } break; - case SILC_TASK_PRI_HIGH: - /* High priority. The task is added before lower priority tasks - but after tasks with higher priority. */ - while(prev != task) { - - /* If we have longer timeout than with the task head of us - we have found our spot. */ - if (silc_task_timeout_compare(&prev->timeout, &new->timeout)) - break; - - /* If we are equal size of timeout, priority kicks in place. */ - if (!silc_task_timeout_compare(&new->timeout, &prev->timeout)) - if (prev->priority >= SILC_TASK_PRI_HIGH) - break; - - /* We have shorter timeout or higher priority, compare to next one. */ - prev = prev->prev; - } - /* Found a spot from the list, add the task to the list. */ - next = prev->next; - new->prev = prev; - new->next = next; - prev->next = new; - next->prev = new; - - if (prev == task) { - /* Check if we are going to be the first task in the queue */ - if (silc_task_timeout_compare(&prev->timeout, &new->timeout)) - break; - if (!silc_task_timeout_compare(&new->timeout, &prev->timeout)) - if (prev->priority >= SILC_TASK_PRI_HIGH) - break; - - /* We are now the first task in queue */ - queue->task = new; - } - break; - case SILC_TASK_PRI_REALTIME: - /* Highest priority. The task is added at the head of the list. - The last registered task is added to the very head of the list - thus we get the LIFO (Last-In-First-Out) order. */ - next = task->next; - while(next != task) { - - /* If we have shorter timeout than the next task we've found - our spot. */ - if (silc_task_timeout_compare(&new->timeout, &next->timeout)) - break; - - /* If we are equal size of timeout we will be first. */ - if (!silc_task_timeout_compare(&next->timeout, &new->timeout)) - break; - - /* We have longer timeout, compare to next one. */ - next = next->next; - } - /* Found a spot from the list, add the task to the list. */ - prev = next->prev; - new->next = next; - new->prev = prev; - prev->next = new; - next->prev = new; - - if (next == task) { - /* Check if we are going to be the first task in the queue */ - if (silc_task_timeout_compare(&next->timeout, &new->timeout)) - break; - - /* We are now the first task in queue */ - queue->task = new; - } default: silc_free(new); return NULL; } -#if 0 - dump_tasks(queue); -#endif - return new; } -/* Registers a new task into the task queue. The task becomes valid - automatically when it is registered. Returns a pointer to the - registered task. */ +/* Registers a new task to the task queue. Arguments are as follows: + + SilcTaskQueue queue Queue where the task is to be registered + int fd File descriptor + SilcTaskCallback cb Callback function to call + void *context Context to be passed to callback function + long seconds Seconds to timeout + long useconds Microseconds to timeout + SilcTaskType type Type of the task + SilcTaskPriority priority Priority of the task + + The same function is used to register all types of tasks. The type + argument tells what type of the task is. Note that when registering + non-timeout tasks one should also pass 0 as timeout as timeout will + be ignored anyway. Also, note, that one cannot register timeout task + with 0 timeout. There cannot be zero timeouts, passing zero means + no timeout is used for the task and SILC_TASK_FD_TASK is used as + default task type in this case. + + One should be careful not to register timeout tasks to the non-timeout + task queue, because they will never expire. As one should not register + non-timeout tasks to timeout task queue because they will never get + scheduled. + + There is a one distinct difference between timeout and non-timeout + tasks when they are executed. Non-timeout tasks remain on the task + queue after execution. Timeout tasks, however, are removed from the + task queue after they have expired. It is safe to re-register a task + in its own callback function. It is also safe to unregister a task + in a callback function. + + Generic tasks apply to all file descriptors, however, one still must + pass the correct file descriptor to the function when registering + generic tasks. */ SilcTask silc_task_register(SilcTaskQueue queue, int fd, SilcTaskCallback cb, void *context, @@ -499,12 +381,7 @@ int silc_task_remove(SilcTaskQueue queue, SilcTask task) queue->task = NULL; if (queue->task == old) queue->task = silc_task_get_first(queue, next); - /*queue->task = next;*/ -#if 0 - dump_tasks(queue); -#endif - silc_free(old); return TRUE; } @@ -515,9 +392,15 @@ int silc_task_remove(SilcTaskQueue queue, SilcTask task) } } -/* Unregisters a task from the task queue. This is the unregister_task - function pointer in task queue object. One should use this function - to unregister tasks. This function invalidates the task. */ +/* Unregisters a task already in the queue. Arguments are as follows: + + SilcTaskQueue queue Queue where from the task is unregistered + SilcTask task Task to be unregistered + + The same function is used to unregister timeout and non-timeout + tasks. One can also unregister all tasks from the queue by passing + SILC_ALL_TASKS as task to the function. It is safe to unregister + a task in a callback function. */ void silc_task_unregister(SilcTaskQueue queue, SilcTask task) { @@ -616,15 +499,27 @@ void silc_task_unregister_by_context(SilcTaskQueue queue, void *context) } } -/* Sets the I/O mask for the task. Only one I/O type can be set at a - time. */ +/* Sets the I/O type of the task. The scheduler checks for this value + and a task must always have at least one of the I/O types set at + all time. When registering new task the type is set by default to + SILC_TASK_READ. If the task doesn't perform reading one must reset + the value to SILC_TASK_WRITE. + + The type sent as argumenet is masked into the task. If the tasks + I/O mask already includes this type this function has no effect. + Only one I/O type can be added at once. If the task must perform + both reading and writing one must call this function for value + SILC_TASK_WRITE as well. */ void silc_task_set_iotype(SilcTask task, int type) { task->iomask |= (1L << type); } -/* Resets the I/O mask to the type sent as argument. */ +/* Resets the mask to the type sent as argument. Note that this resets + the previous values to zero and then adds the type sent as argument. + This function can be used to remove one of the types masked earlier + to the task. */ void silc_task_reset_iotype(SilcTask task, int type) { diff --git a/lib/silcutil/silctask.h b/lib/silcutil/silctask.h index 6fff792e..1c211c8d 100644 --- a/lib/silcutil/silctask.h +++ b/lib/silcutil/silctask.h @@ -135,33 +135,10 @@ typedef enum { For non-timeout tasks this priority behaves same way. Tasks are run in FIFO (First-In-First-Out) order. - SILC_TASK_PRI_HIGH - - High priority for important tasks. This priority should be used only - for important tasks. Life is very fair for tasks with this priority. - These tasks are run as soon as its timeout has expired. They are run - before normal or lower tasks, respectively. For non-timeout tasks - this priority behaves same way. Tasks are run in FIFO order. - - SILC_TASK_PRI_REALTIME - - Highest priority. This priority should be used very carefully because - it can make the scheduler extremely unfair to other tasks. The task - will be run as soon as its timeout has expired. The task is run before - any other task. It is also quaranteed that the last registered task - with this priority is the first task to be run when its timeout - expires. Tasks are run in LIFO (Last-In-First-Out) order. To make - scheduler fair there should never be more than one task in the queue - with this priority. Currently none of the tasks in SILC are important - enough to use this priority. For non-timeout tasks this priority - behaves same way. - */ typedef enum { SILC_TASK_PRI_LOW, SILC_TASK_PRI_NORMAL, - SILC_TASK_PRI_HIGH, - SILC_TASK_PRI_REALTIME, } SilcTaskPriority; /* @@ -206,94 +183,12 @@ typedef enum { task queue this is not defined. This is meant only for internal use and it should be considered to be read-only field. - SilcTask (*register_task)(SilcTaskQueue, int, - SilcTaskCallback, void *, - long, long, - SilcTaskType, - SilcTaskPriority) - - Registers a new task to the task queue. Arguments are as follows: - - SilcTaskQueue queue Queue where the task is to be registered - int fd File descriptor - SilcTaskCallback cb Callback function to call - void *context Context to be passed to callback function - long seconds Seconds to timeout - long useconds Microseconds to timeout - SilcTaskType type Type of the task - SilcTaskPriority priority Priority of the task - - The same function is used to register all types of tasks. The type - argument tells what type of the task is. Note that when registering - non-timeout tasks one should also pass 0 as timeout as timeout will - be ignored anyway. Also, note, that one cannot register timeout task - with 0 timeout. There cannot be zero timeouts, passing zero means - no timeout is used for the task and SILC_TASK_FD_TASK is used as - default task type in this case. - - One should be careful not to register timeout tasks to the non-timeout - task queue, because they will never expire. As one should not register - non-timeout tasks to timeout task queue because they will never get - scheduled. - - There is a one distinct difference between timeout and non-timeout - tasks when they are executed. Non-timeout tasks remain on the task - queue after execution. Timeout tasks, however, are removed from the - task queue after they have expired. It is safe to re-register a task - in its own callback function. It is also safe to unregister a task - in a callback function. - - Generic tasks apply to all file descriptors, however, one still must - pass the correct file descriptor to the function when registering - generic tasks. - - void (*unregister_task)(SilcTaskQueue, SilcTask) - - Unregisters a task already in the queue. Arguments are as follows: - - SilcTaskQueue queue Queue where from the task is unregistered - SilcTask task Task to be unregistered - - The same function is used to unregister timeout and non-timeout - tasks. One can also unregister all tasks from the queue by passing - SILC_ALL_TASKS as task to the function. It is safe to unregister - a task in a callback function. - - void (*set_iotype)(SilcTask, int type) - - Sets the I/O type of the task. The scheduler checks for this value - and a task must always have at least one of the I/O types set at - all time. When registering new task the type is set by default to - SILC_TASK_READ. If the task doesn't perform reading one must reset - the value to SILC_TASK_WRITE. - - The type sent as argumenet is masked into the task. If the tasks - I/O mask already includes this type this function has no effect. - Only one I/O type can be added at once. If the task must perform - both reading and writing one must call this function for value - SILC_TASK_WRITE as well. - - void (*reset_iotype)(SilcTask, int type) - - Resets the mask to the type sent as argument. Note that this resets - the previous values to zero and then adds the type sent as argument. - This function can be used to remove one of the types masked earlier - to the task. - */ typedef struct SilcTaskQueueStruct { SilcTask task; int valid; struct timeval timeout; - - /* Method functions */ - SilcTask (*register_task)(struct SilcTaskQueueStruct *, int, - SilcTaskCallback, void *, long, long, - SilcTaskType, SilcTaskPriority); - void (*unregister_task)(struct SilcTaskQueueStruct *, SilcTask); - void (*set_iotype)(SilcTask, int type); - void (*reset_iotype)(SilcTask, int type); } SilcTaskQueueObject; typedef SilcTaskQueueObject *SilcTaskQueue; -- 2.24.0