X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilccore%2Fsilccommand.c;h=04f03d6b6a6d1acc02fcbd7e4c22cc50cb6f24fc;hb=386c883d8774999c6e74d7c6c37e52e4163a4cb1;hp=cab272faf32ea705d514bc445da92930758832fc;hpb=0f9738ce962b8498bbed0a75d5fb6fa127e3577f;p=silc.git diff --git a/lib/silccore/silccommand.c b/lib/silccore/silccommand.c index cab272fa..04f03d6b 100644 --- a/lib/silccore/silccommand.c +++ b/lib/silccore/silccommand.c @@ -2,9 +2,9 @@ silccommand.c - Author: Pekka Riikonen + Author: Pekka Riikonen - 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 @@ -17,223 +17,228 @@ GNU General Public License for more details. */ -/* - * $Id$ - * $Log$ - * Revision 1.1.1.1 2000/06/27 11:36:55 priikone - * Importet from internal CVS/Added Log headers. - * - * - */ +/* $Id$ */ #include "silcincludes.h" #include "silccommand.h" +/****************************************************************************** + + Command Payload + +******************************************************************************/ + /* Command Payload structure. Contents of this structure is parsed from SILC packets. */ struct SilcCommandPayloadStruct { SilcCommand cmd; - unsigned int argc; - unsigned char **argv; - unsigned int *argv_lens; - unsigned int *argv_types; - unsigned int pos; + uint16 ident; + SilcArgumentPayload args; }; /* Length of the command payload */ -#define SILC_COMMAND_PAYLOAD_LEN 4 +#define SILC_COMMAND_PAYLOAD_LEN 6 /* Parses command payload returning new command payload structure */ -SilcCommandPayload silc_command_parse_payload(SilcBuffer buffer) +SilcCommandPayload silc_command_payload_parse(const unsigned char *payload, + uint32 payload_len) { + SilcBufferStruct buffer; SilcCommandPayload new; - unsigned short payload_len = 0; - unsigned char args_num = 0; - unsigned char arg_num = 0; - unsigned int arg_type = 0; - unsigned int pull_len = 0; - int i = 0; + unsigned char args_num; + uint16 p_len; + int ret; SILC_LOG_DEBUG(("Parsing command payload")); + silc_buffer_set(&buffer, (unsigned char *)payload, payload_len); new = silc_calloc(1, sizeof(*new)); - if (!new) { - SILC_LOG_ERROR(("Could not allocate new command payload")); - return NULL; - } /* Parse the Command Payload */ - silc_buffer_unformat(buffer, - SILC_STR_UI_CHAR(&new->cmd), - SILC_STR_UI_CHAR(&args_num), - SILC_STR_UI_SHORT(&payload_len), - SILC_STR_END); + ret = silc_buffer_unformat(&buffer, + SILC_STR_UI_SHORT(&p_len), + SILC_STR_UI_CHAR(&new->cmd), + SILC_STR_UI_CHAR(&args_num), + SILC_STR_UI_SHORT(&new->ident), + SILC_STR_END); + if (ret == -1) { + silc_free(new); + return NULL; + } - if (payload_len != buffer->len) { + if (p_len != buffer.len) { SILC_LOG_ERROR(("Incorrect command payload in packet, packet dropped")); + silc_free(new); return NULL; } - if (new->cmd == 0) + if (new->cmd == 0) { + silc_free(new); return NULL; + } - if (args_num && payload_len) { - - new->argv = silc_calloc(args_num, sizeof(unsigned char *)); - new->argv_lens = silc_calloc(args_num, sizeof(unsigned int)); - new->argv_types = silc_calloc(args_num, sizeof(unsigned int)); - - silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN); - pull_len += SILC_COMMAND_PAYLOAD_LEN; - - /* Parse Command Argument Payloads */ - arg_num = 1; - while(arg_num) { - silc_buffer_unformat(buffer, - SILC_STR_UI_CHAR(&arg_num), - SILC_STR_UI_CHAR(&arg_type), - SILC_STR_UI_SHORT(&payload_len), - SILC_STR_END); - - /* Check that argument number is correct */ - if (arg_num != i + 1) - goto err; - - new->argv_lens[i] = payload_len; - new->argv_types[i] = arg_type; - - /* Get argument data */ - silc_buffer_pull(buffer, 4); - silc_buffer_unformat(buffer, - SILC_STR_UI_XNSTRING_ALLOC(&new->argv[i], - payload_len), - SILC_STR_END); - silc_buffer_pull(buffer, payload_len); - pull_len += 4 + payload_len; - - i++; - - if (i == args_num) - break; + silc_buffer_pull(&buffer, SILC_COMMAND_PAYLOAD_LEN); + if (args_num) { + new->args = silc_argument_payload_parse(buffer.data, buffer.len, args_num); + if (!new->args) { + silc_free(new); + return NULL; } - - /* Check the number of arguments */ - if (arg_num != args_num) - goto err; } + silc_buffer_push(&buffer, SILC_COMMAND_PAYLOAD_LEN); - new->argc = i; - new->pos = 0; + return new; +} - silc_buffer_push(buffer, pull_len); +/* Encodes Command Payload returning it to SilcBuffer. */ - return new; +SilcBuffer silc_command_payload_encode(SilcCommand cmd, + uint32 argc, + unsigned char **argv, + uint32 *argv_lens, + uint32 *argv_types, + uint16 ident) +{ + SilcBuffer buffer; + SilcBuffer args = NULL; + uint32 len = 0; - err: - if (i) { - int k; + SILC_LOG_DEBUG(("Encoding command payload")); - for (k = 0; k < i; k++) - silc_free(new->argv[k]); + if (argc) { + args = silc_argument_payload_encode(argc, argv, argv_lens, argv_types); + len = args->len; } - silc_free(new->argv); - silc_free(new->argv_lens); - silc_free(new->argv_types); + len += SILC_COMMAND_PAYLOAD_LEN; + buffer = silc_buffer_alloc(len); + silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer)); - if (new) - silc_free(new); + /* Create Command payload */ + silc_buffer_format(buffer, + SILC_STR_UI_SHORT(len), + SILC_STR_UI_CHAR(cmd), + SILC_STR_UI_CHAR(argc), + SILC_STR_UI_SHORT(ident), + SILC_STR_END); + + /* Add arguments */ + if (argc) { + silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN); + silc_buffer_format(buffer, + SILC_STR_UI_XNSTRING(args->data, args->len), + SILC_STR_END); + silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN); + silc_buffer_free(args); + } - return NULL; + return buffer; } -/* Encodes Command Payload returning it to SilcBuffer. */ +/* Same as above but encode the buffer from SilcCommandPayload structure + instead of raw data. */ -SilcBuffer silc_command_encode_payload(SilcCommand cmd, - unsigned int argc, - unsigned char **argv, - unsigned int *argv_lens, - unsigned int *argv_types) +SilcBuffer silc_command_payload_encode_payload(SilcCommandPayload payload) { SilcBuffer buffer; - unsigned int len; - int i; + SilcBuffer args = NULL; + uint32 len = 0; + uint32 argc = 0; SILC_LOG_DEBUG(("Encoding command payload")); - len = 1 + 1 + 2; - for (i = 0; i < argc; i++) - len += 1 + 1 + 2 + argv_lens[i]; + if (payload->args) { + args = silc_argument_payload_encode_payload(payload->args); + len = args->len; + argc = silc_argument_get_arg_num(payload->args); + } + len += SILC_COMMAND_PAYLOAD_LEN; buffer = silc_buffer_alloc(len); silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer)); /* Create Command payload */ silc_buffer_format(buffer, - SILC_STR_UI_CHAR(cmd), - SILC_STR_UI_CHAR(argc), SILC_STR_UI_SHORT(len), + SILC_STR_UI_CHAR(payload->cmd), + SILC_STR_UI_CHAR(argc), + SILC_STR_UI_SHORT(payload->ident), SILC_STR_END); - /* Put arguments */ - if (argc) { - silc_buffer_pull(buffer, 4); - - for (i = 0; i < argc; i++) { - silc_buffer_format(buffer, - SILC_STR_UI_CHAR(i + 1), - SILC_STR_UI_CHAR(argv_types[i]), - SILC_STR_UI_SHORT(argv_lens[i]), - SILC_STR_UI_XNSTRING(argv[i], argv_lens[i]), - SILC_STR_END); - silc_buffer_pull(buffer, 4 + argv_lens[i]); - } - - silc_buffer_push(buffer, len); + /* Add arguments */ + if (args) { + silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN); + silc_buffer_format(buffer, + SILC_STR_UI_XNSTRING(args->data, args->len), + SILC_STR_END); + silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN); + silc_buffer_free(args); } return buffer; } /* Encodes Command payload with variable argument list. The arguments - must be: unsigned char *, unsigned int, ... One unsigned char * - and unsigned int forms one argument, hence `argc' in case when - sending one unsigned char * and unsigned int equals one (1) and - when sending two of those it equals two (2), and so on. This has - to be preserved or bad things will happen. */ - -SilcBuffer silc_command_encode_payload_va(SilcCommand cmd, - unsigned int argc, ...) + must be: uint32, unsigned char *, unsigned int, ... One + {uint32, unsigned char * and unsigned int} forms one argument, + thus `argc' in case when sending one {uint32, unsigned char * + and uint32} equals one (1) and when sending two of those it + equals two (2), and so on. This has to be preserved or bad things + will happen. The variable arguments is: {type, data, data_len}. */ + +SilcBuffer silc_command_payload_encode_va(SilcCommand cmd, + uint16 ident, + uint32 argc, ...) { va_list ap; - unsigned char **argv; - unsigned int *argv_lens = NULL, *argv_types = NULL; - unsigned char *x; - unsigned int x_len; SilcBuffer buffer; - int i; va_start(ap, argc); + buffer = silc_command_payload_encode_vap(cmd, ident, argc, ap); + va_end(ap); - argv = silc_calloc(argc, sizeof(unsigned char *)); - argv_lens = silc_calloc(argc, sizeof(unsigned int)); - argv_types = silc_calloc(argc, sizeof(unsigned int)); + return buffer; +} - for (i = 0; i < argc; i++) { - x = va_arg(ap, unsigned char *); - x_len = va_arg(ap, unsigned int); +/* Same as above but with va_list. */ + +SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd, + uint16 ident, + uint32 argc, va_list ap) +{ + unsigned char **argv = NULL; + uint32 *argv_lens = NULL, *argv_types = NULL; + unsigned char *x; + uint32 x_len; + uint32 x_type; + SilcBuffer buffer; + int i, k = 0; - argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char)); - memcpy(argv[i], x, x_len); - argv_lens[i] = x_len; - argv_types[i] = i + 1; + if (argc) { + argv = silc_calloc(argc, sizeof(unsigned char *)); + argv_lens = silc_calloc(argc, sizeof(uint32)); + argv_types = silc_calloc(argc, sizeof(uint32)); + + for (i = 0, k = 0; i < argc; i++) { + x_type = va_arg(ap, uint32); + x = va_arg(ap, unsigned char *); + x_len = va_arg(ap, uint32); + + if (!x_type || !x || !x_len) + continue; + + argv[k] = silc_memdup(x, x_len); + argv_lens[k] = x_len; + argv_types[k] = x_type; + k++; + } } - buffer = silc_command_encode_payload(cmd, argc, argv, - argv_lens, argv_types); + buffer = silc_command_payload_encode(cmd, k, argv, argv_lens, + argv_types, ident); - for (i = 0; i < argc; i++) + for (i = 0; i < k; i++) silc_free(argv[i]); silc_free(argv); silc_free(argv_lens); @@ -242,99 +247,121 @@ SilcBuffer silc_command_encode_payload_va(SilcCommand cmd, return buffer; } -/* Free's Command Payload */ +/* Same as above except that this is used to encode strictly command + reply packets. The command status message to be returned is sent as + extra argument to this function. The `argc' must not count `status' + as on argument. */ -void silc_command_free_payload(SilcCommandPayload payload) +SilcBuffer +silc_command_reply_payload_encode_va(SilcCommand cmd, + SilcCommandStatus status, + uint16 ident, + uint32 argc, ...) { - int i; + va_list ap; + SilcBuffer buffer; - if (payload) { - for (i = 0; i < payload->argc; i++) - silc_free(payload->argv[i]); + va_start(ap, argc); + buffer = silc_command_reply_payload_encode_vap(cmd, status, ident, argc, ap); + va_end(ap); - silc_free(payload->argv); - silc_free(payload); - } + return buffer; } -/* Returns the command type in payload */ - -SilcCommand silc_command_get(SilcCommandPayload payload) +SilcBuffer +silc_command_reply_payload_encode_vap(SilcCommand cmd, + SilcCommandStatus status, + uint16 ident, uint32 argc, + va_list ap) { - return payload->cmd; -} + unsigned char **argv; + uint32 *argv_lens = NULL, *argv_types = NULL; + unsigned char status_data[2]; + unsigned char *x; + uint32 x_len; + uint32 x_type; + SilcBuffer buffer; + int i, k; -/* Returns number of arguments in payload */ + argc++; + argv = silc_calloc(argc, sizeof(unsigned char *)); + argv_lens = silc_calloc(argc, sizeof(uint32)); + argv_types = silc_calloc(argc, sizeof(uint32)); -unsigned int silc_command_get_arg_num(SilcCommandPayload payload) -{ - return payload->argc; -} + SILC_PUT16_MSB(status, status_data); + argv[0] = silc_memdup(status_data, sizeof(status_data)); + argv_lens[0] = sizeof(status_data); + argv_types[0] = 1; -/* Returns first argument from payload. */ + for (i = 1, k = 1; i < argc; i++) { + x_type = va_arg(ap, uint32); + x = va_arg(ap, unsigned char *); + x_len = va_arg(ap, uint32); -unsigned char *silc_command_get_first_arg(SilcCommandPayload payload, - unsigned int *ret_len) -{ - payload->pos = 0; + if (!x_type || !x || !x_len) + continue; - if (ret_len) - *ret_len = payload->argv_lens[payload->pos]; + argv[k] = silc_memdup(x, x_len); + argv_lens[k] = x_len; + argv_types[k] = x_type; + k++; + } - return payload->argv[payload->pos++]; -} + buffer = silc_command_payload_encode(cmd, k, argv, argv_lens, + argv_types, ident); -/* Returns next argument from payload or NULL if no more arguments. */ + for (i = 0; i < k; i++) + silc_free(argv[i]); + silc_free(argv); + silc_free(argv_lens); + silc_free(argv_types); -unsigned char *silc_command_get_next_arg(SilcCommandPayload payload, - unsigned int *ret_len) -{ - if (payload->pos >= payload->argc) - return NULL; + return buffer; +} - if (ret_len) - *ret_len = payload->argv_lens[payload->pos]; +/* Frees Command Payload */ - return payload->argv[payload->pos++]; +void silc_command_payload_free(SilcCommandPayload payload) +{ + if (payload) { + silc_argument_payload_free(payload->args); + silc_free(payload); + } } -/* Returns argument which type is `type'. */ +/* Returns command */ -unsigned char *silc_command_get_arg_type(SilcCommandPayload payload, - unsigned int type, - unsigned int *ret_len) +SilcCommand silc_command_get(SilcCommandPayload payload) { - int i; + return payload->cmd; +} - for (i = 0; i < payload->argc; i++) - if (payload->argv_types[i] == type) - break; +/* Retuns arguments payload */ - if (i >= payload->argc) - return NULL; +SilcArgumentPayload silc_command_get_args(SilcCommandPayload payload) +{ + return payload->args; +} - if (ret_len) - *ret_len = payload->argv_lens[i]; +/* Returns identifier */ - return payload->argv[i]; +uint16 silc_command_get_ident(SilcCommandPayload payload) +{ + return payload->ident; } -/* Encodes command status payload. Status payload is sent as one reply - argument. The returned payload still has to be saved into the - Command Argument payload. */ +/* Function to set identifier to already allocated Command Payload. Command + payloads are frequentlly resent in SILC and thusly this makes it easy + to set the identifier. */ -SilcBuffer silc_command_encode_status_payload(SilcCommandStatus status, - unsigned char *data, - unsigned int len) +void silc_command_set_ident(SilcCommandPayload payload, uint16 ident) { - SilcBuffer sp; + payload->ident = ident; +} - sp = silc_buffer_alloc(len + 2); - silc_buffer_pull_tail(sp, SILC_BUFFER_END(sp)); - silc_buffer_format(sp, - SILC_STR_UI_SHORT(status), - SILC_STR_UI_XNSTRING(data, len), - SILC_STR_END); +/* Function to set the command to already allocated Command Payload. */ - return sp; +void silc_command_set_command(SilcCommandPayload payload, SilcCommand command) +{ + payload->cmd = command; }