packet_receive.[ch].
--- /dev/null
+/*
+
+ packet_receive.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * Server packet routines to handle received packets.
+ */
+/* $Id$ */
+
+#include "serverincludes.h"
+#include "server_internal.h"
+
+extern char *server_version;
+
+/* Received private message. This resolves the destination of the message
+ and sends the packet. This is used by both server and router. If the
+ destination is our locally connected client this sends the packet to
+ the client. This may also send the message for further routing if
+ the destination is not in our server (or router). */
+
+void silc_server_private_message(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcClientID *id;
+ SilcServerEntry router;
+ SilcSocketConnection dst_sock;
+ SilcClientEntry client;
+ SilcIDListData idata;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!packet->dst_id) {
+ SILC_LOG_ERROR(("Bad Client ID in private message packet, dropped"));
+ goto err;
+ }
+
+ /* Decode destination Client ID */
+ id = silc_id_str2id(packet->dst_id, SILC_ID_CLIENT);
+ if (!id) {
+ SILC_LOG_ERROR(("Could not decode destination Client ID, dropped"));
+ goto err;
+ }
+
+ /* If the destination belongs to our server we don't have to route
+ the message anywhere but to send it to the local destination. */
+ client = silc_idlist_find_client_by_id(server->local_list, id);
+ if (client) {
+ /* It exists, now deliver the message to the destination */
+ dst_sock = (SilcSocketConnection)client->connection;
+
+ /* If we are router and the client has router then the client is in
+ our cell but not directly connected to us. */
+ if (server->server_type == SILC_ROUTER && client->router) {
+ /* We are of course in this case the client's router thus the real
+ "router" of the client is the server who owns the client. Thus
+ we will send the packet to that server. */
+ router = (SilcServerEntry)dst_sock->user_data;
+ idata = (SilcIDListData)router;
+ // assert(client->router == server->id_entry);
+
+ silc_server_send_private_message(server, dst_sock,
+ idata->send_key,
+ idata->hmac,
+ packet);
+ return;
+ }
+
+ /* Seems that client really is directly connected to us */
+ idata = (SilcIDListData)client;
+ silc_server_send_private_message(server, dst_sock,
+ idata->send_key,
+ idata->hmac, packet);
+ return;
+ }
+
+ /* Destination belongs to someone not in this server. If we are normal
+ server our action is to send the packet to our router. */
+ if (server->server_type == SILC_SERVER && !server->standalone) {
+ router = server->router;
+
+ /* Send to primary route */
+ if (router) {
+ dst_sock = (SilcSocketConnection)router->connection;
+ idata = (SilcIDListData)router;
+ silc_server_send_private_message(server, dst_sock,
+ idata->send_key,
+ idata->hmac, packet);
+ }
+ return;
+ }
+
+ /* We are router and we will perform route lookup for the destination
+ and send the message to fastest route. */
+ if (server->server_type == SILC_ROUTER && !server->standalone) {
+ dst_sock = silc_server_get_route(server, id, SILC_ID_CLIENT);
+ router = (SilcServerEntry)dst_sock->user_data;
+ idata = (SilcIDListData)router;
+
+ /* Get fastest route and send packet. */
+ if (router)
+ silc_server_send_private_message(server, dst_sock,
+ idata->send_key,
+ idata->hmac, packet);
+ return;
+ }
+
+ err:
+ silc_server_send_error(server, sock,
+ "No such nickname: Private message not sent");
+}
+
+/* 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
+ client's command request to router and router has now replied to the
+ command. */
+
+void silc_server_packet_relay_command_reply(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ SilcClientEntry client;
+ SilcClientID *id;
+ SilcSocketConnection dst_sock;
+ SilcIDListData idata;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Source must be server or router */
+ if (packet->src_id_type != SILC_ID_SERVER &&
+ sock->type != SILC_SOCKET_TYPE_ROUTER)
+ return;
+
+ /* Destination must be client */
+ if (packet->dst_id_type != SILC_ID_CLIENT)
+ return;
+
+ /* Execute command reply locally for the command */
+ silc_server_command_reply_process(server, sock, buffer);
+
+ id = silc_id_str2id(packet->dst_id, SILC_ID_CLIENT);
+
+ /* Destination must be one of ours */
+ client = silc_idlist_find_client_by_id(server->local_list, id);
+ if (!client) {
+ SILC_LOG_ERROR(("Cannot relay command reply to unknown client"));
+ silc_free(id);
+ return;
+ }
+
+ /* Relay the packet to the client */
+
+ dst_sock = (SilcSocketConnection)client->connection;
+ silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
+ + packet->dst_id_len + packet->padlen);
+
+ silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
+ silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
+
+ idata = (SilcIDListData)client;
+
+ /* Encrypt packet */
+ silc_packet_encrypt(idata->send_key, idata->hmac, dst_sock->outbuf,
+ buffer->len);
+
+ /* Send the packet */
+ silc_server_packet_send_real(server, dst_sock, TRUE);
+
+ silc_free(id);
+}
+
+/* Process received channel message. The message can be originated from
+ client or server. */
+
+void silc_server_channel_message(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcChannelEntry channel = NULL;
+ SilcChannelClientEntry chl;
+ SilcChannelID *id = NULL;
+ void *sender = NULL;
+
+ SILC_LOG_DEBUG(("Processing channel message"));
+
+ /* Sanity checks */
+ if (packet->dst_id_type != SILC_ID_CHANNEL) {
+ SILC_LOG_ERROR(("Received bad message for channel, dropped"));
+ SILC_LOG_DEBUG(("Received bad message for channel, dropped"));
+ goto out;
+ }
+
+ /* Find channel entry */
+ id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+ channel = silc_idlist_find_channel_by_id(server->local_list, id);
+ if (!channel) {
+ SILC_LOG_DEBUG(("Could not find channel"));
+ goto out;
+ }
+
+ /* See that this client is on the channel. If the message is coming
+ from router we won't do the check as the message is from client that
+ we don't know about. Also, if the original sender is not client
+ (as it can be server as well) we don't do the check. */
+ sender = silc_id_str2id(packet->src_id, packet->src_id_type);
+ if (sock->type != SILC_SOCKET_TYPE_ROUTER &&
+ packet->src_id_type == SILC_ID_CLIENT) {
+ silc_list_start(channel->user_list);
+ while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ if (chl->client && !SILC_ID_CLIENT_COMPARE(chl->client->id, sender))
+ break;
+ }
+ if (chl == SILC_LIST_END)
+ goto out;
+ }
+
+ /* Distribute the packet to our local clients. This will send the
+ packet for further routing as well, if needed. */
+ 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);
+}
+
+/* Received channel key packet. We distribute the key to all of our locally
+ 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,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ SilcChannelKeyPayload payload = NULL;
+ SilcChannelID *id = NULL;
+ SilcChannelEntry channel;
+ SilcChannelClientEntry chl;
+ unsigned char *tmp;
+ unsigned int tmp_len;
+ char *cipher;
+
+ if (packet->src_id_type != SILC_ID_SERVER &&
+ sock->type != SILC_SOCKET_TYPE_ROUTER)
+ goto out;
+
+ /* Decode channel key payload */
+ payload = silc_channel_key_payload_parse(buffer);
+ if (!payload) {
+ SILC_LOG_ERROR(("Bad channel key payload, dropped"));
+ goto out;
+ }
+
+ /* Get channel ID */
+ tmp = silc_channel_key_get_id(payload, &tmp_len);
+ id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!id)
+ goto out;
+
+ /* Get the channel entry */
+ channel = silc_idlist_find_channel_by_id(server->local_list, id);
+ if (!channel) {
+ SILC_LOG_ERROR(("Received key for non-existent channel"));
+ goto out;
+ }
+
+ /* Save the key for us as well */
+ tmp = silc_channel_key_get_key(payload, &tmp_len);
+ if (!tmp)
+ goto out;
+ cipher = silc_channel_key_get_cipher(payload, NULL);;
+ if (!cipher)
+ goto out;
+ if (!silc_cipher_alloc(cipher, &channel->channel_key))
+ goto out;
+
+ /* Distribute the key to all clients on the channel */
+ silc_list_start(channel->user_list);
+ while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ silc_server_packet_send(server, chl->client->connection,
+ SILC_PACKET_CHANNEL_KEY, 0,
+ buffer->data, buffer->len, TRUE);
+ }
+
+ channel->key_len = tmp_len * 8;
+ channel->key = silc_calloc(tmp_len, sizeof(unsigned char));
+ memcpy(channel->key, tmp, tmp_len);
+ channel->channel_key->cipher->set_key(channel->channel_key->context,
+ tmp, tmp_len);
+ out:
+ if (id)
+ silc_free(id);
+ if (payload)
+ silc_channel_key_payload_free(payload);
+}
+
+/* Received packet to replace a ID. This checks that the requested ID
+ exists and replaces it with the new one. */
+
+void silc_server_replace_id(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ unsigned char *old_id = NULL, *new_id = NULL;
+ SilcIdType old_id_type, new_id_type;
+ unsigned short old_id_len, new_id_len;
+ void *id = NULL, *id2 = NULL;
+
+ if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+ packet->src_id_type == SILC_ID_CLIENT)
+ return;
+
+ SILC_LOG_DEBUG(("Replacing ID"));
+
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI_SHORT(&old_id_type),
+ SILC_STR_UI16_NSTRING_ALLOC(&old_id, &old_id_len),
+ SILC_STR_UI_SHORT(&new_id_type),
+ SILC_STR_UI16_NSTRING_ALLOC(&new_id, &new_id_len),
+ SILC_STR_END);
+
+ if (old_id_type != new_id_type)
+ goto out;
+
+ if (old_id_len != silc_id_get_len(old_id_type) ||
+ new_id_len != silc_id_get_len(new_id_type))
+ goto out;
+
+ id = silc_id_str2id(old_id, old_id_type);
+ if (!id)
+ goto out;
+
+ id2 = silc_id_str2id(new_id, new_id_type);
+ if (!id2)
+ goto out;
+
+ /* If we are router and this packet is not already broadcast packet
+ we will broadcast it. The sending socket really cannot be router or
+ the router is buggy. If this packet is coming from router then it must
+ have the broadcast flag set already and we won't do anything. */
+ if (server->server_type == SILC_ROUTER &&
+ sock->type == SILC_SOCKET_TYPE_SERVER &&
+ !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
+ SILC_LOG_DEBUG(("Broadcasting received Replace ID packet"));
+ silc_server_packet_send(server, server->router->connection, packet->type,
+ packet->flags | SILC_PACKET_FLAG_BROADCAST,
+ buffer->data, buffer->len, FALSE);
+ }
+
+ /* Replace the old ID */
+ switch(old_id_type) {
+ case SILC_ID_CLIENT:
+ if (silc_idlist_replace_client_id(server->local_list, id, id2) == NULL)
+ if (server->server_type == SILC_ROUTER)
+ silc_idlist_replace_client_id(server->global_list, id, id2);
+ break;
+
+ case SILC_ID_SERVER:
+ if (silc_idlist_replace_server_id(server->local_list, id, id2) == NULL)
+ if (server->server_type == SILC_ROUTER)
+ silc_idlist_replace_server_id(server->global_list, id, id2);
+ break;
+
+ case SILC_ID_CHANNEL:
+ /* XXX Hmm... Basically this cannot occur. Channel ID's cannot be
+ re-generated. */
+ silc_free(id2);
+ break;
+
+ default:
+ silc_free(id2);
+ break;
+ }
+
+ out:
+ if (id)
+ silc_free(id);
+ if (old_id)
+ silc_free(old_id);
+ if (new_id)
+ silc_free(new_id);
+}
+
+
+/* Received New Client packet and processes it. Creates Client ID for the
+ client. Client becomes registered after calling this functions. */
+
+SilcClientEntry silc_server_new_client(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ SilcClientEntry client;
+ SilcIDCacheEntry cache;
+ SilcClientID *client_id;
+ SilcBuffer reply;
+ SilcIDListData idata;
+ char *username = NULL, *realname = NULL, *id_string;
+
+ SILC_LOG_DEBUG(("Creating new client"));
+
+ if (sock->type != SILC_SOCKET_TYPE_CLIENT)
+ return NULL;
+
+ /* Take client entry */
+ client = (SilcClientEntry)sock->user_data;
+ idata = (SilcIDListData)client;
+
+ /* Fetch the old client cache entry so that we can update it. */
+ if (!silc_idcache_find_by_context(server->local_list->clients,
+ sock->user_data, &cache)) {
+ SILC_LOG_ERROR(("Lost client's cache entry - bad thing"));
+ return NULL;
+ }
+
+ /* Parse incoming packet */
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI16_STRING_ALLOC(&username),
+ SILC_STR_UI16_STRING_ALLOC(&realname),
+ SILC_STR_END);
+
+ /* Create Client ID */
+ silc_id_create_client_id(server->id, server->rng, server->md5hash,
+ username, &client_id);
+
+ /* Update client entry */
+ idata->registered = TRUE;
+ client->nickname = strdup(username);
+ client->username = username;
+ client->userinfo = realname;
+ client->id = client_id;
+
+ /* Update the cache entry */
+ cache->id = (void *)client_id;
+ cache->type = SILC_ID_CLIENT;
+ cache->data = username;
+ silc_idcache_sort_by_data(server->local_list->clients);
+
+ /* Notify our router about new client on the SILC network */
+ if (!server->standalone)
+ silc_server_send_new_id(server, (SilcSocketConnection)
+ server->router->connection,
+ server->server_type == SILC_ROUTER ? TRUE : FALSE,
+ client->id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
+
+ /* Send the new client ID to the client. */
+ id_string = silc_id_id2str(client->id, SILC_ID_CLIENT);
+ reply = silc_buffer_alloc(2 + 2 + SILC_ID_CLIENT_LEN);
+ silc_buffer_pull_tail(reply, SILC_BUFFER_END(reply));
+ silc_buffer_format(reply,
+ SILC_STR_UI_SHORT(SILC_ID_CLIENT),
+ SILC_STR_UI_SHORT(SILC_ID_CLIENT_LEN),
+ SILC_STR_UI_XNSTRING(id_string, SILC_ID_CLIENT_LEN),
+ SILC_STR_END);
+ silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID, 0,
+ reply->data, reply->len, FALSE);
+ silc_free(id_string);
+ silc_buffer_free(reply);
+
+ /* Send some nice info to the client */
+ SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+ ("Welcome to the SILC Network %s@%s",
+ username, sock->hostname));
+ SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+ ("Your host is %s, running version %s",
+ server->config->server_info->server_name,
+ server_version));
+ SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+ ("Your connection is secured with %s cipher, "
+ "key length %d bits",
+ idata->send_key->cipher->name,
+ idata->send_key->cipher->key_len));
+ SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+ ("Your current nickname is %s",
+ client->nickname));
+
+ /* Send motd */
+ silc_server_send_motd(server, sock);
+
+ return client;
+}
+
+/* Create new server. This processes received New Server packet and
+ saves the received Server ID. The server is our locally connected
+ server thus we save all the information and save it to local list.
+ This funtion can be used by both normal server and router server.
+ If normal server uses this it means that its router has connected
+ to the server. If router uses this it means that one of the cell's
+ servers is connected to the router. */
+
+SilcServerEntry silc_server_new_server(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ SilcServerEntry new_server;
+ SilcIDCacheEntry cache;
+ SilcServerID *server_id;
+ SilcIDListData idata;
+ unsigned char *server_name, *id_string;
+ unsigned short id_len;
+
+ SILC_LOG_DEBUG(("Creating new server"));
+
+ if (sock->type != SILC_SOCKET_TYPE_SERVER &&
+ sock->type != SILC_SOCKET_TYPE_ROUTER)
+ return NULL;
+
+ /* Take server entry */
+ new_server = (SilcServerEntry)sock->user_data;
+ idata = (SilcIDListData)new_server;
+
+ /* Fetch the old server cache entry so that we can update it. */
+ if (!silc_idcache_find_by_context(server->local_list->servers,
+ sock->user_data, &cache)) {
+ SILC_LOG_ERROR(("Lost server's cache entry - bad thing"));
+ return NULL;
+ }
+
+ /* Parse the incoming packet */
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI16_NSTRING_ALLOC(&id_string, &id_len),
+ SILC_STR_UI16_STRING_ALLOC(&server_name),
+ SILC_STR_END);
+
+ if (id_len > buffer->len) {
+ silc_free(id_string);
+ silc_free(server_name);
+ return NULL;
+ }
+
+ /* Get Server ID */
+ server_id = silc_id_str2id(id_string, SILC_ID_SERVER);
+ silc_free(id_string);
+
+ /* Update client entry */
+ idata->registered = TRUE;
+ new_server->server_name = server_name;
+ new_server->id = server_id;
+
+ /* Update the cache entry */
+ cache->id = (void *)server_id;
+ cache->type = SILC_ID_SERVER;
+ cache->data = server_name;
+ silc_idcache_sort_by_data(server->local_list->servers);
+
+ /* Distribute the information about new server in the SILC network
+ to our router. If we are normal server we won't send anything
+ since this connection must be our router connection. */
+ if (server->server_type == SILC_ROUTER && !server->standalone &&
+ server->router->connection != sock)
+ silc_server_send_new_id(server, server->router->connection,
+ TRUE, new_server->id, SILC_ID_SERVER,
+ SILC_ID_SERVER_LEN);
+
+ return new_server;
+}
+
+/* Processes incoming New ID packet. New ID Payload is used to distribute
+ information about newly registered clients, servers and created
+ channels. */
+
+void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ SilcIDList id_list;
+ SilcServerEntry tmpserver, router;
+ SilcSocketConnection router_sock;
+ SilcIDPayload idp;
+ SilcIdType id_type;
+ void *id, *tmpid;
+
+ SILC_LOG_DEBUG(("Processing new ID"));
+
+ if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+ server->server_type == SILC_SERVER ||
+ packet->src_id_type != SILC_ID_SERVER)
+ return;
+
+ idp = silc_id_payload_parse(buffer);
+ if (!idp)
+ return;
+
+ id_type = silc_id_payload_get_type(idp);
+
+ /* Normal server cannot have other normal server connections */
+ if (id_type == SILC_ID_SERVER && sock->type == SILC_SOCKET_TYPE_SERVER)
+ goto out;
+
+ id = silc_id_payload_get_id(idp);
+ if (!id)
+ goto out;
+
+ /* If the sender of this packet is server and we are router we need to
+ broadcast this packet to other routers in the network. */
+ if (!server->standalone && server->server_type == SILC_ROUTER &&
+ sock->type == SILC_SOCKET_TYPE_SERVER &&
+ !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
+ SILC_LOG_DEBUG(("Broadcasting received New ID packet"));
+ silc_server_packet_send(server, server->router->connection,
+ packet->type,
+ packet->flags | SILC_PACKET_FLAG_BROADCAST,
+ buffer->data, buffer->len, FALSE);
+ }
+
+ /* If the packet is originated from the one who sent it to us we know
+ that the ID belongs to our cell, unless the sender was router. */
+ tmpid = silc_id_str2id(packet->src_id, SILC_ID_SERVER);
+ tmpserver = (SilcServerEntry)sock->user_data;
+
+ if (!SILC_ID_SERVER_COMPARE(tmpid, tmpserver->id) &&
+ sock->type == SILC_SOCKET_TYPE_SERVER) {
+ id_list = server->local_list;
+ router_sock = sock;
+ router = sock->user_data;
+ /* router = server->id_entry; */
+ } else {
+ id_list = server->global_list;
+ router_sock = (SilcSocketConnection)server->router->connection;
+ router = server->router;
+ }
+
+ silc_free(tmpid);
+
+ switch(id_type) {
+ case SILC_ID_CLIENT:
+ {
+ SilcClientEntry idlist;
+
+ SILC_LOG_DEBUG(("New client id(%s) from [%s] %s",
+ silc_id_render(id, SILC_ID_CLIENT),
+ sock->type == SILC_SOCKET_TYPE_SERVER ?
+ "Server" : "Router", sock->hostname));
+
+ /* Add the client to our local list. We are router and we keep
+ cell specific local database of all clients in the cell. */
+ idlist = silc_idlist_add_client(id_list, NULL, NULL, NULL,
+ id, router, router_sock);
+ }
+ break;
+
+ case SILC_ID_SERVER:
+ {
+ SilcServerEntry idlist;
+
+ SILC_LOG_DEBUG(("New server id(%s) from [%s] %s",
+ silc_id_render(id, SILC_ID_SERVER),
+ sock->type == SILC_SOCKET_TYPE_SERVER ?
+ "Server" : "Router", sock->hostname));
+
+ /* Add the server to our local list. We are router and we keep
+ cell specific local database of all servers in the cell. */
+ idlist = silc_idlist_add_server(id_list, NULL, 0, id, router,
+ router_sock);
+ }
+ break;
+
+ case SILC_ID_CHANNEL:
+ SILC_LOG_ERROR(("Channel cannot be registered with NEW_ID packet"));
+#if 0
+ SILC_LOG_DEBUG(("New channel id(%s) from [%s] %s",
+ silc_id_render(id, SILC_ID_CHANNEL),
+ sock->type == SILC_SOCKET_TYPE_SERVER ?
+ "Server" : "Router", sock->hostname));
+
+ /* Add the channel to our local list. We are router and we keep
+ cell specific local database of all channels in the cell. */
+ silc_idlist_add_channel(id_list, NULL, 0, id, router, NULL);
+#endif
+ break;
+
+ default:
+ break;
+ }
+
+ out:
+ silc_id_payload_free(idp);
+}
+
+/* Received Remove Channel User packet to remove a user from a channel.
+ Routers notify other routers that user has left a channel. Client must
+ not send this packet.. Normal server may send this packet but must not
+ receive it. */
+
+void silc_server_remove_channel_user(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ unsigned char *tmp1 = NULL, *tmp2 = NULL;
+ SilcClientID *client_id = NULL;
+ SilcChannelID *channel_id = NULL;
+ SilcChannelEntry channel;
+ SilcClientEntry client;
+
+ SILC_LOG_DEBUG(("Removing user from channel"));
+
+ if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+ server->server_type == SILC_SERVER)
+ return;
+
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI16_STRING_ALLOC(&tmp1),
+ SILC_STR_UI16_STRING_ALLOC(&tmp2),
+ SILC_STR_END);
+
+ if (!tmp1 || !tmp2)
+ goto out;
+
+ client_id = silc_id_str2id(tmp1, SILC_ID_CLIENT);
+ channel_id = silc_id_str2id(tmp2, SILC_ID_CHANNEL);
+ if (!client_id || !channel_id)
+ goto out;
+
+ /* If we are router and this packet is not already broadcast packet
+ we will broadcast it. The sending socket really cannot be router or
+ the router is buggy. If this packet is coming from router then it must
+ have the broadcast flag set already and we won't do anything. */
+ if (!server->standalone && server->server_type == SILC_ROUTER &&
+ sock->type == SILC_SOCKET_TYPE_SERVER &&
+ !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
+ SILC_LOG_DEBUG(("Broadcasting received Remove Channel User packet"));
+ silc_server_packet_send(server, server->router->connection, packet->type,
+ packet->flags | SILC_PACKET_FLAG_BROADCAST,
+ buffer->data, buffer->len, FALSE);
+ }
+
+ /* XXX routers should check server->global_list as well */
+ /* Get channel entry */
+ channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
+ if (!channel)
+ goto out;
+
+ /* XXX routers should check server->global_list as well */
+ /* Get client entry */
+ client = silc_idlist_find_client_by_id(server->local_list, client_id);
+ if (!client)
+ goto out;
+
+ /* Remove from channel */
+ silc_server_remove_from_one_channel(server, sock, channel, client, FALSE);
+
+ out:
+ if (tmp1)
+ silc_free(tmp1);
+ if (tmp2)
+ silc_free(tmp2);
+ if (client_id)
+ silc_free(client_id);
+ if (channel_id)
+ silc_free(channel_id);
+}
+
+/* Received New Channel packet. Information about new channels in the
+ network are distributed using this packet. Save the information about
+ the new channel. */
+
+void silc_server_new_channel(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ unsigned char *id;
+ SilcChannelID *channel_id;
+ unsigned short channel_id_len;
+ char *channel_name;
+
+ SILC_LOG_DEBUG(("Processing New Channel"));
+
+ if (sock->type != SILC_SOCKET_TYPE_ROUTER ||
+ server->server_type == SILC_SERVER ||
+ packet->src_id_type != SILC_ID_SERVER)
+ return;
+
+ /* Parse payload */
+ if (!silc_buffer_unformat(packet->buffer,
+ SILC_STR_UI16_STRING_ALLOC(&channel_name),
+ SILC_STR_UI16_NSTRING_ALLOC(&id, &channel_id_len),
+ SILC_STR_END))
+ return;
+
+ if (!channel_name || !id)
+ return;
+
+ /* Decode the channel ID */
+ channel_id = silc_id_str2id(id, SILC_ID_CHANNEL);
+ if (!channel_id)
+ return;
+ silc_free(id);
+
+ SILC_LOG_DEBUG(("New channel id(%s) from [Router] %s",
+ silc_id_render(channel_id, SILC_ID_CHANNEL),
+ sock->hostname));
+
+ /* Add the new channel. Add it always to global list since if we receive
+ this packet then it cannot be created by ourselves but some other
+ router hence global channel. */
+ silc_idlist_add_channel(server->global_list, channel_name, 0, channel_id,
+ server->router->connection, NULL);
+}
+
+/* Received notify packet. Server can receive notify packets from router.
+ Server then relays the notify messages to clients if needed. */
+
+void silc_server_notify(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcNotifyPayload payload;
+ SilcNotifyType type;
+ SilcArgumentPayload args;
+ int i;
+
+ if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+ packet->src_id_type != SILC_ID_SERVER)
+ return;
+
+ /* For now we expect that the we are normal server and that the
+ sender is router. Server could send (protocol allows it) notify to
+ router but we don't support it yet. XXX! */
+ if (server->server_type != SILC_SERVER &&
+ sock->type != SILC_SOCKET_TYPE_ROUTER)
+ return;
+
+ payload = silc_notify_payload_parse(packet->buffer);
+ if (!payload)
+ return;
+
+ type = silc_notify_get_type(payload);
+ args = silc_notify_get_args(payload);
+ if (!args)
+ goto out;
+
+ switch(type) {
+ case SILC_NOTIFY_TYPE_JOIN:
+ break;
+
+ case SILC_NOTIFY_TYPE_LEAVE:
+ break;
+
+ case SILC_NOTIFY_TYPE_SIGNOFF:
+ break;
+
+ /* Ignore rest notify types for now */
+ case SILC_NOTIFY_TYPE_NONE:
+ case SILC_NOTIFY_TYPE_INVITE:
+ case SILC_NOTIFY_TYPE_TOPIC_SET:
+ case SILC_NOTIFY_TYPE_CMODE_CHANGE:
+ case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
+ case SILC_NOTIFY_TYPE_MOTD:
+ default:
+ break;
+ }
+
+ out:
+ silc_notify_payload_free(payload);
+}
+
+/* Received new channel user packet. Information about new users on a
+ channel are distributed between routers using this packet. The
+ router receiving this will redistribute it and also sent JOIN notify
+ to local clients on the same channel. Normal server sends JOIN notify
+ to its local clients on the channel. */
+
+void silc_server_new_channel_user(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ unsigned char *tmpid1, *tmpid2;
+ SilcClientID *client_id = NULL;
+ SilcChannelID *channel_id = NULL;
+ unsigned short channel_id_len;
+ unsigned short client_id_len;
+ SilcClientEntry client;
+ SilcChannelEntry channel;
+ SilcChannelClientEntry chl;
+ SilcIDList id_list;
+ SilcServerEntry tmpserver, router;
+ SilcSocketConnection router_sock;
+ SilcBuffer clidp;
+ void *tmpid;
+
+ if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+ server->server_type != SILC_ROUTER ||
+ packet->src_id_type != SILC_ID_SERVER)
+ return;
+
+ /* Parse payload */
+ if (!silc_buffer_unformat(packet->buffer,
+ SILC_STR_UI16_NSTRING_ALLOC(&tmpid1,
+ &channel_id_len),
+ SILC_STR_UI16_NSTRING_ALLOC(&tmpid2,
+ &client_id_len),
+ SILC_STR_END))
+ return;
+
+ if (!tmpid1 || !tmpid2)
+ return;
+
+ /* Decode the channel ID */
+ channel_id = silc_id_str2id(tmpid1, SILC_ID_CHANNEL);
+ if (!channel_id)
+ goto out;
+
+ /* Decode the client ID */
+ client_id = silc_id_str2id(tmpid1, SILC_ID_CLIENT);
+ if (!client_id)
+ goto out;
+
+ /* If the packet is originated from the one who sent it to us we know
+ that the ID belongs to our cell, unless the sender was router. */
+ tmpid = silc_id_str2id(packet->src_id, SILC_ID_SERVER);
+ tmpserver = (SilcServerEntry)sock->user_data;
+
+ if (!SILC_ID_SERVER_COMPARE(tmpid, tmpserver->id) &&
+ sock->type == SILC_SOCKET_TYPE_SERVER) {
+ id_list = server->local_list;
+ router_sock = sock;
+ router = sock->user_data;
+ } else {
+ id_list = server->global_list;
+ router_sock = (SilcSocketConnection)server->router->connection;
+ router = server->router;
+ }
+ silc_free(tmpid);
+
+ /* Find the channel */
+ channel = silc_idlist_find_channel_by_id(id_list, channel_id);
+ if (!channel) {
+ SILC_LOG_ERROR(("Received channel user for non-existent channel"));
+ goto out;
+ }
+
+ /* If we are router and this packet is not already broadcast packet
+ we will broadcast it. */
+ if (!server->standalone && server->server_type == SILC_ROUTER &&
+ !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
+ SILC_LOG_DEBUG(("Broadcasting received New Channel User packet"));
+ silc_server_packet_send(server, server->router->connection, packet->type,
+ packet->flags | SILC_PACKET_FLAG_BROADCAST,
+ packet->buffer->data, packet->buffer->len, FALSE);
+ }
+
+ /* Get client entry */
+ client = silc_idlist_find_client_by_id(id_list, client_id);
+ if (!client) {
+ /* This is new client to us, add entry to ID list */
+ client = silc_idlist_add_client(id_list, NULL, NULL, NULL,
+ client_id, router, router_sock);
+ if (!client)
+ goto out;
+ }
+
+ /* Join the client to the channel by adding it to channel's user list.
+ Add also the channel to client entry's channels list for fast cross-
+ referencing. */
+ chl = silc_calloc(1, sizeof(*chl));
+ chl->client = client;
+ chl->channel = channel;
+ silc_list_add(channel->user_list, chl);
+ silc_list_add(client->channels, chl);
+
+ /* Send JOIN notify to local clients on the channel. As we are router
+ it is assured that this is sent only to our local clients and locally
+ connected servers if needed. */
+ clidp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
+ silc_server_send_notify_to_channel(server, channel, TRUE,
+ SILC_NOTIFY_TYPE_JOIN,
+ 1, clidp->data, clidp->len);
+ silc_buffer_free(clidp);
+
+ client_id = NULL;
+
+ out:
+ if (client_id)
+ silc_free(client_id);
+ if (channel_id)
+ silc_free(channel_id);
+ silc_free(tmpid1);
+ silc_free(tmpid2);
+}
--- /dev/null
+/*
+
+ packet_receive.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef PACKET_RECEIVE_H
+#define PACKET_RECEIVE_H
+
+/* Prototypes */
+
+void silc_server_private_message(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_server_packet_relay_command_reply(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_server_channel_message(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_server_channel_key(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_server_replace_id(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+SilcClientEntry silc_server_new_client(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+SilcServerEntry silc_server_new_server(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_server_remove_channel_user(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_server_new_channel(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_server_notify(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_server_new_channel_user(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+
+#endif
--- /dev/null
+/*
+
+ packet_send.c
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+/*
+ * Server packet routines to send packets.
+ */
+/* $Id$ */
+
+#include "serverincludes.h"
+#include "server_internal.h"
+
+/* Routine that sends packet or marks packet to be sent. This is used
+ directly only in special cases. Normal cases should use
+ silc_server_packet_send. Returns < 0 error. */
+
+int silc_server_packet_send_real(SilcServer server,
+ SilcSocketConnection sock,
+ int force_send)
+{
+ int ret;
+
+ /* Send the packet */
+ ret = silc_packet_send(sock, force_send);
+ if (ret != -2)
+ 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
+ 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);
+
+ /* 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
+ put data is sent to the network. */
+ SILC_SET_OUTBUF_PENDING(sock);
+
+ return 0;
+}
+
+/* Assembles a new packet to be sent out to network. This doesn't actually
+ send the packet but creates the packet and fills the outgoing data
+ buffer and marks the packet ready to be sent to network. However, If
+ argument force_send is TRUE the packet is sent immediately and not put
+ to queue. Normal case is that the packet is not sent immediately. */
+
+void silc_server_packet_send(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketType type,
+ SilcPacketFlags flags,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send)
+{
+ void *dst_id = NULL;
+ SilcIdType dst_id_type = SILC_ID_NONE;
+
+ if (!sock)
+ 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;
+ break;
+ case SILC_SOCKET_TYPE_SERVER:
+ case SILC_SOCKET_TYPE_ROUTER:
+ dst_id = ((SilcServerEntry)sock->user_data)->id;
+ dst_id_type = SILC_ID_SERVER;
+ break;
+ default:
+ break;
+ }
+
+ silc_server_packet_send_dest(server, sock, type, flags, dst_id,
+ dst_id_type, data, data_len, force_send);
+}
+
+/* Assembles a new packet to be sent out to network. This doesn't actually
+ send the packet but creates the packet and fills the outgoing data
+ buffer and marks the packet ready to be sent to network. However, If
+ argument force_send is TRUE the packet is sent immediately and not put
+ to queue. Normal case is that the packet is not sent immediately.
+ Destination information is sent as argument for this function. */
+
+void silc_server_packet_send_dest(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketType type,
+ SilcPacketFlags flags,
+ void *dst_id,
+ SilcIdType dst_id_type,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send)
+{
+ SilcPacketContext packetdata;
+ SilcIDListData idata;
+ SilcCipher cipher = NULL;
+ SilcHmac hmac = NULL;
+ unsigned char *dst_id_data = NULL;
+ unsigned int dst_id_len = 0;
+
+ SILC_LOG_DEBUG(("Sending packet, type %d", type));
+
+ /* Get data used in the packet sending, keys and stuff */
+ idata = (SilcIDListData)sock->user_data;
+
+ if (dst_id) {
+ dst_id_data = silc_id_id2str(dst_id, dst_id_type);
+ dst_id_len = silc_id_get_len(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_type = server->id_type;
+ packetdata.dst_id = dst_id_data;
+ packetdata.dst_id_len = dst_id_len;
+ packetdata.dst_id_type = dst_id_type;
+ packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + dst_id_len;
+ packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+ packetdata.rng = server->rng;
+
+ /* Prepare outgoing data buffer for packet sending */
+ silc_packet_send_prepare(sock,
+ SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len,
+ packetdata.padlen,
+ data_len);
+
+ SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
+
+ packetdata.buffer = sock->outbuf;
+
+ /* Put the data to the buffer */
+ if (data && data_len)
+ silc_buffer_put(sock->outbuf, data, data_len);
+
+ /* Create the outgoing packet */
+ silc_packet_assemble(&packetdata);
+
+ if (idata) {
+ cipher = idata->send_key;
+ hmac = idata->hmac;
+ }
+
+ /* Encrypt the packet */
+ silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
+
+ SILC_LOG_HEXDUMP(("Outgoing packet, len %d", sock->outbuf->len),
+ sock->outbuf->data, sock->outbuf->len);
+
+ /* Now actually send the packet */
+ silc_server_packet_send_real(server, sock, force_send);
+
+ if (packetdata.src_id)
+ silc_free(packetdata.src_id);
+ if (packetdata.dst_id)
+ silc_free(packetdata.dst_id);
+}
+
+/* Forwards packet. Packets sent with this function will be marked as
+ forwarded (in the SILC header flags) so that the receiver knows that
+ we have forwarded the packet to it. Forwarded packets are handled
+ specially by the receiver as they are not destined to the receiver
+ originally. However, the receiver knows this because the forwarded
+ flag has been set (and the flag is authenticated). */
+
+void silc_server_packet_forward(SilcServer server,
+ SilcSocketConnection sock,
+ unsigned char *data, unsigned int data_len,
+ int force_send)
+{
+ SilcIDListData idata;
+ SilcCipher cipher = NULL;
+ SilcHmac hmac = NULL;
+
+ SILC_LOG_DEBUG(("Forwarding packet"));
+
+ /* Get data used in the packet sending, keys and stuff */
+ idata = (SilcIDListData)sock->user_data;
+
+ /* Prepare outgoing data buffer for packet sending */
+ silc_packet_send_prepare(sock, 0, 0, data_len);
+
+ /* Put the data to the buffer */
+ if (data && data_len)
+ silc_buffer_put(sock->outbuf, data, data_len);
+
+ /* Add the FORWARDED flag to packet flags */
+ sock->outbuf->data[2] |= (unsigned char)SILC_PACKET_FLAG_FORWARDED;
+
+ if (idata) {
+ cipher = idata->send_key;
+ hmac = idata->hmac;
+ }
+
+ /* Encrypt the packet */
+ silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
+
+ SILC_LOG_HEXDUMP(("Forwarded packet, len %d", sock->outbuf->len),
+ sock->outbuf->data, sock->outbuf->len);
+
+ /* Now actually send the packet */
+ silc_server_packet_send_real(server, sock, force_send);
+}
+
+/* Broadcast received packet to our primary route. This function is used
+ by router to further route received broadcast packet. It is expected
+ that the broadcast flag from the packet is checked before calling this
+ function. This does not test or set the broadcast flag. */
+
+void silc_server_packet_broadcast(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ SilcIDListData idata;
+ void *id;
+
+ SILC_LOG_DEBUG(("Broadcasting received broadcast packet"));
+
+ /* 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_type);
+ if (id && SILC_ID_SERVER_COMPARE(id, server->router->id)) {
+ idata = (SilcIDListData)sock->user_data;
+
+ silc_buffer_push(buffer, buffer->data - buffer->head);
+ silc_packet_send_prepare(sock, 0, 0, buffer->len);
+ silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
+ silc_packet_encrypt(idata->send_key, idata->hmac,
+ sock->outbuf, sock->outbuf->len);
+
+ SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", sock->outbuf->len),
+ sock->outbuf->data, sock->outbuf->len);
+
+ /* Now actually send the packet */
+ silc_server_packet_send_real(server, sock, TRUE);
+ silc_free(id);
+ return;
+ }
+
+ SILC_LOG_DEBUG(("Will not broadcast to primary route since it is the "
+ "original sender of this packet"));
+ silc_free(id);
+}
+
+/* Internal routine to actually create the channel packet and send it
+ to network. This is common function in channel message sending. If
+ `channel_message' is TRUE this encrypts the message as it is strictly
+ a channel message. If FALSE normal encryption process is used. */
+
+static void
+silc_server_packet_send_to_channel_real(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet,
+ SilcCipher cipher,
+ SilcHmac hmac,
+ unsigned char *data,
+ unsigned int data_len,
+ int channel_message,
+ int force_send)
+{
+ packet->truelen = data_len + SILC_PACKET_HEADER_LEN +
+ packet->src_id_len + packet->dst_id_len;
+
+ /* Prepare outgoing data buffer for packet sending */
+ silc_packet_send_prepare(sock,
+ SILC_PACKET_HEADER_LEN +
+ packet->src_id_len +
+ packet->dst_id_len,
+ packet->padlen,
+ data_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. */
+ silc_buffer_put(sock->outbuf, data, data_len);
+ silc_packet_assemble(packet);
+ if (channel_message)
+ silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN +
+ packet->src_id_len + packet->dst_id_len +
+ packet->padlen);
+ else
+ silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
+
+ SILC_LOG_HEXDUMP(("Channel packet, len %d", sock->outbuf->len),
+ sock->outbuf->data, sock->outbuf->len);
+
+ /* Now actually send the packet */
+ silc_server_packet_send_real(server, sock, force_send);
+}
+
+/* This routine is used by the server to send packets to channel. The
+ packet sent with this function is distributed to all clients on
+ the channel. Usually this is used to send notify messages to the
+ channel, things like notify about new user joining to the channel.
+ If `route' is FALSE then the packet is sent only locally and will not
+ be routed anywhere. */
+
+void silc_server_packet_send_to_channel(SilcServer server,
+ SilcChannelEntry channel,
+ SilcPacketType type,
+ unsigned char route,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send)
+{
+ SilcSocketConnection sock = NULL;
+ SilcPacketContext packetdata;
+ SilcClientEntry client = NULL;
+ SilcServerEntry *routed = NULL;
+ SilcChannelClientEntry chl;
+ SilcIDListData idata;
+ unsigned int routed_count = 0;
+
+ /* This doesn't send channel message packets */
+ if (type == SILC_PACKET_CHANNEL_MESSAGE)
+ return;
+
+ SILC_LOG_DEBUG(("Sending packet to channel"));
+
+ /* Set the packet context pointers. */
+ 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_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_type = SILC_ID_CHANNEL;
+ packetdata.rng = server->rng;
+ packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len;
+ packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+
+ /* 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 &&
+ channel->global_users) {
+ SilcServerEntry router;
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ router = server->router;
+ sock = (SilcSocketConnection)router->connection;
+ idata = (SilcIDListData)router;
+
+ SILC_LOG_DEBUG(("Sending channel message to router for routing"));
+
+ silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+ idata->send_key, idata->hmac,
+ data, data_len, FALSE, force_send);
+ }
+
+ /* 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) {
+ client = chl->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. */
+ if (route && client && client->router &&
+ server->server_type == SILC_ROUTER) {
+ int k;
+
+ /* Check if we have sent the packet to this route already */
+ for (k = 0; k < routed_count; k++)
+ if (routed[k] == client->router)
+ break;
+ if (k < routed_count)
+ continue;
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ sock = (SilcSocketConnection)client->router->connection;
+ idata = (SilcIDListData)client->router;
+
+ /* Send the packet */
+ silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+ idata->send_key, idata->hmac,
+ data, data_len, FALSE,
+ force_send);
+
+ /* We want to make sure that the packet is routed to same router
+ only once. Mark this route as sent route. */
+ k = routed_count;
+ routed = silc_realloc(routed, sizeof(*routed) * (k + 1));
+ routed[k] = client->router;
+ routed_count++;
+
+ continue;
+ }
+
+ /* Send to locally connected client */
+ if (client) {
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ sock = (SilcSocketConnection)client->connection;
+ idata = (SilcIDListData)client;
+
+ /* Send the packet */
+ silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+ idata->send_key, idata->hmac,
+ data, data_len, FALSE,
+ force_send);
+ }
+ }
+
+ if (routed_count)
+ silc_free(routed);
+ silc_free(packetdata.src_id);
+ silc_free(packetdata.dst_id);
+}
+
+/* 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
+ the channel. If the sender of the packet is someone on the channel
+ the message will not be sent to that client. The SILC Packet header
+ is encrypted with the session key shared between us and the client.
+ MAC is also computed before encrypting the header. Rest of the
+ packet will be untouched. */
+
+void silc_server_packet_relay_to_channel(SilcServer server,
+ SilcSocketConnection sender_sock,
+ SilcChannelEntry channel,
+ void *sender,
+ SilcIdType sender_type,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send)
+{
+ int found = FALSE;
+ SilcSocketConnection sock = NULL;
+ SilcPacketContext packetdata;
+ SilcClientEntry client = NULL;
+ SilcServerEntry *routed = NULL;
+ SilcChannelClientEntry chl;
+ unsigned int routed_count = 0;
+ SilcIDListData idata;
+
+ SILC_LOG_DEBUG(("Relaying packet to channel"));
+
+ /* 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_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_type = SILC_ID_CHANNEL;
+ packetdata.rng = server->rng;
+ packetdata.padlen = SILC_PACKET_PADLEN((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 (server->server_type == SILC_SERVER && !server->standalone &&
+ channel->global_users) {
+ SilcServerEntry router;
+
+ router = server->router;
+
+ /* Check that the sender is not our router. */
+ if (sender_sock != (SilcSocketConnection)router->connection) {
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ sock = (SilcSocketConnection)router->connection;
+ idata = (SilcIDListData)router;
+
+ SILC_LOG_DEBUG(("Sending channel message to router for routing"));
+
+ silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+ idata->send_key, idata->hmac,
+ data, data_len, TRUE,
+ force_send);
+ }
+ }
+
+ /* 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) {
+ 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)) {
+ found = TRUE;
+ 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) {
+ int k;
+
+ /* 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)) {
+ found = TRUE;
+ continue;
+ }
+
+ /* Check if we have sent the packet to this route already */
+ for (k = 0; k < routed_count; k++)
+ if (routed[k] == client->router)
+ break;
+ if (k < routed_count)
+ continue;
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ sock = (SilcSocketConnection)client->router->connection;
+ idata = (SilcIDListData)client->router;
+
+ /* Send the packet */
+ silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+ idata->send_key, idata->hmac,
+ data, data_len, TRUE,
+ force_send);
+
+ /* We want to make sure that the packet is routed to same router
+ only once. Mark this route as sent route. */
+ k = routed_count;
+ routed = silc_realloc(routed, sizeof(*routed) * (k + 1));
+ routed[k] = client->router;
+ routed_count++;
+
+ continue;
+ }
+
+ /* XXX Check client's mode on the channel. */
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ sock = (SilcSocketConnection)client->connection;
+ idata = (SilcIDListData)client;
+
+ SILC_LOG_DEBUG(("Sending packet to client %s",
+ sock->hostname ? sock->hostname : sock->ip));
+
+ /* Send the packet */
+ silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+ idata->send_key, idata->hmac,
+ data, data_len, TRUE,
+ force_send);
+ }
+ }
+
+ silc_free(packetdata.src_id);
+ 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, this means these are not _to the channel_ but _to the client_
+ on the channel. */
+
+void silc_server_packet_send_local_channel(SilcServer server,
+ SilcChannelEntry channel,
+ SilcPacketType type,
+ SilcPacketFlags flags,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send)
+{
+ SilcClientEntry client;
+ SilcChannelClientEntry chl;
+ 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) {
+ client = chl->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);
+ }
+ }
+}
+
+/* Routine used to send (relay, route) private messages to some destination.
+ If the private message key does not exist then the message is re-encrypted,
+ otherwise we just pass it along. This really is not used to send new
+ private messages (as server does not send them) but to relay received
+ private messages. */
+
+void silc_server_send_private_message(SilcServer server,
+ SilcSocketConnection dst_sock,
+ SilcCipher cipher,
+ SilcHmac hmac,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+
+ /* Send and re-encrypt if private messge key does not exist */
+ if ((packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY) == FALSE) {
+
+ silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
+ + packet->dst_id_len + packet->padlen);
+ silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
+ silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
+
+ /* Re-encrypt packet */
+ silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, buffer->len);
+
+ /* Send the packet */
+ silc_server_packet_send_real(server, dst_sock, FALSE);
+
+ } else {
+ /* Key exist so just send it */
+ silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
+ + packet->dst_id_len + packet->padlen);
+ silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
+ silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
+ silc_server_packet_send_real(server, dst_sock, FALSE);
+ }
+}
+
+/* Sends current motd to client */
+
+void silc_server_send_motd(SilcServer server,
+ SilcSocketConnection sock)
+{
+ char *motd;
+ int motd_len;
+
+ if (server->config && server->config->motd &&
+ server->config->motd->motd_file) {
+
+ motd = silc_file_read(server->config->motd->motd_file, &motd_len);
+ if (!motd)
+ return;
+
+ silc_server_send_notify(server, sock, SILC_NOTIFY_TYPE_MOTD, 1,
+ motd, motd_len);
+ silc_free(motd);
+ }
+}
+
+/* Sends error message. Error messages may or may not have any
+ implications. */
+
+void silc_server_send_error(SilcServer server,
+ SilcSocketConnection sock,
+ const char *fmt, ...)
+{
+ va_list ap;
+ unsigned char buf[4096];
+
+ memset(buf, 0, sizeof(buf));
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ silc_server_packet_send(server, sock, SILC_PACKET_ERROR, 0,
+ buf, strlen(buf), FALSE);
+}
+
+/* Sends notify message. If format is TRUE the variable arguments are
+ formatted and the formatted string is sent as argument payload. If it is
+ FALSE then each argument is sent as separate argument and their format
+ in the argument list must be { argument data, argument length }. */
+
+void silc_server_send_notify(SilcServer server,
+ SilcSocketConnection sock,
+ SilcNotifyType type,
+ unsigned int argc, ...)
+{
+ va_list ap;
+ SilcBuffer packet;
+
+ va_start(ap, argc);
+
+ packet = silc_notify_payload_encode(type, argc, ap);
+ silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 0,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+}
+
+/* Sends notify message destined to specific entity. */
+
+void silc_server_send_notify_dest(SilcServer server,
+ SilcSocketConnection sock,
+ void *dest_id,
+ SilcIdType dest_id_type,
+ SilcNotifyType type,
+ unsigned int argc, ...)
+{
+ va_list ap;
+ SilcBuffer packet;
+
+ va_start(ap, argc);
+
+ packet = silc_notify_payload_encode(type, argc, ap);
+ silc_server_packet_send_dest(server, sock, SILC_PACKET_NOTIFY, 0,
+ dest_id, dest_id_type,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+}
+
+/* Sends notify message to a channel. The notify message sent is
+ distributed to all clients on the channel. If `router_notify' is TRUE
+ then the notify may be routed to primary route or to some other routers.
+ If FALSE it is assured that the notify is sent only locally. */
+
+void silc_server_send_notify_to_channel(SilcServer server,
+ SilcChannelEntry channel,
+ unsigned char route_notify,
+ SilcNotifyType type,
+ unsigned int argc, ...)
+{
+ va_list ap;
+ SilcBuffer packet;
+
+ va_start(ap, argc);
+
+ packet = silc_notify_payload_encode(type, argc, ap);
+ silc_server_packet_send_to_channel(server, channel,
+ SILC_PACKET_NOTIFY, route_notify,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+}
+
+/* Send notify message to all clients the client has joined. It is quaranteed
+ that the message is sent only once to a client (ie. if a client is joined
+ on two same channel it will receive only one notify message). Also, this
+ sends only to local clients (locally connected if we are server, and to
+ local servers if we are router). */
+
+void silc_server_send_notify_on_channels(SilcServer server,
+ SilcClientEntry client,
+ SilcNotifyType type,
+ unsigned int argc, ...)
+{
+ int k;
+ SilcSocketConnection sock = NULL;
+ SilcPacketContext packetdata;
+ SilcClientEntry c;
+ SilcClientEntry *sent_clients = NULL;
+ unsigned int sent_clients_count = 0;
+ SilcServerEntry *routed = NULL;
+ unsigned int routed_count = 0;
+ SilcChannelEntry channel;
+ SilcChannelClientEntry chl, chl2;
+ SilcIDListData idata;
+ SilcBuffer packet;
+ unsigned char *data;
+ unsigned int data_len;
+ int force_send = FALSE;
+ va_list ap;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!silc_list_count(client->channels))
+ return;
+
+ va_start(ap, argc);
+ packet = silc_notify_payload_encode(type, argc, ap);
+ data = packet->data;
+ data_len = packet->len;
+
+ /* Set the packet context pointers. */
+ 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_type = SILC_ID_SERVER;
+ packetdata.rng = server->rng;
+
+ silc_list_start(client->channels);
+ while ((chl = silc_list_get(client->channels)) != SILC_LIST_END) {
+ 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) {
+ c = chl2->client;
+
+ /* Check if we have sent the packet to this client already */
+ for (k = 0; k < sent_clients_count; k++)
+ if (sent_clients[k] == c)
+ break;
+ if (k < sent_clients_count)
+ continue;
+
+ /* If we are router and if this client has router set it is not
+ locally connected client and we will route the message to the
+ router set in the client. */
+ if (c && c->router && server->server_type == SILC_ROUTER) {
+ /* Check if we have sent the packet to this route already */
+ for (k = 0; k < routed_count; k++)
+ if (routed[k] == c->router)
+ break;
+ if (k < routed_count)
+ continue;
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ sock = (SilcSocketConnection)c->router->connection;
+ 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_type = SILC_ID_SERVER;
+ packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len;
+ packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+
+ /* Send the packet */
+ silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+ idata->send_key, idata->hmac,
+ data, data_len, FALSE,
+ force_send);
+
+ silc_free(packetdata.dst_id);
+
+ /* We want to make sure that the packet is routed to same router
+ only once. Mark this route as sent route. */
+ k = routed_count;
+ routed = silc_realloc(routed, sizeof(*routed) * (k + 1));
+ routed[k] = c->router;
+ routed_count++;
+
+ continue;
+ }
+
+ /* Send to locally connected client */
+ if (c) {
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ sock = (SilcSocketConnection)c->connection;
+ 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_type = SILC_ID_CLIENT;
+ packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len;
+ packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+
+ /* Send the packet */
+ silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+ idata->send_key, idata->hmac,
+ data, data_len, FALSE,
+ force_send);
+
+ silc_free(packetdata.dst_id);
+
+ /* Make sure that we send the notify only once per client. */
+ sent_clients = silc_realloc(sent_clients, sizeof(*sent_clients) *
+ (sent_clients_count + 1));
+ sent_clients[sent_clients_count] = c;
+ sent_clients_count++;
+ }
+ }
+ }
+
+ if (routed_count)
+ silc_free(routed);
+ if (sent_clients_count)
+ silc_free(sent_clients);
+ silc_free(packetdata.src_id);
+}
+
+/* Sends New ID Payload to remote end. The packet is used to distribute
+ information about new registered clients, servers, channel etc. usually
+ to routers so that they can keep these information up to date.
+ If the argument `broadcast' is TRUE then the packet is sent as
+ broadcast packet. */
+
+void silc_server_send_new_id(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ void *id, SilcIdType id_type,
+ unsigned int id_len)
+{
+ SilcBuffer idp;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ 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);
+ silc_buffer_free(idp);
+}
+
+/* Sends Replace ID payload to remote end. This is used to replace old
+ ID with new ID sent in the packet. This is called for example when
+ user changes nickname and we create new ID for the user. If the
+ argument `broadcast' is TRUE then the packet is sent as
+ broadcast packet. */
+/* XXX It would be expected that the new id is same type as the old
+ ID. :) */
+
+void silc_server_send_replace_id(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ void *old_id, SilcIdType old_id_type,
+ unsigned int old_id_len,
+ void *new_id, SilcIdType new_id_type,
+ unsigned int new_id_len)
+{
+ SilcBuffer packet;
+ unsigned char *oid;
+ unsigned char *nid;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ oid = silc_id_id2str(old_id, old_id_type);
+ if (!oid)
+ return;
+
+ nid = silc_id_id2str(new_id, new_id_type);
+ if (!nid)
+ return;
+
+ packet = silc_buffer_alloc(2 + 2 + 2 + 2 + old_id_len + new_id_len);
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_SHORT(old_id_type),
+ SILC_STR_UI_SHORT(old_id_len),
+ SILC_STR_UI_XNSTRING(oid, old_id_len),
+ SILC_STR_UI_SHORT(new_id_type),
+ SILC_STR_UI_SHORT(new_id_len),
+ SILC_STR_UI_XNSTRING(nid, new_id_len),
+ SILC_STR_END);
+
+ silc_server_packet_send(server, sock, SILC_PACKET_REPLACE_ID,
+ broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
+ packet->data, packet->len, FALSE);
+ silc_free(oid);
+ silc_free(nid);
+ silc_buffer_free(packet);
+}
+
+/* This function is used to send Remove Channel User payload. This may sent
+ by server but is usually used only by router to notify other routers that
+ user has left a channel. Normal server sends this packet to its router
+ to notify that the router should not hold a record about this client
+ on a channel anymore. Router distributes it further to other routers. */
+
+void silc_server_send_remove_channel_user(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ void *client_id, void *channel_id)
+{
+ SilcBuffer packet;
+ unsigned char *clid, *chid;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ clid = silc_id_id2str(client_id, SILC_ID_CLIENT);
+ if (!clid)
+ return;
+
+ chid = silc_id_id2str(channel_id, SILC_ID_CHANNEL);
+ if (!chid)
+ return;
+
+ packet = silc_buffer_alloc(2 + 2 + SILC_ID_CLIENT_LEN + SILC_ID_CHANNEL_LEN);
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_SHORT(SILC_ID_CLIENT_LEN),
+ SILC_STR_UI_XNSTRING(clid, SILC_ID_CLIENT_LEN),
+ SILC_STR_UI_SHORT(SILC_ID_CHANNEL_LEN),
+ SILC_STR_UI_XNSTRING(chid, SILC_ID_CHANNEL_LEN),
+ SILC_STR_END);
+
+ silc_server_packet_send(server, sock, SILC_PACKET_REMOVE_CHANNEL_USER,
+ broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
+ packet->data, packet->len, FALSE);
+ silc_free(clid);
+ silc_free(chid);
+ silc_buffer_free(packet);
+}
+
+/* Send New Channel Payload to notify about newly created channel in the
+ SILC network. Normal server nevers sends this packet. Router uses this
+ to notify other routers in the network about new channel. This packet
+ is broadcasted. */
+
+void silc_server_send_new_channel(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ char *channel_name,
+ void *channel_id,
+ unsigned int channel_id_len)
+{
+ SilcBuffer packet;
+ unsigned char *cid;
+ unsigned int name_len = strlen(channel_name);
+
+ SILC_LOG_DEBUG(("Start"));
+
+ cid = silc_id_id2str(channel_id, SILC_ID_CHANNEL);
+ if (!cid)
+ return;
+
+ packet = silc_buffer_alloc(2 + 2 + name_len + channel_id_len);
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_SHORT(name_len),
+ SILC_STR_UI_XNSTRING(channel_name, name_len),
+ SILC_STR_UI_SHORT(channel_id_len),
+ SILC_STR_UI_XNSTRING(cid, channel_id_len),
+ SILC_STR_END);
+
+ silc_server_packet_send(server, sock, SILC_PACKET_NEW_CHANNEL,
+ broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
+ packet->data, packet->len, FALSE);
+
+ silc_free(cid);
+ silc_buffer_free(packet);
+}
+
+/* Send New Channel User payload to notify routers in the network about new
+ user on the channel. The packet is may be broadcasted. Normal server
+ can send this but must not receive. Router can send and receive it. */
+
+void silc_server_send_new_channel_user(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ void *channel_id,
+ unsigned int channel_id_len,
+ void *client_id,
+ unsigned int client_id_len)
+{
+ SilcBuffer packet;
+ unsigned char *clid, *chid;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ clid = silc_id_id2str(client_id, SILC_ID_CLIENT);
+ if (!clid)
+ return;
+
+ chid = silc_id_id2str(channel_id, SILC_ID_CHANNEL);
+ if (!chid)
+ return;
+
+ packet = silc_buffer_alloc(2 + 2 + channel_id_len + client_id_len);
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_SHORT(channel_id_len),
+ SILC_STR_UI_XNSTRING(chid, channel_id_len),
+ SILC_STR_UI_SHORT(client_id_len),
+ SILC_STR_UI_XNSTRING(clid, client_id_len),
+ SILC_STR_END);
+
+ silc_server_packet_send(server, sock, SILC_PACKET_NEW_CHANNEL_USER,
+ broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
+ packet->data, packet->len, FALSE);
+ silc_free(clid);
+ silc_free(chid);
+ silc_buffer_free(packet);
+}
--- /dev/null
+/*
+
+ packet_send.h
+
+ Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ Copyright (C) 1997 - 2000 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#ifndef PACKET_SEND_H
+#define PACKET_SEND_H
+
+/* Prototypes */
+
+int silc_server_packet_send_real(SilcServer server,
+ SilcSocketConnection sock,
+ int force_send);
+void silc_server_packet_send(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketType type,
+ SilcPacketFlags flags,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send);
+void silc_server_packet_send_dest(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketType type,
+ SilcPacketFlags flags,
+ void *dst_id,
+ SilcIdType dst_id_type,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send);
+void silc_server_packet_forward(SilcServer server,
+ SilcSocketConnection sock,
+ unsigned char *data, unsigned int data_len,
+ int force_send);
+void silc_server_packet_broadcast(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
+void silc_server_packet_send_to_channel(SilcServer server,
+ SilcChannelEntry channel,
+ SilcPacketType type,
+ unsigned char route,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send);
+void silc_server_packet_relay_to_channel(SilcServer server,
+ SilcSocketConnection sender_sock,
+ SilcChannelEntry channel,
+ void *sender,
+ SilcIdType sender_type,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send);
+void silc_server_packet_send_local_channel(SilcServer server,
+ SilcChannelEntry channel,
+ SilcPacketType type,
+ SilcPacketFlags flags,
+ unsigned char *data,
+ unsigned int data_len,
+ int force_send);
+void silc_server_send_private_message(SilcServer server,
+ SilcSocketConnection dst_sock,
+ SilcCipher cipher,
+ SilcHmac hmac,
+ SilcPacketContext *packet);
+void silc_server_send_motd(SilcServer server,
+ SilcSocketConnection sock);
+void silc_server_send_error(SilcServer server,
+ SilcSocketConnection sock,
+ const char *fmt, ...);
+void silc_server_send_notify(SilcServer server,
+ SilcSocketConnection sock,
+ SilcNotifyType type,
+ unsigned int argc, ...);
+void silc_server_send_notify_dest(SilcServer server,
+ SilcSocketConnection sock,
+ void *dest_id,
+ SilcIdType dest_id_type,
+ SilcNotifyType type,
+ unsigned int argc, ...);
+void silc_server_send_notify_to_channel(SilcServer server,
+ SilcChannelEntry channel,
+ unsigned char route_notify,
+ SilcNotifyType type,
+ unsigned int argc, ...);
+void silc_server_send_notify_on_channels(SilcServer server,
+ SilcClientEntry client,
+ SilcNotifyType type,
+ unsigned int argc, ...);
+void silc_server_send_new_id(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ void *id, SilcIdType id_type,
+ unsigned int id_len);
+void silc_server_send_replace_id(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ void *old_id, SilcIdType old_id_type,
+ unsigned int old_id_len,
+ void *new_id, SilcIdType new_id_type,
+ unsigned int new_id_len);
+void silc_server_send_remove_channel_user(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ void *client_id, void *channel_id);
+void silc_server_send_new_channel(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ char *channel_name,
+ void *channel_id,
+ unsigned int channel_id_len);
+void silc_server_send_new_channel_user(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ void *channel_id,
+ unsigned int channel_id_len,
+ void *client_id,
+ unsigned int client_id_len);
+
+#endif
SILC_TASK_CALLBACK(silc_server_packet_parse_real);
SILC_TASK_CALLBACK(silc_server_timeout_remote);
-extern char *server_version;
-
/* Allocates a new SILC server object. This has to be done before the server
can be used. After allocation one must call silc_server_init to initialize
the server. The new allocated server object is returned to the new_server
sock->protocol = NULL;
}
-/* Internal routine that sends packet or marks packet to be sent. This
- is used directly only in special cases. Normal cases should use
- silc_server_packet_send. Returns < 0 error. */
-
-static int silc_server_packet_send_real(SilcServer server,
- SilcSocketConnection sock,
- int force_send)
-{
- int ret;
-
- /* Send the packet */
- ret = silc_packet_send(sock, force_send);
- if (ret != -2)
- 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
- 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);
-
- /* 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
- put data is sent to the network. */
- SILC_SET_OUTBUF_PENDING(sock);
-
- return 0;
-}
-
-typedef struct {
- SilcPacketContext *packetdata;
- SilcServer server;
- SilcSocketConnection sock;
- SilcCipher cipher;
- SilcHmac hmac;
-} SilcServerInternalPacket;
-
/* This function is used to read packets from network and send packets to
network. This is usually a generic task. */
case SILC_PACKET_NOTIFY:
/*
- * Received notify packet.
+ * Received notify packet. Server can receive notify packets from
+ * router. Server then relays the notify messages to clients if needed.
*/
SILC_LOG_DEBUG(("Notify packet"));
+ silc_server_notify(server, sock, packet);
break;
/*
break;
case SILC_PACKET_PRIVATE_MESSAGE_KEY:
+ /*
+ * XXX
+ */
break;
/*
break;
case SILC_PACKET_NEW_CHANNEL:
+ /*
+ * Received new channel packet. Information about new channel in the
+ * network are distributed using this packet.
+ */
+ SILC_LOG_DEBUG(("New Channel packet"));
+ silc_server_new_channel(server, sock, packet);
break;
case SILC_PACKET_NEW_CHANNEL_USER:
+ /*
+ * Received new channel user packet. Information about new users on a
+ * channel are distributed between routers using this packet. The
+ * router receiving this will redistribute it and also sent JOIN notify
+ * to local clients on the same channel. Normal server sends JOIN notify
+ * to its local clients on the channel.
+ */
+ SILC_LOG_DEBUG(("New Channel User packet"));
+ silc_server_new_channel_user(server, sock, packet);
break;
case SILC_PACKET_NEW_CHANNEL_LIST:
+ /*
+ * List of new channel packets received. This is usually received when
+ * existing server or router connects to us and distributes information
+ * of all channels it has.
+ */
break;
case SILC_PACKET_NEW_CHANNEL_USER_LIST:
+ /*
+ * List of new channel user packets received. This is usually received
+ * when existing server or router connects to us and distributes
+ * information of all channel users it has.
+ */
break;
case SILC_PACKET_REPLACE_ID:
}
-/* Assembles a new packet to be sent out to network. This doesn't actually
- send the packet but creates the packet and fills the outgoing data
- buffer and marks the packet ready to be sent to network. However, If
- argument force_send is TRUE the packet is sent immediately and not put
- to queue. Normal case is that the packet is not sent immediately. */
-
-void silc_server_packet_send(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketType type,
- SilcPacketFlags flags,
- unsigned char *data,
- unsigned int data_len,
- int force_send)
-{
- void *dst_id = NULL;
- SilcIdType dst_id_type = SILC_ID_NONE;
-
- if (!sock)
- 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;
- break;
- case SILC_SOCKET_TYPE_SERVER:
- case SILC_SOCKET_TYPE_ROUTER:
- dst_id = ((SilcServerEntry)sock->user_data)->id;
- dst_id_type = SILC_ID_SERVER;
- break;
- default:
- break;
- }
-
- silc_server_packet_send_dest(server, sock, type, flags, dst_id,
- dst_id_type, data, data_len, force_send);
-}
-
-/* Assembles a new packet to be sent out to network. This doesn't actually
- send the packet but creates the packet and fills the outgoing data
- buffer and marks the packet ready to be sent to network. However, If
- argument force_send is TRUE the packet is sent immediately and not put
- to queue. Normal case is that the packet is not sent immediately.
- Destination information is sent as argument for this function. */
-
-void silc_server_packet_send_dest(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketType type,
- SilcPacketFlags flags,
- void *dst_id,
- SilcIdType dst_id_type,
- unsigned char *data,
- unsigned int data_len,
- int force_send)
-{
- SilcPacketContext packetdata;
- SilcIDListData idata;
- SilcCipher cipher = NULL;
- SilcHmac hmac = NULL;
- unsigned char *dst_id_data = NULL;
- unsigned int dst_id_len = 0;
-
- SILC_LOG_DEBUG(("Sending packet, type %d", type));
-
- /* Get data used in the packet sending, keys and stuff */
- idata = (SilcIDListData)sock->user_data;
-
- if (dst_id) {
- dst_id_data = silc_id_id2str(dst_id, dst_id_type);
- dst_id_len = silc_id_get_len(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_type = server->id_type;
- packetdata.dst_id = dst_id_data;
- packetdata.dst_id_len = dst_id_len;
- packetdata.dst_id_type = dst_id_type;
- packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
- packetdata.src_id_len + dst_id_len;
- packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
- packetdata.rng = server->rng;
-
- /* Prepare outgoing data buffer for packet sending */
- silc_packet_send_prepare(sock,
- SILC_PACKET_HEADER_LEN +
- packetdata.src_id_len +
- packetdata.dst_id_len,
- packetdata.padlen,
- data_len);
-
- SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
-
- packetdata.buffer = sock->outbuf;
-
- /* Put the data to the buffer */
- if (data && data_len)
- silc_buffer_put(sock->outbuf, data, data_len);
-
- /* Create the outgoing packet */
- silc_packet_assemble(&packetdata);
-
- if (idata) {
- cipher = idata->send_key;
- hmac = idata->hmac;
- }
-
- /* Encrypt the packet */
- silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
-
- SILC_LOG_HEXDUMP(("Outgoing packet, len %d", sock->outbuf->len),
- sock->outbuf->data, sock->outbuf->len);
-
- /* Now actually send the packet */
- silc_server_packet_send_real(server, sock, force_send);
-
- if (packetdata.src_id)
- silc_free(packetdata.src_id);
- if (packetdata.dst_id)
- silc_free(packetdata.dst_id);
-}
-
-/* Forwards packet. Packets sent with this function will be marked as
- forwarded (in the SILC header flags) so that the receiver knows that
- we have forwarded the packet to it. Forwarded packets are handled
- specially by the receiver as they are not destined to the receiver
- originally. However, the receiver knows this because the forwarded
- flag has been set (and the flag is authenticated). */
-
-void silc_server_packet_forward(SilcServer server,
- SilcSocketConnection sock,
- unsigned char *data, unsigned int data_len,
- int force_send)
-{
- SilcIDListData idata;
- SilcCipher cipher = NULL;
- SilcHmac hmac = NULL;
-
- SILC_LOG_DEBUG(("Forwarding packet"));
-
- /* Get data used in the packet sending, keys and stuff */
- idata = (SilcIDListData)sock->user_data;
-
- /* Prepare outgoing data buffer for packet sending */
- silc_packet_send_prepare(sock, 0, 0, data_len);
-
- /* Put the data to the buffer */
- if (data && data_len)
- silc_buffer_put(sock->outbuf, data, data_len);
-
- /* Add the FORWARDED flag to packet flags */
- sock->outbuf->data[2] |= (unsigned char)SILC_PACKET_FLAG_FORWARDED;
-
- if (idata) {
- cipher = idata->send_key;
- hmac = idata->hmac;
- }
-
- /* Encrypt the packet */
- silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
-
- SILC_LOG_HEXDUMP(("Forwarded packet, len %d", sock->outbuf->len),
- sock->outbuf->data, sock->outbuf->len);
-
- /* Now actually send the packet */
- silc_server_packet_send_real(server, sock, force_send);
-}
-
-/* Broadcast received packet to our primary route. This function is used
- by router to further route received broadcast packet. It is expected
- that the broadcast flag from the packet is checked before calling this
- function. This does not test or set the broadcast flag. */
-
-void silc_server_packet_broadcast(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketContext *packet)
-{
- SilcBuffer buffer = packet->buffer;
- SilcIDListData idata;
- void *id;
-
- SILC_LOG_DEBUG(("Broadcasting received broadcast packet"));
-
- /* 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_type);
- if (id && SILC_ID_SERVER_COMPARE(id, server->router->id)) {
- idata = (SilcIDListData)sock->user_data;
-
- silc_buffer_push(buffer, buffer->data - buffer->head);
- silc_packet_send_prepare(sock, 0, 0, buffer->len);
- silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
- silc_packet_encrypt(idata->send_key, idata->hmac,
- sock->outbuf, sock->outbuf->len);
-
- SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", sock->outbuf->len),
- sock->outbuf->data, sock->outbuf->len);
-
- /* Now actually send the packet */
- silc_server_packet_send_real(server, sock, TRUE);
- silc_free(id);
- return;
- }
-
- SILC_LOG_DEBUG(("Will not broadcast to primary route since it is the "
- "original sender of this packet"));
- silc_free(id);
-}
-
-/* Internal routine to actually create the channel packet and send it
- to network. This is common function in channel message sending. If
- `channel_message' is TRUE this encrypts the message as it is strictly
- a channel message. If FALSE normal encryption process is used. */
-
-static void
-silc_server_packet_send_to_channel_real(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketContext *packet,
- SilcCipher cipher,
- SilcHmac hmac,
- unsigned char *data,
- unsigned int data_len,
- int channel_message,
- int force_send)
-{
- packet->truelen = data_len + SILC_PACKET_HEADER_LEN +
- packet->src_id_len + packet->dst_id_len;
-
- /* Prepare outgoing data buffer for packet sending */
- silc_packet_send_prepare(sock,
- SILC_PACKET_HEADER_LEN +
- packet->src_id_len +
- packet->dst_id_len,
- packet->padlen,
- data_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. */
- silc_buffer_put(sock->outbuf, data, data_len);
- silc_packet_assemble(packet);
- if (channel_message)
- silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN +
- packet->src_id_len + packet->dst_id_len +
- packet->padlen);
- else
- silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
-
- SILC_LOG_HEXDUMP(("Channel packet, len %d", sock->outbuf->len),
- sock->outbuf->data, sock->outbuf->len);
-
- /* Now actually send the packet */
- silc_server_packet_send_real(server, sock, force_send);
-}
-
-/* This routine is used by the server to send packets to channel. The
- packet sent with this function is distributed to all clients on
- the channel. Usually this is used to send notify messages to the
- channel, things like notify about new user joining to the channel. */
-
-void silc_server_packet_send_to_channel(SilcServer server,
- SilcChannelEntry channel,
- SilcPacketType type,
- unsigned char *data,
- unsigned int data_len,
- int force_send)
-{
- SilcSocketConnection sock = NULL;
- SilcPacketContext packetdata;
- SilcClientEntry client = NULL;
- SilcServerEntry *routed = NULL;
- SilcChannelClientEntry chl;
- SilcIDListData idata;
- unsigned int routed_count = 0;
-
- /* This doesn't send channel message packets */
- if (type == SILC_PACKET_CHANNEL_MESSAGE)
- return;
-
- SILC_LOG_DEBUG(("Sending packet to channel"));
-
- /* Set the packet context pointers. */
- 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_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_type = SILC_ID_CHANNEL;
- packetdata.rng = server->rng;
- packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
- packetdata.src_id_len + packetdata.dst_id_len;
- packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
-
- /* 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 &&
- channel->global_users) {
- SilcServerEntry router;
-
- /* Get data used in packet header encryption, keys and stuff. */
- router = server->router;
- sock = (SilcSocketConnection)router->connection;
- idata = (SilcIDListData)router;
-
- SILC_LOG_DEBUG(("Sending channel message to router for routing"));
-
- silc_server_packet_send_to_channel_real(server, sock, &packetdata,
- idata->send_key, idata->hmac,
- data, data_len, FALSE, force_send);
- }
-
- /* 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) {
- client = chl->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. */
- if (client && client->router && server->server_type == SILC_ROUTER) {
- int k;
-
- /* Check if we have sent the packet to this route already */
- for (k = 0; k < routed_count; k++)
- if (routed[k] == client->router)
- break;
- if (k < routed_count)
- continue;
-
- /* Get data used in packet header encryption, keys and stuff. */
- sock = (SilcSocketConnection)client->router->connection;
- idata = (SilcIDListData)client->router;
-
- /* Send the packet */
- silc_server_packet_send_to_channel_real(server, sock, &packetdata,
- idata->send_key, idata->hmac,
- data, data_len, FALSE,
- force_send);
-
- /* We want to make sure that the packet is routed to same router
- only once. Mark this route as sent route. */
- k = routed_count;
- routed = silc_realloc(routed, sizeof(*routed) * (k + 1));
- routed[k] = client->router;
- routed_count++;
-
- continue;
- }
-
- /* Send to locally connected client */
- if (client) {
-
- /* Get data used in packet header encryption, keys and stuff. */
- sock = (SilcSocketConnection)client->connection;
- idata = (SilcIDListData)client;
-
- /* Send the packet */
- silc_server_packet_send_to_channel_real(server, sock, &packetdata,
- idata->send_key, idata->hmac,
- data, data_len, FALSE,
- force_send);
- }
- }
-
- if (routed_count)
- silc_free(routed);
- silc_free(packetdata.src_id);
- silc_free(packetdata.dst_id);
-}
-
-/* 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
- the channel. If the sender of the packet is someone on the channel
- the message will not be sent to that client. The SILC Packet header
- is encrypted with the session key shared between us and the client.
- MAC is also computed before encrypting the header. Rest of the
- packet will be untouched. */
-
-void silc_server_packet_relay_to_channel(SilcServer server,
- SilcSocketConnection sender_sock,
- SilcChannelEntry channel,
- void *sender,
- SilcIdType sender_type,
- unsigned char *data,
- unsigned int data_len,
- int force_send)
-{
- int found = FALSE;
- SilcSocketConnection sock = NULL;
- SilcPacketContext packetdata;
- SilcClientEntry client = NULL;
- SilcServerEntry *routed = NULL;
- SilcChannelClientEntry chl;
- unsigned int routed_count = 0;
- SilcIDListData idata;
-
- SILC_LOG_DEBUG(("Relaying packet to channel"));
-
- /* 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_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_type = SILC_ID_CHANNEL;
- packetdata.rng = server->rng;
- packetdata.padlen = SILC_PACKET_PADLEN((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 (server->server_type == SILC_SERVER && !server->standalone &&
- channel->global_users) {
- SilcServerEntry router;
-
- router = server->router;
-
- /* Check that the sender is not our router. */
- if (sender_sock != (SilcSocketConnection)router->connection) {
-
- /* Get data used in packet header encryption, keys and stuff. */
- sock = (SilcSocketConnection)router->connection;
- idata = (SilcIDListData)router;
-
- SILC_LOG_DEBUG(("Sending channel message to router for routing"));
-
- silc_server_packet_send_to_channel_real(server, sock, &packetdata,
- idata->send_key, idata->hmac,
- data, data_len, TRUE,
- force_send);
- }
- }
-
- /* 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) {
- 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)) {
- found = TRUE;
- 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) {
- int k;
-
- /* 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)) {
- found = TRUE;
- continue;
- }
-
- /* Check if we have sent the packet to this route already */
- for (k = 0; k < routed_count; k++)
- if (routed[k] == client->router)
- break;
- if (k < routed_count)
- continue;
-
- /* Get data used in packet header encryption, keys and stuff. */
- sock = (SilcSocketConnection)client->router->connection;
- idata = (SilcIDListData)client->router;
-
- /* Send the packet */
- silc_server_packet_send_to_channel_real(server, sock, &packetdata,
- idata->send_key, idata->hmac,
- data, data_len, TRUE,
- force_send);
-
- /* We want to make sure that the packet is routed to same router
- only once. Mark this route as sent route. */
- k = routed_count;
- routed = silc_realloc(routed, sizeof(*routed) * (k + 1));
- routed[k] = client->router;
- routed_count++;
-
- continue;
- }
-
- /* XXX Check client's mode on the channel. */
-
- /* Get data used in packet header encryption, keys and stuff. */
- sock = (SilcSocketConnection)client->connection;
- idata = (SilcIDListData)client;
-
- SILC_LOG_DEBUG(("Sending packet to client %s",
- sock->hostname ? sock->hostname : sock->ip));
-
- /* Send the packet */
- silc_server_packet_send_to_channel_real(server, sock, &packetdata,
- idata->send_key, idata->hmac,
- data, data_len, TRUE,
- force_send);
- }
- }
-
- silc_free(packetdata.src_id);
- 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, this means these are not _to the channel_ but _to the client_
- on the channel. */
-
-void silc_server_packet_send_local_channel(SilcServer server,
- SilcChannelEntry channel,
- SilcPacketType type,
- SilcPacketFlags flags,
- unsigned char *data,
- unsigned int data_len,
- int force_send)
-{
- SilcClientEntry client;
- SilcChannelClientEntry chl;
- 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) {
- client = chl->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
- client's command request to router and router has now replied to the
- command. */
-
-void silc_server_packet_relay_command_reply(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketContext *packet)
-{
- SilcBuffer buffer = packet->buffer;
- SilcClientEntry client;
- SilcClientID *id;
- SilcSocketConnection dst_sock;
- SilcIDListData idata;
-
- SILC_LOG_DEBUG(("Start"));
-
- /* Source must be server or router */
- if (packet->src_id_type != SILC_ID_SERVER &&
- sock->type != SILC_SOCKET_TYPE_ROUTER)
- return;
-
- /* Destination must be client */
- if (packet->dst_id_type != SILC_ID_CLIENT)
- return;
-
- /* Execute command reply locally for the command */
- silc_server_command_reply_process(server, sock, buffer);
-
- id = silc_id_str2id(packet->dst_id, SILC_ID_CLIENT);
-
- /* Destination must be one of ours */
- client = silc_idlist_find_client_by_id(server->local_list, id);
- if (!client) {
- SILC_LOG_ERROR(("Cannot relay command reply to unknown client"));
- silc_free(id);
- return;
- }
-
- /* Relay the packet to the client */
-
- dst_sock = (SilcSocketConnection)client->connection;
- silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
- + packet->dst_id_len + packet->padlen);
-
- silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
- silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
-
- idata = (SilcIDListData)client;
-
- /* Encrypt packet */
- silc_packet_encrypt(idata->send_key, idata->hmac, dst_sock->outbuf,
- buffer->len);
-
- /* Send the packet */
- silc_server_packet_send_real(server, dst_sock, TRUE);
-
- silc_free(id);
-}
-
/* Closes connection to socket connection */
void silc_server_close_connection(SilcServer server,
channel globally from SILC network, in this case we will
notify that this client has left the channel. */
if (channel->global_users)
- silc_server_send_notify_to_channel(server, channel,
+ silc_server_send_notify_to_channel(server, channel, TRUE,
SILC_NOTIFY_TYPE_SIGNOFF, 1,
clidp->data, clidp->len);
/* Send notify to channel about client leaving SILC and thus
the entire channel. */
- silc_server_send_notify_to_channel(server, channel,
+ silc_server_send_notify_to_channel(server, channel, TRUE,
SILC_NOTIFY_TYPE_SIGNOFF, 1,
clidp->data, clidp->len);
silc_buffer_free(chidp);
/* Notify about leaving client if this channel has global users,
ie. the channel is not created locally. */
if (notify && channel->global_users)
- silc_server_send_notify_to_channel(server, channel,
+ silc_server_send_notify_to_channel(server, channel, TRUE,
SILC_NOTIFY_TYPE_LEAVE, 1,
clidp->data, clidp->len);
/* Send notify to channel about client leaving the channel */
if (notify)
- silc_server_send_notify_to_channel(server, channel,
+ silc_server_send_notify_to_channel(server, channel, TRUE,
SILC_NOTIFY_TYPE_LEAVE, 1,
clidp->data, clidp->len);
break;
"Connection timeout");
}
-/* Internal routine used to send (relay, route) private messages to some
- destination. If the private message key does not exist then the message
- is re-encrypted, otherwise we just pass it along. */
-
-static void
-silc_server_private_message_send_internal(SilcServer server,
- SilcSocketConnection dst_sock,
- SilcCipher cipher,
- SilcHmac hmac,
- SilcPacketContext *packet)
-{
- SilcBuffer buffer = packet->buffer;
-
- /* Send and re-encrypt if private messge key does not exist */
- if ((packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY) == FALSE) {
-
- silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
- + packet->dst_id_len + packet->padlen);
- silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
- silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
-
- /* Re-encrypt packet */
- silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, buffer->len);
-
- /* Send the packet */
- silc_server_packet_send_real(server, dst_sock, FALSE);
-
- } else {
- /* Key exist so just send it */
- silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
- + packet->dst_id_len + packet->padlen);
- silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
- silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
- silc_server_packet_send_real(server, dst_sock, FALSE);
- }
-}
-
-/* Received private message. This resolves the destination of the message
- and sends the packet. This is used by both server and router. If the
- destination is our locally connected client this sends the packet to
- the client. This may also send the message for further routing if
- the destination is not in our server (or router). */
-
-void silc_server_private_message(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketContext *packet)
-{
- SilcClientID *id;
- SilcServerEntry router;
- SilcSocketConnection dst_sock;
- SilcClientEntry client;
- SilcIDListData idata;
-
- SILC_LOG_DEBUG(("Start"));
-
- if (!packet->dst_id) {
- SILC_LOG_ERROR(("Bad Client ID in private message packet, dropped"));
- goto err;
- }
-
- /* Decode destination Client ID */
- id = silc_id_str2id(packet->dst_id, SILC_ID_CLIENT);
- if (!id) {
- SILC_LOG_ERROR(("Could not decode destination Client ID, dropped"));
- goto err;
- }
-
- /* If the destination belongs to our server we don't have to route
- the message anywhere but to send it to the local destination. */
- client = silc_idlist_find_client_by_id(server->local_list, id);
- if (client) {
- /* It exists, now deliver the message to the destination */
- dst_sock = (SilcSocketConnection)client->connection;
-
- /* If we are router and the client has router then the client is in
- our cell but not directly connected to us. */
- if (server->server_type == SILC_ROUTER && client->router) {
- /* We are of course in this case the client's router thus the real
- "router" of the client is the server who owns the client. Thus
- we will send the packet to that server. */
- router = (SilcServerEntry)dst_sock->user_data;
- idata = (SilcIDListData)router;
- // assert(client->router == server->id_entry);
-
- silc_server_private_message_send_internal(server, dst_sock,
- idata->send_key,
- idata->hmac,
- packet);
- return;
- }
-
- /* Seems that client really is directly connected to us */
- idata = (SilcIDListData)client;
- silc_server_private_message_send_internal(server, dst_sock,
- idata->send_key,
- idata->hmac, packet);
- return;
- }
-
- /* Destination belongs to someone not in this server. If we are normal
- server our action is to send the packet to our router. */
- if (server->server_type == SILC_SERVER && !server->standalone) {
- router = server->router;
-
- /* Send to primary route */
- if (router) {
- dst_sock = (SilcSocketConnection)router->connection;
- idata = (SilcIDListData)router;
- silc_server_private_message_send_internal(server, dst_sock,
- idata->send_key,
- idata->hmac, packet);
- }
- return;
- }
-
- /* We are router and we will perform route lookup for the destination
- and send the message to fastest route. */
- if (server->server_type == SILC_ROUTER && !server->standalone) {
- dst_sock = silc_server_get_route(server, id, SILC_ID_CLIENT);
- router = (SilcServerEntry)dst_sock->user_data;
- idata = (SilcIDListData)router;
-
- /* Get fastest route and send packet. */
- if (router)
- silc_server_private_message_send_internal(server, dst_sock,
- idata->send_key,
- idata->hmac, packet);
- return;
- }
-
- err:
- silc_server_send_error(server, sock,
- "No such nickname: Private message not sent");
-}
-
-/* Process received channel message. The message can be originated from
- client or server. */
-
-void silc_server_channel_message(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketContext *packet)
-{
- SilcChannelEntry channel = NULL;
- SilcChannelClientEntry chl;
- SilcChannelID *id = NULL;
- void *sender = NULL;
-
- SILC_LOG_DEBUG(("Processing channel message"));
-
- /* Sanity checks */
- if (packet->dst_id_type != SILC_ID_CHANNEL) {
- SILC_LOG_ERROR(("Received bad message for channel, dropped"));
- SILC_LOG_DEBUG(("Received bad message for channel, dropped"));
- goto out;
- }
-
- /* Find channel entry */
- id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
- channel = silc_idlist_find_channel_by_id(server->local_list, id);
- if (!channel) {
- SILC_LOG_DEBUG(("Could not find channel"));
- goto out;
- }
-
- /* See that this client is on the channel. If the message is coming
- from router we won't do the check as the message is from client that
- we don't know about. Also, if the original sender is not client
- (as it can be server as well) we don't do the check. */
- sender = silc_id_str2id(packet->src_id, packet->src_id_type);
- if (sock->type != SILC_SOCKET_TYPE_ROUTER &&
- packet->src_id_type == SILC_ID_CLIENT) {
- silc_list_start(channel->user_list);
- while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
- if (chl->client && !SILC_ID_CLIENT_COMPARE(chl->client->id, sender))
- break;
- }
- if (chl == SILC_LIST_END)
- goto out;
- }
-
- /* Distribute the packet to our local clients. This will send the
- packet for further routing as well, if needed. */
- 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);
-}
-
-/* Received channel key packet. We distribute the key to all of our locally
- 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,
- SilcPacketContext *packet)
-{
- SilcBuffer buffer = packet->buffer;
- SilcChannelKeyPayload payload = NULL;
- SilcChannelID *id = NULL;
- SilcChannelEntry channel;
- SilcChannelClientEntry chl;
- unsigned char *tmp;
- unsigned int tmp_len;
- char *cipher;
-
- if (packet->src_id_type != SILC_ID_SERVER &&
- sock->type != SILC_SOCKET_TYPE_ROUTER)
- goto out;
-
- /* Decode channel key payload */
- payload = silc_channel_key_payload_parse(buffer);
- if (!payload) {
- SILC_LOG_ERROR(("Bad channel key payload, dropped"));
- goto out;
- }
-
- /* Get channel ID */
- tmp = silc_channel_key_get_id(payload, &tmp_len);
- id = silc_id_payload_parse_id(tmp, tmp_len);
- if (!id)
- goto out;
-
- /* Get the channel entry */
- channel = silc_idlist_find_channel_by_id(server->local_list, id);
- if (!channel) {
- SILC_LOG_ERROR(("Received key for non-existent channel"));
- goto out;
- }
-
- /* Save the key for us as well */
- tmp = silc_channel_key_get_key(payload, &tmp_len);
- if (!tmp)
- goto out;
- cipher = silc_channel_key_get_cipher(payload, NULL);;
- if (!cipher)
- goto out;
- if (!silc_cipher_alloc(cipher, &channel->channel_key))
- goto out;
-
- /* Distribute the key to all clients on the channel */
- silc_list_start(channel->user_list);
- while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
- silc_server_packet_send(server, chl->client->connection,
- SILC_PACKET_CHANNEL_KEY, 0,
- buffer->data, buffer->len, TRUE);
- }
-
- channel->key_len = tmp_len * 8;
- channel->key = silc_calloc(tmp_len, sizeof(unsigned char));
- memcpy(channel->key, tmp, tmp_len);
- channel->channel_key->cipher->set_key(channel->channel_key->context,
- tmp, tmp_len);
- out:
- if (id)
- silc_free(id);
- if (payload)
- silc_channel_key_payload_free(payload);
-}
-
-/* Sends current motd to client */
-
-void silc_server_send_motd(SilcServer server,
- SilcSocketConnection sock)
-{
- char *motd;
- int motd_len;
-
- if (server->config && server->config->motd &&
- server->config->motd->motd_file) {
-
- motd = silc_file_read(server->config->motd->motd_file, &motd_len);
- if (!motd)
- return;
-
- silc_server_send_notify(server, sock, SILC_NOTIFY_TYPE_MOTD, 1,
- motd, motd_len);
- silc_free(motd);
- }
-}
-
-/* Sends error message. Error messages may or may not have any
- implications. */
-
-void silc_server_send_error(SilcServer server,
- SilcSocketConnection sock,
- const char *fmt, ...)
-{
- va_list ap;
- unsigned char buf[4096];
-
- memset(buf, 0, sizeof(buf));
- va_start(ap, fmt);
- vsprintf(buf, fmt, ap);
- va_end(ap);
-
- silc_server_packet_send(server, sock, SILC_PACKET_ERROR, 0,
- buf, strlen(buf), FALSE);
-}
-
-/* Sends notify message. If format is TRUE the variable arguments are
- formatted and the formatted string is sent as argument payload. If it is
- FALSE then each argument is sent as separate argument and their format
- in the argument list must be { argument data, argument length }. */
-
-void silc_server_send_notify(SilcServer server,
- SilcSocketConnection sock,
- SilcNotifyType type,
- unsigned int argc, ...)
-{
- va_list ap;
- SilcBuffer packet;
-
- va_start(ap, argc);
-
- packet = silc_notify_payload_encode(type, argc, ap);
- silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 0,
- packet->data, packet->len, FALSE);
- silc_buffer_free(packet);
-}
-
-/* Sends notify message destined to specific entity. */
-
-void silc_server_send_notify_dest(SilcServer server,
- SilcSocketConnection sock,
- void *dest_id,
- SilcIdType dest_id_type,
- SilcNotifyType type,
- unsigned int argc, ...)
-{
- va_list ap;
- SilcBuffer packet;
-
- va_start(ap, argc);
-
- packet = silc_notify_payload_encode(type, argc, ap);
- silc_server_packet_send_dest(server, sock, SILC_PACKET_NOTIFY, 0,
- dest_id, dest_id_type,
- packet->data, packet->len, FALSE);
- silc_buffer_free(packet);
-}
-
-/* Sends notify message to a channel. The notify message sent is
- distributed to all clients on the channel. */
-
-void silc_server_send_notify_to_channel(SilcServer server,
- SilcChannelEntry channel,
- SilcNotifyType type,
- unsigned int argc, ...)
-{
- va_list ap;
- SilcBuffer packet;
-
- va_start(ap, argc);
-
- packet = silc_notify_payload_encode(type, argc, ap);
- silc_server_packet_send_to_channel(server, channel,
- SILC_PACKET_NOTIFY,
- packet->data, packet->len, FALSE);
- silc_buffer_free(packet);
-}
-
-/* Send notify message to all clients the client has joined. It is quaranteed
- that the message is sent only once to a client (ie. if a client is joined
- on two same channel it will receive only one notify message). Also, this
- sends only to local clients (locally connected if we are server, and to
- local servers if we are router). */
+/* Creates new channel. Sends NEW_CHANNEL packet to primary route. This
+ function may be used only by router. In real SILC network all channels
+ are created by routers thus this function is never used by normal
+ server. */
-void silc_server_send_notify_on_channels(SilcServer server,
- SilcClientEntry client,
- SilcNotifyType type,
- unsigned int argc, ...)
-{
- int k;
- SilcSocketConnection sock = NULL;
- SilcPacketContext packetdata;
- SilcClientEntry c;
- SilcClientEntry *sent_clients = NULL;
- unsigned int sent_clients_count = 0;
- SilcServerEntry *routed = NULL;
- unsigned int routed_count = 0;
- SilcChannelEntry channel;
- SilcChannelClientEntry chl, chl2;
- SilcIDListData idata;
- SilcBuffer packet;
- unsigned char *data;
- unsigned int data_len;
- int force_send = FALSE;
- va_list ap;
-
- if (!silc_list_count(client->channels))
- return;
-
- va_start(ap, argc);
- packet = silc_notify_payload_encode(type, argc, ap);
- data = packet->data;
- data_len = packet->len;
-
- /* Set the packet context pointers. */
- 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_type = SILC_ID_SERVER;
- packetdata.rng = server->rng;
-
- silc_list_start(client->channels);
- while ((chl = silc_list_get(client->channels)) != SILC_LIST_END) {
- 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) {
- c = chl2->client;
-
- /* Check if we have sent the packet to this client already */
- for (k = 0; k < sent_clients_count; k++)
- if (sent_clients[k] == c)
- break;
- if (k < sent_clients_count)
- continue;
-
- /* If we are router and if this client has router set it is not
- locally connected client and we will route the message to the
- router set in the client. */
- if (c && c->router && server->server_type == SILC_ROUTER) {
- /* Check if we have sent the packet to this route already */
- for (k = 0; k < routed_count; k++)
- if (routed[k] == c->router)
- break;
- if (k < routed_count)
- continue;
-
- /* Get data used in packet header encryption, keys and stuff. */
- sock = (SilcSocketConnection)c->router->connection;
- 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_type = SILC_ID_SERVER;
- packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
- packetdata.src_id_len + packetdata.dst_id_len;
- packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
-
- /* Send the packet */
- silc_server_packet_send_to_channel_real(server, sock, &packetdata,
- idata->send_key, idata->hmac,
- data, data_len, FALSE,
- force_send);
-
- silc_free(packetdata.dst_id);
-
- /* We want to make sure that the packet is routed to same router
- only once. Mark this route as sent route. */
- k = routed_count;
- routed = silc_realloc(routed, sizeof(*routed) * (k + 1));
- routed[k] = c->router;
- routed_count++;
-
- continue;
- }
-
- /* Send to locally connected client */
- if (c) {
-
- /* Get data used in packet header encryption, keys and stuff. */
- sock = (SilcSocketConnection)c->connection;
- 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_type = SILC_ID_CLIENT;
- packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
- packetdata.src_id_len + packetdata.dst_id_len;
- packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
-
- /* Send the packet */
- silc_server_packet_send_to_channel_real(server, sock, &packetdata,
- idata->send_key, idata->hmac,
- data, data_len, FALSE,
- force_send);
-
- silc_free(packetdata.dst_id);
-
- /* Make sure that we send the notify only once per client. */
- sent_clients = silc_realloc(sent_clients, sizeof(*sent_clients) *
- (sent_clients_count + 1));
- sent_clients[sent_clients_count] = c;
- sent_clients_count++;
- }
- }
- }
-
- if (routed_count)
- silc_free(routed);
- if (sent_clients_count)
- silc_free(sent_clients);
- silc_free(packetdata.src_id);
-}
-
-/* Sends New ID Payload to remote end. The packet is used to distribute
- information about new registered clients, servers, channel etc. usually
- to routers so that they can keep these information up to date.
- If the argument `broadcast' is TRUE then the packet is sent as
- broadcast packet. */
-
-void silc_server_send_new_id(SilcServer server,
- SilcSocketConnection sock,
- int broadcast,
- void *id, SilcIdType id_type,
- unsigned int id_len)
-{
- SilcBuffer idp;
-
- 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);
- silc_buffer_free(idp);
-}
-
-/* Sends Replace ID payload to remote end. This is used to replace old
- ID with new ID sent in the packet. This is called for example when
- user changes nickname and we create new ID for the user. If the
- argument `broadcast' is TRUE then the packet is sent as
- broadcast packet. */
-/* XXX It would be expected that the new id is same type as the old
- ID. :) */
-
-void silc_server_send_replace_id(SilcServer server,
- SilcSocketConnection sock,
- int broadcast,
- void *old_id, SilcIdType old_id_type,
- unsigned int old_id_len,
- void *new_id, SilcIdType new_id_type,
- unsigned int new_id_len)
-{
- SilcBuffer packet;
- unsigned char *oid;
- unsigned char *nid;
-
- oid = silc_id_id2str(old_id, old_id_type);
- if (!oid)
- return;
-
- nid = silc_id_id2str(new_id, new_id_type);
- if (!nid)
- return;
-
- packet = silc_buffer_alloc(2 + 2 + 2 + 2 + old_id_len + new_id_len);
- silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
- silc_buffer_format(packet,
- SILC_STR_UI_SHORT(old_id_type),
- SILC_STR_UI_SHORT(old_id_len),
- SILC_STR_UI_XNSTRING(oid, old_id_len),
- SILC_STR_UI_SHORT(new_id_type),
- SILC_STR_UI_SHORT(new_id_len),
- SILC_STR_UI_XNSTRING(nid, new_id_len),
- SILC_STR_END);
-
- silc_server_packet_send(server, sock, SILC_PACKET_REPLACE_ID,
- broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
- packet->data, packet->len, FALSE);
- silc_free(oid);
- silc_free(nid);
- silc_buffer_free(packet);
-}
-
-/* This function is used to send Remove Channel User payload. This may sent
- by server but is usually used only by router to notify other routers that
- user has left a channel. Normal server sends this packet to its router
- to notify that the router should not hold a record about this client
- on a channel anymore. Router distributes it further to other routers. */
-
-void silc_server_send_remove_channel_user(SilcServer server,
- SilcSocketConnection sock,
- int broadcast,
- void *client_id, void *channel_id)
-{
- SilcBuffer packet;
- unsigned char *clid, *chid;
-
- clid = silc_id_id2str(client_id, SILC_ID_CLIENT);
- if (!clid)
- return;
-
- chid = silc_id_id2str(channel_id, SILC_ID_CHANNEL);
- if (!chid)
- return;
-
- packet = silc_buffer_alloc(2 + 2 + SILC_ID_CLIENT_LEN + SILC_ID_CHANNEL_LEN);
- silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
- silc_buffer_format(packet,
- SILC_STR_UI_SHORT(SILC_ID_CLIENT_LEN),
- SILC_STR_UI_XNSTRING(clid, SILC_ID_CLIENT_LEN),
- SILC_STR_UI_SHORT(SILC_ID_CHANNEL_LEN),
- SILC_STR_UI_XNSTRING(chid, SILC_ID_CHANNEL_LEN),
- SILC_STR_END);
-
- silc_server_packet_send(server, sock, SILC_PACKET_REMOVE_CHANNEL_USER,
- broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
- packet->data, packet->len, FALSE);
- silc_free(clid);
- silc_free(chid);
- silc_buffer_free(packet);
-}
-
-/* Received packet to replace a ID. This checks that the requested ID
- exists and replaces it with the new one. */
-
-void silc_server_replace_id(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketContext *packet)
-{
- SilcBuffer buffer = packet->buffer;
- unsigned char *old_id = NULL, *new_id = NULL;
- SilcIdType old_id_type, new_id_type;
- unsigned short old_id_len, new_id_len;
- void *id = NULL, *id2 = NULL;
-
- if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
- packet->src_id_type == SILC_ID_CLIENT)
- return;
-
- SILC_LOG_DEBUG(("Replacing ID"));
-
- silc_buffer_unformat(buffer,
- SILC_STR_UI_SHORT(&old_id_type),
- SILC_STR_UI16_NSTRING_ALLOC(&old_id, &old_id_len),
- SILC_STR_UI_SHORT(&new_id_type),
- SILC_STR_UI16_NSTRING_ALLOC(&new_id, &new_id_len),
- SILC_STR_END);
-
- if (old_id_type != new_id_type)
- goto out;
-
- if (old_id_len != silc_id_get_len(old_id_type) ||
- new_id_len != silc_id_get_len(new_id_type))
- goto out;
-
- id = silc_id_str2id(old_id, old_id_type);
- if (!id)
- goto out;
-
- id2 = silc_id_str2id(new_id, new_id_type);
- if (!id2)
- goto out;
-
- /* If we are router and this packet is not already broadcast packet
- we will broadcast it. The sending socket really cannot be router or
- the router is buggy. If this packet is coming from router then it must
- have the broadcast flag set already and we won't do anything. */
- if (server->server_type == SILC_ROUTER &&
- sock->type == SILC_SOCKET_TYPE_SERVER &&
- !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
- SILC_LOG_DEBUG(("Broadcasting received Replace ID packet"));
- silc_server_packet_send(server, server->router->connection, packet->type,
- packet->flags | SILC_PACKET_FLAG_BROADCAST,
- buffer->data, buffer->len, FALSE);
- }
-
- /* Replace the old ID */
- switch(old_id_type) {
- case SILC_ID_CLIENT:
- if (silc_idlist_replace_client_id(server->local_list, id, id2) == NULL)
- if (server->server_type == SILC_ROUTER)
- silc_idlist_replace_client_id(server->global_list, id, id2);
- break;
-
- case SILC_ID_SERVER:
- if (silc_idlist_replace_server_id(server->local_list, id, id2) == NULL)
- if (server->server_type == SILC_ROUTER)
- silc_idlist_replace_server_id(server->global_list, id, id2);
- break;
-
- case SILC_ID_CHANNEL:
- /* XXX Hmm... Basically this cannot occur. Channel ID's cannot be
- re-generated. */
- silc_free(id2);
- break;
-
- default:
- silc_free(id2);
- break;
- }
-
- out:
- if (id)
- silc_free(id);
- if (old_id)
- silc_free(old_id);
- if (new_id)
- silc_free(new_id);
-}
-
-/* Creates new channel. */
-
-SilcChannelEntry silc_server_new_channel(SilcServer server,
- SilcServerID *router_id,
- char *cipher, char *channel_name)
+SilcChannelEntry silc_server_create_new_channel(SilcServer server,
+ SilcServerID *router_id,
+ char *cipher,
+ char *channel_name)
{
int i, key_len;
SilcChannelID *channel_id;
/* Notify other routers about the new channel. We send the packet
to our primary route. */
if (server->standalone == FALSE) {
- silc_server_send_new_id(server, server->router->connection,
- server->server_type == SILC_SERVER ? FALSE : TRUE,
- entry->id, SILC_ID_CHANNEL, SILC_ID_CHANNEL_LEN);
+ silc_server_send_new_channel(server, server->router->connection, TRUE,
+ channel_name, entry->id, SILC_ID_CHANNEL_LEN);
}
return entry;
}
-
-/* Create new client. This processes incoming NEW_CLIENT packet and creates
- Client ID for the client. Client becomes registered after calling this
- functions. */
-
-SilcClientEntry silc_server_new_client(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketContext *packet)
-{
- SilcBuffer buffer = packet->buffer;
- SilcClientEntry client;
- SilcIDCacheEntry cache;
- SilcClientID *client_id;
- SilcBuffer reply;
- SilcIDListData idata;
- char *username = NULL, *realname = NULL, *id_string;
-
- SILC_LOG_DEBUG(("Creating new client"));
-
- if (sock->type != SILC_SOCKET_TYPE_CLIENT)
- return NULL;
-
- /* Take client entry */
- client = (SilcClientEntry)sock->user_data;
- idata = (SilcIDListData)client;
-
- /* Fetch the old client cache entry so that we can update it. */
- if (!silc_idcache_find_by_context(server->local_list->clients,
- sock->user_data, &cache)) {
- SILC_LOG_ERROR(("Lost client's cache entry - bad thing"));
- return NULL;
- }
-
- /* Parse incoming packet */
- silc_buffer_unformat(buffer,
- SILC_STR_UI16_STRING_ALLOC(&username),
- SILC_STR_UI16_STRING_ALLOC(&realname),
- SILC_STR_END);
-
- /* Create Client ID */
- silc_id_create_client_id(server->id, server->rng, server->md5hash,
- username, &client_id);
-
- /* Update client entry */
- idata->registered = TRUE;
- client->nickname = strdup(username);
- client->username = username;
- client->userinfo = realname;
- client->id = client_id;
-
- /* Update the cache entry */
- cache->id = (void *)client_id;
- cache->type = SILC_ID_CLIENT;
- cache->data = username;
- silc_idcache_sort_by_data(server->local_list->clients);
-
- /* Notify our router about new client on the SILC network */
- if (!server->standalone)
- silc_server_send_new_id(server, (SilcSocketConnection)
- server->router->connection,
- server->server_type == SILC_ROUTER ? TRUE : FALSE,
- client->id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
-
- /* Send the new client ID to the client. */
- id_string = silc_id_id2str(client->id, SILC_ID_CLIENT);
- reply = silc_buffer_alloc(2 + 2 + SILC_ID_CLIENT_LEN);
- silc_buffer_pull_tail(reply, SILC_BUFFER_END(reply));
- silc_buffer_format(reply,
- SILC_STR_UI_SHORT(SILC_ID_CLIENT),
- SILC_STR_UI_SHORT(SILC_ID_CLIENT_LEN),
- SILC_STR_UI_XNSTRING(id_string, SILC_ID_CLIENT_LEN),
- SILC_STR_END);
- silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID, 0,
- reply->data, reply->len, FALSE);
- silc_free(id_string);
- silc_buffer_free(reply);
-
- /* Send some nice info to the client */
- SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
- ("Welcome to the SILC Network %s@%s",
- username, sock->hostname));
- SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
- ("Your host is %s, running version %s",
- server->config->server_info->server_name,
- server_version));
- SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
- ("Your connection is secured with %s cipher, "
- "key length %d bits",
- idata->send_key->cipher->name,
- idata->send_key->cipher->key_len));
- SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
- ("Your current nickname is %s",
- client->nickname));
-
- /* Send motd */
- silc_server_send_motd(server, sock);
-
- return client;
-}
-
-/* Create new server. This processes incoming NEW_SERVER packet and
- saves the received Server ID. The server is our locally connected
- server thus we save all the information and save it to local list.
- This funtion can be used by both normal server and router server.
- If normal server uses this it means that its router has connected
- to the server. If router uses this it means that one of the cell's
- servers is connected to the router. */
-
-SilcServerEntry silc_server_new_server(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketContext *packet)
-{
- SilcBuffer buffer = packet->buffer;
- SilcServerEntry new_server;
- SilcIDCacheEntry cache;
- SilcServerID *server_id;
- SilcIDListData idata;
- unsigned char *server_name, *id_string;
- unsigned short id_len;
-
- SILC_LOG_DEBUG(("Creating new server"));
-
- if (sock->type != SILC_SOCKET_TYPE_SERVER &&
- sock->type != SILC_SOCKET_TYPE_ROUTER)
- return NULL;
-
- /* Take server entry */
- new_server = (SilcServerEntry)sock->user_data;
- idata = (SilcIDListData)new_server;
-
- /* Fetch the old server cache entry so that we can update it. */
- if (!silc_idcache_find_by_context(server->local_list->servers,
- sock->user_data, &cache)) {
- SILC_LOG_ERROR(("Lost server's cache entry - bad thing"));
- return NULL;
- }
-
- /* Parse the incoming packet */
- silc_buffer_unformat(buffer,
- SILC_STR_UI16_NSTRING_ALLOC(&id_string, &id_len),
- SILC_STR_UI16_STRING_ALLOC(&server_name),
- SILC_STR_END);
-
- if (id_len > buffer->len) {
- silc_free(id_string);
- silc_free(server_name);
- return NULL;
- }
-
- /* Get Server ID */
- server_id = silc_id_str2id(id_string, SILC_ID_SERVER);
- silc_free(id_string);
-
- /* Update client entry */
- idata->registered = TRUE;
- new_server->server_name = server_name;
- new_server->id = server_id;
-
- /* Update the cache entry */
- cache->id = (void *)server_id;
- cache->type = SILC_ID_SERVER;
- cache->data = server_name;
- silc_idcache_sort_by_data(server->local_list->servers);
-
- /* Distribute the information about new server in the SILC network
- to our router. If we are normal server we won't send anything
- since this connection must be our router connection. */
- if (server->server_type == SILC_ROUTER && !server->standalone &&
- server->router->connection != sock)
- silc_server_send_new_id(server, server->router->connection,
- TRUE, new_server->id, SILC_ID_SERVER,
- SILC_ID_SERVER_LEN);
-
- return new_server;
-}
-
-/* Processes incoming New ID Payload. New ID Payload is used to distribute
- information about newly registered clients, servers and created
- channels. */
-
-void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
- SilcPacketContext *packet)
-{
- SilcBuffer buffer = packet->buffer;
- SilcIDList id_list;
- SilcServerEntry tmpserver, router;
- SilcSocketConnection router_sock;
- SilcIDPayload idp;
- SilcIdType id_type;
- void *id, *tmpid;
-
- SILC_LOG_DEBUG(("Processing new ID"));
-
- if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
- server->server_type == SILC_SERVER ||
- packet->src_id_type != SILC_ID_SERVER)
- return;
-
- idp = silc_id_payload_parse(buffer);
- if (!idp)
- return;
-
- id_type = silc_id_payload_get_type(idp);
-
- /* Normal server cannot have other normal server connections */
- if (id_type == SILC_ID_SERVER && sock->type == SILC_SOCKET_TYPE_SERVER)
- goto out;
-
- id = silc_id_payload_get_id(idp);
- if (!id)
- goto out;
-
- /* If the sender of this packet is server and we are router we need to
- broadcast this packet to other routers in the network. */
- if (!server->standalone && server->server_type == SILC_ROUTER &&
- sock->type == SILC_SOCKET_TYPE_SERVER &&
- !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
- SILC_LOG_DEBUG(("Broadcasting received New ID packet"));
- silc_server_packet_send(server, server->router->connection,
- packet->type,
- packet->flags | SILC_PACKET_FLAG_BROADCAST,
- buffer->data, buffer->len, FALSE);
- }
-
- /* If the packet is originated from the one who sent it to us we know
- that the ID belongs to our cell, unless the sender was router. */
- tmpid = silc_id_str2id(packet->src_id, SILC_ID_SERVER);
- tmpserver = (SilcServerEntry)sock->user_data;
-
- if (!SILC_ID_SERVER_COMPARE(tmpid, tmpserver->id) &&
- sock->type == SILC_SOCKET_TYPE_SERVER) {
- id_list = server->local_list;
- router_sock = sock;
- router = sock->user_data;
- /* router = server->id_entry; */
- } else {
- id_list = server->global_list;
- router_sock = (SilcSocketConnection)server->router->connection;
- router = server->router;
- }
-
- silc_free(tmpid);
-
- switch(id_type) {
- case SILC_ID_CLIENT:
- {
- SilcClientEntry idlist;
-
- SILC_LOG_DEBUG(("New client id(%s) from [%s] %s",
- silc_id_render(id, SILC_ID_CLIENT),
- sock->type == SILC_SOCKET_TYPE_SERVER ?
- "Server" : "Router", sock->hostname));
-
- /* Add the client to our local list. We are router and we keep
- cell specific local database of all clients in the cell. */
- idlist = silc_idlist_add_client(id_list, NULL, NULL, NULL,
- id, router, router_sock);
- }
- break;
-
- case SILC_ID_SERVER:
- {
- SilcServerEntry idlist;
-
- SILC_LOG_DEBUG(("New server id(%s) from [%s] %s",
- silc_id_render(id, SILC_ID_SERVER),
- sock->type == SILC_SOCKET_TYPE_SERVER ?
- "Server" : "Router", sock->hostname));
-
- /* Add the server to our local list. We are router and we keep
- cell specific local database of all servers in the cell. */
- idlist = silc_idlist_add_server(id_list, NULL, 0, id, router,
- router_sock);
- }
- break;
-
- case SILC_ID_CHANNEL:
- SILC_LOG_DEBUG(("New channel id(%s) from [%s] %s",
- silc_id_render(id, SILC_ID_CHANNEL),
- sock->type == SILC_SOCKET_TYPE_SERVER ?
- "Server" : "Router", sock->hostname));
-
- /* Add the channel to our local list. We are router and we keep
- cell specific local database of all channels in the cell. */
- silc_idlist_add_channel(id_list, NULL, 0, id, router, NULL);
- break;
-
- default:
- break;
- }
-
- out:
- silc_id_payload_free(idp);
-}
-
-/* Received packet to remove a user from a channel. Routers notify other
- routers that user has left a channel. Client must not send this packet.
- Normal server may send this packet but ignores if it receives one. */
-
-void silc_server_remove_channel_user(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketContext *packet)
-{
- SilcBuffer buffer = packet->buffer;
- unsigned char *tmp1 = NULL, *tmp2 = NULL;
- SilcClientID *client_id = NULL;
- SilcChannelID *channel_id = NULL;
- SilcChannelEntry channel;
- SilcClientEntry client;
-
- SILC_LOG_DEBUG(("Removing user from channel"));
-
- if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
- server->server_type == SILC_SERVER)
- return;
-
- silc_buffer_unformat(buffer,
- SILC_STR_UI16_STRING_ALLOC(&tmp1),
- SILC_STR_UI16_STRING_ALLOC(&tmp2),
- SILC_STR_END);
-
- if (!tmp1 || !tmp2)
- goto out;
-
- client_id = silc_id_str2id(tmp1, SILC_ID_CLIENT);
- channel_id = silc_id_str2id(tmp2, SILC_ID_CHANNEL);
- if (!client_id || !channel_id)
- goto out;
-
- /* If we are router and this packet is not already broadcast packet
- we will broadcast it. The sending socket really cannot be router or
- the router is buggy. If this packet is coming from router then it must
- have the broadcast flag set already and we won't do anything. */
- if (!server->standalone && server->server_type == SILC_ROUTER &&
- sock->type == SILC_SOCKET_TYPE_SERVER &&
- !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
- SILC_LOG_DEBUG(("Broadcasting received Remove Channel User packet"));
- silc_server_packet_send(server, server->router->connection, packet->type,
- packet->flags | SILC_PACKET_FLAG_BROADCAST,
- buffer->data, buffer->len, FALSE);
- }
-
- /* XXX routers should check server->global_list as well */
- /* Get channel entry */
- channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
- if (!channel)
- goto out;
-
- /* XXX routers should check server->global_list as well */
- /* Get client entry */
- client = silc_idlist_find_client_by_id(server->local_list, client_id);
- if (!client)
- goto out;
-
- /* Remove from channel */
- silc_server_remove_from_one_channel(server, sock, channel, client, FALSE);
-
- out:
- if (tmp1)
- silc_free(tmp1);
- if (tmp2)
- silc_free(tmp2);
- if (client_id)
- silc_free(client_id);
- if (channel_id)
- silc_free(channel_id);
-}
void silc_server_packet_parse_type(SilcServer server,
SilcSocketConnection sock,
SilcPacketContext *packet);
-void silc_server_packet_send(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketType type,
- SilcPacketFlags flags,
- unsigned char *data,
- unsigned int data_len,
- int force_send);
-void silc_server_packet_send_dest(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketType type,
- SilcPacketFlags flags,
- void *dst_id,
- SilcIdType dst_id_type,
- unsigned char *data,
- unsigned int data_len,
- int force_send);
-void silc_server_packet_forward(SilcServer server,
- SilcSocketConnection sock,
- unsigned char *data, unsigned int data_len,
- int force_send);
-void silc_server_packet_broadcast(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketContext *packet);
-void silc_server_packet_send_to_channel(SilcServer server,
- SilcChannelEntry channel,
- SilcPacketType type,
- unsigned char *data,
- unsigned int data_len,
- int force_send);
-void silc_server_packet_relay_to_channel(SilcServer server,
- SilcSocketConnection sender_sock,
- SilcChannelEntry channel,
- void *sender,
- SilcIdType sender_type,
- unsigned char *data,
- unsigned int data_len,
- int force_send);
-void silc_server_packet_send_local_channel(SilcServer server,
- SilcChannelEntry channel,
- SilcPacketType type,
- SilcPacketFlags flags,
- unsigned char *data,
- unsigned int data_len,
- int force_send);
-void silc_server_packet_relay_command_reply(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketContext *packet);
void silc_server_close_connection(SilcServer server,
SilcSocketConnection sock);
void silc_server_free_sock_user_data(SilcServer server,
void silc_server_disconnect_remote(SilcServer server,
SilcSocketConnection sock,
const char *fmt, ...);
-void silc_server_private_message(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketContext *packet);
-void silc_server_channel_message(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketContext *packet);
-void silc_server_channel_key(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketContext *packet);
-void silc_server_send_motd(SilcServer server,
- SilcSocketConnection sock);
-void silc_server_send_error(SilcServer server,
- SilcSocketConnection sock,
- const char *fmt, ...);
-void silc_server_send_notify(SilcServer server,
- SilcSocketConnection sock,
- SilcNotifyType type,
- unsigned int argc, ...);
-void silc_server_send_notify_dest(SilcServer server,
- SilcSocketConnection sock,
- void *dest_id,
- SilcIdType dest_id_type,
- SilcNotifyType type,
- unsigned int argc, ...);
-void silc_server_send_notify_to_channel(SilcServer server,
- SilcChannelEntry channel,
- SilcNotifyType type,
- unsigned int argc, ...);
-void silc_server_send_notify_on_channels(SilcServer server,
- SilcClientEntry client,
- SilcNotifyType type,
- unsigned int argc, ...);
-void silc_server_send_new_id(SilcServer server,
- SilcSocketConnection sock,
- int broadcast,
- void *id, SilcIdType id_type,
- unsigned int id_len);
-void silc_server_send_replace_id(SilcServer server,
- SilcSocketConnection sock,
- int broadcast,
- void *old_id, SilcIdType old_id_type,
- unsigned int old_id_len,
- void *new_id, SilcIdType new_id_type,
- unsigned int new_id_len);
-void silc_server_send_remove_channel_user(SilcServer server,
- SilcSocketConnection sock,
- int broadcast,
- void *client_id, void *channel_id);
-void silc_server_replace_id(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketContext *packet);
-SilcChannelEntry silc_server_new_channel(SilcServer server,
- SilcServerID *router_id,
- char *cipher, char *channel_name);
-SilcClientEntry silc_server_new_client(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketContext *packet);
-SilcServerEntry silc_server_new_server(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketContext *packet);
-void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
- SilcPacketContext *packet);
-void silc_server_remove_channel_user(SilcServer server,
- SilcSocketConnection sock,
- SilcPacketContext *packet);
+SilcChannelEntry silc_server_create_new_channel(SilcServer server,
+ SilcServerID *router_id,
+ char *cipher,
+ char *channel_name);
#endif