/*
* $Id$
* $Log$
- * Revision 1.1 2000/06/27 11:36:56 priikone
- * Initial revision
+ * Revision 1.2 2000/07/03 05:51:29 priikone
+ * Added remove_from_one_channel to implement LEAVE command.
+ *
+ * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
+ * Importet from internal CVS/Added Log headers.
*
*
*/
return;
}
+ SILC_LOG_INFO(("Incoming connection from %s (%s)", newsocket->hostname,
+ newsocket->ip));
+
/* Allocate internal context for key exchange protocol. This is
sent as context for the protocol. */
proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
SILC_LOG_DEBUG(("Remote host is client"));
+ SILC_LOG_INFO(("Connection from %s (%s) is client", sock->hostname,
+ sock->ip));
+
/* Add the client to the client ID list. We have not created the
client ID for the client yet. This is done when client registers
itself by sending NEW_CLIENT packet. */
sock->type == SILC_SOCKET_TYPE_SERVER ?
"server" : "router"));
+ SILC_LOG_INFO(("Connection from %s (%s) is %s", sock->hostname,
+ sock->ip, sock->type == SILC_SOCKET_TYPE_SERVER ?
+ "server" : "router"));
+
/* Add the server to the ID list. We don't have the server's ID
yet but we will receive it after the server sends NEW_SERVER
packet to us. */
}
/* If the client has set router it means that it is not locally
- connected client and we won't send message to those in this
- function (they will be routed separately by the caller). */
+ connected client and we will route the packet further. */
if (server->server_type == SILC_ROUTER && client->router) {
int k;
/* XXX Check client's mode on the channel. */
-
/* Get data used in packet header encryption, keys and stuff. */
sock = (SilcSocketConnection)client->connection;
cipher = client->send_key;
silc_free(packetdata.dst_id);
}
+/* This function is used to send packets strictly to all local clients
+ on a particular channel. This is used for example to distribute new
+ channel key to all our locally connected clients on the channel.
+ The packets are always encrypted with the session key shared between
+ the client. */
+
+void silc_server_packet_send_local_channel(SilcServer server,
+ SilcChannelList *channel,
+ SilcPacketType type,
+ SilcPacketFlags flags,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send)
+{
+ int i;
+ SilcClientList *client;
+ SilcSocketConnection sock = NULL;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Send the message to clients on the channel's client list. */
+ for (i = 0; i < channel->user_list_count; i++) {
+ client = channel->user_list[i].client;
+
+ if (client) {
+ sock = (SilcSocketConnection)client->connection;
+
+ /* Send the packet to the client */
+ silc_server_packet_send_dest(server, sock, type, flags, client->id,
+ SILC_ID_CLIENT, data, data_len,
+ force_send);
+ }
+ }
+}
+
/* Relays received command reply packet to the correct destination. The
destination must be one of our locally connected client or the packet
will be ignored. This is called when server has forwarded one of
channel->user_list[k].client = NULL;
channel->user_list[k].mode = SILC_CHANNEL_UMODE_NONE;
- /* XXX */
/* Send notify to channel about client leaving SILC and thus
the entire channel. */
silc_server_send_notify_to_channel(server, channel,
- "%s has left channel %s",
- client->nickname,
- channel->channel_name);
+ "Signoff: %s",
+ client->nickname);
}
}
}
#undef LCCC
}
+/* Removes client from one channel. This is used for example when client
+ calls LEAVE command to remove itself from the channel. Returns TRUE
+ if channel still exists and FALSE if the channel is removed when
+ last client leaves the channel. */
+
+int silc_server_remove_from_one_channel(SilcServer server,
+ SilcSocketConnection sock,
+ SilcChannelList *channel,
+ SilcClientList *client)
+{
+ int i, k;
+ SilcChannelList *ch;
+
+#define LCC(x) server->local_list->channel_cache[(x) - 32]
+#define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
+
+ /* Remove the client from the channel. The client is removed from
+ the channel's user list. */
+ for (i = 0; i < client->channel_count; i++) {
+ ch = client->channel[i];
+ if (!ch || ch != channel)
+ continue;
+
+ /* XXX */
+ client->channel[i] = NULL;
+
+ /* Remove from channel */
+ for (k = 0; k < channel->user_list_count; k++) {
+ if (channel->user_list[k].client == client) {
+
+ /* If this client is last one on the channel the channel
+ is removed all together. */
+ if (channel->user_list_count == 1) {
+ silc_idcache_del_by_id(LCC(channel->channel_name[0]),
+ LCCC(channel->channel_name[0]),
+ SILC_ID_CHANNEL, channel->id);
+ silc_idlist_del_channel(&server->local_list->channels, channel);
+ return FALSE;
+ }
+
+ channel->user_list[k].client = NULL;
+ channel->user_list[k].mode = SILC_CHANNEL_UMODE_NONE;
+
+ /* Send notify to channel about client leaving the channel */
+ silc_server_send_notify_to_channel(server, channel,
+ "%s has left channel %s",
+ client->nickname,
+ channel->channel_name);
+ }
+ }
+ }
+
+ return TRUE;
+#undef LCC
+#undef LCCC
+}
+
/* Timeout callback. This is called if connection is idle or for some
other reason is not responding within some period of time. This
disconnects the remote end. */
SilcPacketContext *packet)
{
SilcChannelList *channel = NULL;
+ SilcClientList *client = NULL;
SilcChannelID *id = NULL;
- SilcClientID *sender;
+ SilcClientID *sender = NULL;
SilcBuffer buffer = packet->buffer;
+ int i;
SILC_LOG_DEBUG(("Processing channel message"));
goto out;
}
- /* Send to local clients */
+ /* Find channel entry */
id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
channel = silc_find_channel(server, id);
if (!channel) {
goto out;
}
+ /* See that this client is on the channel */
+ sender = silc_id_str2id(packet->src_id, packet->src_id_type);
+ for (i = 0; i < channel->user_list_count; i++) {
+ client = channel->user_list[i].client;
+ if (client && !SILC_ID_CLIENT_COMPARE(client->id, sender))
+ break;
+ }
+ if (i >= channel->user_list_count)
+ goto out;
+
/* Distribute the packet to our local clients. This will send the
packet for further routing as well, if needed. */
- sender = silc_id_str2id(packet->src_id, packet->src_id_type);
silc_server_packet_relay_to_channel(server, sock, channel, sender,
packet->src_id_type,
packet->buffer->data,
packet->buffer->len, FALSE);
out:
+ if (sender)
+ silc_free(sender);
+ if (id)
+ silc_free(id);
silc_buffer_free(buffer);
}
/* Received channel key packet. We distribute the key to all of our locally
- connected clients on the channel. Router ignores the packet. */
+ connected clients on the channel. */
+/* XXX Router must accept this packet and distribute the key to all its
+ server that has clients on the channel */
void silc_server_channel_key(SilcServer server,
SilcSocketConnection sock,
char *cipher;
int i;
- if (server->server_type == SILC_ROUTER)
- goto out;
-
if (packet->src_id_type != SILC_ID_SERVER &&
sock->type != SILC_SOCKET_TYPE_ROUTER)
goto out;
cipher = silc_channel_key_get_cipher(payload, NULL);;
if (!cipher)
goto out;
- channel->key_len = key_len;
+ channel->key_len = key_len * 8;
channel->key = silc_calloc(key_len, sizeof(unsigned char));
memcpy(channel->key, key, key_len);
silc_cipher_alloc(cipher, &channel->channel_key);
SilcServerID *router_id,
char *cipher, char *channel_name)
{
- int i, channel_len;
+ int i, channel_len, key_len;
SilcChannelID *channel_id;
SilcChannelList *entry;
SilcCipher key;
cipher = "twofish";
/* Allocate keys */
+ key_len = 16;
silc_cipher_alloc(cipher, &key);
- key->cipher->set_key(key->context, channel_key, 16);
+ key->cipher->set_key(key->context, channel_key, key_len);
/* Create the channel */
silc_id_create_channel_id(router_id, server->rng, &channel_id);
LCCC(channel_name[0]),
channel_name, SILC_ID_CHANNEL,
channel_id, (void *)entry);
- entry->key = silc_calloc(16, sizeof(*entry->key));
- entry->key_len = 16;
- memcpy(entry->key, channel_key, 16);
+ entry->key = silc_calloc(key_len, sizeof(*entry->key));
+ entry->key_len = key_len * 8;
+ memcpy(entry->key, channel_key, key_len);
memset(channel_key, 0, sizeof(channel_key));
/* Notify other routers about the new channel. We send the packet