+/* Check whereto relay the received notify packet that was destined
+ to a client. */
+
+static void
+silc_server_packet_process_relay_notify(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcClientID *id;
+ SilcServerEntry router;
+ SilcSocketConnection dst_sock;
+ SilcClientEntry client;
+ SilcIDListData idata;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Decode destination Client ID */
+ id = silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CLIENT);
+ if (!id) {
+ SILC_LOG_ERROR(("Could not decode destination Client ID, dropped"));
+ return;
+ }
+
+ /* If the destination belongs to our server we don't have to route
+ the packet anywhere but to send it to the local destination. */
+ client = silc_idlist_find_client_by_id(server->local_list, id, NULL);
+ if (client) {
+ /* It exists, now deliver the packet 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)client->router;
+ idata = (SilcIDListData)router;
+ silc_server_packet_relay_notify(server, router->connection,
+ idata->send_key,
+ idata->hmac,
+ packet);
+ silc_free(id);
+ return;
+ }
+
+ /* Seems that client really is directly connected to us */
+ idata = (SilcIDListData)client;
+ silc_server_packet_relay_notify(server, dst_sock,
+ idata->send_key,
+ idata->hmac, packet);
+ silc_free(id);
+ 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_packet_relay_notify(server, dst_sock,
+ idata->send_key,
+ idata->hmac, packet);
+ }
+ silc_free(id);
+ return;
+ }
+
+ /* We are router and we will perform route lookup for the destination
+ and send the packet to fastest route. */
+ if (server->server_type == SILC_ROUTER && !server->standalone) {
+ /* Check first that the ID is valid */
+ client = silc_idlist_find_client_by_id(server->global_list, id, NULL);
+ if (client) {
+ dst_sock = silc_server_route_get(server, id, SILC_ID_CLIENT);
+ router = (SilcServerEntry)dst_sock->user_data;
+ idata = (SilcIDListData)router;
+
+ /* Get fastest route and send packet. */
+ if (router)
+ silc_server_packet_relay_notify(server, dst_sock,
+ idata->send_key,
+ idata->hmac, packet);
+ silc_free(id);
+ return;
+ }
+ }
+}
+