Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2003 Pekka Riikonen
+ Copyright (C) 1997 - 2005 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
int ret;
/* If disconnecting, ignore the data */
- if (SILC_IS_DISCONNECTING(sock))
+ if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock))
return -1;
/* Send the packet */
ret = silc_packet_send(sock, FALSE);
if (ret != -2) {
if (ret == -1) {
+ SILC_SET_CONNECTION_FOR_INPUT(server->schedule, sock->sock);
+ SILC_UNSET_OUTBUF_PENDING(sock);
+ silc_buffer_clear(sock->outbuf);
+
SILC_LOG_ERROR(("Error sending packet to connection "
"%s:%d [%s]", sock->hostname, sock->port,
(sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
"Router")));
- if (sock->user_data)
+ if (sock->user_data) {
+ /* If backup then mark that resuming will not be allowed */
+ if (server->server_type == SILC_ROUTER && !server->backup_router &&
+ sock->type == SILC_SOCKET_TYPE_SERVER) {
+ SilcServerEntry server_entry = sock->user_data;
+ if (server_entry->server_type == SILC_BACKUP_ROUTER)
+ server->backup_closed = TRUE;
+ }
+
silc_server_free_sock_user_data(server, sock, NULL);
+ }
SILC_SET_DISCONNECTING(sock);
silc_server_close_connection(server, sock);
return ret;
idata = (SilcIDListData)sock->user_data;
/* If disconnecting, ignore the data */
- if (SILC_IS_DISCONNECTING(sock))
+ if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock))
return;
/* 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) ||
+ type != SILC_PACKET_REKEY_DONE && type != SILC_PACKET_KEY_EXCHANGE_1
+ && type != SILC_PACKET_KEY_EXCHANGE_2) ||
(sock->user_data == server->id_entry)) {
SILC_LOG_DEBUG(("Connection is disabled"));
return;
int block_len = 0;
/* If disconnecting, ignore the data */
- if (!sock || SILC_IS_DISCONNECTING(sock))
+ if (!sock || SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock))
return;
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) {
+ /* 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 && type != SILC_PACKET_KEY_EXCHANGE_1
+ && type != SILC_PACKET_KEY_EXCHANGE_2) ||
+ (sock->user_data == server->id_entry)) {
SILC_LOG_DEBUG(("Connection is disabled"));
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) {
+ /* 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 && type != SILC_PACKET_KEY_EXCHANGE_1
+ && type != SILC_PACKET_KEY_EXCHANGE_2) ||
+ (sock->user_data == server->id_entry)) {
SILC_LOG_DEBUG(("Connection is disabled"));
return;
}
/* Send to all clients in table */
silc_hash_table_list(clients, &htl);
- while (silc_hash_table_get(&htl, NULL, (void **)&client)) {
+ 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 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;
{
SilcUInt32 mac_len, iv_len;
unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
+ SilcUInt16 totlen, 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
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);
- silc_message_payload_encrypt(data, data_len - iv_len, data_len,
- iv, iv_len, channel->channel_key,
+ silc_message_payload_encrypt(data, totlen, data_len - mac_len,
+ iv, iv_len, channel->channel_key,
channel->hmac);
}
/* 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 || client == sender_entry)
continue;
/* 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 && SILC_IS_LOCAL(chl->client)) {
sock = chl->client->connection;
SilcBuffer channel_pubkeys)
{
SilcBuffer idp, fkey = NULL;
- unsigned char mode[4];
+ 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_pkcs_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,
- 7, idp->data, idp->len,
+ 8, idp->data, idp->len,
mode, 4,
cipher, cipher ? strlen(cipher) : 0,
hmac, hmac ? strlen(hmac) : 0,
strlen(passphrase) : 0,
fkey ? fkey->data : NULL, fkey ? fkey->len : 0,
channel_pubkeys ? channel_pubkeys->data : NULL,
- channel_pubkeys ? channel_pubkeys->len : 0);
+ channel_pubkeys ? channel_pubkeys->len : 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);
}
SilcClientEntry watcher,
SilcClientEntry client,
const char *nickname,
- SilcNotifyType type)
+ SilcNotifyType type,
+ SilcPublicKey public_key)
{
- SilcBuffer idp;
+ 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_pkcs_public_key_payload_encode(public_key);
silc_server_send_notify_dest(server, sock, FALSE, watcher->id,
SILC_ID_CLIENT, SILC_NOTIFY_TYPE_WATCH,
- 4, idp->data, idp->len,
+ 5, idp->data, idp->len,
nickname, nickname ? strlen(nickname) : 0,
mode, sizeof(mode),
type != SILC_NOTIFY_TYPE_NONE ?
- n : NULL, sizeof(n));
+ n : NULL, sizeof(n),
+ pkp ? pkp->data : NULL,
+ pkp ? pkp->len : 0);
silc_buffer_free(idp);
+ silc_buffer_free(pkp);
}
/* Sends notify message destined to specific entity. */
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)
}
/* 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. */
+ function can be used to empty the packet queue. */
void silc_server_packet_queue_purge(SilcServer server,
SilcSocketConnection sock)
{
if (sock && SILC_IS_OUTBUF_PENDING(sock) &&
!(SILC_IS_DISCONNECTING(sock)) && !(SILC_IS_DISCONNECTED(sock))) {
+ int ret;
+
SILC_LOG_DEBUG(("Purging outgoing queue"));
+
server->stat.packets_sent++;
- silc_packet_send(sock, TRUE);
- SILC_UNSET_OUTBUF_PENDING(sock);
+ ret = silc_packet_send(sock, TRUE);
+ if (ret == -2) {
+ if (sock->outbuf && sock->outbuf->len > 0) {
+ /* Couldn't send all data, put the queue back up, we'll send
+ rest later. */
+ SILC_LOG_DEBUG(("Could not purge immediately, sending rest later"));
+ SILC_SET_CONNECTION_FOR_OUTPUT(server->schedule, sock->sock);
+ SILC_SET_OUTBUF_PENDING(sock);
+ return;
+ }
+ } else if (ret == -1) {
+ SILC_LOG_ERROR(("Error purging packet queue, packets dropped"));
+ }
+
+ /* Purged all data */
SILC_SET_CONNECTION_FOR_INPUT(server->schedule, sock->sock);
+ SILC_UNSET_OUTBUF_PENDING(sock);
silc_buffer_clear(sock->outbuf);
}
}