+++ /dev/null
-/*
-
- packet_send.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- 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);
-}