/*
- packet_send.c
+ packet_send.c
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2001 Pekka Riikonen
+ Copyright (C) 1997 - 2002 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; either version 2 of the License, or
- (at your option) any later version.
-
+ 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
/* Send the packet */
ret = silc_packet_send(sock, force_send);
- if (ret != -2)
+ if (ret != -2) {
+ server->stat.packets_sent++;
return ret;
+ }
/* Mark that there is some outgoing data available for this connection.
This call sets the connection both for input and output (the input
SilcPacketType type,
SilcPacketFlags flags,
unsigned char *data,
- uint32 data_len,
+ SilcUInt32 data_len,
bool force_send)
{
void *dst_id = NULL;
SilcIdType dst_id_type = SILC_ID_NONE;
- SilcIDListData idata = (SilcIDListData)sock->user_data;
+ SilcIDListData idata;
if (!sock)
return;
+ idata = (SilcIDListData)sock->user_data;
+
/* If disconnecting, ignore the data */
if (SILC_IS_DISCONNECTING(sock))
return;
- /* If entry is disabled do not sent anything. */
- if (idata && idata->status & SILC_IDLIST_STATUS_DISABLED)
+ /* If entry is disabled do not sent anything. Allow hearbeat and
+ rekeys, though */
+ if ((idata && idata->status & SILC_IDLIST_STATUS_DISABLED &&
+ type != SILC_PACKET_HEARTBEAT && type != SILC_PACKET_REKEY &&
+ type != SILC_PACKET_REKEY_DONE) ||
+ sock->user_data == server->id_entry) {
+ SILC_LOG_DEBUG(("Connection is disabled"));
return;
+ }
/* Get data used in the packet sending, keys and stuff */
switch(sock->type) {
void *dst_id,
SilcIdType dst_id_type,
unsigned char *data,
- uint32 data_len,
+ SilcUInt32 data_len,
bool force_send)
{
SilcPacketContext packetdata;
- SilcIDListData idata = (SilcIDListData)sock->user_data;
+ const SilcBufferStruct packet;
+ SilcIDListData idata;
SilcCipher cipher = NULL;
SilcHmac hmac = NULL;
- uint32 sequence = 0;
+ SilcUInt32 sequence = 0;
unsigned char *dst_id_data = NULL;
- uint32 dst_id_len = 0;
+ SilcUInt32 dst_id_len = 0;
int block_len = 0;
/* If disconnecting, ignore the data */
- if (SILC_IS_DISCONNECTING(sock))
+ if (!sock || SILC_IS_DISCONNECTING(sock))
return;
+ idata = (SilcIDListData)sock->user_data;
+
/* If entry is disabled do not sent anything. */
- if (idata && idata->status & SILC_IDLIST_STATUS_DISABLED)
+ if ((idata && idata->status & SILC_IDLIST_STATUS_DISABLED) ||
+ sock->user_data == server->id_entry) {
+ SILC_LOG_DEBUG(("Connection is disabled"));
return;
+ }
- SILC_LOG_DEBUG(("Sending packet, type %d", type));
+ SILC_LOG_DEBUG(("Sending %s packet", silc_get_packet_name(type)));
if (dst_id) {
dst_id_data = silc_id_id2str(dst_id, dst_id_type);
/* Set the packet context pointers */
packetdata.type = type;
packetdata.flags = flags;
- packetdata.src_id = silc_id_id2str(server->id, server->id_type);
- packetdata.src_id_len = silc_id_get_len(server->id, server->id_type);
- packetdata.src_id_type = server->id_type;
+ packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER);
+ packetdata.src_id_len = silc_id_get_len(server->id, SILC_ID_SERVER);
+ packetdata.src_id_type = SILC_ID_SERVER;
packetdata.dst_id = dst_id_data;
packetdata.dst_id_len = dst_id_len;
packetdata.dst_id_type = dst_id_type;
+ data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len));
packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
packetdata.src_id_len + dst_id_len;
packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len);
- /* Prepare outgoing data buffer for packet sending */
- silc_packet_send_prepare(sock,
- SILC_PACKET_HEADER_LEN +
- packetdata.src_id_len +
- packetdata.dst_id_len,
- packetdata.padlen,
- data_len);
-
- SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
-
- packetdata.buffer = sock->outbuf;
-
- /* Put the data to the buffer */
- if (data && data_len)
- silc_buffer_put(sock->outbuf, data, data_len);
-
/* Create the outgoing packet */
- silc_packet_assemble(&packetdata, cipher);
+ if (!silc_packet_assemble(&packetdata, NULL, cipher, hmac, sock,
+ data, data_len, (const SilcBuffer)&packet)) {
+ SILC_LOG_ERROR(("Cannot assemble packet"));
+ goto out;
+ }
/* Encrypt the packet */
- silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf, sock->outbuf->len);
+ silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&packet, packet.len);
- SILC_LOG_HEXDUMP(("Outgoing packet (%d), len %d", sequence,
- sock->outbuf->len),
- sock->outbuf->data, sock->outbuf->len);
+ SILC_LOG_HEXDUMP(("Outgoing packet (%d), len %d", sequence, packet.len),
+ packet.data, packet.len);
/* Now actually send the packet */
silc_server_packet_send_real(server, sock, force_send);
- if (packetdata.src_id)
- silc_free(packetdata.src_id);
- if (packetdata.dst_id)
- silc_free(packetdata.dst_id);
+ out:
+ silc_free(packetdata.src_id);
+ silc_free(packetdata.dst_id);
}
/* Assembles a new packet to be sent out to network. This doesn't actually
void *dst_id,
SilcIdType dst_id_type,
unsigned char *data,
- uint32 data_len,
+ SilcUInt32 data_len,
bool force_send)
{
SilcPacketContext packetdata;
+ const SilcBufferStruct packet;
SilcIDListData idata;
SilcCipher cipher = NULL;
SilcHmac hmac = NULL;
- uint32 sequence = 0;
+ SilcUInt32 sequence = 0;
unsigned char *dst_id_data = NULL;
- uint32 dst_id_len = 0;
+ SilcUInt32 dst_id_len = 0;
unsigned char *src_id_data = NULL;
- uint32 src_id_len = 0;
+ SilcUInt32 src_id_len = 0;
int block_len = 0;
- SILC_LOG_DEBUG(("Sending packet, type %d", type));
+ SILC_LOG_DEBUG(("Sending %s packet", silc_get_packet_name(type)));
+
+ if (!sock)
+ return;
/* Get data used in the packet sending, keys and stuff */
idata = (SilcIDListData)sock->user_data;
+ /* If entry is disabled do not sent anything. */
+ if ((idata && idata->status & SILC_IDLIST_STATUS_DISABLED) ||
+ sock->user_data == server->id_entry) {
+ SILC_LOG_DEBUG(("Connection is disabled"));
+ return;
+ }
+
+ if (idata) {
+ cipher = idata->send_key;
+ hmac = idata->hmac_send;
+ sequence = idata->psn_send++;
+ block_len = silc_cipher_get_block_len(cipher);
+ }
+
if (dst_id) {
dst_id_data = silc_id_id2str(dst_id, dst_id_type);
dst_id_len = silc_id_get_len(dst_id, dst_id_type);
src_id_len = silc_id_get_len(src_id, src_id_type);
}
- if (idata) {
- cipher = idata->send_key;
- hmac = idata->hmac_send;
- sequence = idata->psn_send++;
- block_len = silc_cipher_get_block_len(cipher);
- }
-
/* Set the packet context pointers */
packetdata.type = type;
packetdata.flags = flags;
packetdata.dst_id = dst_id_data;
packetdata.dst_id_len = dst_id_len;
packetdata.dst_id_type = dst_id_type;
+ data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ dst_id_len));
packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
packetdata.src_id_len + dst_id_len;
packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len);
- /* Prepare outgoing data buffer for packet sending */
- silc_packet_send_prepare(sock,
- SILC_PACKET_HEADER_LEN +
- packetdata.src_id_len +
- packetdata.dst_id_len,
- packetdata.padlen,
- data_len);
-
- SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
-
- packetdata.buffer = sock->outbuf;
-
- /* Put the data to the buffer */
- if (data && data_len)
- silc_buffer_put(sock->outbuf, data, data_len);
-
/* Create the outgoing packet */
- silc_packet_assemble(&packetdata, cipher);
+ if (!silc_packet_assemble(&packetdata, NULL, cipher, hmac, sock, data,
+ data_len, (const SilcBuffer)&packet)) {
+ SILC_LOG_ERROR(("Cannot assemble packe"));
+ goto out;
+ }
/* Encrypt the packet */
- silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf, sock->outbuf->len);
+ silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&packet, packet.len);
- SILC_LOG_HEXDUMP(("Outgoing packet (%d), len %d", sequence,
- sock->outbuf->len),
- sock->outbuf->data, sock->outbuf->len);
+ SILC_LOG_HEXDUMP(("Outgoing packet (%d), len %d", sequence, packet.len),
+ packet.data, packet.len);
/* Now actually send the packet */
silc_server_packet_send_real(server, sock, force_send);
- if (packetdata.src_id)
- silc_free(packetdata.src_id);
- if (packetdata.dst_id)
- silc_free(packetdata.dst_id);
+ out:
+ silc_free(packetdata.src_id);
+ silc_free(packetdata.dst_id);
}
/* Broadcast received packet to our primary route. This function is used
SilcIDListData idata;
void *id;
+ if (!sock)
+ return;
+
SILC_LOG_DEBUG(("Broadcasting received broadcast packet"));
/* If the packet is originated from our primary route we are
not allowed to send the packet. */
id = silc_id_str2id(packet->src_id, packet->src_id_len, packet->src_id_type);
if (id && !SILC_ID_SERVER_COMPARE(id, server->router->id)) {
+ const SilcBufferStruct p;
+
idata = (SilcIDListData)sock->user_data;
silc_buffer_push(buffer, buffer->data - buffer->head);
- silc_packet_send_prepare(sock, 0, 0, buffer->len);
- silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
+ if (!silc_packet_send_prepare(sock, 0, 0, buffer->len, idata->hmac_send,
+ (const SilcBuffer)&p)) {
+ SILC_LOG_ERROR(("Cannot send packet"));
+ silc_free(id);
+ return;
+ }
+ silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
- sock->outbuf, sock->outbuf->len);
+ (SilcBuffer)&p, p.len);
SILC_LOG_HEXDUMP(("Broadcasted packet (%d), len %d", idata->psn_send - 1,
- sock->outbuf->len),
- sock->outbuf->data, sock->outbuf->len);
+ p.len), p.data, p.len);
/* Now actually send the packet */
silc_server_packet_send_real(server, sock, TRUE);
SilcPacketContext *packet)
{
SilcBuffer buffer = packet->buffer;
+ const SilcBufferStruct p;
SilcIDListData idata;
SILC_LOG_DEBUG(("Routing received packet"));
idata = (SilcIDListData)sock->user_data;
silc_buffer_push(buffer, buffer->data - buffer->head);
- silc_packet_send_prepare(sock, 0, 0, buffer->len);
- silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
+ if (!silc_packet_send_prepare(sock, 0, 0, buffer->len, idata->hmac_send,
+ (const SilcBuffer)&p)) {
+ SILC_LOG_ERROR(("Cannot send packet"));
+ return;
+ }
+ silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
- sock->outbuf, sock->outbuf->len);
+ (SilcBuffer)&p, p.len);
SILC_LOG_HEXDUMP(("Routed packet (%d), len %d", idata->psn_send - 1,
- sock->outbuf->len),
- sock->outbuf->data, sock->outbuf->len);
+ p.len), p.data, p.len);
/* Now actually send the packet */
silc_server_packet_send_real(server, sock, TRUE);
clients (for server locally connected, and for router local cell). */
void silc_server_packet_send_clients(SilcServer server,
- SilcClientEntry *clients,
- uint32 clients_count,
+ SilcHashTable clients,
SilcPacketType type,
SilcPacketFlags flags,
bool route,
unsigned char *data,
- uint32 data_len,
+ SilcUInt32 data_len,
bool force_send)
{
SilcSocketConnection sock = NULL;
+ SilcHashTableList htl;
SilcClientEntry client = NULL;
SilcServerEntry *routed = NULL;
- uint32 routed_count = 0;
+ SilcUInt32 routed_count = 0;
bool gone = FALSE;
- int i, k;
+ int k;
- SILC_LOG_DEBUG(("Sending packet to list of clients"));
+ if (!silc_hash_table_count(clients))
+ return;
- /* Send to all clients in table */
- for (i = 0; i < clients_count; i++) {
- client = clients[i];
+ 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. */
/* Send to locally connected client */
sock = (SilcSocketConnection)client->connection;
+ if (!sock)
+ continue;
+
silc_server_packet_send_dest(server, sock, type, flags,
client->id, SILC_ID_CLIENT,
data, data_len, force_send);
}
-
+ silc_hash_table_list_reset(&htl);
silc_free(routed);
}
SilcPacketContext *packet,
SilcCipher cipher,
SilcHmac hmac,
- uint32 sequence,
+ SilcUInt32 sequence,
unsigned char *data,
- uint32 data_len,
+ SilcUInt32 data_len,
bool channel_message,
bool force_send)
{
int block_len;
+ const SilcBufferStruct p;
+
+ if (!sock)
+ return;
+
+ data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
+ packet->src_id_len +
+ packet->dst_id_len));
packet->truelen = data_len + SILC_PACKET_HEADER_LEN +
packet->src_id_len + packet->dst_id_len;
else
packet->padlen = SILC_PACKET_PADLEN(packet->truelen, block_len);
- /* Prepare outgoing data buffer for packet sending */
- silc_packet_send_prepare(sock,
- SILC_PACKET_HEADER_LEN +
- packet->src_id_len +
- packet->dst_id_len,
- packet->padlen,
- data_len);
-
- packet->buffer = sock->outbuf;
-
/* Put the data to buffer, assemble and encrypt the packet. The packet
is encrypted with normal session key shared with the client, unless
the `channel_message' is TRUE. */
- silc_buffer_put(sock->outbuf, data, data_len);
- silc_packet_assemble(packet, cipher);
+ if (!silc_packet_assemble(packet, NULL, cipher, hmac, sock, data,
+ data_len, (const SilcBuffer)&p)) {
+ SILC_LOG_ERROR(("Cannot assemble packet"));
+ return;
+ }
+
if (channel_message)
- silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf,
+ silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&p,
SILC_PACKET_HEADER_LEN + packet->src_id_len +
packet->dst_id_len + packet->padlen);
else
- silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf,
- sock->outbuf->len);
+ silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&p, p.len);
- SILC_LOG_HEXDUMP(("Channel packet (%d), len %d", sequence,
- sock->outbuf->len),
- sock->outbuf->data, sock->outbuf->len);
+ SILC_LOG_HEXDUMP(("Channel packet (%d), len %d", sequence, p.len),
+ p.data, p.len);
/* Now actually send the packet */
silc_server_packet_send_real(server, sock, force_send);
SilcPacketType type,
bool route,
unsigned char *data,
- uint32 data_len,
+ SilcUInt32 data_len,
bool force_send)
{
SilcSocketConnection sock = NULL;
SilcChannelClientEntry chl;
SilcHashTableList htl;
SilcIDListData idata;
- uint32 routed_count = 0;
+ SilcUInt32 routed_count = 0;
bool gone = FALSE;
int k;
/* This doesn't send channel message packets */
assert(type != SILC_PACKET_CHANNEL_MESSAGE);
- SILC_LOG_DEBUG(("Sending packet to channel"));
-
/* Set the packet context pointers. */
packetdata.flags = 0;
packetdata.type = type;
if (sock != sender) {
SILC_LOG_DEBUG(("Sending packet to router for routing"));
-
silc_server_packet_send_to_channel_real(server, sock, &packetdata,
idata->send_key,
idata->hmac_send,
}
}
+ 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)) {
+ while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
client = chl->client;
if (!client)
continue;
if (sender && sock == sender)
continue;
- /* Route only once to router */
+ /* Route only once to router. Protocol prohibits sending channel
+ messages to more than one router. */
if (sock->type == SILC_SOCKET_TYPE_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_to_channel_real(server, sock, &packetdata,
idata->send_key,
sock = (SilcSocketConnection)client->connection;
idata = (SilcIDListData)client;
- if (sender && sock == sender)
+ 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_to_channel_real(server, sock, &packetdata,
idata->send_key,
data, data_len, FALSE,
force_send);
}
+ silc_hash_table_list_reset(&htl);
+ out:
silc_free(routed);
silc_free(packetdata.src_id);
silc_free(packetdata.dst_id);
sock->type == SILC_SOCKET_TYPE_ROUTER &&
!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY) &&
channel->channel_key) {
- SilcBuffer chp;
- uint32 iv_len, i;
- uint16 dlen, flags;
-
- iv_len = silc_cipher_get_block_len(channel->channel_key);
- if (channel->iv[0] == '\0')
- for (i = 0; i < iv_len; i++) channel->iv[i] =
- silc_rng_get_byte(server->rng);
- else
- silc_hash_make(server->md5hash, channel->iv, iv_len, channel->iv);
-
- /* Encode new payload. This encrypts it also. */
- SILC_GET16_MSB(flags, data);
- SILC_GET16_MSB(dlen, data + 2);
+ SilcUInt32 mac_len = silc_hmac_len(channel->hmac);
+ SilcUInt32 iv_len = silc_cipher_get_block_len(channel->channel_key);
+ unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
- if (dlen > data_len) {
+ if (data_len <= mac_len + iv_len) {
SILC_LOG_WARNING(("Corrupted channel message, cannot relay it"));
return FALSE;
}
- chp = silc_channel_message_payload_encode(flags, dlen, data + 4,
- iv_len, channel->iv,
- channel->channel_key,
- channel->hmac);
- memcpy(data, chp->data, chp->len);
- silc_buffer_free(chp);
+ memcpy(iv, data + (data_len - iv_len), iv_len);
+ silc_channel_message_payload_encrypt(data, data_len - iv_len - mac_len,
+ data_len, iv, iv_len,
+ channel->channel_key, channel->hmac);
}
return TRUE;
void silc_server_packet_relay_to_channel(SilcServer server,
SilcSocketConnection sender_sock,
SilcChannelEntry channel,
- void *sender,
+ void *sender_id,
SilcIdType sender_type,
- void *sender_entry,
+ SilcClientEntry sender_entry,
unsigned char *data,
- uint32 data_len,
+ SilcUInt32 data_len,
bool force_send)
{
- bool found = FALSE;
SilcSocketConnection sock = NULL;
SilcPacketContext packetdata;
SilcClientEntry client = NULL;
SilcServerEntry *routed = NULL;
- SilcChannelClientEntry chl;
- uint32 routed_count = 0;
+ SilcChannelClientEntry chl, chl_sender;
+ SilcUInt32 routed_count = 0;
SilcIDListData idata;
SilcHashTableList htl;
bool gone = FALSE;
int k;
- SILC_LOG_DEBUG(("Relaying packet to channel"));
+ 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 packet, if needed. It will be encrypted if
it came from the router thus it needs to be encrypted with the
/* Set the packet context pointers. */
packetdata.flags = 0;
packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
- packetdata.src_id = silc_id_id2str(sender, sender_type);
- packetdata.src_id_len = silc_id_get_len(sender, sender_type);
+ packetdata.src_id = silc_id_id2str(sender_id, sender_type);
+ packetdata.src_id_len = silc_id_get_len(sender_id, sender_type);
packetdata.src_id_type = sender_type;
packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
packetdata.dst_id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
sock = (SilcSocketConnection)router->connection;
idata = (SilcIDListData)router;
- SILC_LOG_DEBUG(("Sending channel message to router for routing"));
+ SILC_LOG_DEBUG(("Sending message to router for routing"));
silc_server_packet_send_to_channel_real(server, sock, &packetdata,
idata->send_key,
routed = silc_calloc(silc_hash_table_count(channel->user_list),
sizeof(*routed));
- /* Mark that to the route the original sender if from is not routed */
- if (sender_type == SILC_ID_CLIENT) {
- client = (SilcClientEntry)sender_entry;
- if (client->router) {
- routed[routed_count++] = client->router;
- SILC_LOG_DEBUG(("************* router %s",
- silc_id_render(client->router->id, SILC_ID_SERVER)));
- }
- }
+ /* 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)) {
+ while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
client = chl->client;
- if (!client)
+ if (!client || client == sender_entry)
continue;
- /* Do not send to the sender */
- if (!found && client == sender_entry) {
- found = TRUE;
+ /* 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) {
- /* Sender maybe server as well so we want to make sure that
- we won't send the message to the server it came from. */
- if (!found && SILC_ID_SERVER_COMPARE(client->router->id, sender)) {
- found = TRUE;
- routed[routed_count++] = client->router;
- continue;
- }
-
/* 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 = (SilcSocketConnection)client->router->connection;
idata = (SilcIDListData)client->router;
- /* Do not send to the sender. Check first whether the true
- sender's router is same as this client's router. Also check
- if the sender socket is the same as this client's router
+ /* Check if the sender socket is the same as this client's router
socket. */
- if (sender_entry &&
- ((SilcClientEntry)sender_entry)->router == client->router)
- continue;
if (sender_sock && sock == sender_sock)
continue;
/* Mark this route routed already. */
routed[routed_count++] = client->router;
- /* If 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. */
if (sock->type == SILC_SOCKET_TYPE_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;
SILC_LOG_DEBUG(("Remote is router, encrypt with session key"));
- gone = TRUE;
/* If private key mode is not set then decrypt the packet
and re-encrypt it */
- if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
- unsigned char *tmp = silc_calloc(data_len, sizeof(*data));
+ if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY) &&
+ channel->channel_key) {
+ unsigned char tmp[SILC_PACKET_MAX_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) */
- if (channel->channel_key &&
- !silc_channel_message_payload_decrypt(tmp, data_len,
- channel->channel_key,
- NULL)) {
- memset(tmp, 0, data_len);
- silc_free(tmp);
- continue;
- }
+ silc_channel_message_payload_decrypt(tmp, data_len,
+ channel->channel_key, NULL);
/* Now re-encrypt and send it to the router */
- silc_server_packet_send_srcdest(server, sock,
+ silc_server_packet_send_srcdest(server, sock,
SILC_PACKET_CHANNEL_MESSAGE, 0,
- sender, sender_type,
+ sender_id, sender_type,
channel->id, SILC_ID_CHANNEL,
tmp, data_len, force_send);
-
- /* Free the copy of the channel message */
- memset(tmp, 0, data_len);
- silc_free(tmp);
} 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_server_packet_send_srcdest(server, sock,
SILC_PACKET_CHANNEL_MESSAGE, 0,
- sender, sender_type,
+ sender_id, sender_type,
channel->id, SILC_ID_CHANNEL,
data, data_len, force_send);
}
- continue;
+ } else {
+ /* Send the packet to normal server */
+ silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+ idata->send_key,
+ idata->hmac_send,
+ idata->psn_send++,
+ data, data_len, TRUE,
+ force_send);
}
- /* Send the packet (to normal server) */
- silc_server_packet_send_to_channel_real(server, sock, &packetdata,
- idata->send_key,
- idata->hmac_send,
- idata->psn_send++,
- data, data_len, TRUE,
- force_send);
-
continue;
}
sock = (SilcSocketConnection)client->connection;
idata = (SilcIDListData)client;
- if (sender_sock && sock == sender_sock)
+ if (!sock || (sender_sock && sock == sender_sock))
continue;
SILC_LOG_DEBUG(("Sending packet to client ID(%s) %s (%s)",
force_send);
}
+ silc_hash_table_list_reset(&htl);
silc_free(routed);
silc_free(packetdata.src_id);
silc_free(packetdata.dst_id);
SilcPacketType type,
SilcPacketFlags flags,
unsigned char *data,
- uint32 data_len,
+ SilcUInt32 data_len,
bool force_send)
{
SilcChannelClientEntry chl;
SilcHashTableList htl;
SilcSocketConnection sock = NULL;
- SILC_LOG_DEBUG(("Start"));
+ 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)) {
+ while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
if (chl->client && !chl->client->router) {
sock = (SilcSocketConnection)chl->client->connection;
force_send);
}
}
+ silc_hash_table_list_reset(&htl);
}
/* Routine used to send (relay, route) private messages to some destination.
SilcSocketConnection dst_sock,
SilcCipher cipher,
SilcHmac hmac,
- uint32 sequence,
+ SilcUInt32 sequence,
SilcPacketContext *packet)
{
SilcBuffer buffer = packet->buffer;
+ const SilcBufferStruct p;
+
+ silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
+ + packet->dst_id_len + packet->padlen);
+ if (!silc_packet_send_prepare(dst_sock, 0, 0, buffer->len, hmac,
+ (const SilcBuffer)&p)) {
+ SILC_LOG_ERROR(("Cannot send packet"));
+ return;
+ }
+ silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
/* Re-encrypt and send if private messge key does not exist */
if (!(packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY)) {
-
- silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
- + packet->dst_id_len + packet->padlen);
- silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
- silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
-
/* Re-encrypt packet */
- silc_packet_encrypt(cipher, hmac, sequence, dst_sock->outbuf, buffer->len);
-
- /* Send the packet */
- silc_server_packet_send_real(server, dst_sock, FALSE);
-
+ silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&p, buffer->len);
} else {
/* Key exist so encrypt just header and send it */
- silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
- + packet->dst_id_len + packet->padlen);
- silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
- silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
-
- /* Encrypt header */
- silc_packet_encrypt(cipher, hmac, sequence, dst_sock->outbuf,
+ silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&p,
SILC_PACKET_HEADER_LEN + packet->src_id_len +
packet->dst_id_len + packet->padlen);
-
- silc_server_packet_send_real(server, dst_sock, FALSE);
}
+
+ /* Send the packet */
+ silc_server_packet_send_real(server, dst_sock, FALSE);
}
/* Sends current motd to client */
void silc_server_send_motd(SilcServer server,
SilcSocketConnection sock)
{
- char *motd;
- uint32 motd_len;
+ char *motd, *motd_file = NULL;
+ SilcUInt32 motd_len;
- if (server->config && server->config->motd &&
- server->config->motd->motd_file) {
+ if (server->config)
+ motd_file = server->config->server_info->motd_file;
- motd = silc_file_readfile(server->config->motd->motd_file, &motd_len);
+ if (motd_file) {
+ motd = silc_file_readfile(motd_file, &motd_len);
if (!motd)
return;
SilcSocketConnection sock,
bool broadcast,
SilcNotifyType type,
- uint32 argc, ...)
+ SilcUInt32 argc, ...)
{
va_list ap;
SilcBuffer packet;
packet->data, packet->len, FALSE);
/* Send to backup routers if this is being broadcasted to primary
- router. */
- if (server->router && server->router->connection &&
- sock == server->router->connection && broadcast)
+ 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, packet->len, FALSE, TRUE);
SilcSocketConnection sock,
bool broadcast,
SilcNotifyType type,
- uint32 argc,
+ SilcUInt32 argc,
SilcBuffer args)
{
SilcBuffer packet;
SilcSocketConnection sock,
bool broadcast,
SilcClientID *old_id,
- SilcClientID *new_id)
+ SilcClientID *new_id,
+ const char *nickname)
{
SilcBuffer idp1, idp2;
silc_server_send_notify(server, sock, broadcast,
SILC_NOTIFY_TYPE_NICK_CHANGE,
- 2, idp1->data, idp1->len, idp2->data, idp2->len);
+ 3, idp1->data, idp1->len, idp2->data, idp2->len,
+ nickname, nickname ? strlen(nickname) : 0);
silc_buffer_free(idp1);
silc_buffer_free(idp2);
}
SilcSocketConnection sock,
bool broadcast,
SilcChannelEntry channel,
- uint32 mode_mask,
+ SilcUInt32 mode_mask,
void *id, SilcIdType id_type,
- char *cipher, char *hmac,
- char *passphrase)
+ const char *cipher, const char *hmac,
+ const char *passphrase,
+ SilcPublicKey founder_key)
{
SilcBuffer idp;
- unsigned char mode[4];
+ unsigned char mode[4], *key = NULL;
+ SilcUInt32 key_len = 0;
idp = silc_id_payload_encode((void *)id, id_type);
SILC_PUT32_MSB(mode_mask, mode);
+ if (founder_key)
+ key = silc_pkcs_public_key_encode(founder_key, &key_len);
silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_CMODE_CHANGE,
- 5, idp->data, idp->len,
+ 6, idp->data, idp->len,
mode, 4,
cipher, cipher ? strlen(cipher) : 0,
hmac, hmac ? strlen(hmac) : 0,
passphrase, passphrase ?
- strlen(passphrase) : 0);
+ strlen(passphrase) : 0,
+ key, key_len);
+ silc_free(key);
silc_buffer_free(idp);
}
-/* Sends CUMODE_CHANGE notify type. This tells that `client_id' changed the
+/* 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. */
SilcSocketConnection sock,
bool broadcast,
SilcChannelEntry channel,
- uint32 mode_mask,
+ SilcUInt32 mode_mask,
void *id, SilcIdType id_type,
- SilcClientID *target)
+ SilcClientID *target,
+ SilcPublicKey founder_key)
{
SilcBuffer idp1, idp2;
- unsigned char mode[4];
+ unsigned char mode[4], *key = NULL;
+ SilcUInt32 key_len = 0;
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)
+ key = silc_pkcs_public_key_encode(founder_key, &key_len);
silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
SILC_ID_CHANNEL,
- SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
+ SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4,
idp1->data, idp1->len,
mode, 4,
- idp2->data, idp2->len);
+ idp2->data, idp2->len,
+ key, key_len);
+ silc_free(key);
silc_buffer_free(idp1);
silc_buffer_free(idp2);
}
SilcSocketConnection sock,
bool broadcast,
SilcClientID *client_id,
- char *comment)
+ const char *comment,
+ void *killer, SilcIdType killer_type)
{
- SilcBuffer idp;
+ SilcBuffer idp1;
+ SilcBuffer idp2;
- idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ 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,
- comment ? 2 : 1, idp->data, idp->len,
- comment, comment ? strlen(comment) : 0);
- silc_buffer_free(idp);
+ 3, idp1->data, idp1->len,
+ comment, comment ? strlen(comment) : 0,
+ idp2->data, idp2->len);
+ silc_buffer_free(idp1);
+ silc_buffer_free(idp2);
}
/* Sends UMODE_CHANGE notify type. This tells that `client_id' client's
SilcSocketConnection sock,
bool broadcast,
SilcClientID *client_id,
- uint32 mode_mask)
+ SilcUInt32 mode_mask)
{
SilcBuffer idp;
unsigned char mode[4];
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,
+ SilcSocketConnection sock,
+ SilcClientEntry watcher,
+ SilcClientEntry client,
+ const char *nickname,
+ SilcNotifyType type)
+{
+ SilcBuffer idp;
+ 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);
+ silc_server_send_notify_dest(server, sock, FALSE, watcher->id,
+ SILC_ID_CLIENT, SILC_NOTIFY_TYPE_WATCH,
+ 4, idp->data, idp->len,
+ nickname, nickname ? strlen(nickname) : 0,
+ mode, sizeof(mode),
+ type != SILC_NOTIFY_TYPE_NONE ?
+ n : NULL, sizeof(n));
+ silc_buffer_free(idp);
+}
+
/* Sends notify message destined to specific entity. */
void silc_server_send_notify_dest(SilcServer server,
void *dest_id,
SilcIdType dest_id_type,
SilcNotifyType type,
- uint32 argc, ...)
+ SilcUInt32 argc, ...)
{
va_list ap;
SilcBuffer packet;
broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
dest_id, dest_id_type,
packet->data, packet->len, FALSE);
+
+ /* 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, packet->len, FALSE, TRUE);
+
silc_buffer_free(packet);
va_end(ap);
}
SilcChannelEntry channel,
bool route_notify,
SilcNotifyType type,
- uint32 argc, ...)
+ SilcUInt32 argc, ...)
{
va_list ap;
SilcBuffer packet;
SilcClientEntry sender,
SilcClientEntry client,
SilcNotifyType type,
- uint32 argc, ...)
+ SilcUInt32 argc, ...)
{
int k;
SilcSocketConnection sock = NULL;
SilcPacketContext packetdata;
SilcClientEntry c;
SilcClientEntry *sent_clients = NULL;
- uint32 sent_clients_count = 0;
+ SilcUInt32 sent_clients_count = 0;
SilcServerEntry *routed = NULL;
- uint32 routed_count = 0;
+ SilcUInt32 routed_count = 0;
SilcHashTableList htl, htl2;
SilcChannelEntry channel;
SilcChannelClientEntry chl, chl2;
SilcIDListData idata;
SilcBuffer packet;
unsigned char *data;
- uint32 data_len;
+ SilcUInt32 data_len;
bool force_send = FALSE;
va_list ap;
- SILC_LOG_DEBUG(("Start"));
-
- if (!silc_hash_table_count(client->channels))
+ 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);
packetdata.src_id_type = SILC_ID_SERVER;
silc_hash_table_list(client->channels, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
+ 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)) {
+ while (silc_hash_table_get(&htl2, NULL, (void **)&chl2)) {
c = chl2->client;
if (sender && c == sender)
sock = (SilcSocketConnection)c->connection;
idata = (SilcIDListData)c;
+ if (!sock)
+ continue;
+
packetdata.dst_id = silc_id_id2str(c->id, SILC_ID_CLIENT);
packetdata.dst_id_len = silc_id_get_len(c->id, SILC_ID_CLIENT);
packetdata.dst_id_type = SILC_ID_CLIENT;
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_free(packetdata.src_id);
SilcSocketConnection sock,
bool broadcast,
void *id, SilcIdType id_type,
- uint32 id_len)
+ SilcUInt32 id_len)
{
SilcBuffer idp;
- SILC_LOG_DEBUG(("Start"));
+ 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, idp->len, FALSE);
-
- /* Send to backup routers if this is being broadcasted to primary
- router. */
- if (server->router && server->router->connection &&
- sock == server->router->connection && broadcast)
- silc_server_backup_send(server, NULL, SILC_PACKET_NEW_ID, 0,
- idp->data, idp->len, FALSE, TRUE);
-
silc_buffer_free(idp);
}
/* Send New Channel Payload to notify about newly created channel in the
- SILC network. Normal server nevers sends this packet. Router uses this
- to notify other routers in the network about new channel. This packet
- is broadcasted. */
+ 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,
SilcSocketConnection sock,
bool broadcast,
char *channel_name,
void *channel_id,
- uint32 channel_id_len,
- uint32 mode)
+ SilcUInt32 channel_id_len,
+ SilcUInt32 mode)
{
SilcBuffer packet;
unsigned char *cid;
- uint32 name_len = strlen(channel_name);
+ SilcUInt32 name_len = strlen(channel_name);
- SILC_LOG_DEBUG(("Start"));
+ SILC_LOG_DEBUG(("Sending new channel"));
cid = silc_id_id2str(channel_id, SILC_ID_CHANNEL);
if (!cid)
broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
packet->data, packet->len, FALSE);
- /* Send to backup routers if this is being broadcasted to primary
- router. */
- if (server->router && server->router->connection &&
- sock == server->router->connection && broadcast)
- silc_server_backup_send(server, NULL, SILC_PACKET_NEW_CHANNEL, 0,
- packet->data, packet->len, FALSE, TRUE);
-
silc_free(cid);
silc_buffer_free(packet);
}
{
SilcBuffer packet;
unsigned char *chid;
- uint32 tmp_len;
+ SilcUInt32 tmp_len;
SILC_LOG_DEBUG(("Sending key to channel %s", channel->channel_name));
chid = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
if (!chid)
return;
+
+ if (!channel->channel_key)
+ return;
/* Encode channel key packet */
tmp_len = strlen(channel->channel_key->cipher->name);
void silc_server_send_command(SilcServer server,
SilcSocketConnection sock,
SilcCommand command,
- uint16 ident,
- uint32 argc, ...)
+ SilcUInt16 ident,
+ SilcUInt32 argc, ...)
{
SilcBuffer packet;
va_list ap;
void silc_server_send_command_reply(SilcServer server,
SilcSocketConnection sock,
SilcCommand command,
- SilcCommandStatus status,
- uint16 ident,
- uint32 argc, ...)
+ SilcStatus status,
+ SilcStatus error,
+ SilcUInt16 ident,
+ SilcUInt32 argc, ...)
{
SilcBuffer packet;
va_list ap;
va_start(ap, argc);
- packet = silc_command_reply_payload_encode_vap(command, status, ident,
- argc, ap);
+ 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, packet->len, TRUE);
silc_buffer_free(packet);
void *dst_id,
SilcIdType dst_id_type,
SilcCommand command,
- SilcCommandStatus status,
- uint16 ident,
- uint32 argc, ...)
+ SilcStatus status,
+ SilcStatus error,
+ SilcUInt16 ident,
+ SilcUInt32 argc, ...)
{
SilcBuffer packet;
va_list ap;
va_start(ap, argc);
- packet = silc_command_reply_payload_encode_vap(command, status, ident,
- argc, ap);
+ 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,
packet->len, TRUE);
SilcSocketConnection dst_sock,
SilcCipher cipher,
SilcHmac hmac,
- uint32 sequence,
+ SilcUInt32 sequence,
SilcPacketContext *packet,
bool force_send)
{
+ const SilcBufferStruct p;
+
silc_buffer_push(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
+ packet->dst_id_len + packet->padlen);
+ if (!silc_packet_send_prepare(dst_sock, 0, 0, packet->buffer->len, hmac,
+ (const SilcBuffer)&p)) {
+ SILC_LOG_ERROR(("Cannot send packet"));
+ return;
+ }
+ silc_buffer_put((SilcBuffer)&p, packet->buffer->data, packet->buffer->len);
- silc_packet_send_prepare(dst_sock, 0, 0, packet->buffer->len);
- silc_buffer_put(dst_sock->outbuf, packet->buffer->data, packet->buffer->len);
-
/* Re-encrypt packet */
- silc_packet_encrypt(cipher, hmac, sequence, dst_sock->outbuf,
- packet->buffer->len);
+ silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&p, p.len);
/* Send the packet */
silc_server_packet_send_real(server, dst_sock, force_send);
void silc_server_send_connection_auth_request(SilcServer server,
SilcSocketConnection sock,
- uint16 conn_type,
+ SilcUInt16 conn_type,
SilcAuthMethod auth_meth)
{
SilcBuffer packet;
if (sock && SILC_IS_OUTBUF_PENDING(sock) &&
(SILC_IS_DISCONNECTED(sock) == FALSE)) {
server->stat.packets_sent++;
-
- if (sock->outbuf->data - sock->outbuf->head)
- silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head);
-
silc_packet_send(sock, TRUE);
-
SILC_SET_CONNECTION_FOR_INPUT(server->schedule, sock->sock);
SILC_UNSET_OUTBUF_PENDING(sock);
silc_buffer_clear(sock->outbuf);
}
}
+
+/* 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,
+ bool route, bool local,
+ unsigned char *data,
+ SilcUInt32 data_len,
+ bool force_send)
+{
+ SilcIDCacheList list = NULL;
+ SilcIDCacheEntry id_cache = NULL;
+ SilcClientEntry client = NULL;
+ SilcSocketConnection sock;
+ SilcServerEntry *routed = NULL;
+ SilcUInt32 routed_count = 0;
+ bool 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) ||
+ !silc_idcache_list_first(list, &id_cache))
+ return;
+ while (id_cache) {
+ 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, force_send);
+ }
+
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ }
+ silc_idcache_list_free(list);
+ return;
+ }
+
+ if (!silc_idcache_get_all(server->local_list->clients, &list) ||
+ !silc_idcache_list_first(list, &id_cache))
+ return;
+ while (id_cache) {
+ client = (SilcClientEntry)id_cache->context;
+ if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) &&
+ !(client->mode & SILC_UMODE_ROUTER_OPERATOR))
+ goto next;
+
+ 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)
+ goto next;
+
+ /* Route only once to router */
+ sock = (SilcSocketConnection)client->router->connection;
+ if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+ if (gone)
+ goto next;
+ gone = TRUE;
+ }
+
+ /* Send the packet */
+ silc_server_packet_send_dest(server, sock, type, flags,
+ client->id, SILC_ID_CLIENT,
+ data, data_len, force_send);
+
+ /* Mark this route routed already */
+ routed = silc_realloc(routed, sizeof(*routed) * (routed_count + 1));
+ routed[routed_count++] = client->router;
+ goto next;
+ }
+
+ if (client->router || !client->connection)
+ goto next;
+
+ /* Send to locally connected client */
+ sock = (SilcSocketConnection)client->connection;
+ silc_server_packet_send_dest(server, sock, type, flags,
+ client->id, SILC_ID_CLIENT,
+ data, data_len, force_send);
+
+ next:
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ }
+ silc_idcache_list_free(list);
+
+ if (!silc_idcache_get_all(server->global_list->clients, &list) ||
+ !silc_idcache_list_first(list, &id_cache))
+ return;
+ while (id_cache) {
+ client = (SilcClientEntry)id_cache->context;
+ if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) &&
+ !(client->mode & SILC_UMODE_ROUTER_OPERATOR))
+ goto nextg;
+
+ 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)
+ goto nextg;
+
+ /* Route only once to router */
+ sock = (SilcSocketConnection)client->router->connection;
+ if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+ if (gone)
+ goto nextg;
+ gone = TRUE;
+ }
+
+ /* Send the packet */
+ silc_server_packet_send_dest(server, sock, type, flags,
+ client->id, SILC_ID_CLIENT,
+ data, data_len, force_send);
+
+ /* Mark this route routed already */
+ routed = silc_realloc(routed, sizeof(*routed) * (routed_count + 1));
+ routed[routed_count++] = client->router;
+ goto nextg;
+ }
+
+ if (client->router || !client->connection)
+ goto nextg;
+
+ /* Send to locally connected client */
+ sock = (SilcSocketConnection)client->connection;
+ silc_server_packet_send_dest(server, sock, type, flags,
+ client->id, SILC_ID_CLIENT,
+ data, data_len, force_send);
+
+ nextg:
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ }
+ silc_idcache_list_free(list);
+ silc_free(routed);
+}
+
+/* Send a notify packet to operators */
+
+void silc_server_send_opers_notify(SilcServer server,
+ bool route,
+ bool 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, packet->len,
+ FALSE);
+ silc_buffer_free(packet);
+ va_end(ap);
+}