Added silcstress.
authorPekka Riikonen <priikone@silcnet.org>
Sun, 1 May 2005 20:54:18 +0000 (20:54 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sun, 1 May 2005 20:54:18 +0000 (20:54 +0000)
apps/Makefile.ad
apps/silcstress/Makefile.am [new file with mode: 0644]
apps/silcstress/configure.ad [new file with mode: 0644]
apps/silcstress/silcstress.c [new file with mode: 0644]

index 9d24796a6f71ad750e01d15cac8fd1d94e9f433a..5b380a463dcaeb5edf8ac2857d164202714b15be 100644 (file)
@@ -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 (file)
index 0000000..2c2aaa9
--- /dev/null
@@ -0,0 +1,25 @@
+#
+#  Makefile.am
+#
+#  Author: Pekka Riikonen <priikone@silcnet.org>
+#
+#  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 (file)
index 0000000..4fa59e0
--- /dev/null
@@ -0,0 +1,25 @@
+#ifdef SILC_DIST_INPLACE
+#
+#  apps/silcstress/configure.ad
+#
+#  Author: Pekka Riikonen <priikone@silcnet.org>
+#
+#  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 (file)
index 0000000..5eda5dc
--- /dev/null
@@ -0,0 +1,584 @@
+/*
+
+  silcstress.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  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 <priikone@silcnet.org>\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
+};