forked from hrydgard/ppsspp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathReporting.cpp
203 lines (164 loc) · 4.54 KB
/
Reporting.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
// Copyright (c) 2012- PPSSPP Project.
// 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, version 2.0 or later versions.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "Core/Reporting.h"
#include "Common/StdThread.h"
#include "Core/Config.h"
#include "Core/System.h"
#include "net/http_client.h"
#include "net/resolve.h"
#include "base/buffer.h"
#include <stdlib.h>
#include <string>
#include <cstdarg>
namespace Reporting
{
const int DEFAULT_PORT = 80;
const u32 SPAM_LIMIT = 100;
const int PAYLOAD_BUFFER_SIZE = 100;
// Internal limiter on number of requests per instance.
static u32 spamProtectionCount = 0;
// Temporarily stores a reference to the hostname.
static std::string lastHostname;
enum RequestType
{
MESSAGE,
};
struct Payload
{
RequestType type;
std::string string1;
std::string string2;
};
static Payload payloadBuffer[PAYLOAD_BUFFER_SIZE];
static int payloadBufferPos = 0;
inline std::string ServerHost()
{
if (g_Config.sReportHost.compare("default") == 0)
return "";
return g_Config.sReportHost;
}
static size_t ServerHostnameLength()
{
if (!IsEnabled())
return g_Config.sReportHost.npos;
// IPv6 literal?
std::string host = ServerHost();
if (host[0] == '[')
{
size_t length = host.find("]:");
if (length != host.npos)
++length;
return length;
}
else
return host.find(':');
}
static const char *ServerHostname()
{
if (!IsEnabled())
return NULL;
std::string host = ServerHost();
size_t length = ServerHostnameLength();
lastHostname = host.substr(0, length);
if (length == lastHostname.npos)
return lastHostname.c_str();
return lastHostname.c_str();
}
static int ServerPort()
{
if (!IsEnabled())
return 0;
std::string host = ServerHost();
size_t offset = ServerHostnameLength();
if (offset == host.npos)
return DEFAULT_PORT;
// Skip the colon.
std::string port = host.substr(offset + 1);
return atoi(port.c_str());
}
// Should only be called once per request.
bool CheckSpamLimited()
{
return ++spamProtectionCount >= SPAM_LIMIT;
}
bool SendReportRequest(const char *uri, const std::string &data, Buffer *output = NULL)
{
bool result = false;
http::Client http;
Buffer theVoid;
if (output == NULL)
output = &theVoid;
net::Init();
if (http.Resolve(ServerHostname(), ServerPort()))
{
http.Connect();
http.POST("/report/message", data, "application/x-www-form-urlencoded", output);
http.Disconnect();
result = true;
}
net::Shutdown();
return result;
}
int Process(int pos)
{
Payload &payload = payloadBuffer[pos];
const int PARAM_BUFFER_SIZE = 4096;
char temp[PARAM_BUFFER_SIZE];
// TODO: Need to escape these values, add more.
snprintf(temp, PARAM_BUFFER_SIZE - 1, "version=%s&game=%s_%s&game_title=%s",
PPSSPP_GIT_VERSION,
g_paramSFO.GetValueString("DISC_ID").c_str(),
g_paramSFO.GetValueString("DISC_VERSION").c_str(),
g_paramSFO.GetValueString("TITLE").c_str());
std::string data;
switch (payload.type)
{
case MESSAGE:
// TODO: Escape.
data = std::string(temp) + "&message=" + payload.string1 + "&value=" + payload.string2;
payload.string1.clear();
payload.string2.clear();
SendReportRequest("/report/message", data);
break;
}
return 0;
}
bool IsEnabled()
{
if (g_Config.sReportHost.empty())
return false;
// Disabled by default for now.
if (g_Config.sReportHost.compare("default") == 0)
return false;
return true;
}
void ReportMessage(const char *message, ...)
{
if (!IsEnabled() || CheckSpamLimited())
return;
const int MESSAGE_BUFFER_SIZE = 32768;
char temp[MESSAGE_BUFFER_SIZE];
va_list args;
va_start(args, message);
vsnprintf(temp, MESSAGE_BUFFER_SIZE - 1, message, args);
temp[MESSAGE_BUFFER_SIZE - 1] = '\0';
va_end(args);
int pos = payloadBufferPos++ % PAYLOAD_BUFFER_SIZE;
Payload &payload = payloadBuffer[pos];
payload.type = MESSAGE;
payload.string1 = message;
payload.string2 = temp;
std::thread th(Process, pos);
th.detach();
}
}