Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
- Copyright (C) 1997 - 2000 Pekka Riikonen
+ Copyright (C) 1997 - 2001 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
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
/* 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);
+ id = silc_id_str2id(packet->src_id, packet->src_id_len, packet->src_id_type);
if (id && SILC_ID_SERVER_COMPARE(id, server->router->id)) {
idata = (SilcIDListData)sock->user_data;
silc_free(id);
}
+/* Routes received packet to `sock'. This is used to route the packets that
+ router receives but are not destined to it. */
+
+void silc_server_packet_route(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcBuffer buffer = packet->buffer;
+ SilcIDListData idata;
+
+ SILC_LOG_DEBUG(("Routing received packet"));
+
+ 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(("Routed 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);
+}
+
/* 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
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. */
+ be routed anywhere (for router locally means cell wide). If `sender'
+ is provided then the packet is not sent to that connection since it
+ originally came from it. */
void silc_server_packet_send_to_channel(SilcServer server,
+ SilcSocketConnection sender,
SilcChannelEntry channel,
SilcPacketType type,
unsigned char route,
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);
+ if (sock != sender) {
+ 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. */
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) {
+ we will route the message to the router set in the client. Though,
+ send locally connected server in all cases. */
+ if (server->server_type == SILC_ROUTER && client && client->router &&
+ ((!route && client->router->router == server->id_entry) || route)) {
int k;
/* Check if we have sent the packet to this route already */
sock = (SilcSocketConnection)client->router->connection;
idata = (SilcIDListData)client->router;
+ if (sender && sock == sender)
+ continue;
+
/* Send the packet */
silc_server_packet_send_to_channel_real(server, sock, &packetdata,
idata->send_key, idata->hmac,
continue;
}
+ if (client && client->router)
+ continue;
+
/* Send to locally connected client */
if (client) {
sock = (SilcSocketConnection)client->connection;
idata = (SilcIDListData)client;
+ if (sender && sock == sender)
+ continue;
+
/* Send the packet */
silc_server_packet_send_to_channel_real(server, sock, &packetdata,
idata->send_key, idata->hmac,
sock = (SilcSocketConnection)client->router->connection;
idata = (SilcIDListData)client->router;
+ if (sender_sock && sock == sender_sock)
+ continue;
+
+ SILC_LOG_DEBUG(("Relaying packet to client ID(%s) %s (%s)",
+ silc_id_render(client->id, SILC_ID_CLIENT),
+ sock->hostname, sock->ip));
+
/* Send the packet */
silc_server_packet_send_to_channel_real(server, sock, &packetdata,
idata->send_key, idata->hmac,
continue;
}
- /* XXX Check client's mode on the channel. */
+ if (client && client->router)
+ continue;
/* 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));
+ if (sender_sock && sock == sender_sock)
+ continue;
+
+ SILC_LOG_DEBUG(("Sending packet to client ID(%s) %s (%s)",
+ silc_id_render(client->id, SILC_ID_CLIENT),
+ sock->hostname, sock->ip));
/* Send the packet */
silc_server_packet_send_to_channel_real(server, sock, &packetdata,
unsigned int data_len,
int force_send)
{
- SilcClientEntry client;
SilcChannelClientEntry chl;
SilcSocketConnection sock = NULL;
/* 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;
+ if (chl->client && !chl->client->router) {
+ sock = (SilcSocketConnection)chl->client->connection;
/* Send the packet to the client */
- silc_server_packet_send_dest(server, sock, type, flags, client->id,
+ silc_server_packet_send_dest(server, sock, type, flags, chl->client->id,
SILC_ID_CLIENT, data, data_len,
force_send);
}
/* 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. */
+ If FALSE it is assured that the notify is sent only locally. If `sender'
+ is provided then the packet is not sent to that connection since it
+ originally came from it. */
void silc_server_send_notify_to_channel(SilcServer server,
+ SilcSocketConnection sender,
SilcChannelEntry channel,
unsigned char route_notify,
SilcNotifyType type,
va_start(ap, argc);
packet = silc_notify_payload_encode(type, argc, ap);
- silc_server_packet_send_to_channel(server, channel,
+ silc_server_packet_send_to_channel(server, sender, channel,
SILC_PACKET_NOTIFY, route_notify,
packet->data, packet->len, FALSE);
silc_buffer_free(packet);
continue;
}
+ if (c && c->router)
+ continue;
+
/* Send to locally connected client */
if (c) {
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_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;
+ clid = silc_id_id2str(client_id, SILC_ID_CLIENT);
+ if (!clid)
+ 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_free(chid);
silc_buffer_free(packet);
}
+
+/* Send Channel Key payload to distribute the new channel key. Normal server
+ sends this to router when new client joins to existing channel. Router
+ sends this to the local server who sent the join command in case where
+ the channel did not exist yet. Both normal and router servers uses this
+ also to send this to locally connected clients on the channel. This
+ must not be broadcasted packet. Routers do not send this to each other.
+ If `sender is provided then the packet is not sent to that connection since
+ it originally came from it. */
+
+void silc_server_send_channel_key(SilcServer server,
+ SilcSocketConnection sender,
+ SilcChannelEntry channel,
+ unsigned char route)
+{
+ SilcBuffer packet;
+ unsigned char *chid;
+ unsigned int tmp_len;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ chid = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+ if (!chid)
+ return;
+
+ /* Encode channel key packet */
+ tmp_len = strlen(channel->channel_key->cipher->name);
+ packet = silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN, chid, tmp_len,
+ channel->channel_key->cipher->name,
+ channel->key_len / 8, channel->key);
+
+ silc_server_packet_send_to_channel(server, sender, channel,
+ SILC_PACKET_CHANNEL_KEY,
+ route, packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+ silc_free(chid);
+}
+
+/* Generic function to send any command. The arguments must be sent already
+ encoded into correct form in correct order. */
+
+void silc_server_send_command(SilcServer server,
+ SilcSocketConnection sock,
+ SilcCommand command,
+ unsigned int argc, ...)
+{
+ SilcBuffer packet;
+ va_list ap;
+
+ va_start(ap, argc);
+
+ packet = silc_command_payload_encode_vap(command, 0, argc, ap);
+ silc_server_packet_send(server, sock, SILC_PACKET_COMMAND, 0,
+ packet->data, packet->len, TRUE);
+ silc_buffer_free(packet);
+}
+
+/* Function used to send REMOVE_ID packet. The packet is used to notify
+ routers that certain ID should be removed. After that the ID will become
+ invalid. If the argument `broadcast' is TRUE then the packet is sent as
+ broadcast packet. */
+
+void silc_server_send_remove_id(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ void *id, unsigned int id_len,
+ SilcIdType id_type)
+{
+ SilcBuffer idp;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ idp = silc_id_payload_encode(id, id_type);
+ silc_server_packet_send(server, sock, SILC_PACKET_REMOVE_ID,
+ broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
+ idp->data, idp->len, FALSE);
+ silc_buffer_free(idp);
+}
+
+/* Function used to send SET_MODE packet. The packet is used to notify routers
+ that channel's or client's channel mode was changed. If the argument
+ `broadcast' is TRUE then the packet is sent as broadcast packet. */
+
+void silc_server_send_set_mode(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ int mode_type, unsigned int mode_mask,
+ unsigned int argc, ...)
+{
+ SilcBuffer packet;
+ va_list ap;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ va_start(ap, argc);
+
+ /* Encode Set Mode payload */
+ packet = silc_set_mode_payload_encode(mode_type, mode_mask, argc, ap);
+ if (!packet)
+ return;
+
+ /* Send the packet */
+ silc_server_packet_send(server, sock, SILC_PACKET_SET_MODE,
+ broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
+ packet->data, packet->len, FALSE);
+
+ silc_buffer_free(packet);
+}
+
+/* Send the heartbeat packet. */
+
+void silc_server_send_heartbeat(SilcServer server,
+ SilcSocketConnection sock)
+{
+ silc_server_packet_send(server, sock, SILC_PACKET_HEARTBEAT, 0,
+ NULL, 0, FALSE);
+}