* 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 <priikone@silcnet.org>
* Added SilcClietFileError enum to indicate error in
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.
}
}
- 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
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;
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 */
SilcServerChannelRekey rekey;
unsigned long created;
+ bool disabled;
};
/*
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;
}
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
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,
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)) {
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)) {
/* 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;
/* 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;
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,
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;
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;
char *config_file = NULL;
SilcServer silcd;
struct sigaction sa;
+ char pid[10];
silc_debug = FALSE;
/* 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. */
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
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
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);
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;
}
{
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;
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,
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;
/* 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,