/* ==================================================================== Disconnect from current server if any. ==================================================================== */ void client_disconnect() { #ifdef NETWORK_ENABLED char buf[128]; if ( !client_is_connected ) return; /* disconnect */ socket_print_stats( &client ); sprintf( buf, _("disconnected from %s"), net_addr_to_string(&client.remote_addr) ); client_add_chatter( buf, 1 ); buf[0] = MSG_DISCONNECT; client_transmit( CODE_BLUE, 1, buf ); client_is_connected = 0; client_data_clear(); gui_label_set_text( label_channel, "MAIN" ); #endif }
NSAPI_PUBLIC Session *session_fill(Session *ns) { pool_handle_t *pool = pool_create(); ns->pool = pool; systhread_setdata(getThreadMallocKey(), ns->pool); ns->client = pblock_create(SESSION_HASHSIZE); ns->inbuf = netbuf_open(ns->csd, NET_BUFFERSIZE); ns->fill = 1; char session_ipaddr[sizeof "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255"]; if (ns->pr_client_addr) { if (ns->pr_client_addr->raw.family == PR_AF_INET || ns->pr_client_addr->raw.family == PR_AF_INET6) { net_addr_to_string(ns->pr_client_addr, session_ipaddr, sizeof(session_ipaddr)); pblock_kvinsert(pb_key_ip, session_ipaddr, strlen(session_ipaddr), ns->client); } } else { net_inet_ntoa(ns->iaddr, session_ipaddr); pblock_kvinsert(pb_key_ip, session_ipaddr, strlen(session_ipaddr), ns->client); } session_fill_cla(pool, ns); NSAPISession *nsn = (NSAPISession *)ns; nsn->thread_data = NULL; nsn->httpfilter = NULL; nsn->input_done = PR_FALSE; nsn->input_os_pos = 0; nsn->exec_rq = NULL; nsn->filter_rq = NULL; nsn->session_clone = PR_FALSE; nsn->received = 0; nsn->transmitted = 0; INTsession_fill_ssl(ns); return ns; }
int write_stats_dump(PRFileDesc *fd, StatsHeaderNode *hdr) { int i = 0; StatsManager::lockStatsData(); const StatsHeader *hdrStats = &hdr->hdrStats; // Version PR_fprintf(fd, "\n%s\n", hdrStats->versionServer); // Uptime char buffer[25]; PRExplodedTime tm; PR_ExplodeTime(hdrStats->timeStarted, PR_LocalTimeParameters, &tm); PR_FormatTimeUSEnglish(buffer, sizeof(buffer), "%c", &tm); PR_fprintf(fd, "\nServer started %s\n", buffer); { StatsProcessNode *process = hdr->process; while (process) { const StatsProcessSlot *procStats = &process->procStats; PR_ExplodeTime(procStats->timeStarted, PR_LocalTimeParameters, &tm); PR_FormatTimeUSEnglish(buffer, sizeof(buffer), "%c", &tm); PR_fprintf(fd, "Process %d started %s\n", procStats->pid, buffer); process = process->next; } } // ConnectionQueue { StatsConnectionQueueSlot connqueues; memset(&connqueues, 0, sizeof(connqueues)); // Accumulate connection queue buckets for every process StatsProcessNode *process = hdr->process; while (process) { StatsConnectionQueueNode *connQueueNode = process->connQueue; while (connQueueNode) { const StatsConnectionQueueSlot *connqueue = &connQueueNode->connQueueStats; connqueues.countQueued += connqueue->countQueued; connqueues.peakQueued += connqueue->peakQueued; connqueues.maxQueued += connqueue->maxQueued; connqueues.countOverflows += connqueue->countOverflows; connqueues.countTotalQueued += connqueue->countTotalQueued; connqueues.ticksTotalQueued += connqueue->ticksTotalQueued; connqueues.countTotalConnections += connqueue->countTotalConnections; connqueues.countQueued1MinuteAverage += connqueue->countQueued1MinuteAverage; connqueues.countQueued5MinuteAverage += connqueue->countQueued5MinuteAverage; connqueues.countQueued15MinuteAverage += connqueue->countQueued15MinuteAverage; connQueueNode = connQueueNode->next; } process = process->next; } PRFloat64 count = (PRInt64)connqueues.countTotalQueued; PRFloat64 ticks = (PRInt64)connqueues.ticksTotalQueued; if (count < 1.0) count = 1.0; PR_fprintf(fd, "\nConnectionQueue:\n" "-----------------------------------------\n" "Current/Peak/Limit Queue Length %d/%d/%d\n" "Total Connections Queued %llu\n" "Average Queue Length (1, 5, 15 minutes) %4.2f, %4.2f, %4.2f\n" "Average Queueing Delay %.2f milliseconds\n", connqueues.countQueued, connqueues.peakQueued, connqueues.maxQueued, connqueues.countTotalQueued, connqueues.countQueued1MinuteAverage, connqueues.countQueued5MinuteAverage, connqueues.countQueued15MinuteAverage, ticks / count / hdrStats->ticksPerSecond * 1000.0); } // Listen sockets { StatsProcessNode *process = hdr->process; StatsListenNode *lsNode = (process) ? process->ls : 0; while (lsNode) { StatsListenSlot *ls = &lsNode->lsStats; PRNetAddr addr; memcpy(&addr, &ls->address, sizeof(ls->address)); char szAddress[512]; memset(szAddress, 0, sizeof(szAddress)); net_addr_to_string(&addr, szAddress, sizeof(szAddress)-1); PR_fprintf(fd, "\nListenSocket %s:\n" "------------------------\n" "Address %s://%s:%hu\n" "Acceptor Threads %d\n" "Default Virtual Server %s\n", ls->id, ls->flagSecure ? "https" : "http", szAddress, PR_ntohs(ls->address.inet.port), ls->countAcceptors, ls->defaultVsId ); lsNode = lsNode->next; } } // Keepalive Info { StatsKeepaliveBucket keepalives; memset(&keepalives, 0, sizeof(keepalives)); // Accumulate keepalive buckets for every process StatsProcessNode *process = hdr->process; while (process) { StatsKeepaliveBucket *procKeepAlive = NULL; procKeepAlive = &process->procStats.keepAliveBucket; StatsManagerUtil::accumulateKeepAlive(&keepalives, procKeepAlive); process = process->next; } PR_fprintf(fd, "\nKeepAliveInfo:\n" "--------------------\n" "KeepAliveCount %lu/%lu\n" "KeepAliveHits %llu\n" "KeepAliveFlushes %llu\n" "KeepAliveRefusals %llu\n" "KeepAliveTimeouts %llu\n" "KeepAliveTimeout %lu seconds\n", keepalives.countConnections, keepalives.maxConnections, keepalives.countHits, keepalives.countFlushes, keepalives.countRefusals, keepalives.countTimeouts, keepalives.secondsTimeout); } // Session Creation Info { PRUint32 countThreads = 0; PRUint32 countBusy = 0; PRUint32 countKeepAlive = 0; PRUint32 countKeepAliveThreads = 0; // Count the number of active threads StatsProcessNode *process = hdr->process; while (process) { StatsProcessSlot *procStats = &process->procStats; if (procStats->mode != STATS_PROCESS_EMPTY) { StatsThreadNode *thread = process->thread; while (thread) { const StatsThreadSlot *threadStats = &thread->threadStats; if (threadStats->mode != STATS_THREAD_EMPTY) { countThreads++; if (threadStats->mode == STATS_THREAD_KEEPALIVE) { countKeepAlive++; } else if (threadStats->mode != STATS_THREAD_IDLE) { countBusy++; } } thread = thread->next; } } // Get number of keepalive threads StatsKeepaliveBucket *procKeepAlive = NULL; procKeepAlive = &process->procStats.keepAliveBucket; countKeepAliveThreads += procKeepAlive->numThreads; process = process->next; } PR_fprintf(fd, "\nSessionCreationInfo:\n" "------------------------\n" "Active Sessions %lu\n" "Keep-Alive Sessions %lu\n" "Total Sessions Created %lu/%lu\n", countBusy, countKeepAlive, countThreads, (hdrStats->maxThreads * hdrStats->maxProcs + countKeepAliveThreads)); } // Cache Info { StatsCacheBucket caches; memset(&caches, 0, sizeof(caches)); // Accumulate cache buckets for every process StatsProcessNode *process = hdr->process; while (process) { StatsCacheBucket *procCache = NULL; procCache = &process->procStats.cacheBucket; StatsManagerUtil::accumulateCache(&caches, procCache); process = process->next; } if (caches.flagEnabled) { PR_fprintf(fd, "\nCacheInfo:\n" "-----------------------\n"); PRInt64 fileLookups = caches.countHits + caches.countMisses; PR_fprintf(fd, "File Cache Enabled yes\n" "File Cache Entries %lu/%lu\n" "File Cache Hit Ratio %llu/%lld (%6.2f%%)\n" "Maximum Age %d\n", caches.countEntries, caches.maxEntries, caches.countHits, fileLookups, percent(caches.countHits, fileLookups), caches.secondsMaxAge); PRInt64 accelRequests = caches.countAcceleratableRequests + caches.countUnacceleratableRequests; PRInt64 accelResponses = caches.countAcceleratableResponses + caches.countUnacceleratableResponses; PRInt64 accelLookups = caches.countAcceleratorHits + caches.countAcceleratorMisses; PR_fprintf(fd, "Accelerator Entries %lu/%lu\n" "Acceleratable Requests %llu/%lld (%6.2f%%)\n" "Acceleratable Responses %llu/%lld (%6.2f%%)\n" "Accelerator Hit Ratio %llu/%lld (%6.2f%%)\n", caches.countAcceleratorEntries, caches.maxEntries, caches.countAcceleratableRequests, accelRequests, percent(caches.countAcceleratableRequests, accelRequests), caches.countAcceleratableResponses, accelResponses, percent(caches.countAcceleratableResponses, accelResponses), caches.countAcceleratorHits, accelLookups, percent(caches.countAcceleratorHits, accelLookups)); } else { PR_fprintf(fd, "\nServer cache disabled\n"); } } // Thread pool info { StatsThreadPoolBucket pools[FUNC_MAXPOOLS]; const char *names[FUNC_MAXPOOLS]; memset(pools, 0, sizeof(pools)); memset(names, 0, sizeof(names)); // Accumulate thread pool buckets for every process StatsProcessNode *process = hdr->process; while (process) { StatsThreadPoolNode *pool = process->threadPool; for (i = 0; pool && (i < FUNC_MAXPOOLS); i++) { StatsManagerUtil::accumulateThreadPool(&pools[i], &pool->threadPoolStats); names[i] = STATS_GET_NAME(&pool->threadPoolStats); pool = pool->next; } process = process->next; } int poolFlag = 0; for (i = 0; i < FUNC_MAXPOOLS; i++) { if (names[i]) { if (!poolFlag) { poolFlag = 1; PR_fprintf(fd, "\nNative pools:\n" "----------------------------\n"); } PR_fprintf(fd, "%s:\n" "Idle/Peak/Limit %lu/%lu/%lu\n" "Work Queue Length/Peak/Limit %lu/%lu/%lu\n", names[i], pools[i].countThreadsIdle, pools[i].countThreads, pools[i].maxThreads, pools[i].countQueued, pools[i].peakQueued, pools[i].maxQueued); } } } // DNS info { StatsDnsBucket dnss; memset(&dnss, 0, sizeof(dnss)); // Accumulate DNS buckets for every process StatsProcessNode *process = hdr->process; while (process) { StatsManagerUtil::accumulateDNS(&dnss, &process->procStats.dnsBucket); process = process->next; } if (dnss.flagCacheEnabled) { PRUint32 totalhits = dnss.countCacheMisses + dnss.countCacheHits; float hitratio; if (totalhits > 0.0) hitratio = (float)dnss.countCacheHits / (float)totalhits; else hitratio = 0.0; PR_fprintf(fd, "\nDNSCacheInfo:\n" "------------------\n" "enabled yes\n" "CacheEntries %lu/%lu\n" "HitRatio %lu/%lu (%6.2f%%)\n", dnss.countCacheEntries, dnss.maxCacheEntries, dnss.countCacheHits, totalhits, hitratio * 100.0); } else { PR_fprintf(fd, "\nServer DNS cache disabled\n"); } if (dnss.flagAsyncEnabled) { PR_fprintf(fd, "\nAsyncDNS Data:\n" "------------------\n" "enabled yes\n" "NameLookups %lu\n" "AddrLookups %lu\n" "LookupsInProgress %lu\n", dnss.countAsyncNameLookups, dnss.countAsyncAddrLookups, dnss.countAsyncLookupsInProgress); } else { PR_fprintf(fd, "\nAsync DNS disabled\n"); } } // NSAPI Profile Info if (hdrStats->maxProfileBuckets) { int i; StatsProfileBucket *profiles = new StatsProfileBucket[hdrStats->maxProfileBuckets]; const char **names = new const char*[hdrStats->maxProfileBuckets]; const char **descs = new const char*[hdrStats->maxProfileBuckets]; memset(profiles, 0, sizeof(profiles[0]) * hdrStats->maxProfileBuckets); memset(names, 0, sizeof(names[0]) * hdrStats->maxProfileBuckets); memset(descs, 0, sizeof(descs[0]) * hdrStats->maxProfileBuckets); // Accumulate profiles for every thread StatsProcessNode *process = hdr->process; while (process) { StatsThreadNode *thread = process->thread; while (thread) { StatsProfileNode *profile = thread->profile; for (i = 0; i < hdrStats->maxProfileBuckets; i++) { StatsManagerUtil::accumulateProfile(&profiles[i], &profile->profileStats); names[i] = STATS_GET_NAME(&profile->profileStats); descs[i] = STATS_GET_DESCRIPTION(&profile->profileStats); profile = profile->next; } thread = thread->next; } process = process->next; } PRInt64 tr = profiles[STATS_PROFILE_ALL].countRequests; PRInt64 tc = profiles[STATS_PROFILE_ALL].countCalls; float td = (float)(PRInt64)profiles[STATS_PROFILE_ALL].ticksDispatch; float tf = (float)(PRInt64)profiles[STATS_PROFILE_ALL].ticksFunction; td /= hdrStats->ticksPerSecond; tf /= hdrStats->ticksPerSecond; float tt = td + tf; PR_fprintf(fd, "\nPerformance Counters:\n" "------------------------------------------------\n" " Average Total Percent\n\n" "Total number of requests: %10llu\n" "Request processing time: %7.4f %12.4f\n", tr, (tr > 0) ? (tt / (float)tr) : 0, tt); for (i = hdrStats->maxProfileBuckets-1; i >= STATS_PROFILE_DEFAULT; i--) { PRInt64 r = profiles[i].countRequests; PRInt64 c = profiles[i].countCalls; const char *name = names[i]; // Don't display cache-bucket if it's empty. This is a predefined // bucket that stored NSAPI accelerator cache statistics in // previous versions of the server. if (!c && i == STATS_PROFILE_CACHE && !strcmp(name, "cache-bucket")) { continue; } float d = (float)(PRInt64)profiles[i].ticksDispatch; float f = (float)(PRInt64)profiles[i].ticksFunction; d /= hdrStats->ticksPerSecond; f /= hdrStats->ticksPerSecond; float t = d + f; PR_fprintf(fd, "\n%s (%s)\n" "Number of Requests: %12llu (%6.2f%%)\n" "Number of Invocations: %12llu (%6.2f%%)\n" "Latency: %7.4f %12.4f (%6.2f%%)\n" "Function Processing Time: %7.4f %12.4f (%6.2f%%)\n" "Total Response Time: %7.4f %12.4f (%6.2f%%)\n", name, SAFESTRING(descs[i]), r, (tr > 0) ? (100.0 * r / (PRFloat64) tr) : 0, c, (tc > 0) ? (100.0 * c / (PRFloat64) tc) : 0, (r > 0)? (d / r): 0, d, (tt > 0)? (100 * d / tt): 0, (r > 0)? (f / r): 0, f, (tt > 0)? (100 * f / tt): 0, (r > 0)? (t / r): 0, t, (tt > 0)? (100 * t / tt): 0); } delete[] profiles; delete[] names; delete[] descs; } else { PR_fprintf(fd, "\nPerformance Statistics disabled\n"); } // Session info { StatsProcessNode *process; int x; int y; // Count the number of rows in our session table int nr = 0; for (process = hdr->process; process; process = process->next) { StatsThreadNode *thread; for (thread = process->thread; thread; thread = thread->next) nr++; } SessionRow *rows = new SessionRow[nr]; PRTime now = PR_Now(); // Collect stats from each session y = 0; for (process = hdr->process; process; process = process->next) { StatsThreadNode *thread; for (thread = process->thread; thread; thread = thread->next) { thread->lock(); PRUint32 mode = thread->threadStats.mode; if (mode != STATS_THREAD_EMPTY && mode != STATS_THREAD_IDLE && mode != STATS_THREAD_KEEPALIVE) { rows[y].columns[SESSION_COLUMN_PROCESS].printf("%u", process->procStats.pid); rows[y].columns[SESSION_COLUMN_STATUS] = StatsManager::getMode(&thread->threadStats); char addr[NET_ADDR_STRING_SIZE]; net_addr_to_string(&thread->threadStats.addressClient, addr, sizeof(addr)); rows[y].columns[SESSION_COLUMN_CLIENT] = addr; rows[y].timeRequestStarted = thread->threadStats.timeRequestStarted; if (rows[y].timeRequestStarted != 0) { PRTime microseconds = now - rows[y].timeRequestStarted; int seconds = (microseconds + PR_USEC_PER_SEC/2) / PR_USEC_PER_SEC; rows[y].columns[SESSION_COLUMN_AGE].printf("%d", seconds); } rows[y].columns[SESSION_COLUMN_VS] = thread->threadStats.vsId; rows[y].columns[SESSION_COLUMN_METHOD] = thread->threadStats.requestBucket.method; rows[y].columns[SESSION_COLUMN_URI] = thread->threadStats.requestBucket.uri; rows[y].columns[SESSION_COLUMN_FUNCTION] = STATS_GET_FUNCTION_NAME(&thread->threadStats); y++; } thread->unlock(); } } // We'll only display stats for active sessions PR_ASSERT(y <= nr); nr = y; // Each column is at least as wide as its label int widths[SESSION_COLUMN_COUNT]; for (x = 0; x < SESSION_COLUMN_COUNT; x++) widths[x] = session_column_labels[x].length(); // Ensure each column is wide enough to fit its largest value for (y = 0; y < nr; y++) { for (x = 0; x < SESSION_COLUMN_COUNT; x++) { if (widths[x] < rows[y].columns[x].length()) widths[x] = rows[y].columns[x].length(); } } // Leave at least 2 spaces between columns for (x = 0; x < SESSION_COLUMN_COUNT - 1; x++) widths[x] += 2; // Calculate total line width and individual column offsets int width = 0; int offsets[SESSION_COLUMN_COUNT]; for (x = 0 ; x < SESSION_COLUMN_COUNT; x++) { offsets[x] = width; width += widths[x]; } char *line = (char *) malloc(width + sizeof('\n')); // Output table heading and column labels PR_fprintf(fd, "\nSessions:\n"); memset(line, '-', width); line[width] = '\n'; PR_Write(fd, line, width + sizeof('\n')); PR_Write(fd, line, format_session(line, offsets, session_column_labels)); PR_Write(fd, "\n", 1); // Sort rows by age const SessionRow **sorted = new const SessionRow *[nr]; for (y = 0; y < nr; y++) sorted[y] = &rows[y]; qsort(sorted, nr, sizeof(sorted[0]), &session_cmp); // Output individual rows for (y = 0; y < nr; y++) PR_Write(fd, line, format_session(line, offsets, sorted[y]->columns)); delete [] sorted; free(line); delete [] rows; } StatsManager::unlockStatsData(); return REQ_PROCEED; }