int silc_server_packet_send_real(SilcServer server,
SilcSocketConnection sock,
- int force_send)
+ bool force_send)
{
int ret;
if (SILC_SERVER_IS_REKEY(sock))
force_send = FALSE;
+ /* If outbound data is already pending do not force send */
+ if (SILC_IS_OUTBUF_PENDING(sock))
+ force_send = FALSE;
+
/* Send the packet */
ret = silc_packet_send(sock, force_send);
if (ret != -2)
SilcPacketFlags flags,
unsigned char *data,
uint32 data_len,
- int force_send)
+ bool force_send)
{
void *dst_id = NULL;
SilcIdType dst_id_type = SILC_ID_NONE;
+ SilcIDListData idata = (SilcIDListData)sock->user_data;
if (!sock)
return;
if (SILC_IS_DISCONNECTING(sock))
return;
+ /* If entry is disabled do not sent anything. */
+ if (idata && idata->status & SILC_IDLIST_STATUS_DISABLED)
+ return;
+
/* Get data used in the packet sending, keys and stuff */
switch(sock->type) {
case SILC_SOCKET_TYPE_CLIENT:
SilcIdType dst_id_type,
unsigned char *data,
uint32 data_len,
- int force_send)
+ bool force_send)
{
SilcPacketContext packetdata;
- SilcIDListData idata;
+ SilcIDListData idata = (SilcIDListData)sock->user_data;
SilcCipher cipher = NULL;
SilcHmac hmac = NULL;
unsigned char *dst_id_data = NULL;
if (SILC_IS_DISCONNECTING(sock))
return;
- SILC_LOG_DEBUG(("Sending packet, type %d", type));
+ /* If entry is disabled do not sent anything. */
+ if (idata && idata->status & SILC_IDLIST_STATUS_DISABLED)
+ return;
- /* Get data used in the packet sending, keys and stuff */
- idata = (SilcIDListData)sock->user_data;
+ SILC_LOG_DEBUG(("Sending packet, type %d", type));
if (dst_id) {
dst_id_data = silc_id_id2str(dst_id, dst_id_type);
SilcIdType dst_id_type,
unsigned char *data,
uint32 data_len,
- int force_send)
+ bool force_send)
{
SilcPacketContext packetdata;
SilcIDListData idata;
unsigned char *data,
uint32 data_len,
int channel_message,
- int force_send)
+ bool force_send)
{
packet->truelen = data_len + SILC_PACKET_HEADER_LEN +
packet->src_id_len + packet->dst_id_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. */
+ 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);
if (channel_message)
SilcSocketConnection sender,
SilcChannelEntry channel,
SilcPacketType type,
- unsigned char route,
+ bool route,
unsigned char *data,
uint32 data_len,
- int force_send)
+ bool force_send)
{
SilcSocketConnection sock = NULL;
SilcPacketContext packetdata;
uint32 routed_count = 0;
/* This doesn't send channel message packets */
- if (type == SILC_PACKET_CHANNEL_MESSAGE)
- return;
+ assert(type != SILC_PACKET_CHANNEL_MESSAGE);
SILC_LOG_DEBUG(("Sending packet to channel"));
/* 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_SERVER && !server->standalone &&
+ if (route && server->server_type != SILC_ROUTER && !server->standalone &&
channel->global_users) {
SilcServerEntry router;
then we'll need to encrypt it with the channel key. This is called
from the silc_server_packet_relay_to_channel. */
-static void
+static bool
silc_server_packet_relay_to_channel_encrypt(SilcServer server,
SilcSocketConnection sock,
SilcChannelEntry channel,
channel->channel_key) {
SilcBuffer chp;
uint32 iv_len, i;
- uint16 data_len, flags;
+ uint16 dlen, flags;
iv_len = silc_cipher_get_block_len(channel->channel_key);
if (channel->iv[0] == '\0')
/* Encode new payload. This encrypts it also. */
SILC_GET16_MSB(flags, data);
- SILC_GET16_MSB(data_len, data + 2);
- chp = silc_channel_message_payload_encode(flags, data_len,
- data + 4,
+ SILC_GET16_MSB(dlen, data + 2);
+
+ if (dlen > data_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);
}
+
+ return TRUE;
}
/* This routine is explicitly used to relay messages to some channel.
void *sender_entry,
unsigned char *data,
uint32 data_len,
- int force_send)
+ bool force_send)
{
bool found = FALSE;
SilcSocketConnection sock = NULL;
SILC_LOG_DEBUG(("Relaying packet to channel"));
+ /* This encrypts the packet, 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;
+
/* Set the packet context pointers. */
packetdata.flags = 0;
packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
packetdata.src_id_len +
packetdata.dst_id_len));
- /* This encrypts the packet, 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. */
- silc_server_packet_relay_to_channel_encrypt(server, sender_sock,
- channel, data,
- data_len);
-
/* 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_SERVER && !server->standalone &&
+ if (server->server_type != SILC_ROUTER && !server->standalone &&
channel->global_users) {
SilcServerEntry router;
channel keys are cell specific and we have different channel
key than the remote router has. */
if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
+ 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 */
SilcPacketFlags flags,
unsigned char *data,
uint32 data_len,
- int force_send)
+ bool force_send)
{
SilcChannelClientEntry chl;
SilcHashTableList htl;
silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY,
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_NOTIFY, 0,
+ packet->data, packet->len, FALSE, TRUE);
+
silc_buffer_free(packet);
va_end(ap);
}
SilcBuffer packet;
unsigned char *data;
uint32 data_len;
- int force_send = FALSE;
+ bool force_send = FALSE;
va_list ap;
SILC_LOG_DEBUG(("Start"));
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);
}
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);
}
chid, tmp_len,
channel->channel_key->cipher->name,
channel->key_len / 8, channel->key);
-
silc_server_packet_send_to_channel(server, sender, channel,
SILC_PACKET_CHANNEL_KEY,
route, packet->data, packet->len, FALSE);
SilcCipher cipher,
SilcHmac hmac,
SilcPacketContext *packet,
- int force_send)
+ bool force_send)
{
silc_buffer_push(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
+ packet->dst_id_len + packet->padlen);
0, packet->data, packet->len, FALSE);
silc_buffer_free(packet);
}
+
+/* Purge the outgoing packet queue to the network if there is data. This
+ function can be used to empty the packet queue. It is guaranteed that
+ after this function returns the outgoing data queue is empty. */
+
+void silc_server_packet_queue_purge(SilcServer server,
+ SilcSocketConnection sock)
+{
+ 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);
+ }
+}