X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=apps%2Fsilcd%2Fpacket_send.c;fp=apps%2Fsilcd%2Fpacket_send.c;h=0000000000000000000000000000000000000000;hb=72c2de619079457f7a68100eb13385275a424a23;hp=7e19280e1649376bb4ab38c8a7afe5431d86b470;hpb=e7b6c157b80152bf9fb9266e6bdd93f9fb0db776;p=runtime.git diff --git a/apps/silcd/packet_send.c b/apps/silcd/packet_send.c deleted file mode 100644 index 7e19280e..00000000 --- a/apps/silcd/packet_send.c +++ /dev/null @@ -1,1716 +0,0 @@ -/* - - packet_send.c - - Author: Pekka Riikonen - - Copyright (C) 1997 - 2007 Pekka Riikonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - -*/ - -#include "serverincludes.h" -#include "server_internal.h" - -/* Send packet to remote connection */ - -SilcBool silc_server_packet_send(SilcServer server, - SilcPacketStream sock, - SilcPacketType type, - SilcPacketFlags flags, - unsigned char *data, - SilcUInt32 data_len) -{ - SilcIDListData idata; - - if (!sock) - return FALSE; - - idata = silc_packet_get_context(sock); - - /* If entry is disabled do not sent anything. Allow hearbeat though */ - if ((idata && idata->status & SILC_IDLIST_STATUS_DISABLED && - type != SILC_PACKET_HEARTBEAT) || - ((SilcServerEntry)idata == server->id_entry)) { - SILC_LOG_DEBUG(("Connection is disabled")); - return FALSE; - } - - SILC_LOG_DEBUG(("Sending %s packet", silc_get_packet_name(type))); - - return silc_packet_send(sock, type, flags, (const unsigned char *)data, - data_len); -} - -/* Send packet to remote connection with specific destination ID. */ - -SilcBool silc_server_packet_send_dest(SilcServer server, - SilcPacketStream sock, - SilcPacketType type, - SilcPacketFlags flags, - void *dst_id, - SilcIdType dst_id_type, - unsigned char *data, - SilcUInt32 data_len) -{ - SilcIDListData idata; - - if (!sock) - return FALSE; - - idata = silc_packet_get_context(sock); - - /* If entry is disabled do not sent anything. Allow hearbeat though */ - if ((idata && idata->status & SILC_IDLIST_STATUS_DISABLED && - type != SILC_PACKET_HEARTBEAT) || - ((SilcServerEntry)idata == server->id_entry)) { - SILC_LOG_DEBUG(("Connection is disabled")); - return FALSE; - } - - SILC_LOG_DEBUG(("Sending %s packet", silc_get_packet_name(type))); - - return silc_packet_send_ext(sock, type, flags, 0, NULL, dst_id_type, dst_id, - (const unsigned char *)data, data_len, - NULL, NULL); -} - -/* Send packet to remote connection with specific source and destination - IDs. */ - -SilcBool silc_server_packet_send_srcdest(SilcServer server, - SilcPacketStream sock, - SilcPacketType type, - SilcPacketFlags flags, - void *src_id, - SilcIdType src_id_type, - void *dst_id, - SilcIdType dst_id_type, - unsigned char *data, - SilcUInt32 data_len) -{ - SilcIDListData idata; - - if (!sock) - return FALSE; - - idata = silc_packet_get_context(sock); - - /* If entry is disabled do not sent anything. Allow hearbeat though */ - if ((idata && idata->status & SILC_IDLIST_STATUS_DISABLED && - type != SILC_PACKET_HEARTBEAT) || - ((SilcServerEntry)idata == server->id_entry)) { - SILC_LOG_DEBUG(("Connection is disabled")); - return FALSE; - } - - SILC_LOG_DEBUG(("Sending %s packet", silc_get_packet_name(type))); - - return silc_packet_send_ext(sock, type, flags, src_id_type, src_id, - dst_id_type, dst_id, - (const unsigned char *)data, data_len, - NULL, NULL); -} - -/* Broadcast received packet to our primary route. This function is used - by router to further route received broadcast packet. It is expected - that the broadcast flag from the packet is checked before calling this - function. This does not test or set the broadcast flag. */ - -SilcBool silc_server_packet_broadcast(SilcServer server, - SilcPacketStream primary_route, - SilcPacket packet) -{ - SilcServerID src_id, dst_id; - - if (!primary_route) - return FALSE; - - SILC_LOG_DEBUG(("Broadcasting received broadcast packet")); - - if (!silc_id_str2id(packet->src_id, packet->src_id_len, packet->src_id_type, - &src_id, sizeof(src_id))) - return FALSE; - if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, packet->dst_id_type, - &dst_id, sizeof(dst_id))) - return FALSE; - - /* If the packet is originated from our primary route we are not allowed - to send the packet. */ - if (SILC_ID_SERVER_COMPARE(&src_id, server->router->id)) { - SILC_LOG_DEBUG(("Will not broadcast to primary route since it is the " - "original sender of this packet")); - return FALSE; - } - - /* Send the packet */ - return silc_server_packet_send_srcdest(server, primary_route, packet->type, - packet->flags, &src_id, - SILC_ID_SERVER, &dst_id, - SILC_ID_SERVER, - packet->buffer.data, - silc_buffer_len(&packet->buffer)); -} - -/* Routes received packet to `sock'. This is used to route the packets that - router receives but are not destined to it. */ - -SilcBool silc_server_packet_route(SilcServer server, - SilcPacketStream sock, - SilcPacket packet) -{ - SilcID src_id, dst_id; - - if (!silc_id_str2id2(packet->src_id, packet->src_id_len, packet->src_id_type, - &src_id)) - return FALSE; - if (!silc_id_str2id2(packet->dst_id, packet->dst_id_len, packet->dst_id_type, - &dst_id)) - return FALSE; - - return silc_server_packet_send_srcdest(server, sock, packet->type, - packet->flags, - SILC_ID_GET_ID(src_id), - src_id.type, - SILC_ID_GET_ID(dst_id), - dst_id.type, - packet->buffer.data, - silc_buffer_len(&packet->buffer)); -} - -/* 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, - SilcHashTable clients, - SilcPacketType type, - SilcPacketFlags flags, - SilcBool route, - unsigned char *data, - SilcUInt32 data_len) -{ - SilcPacketStream sock = NULL; - SilcIDListData idata; - SilcHashTableList htl; - SilcClientEntry client = NULL; - SilcServerEntry *routed = NULL; - SilcUInt32 routed_count = 0; - SilcBool gone = FALSE; - int k; - - if (!silc_hash_table_count(clients)) - return; - - SILC_LOG_DEBUG(("Sending packet to %d clients", - silc_hash_table_count(clients))); - - /* Send to all clients in table */ - silc_hash_table_list(clients, &htl); - while (silc_hash_table_get(&htl, NULL, (void *)&client)) { - /* 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 = client->router->connection; - idata = silc_packet_get_context(sock); - if (idata->conn_type == SILC_CONN_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); - - /* 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 = client->connection; - if (!sock) - continue; - - silc_server_packet_send_dest(server, sock, type, flags, - client->id, SILC_ID_CLIENT, - data, data_len); - } - silc_hash_table_list_reset(&htl); - silc_free(routed); -} - -/* This routine is used by the server to send packets to channel. The - packet sent with this function is distributed to all clients on - the channel. Usually this is used to send notify messages to the - channel, things like notify about new user joining to the channel. - If `route' is FALSE then the packet is sent only locally and will not - be routed anywhere (for router locally means cell wide). If `sender' - is provided then the packet is not sent to that connection since it - originally came from it. If `send_to_clients' is FALSE then the - packet is not sent clients, only servers. */ - -void silc_server_packet_send_to_channel(SilcServer server, - SilcPacketStream sender, - SilcChannelEntry channel, - SilcPacketType type, - SilcBool route, - SilcBool send_to_clients, - unsigned char *data, - SilcUInt32 data_len) -{ - SilcPacketStream sock = NULL; - SilcClientEntry client = NULL; - SilcServerEntry *routed = NULL; - SilcChannelClientEntry chl; - SilcHashTableList htl; - SilcIDListData idata; - SilcUInt32 routed_count = 0; - SilcBool gone = FALSE; - int k; - - /* This doesn't send channel message packets */ - assert(type != SILC_PACKET_CHANNEL_MESSAGE); - - /* If there are global users in the channel we will send the message - first to our router for further routing. */ - if (route && server->server_type != SILC_ROUTER && !server->standalone && - channel->global_users) { - sock = server->router->connection; - if (sock != sender) { - SILC_LOG_DEBUG(("Sending packet to router for routing")); - silc_server_packet_send_dest(server, sock, type, 0, channel->id, - SILC_ID_CHANNEL, data, data_len); - } - } - - if (!silc_hash_table_count(channel->user_list)) { - SILC_LOG_DEBUG(("Channel %s is empty", channel->channel_name)); - goto out; - } - - SILC_LOG_DEBUG(("Sending %s to channel %s", - silc_get_packet_name(type), channel->channel_name)); - - routed = silc_calloc(silc_hash_table_count(channel->user_list), - sizeof(*routed)); - - /* Send the message to clients on the channel's client list. */ - silc_hash_table_list(channel->user_list, &htl); - while (silc_hash_table_get(&htl, NULL, (void *)&chl)) { - client = chl->client; - if (!client) - continue; - - /* 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; - - /* Get data used in packet header encryption, keys and stuff. */ - sock = client->router->connection; - idata = (SilcIDListData)client->router; - - if (sender && sock == sender) - continue; - - /* Route only once to router. Protocol prohibits sending channel - messages to more than one router. */ - if (idata->conn_type == SILC_CONN_ROUTER) { - if (gone) - continue; - gone = TRUE; - } - - SILC_LOG_DEBUG(("Sending packet to client %s", - client->nickname ? client->nickname : - (unsigned char *)"")); - - /* Send the packet */ - silc_server_packet_send_dest(server, sock, type, 0, channel->id, - SILC_ID_CHANNEL, data, data_len); - - /* Mark this route routed already */ - routed[routed_count++] = client->router; - continue; - } - - if (client->router || !send_to_clients) - continue; - - /* Send to locally connected client */ - - /* Get data used in packet header encryption, keys and stuff. */ - sock = client->connection; - if (!sock || (sender && sock == sender)) - continue; - - SILC_LOG_DEBUG(("Sending packet to client %s", - client->nickname ? client->nickname : - (unsigned char *)"")); - - /* Send the packet */ - silc_server_packet_send_dest(server, sock, type, 0, channel->id, - SILC_ID_CHANNEL, data, data_len); - } - silc_hash_table_list_reset(&htl); - - out: - silc_free(routed); -} - -/* This checks whether the relayed packet came from router. If it did - then we'll need to encrypt it with the channel key. This is called - from the silc_server_packet_relay_to_channel. */ - -static SilcBool -silc_server_packet_relay_to_channel_encrypt(SilcServer server, - SilcPacketStream sender, - SilcChannelEntry channel, - unsigned char *data, - unsigned int data_len) -{ - SilcIDListData idata; - SilcUInt32 mac_len, iv_len; - unsigned char iv[SILC_CIPHER_MAX_IV_SIZE]; - SilcUInt16 totlen, len; - SilcID src_id, dst_id; - - idata = silc_packet_get_context(sender); - - /* If we are router and the packet came from router and private key - has not been set for the channel then we must encrypt the packet - as it was decrypted with the session key shared between us and the - router which sent it. This is so, because cells does not share the - same channel key. */ - if (server->server_type == SILC_ROUTER && - idata->conn_type == SILC_CONN_ROUTER && - !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY) && channel->key) { - - /* If we are backup router and remote is our primary router and - we are currently doing backup resuming protocol we must not - re-encrypt message with session key. */ - if (server->backup_router && idata->sconn->backup_resuming && - SILC_PRIMARY_ROUTE(server) == sender) - return TRUE; - - mac_len = silc_hmac_len(channel->hmac); - iv_len = silc_cipher_get_block_len(channel->send_key); - - if (data_len <= mac_len + iv_len) { - SILC_LOG_WARNING(("Corrupted channel message, cannot relay it")); - return FALSE; - } - - totlen = 2; - SILC_GET16_MSB(len, data + totlen); - totlen += 2 + len; - if (totlen + iv_len + mac_len + 2 > data_len) { - SILC_LOG_WARNING(("Corrupted channel message, cannot relay it")); - return FALSE; - } - SILC_GET16_MSB(len, data + totlen); - totlen += 2 + len; - if (totlen + iv_len + mac_len > data_len) { - SILC_LOG_WARNING(("Corrupted channel message, cannot relay it")); - return FALSE; - } - - memcpy(iv, data + (data_len - iv_len - mac_len), iv_len); - - src_id.type = SILC_ID_SERVER; - src_id.u.server_id = *((SilcServerEntry)idata)->id; - dst_id.type = SILC_ID_CHANNEL; - dst_id.u.channel_id = *channel->id; - - return silc_message_payload_encrypt(data, totlen, data_len - mac_len, - iv, &src_id, &dst_id, - channel->send_key, channel->hmac); - } - - return TRUE; -} - -/* This routine is explicitly used to relay messages to some channel. - Packets sent with this function we have received earlier and are - totally encrypted. This just sends the packet to all clients on - the channel. If the sender of the packet is someone on the channel - the message will not be sent to that client. The SILC Packet header - is encrypted with the session key shared between us and the client. - MAC is also computed before encrypting the header. Rest of the - packet will be untouched. */ - -void silc_server_packet_relay_to_channel(SilcServer server, - SilcPacketStream sender_sock, - SilcChannelEntry channel, - void *sender_id, - SilcIdType sender_type, - SilcClientEntry sender_entry, - unsigned char *data, - SilcUInt32 data_len) -{ - SilcPacketStream sock = NULL; - SilcClientEntry client = NULL; - SilcServerEntry *routed = NULL; - SilcChannelClientEntry chl, chl_sender; - SilcUInt32 routed_count = 0; - SilcIDListData idata; - SilcHashTableList htl; - SilcBool gone = FALSE; - int k; - - if (!silc_server_client_on_channel(sender_entry, channel, &chl_sender)) - return; - - SILC_LOG_DEBUG(("Relaying packet to channel %s", channel->channel_name)); - - /* This encrypts the message, if needed. It will be encrypted if - it came from the router thus it needs to be encrypted with the - channel key. If the channel key does not exist, then we know we - don't have a single local user on the channel. */ - if (!silc_server_packet_relay_to_channel_encrypt(server, sender_sock, - channel, data, - data_len)) - return; - - /* If there are global users in the channel we will send the message - first to our router for further routing. */ - if (server->server_type != SILC_ROUTER && !server->standalone && - channel->global_users) { - SilcServerEntry router = server->router; - - /* Check that the sender is not our router. */ - if (sender_sock != router->connection) { - SILC_LOG_DEBUG(("Sending message to router for routing")); - sock = router->connection; - silc_server_packet_send_srcdest(server, sock, - SILC_PACKET_CHANNEL_MESSAGE, 0, - sender_id, sender_type, - channel->id, SILC_ID_CHANNEL, - data, data_len); - } - } - - routed = silc_calloc(silc_hash_table_count(channel->user_list), - sizeof(*routed)); - - /* Assure we won't route the message back to the sender's way. */ - if (sender_entry->router) - routed[routed_count++] = sender_entry->router; - - /* Send the message to clients on the channel's client list. */ - silc_hash_table_list(channel->user_list, &htl); - while (silc_hash_table_get(&htl, NULL, (void *)&chl)) { - client = chl->client; - if (!client || client == sender_entry) - continue; - - /* Check whether message sending is blocked */ - if (chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES) - continue; - if (chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS && - !(chl_sender->mode & SILC_CHANNEL_UMODE_CHANOP) && - !(chl_sender->mode & SILC_CHANNEL_UMODE_CHANFO)) - continue; - if (chl->mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS && - sender_entry->mode & SILC_UMODE_ROBOT) - continue; - - /* If the client has set router it means that it is not locally - connected client and we will route the packet further. */ - if (server->server_type == SILC_ROUTER && client->router) { - - /* 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; - - /* Get data used in packet header encryption, keys and stuff. */ - sock = client->router->connection; - idata = (SilcIDListData)client->router; - - /* Check if the sender socket is the same as this client's router - socket. */ - if (sender_sock && sock == sender_sock) - continue; - - SILC_LOG_DEBUG(("Relaying packet to client ID(%s)", - silc_id_render(client->id, SILC_ID_CLIENT))); - - /* Mark this route routed already. */ - routed[routed_count++] = client->router; - - if (idata->conn_type == SILC_CONN_ROUTER) { - /* The remote connection is router then we'll decrypt the - channel message and re-encrypt it with the session key shared - between us and the remote router. This is done because the - channel keys are cell specific and we have different channel - key than the remote router has. */ - - /* Route only once to router. Protocol prohibits sending channel - messages to more than one router. */ - if (gone) - continue; - gone = TRUE; - - /* If we are backup router and remote is our primary router and - we are currently doing backup resuming protocol we must not - re-encrypt message with session key. */ - if (server->backup_router && idata->sconn->backup_resuming && - SILC_PRIMARY_ROUTE(server) == sock) { - silc_server_packet_send_srcdest(server, sock, - SILC_PACKET_CHANNEL_MESSAGE, 0, - sender_id, sender_type, - channel->id, SILC_ID_CHANNEL, - data, data_len); - continue; - } - - SILC_LOG_DEBUG(("Remote is router, encrypt with session key")); - - /* If private key mode is not set then decrypt the packet - and re-encrypt it */ - if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY) && - channel->receive_key) { - unsigned char tmp[SILC_PACKET_MAX_LEN], sid[32], rid[32]; - SilcUInt32 sid_len, rid_len; - - if (data_len > SILC_PACKET_MAX_LEN) - data_len = SILC_PACKET_MAX_LEN; - memcpy(tmp, data, data_len); - - /* Decrypt the channel message (we don't check the MAC) */ - silc_id_id2str(sender_id, sender_type, sid, sizeof(sid), &sid_len); - silc_id_id2str(channel->id, SILC_ID_CHANNEL, rid, sizeof(rid), - &rid_len); - silc_message_payload_decrypt(tmp, data_len, FALSE, FALSE, - channel->receive_key, - channel->hmac, sid, sid_len, - rid, rid_len, FALSE); - - /* Now re-encrypt and send it to the router */ - silc_server_packet_send_srcdest(server, sock, - SILC_PACKET_CHANNEL_MESSAGE, 0, - sender_id, sender_type, - channel->id, SILC_ID_CHANNEL, - tmp, data_len); - } else { - /* Private key mode is set, we don't have the channel key, so - just re-encrypt the entire packet and send it to the router. */ - silc_server_packet_send_srcdest(server, sock, - SILC_PACKET_CHANNEL_MESSAGE, 0, - sender_id, sender_type, - channel->id, SILC_ID_CHANNEL, - data, data_len); - } - } else { - /* Send the packet to normal server */ - silc_server_packet_send_srcdest(server, sock, - SILC_PACKET_CHANNEL_MESSAGE, 0, - sender_id, sender_type, - channel->id, SILC_ID_CHANNEL, - data, data_len); - } - - continue; - } - - if (client->router) - continue; - - /* Get data used in packet header encryption, keys and stuff. */ - sock = client->connection; - if (!sock || (sender_sock && sock == sender_sock)) - continue; - - SILC_LOG_DEBUG(("Sending packet to client ID(%s)", - silc_id_render(client->id, SILC_ID_CLIENT))); - - /* Send the packet */ - silc_server_packet_send_srcdest(server, sock, - SILC_PACKET_CHANNEL_MESSAGE, 0, - sender_id, sender_type, - channel->id, SILC_ID_CHANNEL, - data, data_len); - } - - silc_hash_table_list_reset(&htl); - silc_free(routed); -} - -/* This function is used to send packets strictly to all local clients - on a particular channel. This is used for example to distribute new - channel key to all our locally connected clients on the channel. - The packets are always encrypted with the session key shared between - the client, this means these are not _to the channel_ but _to the client_ - on the channel. */ - -void silc_server_packet_send_local_channel(SilcServer server, - SilcChannelEntry channel, - SilcPacketType type, - SilcPacketFlags flags, - unsigned char *data, - SilcUInt32 data_len) -{ - SilcChannelClientEntry chl; - SilcHashTableList htl; - SilcPacketStream sock = NULL; - - SILC_LOG_DEBUG(("Send packet to local clients on channel %s", - channel->channel_name)); - - /* Send the message to clients on the channel's client list. */ - silc_hash_table_list(channel->user_list, &htl); - while (silc_hash_table_get(&htl, NULL, (void *)&chl)) { - if (chl->client && SILC_IS_LOCAL(chl->client)) { - sock = chl->client->connection; - - /* Send the packet to the client */ - silc_server_packet_send_dest(server, sock, type, flags, chl->client->id, - SILC_ID_CLIENT, data, data_len); - } - } - silc_hash_table_list_reset(&htl); -} - -/* Sends current motd to client */ - -void silc_server_send_motd(SilcServer server, - SilcPacketStream sock) -{ - char *motd, *motd_file = NULL; - SilcUInt32 motd_len; - - if (server->config) - motd_file = server->config->server_info->motd_file; - - if (motd_file) { - motd = silc_file_readfile(motd_file, &motd_len); - if (!motd) - return; - - motd[motd_len] = 0; - silc_server_send_notify(server, sock, FALSE, SILC_NOTIFY_TYPE_MOTD, 1, - motd, motd_len); - silc_free(motd); - } -} - -/* Sends error message. Error messages may or may not have any - implications. */ - -void silc_server_send_error(SilcServer server, - SilcPacketStream sock, - const char *fmt, ...) -{ - va_list ap; - unsigned char buf[4096]; - - memset(buf, 0, sizeof(buf)); - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf) - 1, fmt, ap); - va_end(ap); - - silc_server_packet_send(server, sock, SILC_PACKET_ERROR, 0, - buf, strlen(buf)); -} - -/* Sends notify message. If format is TRUE the variable arguments are - formatted and the formatted string is sent as argument payload. If it is - FALSE then each argument is sent as separate argument and their format - in the argument list must be { argument data, argument length }. */ - -void silc_server_send_notify(SilcServer server, - SilcPacketStream sock, - SilcBool broadcast, - SilcNotifyType type, - SilcUInt32 argc, ...) -{ - va_list ap; - SilcBuffer packet; - - va_start(ap, argc); - - packet = silc_notify_payload_encode(type, argc, ap); - silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, - broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, - packet->data, silc_buffer_len(packet)); - - /* Send to backup routers if this is being broadcasted to primary - router. The silc_server_backup_send checks further whether to - actually send it or not. */ - if ((broadcast && sock && sock == SILC_PRIMARY_ROUTE(server)) || - (broadcast && !sock && !SILC_PRIMARY_ROUTE(server))) - silc_server_backup_send(server, NULL, SILC_PACKET_NOTIFY, 0, - packet->data, silc_buffer_len(packet), - FALSE, TRUE); - - silc_buffer_free(packet); - va_end(ap); -} - -/* Sends notify message and gets the arguments from the `args' Argument - Payloads. */ - -void silc_server_send_notify_args(SilcServer server, - SilcPacketStream sock, - SilcBool broadcast, - SilcNotifyType type, - SilcUInt32 argc, - SilcBuffer args) -{ - SilcBuffer packet; - - packet = silc_notify_payload_encode_args(type, argc, args); - silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, - broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, - packet->data, silc_buffer_len(packet)); - silc_buffer_free(packet); -} - -/* Send CHANNEL_CHANGE notify type. This tells the receiver to replace the - `old_id' with the `new_id'. */ - -void silc_server_send_notify_channel_change(SilcServer server, - SilcPacketStream sock, - SilcBool broadcast, - SilcChannelID *old_id, - SilcChannelID *new_id) -{ - SilcBuffer idp1, idp2; - - idp1 = silc_id_payload_encode((void *)old_id, SILC_ID_CHANNEL); - idp2 = silc_id_payload_encode((void *)new_id, SILC_ID_CHANNEL); - - silc_server_send_notify(server, sock, broadcast, - SILC_NOTIFY_TYPE_CHANNEL_CHANGE, - 2, idp1->data, silc_buffer_len(idp1), - idp2->data, silc_buffer_len(idp2)); - silc_buffer_free(idp1); - silc_buffer_free(idp2); -} - -/* Send NICK_CHANGE notify type. This tells the receiver to replace the - `old_id' with the `new_id'. */ - -void silc_server_send_notify_nick_change(SilcServer server, - SilcPacketStream sock, - SilcBool broadcast, - SilcClientID *old_id, - SilcClientID *new_id, - const char *nickname) -{ - SilcBuffer idp1, idp2; - - idp1 = silc_id_payload_encode((void *)old_id, SILC_ID_CLIENT); - idp2 = silc_id_payload_encode((void *)new_id, SILC_ID_CLIENT); - - silc_server_send_notify(server, sock, broadcast, - SILC_NOTIFY_TYPE_NICK_CHANGE, - 3, idp1->data, silc_buffer_len(idp1), - idp2->data, silc_buffer_len(idp2), - nickname, nickname ? strlen(nickname) : 0); - silc_buffer_free(idp1); - silc_buffer_free(idp2); -} - -/* Sends JOIN notify type. This tells that new client by `client_id' ID - has joined to the `channel'. */ - -void silc_server_send_notify_join(SilcServer server, - SilcPacketStream sock, - SilcBool broadcast, - SilcChannelEntry channel, - SilcClientID *client_id) -{ - SilcBuffer idp1, idp2; - - idp1 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT); - idp2 = silc_id_payload_encode((void *)channel->id, SILC_ID_CHANNEL); - silc_server_send_notify(server, sock, broadcast, SILC_NOTIFY_TYPE_JOIN, - 2, idp1->data, silc_buffer_len(idp1), - idp2->data, silc_buffer_len(idp2)); - silc_buffer_free(idp1); - silc_buffer_free(idp2); -} - -/* Sends LEAVE notify type. This tells that `client_id' has left the - `channel'. The Notify packet is always destined to the channel. */ - -void silc_server_send_notify_leave(SilcServer server, - SilcPacketStream sock, - SilcBool broadcast, - SilcChannelEntry channel, - SilcClientID *client_id) -{ - SilcBuffer idp; - - idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT); - silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id, - SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_LEAVE, - 1, idp->data, silc_buffer_len(idp)); - silc_buffer_free(idp); -} - -/* Sends CMODE_CHANGE notify type. This tells that `client_id' changed the - `channel' mode to `mode. The Notify packet is always destined to - the channel. */ - -void silc_server_send_notify_cmode(SilcServer server, - SilcPacketStream sock, - SilcBool broadcast, - SilcChannelEntry channel, - SilcUInt32 mode_mask, - void *id, SilcIdType id_type, - const char *cipher, const char *hmac, - const char *passphrase, - SilcPublicKey founder_key, - SilcBuffer channel_pubkeys) -{ - SilcBuffer idp, fkey = NULL; - unsigned char mode[4], ulimit[4]; - - idp = silc_id_payload_encode((void *)id, id_type); - SILC_PUT32_MSB(mode_mask, mode); - if (founder_key) - fkey = silc_public_key_payload_encode(founder_key); - if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) - SILC_PUT32_MSB(channel->user_limit, ulimit); - - silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id, - SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_CMODE_CHANGE, - 8, idp->data, silc_buffer_len(idp), - mode, 4, - cipher, cipher ? strlen(cipher) : 0, - hmac, hmac ? strlen(hmac) : 0, - passphrase, passphrase ? - strlen(passphrase) : 0, - fkey ? fkey->data : NULL, - fkey ? silc_buffer_len(fkey) : 0, - channel_pubkeys ? channel_pubkeys->data : NULL, - channel_pubkeys ? - silc_buffer_len(channel_pubkeys) : 0, - mode_mask & SILC_CHANNEL_MODE_ULIMIT ? - ulimit : NULL, - mode_mask & SILC_CHANNEL_MODE_ULIMIT ? - sizeof(ulimit) : 0); - silc_buffer_free(fkey); - silc_buffer_free(idp); -} - -/* Sends CUMODE_CHANGE notify type. This tells that `id' changed the - `target' client's mode on `channel'. The notify packet is always - destined to the channel. */ - -void silc_server_send_notify_cumode(SilcServer server, - SilcPacketStream sock, - SilcBool broadcast, - SilcChannelEntry channel, - SilcUInt32 mode_mask, - void *id, SilcIdType id_type, - SilcClientID *target, - SilcPublicKey founder_key) -{ - SilcBuffer idp1, idp2, fkey = NULL; - unsigned char mode[4]; - - idp1 = silc_id_payload_encode((void *)id, id_type); - idp2 = silc_id_payload_encode((void *)target, SILC_ID_CLIENT); - SILC_PUT32_MSB(mode_mask, mode); - if (founder_key) - fkey = silc_public_key_payload_encode(founder_key); - - silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id, - SILC_ID_CHANNEL, - SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4, - idp1->data, silc_buffer_len(idp1), - mode, 4, - idp2->data, silc_buffer_len(idp2), - fkey ? fkey->data : NULL, - fkey ? silc_buffer_len(fkey) : 0); - silc_buffer_free(fkey); - silc_buffer_free(idp1); - silc_buffer_free(idp2); -} - -/* Sends SIGNOFF notify type. This tells that `client_id' client has - left SILC network. This function is used only between server and router - traffic. This is not used to send the notify to the channel for - client. The `message may be NULL. */ - -void silc_server_send_notify_signoff(SilcServer server, - SilcPacketStream sock, - SilcBool broadcast, - SilcClientID *client_id, - const char *message) -{ - SilcBuffer idp; - - idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT); - silc_server_send_notify(server, sock, broadcast, - SILC_NOTIFY_TYPE_SIGNOFF, - message ? 2 : 1, idp->data, silc_buffer_len(idp), - message, message ? strlen(message): 0); - silc_buffer_free(idp); -} - -/* Sends TOPIC_SET notify type. This tells that `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 - between routers. */ - -void silc_server_send_notify_topic_set(SilcServer server, - SilcPacketStream sock, - SilcBool broadcast, - SilcChannelEntry channel, - void *id, SilcIdType id_type, - char *topic) -{ - SilcBuffer idp; - - idp = silc_id_payload_encode(id, id_type); - silc_server_send_notify_dest(server, sock, broadcast, - (void *)channel->id, SILC_ID_CHANNEL, - SILC_NOTIFY_TYPE_TOPIC_SET, - topic ? 2 : 1, - idp->data, silc_buffer_len(idp), - topic, topic ? strlen(topic) : 0); - silc_buffer_free(idp); -} - -/* Send KICKED notify type. This tells that the `client_id' on `channel' - was kicked off the channel. The `comment' may indicate the reason - for the kicking. This function is used only between server and router - traffic. */ - -void silc_server_send_notify_kicked(SilcServer server, - SilcPacketStream sock, - SilcBool broadcast, - SilcChannelEntry channel, - SilcClientID *client_id, - SilcClientID *kicker, - char *comment) -{ - SilcBuffer idp1; - SilcBuffer idp2; - - idp1 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT); - idp2 = silc_id_payload_encode((void *)kicker, SILC_ID_CLIENT); - silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id, - SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_KICKED, 3, - idp1->data, silc_buffer_len(idp1), - comment, comment ? strlen(comment) : 0, - idp2->data, silc_buffer_len(idp2)); - silc_buffer_free(idp1); - silc_buffer_free(idp2); -} - -/* Send KILLED notify type. This tells that the `client_id' client was - killed from the network. The `comment' may indicate the reason - for the killing. */ - -void silc_server_send_notify_killed(SilcServer server, - SilcPacketStream sock, - SilcBool broadcast, - SilcClientID *client_id, - const char *comment, - void *killer, SilcIdType killer_type) -{ - SilcBuffer idp1; - SilcBuffer idp2; - - idp1 = silc_id_payload_encode(client_id, SILC_ID_CLIENT); - idp2 = silc_id_payload_encode(killer, killer_type); - silc_server_send_notify_dest(server, sock, broadcast, (void *)client_id, - SILC_ID_CLIENT, SILC_NOTIFY_TYPE_KILLED, - 3, idp1->data, silc_buffer_len(idp1), - comment, comment ? strlen(comment) : 0, - idp2->data, silc_buffer_len(idp2)); - silc_buffer_free(idp1); - silc_buffer_free(idp2); -} - -/* Sends UMODE_CHANGE notify type. This tells that `client_id' client's - user mode in the SILC Network was changed. This function is used to - send the packet between routers as broadcast packet. */ - -void silc_server_send_notify_umode(SilcServer server, - SilcPacketStream sock, - SilcBool broadcast, - SilcClientID *client_id, - SilcUInt32 mode_mask) -{ - SilcBuffer idp; - unsigned char mode[4]; - - idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT); - SILC_PUT32_MSB(mode_mask, mode); - - silc_server_send_notify(server, sock, broadcast, - SILC_NOTIFY_TYPE_UMODE_CHANGE, 2, - idp->data, silc_buffer_len(idp), - mode, 4); - silc_buffer_free(idp); -} - -/* Sends BAN notify type. This tells that ban has been either `add'ed - or `del'eted on the `channel. This function is used to send the packet - between routers as broadcast packet. */ - -void silc_server_send_notify_ban(SilcServer server, - SilcPacketStream sock, - SilcBool broadcast, - SilcChannelEntry channel, - unsigned char *action, - SilcBuffer list) -{ - SilcBuffer idp; - - idp = silc_id_payload_encode((void *)channel->id, SILC_ID_CHANNEL); - silc_server_send_notify(server, sock, broadcast, - SILC_NOTIFY_TYPE_BAN, 3, - idp->data, silc_buffer_len(idp), - action ? action : NULL, action ? 1 : 0, - list ? list->data : NULL, - list ? silc_buffer_len(list) : 0); - silc_buffer_free(idp); -} - -/* Sends INVITE notify type. This tells that invite has been either `add'ed - or `del'eted on the `channel. The sender of the invite is the `client_id'. - This function is used to send the packet between routers as broadcast - packet. */ - -void silc_server_send_notify_invite(SilcServer server, - SilcPacketStream sock, - SilcBool broadcast, - SilcChannelEntry channel, - SilcClientID *client_id, - unsigned char *action, - SilcBuffer list) -{ - SilcBuffer idp, idp2; - - idp = silc_id_payload_encode((void *)channel->id, SILC_ID_CHANNEL); - idp2 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT); - silc_server_send_notify(server, sock, broadcast, - SILC_NOTIFY_TYPE_INVITE, 5, - idp->data, silc_buffer_len(idp), - channel->channel_name, strlen(channel->channel_name), - idp2->data, silc_buffer_len(idp2), - action ? action : NULL, action ? 1 : 0, - list ? list->data : NULL, - list ? silc_buffer_len(list) : 0); - silc_buffer_free(idp); - silc_buffer_free(idp2); -} - -/* Sends WATCH notify type. This tells that the `client' was watched and - its status in the network has changed. */ - -void silc_server_send_notify_watch(SilcServer server, - SilcPacketStream sock, - SilcClientEntry watcher, - SilcClientEntry client, - const char *nickname, - SilcNotifyType type, - SilcPublicKey public_key) -{ - SilcBuffer idp, pkp = NULL; - unsigned char mode[4], n[2]; - - idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT); - SILC_PUT16_MSB(type, n); - SILC_PUT32_MSB(client->mode, mode); - if (public_key) - pkp = silc_public_key_payload_encode(public_key); - silc_server_send_notify_dest(server, sock, FALSE, watcher->id, - SILC_ID_CLIENT, SILC_NOTIFY_TYPE_WATCH, - 5, idp->data, silc_buffer_len(idp), - nickname, nickname ? strlen(nickname) : 0, - mode, sizeof(mode), - type != SILC_NOTIFY_TYPE_NONE ? - n : NULL, sizeof(n), - pkp ? pkp->data : NULL, - pkp ? silc_buffer_len(pkp) : 0); - silc_buffer_free(idp); - silc_buffer_free(pkp); -} - -/* Sends notify message destined to specific entity. */ - -void silc_server_send_notify_dest(SilcServer server, - SilcPacketStream sock, - SilcBool broadcast, - void *dest_id, - SilcIdType dest_id_type, - SilcNotifyType type, - SilcUInt32 argc, ...) -{ - va_list ap; - SilcBuffer packet; - - va_start(ap, argc); - - packet = silc_notify_payload_encode(type, argc, ap); - silc_server_packet_send_dest(server, sock, SILC_PACKET_NOTIFY, - broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, - dest_id, dest_id_type, - packet->data, silc_buffer_len(packet)); - - /* Send to backup routers if this is being broadcasted to primary - router. The silc_server_backup_send checks further whether to - actually send it or not. */ - if ((broadcast && sock && sock == SILC_PRIMARY_ROUTE(server)) || - (broadcast && !sock && !SILC_PRIMARY_ROUTE(server))) - silc_server_backup_send_dest(server, NULL, SILC_PACKET_NOTIFY, 0, - dest_id, dest_id_type, - packet->data, silc_buffer_len(packet), - FALSE, TRUE); - - silc_buffer_free(packet); - va_end(ap); -} - -/* Sends notify message to a channel. The notify message sent is - distributed to all clients on the channel. If `route_notify' is TRUE - then the notify may be routed to primary route or to some other routers. - If FALSE it is assured that the notify is sent only locally. If `sender' - is provided then the packet is not sent to that connection since it - originally came from it. */ - -void silc_server_send_notify_to_channel(SilcServer server, - SilcPacketStream sender, - SilcChannelEntry channel, - SilcBool route_notify, - SilcBool send_to_clients, - SilcNotifyType type, - SilcUInt32 argc, ...) -{ - va_list ap; - SilcBuffer packet; - - va_start(ap, argc); - - packet = silc_notify_payload_encode(type, argc, ap); - silc_server_packet_send_to_channel(server, sender, channel, - SILC_PACKET_NOTIFY, route_notify, - send_to_clients, - packet->data, silc_buffer_len(packet)); - silc_buffer_free(packet); - va_end(ap); -} - -/* Send notify message to all channels the client has joined. It is quaranteed - that the message is sent only once to a client (ie. if a client is joined - on two same channel it will receive only one notify message). Also, this - sends only to local clients (locally connected if we are server, and to - local servers if we are router). If `sender' is provided the packet is - not sent to that client at all. */ - -void silc_server_send_notify_on_channels(SilcServer server, - SilcClientEntry sender, - SilcClientEntry client, - SilcNotifyType type, - SilcUInt32 argc, ...) -{ - int k; - SilcPacketStream sock = NULL; - SilcClientEntry c; - SilcClientEntry *sent_clients = NULL; - SilcUInt32 sent_clients_count = 0; - SilcServerEntry *routed = NULL; - SilcUInt32 routed_count = 0; - SilcHashTableList htl, htl2; - SilcChannelEntry channel; - SilcChannelClientEntry chl, chl2; - SilcBuffer packet; - unsigned char *data; - SilcUInt32 data_len; - va_list ap; - - if (!silc_hash_table_count(client->channels)) { - SILC_LOG_DEBUG(("Client is not joined to any channels")); - return; - } - - SILC_LOG_DEBUG(("Sending notify to joined channels")); - - va_start(ap, argc); - packet = silc_notify_payload_encode(type, argc, ap); - data = packet->data; - data_len = silc_buffer_len(packet); - - silc_hash_table_list(client->channels, &htl); - while (silc_hash_table_get(&htl, NULL, (void *)&chl)) { - channel = chl->channel; - - /* Send the message to all clients on the channel's client list. */ - silc_hash_table_list(channel->user_list, &htl2); - while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) { - c = chl2->client; - - if (sender && c == sender) - continue; - - /* Check if we have sent the packet to this client already */ - for (k = 0; k < sent_clients_count; k++) - if (sent_clients[k] == c) - break; - if (k < sent_clients_count) - continue; - - /* If we are router and if this client has router set it is not - locally connected client and we will route the message to the - router set in the client. */ - if (c && c->router && server->server_type == SILC_ROUTER) { - /* Check if we have sent the packet to this route already */ - for (k = 0; k < routed_count; k++) - if (routed[k] == c->router) - break; - if (k < routed_count) - continue; - - sock = c->router->connection; - - /* Send the packet */ - silc_server_packet_send_dest(server, sock, SILC_PACKET_NOTIFY, 0, - c->router->id, SILC_ID_SERVER, - data, data_len); - - /* We want to make sure that the packet is routed to same router - only once. Mark this route as sent route. */ - routed = silc_realloc(routed, sizeof(*routed) * (routed_count + 1)); - routed[routed_count++] = c->router; - continue; - } - - if (c && c->router) - continue; - - /* Send to locally connected client */ - if (c) { - sock = c->connection; - if (!sock) - continue; - - /* Send the packet */ - silc_server_packet_send_dest(server, sock, SILC_PACKET_NOTIFY, 0, - c->id, SILC_ID_CLIENT, data, data_len); - - /* Make sure that we send the notify only once per client. */ - sent_clients = silc_realloc(sent_clients, sizeof(*sent_clients) * - (sent_clients_count + 1)); - sent_clients[sent_clients_count++] = c; - } - } - silc_hash_table_list_reset(&htl2); - } - - silc_hash_table_list_reset(&htl); - silc_free(routed); - silc_free(sent_clients); - silc_buffer_free(packet); - va_end(ap); -} - -/* Sends New ID Payload to remote end. The packet is used to distribute - information about new registered clients, servers, channel etc. usually - to routers so that they can keep these information up to date. - If the argument `broadcast' is TRUE then the packet is sent as - broadcast packet. */ - -void silc_server_send_new_id(SilcServer server, - SilcPacketStream sock, - SilcBool broadcast, - void *id, SilcIdType id_type, - SilcUInt32 id_len) -{ - SilcBuffer idp; - - SILC_LOG_DEBUG(("Sending new ID")); - - idp = silc_id_payload_encode(id, id_type); - silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID, - broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, - idp->data, silc_buffer_len(idp)); - silc_buffer_free(idp); -} - -/* Send New Channel Payload to notify about newly created channel in the - SILC network. Router uses this to notify other routers in the network - about new channel. This packet is broadcasted by router. */ - -void silc_server_send_new_channel(SilcServer server, - SilcPacketStream sock, - SilcBool broadcast, - char *channel_name, - void *channel_id, - SilcUInt32 channel_id_len, - SilcUInt32 mode) -{ - SilcBuffer packet; - unsigned char cid[32]; - SilcUInt32 name_len = strlen(channel_name); - - SILC_LOG_DEBUG(("Sending new channel")); - - if (!silc_id_id2str(channel_id, SILC_ID_CHANNEL, cid, sizeof(cid), - &channel_id_len)) - return; - - /* Encode the channel payload */ - packet = silc_channel_payload_encode(channel_name, name_len, - cid, channel_id_len, mode); - - silc_server_packet_send(server, sock, SILC_PACKET_NEW_CHANNEL, - broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, - packet->data, silc_buffer_len(packet)); - - silc_buffer_free(packet); -} - -/* Send Channel Key payload to distribute the new channel key. Normal server - sends this to router when new client joins to existing channel. Router - sends this to the local server who sent the join command in case where - the channel did not exist yet. Both normal and router servers uses this - also to send this to locally connected clients on the channel. This - must not be broadcasted packet. Routers do not send this to each other. - If `sender is provided then the packet is not sent to that connection since - it originally came from it. */ - -void silc_server_send_channel_key(SilcServer server, - SilcPacketStream sender, - SilcChannelEntry channel, - unsigned char route) -{ - SilcBuffer packet; - unsigned char cid[32]; - SilcUInt32 tmp_len, cid_len; - const char *cipher; - - SILC_LOG_DEBUG(("Sending key to channel %s", channel->channel_name)); - - if (!channel->key) - return; - - if (!silc_id_id2str(channel->id, SILC_ID_CHANNEL, cid, sizeof(cid), - &cid_len)) - return; - - /* Encode channel key packet */ - cipher = silc_cipher_get_name(channel->send_key); - tmp_len = strlen(cipher); - packet = silc_channel_key_payload_encode(cid_len, cid, tmp_len, cipher, - channel->key_len / 8, channel->key); - silc_server_packet_send_to_channel(server, sender, channel, - SILC_PACKET_CHANNEL_KEY, - route, TRUE, packet->data, - silc_buffer_len(packet)); - silc_buffer_free(packet); -} - -/* Generic function to send any command. The arguments must be sent already - encoded into correct form in correct order. */ - -void silc_server_send_command(SilcServer server, - SilcPacketStream sock, - SilcCommand command, - SilcUInt16 ident, - SilcUInt32 argc, ...) -{ - SilcBuffer packet; - va_list ap; - - /* Statistics */ - server->stat.commands_sent++; - - va_start(ap, argc); - - packet = silc_command_payload_encode_vap(command, ident, argc, ap); - silc_server_packet_send(server, sock, SILC_PACKET_COMMAND, 0, - packet->data, silc_buffer_len(packet)); - silc_buffer_free(packet); - va_end(ap); -} - -/* Generic function to send any command reply. The arguments must be sent - already encoded into correct form in correct order. */ - -void silc_server_send_command_reply(SilcServer server, - SilcPacketStream sock, - SilcCommand command, - SilcStatus status, - SilcStatus error, - SilcUInt16 ident, - SilcUInt32 argc, ...) -{ - SilcBuffer packet; - va_list ap; - - /* Statistics */ - server->stat.commands_sent++; - - va_start(ap, argc); - - packet = silc_command_reply_payload_encode_vap(command, status, error, - ident, argc, ap); - silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, - packet->data, silc_buffer_len(packet)); - silc_buffer_free(packet); - va_end(ap); -} - -/* Generic function to send any command reply. The arguments must be sent - already encoded into correct form in correct order. */ - -void silc_server_send_dest_command_reply(SilcServer server, - SilcPacketStream sock, - void *dst_id, - SilcIdType dst_id_type, - SilcCommand command, - SilcStatus status, - SilcStatus error, - SilcUInt16 ident, - SilcUInt32 argc, ...) -{ - SilcBuffer packet; - va_list ap; - - /* Statistics */ - server->stat.commands_sent++; - - va_start(ap, argc); - - packet = silc_command_reply_payload_encode_vap(command, status, error, - ident, argc, ap); - silc_server_packet_send_dest(server, sock, SILC_PACKET_COMMAND_REPLY, 0, - dst_id, dst_id_type, packet->data, - silc_buffer_len(packet)); - silc_buffer_free(packet); - va_end(ap); -} - -/* Routine used to send the connection authentication packet. */ - -void silc_server_send_connection_auth_request(SilcServer server, - SilcPacketStream sock, - SilcUInt16 conn_type, - SilcAuthMethod auth_meth) -{ - SilcBuffer packet; - - packet = silc_buffer_alloc(4); - silc_buffer_pull_tail(packet, silc_buffer_truelen(packet)); - silc_buffer_format(packet, - SILC_STR_UI_SHORT(conn_type), - SILC_STR_UI_SHORT(auth_meth), - SILC_STR_END); - - silc_server_packet_send(server, sock, SILC_PACKET_CONNECTION_AUTH_REQUEST, - 0, packet->data, silc_buffer_len(packet)); - silc_buffer_free(packet); -} - -/* Send packet to clients that are known to be operators. If server - is router and `route' is TRUE then the packet would go to all operators - in the SILC network. If `route' is FALSE then only local operators - (local for server and cell wide for router). If `local' is TRUE then - only locally connected operators receive the packet. If `local' is - TRUE then `route' is ignored. If server is normal server and `route' - is FALSE it is equivalent to `local' being TRUE. */ - -void silc_server_send_opers(SilcServer server, - SilcPacketType type, - SilcPacketFlags flags, - SilcBool route, bool local, - unsigned char *data, - SilcUInt32 data_len) -{ - SilcList list; - SilcIDCacheEntry id_cache = NULL; - SilcClientEntry client = NULL; - SilcIDListData idata; - SilcPacketStream sock; - SilcServerEntry *routed = NULL; - SilcUInt32 routed_count = 0; - SilcBool gone = FALSE; - int k; - - SILC_LOG_DEBUG(("Sending %s packet to operators", - silc_get_packet_name(type))); - - /* If local was requested send only locally connected operators. */ - if (local || (server->server_type == SILC_SERVER && !route)) { - if (!silc_idcache_get_all(server->local_list->clients, &list)) - return; - silc_list_start(list); - while ((id_cache = silc_list_get(list))) { - client = (SilcClientEntry)id_cache->context; - if (!client->router && SILC_IS_LOCAL(client) && - (client->mode & SILC_UMODE_SERVER_OPERATOR || - client->mode & SILC_UMODE_ROUTER_OPERATOR)) { - - /* Send the packet to locally connected operator */ - silc_server_packet_send_dest(server, client->connection, type, flags, - client->id, SILC_ID_CLIENT, - data, data_len); - } - } - return; - } - - if (!silc_idcache_get_all(server->local_list->clients, &list)) - return; - silc_list_start(list); - while ((id_cache = silc_list_get(list))) { - client = (SilcClientEntry)id_cache->context; - if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) && - !(client->mode & SILC_UMODE_ROUTER_OPERATOR)) - continue; - - if (server->server_type != SILC_SERVER && 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 = client->router->connection; - idata = silc_packet_get_context(sock); - if (idata->conn_type == SILC_CONN_ROUTER) { - if (gone) - continue; - gone = TRUE; - } - - /* Send the packet */ - silc_server_packet_send_dest(server, sock, type, flags, - client->id, SILC_ID_CLIENT, - data, data_len); - - /* Mark this route routed already */ - routed = silc_realloc(routed, sizeof(*routed) * (routed_count + 1)); - routed[routed_count++] = client->router; - continue; - } - - if (client->router || !client->connection) - continue; - - /* Send to locally connected client */ - sock = client->connection; - silc_server_packet_send_dest(server, sock, type, flags, - client->id, SILC_ID_CLIENT, - data, data_len); - - } - - if (!silc_idcache_get_all(server->global_list->clients, &list)) - return; - silc_list_start(list); - while ((id_cache = silc_list_get(list))) { - client = (SilcClientEntry)id_cache->context; - if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) && - !(client->mode & SILC_UMODE_ROUTER_OPERATOR)) - continue; - - if (server->server_type != SILC_SERVER && 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 = client->router->connection; - idata = silc_packet_get_context(sock); - if (idata->conn_type == SILC_CONN_ROUTER) { - if (gone) - continue; - gone = TRUE; - } - - /* Send the packet */ - silc_server_packet_send_dest(server, sock, type, flags, - client->id, SILC_ID_CLIENT, - data, data_len); - - /* Mark this route routed already */ - routed = silc_realloc(routed, sizeof(*routed) * (routed_count + 1)); - routed[routed_count++] = client->router; - continue; - } - - if (client->router || !client->connection) - continue; - - /* Send to locally connected client */ - sock = client->connection; - silc_server_packet_send_dest(server, sock, type, flags, - client->id, SILC_ID_CLIENT, - data, data_len); - } - silc_free(routed); -} - -/* Send a notify packet to operators */ - -void silc_server_send_opers_notify(SilcServer server, - SilcBool route, - SilcBool local, - SilcNotifyType type, - SilcUInt32 argc, ...) -{ - va_list ap; - SilcBuffer packet; - - va_start(ap, argc); - packet = silc_notify_payload_encode(type, argc, ap); - silc_server_send_opers(server, SILC_PACKET_NOTIFY, 0, - route, local, packet->data, silc_buffer_len(packet)); - silc_buffer_free(packet); - va_end(ap); -}