/* * @(#)Status.cpp * * This file is part of webCDwriter - Network CD/DVD Writing. * * Copyright (C) 1999-2006 Jörg P. M. Haeger * * webCDwriter is free software. See CDWserver.cpp for details. */ #include #include #include #include "Config.h" #include "HTTPRequest.h" #include "HTTPResponse.h" #include "HTTPServer.h" #include "LineReader.h" #include "PrintWriter.h" #include "Server.h" #include "ServerSocket.h" #include "Session.h" #include "Socket.h" #include "Status.h" #include "Store.h" #include "String.h" #include "Thread.h" #include "Version.h" template class RingBuffer { Item *items; int size, n, head; Item init; public: RingBuffer(int size, Item init) { items = new Item[size]; this->size = size; n = head = 0; this->init = init; } Item add(Item item) { Item old = items[(head + n) % size]; items[(head + n) % size] = item; if (n < size) { n++; old = init; } else head++; return old; } Item get(int i) { if (i >= n) throw new Exception("i >= n"); return items[(head + i) % size]; } int length() const { return n; } }; RingBuffer lastSessionResults(100, NULL); class StatusServer: public Thread { void run() { log.debug("StatusServer", "started"); ServerSocket serverSocket(config.getStatusPortNo()); for (int i = 1; ; i++) try { Socket *socket = serverSocket.accept(); log.debug("StatusServer", "Status-Request %d accepted", i); HTTPServer server(*socket); HTTPRequest request = server.nextRequest(); String s = "http://"; HTTPResponse response = HTTPResponse::movedPermanently( s + request.host + ":" + config.getPortNo() + "/status.html"); PrintWriter writer(socket->getOutputStream()); response.write(writer); delete socket; log.debug("StatusServer", "Status-Request %d terminated", i); } catch (Exception *e) { log.debug("StatusServer", "Exception: %s", e->getMessage().getBytes()); delete e; } } }; Status::Status() { log.putv("Status::Status()"); } int Status::infoNo = 0; int Status::sessionsNum0 = 0; int Status::sessionsNumNew = 0; int Status::sessionsTotal = 0; int Status::MBwritten0 = 0; int Status::MBwrittenNew = 0; String tdbgcolor = "\"colorTableCellBackground\""; String td = "colorTableCellBackground\">"; String TD = ""; String tr = ""; String TR = ""; void Status::addResult(String &date, String &time, String &user, int sizeKB, String &result, // String &from, String &to, String &label, String &contents) { Options::ProjectInfo &projectInfo) { if (result.indexOf("OK") >= 0) { sessionsNumNew++; MBwrittenNew += sizeKB / 1024; } String str = ""; str = str + td + ++sessionsTotal + TD + td + date + TD + td + time + TD + ""; if (config.getShowUsers()) str = str + user; else str = str + "anonymous"; str = str + TD + ""; if (sizeKB > 1024) str = str + (sizeKB / 1024) + " MB"; else str = str + sizeKB + " KB"; str = str + TD + td + result + TD; if (config.getActiveBoolean("askForProjectInfo")) str = str + td + projectInfo.from + TD + td + projectInfo.to + TD + td + projectInfo.label + TD + td + projectInfo.contents + TD; String *old = lastSessionResults.add(new String(str)); if (old != NULL) str = old; } static int scanToken(const char *str, int &pos, int &length) { while (str[pos] == ' ' || str[pos] == '\t') pos++; int i = pos; while (str[i] != 0 && str[i] != ' ' && str[i] != '\t' && str[i] != '\n') i++; return length = i-pos; } static String *td2(int colspan) { String td = "colorTableCellBackground\""; td = td + " colspan=\"" + colspan + "\">"; return new String(td); } void Status::readLastResults() { File sessions = new File(config.getLogDir(), "sessions"); FILE *file = fopen(sessions.getPath().getBytes(), "r"); if (file == NULL) return; while (1) { char lineStr[4 * 1024]; if (fgets(lineStr, sizeof lineStr, file) == NULL) break; String line = lineStr; String date, time, user, result; int sizeKB; int pos = 0, len; scanToken(lineStr, pos, len); date = line.substring(pos, pos + len); pos += len; scanToken(lineStr, pos, len); time = line.substring(pos, pos + len); pos += len; scanToken(lineStr, pos, len); user = line.substring(pos, pos + len); pos += len; scanToken(lineStr, pos, len); pos += len; scanToken(lineStr, pos, len); pos += len; scanToken(lineStr, pos, len); long long int size; if (sscanf(&lineStr[pos], "%lld", &size) != 1) continue; sizeKB = size / 1024; pos += len; scanToken(lineStr, pos, len); pos += len; scanToken(lineStr, pos, len); result = line.substring(pos, pos + len); result = result.replace('_', ' '); pos += len; Options::ProjectInfo projectInfo; scanToken(lineStr, pos, len); projectInfo.from = line.substring(pos, pos + len); projectInfo.from = projectInfo.from.replace('_', ' '); pos += len; scanToken(lineStr, pos, len); projectInfo.to = line.substring(pos, pos + len); projectInfo.to = projectInfo.to.replace('_', ' '); pos += len; scanToken(lineStr, pos, len); projectInfo.label = line.substring(pos, pos + len); projectInfo.label = projectInfo.label.replace('_', ' '); pos += len; scanToken(lineStr, pos, len); projectInfo.contents = line.substring(pos, pos + len); projectInfo.contents = projectInfo.contents.replace('_', ' '); pos += len; addResult(date, time, user, sizeKB, result, projectInfo); } fclose(file); sessionsNum0 = sessionsNumNew; sessionsNumNew = 0; MBwritten0 = MBwrittenNew; MBwrittenNew = 0; } void Status::start() { readLastResults(); if (config.getStatusPortNo() > 0) (new StatusServer())->start(); } String *Status::getAbout() { String str = ""; str = str + "\n" + "\n" + "\n" + "" + Version.product + " - <i18n>About</i18n>\n" + "\n" + "\n" + "\n"; str = str + "\n" + "\n\n"; #ifdef PRO str = str + "\n" + "\n\n"; #endif str = str + "\n" + "
\n" + "

" + Version.product + Version.productPro + " " + Version.version + "

\n" + "

" + Version.copyright + " " + Version.author + "

\n"; // License box String maxUsers = ""; maxUsers = maxUsers + Server::getMaxUsers(); if (Server::getMaxUsers() >= 10000) maxUsers = "Unlimited"; str = str + "
\n\n" + "colorTableGrid\" border=\"0\"" + " cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">" + "
\n" + "\n" + "colorTableHeaderBackground\">\n" + "" + td2(5) + Server::getLicense() + TD + TR + "\n" + tr + td + "S/N:" + TD + td + Server::getSerialNo() + TD + td + "Servers:" + TD + td + Server::getMaxServers() + TD + td + "Users at the same time:" + TD + td + maxUsers + TD + TR + "\n" + tr + td + "Features:" + TD + td2(5) + Server::getFeatures() + TD + TR + "\n" + tr + td + "Validity:" + TD + td2(5) + Server::getValidity() + TD + TR + "\n" + "
" + "License" + "
\n" + "
\n\n"; str = str + "
" + "This product includes software developed by the OpenSSL Project\n" + "for use in the OpenSSL Toolkit (" + "" + "http://www.openssl.org)." + "
" + "This product includes cryptographic software written by\n" + "Eric Young (eay@cryptsoft.com)." + "
\n\n" + "
\n\n" + "colorTableGrid\" border=\"0\"" + " cellpadding=\"0\" cellspacing=\"0\">" + "
\n" + "\n" + "colorTableHeaderBackground\">\n" + "\n" + "\n" + td + "Translator(s)" + TD + "\n" + "\n" + "
" + "Translation" + "
\n" + "
\n\n" + "
\n\n" + "colorTableGrid\" border=\"0\"" + " cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">" + "
\n" + "\n" + "colorTableHeaderBackground\">\n" + "\n"; if (config.cdrdaoInfo.length() > 0) str = str + "" + td + "cdrdao " + config.cdrdaoInfo + TD + "\n"; String cdrecordHome = Version.cdrecordHome; if (config.cdrecordInfo.indexOf("dummy") >= 0) cdrecordHome = Version.projectHome; str = str + "" + td + "" + config.cdrecordInfo + "" + TD + "\n"; if (config.growisofsInfo.length() > 0) str = str + "" + td + "dvd+rw-tools " + config.growisofsInfo + TD + "\n"; if (config.mpg123Info.length() > 0) str = str + "" + td + "mpg123 " + config.mpg123Info + TD + "\n"; if (config.ogg123Info.length() > 0) str = str + "" + td + "ogg123 " + config.ogg123Info + TD + "\n"; if (config.soxInfo.length() > 0) str = str + "" + td + "sox " + config.soxInfo + TD + "\n"; str = str + "" + td + "" + config.mkisofsInfo + "" + TD + "\n" + "
" + "The local " + Version.product + " uses\n" + "
\n" + "
\n\n"; str = str + "
\n" + "
\n"; str = str + "\n" + "\n"; return new String(str); } String *Status::getConnects() { String sessionsNum = ""; if (store == NULL) sessionsNum = "?"; else sessionsNum = sessionsNum + store->getSessionsNum(); String str = ""; str = str + "\n" + td + "Connections" + TD + td + Server::getActiveServersNum() + TD + td + config.getMaxOpenConnections() + TD + "\n" + td + "Projects" + TD + td + sessionsNum + TD + td + config.getMaxOpenSessions() + TD + "\n"; return new String(str); } String *Status::getSessions() { String str = ""; str = str + "colorTableHeaderBackground\">\n" + "No" + "Date" + "Time" + "User" + "Size" + "Result"; if (config.getActiveBoolean("askForProjectInfo")) str = str + "Initiator" + "Addressee" + "Project" + "Contents"; str = str + "\n\n"; int n = config.getActiveInt("historyLength"); int last = lastSessionResults.length() - 1; for (int i = 0; i < n && i <= last; i++) try { String row = *lastSessionResults.get(last - i); str = str + "" + row + "\n"; } catch (Exception *e) { delete e; } return new String(str); } String *Status::getStatistics() { String str = ""; str = str + "" + td + "Sessions" + TD + td + sessionsNumNew + TD + td + (sessionsNum0 + sessionsNumNew) + TD + "\n" + "" + td + "GB written" + TD + td + (MBwrittenNew / 1024) + TD + td + ((MBwritten0 + MBwrittenNew) / 1024) + TD + "\n"; return new String(str); } String *Status::getStatus() { String str = ""; if (config.getFirstError().length() > 0) { str = str + "

Server Configuration Error

\n" + "

" + config.getFirstError() + "

\n"; char str2[16 * 1024]; strcpy(str2, config.getFirstErrorHelp().getBytes()); replace(str2, "[", "\n
\n"); replace(str2, "]", "\n
\n"); str = str + str2 + "\n" + "

Reload this page to try again!

\n"; return new String(str); } if (store == NULL) { str = str + "

Problem: store == NULL

\n" + "

Make sure you have " + "glibc2/libc6 installed!

\n"; return new String(str); } return new String(str); } String *Status::getStore() { String maxSize, size, total; if (store == NULL) { maxSize = "?"; size = "?"; total = "?"; } else { maxSize = maxSize + store->getMaxSizeInMB(); size = size + store->getSizeInMB(); total = total + store->getSessionsTotal(); } String str = ""; str = str + "" + td + total + " projects" + TD + td + config.getMaxMBytesPerSession() + " MB per project" + TD + "" + td + size + " MB" + TD + td + maxSize + " MB" + TD + "\n"; return new String(str); } String *Status::getWriters() { String str = ""; for (int i = 0; i < config.getNumOfWriters(); i++) { str = str + "" + td + config.getWriterExternalNo(i) + TD + td + config.getWriterInfo(i) + TD + td + config.getWriterSupports(i) + TD + td; int addColumn = 1, showPercent = 1; switch (Server::getWriterStatus(i)) { case idle: str = str + "free"; showPercent = 0; break; case reserved: { str = str + "reserved"; if (config.getShowUsers()) { str = str + " by " + Server::getWriterOwnerUser(i) + "@" + Server::getWriterOwnerIP(i); } struct timeval t; gettimeofday(&t, NULL); t.tv_sec = min(t.tv_sec, Server::getWriterReservedUntil(i)); char str2[1024]; str = str + TD + td + secondsToString( Server::getWriterReservedUntil(i) - t.tv_sec, str2); addColumn = 0; showPercent = 0; break; } case reading: str = str + "reading " + Server::getWriterStateMedium(i); break; case blanking: str = str + "blanking CD-RW"; break; case mkisofs: str = str + "creating image"; break; case writing: str = str + "writing " + Server::getWriterStateMedium(i); break; case fixating: str = str + "fixating " + Server::getWriterStateMedium(i); break; case verifying: str = str + "verifying " + Server::getWriterStateMedium(i); break; } if (addColumn) str = str + TD + td + " "; if (showPercent) str = str + Server::getWriterPercent(i) + "%"; str = str + TD + ""; } return new String(str); } Status status;