ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

connectionmanager.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #define FORBIDDEN_SYMBOL_ALLOW_ALL
00024 
00025 #include <curl/curl.h>
00026 #include "backends/networking/curl/connectionmanager.h"
00027 #include "backends/networking/curl/networkreadstream.h"
00028 #include "common/debug.h"
00029 #include "common/fs.h"
00030 #include "common/system.h"
00031 #include "common/timer.h"
00032 
00033 namespace Common {
00034 
00035 DECLARE_SINGLETON(Networking::ConnectionManager);
00036 
00037 }
00038 
00039 namespace Networking {
00040 
00041 ConnectionManager::ConnectionManager(): _multi(0), _timerStarted(false), _frame(0) {
00042     curl_global_init(CURL_GLOBAL_ALL);
00043     _multi = curl_multi_init();
00044 }
00045 
00046 ConnectionManager::~ConnectionManager() {
00047     stopTimer();
00048 
00049     //terminate all requests
00050     _handleMutex.lock();
00051     for (Common::Array<RequestWithCallback>::iterator i = _requests.begin(); i != _requests.end(); ++i) {
00052         Request *request = i->request;
00053         RequestCallback callback = i->onDeleteCallback;
00054         if (request)
00055             request->finish();
00056         delete request;
00057         if (callback)
00058             (*callback)(request);
00059     }
00060     _requests.clear();
00061 
00062     //cleanup
00063     curl_multi_cleanup(_multi);
00064     curl_global_cleanup();
00065     _multi = nullptr;
00066     _handleMutex.unlock();
00067 }
00068 
00069 void ConnectionManager::registerEasyHandle(CURL *easy) const {
00070     curl_multi_add_handle(_multi, easy);
00071 }
00072 
00073 Request *ConnectionManager::addRequest(Request *request, RequestCallback callback) {
00074     _addedRequestsMutex.lock();
00075     _addedRequests.push_back(RequestWithCallback(request, callback));
00076     if (!_timerStarted)
00077         startTimer();
00078     _addedRequestsMutex.unlock();
00079     return request;
00080 }
00081 
00082 Common::String ConnectionManager::urlEncode(Common::String s) const {
00083     if (!_multi)
00084         return "";
00085 #if LIBCURL_VERSION_NUM >= 0x070F04
00086     char *output = curl_easy_escape(_multi, s.c_str(), s.size());
00087 #else
00088     char *output = curl_escape(s.c_str(), s.size());
00089 #endif
00090     if (output) {
00091         Common::String result = output;
00092         curl_free(output);
00093         return result;
00094     }
00095     return "";
00096 }
00097 
00098 uint32 ConnectionManager::getCloudRequestsPeriodInMicroseconds() {
00099     return TIMER_INTERVAL * CLOUD_PERIOD;
00100 }
00101 
00102 const char *ConnectionManager::getCaCertPath() {
00103 #if defined(DATA_PATH)
00104     static enum {
00105         kNotInitialized,
00106         kFileNotFound,
00107         kFileExists
00108     } state = kNotInitialized;
00109 
00110     if (state == kNotInitialized) {
00111         Common::FSNode node(DATA_PATH"/cacert.pem");
00112         state = node.exists() ? kFileExists : kFileNotFound;
00113     }
00114 
00115     if (state == kFileExists) {
00116         return DATA_PATH"/cacert.pem";
00117     } else {
00118         return nullptr;
00119     }
00120 #else
00121     return nullptr;
00122 #endif
00123 }
00124 
00125 //private goes here:
00126 
00127 void connectionsThread(void *ignored) {
00128     ConnMan.handle();
00129 }
00130 
00131 void ConnectionManager::startTimer(int interval) {
00132     Common::TimerManager *manager = g_system->getTimerManager();
00133     if (manager->installTimerProc(connectionsThread, interval, 0, "Networking::ConnectionManager's Timer")) {
00134         _timerStarted = true;
00135     } else {
00136         warning("Failed to install Networking::ConnectionManager's timer");
00137     }
00138 }
00139 
00140 void ConnectionManager::stopTimer() {
00141     debug(9, "timer stopped");
00142     Common::TimerManager *manager = g_system->getTimerManager();
00143     manager->removeTimerProc(connectionsThread);
00144     _timerStarted = false;
00145 }
00146 
00147 bool ConnectionManager::hasAddedRequests() {
00148     _addedRequestsMutex.lock();
00149     bool hasNewRequests = !_addedRequests.empty();
00150     _addedRequestsMutex.unlock();
00151     return hasNewRequests;
00152 }
00153 
00154 void ConnectionManager::handle() {
00155     //lock mutex here (in case another handle() would be called before this one ends)
00156     _handleMutex.lock();
00157     ++_frame;
00158     if (_frame % CLOUD_PERIOD == 0)
00159         interateRequests();
00160     if (_frame % CURL_PERIOD == 0)
00161         processTransfers();
00162 
00163     if (_requests.empty() && !hasAddedRequests())
00164         stopTimer();
00165     _handleMutex.unlock();
00166 }
00167 
00168 void ConnectionManager::interateRequests() {
00169     //add new requests
00170     _addedRequestsMutex.lock();
00171     for (Common::Array<RequestWithCallback>::iterator i = _addedRequests.begin(); i != _addedRequests.end(); ++i) {
00172         _requests.push_back(*i);
00173     }
00174     _addedRequests.clear();
00175     _addedRequestsMutex.unlock();
00176 
00177     //call handle() of all running requests (so they can do their work)
00178     if (_frame % DEBUG_PRINT_PERIOD == 0)
00179         debug(9, "handling %d request(s)", _requests.size());
00180     for (Common::Array<RequestWithCallback>::iterator i = _requests.begin(); i != _requests.end();) {
00181         Request *request = i->request;
00182         if (request) {
00183             if (request->state() == PROCESSING)
00184                 request->handle();
00185             else if (request->state() == RETRY)
00186                 request->handleRetry();
00187         }
00188 
00189         if (!request || request->state() == FINISHED) {
00190             delete (i->request);
00191             if (i->onDeleteCallback)
00192                 (*i->onDeleteCallback)(i->request); //that's not a mistake (we're passing an address and that method knows there is no object anymore)
00193             _requests.erase(i);
00194             continue;
00195         }
00196 
00197         ++i;
00198     }
00199 }
00200 
00201 void ConnectionManager::processTransfers() {
00202     if (!_multi) return;
00203 
00204     //check libcurl's transfers and notify requests of messages from queue (transfer completion or failure)
00205     int transfersRunning;
00206     curl_multi_perform(_multi, &transfersRunning);
00207 
00208     int messagesInQueue;
00209     CURLMsg *curlMsg;
00210     while ((curlMsg = curl_multi_info_read(_multi, &messagesInQueue))) {
00211         if (curlMsg->msg == CURLMSG_DONE) {
00212             CURL *easyHandle = curlMsg->easy_handle;
00213 
00214             NetworkReadStream *stream = nullptr;
00215             curl_easy_getinfo(easyHandle, CURLINFO_PRIVATE, &stream);
00216 
00217             if (stream)
00218                 stream->finished(curlMsg->data.result);
00219 
00220             curl_multi_remove_handle(_multi, easyHandle);
00221         } else {
00222             warning("Unknown libcurl message type %d", curlMsg->msg);
00223         }
00224     }
00225 }
00226 
00227 } // End of namespace Cloud


Generated on Sat May 30 2020 05:00:33 for ResidualVM by doxygen 1.7.1
curved edge   curved edge