packet_send.c
- Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+ Author: Pekka Riikonen <priikone@silcnet.org>
Copyright (C) 1997 - 2001 Pekka Riikonen
int silc_server_packet_send_real(SilcServer server,
SilcSocketConnection sock,
- int force_send)
+ bool force_send)
{
int ret;
+ /* If disconnecting, ignore the data */
+ if (SILC_IS_DISCONNECTING(sock))
+ return -1;
+
/* If rekey protocol is active we must assure that all packets are
sent through packet queue. */
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)
This call sets the connection both for input and output (the input
is set always and this call keeps the input setting, actually).
Actual data sending is performed by silc_server_packet_process. */
- SILC_SET_CONNECTION_FOR_OUTPUT(sock->sock);
+ SILC_SET_CONNECTION_FOR_OUTPUT(server->schedule, sock->sock);
/* Mark to socket that data is pending in outgoing buffer. This flag
is needed if new data is added to the buffer before the earlier
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 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)
+ return;
+
/* Get data used in the packet sending, keys and stuff */
switch(sock->type) {
case SILC_SOCKET_TYPE_CLIENT:
- dst_id = ((SilcClientEntry)sock->user_data)->id;
- dst_id_type = SILC_ID_CLIENT;
+ if (sock->user_data) {
+ dst_id = ((SilcClientEntry)sock->user_data)->id;
+ dst_id_type = SILC_ID_CLIENT;
+ }
break;
case SILC_SOCKET_TYPE_SERVER:
case SILC_SOCKET_TYPE_ROUTER:
- dst_id = ((SilcServerEntry)sock->user_data)->id;
- dst_id_type = SILC_ID_SERVER;
+ if (sock->user_data) {
+ dst_id = ((SilcServerEntry)sock->user_data)->id;
+ dst_id_type = SILC_ID_SERVER;
+ }
break;
default:
break;
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;
uint32 dst_id_len = 0;
- SILC_LOG_DEBUG(("Sending packet, type %d", type));
+ /* If disconnecting, ignore the data */
+ if (SILC_IS_DISCONNECTING(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)
+ return;
+
+ SILC_LOG_DEBUG(("Sending packet, type %d", type));
if (dst_id) {
dst_id_data = silc_id_id2str(dst_id, dst_id_type);
- dst_id_len = silc_id_get_len(dst_id_type);
+ dst_id_len = silc_id_get_len(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_SERVER_LEN;
+ packetdata.src_id_len = silc_id_get_len(server->id, server->id_type);
packetdata.src_id_type = server->id_type;
packetdata.dst_id = dst_id_data;
packetdata.dst_id_len = dst_id_len;
SilcIdType dst_id_type,
unsigned char *data,
uint32 data_len,
- int force_send)
+ bool force_send)
{
SilcPacketContext packetdata;
SilcIDListData idata;
if (dst_id) {
dst_id_data = silc_id_id2str(dst_id, dst_id_type);
- dst_id_len = silc_id_get_len(dst_id_type);
+ dst_id_len = silc_id_get_len(dst_id, dst_id_type);
}
if (src_id) {
src_id_data = silc_id_id2str(src_id, src_id_type);
- src_id_len = silc_id_get_len(src_id_type);
+ src_id_len = silc_id_get_len(src_id, src_id_type);
}
/* Set the packet context pointers */
/* 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)) {
+ if (id && !SILC_ID_SERVER_COMPARE(id, server->router->id)) {
idata = (SilcIDListData)sock->user_data;
silc_buffer_push(buffer, buffer->data - buffer->head);
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;
SilcClientEntry client = NULL;
SilcServerEntry *routed = NULL;
SilcChannelClientEntry chl;
+ SilcHashTableList htl;
SilcIDListData idata;
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"));
packetdata.flags = 0;
packetdata.type = type;
packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER);
- packetdata.src_id_len = SILC_ID_SERVER_LEN;
+ packetdata.src_id_len = silc_id_get_len(server->id, SILC_ID_SERVER);
packetdata.src_id_type = SILC_ID_SERVER;
packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
- packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
+ packetdata.dst_id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
packetdata.dst_id_type = SILC_ID_CHANNEL;
packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
packetdata.src_id_len + packetdata.dst_id_len;
/* 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;
}
/* Send the message to clients on the channel's client list. */
- silc_list_start(channel->user_list);
- while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
client = chl->client;
/* If client has router set it is not locally connected client and
silc_free(packetdata.dst_id);
}
+/* 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 bool
+silc_server_packet_relay_to_channel_encrypt(SilcServer server,
+ SilcSocketConnection sock,
+ SilcChannelEntry channel,
+ unsigned char *data,
+ unsigned int data_len)
+{
+ /* 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 &&
+ 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);
+
+ 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.
Packets sent with this function we have received earlier and are
totally encrypted. This just sends the packet to all clients on
SilcChannelEntry channel,
void *sender,
SilcIdType sender_type,
+ void *sender_entry,
unsigned char *data,
uint32 data_len,
- int force_send)
+ bool force_send)
{
- int found = FALSE;
+ bool found = FALSE;
SilcSocketConnection sock = NULL;
SilcPacketContext packetdata;
SilcClientEntry client = NULL;
SilcChannelClientEntry chl;
uint32 routed_count = 0;
SilcIDListData idata;
+ SilcHashTableList htl;
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 = silc_id_id2str(sender, sender_type);
- packetdata.src_id_len = silc_id_get_len(sender_type);
+ packetdata.src_id_len = silc_id_get_len(sender, 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_CHANNEL_LEN;
+ packetdata.dst_id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
packetdata.dst_id_type = SILC_ID_CHANNEL;
packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
packetdata.src_id_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;
}
/* Send the message to clients on the channel's client list. */
- silc_list_start(channel->user_list);
- while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
client = chl->client;
if (client) {
/* If sender is one on the channel do not send it the packet. */
- if (!found && !SILC_ID_CLIENT_COMPARE(client->id, sender)) {
+ if (!found && sender_type == SILC_ID_CLIENT &&
+ SILC_ID_CLIENT_COMPARE(client->id, sender)) {
found = TRUE;
continue;
}
/* 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)) {
+ if (!found && SILC_ID_SERVER_COMPARE(client->router->id, sender)) {
found = TRUE;
continue;
}
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
+ socket. */
+ if (sender_entry &&
+ ((SilcClientEntry)sender_entry)->router == client->router)
+ continue;
if (sender_sock && sock == sender_sock)
continue;
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 */
memcpy(tmp, data, data_len);
/* Decrypt the channel message (we don't check the MAC) */
- if (!silc_channel_message_payload_decrypt(tmp, data_len,
+ if (channel->channel_key &&
+ !silc_channel_message_payload_decrypt(tmp, data_len,
channel->channel_key,
NULL)) {
memset(tmp, 0, data_len);
}
continue;
}
-
+
/* Send the packet (to normal server) */
silc_server_packet_send_to_channel_real(server, sock, &packetdata,
idata->send_key,
SilcPacketFlags flags,
unsigned char *data,
uint32 data_len,
- int force_send)
+ bool force_send)
{
SilcChannelClientEntry chl;
+ SilcHashTableList htl;
SilcSocketConnection sock = NULL;
SILC_LOG_DEBUG(("Start"));
/* Send the message to clients on the channel's client list. */
- silc_list_start(channel->user_list);
- while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
if (chl->client && !chl->client->router) {
sock = (SilcSocketConnection)chl->client->connection;
SilcBuffer buffer = packet->buffer;
/* Re-encrypt and send if private messge key does not exist */
- if ((packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY) == FALSE) {
+ 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);
va_start(ap, argc);
packet = silc_notify_payload_encode(type, argc, ap);
- silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 0,
+ 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);
}
/* Sends notify message and gets the arguments from the `args' Argument
SilcBuffer packet;
packet = silc_notify_payload_encode_args(type, argc, args);
- silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 0,
+ silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY,
+ broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
packet->data, packet->len, FALSE);
silc_buffer_free(packet);
}
SilcSocketConnection sock,
int broadcast,
SilcChannelID *old_id,
- SilcChannelID *new_id,
- uint32 id_len)
+ SilcChannelID *new_id)
{
SilcBuffer idp1, idp2;
SilcSocketConnection sock,
int broadcast,
SilcClientID *old_id,
- SilcClientID *new_id,
- uint32 id_len)
+ SilcClientID *new_id)
{
SilcBuffer idp1, idp2;
SilcSocketConnection sock,
int broadcast,
SilcChannelEntry channel,
- SilcClientID *client_id,
- uint32 client_id_len)
+ SilcClientID *client_id)
{
SilcBuffer idp1, idp2;
SilcSocketConnection sock,
int broadcast,
SilcChannelEntry channel,
- SilcClientID *client_id,
- uint32 client_id_len)
+ SilcClientID *client_id)
{
SilcBuffer idp;
SilcChannelEntry channel,
uint32 mode_mask,
void *id, SilcIdType id_type,
- uint32 id_len,
char *cipher, char *hmac)
{
SilcBuffer idp;
int broadcast,
SilcChannelEntry channel,
uint32 mode_mask,
- SilcClientID *client_id,
- uint32 client_id_len,
- SilcClientID *target,
- uint32 target_len)
+ void *id, SilcIdType id_type,
+ SilcClientID *target)
{
SilcBuffer idp1, idp2;
unsigned char mode[4];
- idp1 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ 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);
SilcSocketConnection sock,
int broadcast,
SilcClientID *client_id,
- uint32 client_id_len,
char *message)
{
SilcBuffer idp;
int broadcast,
SilcChannelEntry channel,
SilcClientID *client_id,
- uint32 client_id_len,
char *topic)
{
SilcBuffer idp;
int broadcast,
SilcChannelEntry channel,
SilcClientID *client_id,
- uint32 client_id_len,
char *comment)
{
SilcBuffer idp;
SilcSocketConnection sock,
int broadcast,
SilcClientID *client_id,
- uint32 client_id_len,
char *comment)
{
SilcBuffer idp;
SilcSocketConnection sock,
int broadcast,
SilcClientID *client_id,
- uint32 client_id_len,
uint32 mode_mask)
{
SilcBuffer idp;
int broadcast,
SilcChannelEntry channel,
SilcClientID *client_id,
- uint32 client_id_len,
char *add, char *del)
{
SilcBuffer idp, idp2;
dest_id, dest_id_type,
packet->data, packet->len, FALSE);
silc_buffer_free(packet);
+ va_end(ap);
}
/* Sends notify message to a channel. The notify message sent is
SILC_PACKET_NOTIFY, route_notify,
packet->data, packet->len, FALSE);
silc_buffer_free(packet);
+ va_end(ap);
}
/* Send notify message to all channels the client has joined. It is quaranteed
uint32 sent_clients_count = 0;
SilcServerEntry *routed = NULL;
uint32 routed_count = 0;
+ SilcHashTableList htl, htl2;
SilcChannelEntry channel;
SilcChannelClientEntry chl, chl2;
SilcIDListData idata;
SilcBuffer packet;
unsigned char *data;
uint32 data_len;
- int force_send = FALSE;
+ bool force_send = FALSE;
va_list ap;
SILC_LOG_DEBUG(("Start"));
- if (!silc_list_count(client->channels))
+ if (!silc_hash_table_count(client->channels))
return;
va_start(ap, argc);
packetdata.flags = 0;
packetdata.type = SILC_PACKET_NOTIFY;
packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER);
- packetdata.src_id_len = SILC_ID_SERVER_LEN;
+ packetdata.src_id_len = silc_id_get_len(server->id, SILC_ID_SERVER);
packetdata.src_id_type = SILC_ID_SERVER;
- silc_list_start(client->channels);
- while ((chl = silc_list_get(client->channels)) != SILC_LIST_END) {
+ 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_list_start(channel->user_list);
- while ((chl2 = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ silc_hash_table_list(channel->user_list, &htl2);
+ while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) {
c = chl2->client;
if (sender && c == sender)
idata = (SilcIDListData)c->router;
packetdata.dst_id = silc_id_id2str(c->router->id, SILC_ID_SERVER);
- packetdata.dst_id_len = SILC_ID_SERVER_LEN;
+ packetdata.dst_id_len = silc_id_get_len(c->router->id, SILC_ID_SERVER);
packetdata.dst_id_type = SILC_ID_SERVER;
packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
packetdata.src_id_len + packetdata.dst_id_len;
idata = (SilcIDListData)c;
packetdata.dst_id = silc_id_id2str(c->id, SILC_ID_CLIENT);
- packetdata.dst_id_len = SILC_ID_CLIENT_LEN;
+ packetdata.dst_id_len = silc_id_get_len(c->id, SILC_ID_CLIENT);
packetdata.dst_id_type = SILC_ID_CLIENT;
packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
packetdata.src_id_len + packetdata.dst_id_len;
if (sent_clients_count)
silc_free(sent_clients);
silc_free(packetdata.src_id);
+ va_end(ap);
}
/* Sends New ID Payload to remote end. The packet is used to distribute
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);
}
/* Encode channel key packet */
tmp_len = strlen(channel->channel_key->cipher->name);
- packet = silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN, chid, tmp_len,
+ packet = silc_channel_key_payload_encode(silc_id_get_len(channel->id,
+ SILC_ID_CHANNEL),
+ 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);
void silc_server_send_command(SilcServer server,
SilcSocketConnection sock,
SilcCommand command,
+ uint16 ident,
uint32 argc, ...)
{
SilcBuffer packet;
va_start(ap, argc);
- packet = silc_command_payload_encode_vap(command, 0, argc, ap);
+ packet = silc_command_payload_encode_vap(command, ident, argc, ap);
silc_server_packet_send(server, sock, SILC_PACKET_COMMAND, 0,
packet->data, packet->len, TRUE);
silc_buffer_free(packet);
+ va_end(ap);
}
/* Send the heartbeat packet. */
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);
+ }
+}