--- /dev/null
+/*
+
+ server_st_command_reply.c
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ Copyright (C) 1997 - 2005 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; version 2 of the License.
+
+ 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.
+
+*/
+
+#include "silc.h"
+#include "silcserver.h"
+#include "server_internal.h"
+
+/************************** Types and definitions ***************************/
+
+/* All functions that call the COMMAND_CHECK_STATUS macros must have
+ out: and err: goto labels. */
+
+#define COMMAND_CHECK_STATUS \
+do { \
+ SILC_LOG_DEBUG(("Start")); \
+ if (!silc_command_get_status(cmd->payload, &status, &error)) { \
+ if (SILC_STATUS_IS_ERROR(status)) \
+ goto out; \
+ if (status == SILC_STATUS_LIST_END) \
+ goto out; \
+ goto err; \
+ } \
+} while(0)
+
+
+/************************ Static utility functions **************************/
+
+/* Free's command reply context */
+
+static void silc_server_command_reply_free(SilcServerCommand cmd)
+{
+ /* If pending commmands existed, they will eventually free this context */
+ if (!cmd->pending)
+ silc_server_command_free(cmd);
+}
+
+
+/************************* Command reply received ***************************/
+
+/* Received a COMMAND_REPLY packet. We parse the packet and process the
+ command reply. */
+
+SILC_FSM_STATE(silc_server_st_packet_command_reply)
+{
+ SilcServerThread thread = fsm_context;
+ SilcPacket packet = state_context;
+ SilcEntryData data = silc_packet_get_context(packet->stream);
+ SilcServerCommand cmd;
+ SilcCommandPayload payload;
+ SilcCommand command;
+
+ SILC_LOG_DEBUG(("Process command reply"));
+
+ /* Allocate command context. */
+ cmd = silc_server_command_alloc(thread);
+ if (!cmd) {
+ silc_packet_free(packet);
+ return SILC_FSM_FINISH;
+ }
+
+ cmd->packet = packet;
+
+ /* Get command reply payload from packet */
+ cmd->payload = silc_command_payload_parse(packet->buffer.data,
+ silc_buffer_len(&packet->buffer));
+ if (!cmd->payload) {
+ SILC_LOG_DEBUG(("Bad command reply payload"));
+ silc_server_command_reply_free(cmd);
+ return SILC_FSM_FINISH;
+ }
+
+ /* Client is allowed to send reply only to WHOIS command. */
+ if (data->type == SILC_CONN_CLIENT &&
+ silc_command_get(cmd->payload) != SILC_COMMAND_WHOIS) {
+ silc_server_command_reply_free(cmd);
+ return SILC_FSM_FINISH;
+ }
+
+ /* Get all command pending for this reply */
+ cmd->pending =
+ silc_server_command_pending_get(thread,
+ silc_command_get_ident(cmd->payload));
+
+ silc_fsm_set_state_context(fsm, cmd);
+
+ /* Process command reply */
+ switch (silc_command_get(cmd->payload)) {
+
+ case SILC_COMMAND_WHOIS:
+ /** Command reply WHOIS */
+ silc_fsm_next(fsm, silc_server_st_command_reply_whois);
+ break;
+
+ case SILC_COMMAND_WHOWAS:
+ /** Command reply WHOWAS */
+ silc_fsm_next(fsm, silc_server_st_command_reply_whowas);
+ break;
+
+ case SILC_COMMAND_IDENTIFY:
+ /** Command reply IDENTIFY */
+ silc_fsm_next(fsm, silc_server_st_command_reply_identify);
+ break;
+
+ case SILC_COMMAND_LIST:
+ /** Command reply LIST */
+ silc_fsm_next(fsm, silc_server_st_command_reply_list);
+ break;
+
+ case SILC_COMMAND_INFO:
+ /** Command reply INFO */
+ silc_fsm_next(fsm, silc_server_st_command_reply_info);
+ break;
+
+ case SILC_COMMAND_STATS:
+ /** Command reply STATS */
+ silc_fsm_next(fsm, silc_server_st_command_reply_stats);
+ break;
+
+ case SILC_COMMAND_PING:
+ /** Command reply PING */
+ silc_fsm_next(fsm, silc_server_st_command_reply_ping);
+ break;
+
+ case SILC_COMMAND_JOIN:
+ /** Command reply JOIN */
+ silc_fsm_next(fsm, silc_server_st_command_reply_join);
+ break;
+
+ case SILC_COMMAND_MOTD:
+ /** Command reply MOTD */
+ silc_fsm_next(fsm, silc_server_st_command_reply_motd);
+ break;
+
+ case SILC_COMMAND_WATCH:
+ /** Command reply WATCH */
+ silc_fsm_next(fsm, silc_server_st_command_reply_watch);
+ break;
+
+ case SILC_COMMAND_USERS:
+ /** Command reply USERS */
+ silc_fsm_next(fsm, silc_server_st_command_reply_users);
+ break;
+
+ case SILC_COMMAND_GETKEY:
+ /** Command reply SERVICE */
+ silc_fsm_next(fsm, silc_server_st_command_reply_getkey);
+ break;
+
+ case SILC_COMMAND_SERVICE:
+ /** Command reply SERVICE */
+ silc_fsm_next(fsm, silc_server_st_command_reply_service);
+ break;
+
+ default:
+ SILC_LOG_DEBUG(("Unknown command %d", silc_command_get(cmd->payload)));
+ cmd->pending = NULL;
+ silc_server_command_reply_free(cmd);
+ return SILC_FSM_FINISH;
+ break;
+ }
+
+ /* Statistics */
+
+ return SILC_FSM_CONTINUE;
+}
+
+
+/********************************* WHOIS ************************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_whois)
+{
+ SilcServerThread thread = fsm_context;
+ SilcServerCommand cmd = state_context;
+ SilcStatus status, error;
+
+ COMMAND_CHECK_STATUS;
+
+ out:
+ silc_server_command_pending_signal(cmd);
+ err:
+ silc_server_command_reply_free(cmd);
+
+ return SILC_FSM_FINISH;
+}
+
+
+/********************************* WHOWAS ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_whowas)
+{
+ SilcServerThread thread = fsm_context;
+ SilcServerCommand cmd = state_context;
+ SilcStatus status, error;
+
+ COMMAND_CHECK_STATUS;
+
+ out:
+ silc_server_command_pending_signal(cmd);
+ err:
+ silc_server_command_reply_free(cmd);
+
+ return SILC_FSM_FINISH;
+}
+
+
+/******************************** IDENTIFY **********************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_identify)
+{
+ SilcServerThread thread = fsm_context;
+ SilcServerCommand cmd = state_context;
+ SilcStatus status, error;
+
+ COMMAND_CHECK_STATUS;
+
+ out:
+ silc_server_command_pending_signal(cmd);
+ err:
+ silc_server_command_reply_free(cmd);
+
+ return SILC_FSM_FINISH;
+}
+
+
+/********************************** LIST ************************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_list)
+{
+ SilcServerThread thread = fsm_context;
+ SilcServerCommand cmd = state_context;
+ SilcStatus status, error;
+
+ COMMAND_CHECK_STATUS;
+
+ out:
+ silc_server_command_pending_signal(cmd);
+ err:
+ silc_server_command_reply_free(cmd);
+
+ return SILC_FSM_FINISH;
+}
+
+
+/********************************** INFO ************************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_info)
+{
+ SilcServerThread thread = fsm_context;
+ SilcServerCommand cmd = state_context;
+ SilcStatus status, error;
+
+ COMMAND_CHECK_STATUS;
+
+ out:
+ silc_server_command_pending_signal(cmd);
+ err:
+ silc_server_command_reply_free(cmd);
+
+ return SILC_FSM_FINISH;
+}
+
+
+/********************************** STATS ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_stats)
+{
+ SilcServerThread thread = fsm_context;
+ SilcServer server = thread->server;
+ SilcServerCommand cmd = state_context;
+ SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+ SilcStatus status, error;
+ unsigned char *tmp;
+ SilcUInt32 tmp_len;
+ SilcBufferStruct buf;
+
+ COMMAND_CHECK_STATUS;
+
+ /* Get statistics structure */
+ tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+ if (server->server_type != SILC_ROUTER && tmp) {
+ silc_buffer_set(&buf, tmp, tmp_len);
+ silc_buffer_unformat(&buf,
+ SILC_STR_UI_INT(NULL),
+ SILC_STR_UI_INT(NULL),
+ SILC_STR_UI_INT(NULL),
+ SILC_STR_UI_INT(NULL),
+ SILC_STR_UI_INT(NULL),
+ SILC_STR_UI_INT(NULL),
+ SILC_STR_UI_INT(&server->stat.cell_clients),
+ SILC_STR_UI_INT(&server->stat.cell_channels),
+ SILC_STR_UI_INT(&server->stat.cell_servers),
+ SILC_STR_UI_INT(&server->stat.clients),
+ SILC_STR_UI_INT(&server->stat.channels),
+ SILC_STR_UI_INT(&server->stat.servers),
+ SILC_STR_UI_INT(&server->stat.routers),
+ SILC_STR_UI_INT(&server->stat.server_ops),
+ SILC_STR_UI_INT(&server->stat.router_ops),
+ SILC_STR_END);
+ }
+
+ out:
+ silc_server_command_pending_signal(cmd);
+ err:
+ silc_server_command_reply_free(cmd);
+
+ return SILC_FSM_FINISH;
+}
+
+
+/********************************** PING ************************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_ping)
+{
+ SilcServerThread thread = fsm_context;
+ SilcServerCommand cmd = state_context;
+ SilcStatus status, error;
+
+ COMMAND_CHECK_STATUS;
+
+ out:
+ silc_server_command_pending_signal(cmd);
+ err:
+ silc_server_command_reply_free(cmd);
+
+ return SILC_FSM_FINISH;
+}
+
+
+/********************************** JOIN ************************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_join)
+{
+ SilcServerThread thread = fsm_context;
+ SilcServerCommand cmd = state_context;
+ SilcStatus status, error;
+
+ COMMAND_CHECK_STATUS;
+
+ out:
+ silc_server_command_pending_signal(cmd);
+ err:
+ silc_server_command_reply_free(cmd);
+
+ return SILC_FSM_FINISH;
+}
+
+
+/********************************** MOTD ************************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_motd)
+{
+ SilcServerThread thread = fsm_context;
+ SilcServerCommand cmd = state_context;
+ SilcStatus status, error;
+
+ COMMAND_CHECK_STATUS;
+
+ out:
+ silc_server_command_pending_signal(cmd);
+ err:
+ silc_server_command_reply_free(cmd);
+
+ return SILC_FSM_FINISH;
+}
+
+
+/********************************** WATCH ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_watch)
+{
+ SilcServerThread thread = fsm_context;
+ SilcServerCommand cmd = state_context;
+ SilcStatus status, error;
+
+ COMMAND_CHECK_STATUS;
+
+ out:
+ silc_server_command_pending_signal(cmd);
+ err:
+ silc_server_command_reply_free(cmd);
+
+ return SILC_FSM_FINISH;
+}
+
+
+/********************************** USERS ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_users)
+{
+ SilcServerThread thread = fsm_context;
+ SilcServerCommand cmd = state_context;
+ SilcStatus status, error;
+
+ COMMAND_CHECK_STATUS;
+
+ out:
+ silc_server_command_pending_signal(cmd);
+ err:
+ silc_server_command_reply_free(cmd);
+
+ return SILC_FSM_FINISH;
+}
+
+
+/********************************** GETKEY **********************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_getkey)
+{
+ SilcServerThread thread = fsm_context;
+ SilcServer server = thread->server;
+ SilcServerCommand cmd = state_context;
+ SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+ SilcStatus status, error;
+ unsigned char *tmp;
+ SilcUInt32 len;
+ SilcClientEntry client = NULL;
+ SilcServerEntry server_entry = NULL;
+ SilcIDPayload idp = NULL;
+ SilcClientID client_id;
+ SilcServerID server_id;
+ SilcIdType id_type;
+ SilcPublicKey public_key = NULL;
+
+ COMMAND_CHECK_STATUS;
+
+ /* Get ID */
+ tmp = silc_argument_get_arg_type(args, 2, &len);
+ if (!tmp)
+ goto out;
+ idp = silc_id_payload_parse(tmp, len);
+ if (!idp)
+ goto out;
+
+ /* Get the public key payload */
+ tmp = silc_argument_get_arg_type(args, 3, &len);
+ if (!tmp)
+ goto out;
+ if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
+ goto out;
+
+ /* Store the public key */
+ id_type = silc_id_payload_get_type(idp);
+ if (id_type == SILC_ID_CLIENT) {
+ if (!silc_id_payload_get_id(idp, &client_id, sizeof(client_id)))
+ goto out;
+
+ client = silc_server_find_client_by_id(server, &client_id, TRUE, NULL);
+ if (!client)
+ goto out;
+
+ if (!client->data.public_key) {
+ silc_skr_add_public_key_simple(server->repository, public_key,
+ SILC_SKR_USAGE_IDENTIFICATION, client);
+ client->data.public_key = public_key;
+ public_key = NULL;
+ }
+
+ } else if (id_type == SILC_ID_SERVER) {
+ if (!silc_id_payload_get_id(idp, &server_id, sizeof(server_id)))
+ goto out;
+
+ server_entry = silc_server_find_server_by_id(server, &server_id,
+ TRUE, NULL);
+ if (!server_entry)
+ goto out;
+
+ server_entry->data.public_key = public_key;
+ public_key = NULL;
+ }
+
+ out:
+ silc_server_command_pending_signal(cmd);
+ if (idp)
+ silc_id_payload_free(idp);
+ if (public_key)
+ silc_pkcs_public_key_free(public_key);
+ err:
+ silc_server_command_reply_free(cmd);
+
+ return SILC_FSM_FINISH;
+}
+
+
+/******************************** SERVICE ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_service)
+{
+ SilcServerThread thread = fsm_context;
+ SilcServerCommand cmd = state_context;
+ SilcStatus status, error;
+
+ COMMAND_CHECK_STATUS;
+
+ out:
+ silc_server_command_pending_signal(cmd);
+ err:
+ silc_server_command_reply_free(cmd);
+
+ return SILC_FSM_FINISH;
+}