From c198279bceee270adb93075ff81b99ff2619b530 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Mon, 29 Oct 2001 19:26:11 +0000 Subject: [PATCH] updates. --- CHANGES | 16 +++++++ TODO | 2 - apps/silcd/command.c | 4 +- apps/silcd/command_reply.c | 4 +- apps/silcd/idlist.h | 1 + apps/silcd/packet_receive.c | 42 +++++++++++++++++ apps/silcd/packet_send.c | 72 +++++++++++++++++++++++++++++ apps/silcd/packet_send.h | 9 ++++ apps/silcd/server.c | 4 +- apps/silcd/server_util.c | 18 +++++--- apps/silcd/silcd.c | 7 +++ doc/draft-riikonen-silc-pp-04.nroff | 3 +- lib/silcclient/client_ftp.c | 10 ++-- lib/silcclient/client_prvmsg.c | 2 +- lib/silcclient/idlist.c | 8 +++- lib/silccore/silcpacket.c | 5 ++ 16 files changed, 186 insertions(+), 21 deletions(-) diff --git a/CHANGES b/CHANGES index b5fe2a1d..fa52bbf6 100644 --- a/CHANGES +++ b/CHANGES @@ -18,6 +18,22 @@ Mon Oct 29 17:43:04 EST 2001 Pekka Riikonen * Fixed a crash in client resolving in client_prvmsg.c in client library. Affected file lib/silcclient/client_prvmsg.c. + * Do not actually remove the client directly from ID cache + during SERVER_SIGNOFF, but invalidate it. This way we + preserve the WHOWAS info for the client. Affected file + silcd/server_util.c. + + * Fixed SERVER_SIGNOFF notify handling in the server. The + server is now able to process incoming SERVER_SIGNOFF notify + for a server that it doesn't even know about. It will remove + the clients provided in the notify. Affected file + silcd/packet_receive.c. + + * Check for partial packet in data queue after every packet that + was found from the queue. Return and wait for more data if + there is partial data in queue. Affecte file is + lib/silccore/silcpacket.c. + Sun Oct 28 18:46:27 EST 2001 Pekka Riikonen * Added SilcClietFileError enum to indicate error in diff --git a/TODO b/TODO index feb6e8bc..c601c8dd 100644 --- a/TODO +++ b/TODO @@ -47,8 +47,6 @@ TODO/bugs In SILC Server o After backup resume protocol the TOPIC_SET was not handled correctly by all (unknown Channel ID). - o Server signoff notifys does not go to normal servers from routers. - o Channel user mode changes are notified unnecessarely when switching to backup router on router crash. diff --git a/apps/silcd/command.c b/apps/silcd/command.c index e45e75af..59509fdd 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -3262,7 +3262,7 @@ SILC_SERVER_CMD_FUNC(join) } } - if (!channel || !channel->id) { + if (!channel || channel->disabled) { /* Channel not found */ /* If we are standalone server we don't have a router, we just create @@ -5014,7 +5014,7 @@ SILC_SERVER_CMD_FUNC(users) channel = silc_idlist_find_channel_by_name(server->local_list, channel_name, NULL); - if (!channel) { + if (!channel || channel->disabled) { if (server->server_type != SILC_ROUTER && !server->standalone && !cmd->pending) { SilcBuffer tmpbuf; diff --git a/apps/silcd/command_reply.c b/apps/silcd/command_reply.c index c718c3ba..cb6c6973 100644 --- a/apps/silcd/command_reply.c +++ b/apps/silcd/command_reply.c @@ -816,10 +816,10 @@ SILC_SERVER_CMD_REPLY_FUNC(join) server->stat.my_channels++; } else { /* The entry exists. */ - if (cache->id) - silc_free(cache->id); + silc_free(cache->id); entry->id = id; cache->id = entry->id; + entry->disabled = FALSE; /* Remove the founder auth data if the mode is not set but we have them in the entry */ diff --git a/apps/silcd/idlist.h b/apps/silcd/idlist.h index 6e8e2c94..0436d9a4 100644 --- a/apps/silcd/idlist.h +++ b/apps/silcd/idlist.h @@ -491,6 +491,7 @@ struct SilcChannelEntryStruct { SilcServerChannelRekey rekey; unsigned long created; + bool disabled; }; /* diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index 3d4662e3..099a4557 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -827,6 +827,48 @@ void silc_server_notify(SilcServer server, server_entry = silc_idlist_find_server_by_id(server->local_list, server_id, TRUE, NULL); if (!server_entry) { + /* If we are normal server then we might not have the server. Check + whether router was kind enough to send the list of all clients + that actually was to be removed. Remove them if the list is + available. */ + if (server->server_type != SILC_ROUTER && + silc_argument_get_arg_num(args) > 1) { + 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) + continue; + client_id = silc_id_payload_parse_id(tmp, tmp_len); + if (!client_id) + continue; + + /* Get client entry */ + client = silc_idlist_find_client_by_id(server->global_list, + client_id, TRUE, &cache); + if (!client) { + client = silc_idlist_find_client_by_id(server->local_list, + client_id, TRUE, &cache); + if (!client) { + silc_free(client_id); + continue; + } + } + silc_free(client_id); + + /* Remove the client from all channels. */ + silc_server_remove_from_channels(server, NULL, client, + TRUE, NULL, FALSE); + + client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED; + cache->expire = SILC_ID_CACHE_EXPIRE_DEF; + server->stat.clients--; + if (server->server_type == SILC_ROUTER) + server->stat.cell_clients--; + } + } + silc_free(server_id); goto out; } diff --git a/apps/silcd/packet_send.c b/apps/silcd/packet_send.c index d2e19b74..acea2644 100644 --- a/apps/silcd/packet_send.c +++ b/apps/silcd/packet_send.c @@ -386,6 +386,78 @@ void silc_server_packet_route(SilcServer server, silc_server_packet_send_real(server, sock, TRUE); } +/* This routine can be used to send a packet to table of clients provided + in `clients'. If `route' is FALSE the packet is routed only to local + clients (for server locally connected, and for router local cell). */ + +void silc_server_packet_send_clients(SilcServer server, + SilcClientEntry *clients, + uint32 clients_count, + SilcPacketType type, + SilcPacketFlags flags, + bool route, + unsigned char *data, + uint32 data_len, + bool force_send) +{ + SilcSocketConnection sock = NULL; + SilcClientEntry client = NULL; + SilcServerEntry *routed = NULL; + uint32 routed_count = 0; + bool gone = FALSE; + int i, k; + + SILC_LOG_DEBUG(("Sending packet to list of clients")); + + /* Send to all clients in table */ + for (i = 0; i < clients_count; i++) { + client = clients[i]; + + /* If client has router set it is not locally connected client and + we will route the message to the router set in the client. Though, + send locally connected server in all cases. */ + if (server->server_type == SILC_ROUTER && client->router && + ((!route && client->router->router == server->id_entry) || route)) { + + /* Check if we have sent the packet to this route already */ + for (k = 0; k < routed_count; k++) + if (routed[k] == client->router) + break; + if (k < routed_count) + continue; + + /* Route only once to router */ + sock = (SilcSocketConnection)client->router->connection; + if (sock->type == SILC_SOCKET_TYPE_ROUTER) { + if (gone) + continue; + gone = TRUE; + } + + /* Send the packet */ + silc_server_packet_send_dest(server, sock, type, flags, + client->router->id, SILC_ID_SERVER, + data, data_len, force_send); + + /* Mark this route routed already */ + routed = silc_realloc(routed, sizeof(*routed) * (routed_count + 1)); + routed[routed_count++] = client->router; + continue; + } + + if (client->router) + continue; + + /* Send to locally connected client */ + sock = (SilcSocketConnection)client->connection; + silc_server_packet_send_dest(server, sock, type, flags, + client->id, SILC_ID_CLIENT, + data, data_len, force_send); + } + + silc_free(routed); +} + /* Internal routine to actually create the channel packet and send it to network. This is common function in channel message sending. If `channel_message' is TRUE this encrypts the message as it is strictly diff --git a/apps/silcd/packet_send.h b/apps/silcd/packet_send.h index 25efb1a1..48e12977 100644 --- a/apps/silcd/packet_send.h +++ b/apps/silcd/packet_send.h @@ -59,6 +59,15 @@ void silc_server_packet_broadcast(SilcServer server, void silc_server_packet_route(SilcServer server, SilcSocketConnection sock, SilcPacketContext *packet); +void silc_server_packet_send_clients(SilcServer server, + SilcClientEntry *clients, + uint32 clients_count, + SilcPacketType type, + SilcPacketFlags flags, + bool route, + unsigned char *data, + uint32 data_len, + bool force_send); void silc_server_packet_send_to_channel(SilcServer server, SilcSocketConnection sender, SilcChannelEntry channel, diff --git a/apps/silcd/server.c b/apps/silcd/server.c index a735140a..78558f4b 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -2516,7 +2516,7 @@ void silc_server_remove_from_channels(SilcServer server, SilcChannelClientEntry chl2; SilcHashTableList htl2; - channel->id = NULL; + channel->disabled = TRUE; silc_hash_table_list(channel->user_list, &htl2); while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) { @@ -2636,7 +2636,7 @@ int silc_server_remove_from_one_channel(SilcServer server, SilcChannelClientEntry chl2; SilcHashTableList htl2; - channel->id = NULL; + channel->disabled = TRUE; silc_hash_table_list(channel->user_list, &htl2); while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) { diff --git a/apps/silcd/server_util.c b/apps/silcd/server_util.c index 5f4c9ea8..d0488095 100644 --- a/apps/silcd/server_util.c +++ b/apps/silcd/server_util.c @@ -212,7 +212,11 @@ bool silc_server_remove_clients_by_server(SilcServer server, /* Remove the client entry */ silc_server_remove_clients_channels(server, NULL, client, channels); - silc_idlist_del_client(server->local_list, client); + client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED; + id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF; + server->stat.clients--; + if (server->server_type == SILC_ROUTER) + server->stat.cell_clients--; if (!silc_idcache_list_next(list, &id_cache)) break; @@ -264,7 +268,11 @@ bool silc_server_remove_clients_by_server(SilcServer server, /* Remove the client entry */ silc_server_remove_clients_channels(server, NULL, client, channels); - silc_idlist_del_client(server->global_list, client); + client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED; + id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF; + server->stat.clients--; + if (server->server_type == SILC_ROUTER) + server->stat.cell_clients--; if (!silc_idcache_list_next(list, &id_cache)) break; @@ -291,7 +299,8 @@ bool silc_server_remove_clients_by_server(SilcServer server, silc_buffer_free(args); } - /* Send to local clients */ + /* Send to local clients. We also send the list of client ID's that + is to be removed for those servers that would like to use that list. */ args = silc_argument_payload_encode(argc, argv, argv_lens, argv_types); not = silc_notify_payload_encode_args(SILC_NOTIFY_TYPE_SERVER_SIGNOFF, @@ -473,8 +482,6 @@ void silc_server_update_clients_by_server(SilcServer server, if (silc_idcache_list_first(list, &id_cache)) { while (id_cache) { client = (SilcClientEntry)id_cache->context; - - if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) { if (!silc_idcache_list_next(list, &id_cache)) break; @@ -522,7 +529,6 @@ void silc_server_update_clients_by_server(SilcServer server, if (silc_idcache_list_first(list, &id_cache)) { while (id_cache) { client = (SilcClientEntry)id_cache->context; - if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) { if (!silc_idcache_list_next(list, &id_cache)) break; diff --git a/apps/silcd/silcd.c b/apps/silcd/silcd.c index 6a8b62b4..ed64407f 100644 --- a/apps/silcd/silcd.c +++ b/apps/silcd/silcd.c @@ -102,6 +102,7 @@ int main(int argc, char **argv) char *config_file = NULL; SilcServer silcd; struct sigaction sa; + char pid[10]; silc_debug = FALSE; @@ -197,6 +198,12 @@ int main(int argc, char **argv) /* Before running the server, fork to background and set both user and group no non-root */ silc_server_daemonise(silcd); + + /* Set /var/run/silcd.pid */ + unlink("/var/run/silcd/pid"); + memset(pid, 0, sizeof(pid)); + snprintf(pid, sizeof(pid) - 1, "%d\n", getpid()); + silc_file_writefile("/var/run/silcd.pid", pid, strlen(pid)); /* Run the server. When this returns the server has been stopped and we will exit. */ diff --git a/doc/draft-riikonen-silc-pp-04.nroff b/doc/draft-riikonen-silc-pp-04.nroff index d825d1ff..e16ee17f 100644 --- a/doc/draft-riikonen-silc-pp-04.nroff +++ b/doc/draft-riikonen-silc-pp-04.nroff @@ -1367,7 +1367,8 @@ Also, all ID's sent in arguments are sent inside ID Payload. 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. + MAY be omitted. Server receiving the Client ID's in the payload + may use them directly to remove the client. 12 SILC_NOTIFY_TYPE_KICKED diff --git a/lib/silcclient/client_ftp.c b/lib/silcclient/client_ftp.c index 9badcc72..fca04ad4 100644 --- a/lib/silcclient/client_ftp.c +++ b/lib/silcclient/client_ftp.c @@ -185,7 +185,9 @@ static void silc_client_ftp_send_packet(SilcSocketConnection sock, silc_client_packet_send(client, sock, SILC_PACKET_FTP, NULL, 0, NULL, NULL, session->packet->data, session->packet->len, TRUE); - silc_buffer_clear(session->packet); + /* Clear buffer */ + session->packet->data = session->packet->tail = session->packet->head; + session->packet->len = 0; } /* SFTP monitor callback for SFTP server. This reports the application @@ -635,7 +637,8 @@ void silc_client_ftp_free_sessions(SilcClient client, SilcClientFtpSession session; silc_dlist_start(conn->ftp_sessions); while ((session = silc_dlist_get(conn->ftp_sessions)) != SILC_LIST_END) { - session->sock->user_data = NULL; + if (session->sock) + session->sock->user_data = NULL; silc_client_ftp_session_free(session); } silc_dlist_del(conn->ftp_sessions, session); @@ -657,7 +660,8 @@ void silc_client_ftp_session_free_client(SilcClientConnection conn, silc_dlist_start(conn->ftp_sessions); while ((session = silc_dlist_get(conn->ftp_sessions)) != SILC_LIST_END) { if (session->client_entry == client_entry) { - session->sock->user_data = NULL; + if (session->sock) + session->sock->user_data = NULL; silc_client_ftp_session_free(session); break; } diff --git a/lib/silcclient/client_prvmsg.c b/lib/silcclient/client_prvmsg.c index 2f105427..5acc8610 100644 --- a/lib/silcclient/client_prvmsg.c +++ b/lib/silcclient/client_prvmsg.c @@ -147,7 +147,7 @@ void silc_client_private_message(SilcClient client, { SilcClientConnection conn = (SilcClientConnection)sock->user_data; SilcPrivateMessagePayload payload = NULL; - SilcIDCacheEntry id_cache; + SilcIDCacheEntry id_cache = NULL; SilcClientID *remote_id = NULL; SilcClientEntry remote_client; SilcMessageFlags flags; diff --git a/lib/silcclient/idlist.c b/lib/silcclient/idlist.c index f5686a72..45b91af6 100644 --- a/lib/silcclient/idlist.c +++ b/lib/silcclient/idlist.c @@ -216,8 +216,10 @@ SILC_CLIENT_CMD_FUNC(get_clients_list_callback) SILC_GET16_MSB(idp_len, client_id_list->data + 2); idp_len += 4; client_id = silc_id_payload_parse_id(client_id_list->data, idp_len); - if (!client_id) + if (!client_id) { + silc_buffer_pull(client_id_list, idp_len); continue; + } /* Get the client entry */ if (silc_idcache_find_by_id_one_ext(i->conn->client_cache, @@ -295,8 +297,10 @@ void silc_client_get_clients_by_list(SilcClient client, SILC_GET16_MSB(idp_len, client_id_list->data + 2); idp_len += 4; client_id = silc_id_payload_parse_id(client_id_list->data, idp_len); - if (!client_id) + if (!client_id) { + silc_buffer_pull(client_id_list, idp_len); continue; + } /* Check if we have this client cached already. */ id_cache = NULL; diff --git a/lib/silccore/silcpacket.c b/lib/silccore/silcpacket.c index d05c0bd1..d18781a4 100644 --- a/lib/silccore/silcpacket.c +++ b/lib/silccore/silcpacket.c @@ -344,6 +344,11 @@ void silc_packet_receive_process(SilcSocketConnection sock, /* Parse the packets from the data */ while (sock->inbuf->len > 0 && cont) { + if (sock->inbuf->len < SILC_PACKET_MIN_HEADER_LEN) { + SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest")); + return; + } + /* Decrypt first 16 bytes of the packet */ if (!SILC_IS_INBUF_PENDING(sock) && cipher) silc_cipher_decrypt(cipher, sock->inbuf->data, sock->inbuf->data, -- 2.24.0