mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-02-23 14:42:33 +01:00
byuu says: After 20 months of development, higan v095 is released at long last! The most notable feature is vastly improved Game Boy Advance emulation. With many thanks to endrift, Cydrak, Jonas Quinn and jchadwick, this release contains substantially improved CPU timings and many bugfixes. Being one of only two GBA emulators to offer ROM prefetch emulation, higan is very near mGBA in terms of accuracy, and far ahead of all others. As a result of these fixes, compatibility is also much higher than in v094. There are also several improvements to SNES emulation. Most significantly is support for mid-scanline changes to the background mode in the accuracy profile. Due to substantial changes to the user interface library used by higan, this release features yet again a brand-new UI. With the exception of video shaders and NSS DIP switch selection, it is at feature-parity with the previous UI. It also offers some new features that v094 lacked. The cheat code database has also been updated to the latest version by mightymo.
162 lines
4.5 KiB
C++
162 lines
4.5 KiB
C++
#ifndef NALL_HTTP_ROLE_HPP
|
|
#define NALL_HTTP_ROLE_HPP
|
|
|
|
//Role: base class for Client and Server
|
|
//provides shared functionality
|
|
|
|
#include <nall/http/request.hpp>
|
|
#include <nall/http/response.hpp>
|
|
|
|
namespace nall { namespace HTTP {
|
|
|
|
struct Role {
|
|
struct Settings {
|
|
signed connectionLimit = 1 * 1024; //server
|
|
signed headSizeLimit = 16 * 1024; //client, server
|
|
signed bodySizeLimit = 8192 * 1024; //client, server
|
|
signed chunkSize = 32 * 1024; //client, server
|
|
signed threadStackSize = 128 * 1024; //server
|
|
signed timeoutReceive = 15 * 1000; //server
|
|
signed timeoutSend = 15 * 1000; //server
|
|
} settings;
|
|
|
|
inline auto configure(const string& parameters) -> bool;
|
|
inline auto download(signed fd, Message& message) -> bool;
|
|
inline auto upload(signed fd, const Message& message) -> bool;
|
|
};
|
|
|
|
auto Role::configure(const string& parameters) -> bool {
|
|
auto document = BML::unserialize(parameters);
|
|
for(auto parameter : document) {
|
|
auto name = parameter.name();
|
|
auto value = parameter.integer();
|
|
|
|
if(0);
|
|
else if(name == "connectionLimit") settings.connectionLimit = value;
|
|
else if(name == "headSizeLimit") settings.headSizeLimit = value;
|
|
else if(name == "bodySizeLimit") settings.bodySizeLimit = value;
|
|
else if(name == "chunkSize") settings.chunkSize = value;
|
|
else if(name == "threadStackSize") settings.threadStackSize = value;
|
|
else if(name == "timeoutReceive") settings.timeoutReceive = value;
|
|
else if(name == "timeoutSend") settings.timeoutSend = value;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
auto Role::download(signed fd, Message& message) -> bool {
|
|
auto& head = message._head;
|
|
auto& body = message._body;
|
|
string chunk;
|
|
uint8_t packet[settings.chunkSize], *p = nullptr;
|
|
|
|
head.reset(), head.reserve(4095);
|
|
body.reset(), body.reserve(4095);
|
|
|
|
bool headReceived = false;
|
|
bool chunked = false;
|
|
bool chunkReceived = false;
|
|
bool chunkFooterReceived = true;
|
|
signed length = 0;
|
|
signed chunkLength = 0;
|
|
signed contentLength = 0;
|
|
|
|
while(true) {
|
|
if(auto limit = settings.headSizeLimit) if(head.size() >= limit) return false;
|
|
if(auto limit = settings.bodySizeLimit) if(body.size() >= limit) return false;
|
|
|
|
if(headReceived && !chunked && body.size() >= contentLength) {
|
|
body.resize(contentLength);
|
|
break;
|
|
}
|
|
|
|
if(length == 0) {
|
|
length = recv(fd, packet, settings.chunkSize, MSG_NOSIGNAL);
|
|
if(length <= 0) return false;
|
|
p = packet;
|
|
}
|
|
|
|
if(!headReceived) {
|
|
head.append((char)*p++);
|
|
--length;
|
|
|
|
if(head.endsWith("\r\n\r\n") || head.endsWith("\n\n")) {
|
|
headReceived = true;
|
|
if(!message.setHead()) return false;
|
|
chunked = message.header["Transfer-Encoding"].value().iequals("chunked");
|
|
contentLength = message.header["Content-Length"].value().decimal();
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if(chunked && !chunkReceived) {
|
|
char n = *p++;
|
|
--length;
|
|
|
|
if(!chunkFooterReceived) {
|
|
if(n == '\n') chunkFooterReceived = true;
|
|
continue;
|
|
}
|
|
|
|
chunk.append(n);
|
|
|
|
if(chunk.endsWith("\r\n") || chunk.endsWith("\n")) {
|
|
chunkReceived = true;
|
|
chunkLength = hex(chunk);
|
|
if(chunkLength == 0) break;
|
|
chunk.reset();
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if(!chunked) {
|
|
body.resize(body.size() + length);
|
|
memory::copy(body.get() + body.size() - length, p, length);
|
|
|
|
p += length;
|
|
length = 0;
|
|
} else {
|
|
signed transferLength = min(length, chunkLength);
|
|
body.resize(body.size() + transferLength);
|
|
memory::copy(body.get() + body.size() - transferLength, p, transferLength);
|
|
|
|
p += transferLength;
|
|
length -= transferLength;
|
|
chunkLength -= transferLength;
|
|
|
|
if(chunkLength == 0) {
|
|
chunkReceived = false;
|
|
chunkFooterReceived = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!message.setBody()) return false;
|
|
return true;
|
|
}
|
|
|
|
auto Role::upload(signed fd, const Message& message) -> bool {
|
|
auto transfer = [&](const uint8_t* data, unsigned size) -> bool {
|
|
while(size) {
|
|
signed length = send(fd, data, min(size, settings.chunkSize), MSG_NOSIGNAL);
|
|
if(length < 0) return false;
|
|
data += length;
|
|
size -= length;
|
|
}
|
|
return true;
|
|
};
|
|
|
|
if(message.head([&](const uint8_t* data, unsigned size) -> bool { return transfer(data, size); })) {
|
|
if(message.body([&](const uint8_t* data, unsigned size) -> bool { return transfer(data, size); })) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
}}
|
|
|
|
#endif
|