2016-05-15 11:22:35 +06:00
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers , whose names
* are too numerous to list here . Please refer to the COPYRIGHT
* file distributed with this source distribution .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*
*/
# define FORBIDDEN_SYMBOL_ALLOW_ALL
2016-05-16 01:05:40 +06:00
# include "backends/networking/curl/connectionmanager.h"
# include "backends/networking/curl/networkreadstream.h"
2016-05-15 11:22:35 +06:00
# include "common/debug.h"
2016-05-18 15:21:09 +06:00
# include "common/system.h"
# include "common/timer.h"
2016-05-15 11:22:35 +06:00
# include <curl/curl.h>
2016-05-27 22:15:43 +06:00
namespace Common {
2016-05-18 15:21:09 +06:00
DECLARE_SINGLETON ( Networking : : ConnectionManager ) ;
2016-05-15 11:22:35 +06:00
2016-05-27 22:15:43 +06:00
}
2016-05-16 01:05:40 +06:00
namespace Networking {
2016-05-15 11:22:35 +06:00
2016-06-04 20:18:32 +06:00
ConnectionManager : : ConnectionManager ( ) : _multi ( 0 ) , _timerStarted ( false ) , _frame ( 0 ) {
2016-05-15 11:22:35 +06:00
curl_global_init ( CURL_GLOBAL_ALL ) ;
_multi = curl_multi_init ( ) ;
}
ConnectionManager : : ~ ConnectionManager ( ) {
2016-06-01 14:07:50 +06:00
//terminate all requests
_handleMutex . lock ( ) ;
for ( Common : : Array < RequestWithCallback > : : iterator i = _requests . begin ( ) ; i ! = _requests . end ( ) ; + + i ) {
Request * request = i - > request ;
2016-06-02 11:37:10 +06:00
RequestCallback callback = i - > onDeleteCallback ;
2016-06-01 14:07:50 +06:00
if ( request ) request - > finish ( ) ;
delete request ;
if ( callback ) ( * callback ) ( request ) ;
}
2016-06-03 18:04:48 +06:00
_requests . clear ( ) ;
2016-06-01 14:07:50 +06:00
//cleanup
2016-05-15 11:22:35 +06:00
curl_multi_cleanup ( _multi ) ;
curl_global_cleanup ( ) ;
2016-06-03 18:04:48 +06:00
_multi = nullptr ;
_handleMutex . unlock ( ) ;
2016-05-15 11:22:35 +06:00
}
2016-05-18 15:21:09 +06:00
void ConnectionManager : : registerEasyHandle ( CURL * easy ) {
curl_multi_add_handle ( _multi , easy ) ;
}
2016-06-01 12:39:10 +06:00
Request * ConnectionManager : : addRequest ( Request * request , RequestCallback callback ) {
_requests . push_back ( RequestWithCallback ( request , callback ) ) ;
2016-05-18 15:21:09 +06:00
if ( ! _timerStarted ) startTimer ( ) ;
2016-05-27 15:21:06 +06:00
return request ;
2016-05-26 17:56:13 +06:00
}
2016-06-05 15:44:05 +06:00
void ConnectionManager : : showCloudDisabledIcon ( ) {
_icon . showDisabled ( ) ;
startTimer ( ) ;
}
2016-05-18 15:21:09 +06:00
//private goes here:
void connectionsThread ( void * ignored ) {
ConnMan . handle ( ) ;
}
void ConnectionManager : : startTimer ( int interval ) {
Common : : TimerManager * manager = g_system - > getTimerManager ( ) ;
if ( manager - > installTimerProc ( connectionsThread , interval , 0 , " Networking::ConnectionManager's Timer " ) ) {
_timerStarted = true ;
} else {
warning ( " Failed to install Networking::ConnectionManager's timer " ) ;
}
}
void ConnectionManager : : stopTimer ( ) {
2016-05-26 21:40:01 +06:00
debug ( " timer stopped " ) ;
2016-05-18 15:21:09 +06:00
Common : : TimerManager * manager = g_system - > getTimerManager ( ) ;
manager - > removeTimerProc ( connectionsThread ) ;
_timerStarted = false ;
2016-05-15 11:22:35 +06:00
}
void ConnectionManager : : handle ( ) {
2016-06-01 14:07:50 +06:00
//lock mutex here (in case another handle() would be called before this one ends)
_handleMutex . lock ( ) ;
2016-06-03 18:04:48 +06:00
+ + _frame ;
if ( _frame % CLOUD_PERIOD = = 0 ) interateRequests ( ) ;
if ( _frame % CURL_PERIOD = = 0 ) processTransfers ( ) ;
2016-06-04 20:18:32 +06:00
if ( _icon . draw ( ) & & _requests . empty ( ) )
stopTimer ( ) ;
_handleMutex . unlock ( ) ;
2016-05-18 15:21:09 +06:00
}
void ConnectionManager : : interateRequests ( ) {
//call handle() of all running requests (so they can do their work)
2016-05-27 15:21:06 +06:00
debug ( " handling %d request(s) " , _requests . size ( ) ) ;
2016-06-01 12:39:10 +06:00
for ( Common : : Array < RequestWithCallback > : : iterator i = _requests . begin ( ) ; i ! = _requests . end ( ) ; ) {
2016-06-03 19:54:20 +06:00
Request * request = i - > request ;
if ( request ) {
if ( request - > state ( ) = = PROCESSING ) request - > handle ( ) ;
else if ( request - > state ( ) = = RETRY ) request - > handleRetry ( ) ;
}
2016-05-27 15:21:06 +06:00
if ( ! request | | request - > state ( ) = = FINISHED ) {
2016-06-01 12:39:10 +06:00
delete ( i - > request ) ;
2016-06-02 11:37:10 +06:00
if ( i - > onDeleteCallback ) ( * i - > onDeleteCallback ) ( i - > request ) ; //that's not a mistake (we're passing an address and that method knows there is no object anymore)
2016-05-27 15:21:06 +06:00
_requests . erase ( i ) ;
continue ;
}
+ + i ;
2016-05-18 15:21:09 +06:00
}
}
void ConnectionManager : : processTransfers ( ) {
2016-06-03 18:04:48 +06:00
if ( ! _multi ) return ;
2016-05-18 15:21:09 +06:00
//check libcurl's transfers and notify requests of messages from queue (transfer completion or failure)
2016-05-17 01:19:49 +06:00
int transfersRunning ;
curl_multi_perform ( _multi , & transfersRunning ) ;
2016-05-15 11:22:35 +06:00
2016-05-17 01:19:49 +06:00
int messagesInQueue ;
2016-05-15 11:22:35 +06:00
CURLMsg * curlMsg ;
2016-05-17 01:19:49 +06:00
while ( ( curlMsg = curl_multi_info_read ( _multi , & messagesInQueue ) ) ) {
CURL * easyHandle = curlMsg - > easy_handle ;
2016-05-15 11:22:35 +06:00
2016-05-17 01:19:49 +06:00
NetworkReadStream * stream ;
curl_easy_getinfo ( easyHandle , CURLINFO_PRIVATE , & stream ) ;
2016-05-17 20:17:41 +06:00
if ( stream ) stream - > finished ( ) ;
2016-05-15 11:22:35 +06:00
2016-05-17 01:19:49 +06:00
if ( curlMsg - > msg = = CURLMSG_DONE ) {
2016-05-18 15:21:09 +06:00
debug ( " ConnectionManager: SUCCESS (%d - %s) " , curlMsg - > data . result , curl_easy_strerror ( curlMsg - > data . result ) ) ;
2016-05-16 01:05:40 +06:00
} else {
2016-05-18 15:21:09 +06:00
debug ( " ConnectionManager: FAILURE (CURLMsg (%d)) " , curlMsg - > msg ) ;
2016-05-15 11:22:35 +06:00
}
2016-05-17 01:19:49 +06:00
curl_multi_remove_handle ( _multi , easyHandle ) ;
2016-05-15 11:22:35 +06:00
}
}
2016-05-28 20:10:38 +02:00
} // End of namespace Cloud