+ silc_schedule_stop(silcd->schedule);
+}
+
+/* Dump server statistics into a file into /tmp directory */
+
+SILC_TASK_CALLBACK(dump_stats)
+{
+ FILE *fdd;
+ char filename[256];
+
+ memset(filename, 0, sizeof(filename));
+ snprintf(filename, sizeof(filename) - 1, "/tmp/silcd.%d.stats", getpid());
+ fdd = fopen(filename, "w+");
+ if (!fdd)
+ return;
+
+#define STAT_OUTPUT(fmt, stat) fprintf(fdd, fmt "\n", (int)stat);
+
+ fprintf(fdd, "SILC Server %s Statistics\n\n", silcd->server_name);
+ fprintf(fdd, "Local Stats:\n");
+ STAT_OUTPUT(" My clients : %d", silcd->stat.my_clients);
+ STAT_OUTPUT(" My servers : %d", silcd->stat.my_servers);
+ STAT_OUTPUT(" My routers : %d", silcd->stat.my_routers);
+ STAT_OUTPUT(" My channels : %d", silcd->stat.my_channels);
+ STAT_OUTPUT(" My joined users : %d", silcd->stat.my_chanclients);
+ STAT_OUTPUT(" My aways : %d", silcd->stat.my_aways);
+ STAT_OUTPUT(" My detached clients : %d", silcd->stat.my_detached);
+ STAT_OUTPUT(" My server operators : %d", silcd->stat.my_server_ops);
+ STAT_OUTPUT(" My router operators : %d", silcd->stat.my_router_ops);
+ fprintf(fdd, "\nGlobal Stats:\n");
+ STAT_OUTPUT(" Cell clients : %d", silcd->stat.cell_clients);
+ STAT_OUTPUT(" Cell servers : %d", silcd->stat.cell_servers);
+ STAT_OUTPUT(" Cell channels : %d", silcd->stat.cell_channels);
+ STAT_OUTPUT(" Cell joined users : %d", silcd->stat.cell_chanclients);
+ STAT_OUTPUT(" All clients : %d", silcd->stat.clients);
+ STAT_OUTPUT(" All servers : %d", silcd->stat.servers);
+ STAT_OUTPUT(" All routers : %d", silcd->stat.routers);
+ STAT_OUTPUT(" All channels : %d", silcd->stat.channels);
+ STAT_OUTPUT(" All joined users : %d", silcd->stat.chanclients);
+ STAT_OUTPUT(" All aways : %d", silcd->stat.aways);
+ STAT_OUTPUT(" All detached clients : %d", silcd->stat.detached);
+ STAT_OUTPUT(" All server operators : %d", silcd->stat.server_ops);
+ STAT_OUTPUT(" All router operators : %d", silcd->stat.router_ops);
+ fprintf(fdd, "\nGeneral Stats:\n");
+ STAT_OUTPUT(" Connection attempts : %d", silcd->stat.conn_attempts);
+ STAT_OUTPUT(" Connection failures : %d", silcd->stat.conn_failures);
+ STAT_OUTPUT(" Authentication attempts : %d", silcd->stat.auth_attempts);
+ STAT_OUTPUT(" Authentication failures : %d", silcd->stat.auth_failures);
+ STAT_OUTPUT(" Packets sent : %d", silcd->stat.packets_sent);
+ STAT_OUTPUT(" Packets received : %d", silcd->stat.packets_received);
+ STAT_OUTPUT(" Connections : %d", silcd->stat.conn_num);
+
+#undef STAT_OUTPUT
+
+#ifdef SILC_DEBUG
+ /* Dump internal flags */
+ fprintf(fdd, "\nDumping internal flags\n");
+ fprintf(fdd, " server_type : %d\n", silcd->server_type);
+ fprintf(fdd, " standalone : %d\n", silcd->standalone);
+ fprintf(fdd, " listenning : %d\n", silcd->listenning);
+ fprintf(fdd, " background : %d\n", silcd->background);
+ fprintf(fdd, " backup_router : %d\n", silcd->backup_router);
+ fprintf(fdd, " backup_primary : %d\n", silcd->backup_primary);
+ fprintf(fdd, " backup_noswitch : %d\n", silcd->backup_noswitch);
+ fprintf(fdd, " backup_closed : %d\n", silcd->backup_closed);
+ fprintf(fdd, " wait_backup : %d\n", silcd->wait_backup);
+ if (silcd->router)
+ fprintf(fdd, " primary router : %s\n",
+ silcd->router->server_name ? silcd->router->server_name : "");
+
+ /* Dump socket connections */
+ {
+ int i;
+ SilcSocketConnection s;
+
+ fprintf(fdd, "\nDumping socket connections\n");
+ for (i = 0; i < silcd->config->param.connections_max; i++) {
+ s = silcd->sockets[i];
+ if (!s)
+ continue;
+ fprintf(fdd, " %d: host %s ip %s port %d type %d flags 0x%x\n",
+ s->sock, s->hostname ? s->hostname : "N/A",
+ s->ip ? s->ip : "N/A", s->port, s->type,
+ (unsigned int)s->flags);
+ }
+ }
+
+ /* Dump lists */
+ {
+ SilcIDCacheList list = NULL;
+ SilcIDCacheEntry id_cache = NULL;
+ SilcServerEntry server_entry;
+ SilcClientEntry client_entry;
+ SilcChannelEntry channel_entry;
+ int c;
+
+ fprintf(fdd, "\nDumping databases\n");
+
+ if (silc_idcache_get_all(silcd->local_list->servers, &list)) {
+ if (silc_idcache_list_first(list, &id_cache)) {
+ fprintf(fdd, "\nServers in local-list:\n");
+ c = 1;
+ while (id_cache) {
+ server_entry = (SilcServerEntry)id_cache->context;
+ fprintf(fdd, " %d: name %s id %s status 0x%x\n", c,
+ server_entry->server_name ? server_entry->server_name :
+ "N/A", server_entry->id ?
+ silc_id_render(server_entry->id, SILC_ID_SERVER) : "N/A",
+ server_entry->data.status);
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ c++;
+ }
+ }
+ silc_idcache_list_free(list);
+ }
+ if (silc_idcache_get_all(silcd->global_list->servers, &list)) {
+ if (silc_idcache_list_first(list, &id_cache)) {
+ fprintf(fdd, "\nServers in global-list:\n");
+ c = 1;
+ while (id_cache) {
+ server_entry = (SilcServerEntry)id_cache->context;
+ fprintf(fdd, " %d: name %s id %s status 0x%x\n", c,
+ server_entry->server_name ? server_entry->server_name :
+ "N/A", server_entry->id ?
+ silc_id_render(server_entry->id, SILC_ID_SERVER) : "N/A",
+ server_entry->data.status);
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ c++;
+ }
+ }
+ silc_idcache_list_free(list);
+ }
+ if (silc_idcache_get_all(silcd->local_list->clients, &list)) {
+ if (silc_idcache_list_first(list, &id_cache)) {
+ fprintf(fdd, "\nClients in local-list:\n");
+ c = 1;
+ while (id_cache) {
+ client_entry = (SilcClientEntry)id_cache->context;
+ server_entry = client_entry->router;
+ fprintf(fdd, " %d: name %s id %s status 0x%x from %s\n", c,
+ client_entry->nickname ? client_entry->nickname :
+ (unsigned char *)"N/A", client_entry->id ?
+ silc_id_render(client_entry->id, SILC_ID_CLIENT) : "N/A",
+ client_entry->data.status, server_entry ?
+ server_entry->server_name ? server_entry->server_name :
+ "N/A" : "local");
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ c++;
+ }
+ }
+ silc_idcache_list_free(list);
+ }
+ if (silc_idcache_get_all(silcd->global_list->clients, &list)) {
+ if (silc_idcache_list_first(list, &id_cache)) {
+ fprintf(fdd, "\nClients in global-list:\n");
+ c = 1;
+ while (id_cache) {
+ client_entry = (SilcClientEntry)id_cache->context;
+ server_entry = client_entry->router;
+ fprintf(fdd, " %d: name %s id %s status 0x%x from %s\n", c,
+ client_entry->nickname ? client_entry->nickname :
+ (unsigned char *)"N/A", client_entry->id ?
+ silc_id_render(client_entry->id, SILC_ID_CLIENT) : "N/A",
+ client_entry->data.status, server_entry ?
+ server_entry->server_name ? server_entry->server_name :
+ "N/A" : "local");
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ c++;
+ }
+ }
+ silc_idcache_list_free(list);
+ }
+ if (silc_idcache_get_all(silcd->local_list->channels, &list)) {
+ if (silc_idcache_list_first(list, &id_cache)) {
+ fprintf(fdd, "\nChannels in local-list:\n");
+ c = 1;
+ while (id_cache) {
+ channel_entry = (SilcChannelEntry)id_cache->context;
+ fprintf(fdd, " %d: name %s id %s\n", c,
+ channel_entry->channel_name ? channel_entry->channel_name :
+ "N/A", channel_entry->id ?
+ silc_id_render(channel_entry->id, SILC_ID_CHANNEL) : "N/A");
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ c++;
+ }
+ }
+ silc_idcache_list_free(list);
+ }
+ if (silc_idcache_get_all(silcd->global_list->channels, &list)) {
+ if (silc_idcache_list_first(list, &id_cache)) {
+ fprintf(fdd, "\nChannels in global-list:\n");
+ c = 1;
+ while (id_cache) {
+ channel_entry = (SilcChannelEntry)id_cache->context;
+ fprintf(fdd, " %d: name %s id %s\n", c,
+ channel_entry->channel_name ? channel_entry->channel_name :
+ "N/A", channel_entry->id ?
+ silc_id_render(channel_entry->id, SILC_ID_CHANNEL) : "N/A");
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ c++;
+ }
+ }
+ silc_idcache_list_free(list);
+ }
+ }
+#endif
+
+ fflush(fdd);
+ fclose(fdd);
+}
+
+#ifdef SILC_DEBUG
+
+typedef struct {
+ int level;
+ const char *string;
+} DebugLevel;
+
+static DebugLevel debug_levels[] = {
+ /* Very basic stuff from silcd/ */
+ { 3, "silcd\\.c,server\\.c" },
+
+ /* More stuff from silcd/ */
+ { 7, "silcd\\.c,server\\.c,command\\.c,server_backup\\.c,packet_send\\.c" },
+
+ /* All basic stuff from silcd/ */
+ { 10, "silc_server_*" },
+
+ /* All from silcd/ */
+ { 15, "*silcd*,*serverid*,silc_server_*,*idlist*" },
+
+ /* All from silcd/ and basic stuff from libs */
+ { 20, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,*silcske*" },
+
+ /* All from silcd/ and more stuff from libs */
+ { 25, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
+ "*silcpacket*,*ske*,*silcrng*" },
+
+ /* All from silcd/ and even more stuff from libs */
+ { 30, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
+ "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*" },
+
+ /* All from silcd/ and even more stuff from libs + all from silccore */
+ { 35, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
+ "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
+ "*silcid*,*argument*" },
+
+ /* All from silcd/, all from silccore, silccrypt and silcmath */
+ { 40, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
+ "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
+ "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*" },
+
+ /* All from silcd/, all from silccore, silccrypt and silcmath + stuff
+ from silcutil */
+ { 45, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
+ "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
+ "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
+ "*sockconn*" },
+
+ /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff
+ from silcutil */
+ { 50, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
+ "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
+ "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
+ "*sockconn*,*net*" },
+
+ /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff
+ from silcutil */
+ { 55, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
+ "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
+ "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
+ "*sockconn*,*net*,*log*,*config*" },
+
+ /* All */
+ { 90, "*" },
+
+ { -1, NULL },
+};
+
+static void silc_get_debug_level(int level)
+{
+ int i;
+
+ if (level < 0)
+ return;
+
+ for (i = 0; debug_levels[i].string; i++)
+ if (level <= debug_levels[i].level) {
+ silc_log_set_debug_string(debug_levels[i].string);
+ break;
+ }
+}
+#endif /* SILC_DEBUG */
+
+/* This function should not be called directly but through the appropriate
+ wrapper macro defined in server.h */
+
+void silc_server_stderr(SilcLogType type, char *message)
+{
+ if (silcd->background) {
+ char *p, *n = message;
+
+ /* remove newlines if we are going to output it to a log file */
+ for (p = n; *p; p++) {
+ if (*p != '\n') {
+ if (p != n)
+ *n = *p;
+ n++;
+ }
+ }
+ *n = 0;
+
+ /* the message is freed inside the logging function */
+ silc_log_output(type, message);
+ }
+ else {
+ fprintf(stderr, "%s\n", message);
+ silc_free(message);
+ }