From d56fa9060fe64259cf6a94a282d82e9eaaf1b32e Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Mon, 9 Oct 2000 11:38:33 +0000 Subject: [PATCH] Created silcpayload.[ch] for generic payloads. Changed command payload to use new generic payloads. Changed channel payload to protocol compliant. --- lib/silccore/Makefile.am | 4 +- lib/silccore/silcchannel.c | 83 ++++----- lib/silccore/silcchannel.h | 16 +- lib/silccore/silccommand.c | 239 +++++++------------------ lib/silccore/silccommand.h | 23 ++- lib/silccore/silcnotify.h | 13 ++ lib/silccore/silcpayload.c | 356 +++++++++++++++++++++++++++++++++++++ lib/silccore/silcpayload.h | 51 ++++++ 8 files changed, 532 insertions(+), 253 deletions(-) create mode 100644 lib/silccore/silcpayload.c create mode 100644 lib/silccore/silcpayload.h diff --git a/lib/silccore/Makefile.am b/lib/silccore/Makefile.am index 62ed6aef..72fd28d0 100644 --- a/lib/silccore/Makefile.am +++ b/lib/silccore/Makefile.am @@ -27,7 +27,9 @@ libsilccore_a_SOURCES = \ silccommand.c \ silcpacket.c \ silcprotocol.c \ - silcsockconn.c + silcsockconn.c \ + silcpayload.c \ + silcnotify.c EXTRA_DIST = *.h diff --git a/lib/silccore/silcchannel.c b/lib/silccore/silcchannel.c index 4cfe3002..c2226da4 100644 --- a/lib/silccore/silcchannel.c +++ b/lib/silccore/silcchannel.c @@ -17,46 +17,30 @@ GNU General Public License for more details. */ -/* - * $Id$ - * $Log$ - * Revision 1.2 2000/07/05 06:06:35 priikone - * Global cosmetic change. - * - * Revision 1.1.1.1 2000/06/27 11:36:55 priikone - * Imported from internal CVS/Added Log headers. - * - * - */ +/* Channel Payload and Channel Key Payload implementations. */ +/* $Id$ */ #include "silcincludes.h" #include "silcchannel.h" +/****************************************************************************** + + Channel Payload + +******************************************************************************/ + /* Channel Payload structure. Contents of this structure is parsed from SILC packets. */ struct SilcChannelPayloadStruct { - unsigned short nick_len; - unsigned char *nick; unsigned short data_len; unsigned char *data; unsigned short iv_len; unsigned char *iv; }; -/* Channel Key Payload structrue. Channel keys are parsed from SILC - packets into this structure. */ -struct SilcChannelKeyPayloadStruct { - unsigned short id_len; - unsigned char *id; - unsigned short cipher_len; - unsigned char *cipher; - unsigned short key_len; - unsigned char *key; -}; - /* Parses channel payload returning new channel payload structure */ -SilcChannelPayload silc_channel_parse_payload(SilcBuffer buffer) +SilcChannelPayload silc_channel_payload_parse(SilcBuffer buffer) { SilcChannelPayload new; @@ -67,12 +51,11 @@ SilcChannelPayload silc_channel_parse_payload(SilcBuffer buffer) /* Parse the Channel Payload. Ignore padding and IV, we don't need them. */ silc_buffer_unformat(buffer, - SILC_STR_UI16_NSTRING_ALLOC(&new->nick, &new->nick_len), SILC_STR_UI16_NSTRING_ALLOC(&new->data, &new->data_len), SILC_STR_UI16_NSTRING_ALLOC(NULL, NULL), SILC_STR_END); - if (new->data_len < 1) { + if (new->data_len < 1 || new->data_len > buffer->len) { SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped")); goto err; } @@ -80,8 +63,6 @@ SilcChannelPayload silc_channel_parse_payload(SilcBuffer buffer) return new; err: - if (new->nick) - silc_free(new->nick); if (new->data) silc_free(new->data); if (new->iv) @@ -95,9 +76,7 @@ SilcChannelPayload silc_channel_parse_payload(SilcBuffer buffer) encrypted separately from other parts of the packet padding must be applied to the payload. */ -SilcBuffer silc_channel_encode_payload(unsigned short nick_len, - unsigned char *nick, - unsigned short data_len, +SilcBuffer silc_channel_payload_encode(unsigned short data_len, unsigned char *data, unsigned short iv_len, unsigned char *iv, @@ -112,7 +91,7 @@ SilcBuffer silc_channel_encode_payload(unsigned short nick_len, /* Calculate length of padding. IV is not included into the calculation since it is not encrypted. */ - len = 2 + nick_len + 2 + data_len + 2; + len = 2 + data_len + 2; pad_len = SILC_PACKET_PADLEN((len + 2)); /* Allocate channel payload buffer */ @@ -127,8 +106,6 @@ SilcBuffer silc_channel_encode_payload(unsigned short nick_len, /* Encode the Channel Payload */ silc_buffer_format(buffer, - SILC_STR_UI_SHORT(nick_len), - SILC_STR_UI_XNSTRING(nick, nick_len), SILC_STR_UI_SHORT(data_len), SILC_STR_UI_XNSTRING(data, data_len), SILC_STR_UI_SHORT(pad_len), @@ -142,7 +119,7 @@ SilcBuffer silc_channel_encode_payload(unsigned short nick_len, /* Free's Channel Payload */ -void silc_channel_free_payload(SilcChannelPayload payload) +void silc_channel_payload_free(SilcChannelPayload payload) { if (payload) { if (payload->data) @@ -153,17 +130,6 @@ void silc_channel_free_payload(SilcChannelPayload payload) } } -/* Return nickname */ - -unsigned char *silc_channel_get_nickname(SilcChannelPayload payload, - unsigned int *nick_len) -{ - if (nick_len) - *nick_len = payload->nick_len; - - return payload->nick; -} - /* Return data */ unsigned char *silc_channel_get_data(SilcChannelPayload payload, @@ -186,9 +152,26 @@ unsigned char *silc_channel_get_iv(SilcChannelPayload payload, return payload->iv; } +/****************************************************************************** + + Channel Key Payload + +******************************************************************************/ + +/* Channel Key Payload structrue. Channel keys are parsed from SILC + packets into this structure. */ +struct SilcChannelKeyPayloadStruct { + unsigned short id_len; + unsigned char *id; + unsigned short cipher_len; + unsigned char *cipher; + unsigned short key_len; + unsigned char *key; +}; + /* Parses channel key payload returning new channel key payload structure */ -SilcChannelKeyPayload silc_channel_key_parse_payload(SilcBuffer buffer) +SilcChannelKeyPayload silc_channel_key_payload_parse(SilcBuffer buffer) { SilcChannelKeyPayload new; @@ -225,7 +208,7 @@ SilcChannelKeyPayload silc_channel_key_parse_payload(SilcBuffer buffer) /* Encodes channel key payload into a buffer and returns it. This is used to add channel key payload into a packet. */ -SilcBuffer silc_channel_key_encode_payload(unsigned short id_len, +SilcBuffer silc_channel_key_payload_encode(unsigned short id_len, unsigned char *id, unsigned short cipher_len, unsigned char *cipher, @@ -263,7 +246,7 @@ SilcBuffer silc_channel_key_encode_payload(unsigned short id_len, /* Free's Channel Key Payload */ -void silc_channel_key_free_payload(SilcChannelKeyPayload payload) +void silc_channel_key_payload_free(SilcChannelKeyPayload payload) { if (payload) { if (payload->id) diff --git a/lib/silccore/silcchannel.h b/lib/silccore/silcchannel.h index b39045fa..9517db1b 100644 --- a/lib/silccore/silcchannel.h +++ b/lib/silccore/silcchannel.h @@ -42,29 +42,25 @@ typedef struct SilcChannelKeyPayloadStruct *SilcChannelKeyPayload; #define SILC_CHANNEL_UMODE_CHANOP 0x0002 /* channel operator */ /* Prototypes */ -SilcChannelPayload silc_channel_parse_payload(SilcBuffer buffer); -SilcBuffer silc_channel_encode_payload(unsigned short nick_len, - unsigned char *nick, - unsigned short data_len, +SilcChannelPayload silc_channel_payload_parse(SilcBuffer buffer); +SilcBuffer silc_channel_payload_encode(unsigned short data_len, unsigned char *data, unsigned short iv_len, unsigned char *iv, SilcRng rng); -void silc_channel_free_payload(SilcChannelPayload payload); -unsigned char *silc_channel_get_nickname(SilcChannelPayload payload, - unsigned int *nick_len); +void silc_channel_payload_free(SilcChannelPayload payload); unsigned char *silc_channel_get_data(SilcChannelPayload payload, unsigned int *data_len); unsigned char *silc_channel_get_iv(SilcChannelPayload payload, unsigned int *iv_len); -SilcChannelKeyPayload silc_channel_key_parse_payload(SilcBuffer buffer); -SilcBuffer silc_channel_key_encode_payload(unsigned short id_len, +SilcChannelKeyPayload silc_channel_key_payload_parse(SilcBuffer buffer); +SilcBuffer silc_channel_key_payload_encode(unsigned short id_len, unsigned char *id, unsigned short cipher_len, unsigned char *cipher, unsigned short key_len, unsigned char *key); -void silc_channel_key_free_payload(SilcChannelKeyPayload payload); +void silc_channel_key_payload_free(SilcChannelKeyPayload payload); unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload, unsigned int *id_len); unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload, diff --git a/lib/silccore/silccommand.c b/lib/silccore/silccommand.c index cfdf18a0..b9bd78f0 100644 --- a/lib/silccore/silccommand.c +++ b/lib/silccore/silccommand.c @@ -17,52 +17,35 @@ GNU General Public License for more details. */ -/* - * $Id$ - * $Log$ - * Revision 1.3 2000/07/06 07:11:06 priikone - * Removed status paylaod encoding functions -> not needed anymore. - * Added encode_reply_payload_va to encode reply packets only. - * Normal encode_payload_va accepts now argument type as variable - * argument as well. - * - * Revision 1.2 2000/07/05 06:06:35 priikone - * Global cosmetic change. - * - * Revision 1.1.1.1 2000/06/27 11:36:55 priikone - * Imported 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; + unsigned short 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(SilcBuffer 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; + unsigned short payload_len; SILC_LOG_DEBUG(("Parsing command payload")); @@ -70,132 +53,74 @@ SilcCommandPayload silc_command_parse_payload(SilcBuffer buffer) /* 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(&payload_len), + 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); 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; - } - - /* Check the number of arguments */ - if (arg_num != args_num) - goto err; } - new->argc = i; - new->pos = 0; - - silc_buffer_push(buffer, pull_len); - - return new; - - err: - if (i) { - int k; - - for (k = 0; k < i; k++) - silc_free(new->argv[k]); - } - - silc_free(new->argv); - silc_free(new->argv_lens); - silc_free(new->argv_types); - - if (new) + silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN); + new->args = silc_argument_payload_parse(buffer, args_num); + if (!new->args) { silc_free(new); + return NULL; + } + silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN); - return NULL; + return new; } /* Encodes Command Payload returning it to SilcBuffer. */ -SilcBuffer silc_command_encode_payload(SilcCommand cmd, +SilcBuffer silc_command_payload_encode(SilcCommand cmd, unsigned int argc, unsigned char **argv, unsigned int *argv_lens, - unsigned int *argv_types) + unsigned int *argv_types, + unsigned short ident) { SilcBuffer buffer; - unsigned int len; - int i; + SilcBuffer args = NULL; + unsigned int len = 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 (argc) { + args = silc_argument_payload_encode(argc, argv, argv_lens, argv_types); + len = args->len; + } + 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_SHORT(len), SILC_STR_UI_CHAR(cmd), SILC_STR_UI_CHAR(argc), - SILC_STR_UI_SHORT(len), + SILC_STR_UI_SHORT(ident), SILC_STR_END); - /* Put arguments */ + /* Add 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); + 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_free(args); } return buffer; @@ -209,7 +134,8 @@ SilcBuffer silc_command_encode_payload(SilcCommand cmd, 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_encode_payload_va(SilcCommand cmd, +SilcBuffer silc_command_payload_encode_va(SilcCommand cmd, + unsigned short ident, unsigned int argc, ...) { va_list ap; @@ -238,8 +164,8 @@ SilcBuffer silc_command_encode_payload_va(SilcCommand cmd, argv_types[i] = x_type; } - buffer = silc_command_encode_payload(cmd, argc, argv, - argv_lens, argv_types); + buffer = silc_command_payload_encode(cmd, argc, argv, + argv_lens, argv_types, ident); for (i = 0; i < argc; i++) silc_free(argv[i]); @@ -256,8 +182,9 @@ SilcBuffer silc_command_encode_payload_va(SilcCommand cmd, as on argument. */ SilcBuffer -silc_command_encode_reply_payload_va(SilcCommand cmd, +silc_command_reply_payload_encode_va(SilcCommand cmd, SilcCommandStatus status, + unsigned short ident, unsigned int argc, ...) { va_list ap; @@ -294,8 +221,8 @@ silc_command_encode_reply_payload_va(SilcCommand cmd, argv_types[i] = x_type; } - buffer = silc_command_encode_payload(cmd, argc, argv, - argv_lens, argv_types); + buffer = silc_command_payload_encode(cmd, argc, argv, + argv_lens, argv_types, ident); for (i = 0; i < argc; i++) silc_free(argv[i]); @@ -310,75 +237,29 @@ silc_command_encode_reply_payload_va(SilcCommand cmd, void silc_command_free_payload(SilcCommandPayload payload) { - int i; - if (payload) { - for (i = 0; i < payload->argc; i++) - silc_free(payload->argv[i]); - - silc_free(payload->argv); + silc_argument_payload_free(payload->args); silc_free(payload); } } -/* Returns the command type in payload */ +/* Returns command */ SilcCommand silc_command_get(SilcCommandPayload payload) { return payload->cmd; } -/* Returns number of arguments in payload */ +/* Retuns arguments payload */ -unsigned int silc_command_get_arg_num(SilcCommandPayload payload) +SilcArgumentPayload silc_command_get_args(SilcCommandPayload payload) { - return payload->argc; -} - -/* Returns first argument from payload. */ - -unsigned char *silc_command_get_first_arg(SilcCommandPayload payload, - unsigned int *ret_len) -{ - payload->pos = 0; - - if (ret_len) - *ret_len = payload->argv_lens[payload->pos]; - - return payload->argv[payload->pos++]; + return payload->args; } -/* Returns next argument from payload or NULL if no more arguments. */ +/* Returns identifier */ -unsigned char *silc_command_get_next_arg(SilcCommandPayload payload, - unsigned int *ret_len) +unsigned short silc_command_get_ident(SilcCommandPayload payload) { - if (payload->pos >= payload->argc) - return NULL; - - if (ret_len) - *ret_len = payload->argv_lens[payload->pos]; - - return payload->argv[payload->pos++]; -} - -/* Returns argument which type is `type'. */ - -unsigned char *silc_command_get_arg_type(SilcCommandPayload payload, - unsigned int type, - unsigned int *ret_len) -{ - int i; - - for (i = 0; i < payload->argc; i++) - if (payload->argv_types[i] == type) - break; - - if (i >= payload->argc) - return NULL; - - if (ret_len) - *ret_len = payload->argv_lens[i]; - - return payload->argv[i]; + return payload->ident; } diff --git a/lib/silccore/silccommand.h b/lib/silccore/silccommand.h index 8ecaeaa3..0912b76d 100644 --- a/lib/silccore/silccommand.h +++ b/lib/silccore/silccommand.h @@ -127,27 +127,24 @@ typedef unsigned short SilcCommandStatus; #define SILC_STATUS_ERR_AUTH_FAILED 43 /* Prototypes */ -SilcCommandPayload silc_command_parse_payload(SilcBuffer buffer); -SilcBuffer silc_command_encode_payload(SilcCommand cmd, +SilcCommandPayload silc_command_payload_parse(SilcBuffer buffer); +SilcBuffer silc_command_payload_encode(SilcCommand cmd, unsigned int argc, unsigned char **argv, unsigned int *argv_lens, - unsigned int *argv_types); -SilcBuffer silc_command_encode_payload_va(SilcCommand cmd, + unsigned int *argv_types, + unsigned short ident); +SilcBuffer silc_command_payload_encode_va(SilcCommand cmd, + unsigned short ident, unsigned int argc, ...); SilcBuffer -silc_command_encode_reply_payload_va(SilcCommand cmd, +silc_command_reply_payload_encode_va(SilcCommand cmd, SilcCommandStatus status, + unsigned short ident, unsigned int argc, ...); void silc_command_free_payload(SilcCommandPayload payload); SilcCommand silc_command_get(SilcCommandPayload payload); -unsigned int silc_command_get_arg_num(SilcCommandPayload payload); -unsigned char *silc_command_get_first_arg(SilcCommandPayload payload, - unsigned int *ret_len); -unsigned char *silc_command_get_next_arg(SilcCommandPayload payload, - unsigned int *ret_len); -unsigned char *silc_command_get_arg_type(SilcCommandPayload payload, - unsigned int type, - unsigned int *ret_len); +SilcArgumentPayload silc_command_get_args(SilcCommandPayload payload); +unsigned short silc_command_get_ident(SilcCommandPayload payload); #endif diff --git a/lib/silccore/silcnotify.h b/lib/silccore/silcnotify.h index fd7662ad..9215e2b4 100644 --- a/lib/silccore/silcnotify.h +++ b/lib/silccore/silcnotify.h @@ -21,6 +21,9 @@ #ifndef SILCNOTIFY_H #define SILCNOTIFY_H +/* Forward declarations */ +typedef struct SilcNotifyPayloadStruct *SilcNotifyPayload; + /* Type definition of notify type */ typedef unsigned short SilcNotifyType; @@ -35,4 +38,14 @@ typedef unsigned short SilcNotifyType; #define SILC_NOTIFY_TYPE_TOPIC_SET 5 /* "topic has been changed" */ #define SILC_NOTIFY_TYPE_NICK_CHANGE 6 /* "has changed nickname" */ +/* Prototypes */ +SilcNotifyPayload silc_notify_payload_parse(SilcBuffer buffer); +SilcBuffer silc_notify_payload_encode(SilcNotifyType type, char *message, + unsigned int argc, va_list ap); +void silc_notify_payload_free(SilcNotifyPayload payload); +SilcNotifyType silc_notify_get_type(SilcNotifyPayload payload); +unsigned int silc_notify_get_arg_num(SilcNotifyPayload payload); +unsigned char *silc_notify_get_message(SilcNotifyPayload payload); +SilcArgumentPayload silc_notify_get_args(SilcNotifyPayload payload); + #endif diff --git a/lib/silccore/silcpayload.c b/lib/silccore/silcpayload.c new file mode 100644 index 00000000..50c409d9 --- /dev/null +++ b/lib/silccore/silcpayload.c @@ -0,0 +1,356 @@ +/* + + silcpayload.c + + Author: Pekka Riikonen + + Copyright (C) 2000 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. + + 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. + +*/ +/* Implementation of generic payloads described in the protocol + specification drafts. */ +/* $Id$ */ + +#include "silcincludes.h" +#include "silcpayload.h" + +/****************************************************************************** + + ID Payload + +******************************************************************************/ + +struct SilcIDPayloadStruct { + SilcIdType type; + unsigned short len; + unsigned char *id; +}; + +/* Parses data and return ID payload into payload structure */ + +SilcIDPayload silc_id_payload_parse(SilcBuffer buffer) +{ + SilcIDPayload new; + + SILC_LOG_DEBUG(("Parsing ID payload")); + + new = silc_calloc(1, sizeof(*new)); + + silc_buffer_unformat(buffer, + SILC_STR_UI_SHORT(&new->type), + SILC_STR_UI_SHORT(&new->len), + SILC_STR_END); + + if (new->len > buffer->len) + goto err; + + silc_buffer_pull(buffer, 4); + silc_buffer_unformat(buffer, + SILC_STR_UI_XNSTRING_ALLOC(&new->id, new->len), + SILC_STR_END); + silc_buffer_push(buffer, 4); + + return new; + + err: + silc_free(new); + return NULL; +} + +/* Encodes ID Payload */ + +SilcBuffer silc_id_payload_encode(void *id, unsigned short len, + SilcIdType type) +{ + SilcBuffer buffer; + unsigned char *id_data; + + SILC_LOG_DEBUG(("Parsing ID payload")); + + id_data = silc_id_id2str(id, type); + + buffer = silc_buffer_alloc(4 + len); + silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer)); + silc_buffer_format(buffer, + SILC_STR_UI_SHORT(type), + SILC_STR_UI_SHORT(len), + SILC_STR_UI_XNSTRING(id_data, len), + SILC_STR_END); + silc_free(id_data); + + return buffer; +} + +/* Free ID Payload */ + +void silc_id_payload_free(SilcIDPayload payload) +{ + if (payload) { + silc_free(payload->id); + } +} + +/* Get ID type */ + +SilcIdType silc_id_payload_get_type(SilcIDPayload payload) +{ + return payload->type; +} + +/* Get ID */ + +void *silc_id_payload_get_id(SilcIDPayload payload) +{ + return silc_id_str2id(payload->id, payload->type); +} + +/****************************************************************************** + + Argument Payload + +******************************************************************************/ + +struct SilcArgumentPayloadStruct { + unsigned int argc; + unsigned char **argv; + unsigned int *argv_lens; + unsigned int *argv_types; + unsigned int pos; +}; + +/* Parses arguments and returns them into Argument Payload structure. */ + +SilcArgumentPayload silc_argument_payload_parse(SilcBuffer buffer, + unsigned int argc) +{ + SilcArgumentPayload new; + unsigned short payload_len = 0; + unsigned char arg_num = 0; + unsigned int arg_type = 0; + unsigned int pull_len = 0; + int i = 0; + + SILC_LOG_DEBUG(("Parsing argument payload")); + + new = silc_calloc(1, sizeof(*new)); + new->argv = silc_calloc(argc, sizeof(unsigned char *)); + new->argv_lens = silc_calloc(argc, sizeof(unsigned int)); + new->argv_types = silc_calloc(argc, sizeof(unsigned int)); + + /* Get arguments */ + arg_num = 1; + for (i = 0; i < argc; i++) { + silc_buffer_unformat(buffer, + SILC_STR_UI_SHORT(&payload_len), + SILC_STR_UI_CHAR(&arg_type), + SILC_STR_END); + + new->argv_lens[i] = payload_len; + new->argv_types[i] = arg_type; + + if (payload_len > buffer->len) + break; + + /* Get argument data */ + silc_buffer_pull(buffer, 3); + 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 += 3 + payload_len; + } + + if (buffer->len != 0) + goto err; + + new->argc = argc; + new->pos = 0; + + silc_buffer_push(buffer, pull_len); + + return new; + + err: + if (i) { + int k; + + for (k = 0; k < i; k++) + silc_free(new->argv[k]); + } + + silc_free(new->argv); + silc_free(new->argv_lens); + silc_free(new->argv_types); + + if (new) + silc_free(new); + + return NULL; +} + +/* Encodes arguments in to Argument Paylods returning them to SilcBuffer. */ + +SilcBuffer silc_argument_payload_encode(unsigned int argc, + unsigned char **argv, + unsigned int *argv_lens, + unsigned int *argv_types) +{ + SilcBuffer buffer; + unsigned int len; + int i; + + SILC_LOG_DEBUG(("Encoding Argument payload")); + + len = 0; + for (i = 0; i < argc; i++) + len += 3 + argv_lens[i]; + + buffer = silc_buffer_alloc(len); + silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer)); + + /* Put arguments */ + for (i = 0; i < argc; i++) { + silc_buffer_format(buffer, + SILC_STR_UI_SHORT(argv_lens[i]), + SILC_STR_UI_CHAR(argv_types[i]), + SILC_STR_UI_XNSTRING(argv[i], argv_lens[i]), + SILC_STR_END); + silc_buffer_pull(buffer, 3 + argv_lens[i]); + } + + silc_buffer_push(buffer, len); + + return buffer; +} + +#if 0 +/* Encodes Argument 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}. */ + +SilcBuffer silc_command_encode_payload_va(unsigned int argc, ...) +{ + 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); + + argv = silc_calloc(argc, sizeof(unsigned char *)); + argv_lens = silc_calloc(argc, sizeof(unsigned int)); + argv_types = silc_calloc(argc, sizeof(unsigned int)); + + 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); + + 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; + } + + buffer = silc_argument_payload_encode(argc, argv, + argv_lens, argv_types); + + for (i = 0; i < argc; i++) + silc_free(argv[i]); + silc_free(argv); + silc_free(argv_lens); + silc_free(argv_types); + + return buffer; +} +#endif + +/* Free's Command Payload */ + +void silc_argument_payload_free(SilcArgumentPayload payload) +{ + int i; + + if (payload) { + for (i = 0; i < payload->argc; i++) + silc_free(payload->argv[i]); + + silc_free(payload->argv); + silc_free(payload); + } +} + +/* Returns number of arguments in payload */ + +unsigned int silc_argument_get_arg_num(SilcArgumentPayload payload) +{ + return payload->argc; +} + +/* Returns first argument from payload. */ + +unsigned char *silc_argument_get_first_arg(SilcArgumentPayload payload, + unsigned int *ret_len) +{ + payload->pos = 0; + + if (ret_len) + *ret_len = payload->argv_lens[payload->pos]; + + return payload->argv[payload->pos++]; +} + +/* Returns next argument from payload or NULL if no more arguments. */ + +unsigned char *silc_argument_get_next_arg(SilcArgumentPayload payload, + unsigned int *ret_len) +{ + if (payload->pos >= payload->argc) + return NULL; + + if (ret_len) + *ret_len = payload->argv_lens[payload->pos]; + + return payload->argv[payload->pos++]; +} + +/* Returns argument which type is `type'. */ + +unsigned char *silc_argument_get_arg_type(SilcArgumentPayload payload, + unsigned int type, + unsigned int *ret_len) +{ + int i; + + for (i = 0; i < payload->argc; i++) + if (payload->argv_types[i] == type) + break; + + if (i >= payload->argc) + return NULL; + + if (ret_len) + *ret_len = payload->argv_lens[i]; + + return payload->argv[i]; +} diff --git a/lib/silccore/silcpayload.h b/lib/silccore/silcpayload.h new file mode 100644 index 00000000..a880aca1 --- /dev/null +++ b/lib/silccore/silcpayload.h @@ -0,0 +1,51 @@ +/* + + silcpayload.h + + Author: Pekka Riikonen + + Copyright (C) 2000 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. + + 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. + +*/ + +#ifndef SILCPAYLOAD_H +#define SILCPAYLOAD_H + +/* Forward declarations */ +typedef struct SilcIDPayloadStruct *SilcIDPayload; +typedef struct SilcArgumentPayloadStruct *SilcArgumentPayload; + +/* Prototypes */ +SilcIDPayload silc_id_payload_parse(SilcBuffer buffer); +SilcBuffer silc_id_payload_encode(void *id, unsigned short len, + SilcIdType type); +SilcArgumentPayload silc_argument_payload_parse(SilcBuffer buffer, + unsigned int argc); +void silc_id_payload_free(SilcIDPayload payload); +SilcIdType silc_id_payload_get_type(SilcIDPayload payload); +void *silc_id_payload_get_id(SilcIDPayload payload); +SilcBuffer silc_argument_payload_encode(unsigned int argc, + unsigned char **argv, + unsigned int *argv_lens, + unsigned int *argv_types); +void silc_argument_payload_free(SilcArgumentPayload payload); +unsigned int silc_argument_get_arg_num(SilcArgumentPayload payload); +unsigned char *silc_argument_get_first_arg(SilcArgumentPayload payload, + unsigned int *ret_len); +unsigned char *silc_argument_get_next_arg(SilcArgumentPayload payload, + unsigned int *ret_len); +unsigned char *silc_argument_get_arg_type(SilcArgumentPayload payload, + unsigned int type, + unsigned int *ret_len); + +#endif -- 2.24.0