From 4f37fdfdc573decce5f3853449dac1bc0201bb7e Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Sun, 1 May 2005 20:54:18 +0000 Subject: [PATCH] Added silcstress. --- apps/Makefile.ad | 4 +- apps/silcstress/Makefile.am | 25 ++ apps/silcstress/configure.ad | 25 ++ apps/silcstress/silcstress.c | 584 +++++++++++++++++++++++++++++++++++ 4 files changed, 637 insertions(+), 1 deletion(-) create mode 100644 apps/silcstress/Makefile.am create mode 100644 apps/silcstress/configure.ad create mode 100644 apps/silcstress/silcstress.c diff --git a/apps/Makefile.ad b/apps/Makefile.ad index 9d24796a..5b380a46 100644 --- a/apps/Makefile.ad +++ b/apps/Makefile.ad @@ -27,4 +27,6 @@ SUBDIRS = \ #ifdef SILC_DIST_CLIENT @IRSSI_SUBDIR@ \ #endif SILC_DIST_CLIENT - +#ifdef SILC_DIST_INPLACE + silcstress +#endif SILC_DIST_INPLACE diff --git a/apps/silcstress/Makefile.am b/apps/silcstress/Makefile.am new file mode 100644 index 00000000..2c2aaa90 --- /dev/null +++ b/apps/silcstress/Makefile.am @@ -0,0 +1,25 @@ +# +# Makefile.am +# +# Author: Pekka Riikonen +# +# Copyright (C) 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. +# + +AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign + +bin_PROGRAMS = silcstress +silcstress_SOURCES = silcstress.c + +LIBS = -lsilcclient $(SILC_COMMON_LIBS) + +include $(top_srcdir)/Makefile.defines.in diff --git a/apps/silcstress/configure.ad b/apps/silcstress/configure.ad new file mode 100644 index 00000000..4fa59e0c --- /dev/null +++ b/apps/silcstress/configure.ad @@ -0,0 +1,25 @@ +#ifdef SILC_DIST_INPLACE +# +# apps/silcstress/configure.ad +# +# Author: Pekka Riikonen +# +# Copyright (C) 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. +# + +# +# Makefile outputs +# +AC_CONFIG_FILES( +apps/silcstress/Makefile +) +#endif SILC_DIST_INPLACE diff --git a/apps/silcstress/silcstress.c b/apps/silcstress/silcstress.c new file mode 100644 index 00000000..5eda5dcc --- /dev/null +++ b/apps/silcstress/silcstress.c @@ -0,0 +1,584 @@ +/* + + silcstress.c + + Author: Pekka Riikonen + + Copyright (C) 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. + +*/ + +/* + TODO: + + - join to created clients with another client, to get the sent messages + as reply (channel message). + - create x clients + +*/ + +/* + Results: + + SILC Server 0.9.20 (debug), Linux 2.6.11, RAM 512 MB: + + - 3000 channels == silcd size 10 MB (-c 3000 -n) + - 10000 channels == silcd size 37 MB (-c 10000 -n) + (Flooding channel creation is very heavy operation for silcd; JOIN + should be controlled better in silcd) + + - 1 channel, default data flood, QoS == silcd load < 1.0% + - 10 channels, default data flood, QoS == silcd load < 4.0% + - 100 channels, default data flood, QoS == silcd load < 5.0% + (Qos: rate=20, bytes_limit=500B, usec_limit=200000) + +*/ + +#include "silcincludes.h" +#include "silcclient.h" + +typedef struct { + SilcClient client; + SilcClientConnection conn; + int msize; + int loops; + int flood; + int channels; + bool nosend; + SilcMutex m; +} *SilcStress; + +typedef struct { + SilcStress sc; + SilcChannelEntry channel; +} *SilcStressWorker; + +SilcClientOperations ops; + +/* Long command line options */ +static struct option long_opts[] = +{ + { "server", 1, NULL,'s' }, + { "port", 1, NULL,'p' }, + { "channels", 1, NULL,'c' }, + { "msize", 1, NULL,'m' }, + { "loops", 1, NULL,'l' }, + { "flood", 1, NULL,'f' }, + { "nosend", 0, NULL,'n' }, + { "debug", 2, NULL, 'd' }, + { "help", 0, NULL, 'h' }, + { "version", 0, NULL,'V' }, + + { NULL, 0, NULL, 0 } +}; + +static void silc_stress_usage(void) +{ + printf("" +"Usage: silcstress [options]\n" +"\n" +" Generic Options:\n" +" -s --server=server Server to connect\n" +" -p --port=NUMBER Server port to connect (def: 706)\n" +" -c --channels=NUMBER Number of channels to create (def: 1)\n" +" -m --msize=NUMBER Size of message in bytes (def: 512)\n" +" -l --loops=NUMBER Number of loops to send data (def: 1024)\n" +" -f --flood=NUMBER Send message in every usec (def: 50000)\n" +" -n --nosend Don't send any data\n" +" -d --debug=string Enable debugging\n" +" -h --help Display this message and exit\n" +" -V --version Display version and exit\n" +"\n"); + exit(0); +} + +int main(int argc, char **argv) +{ + int opt, option_index; + int c = 1, port = 706, b = 512, l = 1024, f = 50000, n = FALSE; + char *server = NULL; + SilcStress sc; + + if (argc > 1) { + while ((opt = getopt_long(argc, argv, "d:hVc:s:p:m:l:f:n", + long_opts, &option_index)) != EOF) { + switch(opt) { + case 'h': + silc_stress_usage(); + break; + case 'V': + printf("SILC Stress, version %s\n", silc_dist_version); + printf("(c) 2005 Pekka Riikonen \n"); + exit(0); + break; + case 'd': +#ifdef SILC_DEBUG + silc_debug = TRUE; + silc_debug_hexdump = TRUE; + if (optarg) + silc_log_set_debug_string(optarg); + silc_log_quick = TRUE; +#else + fprintf(stderr, + "Run-time debugging is not enabled. To enable it recompile\n" + "the server with --enable-debug configuration option.\n"); +#endif + break; + case 'c': + c = atoi(optarg); + break; + case 'l': + l = atoi(optarg); + break; + case 'f': + f = atoi(optarg); + break; + case 'm': + b = atoi(optarg); + break; + case 'p': + port = atoi(optarg); + break; + case 's': + server = strdup(optarg); + break; + case 'n': + n = TRUE; + break; + default: + silc_stress_usage(); + break; + } + } + } + + if (!server) + silc_stress_usage(); + + sc = silc_calloc(1, sizeof(*sc)); + if (!sc) + return 1; + sc->channels = c; + sc->msize = b; + sc->loops = l; + sc->flood = f; + sc->nosend = n; + + sc->client = silc_client_alloc(&ops, NULL, sc, NULL); + if (!sc->client) + return 1; + + sc->client->username = silc_get_username(); + sc->client->hostname = silc_net_localhost(); + sc->client->realname = strdup("SILC STRESS"); + + if (!silc_client_init(sc->client)) + return 1; + + if (!silc_load_key_pair("silcstress.pub", "silcstress.prv", "", + &sc->client->pkcs, + &sc->client->public_key, + &sc->client->private_key)) { + if (!silc_create_key_pair("rsa", 2048, "silcstress.pub", + "silcstress.prv", NULL, "", + &sc->client->pkcs, + &sc->client->public_key, + &sc->client->private_key, FALSE)) { + return 1; + } + } + + silc_mutex_alloc(&sc->m); + + silc_client_connect_to_server(sc->client, NULL, port, server, sc); + + silc_client_run(sc->client); + + silc_client_free(sc->client); + silc_free(sc); + silc_free(server); + + return 0; +} + +/* Worker thread */ + +static void * +silc_stress_worker(void *context) +{ + SilcStressWorker w = context; + SilcClient client = w->sc->client; + SilcClientConnection conn = w->sc->conn; + SilcChannelEntry channel = w->channel; + char *tmp; + int i; + + tmp = silc_calloc(w->sc->msize, sizeof(*tmp)); + if (!tmp) + return NULL; + + memset(tmp, 'M', w->sc->msize); + + for (i = 0; i < w->sc->loops; i++) { + /* Our packet routines don't like threads, so let's lock :( */ + silc_mutex_lock(w->sc->m); + if (!w->sc->conn) + return NULL; + silc_client_send_channel_message(client, conn, channel, NULL, 0, + tmp, w->sc->msize, TRUE); + silc_mutex_unlock(w->sc->m); + usleep(w->sc->flood); + } + + silc_free(tmp); + + return NULL; +} + + +/* "say" client operation is a message from the client library to the + application. It may include error messages or something else. We + just dump them to screen. */ + +static void +silc_say(SilcClient client, SilcClientConnection conn, + SilcClientMessageType type, char *msg, ...) +{ + char str[200]; + va_list va; + va_start(va, msg); + vsnprintf(str, sizeof(str) - 1, msg, va); + fprintf(stdout, "%s\n", str); + va_end(va); +} + + +/* Message for a channel. The `sender' is the sender of the message + The `channel' is the channel. The `message' is the message. Note + that `message' maybe NULL. The `flags' indicates message flags + and it is used to determine how the message can be interpreted + (like it may tell the message is multimedia message). */ + +static void +silc_channel_message(SilcClient client, SilcClientConnection conn, + SilcClientEntry sender, SilcChannelEntry channel, + SilcMessagePayload payload, + SilcChannelPrivateKey key, + SilcMessageFlags flags, const unsigned char *message, + SilcUInt32 message_len) +{ + +} + + +/* Private message to the client. The `sender' is the sender of the + message. The message is `message'and maybe NULL. The `flags' + indicates message flags and it is used to determine how the message + can be interpreted (like it may tell the message is multimedia + message). */ + +static void +silc_private_message(SilcClient client, SilcClientConnection conn, + SilcClientEntry sender, SilcMessagePayload payload, + SilcMessageFlags flags, + const unsigned char *message, + SilcUInt32 message_len) +{ +} + + +/* Notify message to the client. The notify arguments are sent in the + same order as servers sends them. The arguments are same as received + from the server except for ID's. If ID is received application receives + the corresponding entry to the ID. For example, if Client ID is received + application receives SilcClientEntry. Also, if the notify type is + for channel the channel entry is sent to application (even if server + does not send it because client library gets the channel entry from + the Channel ID in the packet's header). */ + +static void +silc_notify(SilcClient client, SilcClientConnection conn, + SilcNotifyType type, ...) +{ + +} + + +/* Command handler. This function is called always in the command function. + If error occurs it will be called as well. `conn' is the associated + client connection. `cmd_context' is the command context that was + originally sent to the command. `success' is FALSE if error occurred + during command. `command' is the command being processed. It must be + noted that this is not reply from server. This is merely called just + after application has called the command. Just to tell application + that the command really was processed. */ + +static void +silc_command(SilcClient client, SilcClientConnection conn, + SilcClientCommandContext cmd_context, bool success, + SilcCommand command, SilcStatus status) +{ + /* If error occurred in client library with our command, print the error */ + if (status != SILC_STATUS_OK) + fprintf(stderr, "COMMAND %s: %s\n", + silc_get_command_name(command), + silc_get_status_message(status)); +} + + +/* Command reply handler. This function is called always in the command reply + function. If error occurs it will be called as well. Normal scenario + is that it will be called after the received command data has been parsed + and processed. The function is used to pass the received command data to + the application. + + `conn' is the associated client connection. `cmd_payload' is the command + payload data received from server and it can be ignored. It is provided + if the application would like to re-parse the received command data, + however, it must be noted that the data is parsed already by the library + thus the payload can be ignored. `success' is FALSE if error occurred. + In this case arguments are not sent to the application. The `status' is + the command reply status server returned. The `command' is the command + reply being processed. The function has variable argument list and each + command defines the number and type of arguments it passes to the + application (on error they are not sent). */ + +static void +silc_command_reply(SilcClient client, SilcClientConnection conn, + SilcCommandPayload cmd_payload, bool success, + SilcCommand command, SilcStatus status, ...) +{ + SilcStress sc = client->application; + va_list va; + + /* If error occurred in client library with our command, print the error */ + if (status != SILC_STATUS_OK) + fprintf(stderr, "COMMAND REPLY %s: %s\n", + silc_get_command_name(command), + silc_get_status_message(status)); + + va_start(va, status); + + /* Check for successful JOIN */ + if (command == SILC_COMMAND_JOIN && sc->nosend == FALSE) { + /* Create worker thread for data sending */ + SilcThread t; + SilcChannelEntry channel; + SilcStressWorker w; + + (void)va_arg(va, SilcClientEntry); + channel = va_arg(va, SilcChannelEntry); + + w = silc_calloc(1, sizeof(*w)); + if (!w) + exit(1); + + w->sc = sc; + w->channel = channel; + + t = silc_thread_create(silc_stress_worker, w, FALSE); + } + + va_end(va); +} + + +/* Called to indicate that connection was either successfully established + or connecting failed. This is also the first time application receives + the SilcClientConnection objecet which it should save somewhere. + If the `success' is FALSE the application must always call the function + silc_client_close_connection. */ + +static void +silc_connected(SilcClient client, SilcClientConnection conn, + SilcClientConnectionStatus status) +{ + SilcStress sc = client->application; + char tmp[16]; + int i; + + if (status != SILC_CLIENT_CONN_SUCCESS) { + fprintf(stderr, "Could not connect to server\n"); + silc_client_close_connection(client, conn); + return; + } + + fprintf(stdout, "Connected to server.\n"); + + /* Save the connection context */ + sc->conn = conn; + + /* Join channels */ + for (i = 0; i < sc->channels; i++) { + memset(tmp, 0, sizeof(tmp)); + snprintf(tmp, sizeof(tmp) - 1, "JOIN %d", i); + silc_client_command_call(client, conn, tmp); + } + + +} + + +/* Called to indicate that connection was disconnected to the server. + The `status' may tell the reason of the disconnection, and if the + `message' is non-NULL it may include the disconnection message + received from server. */ + +static void +silc_disconnected(SilcClient client, SilcClientConnection conn, + SilcStatus status, const char *message) +{ + SilcStress sc = client->application; + + /* We got disconnected from server */ + sc->conn = NULL; + fprintf(stdout, "%s:%s\n", silc_get_status_message(status), + message); +} + + +/* Find authentication method and authentication data by hostname and + port. The hostname may be IP address as well. When the authentication + method has been resolved the `completion' callback with the found + authentication method and authentication data is called. The `conn' + may be NULL. */ + +static void +silc_get_auth_method(SilcClient client, SilcClientConnection conn, + char *hostname, SilcUInt16 port, + SilcGetAuthMeth completion, + void *context) +{ + completion(TRUE, SILC_AUTH_NONE, NULL, 0, context); +} + + +/* Verifies received public key. The `conn_type' indicates which entity + (server, client etc.) has sent the public key. If user decides to trust + the application may save the key as trusted public key for later + use. The `completion' must be called after the public key has been + verified. */ + +static void +silc_verify_public_key(SilcClient client, SilcClientConnection conn, + SilcSocketType conn_type, unsigned char *pk, + SilcUInt32 pk_len, SilcSKEPKType pk_type, + SilcVerifyPublicKey completion, void *context) +{ + completion(TRUE, context); +} + + +/* Ask (interact, that is) a passphrase from user. The passphrase is + returned to the library by calling the `completion' callback with + the `context'. The returned passphrase SHOULD be in UTF-8 encoded, + if not then the library will attempt to encode. */ + +static void +silc_ask_passphrase(SilcClient client, SilcClientConnection conn, + SilcAskPassphrase completion, void *context) +{ + completion(NULL, 0, context); +} + + +/* Notifies application that failure packet was received. This is called + if there is some protocol active in the client. The `protocol' is the + protocol context. The `failure' is opaque pointer to the failure + indication. Note, that the `failure' is protocol dependant and + application must explicitly cast it to correct type. Usually `failure' + is 32 bit failure type (see protocol specs for all protocol failure + types). */ + +static void +silc_failure(SilcClient client, SilcClientConnection conn, + SilcProtocol protocol, void *failure) +{ + fprintf(stderr, "Connecting failed (protocol failure)\n"); +} + + +/* Asks whether the user would like to perform the key agreement protocol. + This is called after we have received an key agreement packet or an + reply to our key agreement packet. This returns TRUE if the user wants + the library to perform the key agreement protocol and FALSE if it is not + desired (application may start it later by calling the function + silc_client_perform_key_agreement). If TRUE is returned also the + `completion' and `context' arguments must be set by the application. */ + +static bool +silc_key_agreement(SilcClient client, SilcClientConnection conn, + SilcClientEntry client_entry, const char *hostname, + SilcUInt16 port, SilcKeyAgreementCallback *completion, + void **context) +{ + return FALSE; +} + + +/* Notifies application that file transfer protocol session is being + requested by the remote client indicated by the `client_entry' from + the `hostname' and `port'. The `session_id' is the file transfer + session and it can be used to either accept or reject the file + transfer request, by calling the silc_client_file_receive or + silc_client_file_close, respectively. */ + +static void +silc_ftp(SilcClient client, SilcClientConnection conn, + SilcClientEntry client_entry, SilcUInt32 session_id, + const char *hostname, SilcUInt16 port) +{ + +} + + +/* Delivers SILC session detachment data indicated by `detach_data' to the + application. If application has issued SILC_COMMAND_DETACH command + the client session in the SILC network is not quit. The client remains + in the network but is detached. The detachment data may be used later + to resume the session in the SILC Network. The appliation is + responsible of saving the `detach_data', to for example in a file. + + The detachment data can be given as argument to the functions + silc_client_connect_to_server, or silc_client_add_connection when + creating connection to remote server, inside SilcClientConnectionParams + structure. If it is provided the client library will attempt to resume + the session in the network. After the connection is created + successfully, the application is responsible of setting the user + interface for user into the same state it was before detaching (showing + same channels, channel modes, etc). It can do this by fetching the + information (like joined channels) from the client library. */ + +static void +silc_detach(SilcClient client, SilcClientConnection conn, + const unsigned char *detach_data, SilcUInt32 detach_data_len) +{ + +} + +SilcClientOperations ops = { + silc_say, + silc_channel_message, + silc_private_message, + silc_notify, + silc_command, + silc_command_reply, + silc_connected, + silc_disconnected, + silc_get_auth_method, + silc_verify_public_key, + silc_ask_passphrase, + silc_failure, + silc_key_agreement, + silc_ftp, + silc_detach +}; -- 2.43.0