#include #include #include #include "../shared/CommandDispatcher.h" #include "../shared/ReplyToClient.h" #include "../shared/LogFile.h" #include "UserInfo.h" #include "../shared/ThreadMonitor.h" #include "../shared/GlobalConfigFile.h" #include "Download.h" DownloadThread::DownloadThread() : ThreadClass("DownloadThread"), _incomingRequests("DownloadThread") { // We have just one configurable item. The base directory makes it easy for // the development server to share files with the live server most of the // time, but to point to other places for the sake of testing. There is no // need for an more configuration items in the code. Use soft links to do // more. const std::string baseDir = getConfigItem("download_base_dir", "Downloads/"); _locationList["/GifCharts/"] = Location(baseDir + "GifCharts/", true); _locationList["/Filters/"] = Location(baseDir + "Filters/"); _locationList["/Alerts/"] = Location(baseDir + "Alerts/"); _locationList["/Texture/"] = Location(baseDir + "Texture/"); _locationList["/Misc/"] = Location(baseDir + "Misc/"); _locationList["/Status/"] = Location(baseDir + "Status/", true); CommandDispatcher *dispatcher = CommandDispatcher::getInstance(); dispatcher->listenForCommand("download", &_incomingRequests, mtExternalRequest); startThread(); } DownloadThread::~DownloadThread() { Request *r = new Request(NULL); r->callbackId = mtQuit; _incomingRequests.newRequest(r); waitForThread(); } std::string DownloadThread::getData(DownloadRequest *request) { std::string filename = request->file; if ((filename.find('\0') != filename.npos) || (filename.find('/') != filename.npos)) { TclList logMsg; logMsg<<"Download.C" <<"Invlalid char in filename" <location <file; LogFile::primary().sendString(logMsg, request->getSocketInfo()); return ""; } Location *location = getProperty(_locationList, request->location); if (!location) { TclList logMsg; logMsg<<"Download.C" <<"Invlalid location" <location <file; LogFile::primary().sendString(logMsg, request->getSocketInfo()); return ""; } if (location->_requiresLogin) { UserInfoStatus status = userInfoGetInfo(request->getSocketInfo()).status; if ((status != sSuspended) && (status != sFull)) { ThreadMonitor::find().increment("NO PERMISSION"); return ""; } } ThreadMonitor::find().increment(request->location); filename = location->_directory + filename; int handle = open(filename.c_str(), O_RDONLY); if (handle < 0) { std::string errorMsg(errorString()); TclList logMsg; logMsg<<"Download.C" <<"Error opening file" <location <file <getSocketInfo()); return ""; } std::string result(getDataFromFile(handle, filename, request->getSocketInfo())); close(handle); return result; } std::string DownloadThread::getDataFromFile(int handle, std::string filename, SocketInfo *socket) { struct stat fileInfo; int statResult = fstat(handle, &fileInfo); if (statResult) { std::string errorMsg(errorString()); TclList logMsg; logMsg<<"Download.C" <<"Error calling stat on file" < 200000) { TclList logMsg; logMsg<<"Download.C" <<"Error, file is too big" < (long)result.length()) { char buffer[1024]; int countThisTime = read(handle, buffer, std::min(sizeof(buffer), fileInfo.st_size - result.length())); if (countThisTime < 0) { std::string errorMsg(errorString()); TclList logMsg; logMsg<<"Download.C" <<"Error, calling read on file" <callbackId) { case mtExternalRequest: { ExternalRequest *incoming = dynamic_cast(current); DownloadRequest *outgoing = new DownloadRequest(incoming->getSocketInfo()); outgoing->returnMessageId = incoming->getResponseMessageId(); outgoing->location = incoming->getProperty("location"); outgoing->file = incoming->getProperty("file"); pendingRequests.push(outgoing); break; } case mtQuit: { delete current; return; } case DeleteSocketThread::callbackId: { SocketInfo *socket = current->getSocketInfo(); pendingRequests.remove(socket); break; } } delete current; } if (pendingRequests.empty()) { _incomingRequests.waitForRequest(); } else { DownloadRequest *current = dynamic_cast(pendingRequests.pop()); addToOutputQueue(current->getSocketInfo(), getData(current), current->returnMessageId); delete current; } } }