X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilccore%2Fsilccommand.c;h=83dbde8cf6263e1f218019c410123a572747e1cc;hb=40f8443d8d3a6577336ee66d18e04d9ac4d956bb;hp=6c45cdb87535ad3908406e2b1f10b1c12935f9fa;hpb=4d35af3be05cacf69ca4bd634973cdcd25118e98;p=silc.git diff --git a/lib/silccore/silccommand.c b/lib/silccore/silccommand.c index 6c45cdb8..83dbde8c 100644 --- a/lib/silccore/silccommand.c +++ b/lib/silccore/silccommand.c @@ -2,15 +2,14 @@ silccommand.c - Author: Pekka Riikonen + Author: Pekka Riikonen - Copyright (C) 1997 - 2000 Pekka Riikonen + 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; either version 2 of the License, or - (at your option) any later version. - + 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 @@ -19,7 +18,7 @@ */ /* $Id$ */ -#include "silcincludes.h" +#include "silc.h" #include "silccommand.h" /****************************************************************************** @@ -32,7 +31,7 @@ from SILC packets. */ struct SilcCommandPayloadStruct { SilcCommand cmd; - unsigned short ident; + SilcUInt16 ident; SilcArgumentPayload args; }; @@ -41,69 +40,88 @@ struct SilcCommandPayloadStruct { /* Parses command payload returning new command payload structure */ -SilcCommandPayload silc_command_payload_parse(SilcBuffer buffer) +SilcCommandPayload silc_command_payload_parse(const unsigned char *payload, + SilcUInt32 payload_len) { - SilcCommandPayload new; + SilcBufferStruct buffer; + SilcCommandPayload newp; unsigned char args_num; - unsigned short payload_len; + SilcUInt16 p_len; + int ret; SILC_LOG_DEBUG(("Parsing command payload")); - new = silc_calloc(1, sizeof(*new)); + silc_buffer_set(&buffer, (unsigned char *)payload, payload_len); + newp = silc_calloc(1, sizeof(*newp)); + if (!newp) + return NULL; /* Parse the Command Payload */ - silc_buffer_unformat(buffer, - SILC_STR_UI_SHORT(&payload_len), - SILC_STR_UI_CHAR(&new->cmd), - SILC_STR_UI_CHAR(&args_num), - SILC_STR_UI_SHORT(&new->ident), - SILC_STR_END); - - if (payload_len != buffer->len) { - SILC_LOG_ERROR(("Incorrect command payload in packet, packet dropped")); - silc_free(new); + ret = silc_buffer_unformat(&buffer, + SILC_STR_UI_SHORT(&p_len), + SILC_STR_UI_CHAR(&newp->cmd), + SILC_STR_UI_CHAR(&args_num), + SILC_STR_UI_SHORT(&newp->ident), + SILC_STR_END); + if (ret == -1) { + SILC_LOG_ERROR(("Incorrect command payload in packet")); + silc_free(newp); return NULL; } - if (new->cmd == 0) { - silc_free(new); + if (p_len != silc_buffer_len(&buffer)) { + SILC_LOG_ERROR(("Incorrect command payload in packet")); + silc_free(newp); return NULL; } - silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN); - new->args = silc_argument_payload_parse(buffer, args_num); - if (!new->args) { - silc_free(new); + if (newp->cmd == 0) { + SILC_LOG_ERROR(("Incorrect command type in command payload")); + silc_free(newp); return NULL; } - silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN); - return new; + silc_buffer_pull(&buffer, SILC_COMMAND_PAYLOAD_LEN); + if (args_num) { + newp->args = silc_argument_payload_parse(buffer.data, + silc_buffer_len(&buffer), + args_num); + if (!newp->args) { + silc_free(newp); + return NULL; + } + } + silc_buffer_push(&buffer, SILC_COMMAND_PAYLOAD_LEN); + + return newp; } /* Encodes Command Payload returning it to SilcBuffer. */ SilcBuffer silc_command_payload_encode(SilcCommand cmd, - unsigned int argc, + SilcUInt32 argc, unsigned char **argv, - unsigned int *argv_lens, - unsigned int *argv_types, - unsigned short ident) + SilcUInt32 *argv_lens, + SilcUInt32 *argv_types, + SilcUInt16 ident) { SilcBuffer buffer; SilcBuffer args = NULL; - unsigned int len = 0; + SilcUInt32 len = 0; SILC_LOG_DEBUG(("Encoding command payload")); if (argc) { args = silc_argument_payload_encode(argc, argv, argv_lens, argv_types); - len = args->len; + if (!args) + return NULL; + len = silc_buffer_len(args); } len += SILC_COMMAND_PAYLOAD_LEN; - buffer = silc_buffer_alloc(len); - silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer)); + buffer = silc_buffer_alloc_size(len); + if (!buffer) + return NULL; /* Create Command payload */ silc_buffer_format(buffer, @@ -117,98 +135,134 @@ SilcBuffer silc_command_payload_encode(SilcCommand cmd, if (argc) { silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN); silc_buffer_format(buffer, - SILC_STR_UI_XNSTRING(args->data, args->len), + SILC_STR_UI_XNSTRING(args->data, + silc_buffer_len(args)), SILC_STR_END); silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN); - silc_free(args); + silc_buffer_free(args); } return buffer; } -/* Encodes Command payload with variable argument list. The arguments - must be: unsigned int, unsigned char *, unsigned int, ... One - {unsigned int, unsigned char * and unsigned int} forms one argument, - thus `argc' in case when sending one {unsigned int, 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. The variable arguments is: {type, data, data_len}. */ +/* Same as above but encode the buffer from SilcCommandPayload structure + instead of raw data. */ -SilcBuffer silc_command_payload_encode_va(SilcCommand cmd, - unsigned short ident, - unsigned int argc, ...) +SilcBuffer silc_command_payload_encode_payload(SilcCommandPayload payload) { - va_list ap; - unsigned char **argv; - unsigned int *argv_lens = NULL, *argv_types = NULL; - unsigned char *x; - unsigned int x_len; - unsigned int x_type; SilcBuffer buffer; - int i; - - va_start(ap, argc); + SilcBuffer args = NULL; + SilcUInt32 len = 0; + SilcUInt32 argc = 0; - argv = silc_calloc(argc, sizeof(unsigned char *)); - argv_lens = silc_calloc(argc, sizeof(unsigned int)); - argv_types = silc_calloc(argc, sizeof(unsigned int)); + SILC_LOG_DEBUG(("Encoding command payload")); - for (i = 0; i < argc; i++) { - x_type = va_arg(ap, unsigned int); - x = va_arg(ap, unsigned char *); - x_len = va_arg(ap, unsigned int); + if (payload->args) { + args = silc_argument_payload_encode_payload(payload->args); + if (args) + len = silc_buffer_len(args); + argc = silc_argument_get_arg_num(payload->args); + } - argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char)); - memcpy(argv[i], x, x_len); - argv_lens[i] = x_len; - argv_types[i] = x_type; + len += SILC_COMMAND_PAYLOAD_LEN; + buffer = silc_buffer_alloc_size(len); + if (!buffer) { + if (args) + silc_buffer_free(args); + return NULL; } - buffer = silc_command_payload_encode(cmd, argc, argv, - argv_lens, argv_types, ident); + /* Create Command payload */ + silc_buffer_format(buffer, + 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); - for (i = 0; i < argc; i++) - silc_free(argv[i]); - silc_free(argv); - silc_free(argv_lens); - silc_free(argv_types); + /* Add arguments */ + if (args) { + silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN); + silc_buffer_format(buffer, + SILC_STR_UI_XNSTRING(args->data, + silc_buffer_len(args)), + SILC_STR_END); + silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN); + silc_buffer_free(args); + } return buffer; } -/* Same as above but with va_list. */ +/* Encodes Command payload with variable argument list. The arguments + must be: SilcUInt32, unsigned char *, unsigned int, ... One + {SilcUInt32, unsigned char * and unsigned int} forms one argument, + thus `argc' in case when sending one {SilcUInt32, unsigned char * + and SilcUInt32} 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_vap(SilcCommand cmd, - unsigned short ident, - unsigned int argc, va_list ap) +SilcBuffer silc_command_payload_encode_va(SilcCommand cmd, + SilcUInt16 ident, + SilcUInt32 argc, ...) { - unsigned char **argv; - unsigned int *argv_lens = NULL, *argv_types = NULL; - unsigned char *x; - unsigned int x_len; - unsigned int x_type; + va_list ap; SilcBuffer buffer; - int i; - argv = silc_calloc(argc, sizeof(unsigned char *)); - argv_lens = silc_calloc(argc, sizeof(unsigned int)); - argv_types = silc_calloc(argc, sizeof(unsigned int)); + va_start(ap, argc); + buffer = silc_command_payload_encode_vap(cmd, ident, argc, ap); + va_end(ap); - for (i = 0; i < argc; i++) { - x_type = va_arg(ap, unsigned int); - x = va_arg(ap, unsigned char *); - x_len = va_arg(ap, unsigned int); + return buffer; +} + +/* Same as above but with va_list. */ - argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char)); - memcpy(argv[i], x, x_len); - argv_lens[i] = x_len; - argv_types[i] = x_type; +SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd, + SilcUInt16 ident, + SilcUInt32 argc, va_list ap) +{ + unsigned char **argv = NULL; + SilcUInt32 *argv_lens = NULL, *argv_types = NULL; + unsigned char *x; + SilcUInt32 x_len; + SilcUInt32 x_type; + SilcBuffer buffer = NULL; + int i, k = 0; + + if (argc) { + argv = silc_calloc(argc, sizeof(unsigned char *)); + if (!argv) + return NULL; + argv_lens = silc_calloc(argc, sizeof(SilcUInt32)); + if (!argv_lens) + return NULL; + argv_types = silc_calloc(argc, sizeof(SilcUInt32)); + if (!argv_types) + return NULL; + + for (i = 0, k = 0; i < argc; i++) { + x_type = va_arg(ap, SilcUInt32); + x = va_arg(ap, unsigned char *); + x_len = va_arg(ap, SilcUInt32); + + if (!x_type || !x || !x_len) + continue; + + argv[k] = silc_memdup(x, x_len); + if (!argv[k]) + goto out; + argv_lens[k] = x_len; + argv_types[k] = x_type; + k++; + } } - buffer = silc_command_payload_encode(cmd, argc, argv, - argv_lens, argv_types, ident); + buffer = silc_command_payload_encode(cmd, k, argv, argv_lens, + argv_types, ident); - for (i = 0; i < argc; i++) + out: + for (i = 0; i < k; i++) silc_free(argv[i]); silc_free(argv); silc_free(argv_lens); @@ -222,50 +276,89 @@ SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd, extra argument to this function. The `argc' must not count `status' as on argument. */ -SilcBuffer -silc_command_reply_payload_encode_va(SilcCommand cmd, - SilcCommandStatus status, - unsigned short ident, - unsigned int argc, ...) +SilcBuffer +silc_command_reply_payload_encode_va(SilcCommand cmd, + SilcStatus status, + SilcStatus error, + SilcUInt16 ident, + SilcUInt32 argc, ...) { va_list ap; - unsigned char **argv; - unsigned int *argv_lens = NULL, *argv_types = NULL; - unsigned char status_data[2]; - unsigned char *x; - unsigned int x_len; - unsigned int x_type; SilcBuffer buffer; - int i; va_start(ap, argc); + buffer = silc_command_reply_payload_encode_vap(cmd, status, error, + ident, argc, ap); + va_end(ap); + + return buffer; +} + +SilcBuffer +silc_command_reply_payload_encode_vap(SilcCommand cmd, + SilcStatus status, + SilcStatus error, + SilcUInt16 ident, SilcUInt32 argc, + va_list ap) +{ + unsigned char **argv; + SilcUInt32 *argv_lens = NULL, *argv_types = NULL; + unsigned char status_data[2]; + unsigned char *x; + SilcUInt32 x_len; + SilcUInt32 x_type; + SilcBuffer buffer = NULL; + int i, k; argc++; argv = silc_calloc(argc, sizeof(unsigned char *)); - argv_lens = silc_calloc(argc, sizeof(unsigned int)); - argv_types = silc_calloc(argc, sizeof(unsigned int)); + if (!argv) + return NULL; + argv_lens = silc_calloc(argc, sizeof(SilcUInt32)); + if (!argv_lens) { + silc_free(argv); + return NULL; + } + argv_types = silc_calloc(argc, sizeof(SilcUInt32)); + if (!argv_types) { + silc_free(argv_lens); + silc_free(argv); + return NULL; + } - SILC_PUT16_MSB(status, status_data); - argv[0] = silc_calloc(sizeof(status_data) + 1, sizeof(unsigned char)); - memcpy(argv[0], status_data, sizeof(status_data)); + status_data[0] = status; + status_data[1] = error; + argv[0] = silc_memdup(status_data, sizeof(status_data)); + if (!argv[0]) { + silc_free(argv_types); + silc_free(argv_lens); + silc_free(argv); + return NULL; + } argv_lens[0] = sizeof(status_data); argv_types[0] = 1; - for (i = 1; i < argc; i++) { - x_type = va_arg(ap, unsigned int); + for (i = 1, k = 1; i < argc; i++) { + x_type = va_arg(ap, SilcUInt32); x = va_arg(ap, unsigned char *); - x_len = va_arg(ap, unsigned int); + x_len = va_arg(ap, SilcUInt32); + + if (!x_type || !x || !x_len) + continue; - argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char)); - memcpy(argv[i], x, x_len); - argv_lens[i] = x_len; - argv_types[i] = x_type; + argv[k] = silc_memdup(x, x_len); + if (!argv[k]) + goto out; + argv_lens[k] = x_len; + argv_types[k] = x_type; + k++; } - buffer = silc_command_payload_encode(cmd, argc, argv, - argv_lens, argv_types, ident); + buffer = silc_command_payload_encode(cmd, k, argv, argv_lens, + argv_types, ident); - for (i = 0; i < argc; i++) + out: + for (i = 0; i < k; i++) silc_free(argv[i]); silc_free(argv); silc_free(argv_lens); @@ -274,9 +367,9 @@ silc_command_reply_payload_encode_va(SilcCommand cmd, return buffer; } -/* Free's Command Payload */ +/* Frees Command Payload */ -void silc_command_free_payload(SilcCommandPayload payload) +void silc_command_payload_free(SilcCommandPayload payload) { if (payload) { silc_argument_payload_free(payload->args); @@ -300,7 +393,66 @@ SilcArgumentPayload silc_command_get_args(SilcCommandPayload payload) /* Returns identifier */ -unsigned short silc_command_get_ident(SilcCommandPayload payload) +SilcUInt16 silc_command_get_ident(SilcCommandPayload payload) { return payload->ident; } + +/* Return command status */ + +SilcBool silc_command_get_status(SilcCommandPayload payload, + SilcStatus *status, + SilcStatus *error) +{ + unsigned char *tmp; + SilcUInt32 tmp_len; + + if (!payload->args) + return 0; + tmp = silc_argument_get_arg_type(payload->args, 1, &tmp_len); + if (!tmp || tmp_len != 2) + return 0; + + /* Check for 1.0 protocol version which didn't have `error' */ + if (tmp[0] == 0 && tmp[1] != 0) { + /* Protocol 1.0 version */ + SilcStatus s; + SILC_GET16_MSB(s, tmp); + if (status) + *status = s; + if (error) + *error = 0; + if (s >= SILC_STATUS_ERR_NO_SUCH_NICK && error) + *error = s; + return (s < SILC_STATUS_ERR_NO_SUCH_NICK); + } + + /* Take both status and possible error */ + if (status) + *status = (SilcStatus)tmp[0]; + if (error) + *error = (SilcStatus)tmp[1]; + + /* If single error occurred have the both `status' and `error' indicate + the error value for convenience. */ + if (tmp[0] >= SILC_STATUS_ERR_NO_SUCH_NICK && error) + *error = tmp[0]; + + return (tmp[0] < SILC_STATUS_ERR_NO_SUCH_NICK && tmp[1] == SILC_STATUS_OK); +} + +/* 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. */ + +void silc_command_set_ident(SilcCommandPayload payload, SilcUInt16 ident) +{ + payload->ident = ident; +} + +/* Function to set the command to already allocated Command Payload. */ + +void silc_command_set_command(SilcCommandPayload payload, SilcCommand command) +{ + payload->cmd = command; +}