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
/* 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
if (idata && idata->status & SILC_IDLIST_STATUS_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;
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)));
/* Get data used in the packet sending, keys and stuff */
idata = (SilcIDListData)sock->user_data;
clients (for server locally connected, and for router local cell). */
void silc_server_packet_send_clients(SilcServer server,
- SilcClientEntry *clients,
- SilcUInt32 clients_count,
+ SilcHashTable clients,
SilcPacketType type,
SilcPacketFlags flags,
bool route,
bool force_send)
{
SilcSocketConnection sock = NULL;
+ SilcHashTableList htl;
SilcClientEntry client = NULL;
SilcServerEntry *routed = NULL;
SilcUInt32 routed_count = 0;
bool gone = FALSE;
- int i, k;
+ int k;
SILC_LOG_DEBUG(("Sending packet to list of clients"));
/* Send to all clients in table */
- for (i = 0; i < clients_count; i++) {
- client = clients[i];
-
+ 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);
}
/* 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;
channel->channel_key) {
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 (data_len <= mac_len + iv_len) {
SILC_LOG_WARNING(("Corrupted channel message, cannot relay it"));
return FALSE;
}
- memcpy(channel->iv, data + (data_len - iv_len), iv_len);
+ memcpy(iv, data + (data_len - iv_len), iv_len);
silc_channel_message_payload_encrypt(data, data_len - iv_len - mac_len,
- data_len, channel->iv, iv_len,
+ data_len, iv, iv_len,
channel->channel_key, channel->hmac);
}
SilcPacketContext packetdata;
SilcClientEntry client = NULL;
SilcServerEntry *routed = NULL;
- SilcChannelClientEntry chl;
+ SilcChannelClientEntry chl, chl_sender;
SilcUInt32 routed_count = 0;
SilcIDListData idata;
SilcHashTableList htl;
SILC_LOG_DEBUG(("Relaying packet to channel"));
+ if (!silc_server_client_on_channel(sender_entry, channel, &chl_sender))
+ return;
+
/* 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
/* 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;
+ /* 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) {
/* 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;
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);
}
SilcChannelEntry channel,
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. */
SilcChannelEntry channel,
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
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,
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)
{
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);
}
unsigned char *cid;
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->server_type == SILC_ROUTER &&
- 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);
}
void silc_server_send_command_reply(SilcServer server,
SilcSocketConnection sock,
SilcCommand command,
- SilcCommandStatus status,
+ SilcStatus status,
+ SilcStatus error,
SilcUInt16 ident,
SilcUInt32 argc, ...)
{
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,
+ SilcStatus status,
+ SilcStatus error,
SilcUInt16 ident,
SilcUInt32 argc, ...)
{
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);
return;
}
silc_buffer_put((SilcBuffer)&p, packet->buffer->data, packet->buffer->len);
-
+
/* Re-encrypt packet */
- silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&p,
- 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);