18 #include "precompiled.h"
34 #define DEBUG_UPLOADS 0
96 curl_easy_setopt(
m_Curl, CURLOPT_VERBOSE, 1L);
103 curl_easy_setopt(
m_Curl, CURLOPT_NOSIGNAL, 1L);
106 curl_easy_setopt(
m_Curl, CURLOPT_FOLLOWLOCATION, 0L);
110 curl_easy_setopt(
m_Curl, CURLOPT_WRITEDATA,
this);
112 curl_easy_setopt(
m_Curl, CURLOPT_READDATA,
this);
115 curl_easy_setopt(
m_Curl, CURLOPT_URL, url.c_str());
116 curl_easy_setopt(
m_Curl, CURLOPT_POST, 1L);
121 std::string ua =
"User-Agent: 0ad ";
122 ua += curl_version();
123 ua +=
" (http://play0ad.com/)";
126 m_Headers = curl_slist_append(m_Headers,
"Content-Type: application/octet-stream");
128 m_Headers = curl_slist_append(m_Headers,
"Accept: ");
129 curl_easy_setopt(
m_Curl, CURLOPT_HTTPHEADER, m_Headers);
149 curl_easy_cleanup(
m_Curl);
203 void Submit(
const shared_ptr<CUserReport>& report)
325 debug_printf(L
">>> CUserReporterWorker status: %hs\n", status.c_str());
333 shared_ptr<CUserReport> report;
352 TIMER(L
"CUserReporterWorker request");
355 CURLcode err = curl_easy_perform(
m_Curl);
364 curl_easy_getinfo(
m_Curl, CURLINFO_RESPONSE_CODE, &code);
365 SetStatus(
"completed:" + CStr::FromInt(code));
408 r +=
"&time=" + CStr::FromInt64(report.
m_Time);
413 r +=
"&version=" + CStr::FromInt(report.
m_Version);
422 std::string compressed;
423 compressed.resize(compressBound(r.size()));
424 uLongf destLen = compressed.size();
425 int ok = compress((Bytef*)compressed.c_str(), &destLen, (
const Bytef*)r.c_str(), r.size());
427 compressed.resize(destLen);
434 char* escaped = curl_easy_escape(
m_Curl, str.c_str(), str.size());
443 if (self->GetShutdown())
446 self->
m_ResponseData += std::string((
char*)buffer, (
char*)buffer+size*nmemb);
451 static size_t SendCallback(
char* bufptr,
size_t size,
size_t nmemb,
void* userp)
455 if (self->GetShutdown())
456 return CURL_READFUNC_ABORT;
459 size_t amount = std::min(self->m_RequestData.size() -
self->m_RequestDataOffset, size*nmemb);
463 amount = std::min((
size_t)1024, amount);
467 memcpy(bufptr, &self->m_RequestData[self->m_RequestDataOffset], amount);
468 self->m_RequestDataOffset += amount;
471 self->SetStatus(
"sending:" + CStr::FromDouble((
double)self->m_RequestDataOffset / self->m_RequestData.size()));
526 if (userID.length() != 16)
533 for (
size_t i = 0; i <
ARRAY_SIZE(bytes); ++i)
550 CFG_GET_VAL(
"userreport.enabledversion", Int, version);
583 curl_global_init(CURL_GLOBAL_ALL & ~CURL_GLOBAL_WIN32);
600 curl_global_cleanup();
623 report->m_Time = time(NULL);
624 report->m_Type = type;
625 report->m_Version = version;
626 report->m_Data = data;
void SetStatus(const std::string &status)
void Update()
Must be called frequently (preferably every frame), to update some internal reconnection timers...
static const double TIMER_CHECK_INTERVAL
Time interval (seconds) at which the worker thread will check its reconnection timers.
CUserReporter g_UserReporter
static const double RECONNECT_INVERVAL
Seconds we should wait before reconnecting to the server after a failure.
void AppendEscaped(std::string &buffer, const std::string &str)
std::string m_RequestData
std::string utf8_from_wstring(const std::wstring &src, Status *err)
opposite of wstring_from_utf8
#define CFG_GET_VAL(name, type, destination)
std::string m_ResponseData
CUserReporterWorker(const std::string &userID, const std::string &url)
Locks a CMutex over this object's lifetime.
CUserReporterWorker * m_Worker
Status sys_get_proxy_config(const std::wstring &url, std::wstring &proxy)
get the proxy address for accessing the given HTTP URL.
A non-recursive mutual exclusion lock.
std::deque< shared_ptr< CUserReport > > m_ReportQueue
int sprintf_s(char *buf, size_t max_chars, const char *fmt,...) PRINTF_ARGS(3)
LIB_API void debug_SetThreadName(const char *name)
inform the debugger of the current thread's name.
void SDL_DestroySemaphore(SDL_sem *sem)
char m_ErrorBuffer[CURL_ERROR_SIZE]
#define ENSURE(expr)
ensure the expression <expr> evaluates to non-zero.
#define PROFILE2(region)
Starts timing from now until the end of the current scope.
int pthread_create(pthread_t *thread_id, const void *attr, void *(*func)(void *), void *arg)
void SubmitReport(const char *type, int version, const std::string &data)
Submit a report to be transmitted to the online server.
static const int REPORTER_VERSION
Version number stored in config file when the user agrees to the reporting.
bool Shutdown()
Called by main thread to request shutdown.
New profiler (complementing the older CProfileManager)
void RegisterCurrentThread(const std::string &name)
Call in any thread to enable the profiler in that thread.
void Submit(const shared_ptr< CUserReport > &report)
Called by main thread to add a new report to the queue.
size_t m_RequestDataOffset
#define SAFE_DELETE(p)
delete memory ensuing from new and set the pointer to zero (thus making double-frees safe / a no-op) ...
void Update()
Called by the main thread every frame, so we can check retransmission timers.
void ConstructRequestData(const CUserReport &report)
Status sys_generate_random_bytes(u8 *buf, size_t count)
generate high-quality random bytes.
static void * RunThread(void *data)
#define TIMER(description)
Measures the time taken to execute code up until end of the current scope; displays it via debug_prin...
std::wstring wstring_from_utf8(const std::string &src, Status *err)
convert UTF-8 to a wide string (UTF-16 or UCS-4, depending on the platform's wchar_t).
SDL_sem * SDL_CreateSemaphore(int cnt)
void RecordRegionEnter(const char *id)
void SetReportingEnabled(bool enabled)
static size_t SendCallback(char *bufptr, size_t size, size_t nmemb, void *userp)
std::string GetStatus()
Called by main thread to determine the current status of the uploader.
static size_t ReceiveCallback(void *buffer, size_t size, size_t nmemb, void *userp)
void RecordRegionLeave(const char *id)
int pthread_join(pthread_t thread, void **value_ptr)
void SetEnabled(bool enabled)
Called by main thread, when the online reporting is enabled/disabled.
int SDL_SemPost(SDL_sem *sem)
int SDL_SemWait(SDL_sem *sem)
void debug_printf(const wchar_t *fmt,...)
write a formatted string to the debug channel, subject to filtering (see below).
bool IsReportingEnabled()