diff --git a/.gitignore b/.gitignore index ab5676c5..421c2721 100644 --- a/.gitignore +++ b/.gitignore @@ -9,5 +9,8 @@ *.so.1 *.patch *.rar +*.obj */out */bin +/bsnes/vstudio/bsnes/ +/bsnes/Snesida/x64/ diff --git a/README.md b/README.md index 032cd4b9..a0877a22 100644 --- a/README.md +++ b/README.md @@ -1,60 +1,5 @@ -# bsnes-plus +# snesida -bsnes-plus (or bsnes+) is a fork of bsnes (based on bsnes-classic) intended to -introduce some new features and improvements, mostly aimed at debugging. +IDA debugger plugin based on bsnes-plus fork of bsnes emulator. -## What's new - -- Improved debugger UI with register editing -- Redesigned memory editor and breakpoint editor -- Improved handling of address mirroring for breakpoints (extends to the entire address space, not just RAM) -- Real-time code and data highlighting in memory editor, with fast searching for known code/data locations and unexplored regions -- Cartridge ROM and RAM views in memory editor for mapper-agnostic analysis -- Enhanced VRAM, sprite, and tilemap viewing -- SA-1 disassembly and debugging -- SA-1 bus and BW-RAM viewing and (partial) usage logging -- Super FX disassembly and debugging -- Super FX bus viewing and usage logging - -Non-debugging features: - -- Satellaview / BS-X support -- SPC file dumping -- SPC output visualizer (keyboards & peak meters) -- IPS and BPS soft patching -- Multiple emulation improvements backported from bsnes/higan (mostly via bsnes-classic) - -## Development builds - -[![Build status](https://ci.appveyor.com/api/projects/status/2eatkcuu14r8rnfx/branch/master?svg=true)](https://ci.appveyor.com/project/devinacker/bsnes-plus/branch/master) - -Up-to-date development builds are available [from AppVeyor](https://ci.appveyor.com/project/devinacker/bsnes-plus/branch/master/artifacts) (64-bit Windows, compatibility and accuracy profiles). - -## Building on Windows - -- [Get mingw-w64](http://mingw-w64.yaxm.org/doku.php/download) (make sure toolchain supports 64-bit builds) -- Initialize the bsnes-plus-ext-qt submodule in git -- Run `mingw32-make` - -## Building on OS X - -Currently, OS X is not officially 100% supported. See [this fork](https://github.com/Optiroc/bsnes-plus) for now. - -## Building on Linux / other *nix - -As there is no ``configure`` step, make sure necessary Qt5/X11 packages are installed. On a Debian/Ubuntu system, it would require a command like: - -``` -sudo apt install qt5-default qtbase5-dev-tools libxv-dev libsdl1.2-dev libao-dev libopenal-dev g++ -``` - -Afterwards, run ``make`` and if everything works out correctly you will find the output binary in the ``out/`` directory. - -The snesfilter, snesreader, and supergameboy plugins can all be built by running make (or mingw32-make) after you've configured your environment to build bsnes itself. -After building, just copy the .dll, .so, or .dylib files into the same directory as bsnes itself. - -bsnes v073 and its derivatives are licensed under the GPL v2; see *Help > License ...* for more information. - -## Contributors - -See *Help > Documentation ...* for a list of authors. +![изображение](https://user-images.githubusercontent.com/7189309/114788734-aee19880-9d8a-11eb-991f-7537c0b14354.png) diff --git a/bsnes/Snesida/ida_debmod.h b/bsnes/Snesida/ida_debmod.h new file mode 100644 index 00000000..c5dc44a1 --- /dev/null +++ b/bsnes/Snesida/ida_debmod.h @@ -0,0 +1,53 @@ +#pragma once + +// +// +// This is the base debmod_t class definition +// From this class all debugger code must inherite and specialize +// +// Some OS specific functions must be implemented: +// bool init_subsystem(); +// bool term_subsystem(); +// debmod_t *create_debug_session(); +// int create_thread(thread_cb_t thread_cb, void *context); +// + +#undef INLINE + +#include +#include +#include + +//-------------------------------------------------------------------------- +// Very simple class to store pending events +enum queue_pos_t +{ + IN_FRONT, + IN_BACK +}; + +struct eventlist_t : public std::deque +{ +private: + bool synced; +public: + // save a pending event + void enqueue(const debug_event_t &ev, queue_pos_t pos) + { + if (pos != IN_BACK) + push_front(ev); + else + push_back(ev); + } + + // retrieve a pending event + bool retrieve(debug_event_t *event) + { + if (empty()) + return false; + // get the first event and return it + *event = front(); + pop_front(); + return true; + } +}; diff --git a/bsnes/Snesida/ida_debug.cpp b/bsnes/Snesida/ida_debug.cpp new file mode 100644 index 00000000..0d752ca5 --- /dev/null +++ b/bsnes/Snesida/ida_debug.cpp @@ -0,0 +1,1060 @@ +#include "gen-cpp/IdaClient.h" +#include "gen-cpp/BsnesDebugger.h" +#include +#include +#include +#include +#include +#include + +using namespace ::apache::thrift; +using namespace ::apache::thrift::protocol; +using namespace ::apache::thrift::transport; +using namespace ::apache::thrift::server; +using namespace ::apache::thrift::concurrency; + +#include +#include +#include +#include +#include + +#include "ida_plugin.h" +#include "ida_debmod.h" +#include "ida_registers.h" + +::std::shared_ptr client; +::std::shared_ptr srv; +::std::shared_ptr cli_transport; + +static ::std::mutex list_mutex; +static eventlist_t events; + +static const char* const p_reg[] = +{ + "CF", + "ZF", + "IF", + "DF", + "XF", + "MF", + "VF", + "NF", +}; + +static register_info_t registers[] = { + {"A", 0, RC_CPU, dt_word, NULL, 0}, + {"X", 0, RC_CPU, dt_word, NULL, 0}, + {"Y", 0, RC_CPU, dt_word, NULL, 0}, + + {"D", 0, RC_CPU, dt_word, NULL, 0}, + {"DB", 0, RC_CPU, dt_byte, NULL, 0}, + + {"PC", REGISTER_IP | REGISTER_ADDRESS, RC_CPU, dt_dword, NULL, 0}, + {"S", REGISTER_SP | REGISTER_ADDRESS, RC_CPU, dt_word, NULL, 0}, + + {"P", REGISTER_READONLY, RC_CPU, dt_byte, p_reg, 0xFF}, + {"m", REGISTER_READONLY, RC_CPU, dt_byte, NULL, 0}, + {"x", REGISTER_READONLY, RC_CPU, dt_byte, NULL, 0}, + {"e", REGISTER_READONLY, RC_CPU, dt_byte, NULL, 0}, +}; + +static const char* register_classes[] = { + "General Registers", + NULL +}; + +static struct apply_codemap_req : public exec_request_t { +private: + const std::set& _changed; + const bool _is_step; +public: + apply_codemap_req(const std::set& changed, bool is_step) : _changed(changed), _is_step(is_step) {}; + + int idaapi execute(void) override { + auto m = _changed.size(); + + if (!_is_step) { + show_wait_box("Applying codemap: %d/%d...", 1, m); + } + + auto x = 0; + for (auto i = _changed.cbegin(); i != _changed.cend(); ++i) { + if (!_is_step && user_cancelled()) { + break; + } + + if (!_is_step) { + replace_wait_box("Applying codemap: %d/%d...", x, m); + } + + ea_t addr = (ea_t)(*i | 0x800000); + auto_make_code(addr); + plan_ea(addr); + show_addr(addr); + x++; + } + + if (!_is_step) { + hide_wait_box(); + } + + return 0; + } +}; + +static void apply_codemap(const std::set& changed, bool is_step) +{ + if (changed.empty()) return; + + apply_codemap_req req(changed, is_step); + execute_sync(req, MFF_FAST); +} + +static void pause_execution() +{ + try { + if (client) { + client->pause(); + } + } + catch (...) { + + } +} + +static void continue_execution() +{ + try { + if (client) { + client->resume(); + } + } + catch (...) { + + } +} + +static void stop_server() { + try { + srv->stop(); + } + catch (...) { + + } +} + +static void finish_execution() +{ + try { + if (client) { + client->exit_emulation(); + } + } + catch (...) { + + } + + stop_server(); +} + +class IdaClientHandler : virtual public IdaClientIf { + +public: + void pause_event(const int32_t address) override { + ::std::lock_guard<::std::mutex> lock(list_mutex); + + debug_event_t ev; + ev.pid = 1; + ev.tid = 1; + ev.ea = address | 0x800000; + ev.handled = true; + ev.set_eid(PROCESS_SUSPENDED); + events.enqueue(ev, IN_BACK); + } + + + void start_event() override { + ::std::lock_guard<::std::mutex> lock(list_mutex); + + debug_event_t ev; + ev.pid = 1; + ev.tid = 1; + ev.ea = BADADDR; + ev.handled = true; + + ev.set_modinfo(PROCESS_STARTED).name.sprnt("BSNES"); + ev.set_modinfo(PROCESS_STARTED).base = 0; + ev.set_modinfo(PROCESS_STARTED).size = 0; + ev.set_modinfo(PROCESS_STARTED).rebase_to = BADADDR; + + events.enqueue(ev, IN_BACK); + } + + + void stop_event() override { + ::std::lock_guard<::std::mutex> lock(list_mutex); + + debug_event_t ev; + ev.pid = 1; + ev.handled = true; + ev.set_exit_code(PROCESS_EXITED, 0); + + events.enqueue(ev, IN_BACK); + } + + + void add_visited(const std::set& changed, bool is_step) override { + apply_codemap(changed, is_step); + } + +}; + +static void init_ida_server() { + try { + ::std::shared_ptr handler(new IdaClientHandler()); + ::std::shared_ptr processor(new IdaClientProcessor(handler)); + ::std::shared_ptr serverTransport(new TNonblockingServerSocket(9091)); + ::std::shared_ptr transportFactory(new TFramedTransportFactory()); + ::std::shared_ptr protocolFactory(new TBinaryProtocolFactory()); + + srv = ::std::shared_ptr(new TNonblockingServer(processor, protocolFactory, serverTransport)); + ::std::shared_ptr tf(new ThreadFactory()); + ::std::shared_ptr thread = tf->newThread(srv); + thread->start(); + } catch (...) { + + } +} + +static void init_emu_client() { + ::std::shared_ptr socket(new TSocket("127.0.0.1", 9090)); + cli_transport = ::std::shared_ptr(new TFramedTransport(socket)); + ::std::shared_ptr protocol(new TBinaryProtocol(cli_transport)); + client = ::std::shared_ptr(new BsnesDebuggerClient(protocol)); + + show_wait_box("Waiting for BSNES-PLUS emulation..."); + + while (true) { + if (user_cancelled()) { + break; + } + + try { + cli_transport->open(); + break; + } + catch (...) { + + } + } + + hide_wait_box(); +} + + +// Initialize debugger +// Returns true-success +// This function is called from the main thread +static drc_t idaapi init_debugger(const char* hostname, int portnum, const char* password, qstring* errbuf) +{ + return DRC_OK; +} + +// Terminate debugger +// Returns true-success +// This function is called from the main thread +static drc_t idaapi term_debugger(void) +{ + finish_execution(); + return DRC_OK; +} + +// Return information about the n-th "compatible" running process. +// If n is 0, the processes list is reinitialized. +// 1-ok, 0-failed, -1-network error +// This function is called from the main thread +static drc_t s_get_processes(procinfo_vec_t* procs, qstring* errbuf) { + process_info_t info; + info.name.sprnt("bsnes"); + info.pid = 1; + procs->add(info); + + return DRC_OK; +} + +// Start an executable to debug +// 1 - ok, 0 - failed, -2 - file not found (ask for process options) +// 1|CRC32_MISMATCH - ok, but the input file crc does not match +// -1 - network error +// This function is called from debthread +static drc_t idaapi s_start_process(const char* path, + const char* args, + const char* startdir, + uint32 dbg_proc_flags, + const char* input_path, + uint32 input_file_crc32, + qstring* errbuf = NULL) +{ + ::std::lock_guard<::std::mutex> lock(list_mutex); + events.clear(); + + init_ida_server(); + init_emu_client(); + + try { + if (client) { + client->start_emulation(); + } + } + catch (...) { + return DRC_FAILED; + } + + return DRC_OK; +} + +// Prepare to pause the process +// This function will prepare to pause the process +// Normally the next get_debug_event() will pause the process +// If the process is sleeping then the pause will not occur +// until the process wakes up. The interface should take care of +// this situation. +// If this function is absent, then it won't be possible to pause the program +// 1-ok, 0-failed, -1-network error +// This function is called from debthread +static drc_t idaapi prepare_to_pause_process(qstring* errbuf) +{ + pause_execution(); + return DRC_OK; +} + +// Stop the process. +// May be called while the process is running or suspended. +// Must terminate the process in any case. +// The kernel will repeatedly call get_debug_event() and until PROCESS_EXIT. +// In this mode, all other events will be automatically handled and process will be resumed. +// 1-ok, 0-failed, -1-network error +// This function is called from debthread +static drc_t idaapi emul_exit_process(qstring* errbuf) +{ + finish_execution(); + + return DRC_OK; +} + +// Get a pending debug event and suspend the process +// This function will be called regularly by IDA. +// This function is called from debthread +static gdecode_t idaapi get_debug_event(debug_event_t* event, int timeout_ms) +{ + while (true) + { + ::std::lock_guard<::std::mutex> lock(list_mutex); + + // are there any pending events? + if (events.retrieve(event)) + { + return events.empty() ? GDE_ONE_EVENT : GDE_MANY_EVENTS; + } + if (events.empty()) + break; + } + return GDE_NO_EVENT; +} + +// Continue after handling the event +// 1-ok, 0-failed, -1-network error +// This function is called from debthread +static drc_t idaapi continue_after_event(const debug_event_t* event) +{ + dbg_notification_t req = get_running_notification(); + switch (event->eid()) + { + case STEP: + case PROCESS_SUSPENDED: + if (req == dbg_null || req == dbg_run_to) { + continue_execution(); + } + break; + case PROCESS_EXITED: + stop_server(); + break; + } + + return DRC_OK; +} + +// The following function will be called by the kernel each time +// when it has stopped the debugger process for some reason, +// refreshed the database and the screen. +// The debugger module may add information to the database if it wants. +// The reason for introducing this function is that when an event line +// LOAD_DLL happens, the database does not reflect the memory state yet +// and therefore we can't add information about the dll into the database +// in the get_debug_event() function. +// Only when the kernel has adjusted the database we can do it. +// Example: for imported PE DLLs we will add the exported function +// names to the database. +// This function pointer may be absent, i.e. NULL. +// This function is called from the main thread +static void idaapi stopped_at_debug_event(bool dlls_added) +{ +} + +// The following functions manipulate threads. +// 1-ok, 0-failed, -1-network error +// These functions are called from debthread +static drc_t idaapi s_set_resume_mode(thid_t tid, resume_mode_t resmod) // Run one instruction in the thread +{ + switch (resmod) + { + case RESMOD_INTO: ///< step into call (the most typical single stepping) + try { + if (client) { + client->step_into(); + } + } + catch (...) { + return DRC_FAILED; + } + + break; + case RESMOD_OVER: ///< step over call + try { + if (client) { + client->step_over(); + } + } + catch (...) { + return DRC_FAILED; + } + break; + } + + return DRC_OK; +} + +// Read thread registers +// tid - thread id +// clsmask- bitmask of register classes to read +// regval - pointer to vector of regvals for all registers +// regval is assumed to have debugger_t::registers_size elements +// 1-ok, 0-failed, -1-network error +// This function is called from debthread +static drc_t idaapi read_registers(thid_t tid, int clsmask, regval_t* values, qstring* errbuf) +{ + if (clsmask & RC_CPU) + { + BsnesRegisters regs; + + try { + if (client) { + client->get_cpu_regs(regs); + + values[static_cast(SNES_REGS::SR_PC)].ival = regs.pc | 0x800000; + values[static_cast(SNES_REGS::SR_A)].ival = regs.a; + values[static_cast(SNES_REGS::SR_X)].ival = regs.x; + values[static_cast(SNES_REGS::SR_Y)].ival = regs.y; + values[static_cast(SNES_REGS::SR_S)].ival = regs.s; + values[static_cast(SNES_REGS::SR_D)].ival = regs.d; + values[static_cast(SNES_REGS::SR_DB)].ival = regs.db; + values[static_cast(SNES_REGS::SR_P)].ival = regs.p; + values[static_cast(SNES_REGS::SR_MFLAG)].ival = regs.mflag; + values[static_cast(SNES_REGS::SR_XFLAG)].ival = regs.xflag; + values[static_cast(SNES_REGS::SR_EFLAG)].ival = regs.eflag; + } + } + catch (...) { + return DRC_FAILED; + } + } + + return DRC_OK; +} + +// Write one thread register +// tid - thread id +// regidx - register index +// regval - new value of the register +// 1-ok, 0-failed, -1-network error +// This function is called from debthread +static drc_t idaapi write_register(thid_t tid, int regidx, const regval_t* value, qstring* errbuf) +{ + if (regidx >= static_cast(SNES_REGS::SR_PC) && regidx <= static_cast(SNES_REGS::SR_EFLAG)) { + try { + if (client) { + client->set_cpu_reg(static_cast(regidx), value->ival & 0xFFFFFFFF); + } + } + catch (...) { + return DRC_FAILED; + } + } + + return DRC_OK; + +} + +// The following functions manipulate bytes in the memory. +// +// Get information on the memory areas +// The debugger module fills 'areas'. The returned vector MUST be sorted. +// Returns: +// -3: use idb segmentation +// -2: no changes +// -1: the process does not exist anymore +// 0: failed +// 1: new memory layout is returned +// This function is called from debthread +static drc_t idaapi get_memory_info(meminfo_vec_t& areas, qstring* errbuf) +{ + memory_info_t info; + + info.start_ea = 0x0000; + info.end_ea = 0x01FFF; + info.sclass = "STACK"; + info.bitness = 0; + info.perm = SEGPERM_READ | SEGPERM_WRITE; + areas.push_back(info); + + // Don't remove this loop + for (int i = 0; i < get_segm_qty(); ++i) + { + segment_t* segm = getnseg(i); + + info.start_ea = segm->start_ea; + info.end_ea = segm->end_ea; + + qstring buf; + get_segm_name(&buf, segm); + info.name = buf; + + get_segm_class(&buf, segm); + info.sclass = buf; + + info.sbase = get_segm_base(segm); + + info.perm = segm->perm; + info.bitness = segm->bitness; + areas.push_back(info); + } + // Don't remove this loop + + return DRC_OK; +} + +// Read process memory +// Returns number of read bytes +// 0 means read error +// -1 means that the process does not exist anymore +// This function is called from debthread +static ssize_t idaapi read_memory(ea_t ea, void* buffer, size_t size, qstring* errbuf) +{ + std::string mem; + + try { + if (client) { + client->read_memory(mem, DbgMemorySource::CPUBus, (int32_t)ea, (int32_t)size); + + memcpy(&((unsigned char*)buffer)[0], mem.c_str(), size); + } + } + catch (...) { + return DRC_FAILED; + } + + return size; +} + +// Write process memory +// Returns number of written bytes, -1-fatal error +// This function is called from debthread +static ssize_t idaapi write_memory(ea_t ea, const void* buffer, size_t size, qstring* errbuf) +{ + std::string mem((const char*)buffer); + + try { + if (client) { + client->write_memory(DbgMemorySource::CPUBus, (int32_t)ea, mem); + } + } + catch (...) { + return 0; + } + + return size; +} + +// Is it possible to set breakpoint? +// Returns: BPT_... +// This function is called from debthread or from the main thread if debthread +// is not running yet. +// It is called to verify hardware breakpoints. +static int idaapi is_ok_bpt(bpttype_t type, ea_t ea, int len) +{ + DbgMemorySource::type btype = DbgMemorySource::CPUBus; + + switch (btype) { + case DbgMemorySource::CPUBus: + case DbgMemorySource::APURAM: + case DbgMemorySource::DSP: + case DbgMemorySource::VRAM: + case DbgMemorySource::OAM: + case DbgMemorySource::CGRAM: + case DbgMemorySource::SA1Bus: + case DbgMemorySource::SFXBus: + break; + default: + return BPT_BAD_TYPE; + } + + switch (type) + { + case BPT_EXEC: + case BPT_READ: + case BPT_WRITE: + case BPT_RDWR: + return BPT_OK; + } + + return BPT_BAD_TYPE; +} + +// Add/del breakpoints. +// bpts array contains nadd bpts to add, followed by ndel bpts to del. +// returns number of successfully modified bpts, -1-network error +// This function is called from debthread +static drc_t idaapi update_bpts(int* nbpts, update_bpt_info_t* bpts, int nadd, int ndel, qstring* errbuf) +{ + for (int i = 0; i < nadd; ++i) + { + ea_t start = bpts[i].ea; + ea_t end = bpts[i].ea + bpts[i].size - 1; + + DbgBreakpoint bp; + bp.bstart = start; + bp.bend = end; + bp.enabled = true; + + switch (bpts[i].type) + { + case BPT_EXEC: + bp.type = BpType::BP_PC; + break; + case BPT_READ: + bp.type = BpType::BP_READ; + break; + case BPT_WRITE: + bp.type = BpType::BP_WRITE; + break; + case BPT_RDWR: + bp.type = BpType::BP_READ; + break; + } + + DbgMemorySource::type type = DbgMemorySource::CPUBus; + + switch (type) { + case DbgMemorySource::CPUBus: + bp.src = DbgBptSource::CPUBus; + break; + case DbgMemorySource::APURAM: + bp.src = DbgBptSource::APURAM; + break; + case DbgMemorySource::DSP: + bp.src = DbgBptSource::DSP; + break; + case DbgMemorySource::VRAM: + bp.src = DbgBptSource::VRAM; + break; + case DbgMemorySource::OAM: + bp.src = DbgBptSource::OAM; + break; + case DbgMemorySource::CGRAM: + bp.src = DbgBptSource::CGRAM; + break; + case DbgMemorySource::SA1Bus: + bp.src = DbgBptSource::SA1Bus; + break; + case DbgMemorySource::SFXBus: + bp.src = DbgBptSource::SFXBus; + break; + default: + continue; + } + + try { + if (client) { + client->add_breakpoint(bp); + } + } + catch (...) { + return DRC_FAILED; + } + + bpts[i].code = BPT_OK; + } + + for (int i = 0; i < ndel; ++i) + { + ea_t start = bpts[nadd + i].ea; + ea_t end = bpts[nadd + i].ea + bpts[nadd + i].size - 1; + + DbgBreakpoint bp; + bp.bstart = start; + bp.bend = end; + bp.enabled = true; + + switch (bpts[i].type) + { + case BPT_EXEC: + bp.type = BpType::BP_PC; + break; + case BPT_READ: + bp.type = BpType::BP_READ; + break; + case BPT_WRITE: + bp.type = BpType::BP_WRITE; + break; + case BPT_RDWR: + bp.type = BpType::BP_READ; + break; + } + + DbgMemorySource::type type = DbgMemorySource::CPUBus; + + switch (type) { + case DbgMemorySource::CPUBus: + bp.src = DbgBptSource::CPUBus; + break; + case DbgMemorySource::APURAM: + bp.src = DbgBptSource::APURAM; + break; + case DbgMemorySource::DSP: + bp.src = DbgBptSource::DSP; + break; + case DbgMemorySource::VRAM: + bp.src = DbgBptSource::VRAM; + break; + case DbgMemorySource::OAM: + bp.src = DbgBptSource::OAM; + break; + case DbgMemorySource::CGRAM: + bp.src = DbgBptSource::CGRAM; + break; + case DbgMemorySource::SA1Bus: + bp.src = DbgBptSource::SA1Bus; + break; + case DbgMemorySource::SFXBus: + bp.src = DbgBptSource::SFXBus; + break; + default: + continue; + } + + try { + if (client) { + client->del_breakpoint(bp); + } + } + catch (...) { + return DRC_FAILED; + } + + bpts[nadd + i].code = BPT_OK; + } + + *nbpts = (ndel + nadd); + return DRC_OK; +} + +static ssize_t idaapi idd_notify(void*, int msgid, va_list va) { + drc_t retcode = DRC_NONE; + qstring* errbuf; + + switch (msgid) + { + case debugger_t::ev_init_debugger: + { + const char* hostname = va_arg(va, const char*); + + int portnum = va_arg(va, int); + const char* password = va_arg(va, const char*); + errbuf = va_arg(va, qstring*); + QASSERT(1522, errbuf != NULL); + retcode = init_debugger(hostname, portnum, password, errbuf); + } + break; + + case debugger_t::ev_term_debugger: + retcode = term_debugger(); + break; + + case debugger_t::ev_get_processes: + { + procinfo_vec_t* procs = va_arg(va, procinfo_vec_t*); + errbuf = va_arg(va, qstring*); + retcode = s_get_processes(procs, errbuf); + } + break; + + case debugger_t::ev_start_process: + { + const char* path = va_arg(va, const char*); + const char* args = va_arg(va, const char*); + const char* startdir = va_arg(va, const char*); + uint32 dbg_proc_flags = va_arg(va, uint32); + const char* input_path = va_arg(va, const char*); + uint32 input_file_crc32 = va_arg(va, uint32); + errbuf = va_arg(va, qstring*); + retcode = s_start_process(path, + args, + startdir, + dbg_proc_flags, + input_path, + input_file_crc32, + errbuf); + } + break; + + //case debugger_t::ev_attach_process: + //{ + // pid_t pid = va_argi(va, pid_t); + // int event_id = va_arg(va, int); + // uint32 dbg_proc_flags = va_arg(va, uint32); + // errbuf = va_arg(va, qstring*); + // retcode = s_attach_process(pid, event_id, dbg_proc_flags, errbuf); + //} + //break; + + //case debugger_t::ev_detach_process: + // retcode = g_dbgmod.dbg_detach_process(); + // break; + + case debugger_t::ev_get_debapp_attrs: + { + debapp_attrs_t* out_pattrs = va_arg(va, debapp_attrs_t*); + out_pattrs->addrsize = 3; + out_pattrs->is_be = false; + out_pattrs->platform = "snes"; + out_pattrs->cbsize = sizeof(debapp_attrs_t); + retcode = DRC_OK; + } + break; + + case debugger_t::ev_rebase_if_required_to: + { + ea_t new_base = va_arg(va, ea_t); + retcode = DRC_OK; + } + break; + + case debugger_t::ev_request_pause: + errbuf = va_arg(va, qstring*); + retcode = prepare_to_pause_process(errbuf); + break; + + case debugger_t::ev_exit_process: + errbuf = va_arg(va, qstring*); + retcode = emul_exit_process(errbuf); + break; + + case debugger_t::ev_get_debug_event: + { + gdecode_t* code = va_arg(va, gdecode_t*); + debug_event_t* event = va_arg(va, debug_event_t*); + int timeout_ms = va_arg(va, int); + *code = get_debug_event(event, timeout_ms); + retcode = DRC_OK; + } + break; + + case debugger_t::ev_resume: + { + debug_event_t* event = va_arg(va, debug_event_t*); + retcode = continue_after_event(event); + } + break; + + //case debugger_t::ev_set_exception_info: + //{ + // exception_info_t* info = va_arg(va, exception_info_t*); + // int qty = va_arg(va, int); + // g_dbgmod.dbg_set_exception_info(info, qty); + // retcode = DRC_OK; + //} + //break; + + //case debugger_t::ev_suspended: + //{ + // bool dlls_added = va_argi(va, bool); + // thread_name_vec_t* thr_names = va_arg(va, thread_name_vec_t*); + // retcode = DRC_OK; + //} + //break; + + case debugger_t::ev_thread_suspend: + { + thid_t tid = va_argi(va, thid_t); + pause_execution(); + retcode = DRC_OK; + } + break; + + case debugger_t::ev_thread_continue: + { + thid_t tid = va_argi(va, thid_t); + continue_execution(); + retcode = DRC_OK; + } + break; + + case debugger_t::ev_set_resume_mode: + { + thid_t tid = va_argi(va, thid_t); + resume_mode_t resmod = va_argi(va, resume_mode_t); + retcode = s_set_resume_mode(tid, resmod); + } + break; + + case debugger_t::ev_read_registers: + { + thid_t tid = va_argi(va, thid_t); + int clsmask = va_arg(va, int); + regval_t* values = va_arg(va, regval_t*); + errbuf = va_arg(va, qstring*); + retcode = read_registers(tid, clsmask, values, errbuf); + } + break; + + case debugger_t::ev_write_register: + { + thid_t tid = va_argi(va, thid_t); + int regidx = va_arg(va, int); + const regval_t* value = va_arg(va, const regval_t*); + errbuf = va_arg(va, qstring*); + retcode = write_register(tid, regidx, value, errbuf); + } + break; + + case debugger_t::ev_get_memory_info: + { + meminfo_vec_t* ranges = va_arg(va, meminfo_vec_t*); + errbuf = va_arg(va, qstring*); + retcode = get_memory_info(*ranges, errbuf); + } + break; + + case debugger_t::ev_read_memory: + { + size_t* nbytes = va_arg(va, size_t*); + ea_t ea = va_arg(va, ea_t); + void* buffer = va_arg(va, void*); + size_t size = va_arg(va, size_t); + errbuf = va_arg(va, qstring*); + ssize_t code = read_memory(ea, buffer, size, errbuf); + *nbytes = code >= 0 ? code : 0; + retcode = code >= 0 ? DRC_OK : DRC_NOPROC; + } + break; + + case debugger_t::ev_write_memory: + { + size_t* nbytes = va_arg(va, size_t*); + ea_t ea = va_arg(va, ea_t); + const void* buffer = va_arg(va, void*); + size_t size = va_arg(va, size_t); + errbuf = va_arg(va, qstring*); + ssize_t code = write_memory(ea, buffer, size, errbuf); + *nbytes = code >= 0 ? code : 0; + retcode = code >= 0 ? DRC_OK : DRC_NOPROC; + } + break; + + case debugger_t::ev_check_bpt: + { + int* bptvc = va_arg(va, int*); + bpttype_t type = va_argi(va, bpttype_t); + ea_t ea = va_arg(va, ea_t); + int len = va_arg(va, int); + *bptvc = is_ok_bpt(type, ea, len); + retcode = DRC_OK; + } + break; + + case debugger_t::ev_update_bpts: + { + int* nbpts = va_arg(va, int*); + update_bpt_info_t* bpts = va_arg(va, update_bpt_info_t*); + int nadd = va_arg(va, int); + int ndel = va_arg(va, int); + errbuf = va_arg(va, qstring*); + retcode = update_bpts(nbpts, bpts, nadd, ndel, errbuf); + } + break; + + //case debugger_t::ev_update_lowcnds: + //{ + // int* nupdated = va_arg(va, int*); + // const lowcnd_t* lowcnds = va_arg(va, const lowcnd_t*); + // int nlowcnds = va_arg(va, int); + // errbuf = va_arg(va, qstring*); + // retcode = update_lowcnds(nupdated, lowcnds, nlowcnds, errbuf); + //} + //break; + + //case debugger_t::ev_eval_lowcnd: + //{ + // thid_t tid = va_argi(va, thid_t); + // ea_t ea = va_arg(va, ea_t); + // errbuf = va_arg(va, qstring*); + // retcode = g_dbgmod.dbg_eval_lowcnd(tid, ea, errbuf); + //} + //break; + + //case debugger_t::ev_bin_search: + //{ + // ea_t* ea = va_arg(va, ea_t*); + // ea_t start_ea = va_arg(va, ea_t); + // ea_t end_ea = va_arg(va, ea_t); + // const compiled_binpat_vec_t* ptns = va_arg(va, const compiled_binpat_vec_t*); + // int srch_flags = va_arg(va, int); + // errbuf = va_arg(va, qstring*); + // if (ptns != NULL) + // retcode = g_dbgmod.dbg_bin_search(ea, start_ea, end_ea, *ptns, srch_flags, errbuf); + //} + //break; + default: + retcode = DRC_NONE; + } + + return retcode; +} + +debugger_t debugger{ + IDD_INTERFACE_VERSION, + NAME, + 0x8000 + 6581, // (6) + "65816", + + DBG_FLAG_NOHOST | DBG_FLAG_CAN_CONT_BPT | DBG_FLAG_SAFE | DBG_FLAG_FAKE_ATTACH | DBG_FLAG_NOPASSWORD | + DBG_FLAG_NOSTARTDIR | DBG_FLAG_NOPARAMETERS | DBG_FLAG_ANYSIZE_HWBPT | DBG_FLAG_DEBTHREAD | DBG_FLAG_PREFER_SWBPTS, + DBG_HAS_GET_PROCESSES | DBG_HAS_REQUEST_PAUSE | DBG_HAS_SET_RESUME_MODE | DBG_HAS_THREAD_SUSPEND | DBG_HAS_THREAD_CONTINUE | DBG_HAS_CHECK_BPT, + + register_classes, + RC_CPU, + registers, + qnumber(registers), + + 0x1000, + + NULL, + 0, + 0, + + DBG_RESMOD_STEP_INTO | DBG_RESMOD_STEP_OVER, + + NULL, + idd_notify +}; diff --git a/bsnes/Snesida/ida_plugin.cpp b/bsnes/Snesida/ida_plugin.cpp new file mode 100644 index 00000000..916de0e3 --- /dev/null +++ b/bsnes/Snesida/ida_plugin.cpp @@ -0,0 +1,119 @@ +#include +#include +#include +#include + +#include "ida_plugin.h" + +extern debugger_t debugger; + +static bool plugin_inited; + +struct m68k_events_visitor_t : public post_event_visitor_t { + ssize_t idaapi handle_post_event(ssize_t code, int notification_code, va_list va) override { + switch (notification_code) { + case processor_t::ev_get_idd_opinfo: { + idd_opinfo_t* opinf = va_arg(va, idd_opinfo_t*); + ea_t ea = va_arg(va, ea_t); + int n = va_arg(va, int); + int thread_id = va_arg(va, int); + processor_t::regval_getter_t *getreg = va_arg(va, processor_t::regval_getter_t *); + const regval_t* regvalues = va_arg(va, const regval_t*); + + //opinf->ea = BADADDR; + //opinf->debregidx = 0; + //opinf->modified = false; + //opinf->value.ival = 0; + //opinf->value_size = 4; + + insn_t out; + if (!decode_insn(&out, ea)) { + return code; + } + + op_t op = out.ops[n]; + + switch (op.dtype) { + case dt_byte: + opinf->value_size = 1; + break; + case dt_dword: + opinf->value_size = 4; + break; + default: + opinf->value_size = 2; + break; + } + + switch (op.type) { + case o_mem: + case o_near: + opinf->ea = op.addr; + break; + case o_imm: + opinf->ea = op.value; + break; + } + return 1; + } break; + } + + return code; + } +} ctx; + +static bool init_plugin(void) { + return (ph.id == PLFM_65C816); +} + +static void print_version() +{ + static const char format[] = NAME " debugger plugin v%s;\nAuthor: DrMefistO [Lab 313] ."; + info(format, VERSION); + msg(format, VERSION); +} + +static plugmod_t* idaapi init(void) { + if (init_plugin()) { + dbg = &debugger; + plugin_inited = true; + + //register_post_event_visitor(HT_IDP, &ctx, nullptr); + + print_version(); + return PLUGIN_KEEP; + } + + return PLUGIN_SKIP; +} + +static void idaapi term(void) { + if (plugin_inited) { + //unregister_post_event_visitor(HT_IDP, &ctx); + + plugin_inited = false; + } +} + +static bool idaapi run(size_t arg) { + return false; +} + +char comment[] = NAME " debugger plugin by DrMefistO."; + +char help[] = + NAME " debugger plugin by DrMefistO.\n" + "\n" + "This module lets you debug SNES roms in IDA.\n"; + +plugin_t PLUGIN = { + IDP_INTERFACE_VERSION, + PLUGIN_PROC | PLUGIN_DBG, + init, + term, + run, + comment, + help, + NAME " debugger plugin", + "" +}; diff --git a/bsnes/Snesida/ida_plugin.h b/bsnes/Snesida/ida_plugin.h new file mode 100644 index 00000000..95880dcd --- /dev/null +++ b/bsnes/Snesida/ida_plugin.h @@ -0,0 +1,4 @@ +#pragma once + +#define NAME "snesida" +#define VERSION "1.0" diff --git a/bsnes/Snesida/ida_registers.h b/bsnes/Snesida/ida_registers.h new file mode 100644 index 00000000..955f1ba2 --- /dev/null +++ b/bsnes/Snesida/ida_registers.h @@ -0,0 +1,19 @@ +#pragma once + +#define RC_CPU (1 << 0) +#define RC_PPU (1 << 1) + +enum class SNES_REGS : uint8_t +{ + SR_A, + SR_X, + SR_Y, + SR_D, + SR_DB, + SR_PC, + SR_S, + SR_P, + SR_MFLAG, + SR_XFLAG, + SR_EFLAG, +}; diff --git a/bsnes/Snesida/snesida.vcxproj b/bsnes/Snesida/snesida.vcxproj new file mode 100644 index 00000000..53f998c5 --- /dev/null +++ b/bsnes/Snesida/snesida.vcxproj @@ -0,0 +1,111 @@ + + + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {c89c7ccd-a6da-4364-a7da-8092983fb9a5} + snesida + 10.0 + + + + DynamicLibrary + true + v142 + MultiByte + + + DynamicLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + true + snesida + c:\Program Files\IDA Pro 7.6\plugins\ + + + false + snesida + c:\Program Files\IDA Pro 7.6\plugins\ + + + + Level3 + __NT__;__IDP__;__X64__;USE_STANDARD_FILE_FUNCTIONS;_DEBUG;SNESIDA_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + d:/idasdk76/include/;../;../thrift/;../thrift/libevent/include/;C:/local/boost_1_75_0/;%(AdditionalIncludeDirectories) + ProgramDatabase + MultiThreadedDebug + + + Windows + true + false + d:\idasdk76\lib\x64_win_vc_32\;../thrift/;../thrift/libevent/lib/;%(AdditionalLibraryDirectories) + ida.lib;thriftd_$(PlatformArchitecture).lib;thriftnbd_$(PlatformArchitecture).lib;event_$(PlatformArchitecture).lib;Iphlpapi.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + __NT__;__IDP__;__X64__;USE_STANDARD_FILE_FUNCTIONS;NDEBUG;SNESIDA_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + d:/idasdk76/include/;../;../thrift/;../thrift/libevent/include/;C:/local/boost_1_75_0/;%(AdditionalIncludeDirectories) + MultiThreaded + + + Windows + true + true + true + false + d:\idasdk76\lib\x64_win_vc_32\;../thrift/;../thrift/libevent/lib/;%(AdditionalLibraryDirectories) + ida.lib;thrift_$(PlatformArchitecture).lib;thriftnb_$(PlatformArchitecture).lib;event_$(PlatformArchitecture).lib;Iphlpapi.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bsnes/Snesida/snesida.vcxproj.filters b/bsnes/Snesida/snesida.vcxproj.filters new file mode 100644 index 00000000..04495e99 --- /dev/null +++ b/bsnes/Snesida/snesida.vcxproj.filters @@ -0,0 +1,53 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {b200e2f7-35df-470c-8c66-43f4473644b8} + + + + + Source Files + + + Source Files + + + thrift + + + thrift + + + thrift + + + + + Header Files + + + Header Files + + + Header Files + + + thrift + + + thrift + + + thrift + + + \ No newline at end of file diff --git a/bsnes/Snesida/snesida.vcxproj.user b/bsnes/Snesida/snesida.vcxproj.user new file mode 100644 index 00000000..0d878296 --- /dev/null +++ b/bsnes/Snesida/snesida.vcxproj.user @@ -0,0 +1,13 @@ + + + + $(OutDir) + WindowsLocalDebugger + c:\Program Files\IDA Pro 7.6\ida.exe + + + WindowsLocalDebugger + c:\Program Files\IDA Pro 7.6\ida.exe + $(OutDir) + + \ No newline at end of file diff --git a/bsnes/gen-cpp/BsnesDebugger.cpp b/bsnes/gen-cpp/BsnesDebugger.cpp new file mode 100644 index 00000000..fa86f4ca --- /dev/null +++ b/bsnes/gen-cpp/BsnesDebugger.cpp @@ -0,0 +1,4524 @@ +/** + * Autogenerated by Thrift Compiler (0.14.0) + * + * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + * @generated + */ +#include "BsnesDebugger.h" + + + + +BsnesDebugger_get_cpu_reg_args::~BsnesDebugger_get_cpu_reg_args() noexcept { +} + + +uint32_t BsnesDebugger_get_cpu_reg_args::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 1: + if (ftype == ::apache::thrift::protocol::T_I32) { + int32_t ecast6; + xfer += iprot->readI32(ecast6); + this->reg = (BsnesRegister::type)ecast6; + this->__isset.reg = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_get_cpu_reg_args::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_get_cpu_reg_args"); + + xfer += oprot->writeFieldBegin("reg", ::apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32((int32_t)this->reg); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_get_cpu_reg_pargs::~BsnesDebugger_get_cpu_reg_pargs() noexcept { +} + + +uint32_t BsnesDebugger_get_cpu_reg_pargs::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_get_cpu_reg_pargs"); + + xfer += oprot->writeFieldBegin("reg", ::apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32((int32_t)(*(this->reg))); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_get_cpu_reg_result::~BsnesDebugger_get_cpu_reg_result() noexcept { +} + + +uint32_t BsnesDebugger_get_cpu_reg_result::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 0: + if (ftype == ::apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->success); + this->__isset.success = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_get_cpu_reg_result::write(::apache::thrift::protocol::TProtocol* oprot) const { + + uint32_t xfer = 0; + + xfer += oprot->writeStructBegin("BsnesDebugger_get_cpu_reg_result"); + + if (this->__isset.success) { + xfer += oprot->writeFieldBegin("success", ::apache::thrift::protocol::T_I32, 0); + xfer += oprot->writeI32(this->success); + xfer += oprot->writeFieldEnd(); + } + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_get_cpu_reg_presult::~BsnesDebugger_get_cpu_reg_presult() noexcept { +} + + +uint32_t BsnesDebugger_get_cpu_reg_presult::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 0: + if (ftype == ::apache::thrift::protocol::T_I32) { + xfer += iprot->readI32((*(this->success))); + this->__isset.success = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + + +BsnesDebugger_get_cpu_regs_args::~BsnesDebugger_get_cpu_regs_args() noexcept { +} + + +uint32_t BsnesDebugger_get_cpu_regs_args::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_get_cpu_regs_args::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_get_cpu_regs_args"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_get_cpu_regs_pargs::~BsnesDebugger_get_cpu_regs_pargs() noexcept { +} + + +uint32_t BsnesDebugger_get_cpu_regs_pargs::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_get_cpu_regs_pargs"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_get_cpu_regs_result::~BsnesDebugger_get_cpu_regs_result() noexcept { +} + + +uint32_t BsnesDebugger_get_cpu_regs_result::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 0: + if (ftype == ::apache::thrift::protocol::T_STRUCT) { + xfer += this->success.read(iprot); + this->__isset.success = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_get_cpu_regs_result::write(::apache::thrift::protocol::TProtocol* oprot) const { + + uint32_t xfer = 0; + + xfer += oprot->writeStructBegin("BsnesDebugger_get_cpu_regs_result"); + + if (this->__isset.success) { + xfer += oprot->writeFieldBegin("success", ::apache::thrift::protocol::T_STRUCT, 0); + xfer += this->success.write(oprot); + xfer += oprot->writeFieldEnd(); + } + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_get_cpu_regs_presult::~BsnesDebugger_get_cpu_regs_presult() noexcept { +} + + +uint32_t BsnesDebugger_get_cpu_regs_presult::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 0: + if (ftype == ::apache::thrift::protocol::T_STRUCT) { + xfer += (*(this->success)).read(iprot); + this->__isset.success = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + + +BsnesDebugger_set_cpu_reg_args::~BsnesDebugger_set_cpu_reg_args() noexcept { +} + + +uint32_t BsnesDebugger_set_cpu_reg_args::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 1: + if (ftype == ::apache::thrift::protocol::T_I32) { + int32_t ecast7; + xfer += iprot->readI32(ecast7); + this->reg = (BsnesRegister::type)ecast7; + this->__isset.reg = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 2: + if (ftype == ::apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->value); + this->__isset.value = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_set_cpu_reg_args::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_set_cpu_reg_args"); + + xfer += oprot->writeFieldBegin("reg", ::apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32((int32_t)this->reg); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("value", ::apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeI32(this->value); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_set_cpu_reg_pargs::~BsnesDebugger_set_cpu_reg_pargs() noexcept { +} + + +uint32_t BsnesDebugger_set_cpu_reg_pargs::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_set_cpu_reg_pargs"); + + xfer += oprot->writeFieldBegin("reg", ::apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32((int32_t)(*(this->reg))); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("value", ::apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeI32((*(this->value))); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_set_cpu_reg_result::~BsnesDebugger_set_cpu_reg_result() noexcept { +} + + +uint32_t BsnesDebugger_set_cpu_reg_result::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_set_cpu_reg_result::write(::apache::thrift::protocol::TProtocol* oprot) const { + + uint32_t xfer = 0; + + xfer += oprot->writeStructBegin("BsnesDebugger_set_cpu_reg_result"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_set_cpu_reg_presult::~BsnesDebugger_set_cpu_reg_presult() noexcept { +} + + +uint32_t BsnesDebugger_set_cpu_reg_presult::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + + +BsnesDebugger_read_memory_args::~BsnesDebugger_read_memory_args() noexcept { +} + + +uint32_t BsnesDebugger_read_memory_args::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 1: + if (ftype == ::apache::thrift::protocol::T_I32) { + int32_t ecast8; + xfer += iprot->readI32(ecast8); + this->src = (DbgMemorySource::type)ecast8; + this->__isset.src = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 2: + if (ftype == ::apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->address); + this->__isset.address = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 3: + if (ftype == ::apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->size); + this->__isset.size = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_read_memory_args::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_read_memory_args"); + + xfer += oprot->writeFieldBegin("src", ::apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32((int32_t)this->src); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("address", ::apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeI32(this->address); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("size", ::apache::thrift::protocol::T_I32, 3); + xfer += oprot->writeI32(this->size); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_read_memory_pargs::~BsnesDebugger_read_memory_pargs() noexcept { +} + + +uint32_t BsnesDebugger_read_memory_pargs::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_read_memory_pargs"); + + xfer += oprot->writeFieldBegin("src", ::apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32((int32_t)(*(this->src))); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("address", ::apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeI32((*(this->address))); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("size", ::apache::thrift::protocol::T_I32, 3); + xfer += oprot->writeI32((*(this->size))); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_read_memory_result::~BsnesDebugger_read_memory_result() noexcept { +} + + +uint32_t BsnesDebugger_read_memory_result::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 0: + if (ftype == ::apache::thrift::protocol::T_STRING) { + xfer += iprot->readBinary(this->success); + this->__isset.success = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_read_memory_result::write(::apache::thrift::protocol::TProtocol* oprot) const { + + uint32_t xfer = 0; + + xfer += oprot->writeStructBegin("BsnesDebugger_read_memory_result"); + + if (this->__isset.success) { + xfer += oprot->writeFieldBegin("success", ::apache::thrift::protocol::T_STRING, 0); + xfer += oprot->writeBinary(this->success); + xfer += oprot->writeFieldEnd(); + } + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_read_memory_presult::~BsnesDebugger_read_memory_presult() noexcept { +} + + +uint32_t BsnesDebugger_read_memory_presult::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 0: + if (ftype == ::apache::thrift::protocol::T_STRING) { + xfer += iprot->readBinary((*(this->success))); + this->__isset.success = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + + +BsnesDebugger_write_memory_args::~BsnesDebugger_write_memory_args() noexcept { +} + + +uint32_t BsnesDebugger_write_memory_args::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 1: + if (ftype == ::apache::thrift::protocol::T_I32) { + int32_t ecast9; + xfer += iprot->readI32(ecast9); + this->src = (DbgMemorySource::type)ecast9; + this->__isset.src = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 2: + if (ftype == ::apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->address); + this->__isset.address = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 3: + if (ftype == ::apache::thrift::protocol::T_STRING) { + xfer += iprot->readBinary(this->data); + this->__isset.data = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_write_memory_args::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_write_memory_args"); + + xfer += oprot->writeFieldBegin("src", ::apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32((int32_t)this->src); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("address", ::apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeI32(this->address); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("data", ::apache::thrift::protocol::T_STRING, 3); + xfer += oprot->writeBinary(this->data); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_write_memory_pargs::~BsnesDebugger_write_memory_pargs() noexcept { +} + + +uint32_t BsnesDebugger_write_memory_pargs::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_write_memory_pargs"); + + xfer += oprot->writeFieldBegin("src", ::apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32((int32_t)(*(this->src))); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("address", ::apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeI32((*(this->address))); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("data", ::apache::thrift::protocol::T_STRING, 3); + xfer += oprot->writeBinary((*(this->data))); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_write_memory_result::~BsnesDebugger_write_memory_result() noexcept { +} + + +uint32_t BsnesDebugger_write_memory_result::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_write_memory_result::write(::apache::thrift::protocol::TProtocol* oprot) const { + + uint32_t xfer = 0; + + xfer += oprot->writeStructBegin("BsnesDebugger_write_memory_result"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_write_memory_presult::~BsnesDebugger_write_memory_presult() noexcept { +} + + +uint32_t BsnesDebugger_write_memory_presult::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + + +BsnesDebugger_add_breakpoint_args::~BsnesDebugger_add_breakpoint_args() noexcept { +} + + +uint32_t BsnesDebugger_add_breakpoint_args::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 1: + if (ftype == ::apache::thrift::protocol::T_STRUCT) { + xfer += this->bpt.read(iprot); + this->__isset.bpt = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_add_breakpoint_args::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_add_breakpoint_args"); + + xfer += oprot->writeFieldBegin("bpt", ::apache::thrift::protocol::T_STRUCT, 1); + xfer += this->bpt.write(oprot); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_add_breakpoint_pargs::~BsnesDebugger_add_breakpoint_pargs() noexcept { +} + + +uint32_t BsnesDebugger_add_breakpoint_pargs::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_add_breakpoint_pargs"); + + xfer += oprot->writeFieldBegin("bpt", ::apache::thrift::protocol::T_STRUCT, 1); + xfer += (*(this->bpt)).write(oprot); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_add_breakpoint_result::~BsnesDebugger_add_breakpoint_result() noexcept { +} + + +uint32_t BsnesDebugger_add_breakpoint_result::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_add_breakpoint_result::write(::apache::thrift::protocol::TProtocol* oprot) const { + + uint32_t xfer = 0; + + xfer += oprot->writeStructBegin("BsnesDebugger_add_breakpoint_result"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_add_breakpoint_presult::~BsnesDebugger_add_breakpoint_presult() noexcept { +} + + +uint32_t BsnesDebugger_add_breakpoint_presult::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + + +BsnesDebugger_del_breakpoint_args::~BsnesDebugger_del_breakpoint_args() noexcept { +} + + +uint32_t BsnesDebugger_del_breakpoint_args::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 1: + if (ftype == ::apache::thrift::protocol::T_STRUCT) { + xfer += this->bpt.read(iprot); + this->__isset.bpt = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_del_breakpoint_args::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_del_breakpoint_args"); + + xfer += oprot->writeFieldBegin("bpt", ::apache::thrift::protocol::T_STRUCT, 1); + xfer += this->bpt.write(oprot); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_del_breakpoint_pargs::~BsnesDebugger_del_breakpoint_pargs() noexcept { +} + + +uint32_t BsnesDebugger_del_breakpoint_pargs::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_del_breakpoint_pargs"); + + xfer += oprot->writeFieldBegin("bpt", ::apache::thrift::protocol::T_STRUCT, 1); + xfer += (*(this->bpt)).write(oprot); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_del_breakpoint_result::~BsnesDebugger_del_breakpoint_result() noexcept { +} + + +uint32_t BsnesDebugger_del_breakpoint_result::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_del_breakpoint_result::write(::apache::thrift::protocol::TProtocol* oprot) const { + + uint32_t xfer = 0; + + xfer += oprot->writeStructBegin("BsnesDebugger_del_breakpoint_result"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_del_breakpoint_presult::~BsnesDebugger_del_breakpoint_presult() noexcept { +} + + +uint32_t BsnesDebugger_del_breakpoint_presult::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + + +BsnesDebugger_pause_args::~BsnesDebugger_pause_args() noexcept { +} + + +uint32_t BsnesDebugger_pause_args::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_pause_args::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_pause_args"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_pause_pargs::~BsnesDebugger_pause_pargs() noexcept { +} + + +uint32_t BsnesDebugger_pause_pargs::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_pause_pargs"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_pause_result::~BsnesDebugger_pause_result() noexcept { +} + + +uint32_t BsnesDebugger_pause_result::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_pause_result::write(::apache::thrift::protocol::TProtocol* oprot) const { + + uint32_t xfer = 0; + + xfer += oprot->writeStructBegin("BsnesDebugger_pause_result"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_pause_presult::~BsnesDebugger_pause_presult() noexcept { +} + + +uint32_t BsnesDebugger_pause_presult::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + + +BsnesDebugger_resume_args::~BsnesDebugger_resume_args() noexcept { +} + + +uint32_t BsnesDebugger_resume_args::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_resume_args::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_resume_args"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_resume_pargs::~BsnesDebugger_resume_pargs() noexcept { +} + + +uint32_t BsnesDebugger_resume_pargs::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_resume_pargs"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_resume_result::~BsnesDebugger_resume_result() noexcept { +} + + +uint32_t BsnesDebugger_resume_result::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_resume_result::write(::apache::thrift::protocol::TProtocol* oprot) const { + + uint32_t xfer = 0; + + xfer += oprot->writeStructBegin("BsnesDebugger_resume_result"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_resume_presult::~BsnesDebugger_resume_presult() noexcept { +} + + +uint32_t BsnesDebugger_resume_presult::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + + +BsnesDebugger_start_emulation_args::~BsnesDebugger_start_emulation_args() noexcept { +} + + +uint32_t BsnesDebugger_start_emulation_args::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_start_emulation_args::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_start_emulation_args"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_start_emulation_pargs::~BsnesDebugger_start_emulation_pargs() noexcept { +} + + +uint32_t BsnesDebugger_start_emulation_pargs::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_start_emulation_pargs"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_start_emulation_result::~BsnesDebugger_start_emulation_result() noexcept { +} + + +uint32_t BsnesDebugger_start_emulation_result::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_start_emulation_result::write(::apache::thrift::protocol::TProtocol* oprot) const { + + uint32_t xfer = 0; + + xfer += oprot->writeStructBegin("BsnesDebugger_start_emulation_result"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_start_emulation_presult::~BsnesDebugger_start_emulation_presult() noexcept { +} + + +uint32_t BsnesDebugger_start_emulation_presult::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + + +BsnesDebugger_exit_emulation_args::~BsnesDebugger_exit_emulation_args() noexcept { +} + + +uint32_t BsnesDebugger_exit_emulation_args::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_exit_emulation_args::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_exit_emulation_args"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_exit_emulation_pargs::~BsnesDebugger_exit_emulation_pargs() noexcept { +} + + +uint32_t BsnesDebugger_exit_emulation_pargs::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_exit_emulation_pargs"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_exit_emulation_result::~BsnesDebugger_exit_emulation_result() noexcept { +} + + +uint32_t BsnesDebugger_exit_emulation_result::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_exit_emulation_result::write(::apache::thrift::protocol::TProtocol* oprot) const { + + uint32_t xfer = 0; + + xfer += oprot->writeStructBegin("BsnesDebugger_exit_emulation_result"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_exit_emulation_presult::~BsnesDebugger_exit_emulation_presult() noexcept { +} + + +uint32_t BsnesDebugger_exit_emulation_presult::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + + +BsnesDebugger_step_into_args::~BsnesDebugger_step_into_args() noexcept { +} + + +uint32_t BsnesDebugger_step_into_args::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_step_into_args::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_step_into_args"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_step_into_pargs::~BsnesDebugger_step_into_pargs() noexcept { +} + + +uint32_t BsnesDebugger_step_into_pargs::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_step_into_pargs"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_step_into_result::~BsnesDebugger_step_into_result() noexcept { +} + + +uint32_t BsnesDebugger_step_into_result::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_step_into_result::write(::apache::thrift::protocol::TProtocol* oprot) const { + + uint32_t xfer = 0; + + xfer += oprot->writeStructBegin("BsnesDebugger_step_into_result"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_step_into_presult::~BsnesDebugger_step_into_presult() noexcept { +} + + +uint32_t BsnesDebugger_step_into_presult::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + + +BsnesDebugger_step_over_args::~BsnesDebugger_step_over_args() noexcept { +} + + +uint32_t BsnesDebugger_step_over_args::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_step_over_args::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_step_over_args"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_step_over_pargs::~BsnesDebugger_step_over_pargs() noexcept { +} + + +uint32_t BsnesDebugger_step_over_pargs::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesDebugger_step_over_pargs"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_step_over_result::~BsnesDebugger_step_over_result() noexcept { +} + + +uint32_t BsnesDebugger_step_over_result::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesDebugger_step_over_result::write(::apache::thrift::protocol::TProtocol* oprot) const { + + uint32_t xfer = 0; + + xfer += oprot->writeStructBegin("BsnesDebugger_step_over_result"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +BsnesDebugger_step_over_presult::~BsnesDebugger_step_over_presult() noexcept { +} + + +uint32_t BsnesDebugger_step_over_presult::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +int32_t BsnesDebuggerClient::get_cpu_reg(const BsnesRegister::type reg) +{ + send_get_cpu_reg(reg); + return recv_get_cpu_reg(); +} + +void BsnesDebuggerClient::send_get_cpu_reg(const BsnesRegister::type reg) +{ + int32_t cseqid = 0; + oprot_->writeMessageBegin("get_cpu_reg", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_get_cpu_reg_pargs args; + args.reg = ® + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); +} + +int32_t BsnesDebuggerClient::recv_get_cpu_reg() +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + iprot_->readMessageBegin(fname, mtype, rseqid); + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("get_cpu_reg") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + int32_t _return; + BsnesDebugger_get_cpu_reg_presult result; + result.success = &_return; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + if (result.__isset.success) { + return _return; + } + throw ::apache::thrift::TApplicationException(::apache::thrift::TApplicationException::MISSING_RESULT, "get_cpu_reg failed: unknown result"); +} + +void BsnesDebuggerClient::get_cpu_regs(BsnesRegisters& _return) +{ + send_get_cpu_regs(); + recv_get_cpu_regs(_return); +} + +void BsnesDebuggerClient::send_get_cpu_regs() +{ + int32_t cseqid = 0; + oprot_->writeMessageBegin("get_cpu_regs", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_get_cpu_regs_pargs args; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); +} + +void BsnesDebuggerClient::recv_get_cpu_regs(BsnesRegisters& _return) +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + iprot_->readMessageBegin(fname, mtype, rseqid); + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("get_cpu_regs") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + BsnesDebugger_get_cpu_regs_presult result; + result.success = &_return; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + if (result.__isset.success) { + // _return pointer has now been filled + return; + } + throw ::apache::thrift::TApplicationException(::apache::thrift::TApplicationException::MISSING_RESULT, "get_cpu_regs failed: unknown result"); +} + +void BsnesDebuggerClient::set_cpu_reg(const BsnesRegister::type reg, const int32_t value) +{ + send_set_cpu_reg(reg, value); + recv_set_cpu_reg(); +} + +void BsnesDebuggerClient::send_set_cpu_reg(const BsnesRegister::type reg, const int32_t value) +{ + int32_t cseqid = 0; + oprot_->writeMessageBegin("set_cpu_reg", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_set_cpu_reg_pargs args; + args.reg = ® + args.value = &value; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); +} + +void BsnesDebuggerClient::recv_set_cpu_reg() +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + iprot_->readMessageBegin(fname, mtype, rseqid); + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("set_cpu_reg") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + BsnesDebugger_set_cpu_reg_presult result; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + return; +} + +void BsnesDebuggerClient::read_memory(std::string& _return, const DbgMemorySource::type src, const int32_t address, const int32_t size) +{ + send_read_memory(src, address, size); + recv_read_memory(_return); +} + +void BsnesDebuggerClient::send_read_memory(const DbgMemorySource::type src, const int32_t address, const int32_t size) +{ + int32_t cseqid = 0; + oprot_->writeMessageBegin("read_memory", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_read_memory_pargs args; + args.src = &src; + args.address = &address; + args.size = &size; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); +} + +void BsnesDebuggerClient::recv_read_memory(std::string& _return) +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + iprot_->readMessageBegin(fname, mtype, rseqid); + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("read_memory") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + BsnesDebugger_read_memory_presult result; + result.success = &_return; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + if (result.__isset.success) { + // _return pointer has now been filled + return; + } + throw ::apache::thrift::TApplicationException(::apache::thrift::TApplicationException::MISSING_RESULT, "read_memory failed: unknown result"); +} + +void BsnesDebuggerClient::write_memory(const DbgMemorySource::type src, const int32_t address, const std::string& data) +{ + send_write_memory(src, address, data); + recv_write_memory(); +} + +void BsnesDebuggerClient::send_write_memory(const DbgMemorySource::type src, const int32_t address, const std::string& data) +{ + int32_t cseqid = 0; + oprot_->writeMessageBegin("write_memory", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_write_memory_pargs args; + args.src = &src; + args.address = &address; + args.data = &data; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); +} + +void BsnesDebuggerClient::recv_write_memory() +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + iprot_->readMessageBegin(fname, mtype, rseqid); + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("write_memory") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + BsnesDebugger_write_memory_presult result; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + return; +} + +void BsnesDebuggerClient::add_breakpoint(const DbgBreakpoint& bpt) +{ + send_add_breakpoint(bpt); + recv_add_breakpoint(); +} + +void BsnesDebuggerClient::send_add_breakpoint(const DbgBreakpoint& bpt) +{ + int32_t cseqid = 0; + oprot_->writeMessageBegin("add_breakpoint", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_add_breakpoint_pargs args; + args.bpt = &bpt; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); +} + +void BsnesDebuggerClient::recv_add_breakpoint() +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + iprot_->readMessageBegin(fname, mtype, rseqid); + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("add_breakpoint") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + BsnesDebugger_add_breakpoint_presult result; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + return; +} + +void BsnesDebuggerClient::del_breakpoint(const DbgBreakpoint& bpt) +{ + send_del_breakpoint(bpt); + recv_del_breakpoint(); +} + +void BsnesDebuggerClient::send_del_breakpoint(const DbgBreakpoint& bpt) +{ + int32_t cseqid = 0; + oprot_->writeMessageBegin("del_breakpoint", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_del_breakpoint_pargs args; + args.bpt = &bpt; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); +} + +void BsnesDebuggerClient::recv_del_breakpoint() +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + iprot_->readMessageBegin(fname, mtype, rseqid); + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("del_breakpoint") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + BsnesDebugger_del_breakpoint_presult result; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + return; +} + +void BsnesDebuggerClient::pause() +{ + send_pause(); + recv_pause(); +} + +void BsnesDebuggerClient::send_pause() +{ + int32_t cseqid = 0; + oprot_->writeMessageBegin("pause", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_pause_pargs args; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); +} + +void BsnesDebuggerClient::recv_pause() +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + iprot_->readMessageBegin(fname, mtype, rseqid); + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("pause") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + BsnesDebugger_pause_presult result; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + return; +} + +void BsnesDebuggerClient::resume() +{ + send_resume(); + recv_resume(); +} + +void BsnesDebuggerClient::send_resume() +{ + int32_t cseqid = 0; + oprot_->writeMessageBegin("resume", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_resume_pargs args; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); +} + +void BsnesDebuggerClient::recv_resume() +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + iprot_->readMessageBegin(fname, mtype, rseqid); + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("resume") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + BsnesDebugger_resume_presult result; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + return; +} + +void BsnesDebuggerClient::start_emulation() +{ + send_start_emulation(); + recv_start_emulation(); +} + +void BsnesDebuggerClient::send_start_emulation() +{ + int32_t cseqid = 0; + oprot_->writeMessageBegin("start_emulation", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_start_emulation_pargs args; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); +} + +void BsnesDebuggerClient::recv_start_emulation() +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + iprot_->readMessageBegin(fname, mtype, rseqid); + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("start_emulation") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + BsnesDebugger_start_emulation_presult result; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + return; +} + +void BsnesDebuggerClient::exit_emulation() +{ + send_exit_emulation(); + recv_exit_emulation(); +} + +void BsnesDebuggerClient::send_exit_emulation() +{ + int32_t cseqid = 0; + oprot_->writeMessageBegin("exit_emulation", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_exit_emulation_pargs args; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); +} + +void BsnesDebuggerClient::recv_exit_emulation() +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + iprot_->readMessageBegin(fname, mtype, rseqid); + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("exit_emulation") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + BsnesDebugger_exit_emulation_presult result; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + return; +} + +void BsnesDebuggerClient::step_into() +{ + send_step_into(); + recv_step_into(); +} + +void BsnesDebuggerClient::send_step_into() +{ + int32_t cseqid = 0; + oprot_->writeMessageBegin("step_into", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_step_into_pargs args; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); +} + +void BsnesDebuggerClient::recv_step_into() +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + iprot_->readMessageBegin(fname, mtype, rseqid); + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("step_into") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + BsnesDebugger_step_into_presult result; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + return; +} + +void BsnesDebuggerClient::step_over() +{ + send_step_over(); + recv_step_over(); +} + +void BsnesDebuggerClient::send_step_over() +{ + int32_t cseqid = 0; + oprot_->writeMessageBegin("step_over", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_step_over_pargs args; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); +} + +void BsnesDebuggerClient::recv_step_over() +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + iprot_->readMessageBegin(fname, mtype, rseqid); + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("step_over") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + BsnesDebugger_step_over_presult result; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + return; +} + +bool BsnesDebuggerProcessor::dispatchCall(::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, const std::string& fname, int32_t seqid, void* callContext) { + ProcessMap::iterator pfn; + pfn = processMap_.find(fname); + if (pfn == processMap_.end()) { + iprot->skip(::apache::thrift::protocol::T_STRUCT); + iprot->readMessageEnd(); + iprot->getTransport()->readEnd(); + ::apache::thrift::TApplicationException x(::apache::thrift::TApplicationException::UNKNOWN_METHOD, "Invalid method name: '"+fname+"'"); + oprot->writeMessageBegin(fname, ::apache::thrift::protocol::T_EXCEPTION, seqid); + x.write(oprot); + oprot->writeMessageEnd(); + oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + return true; + } + (this->*(pfn->second))(seqid, iprot, oprot, callContext); + return true; +} + +void BsnesDebuggerProcessor::process_get_cpu_reg(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext) +{ + void* ctx = nullptr; + if (this->eventHandler_.get() != nullptr) { + ctx = this->eventHandler_->getContext("BsnesDebugger.get_cpu_reg", callContext); + } + ::apache::thrift::TProcessorContextFreer freer(this->eventHandler_.get(), ctx, "BsnesDebugger.get_cpu_reg"); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preRead(ctx, "BsnesDebugger.get_cpu_reg"); + } + + BsnesDebugger_get_cpu_reg_args args; + args.read(iprot); + iprot->readMessageEnd(); + uint32_t bytes = iprot->getTransport()->readEnd(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postRead(ctx, "BsnesDebugger.get_cpu_reg", bytes); + } + + BsnesDebugger_get_cpu_reg_result result; + try { + result.success = iface_->get_cpu_reg(args.reg); + result.__isset.success = true; + } catch (const std::exception& e) { + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->handlerError(ctx, "BsnesDebugger.get_cpu_reg"); + } + + ::apache::thrift::TApplicationException x(e.what()); + oprot->writeMessageBegin("get_cpu_reg", ::apache::thrift::protocol::T_EXCEPTION, seqid); + x.write(oprot); + oprot->writeMessageEnd(); + oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + return; + } + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preWrite(ctx, "BsnesDebugger.get_cpu_reg"); + } + + oprot->writeMessageBegin("get_cpu_reg", ::apache::thrift::protocol::T_REPLY, seqid); + result.write(oprot); + oprot->writeMessageEnd(); + bytes = oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postWrite(ctx, "BsnesDebugger.get_cpu_reg", bytes); + } +} + +void BsnesDebuggerProcessor::process_get_cpu_regs(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext) +{ + void* ctx = nullptr; + if (this->eventHandler_.get() != nullptr) { + ctx = this->eventHandler_->getContext("BsnesDebugger.get_cpu_regs", callContext); + } + ::apache::thrift::TProcessorContextFreer freer(this->eventHandler_.get(), ctx, "BsnesDebugger.get_cpu_regs"); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preRead(ctx, "BsnesDebugger.get_cpu_regs"); + } + + BsnesDebugger_get_cpu_regs_args args; + args.read(iprot); + iprot->readMessageEnd(); + uint32_t bytes = iprot->getTransport()->readEnd(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postRead(ctx, "BsnesDebugger.get_cpu_regs", bytes); + } + + BsnesDebugger_get_cpu_regs_result result; + try { + iface_->get_cpu_regs(result.success); + result.__isset.success = true; + } catch (const std::exception& e) { + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->handlerError(ctx, "BsnesDebugger.get_cpu_regs"); + } + + ::apache::thrift::TApplicationException x(e.what()); + oprot->writeMessageBegin("get_cpu_regs", ::apache::thrift::protocol::T_EXCEPTION, seqid); + x.write(oprot); + oprot->writeMessageEnd(); + oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + return; + } + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preWrite(ctx, "BsnesDebugger.get_cpu_regs"); + } + + oprot->writeMessageBegin("get_cpu_regs", ::apache::thrift::protocol::T_REPLY, seqid); + result.write(oprot); + oprot->writeMessageEnd(); + bytes = oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postWrite(ctx, "BsnesDebugger.get_cpu_regs", bytes); + } +} + +void BsnesDebuggerProcessor::process_set_cpu_reg(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext) +{ + void* ctx = nullptr; + if (this->eventHandler_.get() != nullptr) { + ctx = this->eventHandler_->getContext("BsnesDebugger.set_cpu_reg", callContext); + } + ::apache::thrift::TProcessorContextFreer freer(this->eventHandler_.get(), ctx, "BsnesDebugger.set_cpu_reg"); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preRead(ctx, "BsnesDebugger.set_cpu_reg"); + } + + BsnesDebugger_set_cpu_reg_args args; + args.read(iprot); + iprot->readMessageEnd(); + uint32_t bytes = iprot->getTransport()->readEnd(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postRead(ctx, "BsnesDebugger.set_cpu_reg", bytes); + } + + BsnesDebugger_set_cpu_reg_result result; + try { + iface_->set_cpu_reg(args.reg, args.value); + } catch (const std::exception& e) { + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->handlerError(ctx, "BsnesDebugger.set_cpu_reg"); + } + + ::apache::thrift::TApplicationException x(e.what()); + oprot->writeMessageBegin("set_cpu_reg", ::apache::thrift::protocol::T_EXCEPTION, seqid); + x.write(oprot); + oprot->writeMessageEnd(); + oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + return; + } + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preWrite(ctx, "BsnesDebugger.set_cpu_reg"); + } + + oprot->writeMessageBegin("set_cpu_reg", ::apache::thrift::protocol::T_REPLY, seqid); + result.write(oprot); + oprot->writeMessageEnd(); + bytes = oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postWrite(ctx, "BsnesDebugger.set_cpu_reg", bytes); + } +} + +void BsnesDebuggerProcessor::process_read_memory(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext) +{ + void* ctx = nullptr; + if (this->eventHandler_.get() != nullptr) { + ctx = this->eventHandler_->getContext("BsnesDebugger.read_memory", callContext); + } + ::apache::thrift::TProcessorContextFreer freer(this->eventHandler_.get(), ctx, "BsnesDebugger.read_memory"); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preRead(ctx, "BsnesDebugger.read_memory"); + } + + BsnesDebugger_read_memory_args args; + args.read(iprot); + iprot->readMessageEnd(); + uint32_t bytes = iprot->getTransport()->readEnd(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postRead(ctx, "BsnesDebugger.read_memory", bytes); + } + + BsnesDebugger_read_memory_result result; + try { + iface_->read_memory(result.success, args.src, args.address, args.size); + result.__isset.success = true; + } catch (const std::exception& e) { + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->handlerError(ctx, "BsnesDebugger.read_memory"); + } + + ::apache::thrift::TApplicationException x(e.what()); + oprot->writeMessageBegin("read_memory", ::apache::thrift::protocol::T_EXCEPTION, seqid); + x.write(oprot); + oprot->writeMessageEnd(); + oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + return; + } + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preWrite(ctx, "BsnesDebugger.read_memory"); + } + + oprot->writeMessageBegin("read_memory", ::apache::thrift::protocol::T_REPLY, seqid); + result.write(oprot); + oprot->writeMessageEnd(); + bytes = oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postWrite(ctx, "BsnesDebugger.read_memory", bytes); + } +} + +void BsnesDebuggerProcessor::process_write_memory(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext) +{ + void* ctx = nullptr; + if (this->eventHandler_.get() != nullptr) { + ctx = this->eventHandler_->getContext("BsnesDebugger.write_memory", callContext); + } + ::apache::thrift::TProcessorContextFreer freer(this->eventHandler_.get(), ctx, "BsnesDebugger.write_memory"); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preRead(ctx, "BsnesDebugger.write_memory"); + } + + BsnesDebugger_write_memory_args args; + args.read(iprot); + iprot->readMessageEnd(); + uint32_t bytes = iprot->getTransport()->readEnd(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postRead(ctx, "BsnesDebugger.write_memory", bytes); + } + + BsnesDebugger_write_memory_result result; + try { + iface_->write_memory(args.src, args.address, args.data); + } catch (const std::exception& e) { + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->handlerError(ctx, "BsnesDebugger.write_memory"); + } + + ::apache::thrift::TApplicationException x(e.what()); + oprot->writeMessageBegin("write_memory", ::apache::thrift::protocol::T_EXCEPTION, seqid); + x.write(oprot); + oprot->writeMessageEnd(); + oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + return; + } + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preWrite(ctx, "BsnesDebugger.write_memory"); + } + + oprot->writeMessageBegin("write_memory", ::apache::thrift::protocol::T_REPLY, seqid); + result.write(oprot); + oprot->writeMessageEnd(); + bytes = oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postWrite(ctx, "BsnesDebugger.write_memory", bytes); + } +} + +void BsnesDebuggerProcessor::process_add_breakpoint(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext) +{ + void* ctx = nullptr; + if (this->eventHandler_.get() != nullptr) { + ctx = this->eventHandler_->getContext("BsnesDebugger.add_breakpoint", callContext); + } + ::apache::thrift::TProcessorContextFreer freer(this->eventHandler_.get(), ctx, "BsnesDebugger.add_breakpoint"); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preRead(ctx, "BsnesDebugger.add_breakpoint"); + } + + BsnesDebugger_add_breakpoint_args args; + args.read(iprot); + iprot->readMessageEnd(); + uint32_t bytes = iprot->getTransport()->readEnd(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postRead(ctx, "BsnesDebugger.add_breakpoint", bytes); + } + + BsnesDebugger_add_breakpoint_result result; + try { + iface_->add_breakpoint(args.bpt); + } catch (const std::exception& e) { + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->handlerError(ctx, "BsnesDebugger.add_breakpoint"); + } + + ::apache::thrift::TApplicationException x(e.what()); + oprot->writeMessageBegin("add_breakpoint", ::apache::thrift::protocol::T_EXCEPTION, seqid); + x.write(oprot); + oprot->writeMessageEnd(); + oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + return; + } + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preWrite(ctx, "BsnesDebugger.add_breakpoint"); + } + + oprot->writeMessageBegin("add_breakpoint", ::apache::thrift::protocol::T_REPLY, seqid); + result.write(oprot); + oprot->writeMessageEnd(); + bytes = oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postWrite(ctx, "BsnesDebugger.add_breakpoint", bytes); + } +} + +void BsnesDebuggerProcessor::process_del_breakpoint(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext) +{ + void* ctx = nullptr; + if (this->eventHandler_.get() != nullptr) { + ctx = this->eventHandler_->getContext("BsnesDebugger.del_breakpoint", callContext); + } + ::apache::thrift::TProcessorContextFreer freer(this->eventHandler_.get(), ctx, "BsnesDebugger.del_breakpoint"); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preRead(ctx, "BsnesDebugger.del_breakpoint"); + } + + BsnesDebugger_del_breakpoint_args args; + args.read(iprot); + iprot->readMessageEnd(); + uint32_t bytes = iprot->getTransport()->readEnd(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postRead(ctx, "BsnesDebugger.del_breakpoint", bytes); + } + + BsnesDebugger_del_breakpoint_result result; + try { + iface_->del_breakpoint(args.bpt); + } catch (const std::exception& e) { + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->handlerError(ctx, "BsnesDebugger.del_breakpoint"); + } + + ::apache::thrift::TApplicationException x(e.what()); + oprot->writeMessageBegin("del_breakpoint", ::apache::thrift::protocol::T_EXCEPTION, seqid); + x.write(oprot); + oprot->writeMessageEnd(); + oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + return; + } + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preWrite(ctx, "BsnesDebugger.del_breakpoint"); + } + + oprot->writeMessageBegin("del_breakpoint", ::apache::thrift::protocol::T_REPLY, seqid); + result.write(oprot); + oprot->writeMessageEnd(); + bytes = oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postWrite(ctx, "BsnesDebugger.del_breakpoint", bytes); + } +} + +void BsnesDebuggerProcessor::process_pause(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext) +{ + void* ctx = nullptr; + if (this->eventHandler_.get() != nullptr) { + ctx = this->eventHandler_->getContext("BsnesDebugger.pause", callContext); + } + ::apache::thrift::TProcessorContextFreer freer(this->eventHandler_.get(), ctx, "BsnesDebugger.pause"); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preRead(ctx, "BsnesDebugger.pause"); + } + + BsnesDebugger_pause_args args; + args.read(iprot); + iprot->readMessageEnd(); + uint32_t bytes = iprot->getTransport()->readEnd(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postRead(ctx, "BsnesDebugger.pause", bytes); + } + + BsnesDebugger_pause_result result; + try { + iface_->pause(); + } catch (const std::exception& e) { + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->handlerError(ctx, "BsnesDebugger.pause"); + } + + ::apache::thrift::TApplicationException x(e.what()); + oprot->writeMessageBegin("pause", ::apache::thrift::protocol::T_EXCEPTION, seqid); + x.write(oprot); + oprot->writeMessageEnd(); + oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + return; + } + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preWrite(ctx, "BsnesDebugger.pause"); + } + + oprot->writeMessageBegin("pause", ::apache::thrift::protocol::T_REPLY, seqid); + result.write(oprot); + oprot->writeMessageEnd(); + bytes = oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postWrite(ctx, "BsnesDebugger.pause", bytes); + } +} + +void BsnesDebuggerProcessor::process_resume(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext) +{ + void* ctx = nullptr; + if (this->eventHandler_.get() != nullptr) { + ctx = this->eventHandler_->getContext("BsnesDebugger.resume", callContext); + } + ::apache::thrift::TProcessorContextFreer freer(this->eventHandler_.get(), ctx, "BsnesDebugger.resume"); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preRead(ctx, "BsnesDebugger.resume"); + } + + BsnesDebugger_resume_args args; + args.read(iprot); + iprot->readMessageEnd(); + uint32_t bytes = iprot->getTransport()->readEnd(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postRead(ctx, "BsnesDebugger.resume", bytes); + } + + BsnesDebugger_resume_result result; + try { + iface_->resume(); + } catch (const std::exception& e) { + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->handlerError(ctx, "BsnesDebugger.resume"); + } + + ::apache::thrift::TApplicationException x(e.what()); + oprot->writeMessageBegin("resume", ::apache::thrift::protocol::T_EXCEPTION, seqid); + x.write(oprot); + oprot->writeMessageEnd(); + oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + return; + } + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preWrite(ctx, "BsnesDebugger.resume"); + } + + oprot->writeMessageBegin("resume", ::apache::thrift::protocol::T_REPLY, seqid); + result.write(oprot); + oprot->writeMessageEnd(); + bytes = oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postWrite(ctx, "BsnesDebugger.resume", bytes); + } +} + +void BsnesDebuggerProcessor::process_start_emulation(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext) +{ + void* ctx = nullptr; + if (this->eventHandler_.get() != nullptr) { + ctx = this->eventHandler_->getContext("BsnesDebugger.start_emulation", callContext); + } + ::apache::thrift::TProcessorContextFreer freer(this->eventHandler_.get(), ctx, "BsnesDebugger.start_emulation"); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preRead(ctx, "BsnesDebugger.start_emulation"); + } + + BsnesDebugger_start_emulation_args args; + args.read(iprot); + iprot->readMessageEnd(); + uint32_t bytes = iprot->getTransport()->readEnd(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postRead(ctx, "BsnesDebugger.start_emulation", bytes); + } + + BsnesDebugger_start_emulation_result result; + try { + iface_->start_emulation(); + } catch (const std::exception& e) { + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->handlerError(ctx, "BsnesDebugger.start_emulation"); + } + + ::apache::thrift::TApplicationException x(e.what()); + oprot->writeMessageBegin("start_emulation", ::apache::thrift::protocol::T_EXCEPTION, seqid); + x.write(oprot); + oprot->writeMessageEnd(); + oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + return; + } + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preWrite(ctx, "BsnesDebugger.start_emulation"); + } + + oprot->writeMessageBegin("start_emulation", ::apache::thrift::protocol::T_REPLY, seqid); + result.write(oprot); + oprot->writeMessageEnd(); + bytes = oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postWrite(ctx, "BsnesDebugger.start_emulation", bytes); + } +} + +void BsnesDebuggerProcessor::process_exit_emulation(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext) +{ + void* ctx = nullptr; + if (this->eventHandler_.get() != nullptr) { + ctx = this->eventHandler_->getContext("BsnesDebugger.exit_emulation", callContext); + } + ::apache::thrift::TProcessorContextFreer freer(this->eventHandler_.get(), ctx, "BsnesDebugger.exit_emulation"); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preRead(ctx, "BsnesDebugger.exit_emulation"); + } + + BsnesDebugger_exit_emulation_args args; + args.read(iprot); + iprot->readMessageEnd(); + uint32_t bytes = iprot->getTransport()->readEnd(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postRead(ctx, "BsnesDebugger.exit_emulation", bytes); + } + + BsnesDebugger_exit_emulation_result result; + try { + iface_->exit_emulation(); + } catch (const std::exception& e) { + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->handlerError(ctx, "BsnesDebugger.exit_emulation"); + } + + ::apache::thrift::TApplicationException x(e.what()); + oprot->writeMessageBegin("exit_emulation", ::apache::thrift::protocol::T_EXCEPTION, seqid); + x.write(oprot); + oprot->writeMessageEnd(); + oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + return; + } + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preWrite(ctx, "BsnesDebugger.exit_emulation"); + } + + oprot->writeMessageBegin("exit_emulation", ::apache::thrift::protocol::T_REPLY, seqid); + result.write(oprot); + oprot->writeMessageEnd(); + bytes = oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postWrite(ctx, "BsnesDebugger.exit_emulation", bytes); + } +} + +void BsnesDebuggerProcessor::process_step_into(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext) +{ + void* ctx = nullptr; + if (this->eventHandler_.get() != nullptr) { + ctx = this->eventHandler_->getContext("BsnesDebugger.step_into", callContext); + } + ::apache::thrift::TProcessorContextFreer freer(this->eventHandler_.get(), ctx, "BsnesDebugger.step_into"); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preRead(ctx, "BsnesDebugger.step_into"); + } + + BsnesDebugger_step_into_args args; + args.read(iprot); + iprot->readMessageEnd(); + uint32_t bytes = iprot->getTransport()->readEnd(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postRead(ctx, "BsnesDebugger.step_into", bytes); + } + + BsnesDebugger_step_into_result result; + try { + iface_->step_into(); + } catch (const std::exception& e) { + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->handlerError(ctx, "BsnesDebugger.step_into"); + } + + ::apache::thrift::TApplicationException x(e.what()); + oprot->writeMessageBegin("step_into", ::apache::thrift::protocol::T_EXCEPTION, seqid); + x.write(oprot); + oprot->writeMessageEnd(); + oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + return; + } + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preWrite(ctx, "BsnesDebugger.step_into"); + } + + oprot->writeMessageBegin("step_into", ::apache::thrift::protocol::T_REPLY, seqid); + result.write(oprot); + oprot->writeMessageEnd(); + bytes = oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postWrite(ctx, "BsnesDebugger.step_into", bytes); + } +} + +void BsnesDebuggerProcessor::process_step_over(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext) +{ + void* ctx = nullptr; + if (this->eventHandler_.get() != nullptr) { + ctx = this->eventHandler_->getContext("BsnesDebugger.step_over", callContext); + } + ::apache::thrift::TProcessorContextFreer freer(this->eventHandler_.get(), ctx, "BsnesDebugger.step_over"); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preRead(ctx, "BsnesDebugger.step_over"); + } + + BsnesDebugger_step_over_args args; + args.read(iprot); + iprot->readMessageEnd(); + uint32_t bytes = iprot->getTransport()->readEnd(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postRead(ctx, "BsnesDebugger.step_over", bytes); + } + + BsnesDebugger_step_over_result result; + try { + iface_->step_over(); + } catch (const std::exception& e) { + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->handlerError(ctx, "BsnesDebugger.step_over"); + } + + ::apache::thrift::TApplicationException x(e.what()); + oprot->writeMessageBegin("step_over", ::apache::thrift::protocol::T_EXCEPTION, seqid); + x.write(oprot); + oprot->writeMessageEnd(); + oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + return; + } + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preWrite(ctx, "BsnesDebugger.step_over"); + } + + oprot->writeMessageBegin("step_over", ::apache::thrift::protocol::T_REPLY, seqid); + result.write(oprot); + oprot->writeMessageEnd(); + bytes = oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postWrite(ctx, "BsnesDebugger.step_over", bytes); + } +} + +::std::shared_ptr< ::apache::thrift::TProcessor > BsnesDebuggerProcessorFactory::getProcessor(const ::apache::thrift::TConnectionInfo& connInfo) { + ::apache::thrift::ReleaseHandler< BsnesDebuggerIfFactory > cleanup(handlerFactory_); + ::std::shared_ptr< BsnesDebuggerIf > handler(handlerFactory_->getHandler(connInfo), cleanup); + ::std::shared_ptr< ::apache::thrift::TProcessor > processor(new BsnesDebuggerProcessor(handler)); + return processor; +} + +int32_t BsnesDebuggerConcurrentClient::get_cpu_reg(const BsnesRegister::type reg) +{ + int32_t seqid = send_get_cpu_reg(reg); + return recv_get_cpu_reg(seqid); +} + +int32_t BsnesDebuggerConcurrentClient::send_get_cpu_reg(const BsnesRegister::type reg) +{ + int32_t cseqid = this->sync_->generateSeqId(); + ::apache::thrift::async::TConcurrentSendSentry sentry(this->sync_.get()); + oprot_->writeMessageBegin("get_cpu_reg", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_get_cpu_reg_pargs args; + args.reg = ® + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); + + sentry.commit(); + return cseqid; +} + +int32_t BsnesDebuggerConcurrentClient::recv_get_cpu_reg(const int32_t seqid) +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + // the read mutex gets dropped and reacquired as part of waitForWork() + // The destructor of this sentry wakes up other clients + ::apache::thrift::async::TConcurrentRecvSentry sentry(this->sync_.get(), seqid); + + while(true) { + if(!this->sync_->getPending(fname, mtype, rseqid)) { + iprot_->readMessageBegin(fname, mtype, rseqid); + } + if(seqid == rseqid) { + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + sentry.commit(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("get_cpu_reg") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + // in a bad state, don't commit + using ::apache::thrift::protocol::TProtocolException; + throw TProtocolException(TProtocolException::INVALID_DATA); + } + int32_t _return; + BsnesDebugger_get_cpu_reg_presult result; + result.success = &_return; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + if (result.__isset.success) { + sentry.commit(); + return _return; + } + // in a bad state, don't commit + throw ::apache::thrift::TApplicationException(::apache::thrift::TApplicationException::MISSING_RESULT, "get_cpu_reg failed: unknown result"); + } + // seqid != rseqid + this->sync_->updatePending(fname, mtype, rseqid); + + // this will temporarily unlock the readMutex, and let other clients get work done + this->sync_->waitForWork(seqid); + } // end while(true) +} + +void BsnesDebuggerConcurrentClient::get_cpu_regs(BsnesRegisters& _return) +{ + int32_t seqid = send_get_cpu_regs(); + recv_get_cpu_regs(_return, seqid); +} + +int32_t BsnesDebuggerConcurrentClient::send_get_cpu_regs() +{ + int32_t cseqid = this->sync_->generateSeqId(); + ::apache::thrift::async::TConcurrentSendSentry sentry(this->sync_.get()); + oprot_->writeMessageBegin("get_cpu_regs", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_get_cpu_regs_pargs args; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); + + sentry.commit(); + return cseqid; +} + +void BsnesDebuggerConcurrentClient::recv_get_cpu_regs(BsnesRegisters& _return, const int32_t seqid) +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + // the read mutex gets dropped and reacquired as part of waitForWork() + // The destructor of this sentry wakes up other clients + ::apache::thrift::async::TConcurrentRecvSentry sentry(this->sync_.get(), seqid); + + while(true) { + if(!this->sync_->getPending(fname, mtype, rseqid)) { + iprot_->readMessageBegin(fname, mtype, rseqid); + } + if(seqid == rseqid) { + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + sentry.commit(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("get_cpu_regs") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + // in a bad state, don't commit + using ::apache::thrift::protocol::TProtocolException; + throw TProtocolException(TProtocolException::INVALID_DATA); + } + BsnesDebugger_get_cpu_regs_presult result; + result.success = &_return; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + if (result.__isset.success) { + // _return pointer has now been filled + sentry.commit(); + return; + } + // in a bad state, don't commit + throw ::apache::thrift::TApplicationException(::apache::thrift::TApplicationException::MISSING_RESULT, "get_cpu_regs failed: unknown result"); + } + // seqid != rseqid + this->sync_->updatePending(fname, mtype, rseqid); + + // this will temporarily unlock the readMutex, and let other clients get work done + this->sync_->waitForWork(seqid); + } // end while(true) +} + +void BsnesDebuggerConcurrentClient::set_cpu_reg(const BsnesRegister::type reg, const int32_t value) +{ + int32_t seqid = send_set_cpu_reg(reg, value); + recv_set_cpu_reg(seqid); +} + +int32_t BsnesDebuggerConcurrentClient::send_set_cpu_reg(const BsnesRegister::type reg, const int32_t value) +{ + int32_t cseqid = this->sync_->generateSeqId(); + ::apache::thrift::async::TConcurrentSendSentry sentry(this->sync_.get()); + oprot_->writeMessageBegin("set_cpu_reg", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_set_cpu_reg_pargs args; + args.reg = ® + args.value = &value; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); + + sentry.commit(); + return cseqid; +} + +void BsnesDebuggerConcurrentClient::recv_set_cpu_reg(const int32_t seqid) +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + // the read mutex gets dropped and reacquired as part of waitForWork() + // The destructor of this sentry wakes up other clients + ::apache::thrift::async::TConcurrentRecvSentry sentry(this->sync_.get(), seqid); + + while(true) { + if(!this->sync_->getPending(fname, mtype, rseqid)) { + iprot_->readMessageBegin(fname, mtype, rseqid); + } + if(seqid == rseqid) { + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + sentry.commit(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("set_cpu_reg") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + // in a bad state, don't commit + using ::apache::thrift::protocol::TProtocolException; + throw TProtocolException(TProtocolException::INVALID_DATA); + } + BsnesDebugger_set_cpu_reg_presult result; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + sentry.commit(); + return; + } + // seqid != rseqid + this->sync_->updatePending(fname, mtype, rseqid); + + // this will temporarily unlock the readMutex, and let other clients get work done + this->sync_->waitForWork(seqid); + } // end while(true) +} + +void BsnesDebuggerConcurrentClient::read_memory(std::string& _return, const DbgMemorySource::type src, const int32_t address, const int32_t size) +{ + int32_t seqid = send_read_memory(src, address, size); + recv_read_memory(_return, seqid); +} + +int32_t BsnesDebuggerConcurrentClient::send_read_memory(const DbgMemorySource::type src, const int32_t address, const int32_t size) +{ + int32_t cseqid = this->sync_->generateSeqId(); + ::apache::thrift::async::TConcurrentSendSentry sentry(this->sync_.get()); + oprot_->writeMessageBegin("read_memory", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_read_memory_pargs args; + args.src = &src; + args.address = &address; + args.size = &size; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); + + sentry.commit(); + return cseqid; +} + +void BsnesDebuggerConcurrentClient::recv_read_memory(std::string& _return, const int32_t seqid) +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + // the read mutex gets dropped and reacquired as part of waitForWork() + // The destructor of this sentry wakes up other clients + ::apache::thrift::async::TConcurrentRecvSentry sentry(this->sync_.get(), seqid); + + while(true) { + if(!this->sync_->getPending(fname, mtype, rseqid)) { + iprot_->readMessageBegin(fname, mtype, rseqid); + } + if(seqid == rseqid) { + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + sentry.commit(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("read_memory") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + // in a bad state, don't commit + using ::apache::thrift::protocol::TProtocolException; + throw TProtocolException(TProtocolException::INVALID_DATA); + } + BsnesDebugger_read_memory_presult result; + result.success = &_return; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + if (result.__isset.success) { + // _return pointer has now been filled + sentry.commit(); + return; + } + // in a bad state, don't commit + throw ::apache::thrift::TApplicationException(::apache::thrift::TApplicationException::MISSING_RESULT, "read_memory failed: unknown result"); + } + // seqid != rseqid + this->sync_->updatePending(fname, mtype, rseqid); + + // this will temporarily unlock the readMutex, and let other clients get work done + this->sync_->waitForWork(seqid); + } // end while(true) +} + +void BsnesDebuggerConcurrentClient::write_memory(const DbgMemorySource::type src, const int32_t address, const std::string& data) +{ + int32_t seqid = send_write_memory(src, address, data); + recv_write_memory(seqid); +} + +int32_t BsnesDebuggerConcurrentClient::send_write_memory(const DbgMemorySource::type src, const int32_t address, const std::string& data) +{ + int32_t cseqid = this->sync_->generateSeqId(); + ::apache::thrift::async::TConcurrentSendSentry sentry(this->sync_.get()); + oprot_->writeMessageBegin("write_memory", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_write_memory_pargs args; + args.src = &src; + args.address = &address; + args.data = &data; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); + + sentry.commit(); + return cseqid; +} + +void BsnesDebuggerConcurrentClient::recv_write_memory(const int32_t seqid) +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + // the read mutex gets dropped and reacquired as part of waitForWork() + // The destructor of this sentry wakes up other clients + ::apache::thrift::async::TConcurrentRecvSentry sentry(this->sync_.get(), seqid); + + while(true) { + if(!this->sync_->getPending(fname, mtype, rseqid)) { + iprot_->readMessageBegin(fname, mtype, rseqid); + } + if(seqid == rseqid) { + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + sentry.commit(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("write_memory") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + // in a bad state, don't commit + using ::apache::thrift::protocol::TProtocolException; + throw TProtocolException(TProtocolException::INVALID_DATA); + } + BsnesDebugger_write_memory_presult result; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + sentry.commit(); + return; + } + // seqid != rseqid + this->sync_->updatePending(fname, mtype, rseqid); + + // this will temporarily unlock the readMutex, and let other clients get work done + this->sync_->waitForWork(seqid); + } // end while(true) +} + +void BsnesDebuggerConcurrentClient::add_breakpoint(const DbgBreakpoint& bpt) +{ + int32_t seqid = send_add_breakpoint(bpt); + recv_add_breakpoint(seqid); +} + +int32_t BsnesDebuggerConcurrentClient::send_add_breakpoint(const DbgBreakpoint& bpt) +{ + int32_t cseqid = this->sync_->generateSeqId(); + ::apache::thrift::async::TConcurrentSendSentry sentry(this->sync_.get()); + oprot_->writeMessageBegin("add_breakpoint", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_add_breakpoint_pargs args; + args.bpt = &bpt; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); + + sentry.commit(); + return cseqid; +} + +void BsnesDebuggerConcurrentClient::recv_add_breakpoint(const int32_t seqid) +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + // the read mutex gets dropped and reacquired as part of waitForWork() + // The destructor of this sentry wakes up other clients + ::apache::thrift::async::TConcurrentRecvSentry sentry(this->sync_.get(), seqid); + + while(true) { + if(!this->sync_->getPending(fname, mtype, rseqid)) { + iprot_->readMessageBegin(fname, mtype, rseqid); + } + if(seqid == rseqid) { + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + sentry.commit(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("add_breakpoint") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + // in a bad state, don't commit + using ::apache::thrift::protocol::TProtocolException; + throw TProtocolException(TProtocolException::INVALID_DATA); + } + BsnesDebugger_add_breakpoint_presult result; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + sentry.commit(); + return; + } + // seqid != rseqid + this->sync_->updatePending(fname, mtype, rseqid); + + // this will temporarily unlock the readMutex, and let other clients get work done + this->sync_->waitForWork(seqid); + } // end while(true) +} + +void BsnesDebuggerConcurrentClient::del_breakpoint(const DbgBreakpoint& bpt) +{ + int32_t seqid = send_del_breakpoint(bpt); + recv_del_breakpoint(seqid); +} + +int32_t BsnesDebuggerConcurrentClient::send_del_breakpoint(const DbgBreakpoint& bpt) +{ + int32_t cseqid = this->sync_->generateSeqId(); + ::apache::thrift::async::TConcurrentSendSentry sentry(this->sync_.get()); + oprot_->writeMessageBegin("del_breakpoint", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_del_breakpoint_pargs args; + args.bpt = &bpt; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); + + sentry.commit(); + return cseqid; +} + +void BsnesDebuggerConcurrentClient::recv_del_breakpoint(const int32_t seqid) +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + // the read mutex gets dropped and reacquired as part of waitForWork() + // The destructor of this sentry wakes up other clients + ::apache::thrift::async::TConcurrentRecvSentry sentry(this->sync_.get(), seqid); + + while(true) { + if(!this->sync_->getPending(fname, mtype, rseqid)) { + iprot_->readMessageBegin(fname, mtype, rseqid); + } + if(seqid == rseqid) { + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + sentry.commit(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("del_breakpoint") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + // in a bad state, don't commit + using ::apache::thrift::protocol::TProtocolException; + throw TProtocolException(TProtocolException::INVALID_DATA); + } + BsnesDebugger_del_breakpoint_presult result; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + sentry.commit(); + return; + } + // seqid != rseqid + this->sync_->updatePending(fname, mtype, rseqid); + + // this will temporarily unlock the readMutex, and let other clients get work done + this->sync_->waitForWork(seqid); + } // end while(true) +} + +void BsnesDebuggerConcurrentClient::pause() +{ + int32_t seqid = send_pause(); + recv_pause(seqid); +} + +int32_t BsnesDebuggerConcurrentClient::send_pause() +{ + int32_t cseqid = this->sync_->generateSeqId(); + ::apache::thrift::async::TConcurrentSendSentry sentry(this->sync_.get()); + oprot_->writeMessageBegin("pause", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_pause_pargs args; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); + + sentry.commit(); + return cseqid; +} + +void BsnesDebuggerConcurrentClient::recv_pause(const int32_t seqid) +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + // the read mutex gets dropped and reacquired as part of waitForWork() + // The destructor of this sentry wakes up other clients + ::apache::thrift::async::TConcurrentRecvSentry sentry(this->sync_.get(), seqid); + + while(true) { + if(!this->sync_->getPending(fname, mtype, rseqid)) { + iprot_->readMessageBegin(fname, mtype, rseqid); + } + if(seqid == rseqid) { + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + sentry.commit(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("pause") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + // in a bad state, don't commit + using ::apache::thrift::protocol::TProtocolException; + throw TProtocolException(TProtocolException::INVALID_DATA); + } + BsnesDebugger_pause_presult result; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + sentry.commit(); + return; + } + // seqid != rseqid + this->sync_->updatePending(fname, mtype, rseqid); + + // this will temporarily unlock the readMutex, and let other clients get work done + this->sync_->waitForWork(seqid); + } // end while(true) +} + +void BsnesDebuggerConcurrentClient::resume() +{ + int32_t seqid = send_resume(); + recv_resume(seqid); +} + +int32_t BsnesDebuggerConcurrentClient::send_resume() +{ + int32_t cseqid = this->sync_->generateSeqId(); + ::apache::thrift::async::TConcurrentSendSentry sentry(this->sync_.get()); + oprot_->writeMessageBegin("resume", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_resume_pargs args; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); + + sentry.commit(); + return cseqid; +} + +void BsnesDebuggerConcurrentClient::recv_resume(const int32_t seqid) +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + // the read mutex gets dropped and reacquired as part of waitForWork() + // The destructor of this sentry wakes up other clients + ::apache::thrift::async::TConcurrentRecvSentry sentry(this->sync_.get(), seqid); + + while(true) { + if(!this->sync_->getPending(fname, mtype, rseqid)) { + iprot_->readMessageBegin(fname, mtype, rseqid); + } + if(seqid == rseqid) { + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + sentry.commit(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("resume") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + // in a bad state, don't commit + using ::apache::thrift::protocol::TProtocolException; + throw TProtocolException(TProtocolException::INVALID_DATA); + } + BsnesDebugger_resume_presult result; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + sentry.commit(); + return; + } + // seqid != rseqid + this->sync_->updatePending(fname, mtype, rseqid); + + // this will temporarily unlock the readMutex, and let other clients get work done + this->sync_->waitForWork(seqid); + } // end while(true) +} + +void BsnesDebuggerConcurrentClient::start_emulation() +{ + int32_t seqid = send_start_emulation(); + recv_start_emulation(seqid); +} + +int32_t BsnesDebuggerConcurrentClient::send_start_emulation() +{ + int32_t cseqid = this->sync_->generateSeqId(); + ::apache::thrift::async::TConcurrentSendSentry sentry(this->sync_.get()); + oprot_->writeMessageBegin("start_emulation", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_start_emulation_pargs args; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); + + sentry.commit(); + return cseqid; +} + +void BsnesDebuggerConcurrentClient::recv_start_emulation(const int32_t seqid) +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + // the read mutex gets dropped and reacquired as part of waitForWork() + // The destructor of this sentry wakes up other clients + ::apache::thrift::async::TConcurrentRecvSentry sentry(this->sync_.get(), seqid); + + while(true) { + if(!this->sync_->getPending(fname, mtype, rseqid)) { + iprot_->readMessageBegin(fname, mtype, rseqid); + } + if(seqid == rseqid) { + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + sentry.commit(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("start_emulation") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + // in a bad state, don't commit + using ::apache::thrift::protocol::TProtocolException; + throw TProtocolException(TProtocolException::INVALID_DATA); + } + BsnesDebugger_start_emulation_presult result; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + sentry.commit(); + return; + } + // seqid != rseqid + this->sync_->updatePending(fname, mtype, rseqid); + + // this will temporarily unlock the readMutex, and let other clients get work done + this->sync_->waitForWork(seqid); + } // end while(true) +} + +void BsnesDebuggerConcurrentClient::exit_emulation() +{ + int32_t seqid = send_exit_emulation(); + recv_exit_emulation(seqid); +} + +int32_t BsnesDebuggerConcurrentClient::send_exit_emulation() +{ + int32_t cseqid = this->sync_->generateSeqId(); + ::apache::thrift::async::TConcurrentSendSentry sentry(this->sync_.get()); + oprot_->writeMessageBegin("exit_emulation", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_exit_emulation_pargs args; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); + + sentry.commit(); + return cseqid; +} + +void BsnesDebuggerConcurrentClient::recv_exit_emulation(const int32_t seqid) +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + // the read mutex gets dropped and reacquired as part of waitForWork() + // The destructor of this sentry wakes up other clients + ::apache::thrift::async::TConcurrentRecvSentry sentry(this->sync_.get(), seqid); + + while(true) { + if(!this->sync_->getPending(fname, mtype, rseqid)) { + iprot_->readMessageBegin(fname, mtype, rseqid); + } + if(seqid == rseqid) { + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + sentry.commit(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("exit_emulation") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + // in a bad state, don't commit + using ::apache::thrift::protocol::TProtocolException; + throw TProtocolException(TProtocolException::INVALID_DATA); + } + BsnesDebugger_exit_emulation_presult result; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + sentry.commit(); + return; + } + // seqid != rseqid + this->sync_->updatePending(fname, mtype, rseqid); + + // this will temporarily unlock the readMutex, and let other clients get work done + this->sync_->waitForWork(seqid); + } // end while(true) +} + +void BsnesDebuggerConcurrentClient::step_into() +{ + int32_t seqid = send_step_into(); + recv_step_into(seqid); +} + +int32_t BsnesDebuggerConcurrentClient::send_step_into() +{ + int32_t cseqid = this->sync_->generateSeqId(); + ::apache::thrift::async::TConcurrentSendSentry sentry(this->sync_.get()); + oprot_->writeMessageBegin("step_into", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_step_into_pargs args; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); + + sentry.commit(); + return cseqid; +} + +void BsnesDebuggerConcurrentClient::recv_step_into(const int32_t seqid) +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + // the read mutex gets dropped and reacquired as part of waitForWork() + // The destructor of this sentry wakes up other clients + ::apache::thrift::async::TConcurrentRecvSentry sentry(this->sync_.get(), seqid); + + while(true) { + if(!this->sync_->getPending(fname, mtype, rseqid)) { + iprot_->readMessageBegin(fname, mtype, rseqid); + } + if(seqid == rseqid) { + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + sentry.commit(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("step_into") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + // in a bad state, don't commit + using ::apache::thrift::protocol::TProtocolException; + throw TProtocolException(TProtocolException::INVALID_DATA); + } + BsnesDebugger_step_into_presult result; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + sentry.commit(); + return; + } + // seqid != rseqid + this->sync_->updatePending(fname, mtype, rseqid); + + // this will temporarily unlock the readMutex, and let other clients get work done + this->sync_->waitForWork(seqid); + } // end while(true) +} + +void BsnesDebuggerConcurrentClient::step_over() +{ + int32_t seqid = send_step_over(); + recv_step_over(seqid); +} + +int32_t BsnesDebuggerConcurrentClient::send_step_over() +{ + int32_t cseqid = this->sync_->generateSeqId(); + ::apache::thrift::async::TConcurrentSendSentry sentry(this->sync_.get()); + oprot_->writeMessageBegin("step_over", ::apache::thrift::protocol::T_CALL, cseqid); + + BsnesDebugger_step_over_pargs args; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); + + sentry.commit(); + return cseqid; +} + +void BsnesDebuggerConcurrentClient::recv_step_over(const int32_t seqid) +{ + + int32_t rseqid = 0; + std::string fname; + ::apache::thrift::protocol::TMessageType mtype; + + // the read mutex gets dropped and reacquired as part of waitForWork() + // The destructor of this sentry wakes up other clients + ::apache::thrift::async::TConcurrentRecvSentry sentry(this->sync_.get(), seqid); + + while(true) { + if(!this->sync_->getPending(fname, mtype, rseqid)) { + iprot_->readMessageBegin(fname, mtype, rseqid); + } + if(seqid == rseqid) { + if (mtype == ::apache::thrift::protocol::T_EXCEPTION) { + ::apache::thrift::TApplicationException x; + x.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + sentry.commit(); + throw x; + } + if (mtype != ::apache::thrift::protocol::T_REPLY) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + } + if (fname.compare("step_over") != 0) { + iprot_->skip(::apache::thrift::protocol::T_STRUCT); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + // in a bad state, don't commit + using ::apache::thrift::protocol::TProtocolException; + throw TProtocolException(TProtocolException::INVALID_DATA); + } + BsnesDebugger_step_over_presult result; + result.read(iprot_); + iprot_->readMessageEnd(); + iprot_->getTransport()->readEnd(); + + sentry.commit(); + return; + } + // seqid != rseqid + this->sync_->updatePending(fname, mtype, rseqid); + + // this will temporarily unlock the readMutex, and let other clients get work done + this->sync_->waitForWork(seqid); + } // end while(true) +} + + + diff --git a/bsnes/gen-cpp/BsnesDebugger.h b/bsnes/gen-cpp/BsnesDebugger.h new file mode 100644 index 00000000..3825a66a --- /dev/null +++ b/bsnes/gen-cpp/BsnesDebugger.h @@ -0,0 +1,1604 @@ +/** + * Autogenerated by Thrift Compiler (0.14.0) + * + * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + * @generated + */ +#ifndef BsnesDebugger_H +#define BsnesDebugger_H + +#include +#include +#include +#include "debug_proto_types.h" + + + +#ifdef _MSC_VER + #pragma warning( push ) + #pragma warning (disable : 4250 ) //inheriting methods via dominance +#endif + +class BsnesDebuggerIf { + public: + virtual ~BsnesDebuggerIf() {} + virtual int32_t get_cpu_reg(const BsnesRegister::type reg) = 0; + virtual void get_cpu_regs(BsnesRegisters& _return) = 0; + virtual void set_cpu_reg(const BsnesRegister::type reg, const int32_t value) = 0; + virtual void read_memory(std::string& _return, const DbgMemorySource::type src, const int32_t address, const int32_t size) = 0; + virtual void write_memory(const DbgMemorySource::type src, const int32_t address, const std::string& data) = 0; + virtual void add_breakpoint(const DbgBreakpoint& bpt) = 0; + virtual void del_breakpoint(const DbgBreakpoint& bpt) = 0; + virtual void pause() = 0; + virtual void resume() = 0; + virtual void start_emulation() = 0; + virtual void exit_emulation() = 0; + virtual void step_into() = 0; + virtual void step_over() = 0; +}; + +class BsnesDebuggerIfFactory { + public: + typedef BsnesDebuggerIf Handler; + + virtual ~BsnesDebuggerIfFactory() {} + + virtual BsnesDebuggerIf* getHandler(const ::apache::thrift::TConnectionInfo& connInfo) = 0; + virtual void releaseHandler(BsnesDebuggerIf* /* handler */) = 0; +}; + +class BsnesDebuggerIfSingletonFactory : virtual public BsnesDebuggerIfFactory { + public: + BsnesDebuggerIfSingletonFactory(const ::std::shared_ptr& iface) : iface_(iface) {} + virtual ~BsnesDebuggerIfSingletonFactory() {} + + virtual BsnesDebuggerIf* getHandler(const ::apache::thrift::TConnectionInfo&) { + return iface_.get(); + } + virtual void releaseHandler(BsnesDebuggerIf* /* handler */) {} + + protected: + ::std::shared_ptr iface_; +}; + +class BsnesDebuggerNull : virtual public BsnesDebuggerIf { + public: + virtual ~BsnesDebuggerNull() {} + int32_t get_cpu_reg(const BsnesRegister::type /* reg */) { + int32_t _return = 0; + return _return; + } + void get_cpu_regs(BsnesRegisters& /* _return */) { + return; + } + void set_cpu_reg(const BsnesRegister::type /* reg */, const int32_t /* value */) { + return; + } + void read_memory(std::string& /* _return */, const DbgMemorySource::type /* src */, const int32_t /* address */, const int32_t /* size */) { + return; + } + void write_memory(const DbgMemorySource::type /* src */, const int32_t /* address */, const std::string& /* data */) { + return; + } + void add_breakpoint(const DbgBreakpoint& /* bpt */) { + return; + } + void del_breakpoint(const DbgBreakpoint& /* bpt */) { + return; + } + void pause() { + return; + } + void resume() { + return; + } + void start_emulation() { + return; + } + void exit_emulation() { + return; + } + void step_into() { + return; + } + void step_over() { + return; + } +}; + +typedef struct _BsnesDebugger_get_cpu_reg_args__isset { + _BsnesDebugger_get_cpu_reg_args__isset() : reg(false) {} + bool reg :1; +} _BsnesDebugger_get_cpu_reg_args__isset; + +class BsnesDebugger_get_cpu_reg_args { + public: + + BsnesDebugger_get_cpu_reg_args(const BsnesDebugger_get_cpu_reg_args&); + BsnesDebugger_get_cpu_reg_args& operator=(const BsnesDebugger_get_cpu_reg_args&); + BsnesDebugger_get_cpu_reg_args() : reg((BsnesRegister::type)0) { + } + + virtual ~BsnesDebugger_get_cpu_reg_args() noexcept; + /** + * + * @see BsnesRegister + */ + BsnesRegister::type reg; + + _BsnesDebugger_get_cpu_reg_args__isset __isset; + + void __set_reg(const BsnesRegister::type val); + + bool operator == (const BsnesDebugger_get_cpu_reg_args & rhs) const + { + if (!(reg == rhs.reg)) + return false; + return true; + } + bool operator != (const BsnesDebugger_get_cpu_reg_args &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_get_cpu_reg_args & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_get_cpu_reg_pargs { + public: + + + virtual ~BsnesDebugger_get_cpu_reg_pargs() noexcept; + /** + * + * @see BsnesRegister + */ + const BsnesRegister::type* reg; + + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + +typedef struct _BsnesDebugger_get_cpu_reg_result__isset { + _BsnesDebugger_get_cpu_reg_result__isset() : success(false) {} + bool success :1; +} _BsnesDebugger_get_cpu_reg_result__isset; + +class BsnesDebugger_get_cpu_reg_result { + public: + + BsnesDebugger_get_cpu_reg_result(const BsnesDebugger_get_cpu_reg_result&); + BsnesDebugger_get_cpu_reg_result& operator=(const BsnesDebugger_get_cpu_reg_result&); + BsnesDebugger_get_cpu_reg_result() : success(0) { + } + + virtual ~BsnesDebugger_get_cpu_reg_result() noexcept; + int32_t success; + + _BsnesDebugger_get_cpu_reg_result__isset __isset; + + void __set_success(const int32_t val); + + bool operator == (const BsnesDebugger_get_cpu_reg_result & rhs) const + { + if (!(success == rhs.success)) + return false; + return true; + } + bool operator != (const BsnesDebugger_get_cpu_reg_result &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_get_cpu_reg_result & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + +typedef struct _BsnesDebugger_get_cpu_reg_presult__isset { + _BsnesDebugger_get_cpu_reg_presult__isset() : success(false) {} + bool success :1; +} _BsnesDebugger_get_cpu_reg_presult__isset; + +class BsnesDebugger_get_cpu_reg_presult { + public: + + + virtual ~BsnesDebugger_get_cpu_reg_presult() noexcept; + int32_t* success; + + _BsnesDebugger_get_cpu_reg_presult__isset __isset; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + +}; + + +class BsnesDebugger_get_cpu_regs_args { + public: + + BsnesDebugger_get_cpu_regs_args(const BsnesDebugger_get_cpu_regs_args&); + BsnesDebugger_get_cpu_regs_args& operator=(const BsnesDebugger_get_cpu_regs_args&); + BsnesDebugger_get_cpu_regs_args() { + } + + virtual ~BsnesDebugger_get_cpu_regs_args() noexcept; + + bool operator == (const BsnesDebugger_get_cpu_regs_args & /* rhs */) const + { + return true; + } + bool operator != (const BsnesDebugger_get_cpu_regs_args &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_get_cpu_regs_args & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_get_cpu_regs_pargs { + public: + + + virtual ~BsnesDebugger_get_cpu_regs_pargs() noexcept; + + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + +typedef struct _BsnesDebugger_get_cpu_regs_result__isset { + _BsnesDebugger_get_cpu_regs_result__isset() : success(false) {} + bool success :1; +} _BsnesDebugger_get_cpu_regs_result__isset; + +class BsnesDebugger_get_cpu_regs_result { + public: + + BsnesDebugger_get_cpu_regs_result(const BsnesDebugger_get_cpu_regs_result&); + BsnesDebugger_get_cpu_regs_result& operator=(const BsnesDebugger_get_cpu_regs_result&); + BsnesDebugger_get_cpu_regs_result() { + } + + virtual ~BsnesDebugger_get_cpu_regs_result() noexcept; + BsnesRegisters success; + + _BsnesDebugger_get_cpu_regs_result__isset __isset; + + void __set_success(const BsnesRegisters& val); + + bool operator == (const BsnesDebugger_get_cpu_regs_result & rhs) const + { + if (!(success == rhs.success)) + return false; + return true; + } + bool operator != (const BsnesDebugger_get_cpu_regs_result &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_get_cpu_regs_result & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + +typedef struct _BsnesDebugger_get_cpu_regs_presult__isset { + _BsnesDebugger_get_cpu_regs_presult__isset() : success(false) {} + bool success :1; +} _BsnesDebugger_get_cpu_regs_presult__isset; + +class BsnesDebugger_get_cpu_regs_presult { + public: + + + virtual ~BsnesDebugger_get_cpu_regs_presult() noexcept; + BsnesRegisters* success; + + _BsnesDebugger_get_cpu_regs_presult__isset __isset; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + +}; + +typedef struct _BsnesDebugger_set_cpu_reg_args__isset { + _BsnesDebugger_set_cpu_reg_args__isset() : reg(false), value(false) {} + bool reg :1; + bool value :1; +} _BsnesDebugger_set_cpu_reg_args__isset; + +class BsnesDebugger_set_cpu_reg_args { + public: + + BsnesDebugger_set_cpu_reg_args(const BsnesDebugger_set_cpu_reg_args&); + BsnesDebugger_set_cpu_reg_args& operator=(const BsnesDebugger_set_cpu_reg_args&); + BsnesDebugger_set_cpu_reg_args() : reg((BsnesRegister::type)0), value(0) { + } + + virtual ~BsnesDebugger_set_cpu_reg_args() noexcept; + /** + * + * @see BsnesRegister + */ + BsnesRegister::type reg; + int32_t value; + + _BsnesDebugger_set_cpu_reg_args__isset __isset; + + void __set_reg(const BsnesRegister::type val); + + void __set_value(const int32_t val); + + bool operator == (const BsnesDebugger_set_cpu_reg_args & rhs) const + { + if (!(reg == rhs.reg)) + return false; + if (!(value == rhs.value)) + return false; + return true; + } + bool operator != (const BsnesDebugger_set_cpu_reg_args &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_set_cpu_reg_args & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_set_cpu_reg_pargs { + public: + + + virtual ~BsnesDebugger_set_cpu_reg_pargs() noexcept; + /** + * + * @see BsnesRegister + */ + const BsnesRegister::type* reg; + const int32_t* value; + + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_set_cpu_reg_result { + public: + + BsnesDebugger_set_cpu_reg_result(const BsnesDebugger_set_cpu_reg_result&); + BsnesDebugger_set_cpu_reg_result& operator=(const BsnesDebugger_set_cpu_reg_result&); + BsnesDebugger_set_cpu_reg_result() { + } + + virtual ~BsnesDebugger_set_cpu_reg_result() noexcept; + + bool operator == (const BsnesDebugger_set_cpu_reg_result & /* rhs */) const + { + return true; + } + bool operator != (const BsnesDebugger_set_cpu_reg_result &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_set_cpu_reg_result & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_set_cpu_reg_presult { + public: + + + virtual ~BsnesDebugger_set_cpu_reg_presult() noexcept; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + +}; + +typedef struct _BsnesDebugger_read_memory_args__isset { + _BsnesDebugger_read_memory_args__isset() : src(false), address(false), size(false) {} + bool src :1; + bool address :1; + bool size :1; +} _BsnesDebugger_read_memory_args__isset; + +class BsnesDebugger_read_memory_args { + public: + + BsnesDebugger_read_memory_args(const BsnesDebugger_read_memory_args&); + BsnesDebugger_read_memory_args& operator=(const BsnesDebugger_read_memory_args&); + BsnesDebugger_read_memory_args() : src((DbgMemorySource::type)0), address(0), size(0) { + } + + virtual ~BsnesDebugger_read_memory_args() noexcept; + /** + * + * @see DbgMemorySource + */ + DbgMemorySource::type src; + int32_t address; + int32_t size; + + _BsnesDebugger_read_memory_args__isset __isset; + + void __set_src(const DbgMemorySource::type val); + + void __set_address(const int32_t val); + + void __set_size(const int32_t val); + + bool operator == (const BsnesDebugger_read_memory_args & rhs) const + { + if (!(src == rhs.src)) + return false; + if (!(address == rhs.address)) + return false; + if (!(size == rhs.size)) + return false; + return true; + } + bool operator != (const BsnesDebugger_read_memory_args &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_read_memory_args & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_read_memory_pargs { + public: + + + virtual ~BsnesDebugger_read_memory_pargs() noexcept; + /** + * + * @see DbgMemorySource + */ + const DbgMemorySource::type* src; + const int32_t* address; + const int32_t* size; + + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + +typedef struct _BsnesDebugger_read_memory_result__isset { + _BsnesDebugger_read_memory_result__isset() : success(false) {} + bool success :1; +} _BsnesDebugger_read_memory_result__isset; + +class BsnesDebugger_read_memory_result { + public: + + BsnesDebugger_read_memory_result(const BsnesDebugger_read_memory_result&); + BsnesDebugger_read_memory_result& operator=(const BsnesDebugger_read_memory_result&); + BsnesDebugger_read_memory_result() : success() { + } + + virtual ~BsnesDebugger_read_memory_result() noexcept; + std::string success; + + _BsnesDebugger_read_memory_result__isset __isset; + + void __set_success(const std::string& val); + + bool operator == (const BsnesDebugger_read_memory_result & rhs) const + { + if (!(success == rhs.success)) + return false; + return true; + } + bool operator != (const BsnesDebugger_read_memory_result &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_read_memory_result & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + +typedef struct _BsnesDebugger_read_memory_presult__isset { + _BsnesDebugger_read_memory_presult__isset() : success(false) {} + bool success :1; +} _BsnesDebugger_read_memory_presult__isset; + +class BsnesDebugger_read_memory_presult { + public: + + + virtual ~BsnesDebugger_read_memory_presult() noexcept; + std::string* success; + + _BsnesDebugger_read_memory_presult__isset __isset; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + +}; + +typedef struct _BsnesDebugger_write_memory_args__isset { + _BsnesDebugger_write_memory_args__isset() : src(false), address(false), data(false) {} + bool src :1; + bool address :1; + bool data :1; +} _BsnesDebugger_write_memory_args__isset; + +class BsnesDebugger_write_memory_args { + public: + + BsnesDebugger_write_memory_args(const BsnesDebugger_write_memory_args&); + BsnesDebugger_write_memory_args& operator=(const BsnesDebugger_write_memory_args&); + BsnesDebugger_write_memory_args() : src((DbgMemorySource::type)0), address(0), data() { + } + + virtual ~BsnesDebugger_write_memory_args() noexcept; + /** + * + * @see DbgMemorySource + */ + DbgMemorySource::type src; + int32_t address; + std::string data; + + _BsnesDebugger_write_memory_args__isset __isset; + + void __set_src(const DbgMemorySource::type val); + + void __set_address(const int32_t val); + + void __set_data(const std::string& val); + + bool operator == (const BsnesDebugger_write_memory_args & rhs) const + { + if (!(src == rhs.src)) + return false; + if (!(address == rhs.address)) + return false; + if (!(data == rhs.data)) + return false; + return true; + } + bool operator != (const BsnesDebugger_write_memory_args &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_write_memory_args & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_write_memory_pargs { + public: + + + virtual ~BsnesDebugger_write_memory_pargs() noexcept; + /** + * + * @see DbgMemorySource + */ + const DbgMemorySource::type* src; + const int32_t* address; + const std::string* data; + + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_write_memory_result { + public: + + BsnesDebugger_write_memory_result(const BsnesDebugger_write_memory_result&); + BsnesDebugger_write_memory_result& operator=(const BsnesDebugger_write_memory_result&); + BsnesDebugger_write_memory_result() { + } + + virtual ~BsnesDebugger_write_memory_result() noexcept; + + bool operator == (const BsnesDebugger_write_memory_result & /* rhs */) const + { + return true; + } + bool operator != (const BsnesDebugger_write_memory_result &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_write_memory_result & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_write_memory_presult { + public: + + + virtual ~BsnesDebugger_write_memory_presult() noexcept; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + +}; + +typedef struct _BsnesDebugger_add_breakpoint_args__isset { + _BsnesDebugger_add_breakpoint_args__isset() : bpt(false) {} + bool bpt :1; +} _BsnesDebugger_add_breakpoint_args__isset; + +class BsnesDebugger_add_breakpoint_args { + public: + + BsnesDebugger_add_breakpoint_args(const BsnesDebugger_add_breakpoint_args&); + BsnesDebugger_add_breakpoint_args& operator=(const BsnesDebugger_add_breakpoint_args&); + BsnesDebugger_add_breakpoint_args() { + } + + virtual ~BsnesDebugger_add_breakpoint_args() noexcept; + DbgBreakpoint bpt; + + _BsnesDebugger_add_breakpoint_args__isset __isset; + + void __set_bpt(const DbgBreakpoint& val); + + bool operator == (const BsnesDebugger_add_breakpoint_args & rhs) const + { + if (!(bpt == rhs.bpt)) + return false; + return true; + } + bool operator != (const BsnesDebugger_add_breakpoint_args &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_add_breakpoint_args & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_add_breakpoint_pargs { + public: + + + virtual ~BsnesDebugger_add_breakpoint_pargs() noexcept; + const DbgBreakpoint* bpt; + + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_add_breakpoint_result { + public: + + BsnesDebugger_add_breakpoint_result(const BsnesDebugger_add_breakpoint_result&); + BsnesDebugger_add_breakpoint_result& operator=(const BsnesDebugger_add_breakpoint_result&); + BsnesDebugger_add_breakpoint_result() { + } + + virtual ~BsnesDebugger_add_breakpoint_result() noexcept; + + bool operator == (const BsnesDebugger_add_breakpoint_result & /* rhs */) const + { + return true; + } + bool operator != (const BsnesDebugger_add_breakpoint_result &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_add_breakpoint_result & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_add_breakpoint_presult { + public: + + + virtual ~BsnesDebugger_add_breakpoint_presult() noexcept; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + +}; + +typedef struct _BsnesDebugger_del_breakpoint_args__isset { + _BsnesDebugger_del_breakpoint_args__isset() : bpt(false) {} + bool bpt :1; +} _BsnesDebugger_del_breakpoint_args__isset; + +class BsnesDebugger_del_breakpoint_args { + public: + + BsnesDebugger_del_breakpoint_args(const BsnesDebugger_del_breakpoint_args&); + BsnesDebugger_del_breakpoint_args& operator=(const BsnesDebugger_del_breakpoint_args&); + BsnesDebugger_del_breakpoint_args() { + } + + virtual ~BsnesDebugger_del_breakpoint_args() noexcept; + DbgBreakpoint bpt; + + _BsnesDebugger_del_breakpoint_args__isset __isset; + + void __set_bpt(const DbgBreakpoint& val); + + bool operator == (const BsnesDebugger_del_breakpoint_args & rhs) const + { + if (!(bpt == rhs.bpt)) + return false; + return true; + } + bool operator != (const BsnesDebugger_del_breakpoint_args &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_del_breakpoint_args & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_del_breakpoint_pargs { + public: + + + virtual ~BsnesDebugger_del_breakpoint_pargs() noexcept; + const DbgBreakpoint* bpt; + + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_del_breakpoint_result { + public: + + BsnesDebugger_del_breakpoint_result(const BsnesDebugger_del_breakpoint_result&); + BsnesDebugger_del_breakpoint_result& operator=(const BsnesDebugger_del_breakpoint_result&); + BsnesDebugger_del_breakpoint_result() { + } + + virtual ~BsnesDebugger_del_breakpoint_result() noexcept; + + bool operator == (const BsnesDebugger_del_breakpoint_result & /* rhs */) const + { + return true; + } + bool operator != (const BsnesDebugger_del_breakpoint_result &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_del_breakpoint_result & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_del_breakpoint_presult { + public: + + + virtual ~BsnesDebugger_del_breakpoint_presult() noexcept; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + +}; + + +class BsnesDebugger_pause_args { + public: + + BsnesDebugger_pause_args(const BsnesDebugger_pause_args&); + BsnesDebugger_pause_args& operator=(const BsnesDebugger_pause_args&); + BsnesDebugger_pause_args() { + } + + virtual ~BsnesDebugger_pause_args() noexcept; + + bool operator == (const BsnesDebugger_pause_args & /* rhs */) const + { + return true; + } + bool operator != (const BsnesDebugger_pause_args &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_pause_args & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_pause_pargs { + public: + + + virtual ~BsnesDebugger_pause_pargs() noexcept; + + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_pause_result { + public: + + BsnesDebugger_pause_result(const BsnesDebugger_pause_result&); + BsnesDebugger_pause_result& operator=(const BsnesDebugger_pause_result&); + BsnesDebugger_pause_result() { + } + + virtual ~BsnesDebugger_pause_result() noexcept; + + bool operator == (const BsnesDebugger_pause_result & /* rhs */) const + { + return true; + } + bool operator != (const BsnesDebugger_pause_result &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_pause_result & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_pause_presult { + public: + + + virtual ~BsnesDebugger_pause_presult() noexcept; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + +}; + + +class BsnesDebugger_resume_args { + public: + + BsnesDebugger_resume_args(const BsnesDebugger_resume_args&); + BsnesDebugger_resume_args& operator=(const BsnesDebugger_resume_args&); + BsnesDebugger_resume_args() { + } + + virtual ~BsnesDebugger_resume_args() noexcept; + + bool operator == (const BsnesDebugger_resume_args & /* rhs */) const + { + return true; + } + bool operator != (const BsnesDebugger_resume_args &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_resume_args & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_resume_pargs { + public: + + + virtual ~BsnesDebugger_resume_pargs() noexcept; + + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_resume_result { + public: + + BsnesDebugger_resume_result(const BsnesDebugger_resume_result&); + BsnesDebugger_resume_result& operator=(const BsnesDebugger_resume_result&); + BsnesDebugger_resume_result() { + } + + virtual ~BsnesDebugger_resume_result() noexcept; + + bool operator == (const BsnesDebugger_resume_result & /* rhs */) const + { + return true; + } + bool operator != (const BsnesDebugger_resume_result &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_resume_result & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_resume_presult { + public: + + + virtual ~BsnesDebugger_resume_presult() noexcept; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + +}; + + +class BsnesDebugger_start_emulation_args { + public: + + BsnesDebugger_start_emulation_args(const BsnesDebugger_start_emulation_args&); + BsnesDebugger_start_emulation_args& operator=(const BsnesDebugger_start_emulation_args&); + BsnesDebugger_start_emulation_args() { + } + + virtual ~BsnesDebugger_start_emulation_args() noexcept; + + bool operator == (const BsnesDebugger_start_emulation_args & /* rhs */) const + { + return true; + } + bool operator != (const BsnesDebugger_start_emulation_args &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_start_emulation_args & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_start_emulation_pargs { + public: + + + virtual ~BsnesDebugger_start_emulation_pargs() noexcept; + + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_start_emulation_result { + public: + + BsnesDebugger_start_emulation_result(const BsnesDebugger_start_emulation_result&); + BsnesDebugger_start_emulation_result& operator=(const BsnesDebugger_start_emulation_result&); + BsnesDebugger_start_emulation_result() { + } + + virtual ~BsnesDebugger_start_emulation_result() noexcept; + + bool operator == (const BsnesDebugger_start_emulation_result & /* rhs */) const + { + return true; + } + bool operator != (const BsnesDebugger_start_emulation_result &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_start_emulation_result & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_start_emulation_presult { + public: + + + virtual ~BsnesDebugger_start_emulation_presult() noexcept; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + +}; + + +class BsnesDebugger_exit_emulation_args { + public: + + BsnesDebugger_exit_emulation_args(const BsnesDebugger_exit_emulation_args&); + BsnesDebugger_exit_emulation_args& operator=(const BsnesDebugger_exit_emulation_args&); + BsnesDebugger_exit_emulation_args() { + } + + virtual ~BsnesDebugger_exit_emulation_args() noexcept; + + bool operator == (const BsnesDebugger_exit_emulation_args & /* rhs */) const + { + return true; + } + bool operator != (const BsnesDebugger_exit_emulation_args &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_exit_emulation_args & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_exit_emulation_pargs { + public: + + + virtual ~BsnesDebugger_exit_emulation_pargs() noexcept; + + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_exit_emulation_result { + public: + + BsnesDebugger_exit_emulation_result(const BsnesDebugger_exit_emulation_result&); + BsnesDebugger_exit_emulation_result& operator=(const BsnesDebugger_exit_emulation_result&); + BsnesDebugger_exit_emulation_result() { + } + + virtual ~BsnesDebugger_exit_emulation_result() noexcept; + + bool operator == (const BsnesDebugger_exit_emulation_result & /* rhs */) const + { + return true; + } + bool operator != (const BsnesDebugger_exit_emulation_result &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_exit_emulation_result & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_exit_emulation_presult { + public: + + + virtual ~BsnesDebugger_exit_emulation_presult() noexcept; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + +}; + + +class BsnesDebugger_step_into_args { + public: + + BsnesDebugger_step_into_args(const BsnesDebugger_step_into_args&); + BsnesDebugger_step_into_args& operator=(const BsnesDebugger_step_into_args&); + BsnesDebugger_step_into_args() { + } + + virtual ~BsnesDebugger_step_into_args() noexcept; + + bool operator == (const BsnesDebugger_step_into_args & /* rhs */) const + { + return true; + } + bool operator != (const BsnesDebugger_step_into_args &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_step_into_args & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_step_into_pargs { + public: + + + virtual ~BsnesDebugger_step_into_pargs() noexcept; + + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_step_into_result { + public: + + BsnesDebugger_step_into_result(const BsnesDebugger_step_into_result&); + BsnesDebugger_step_into_result& operator=(const BsnesDebugger_step_into_result&); + BsnesDebugger_step_into_result() { + } + + virtual ~BsnesDebugger_step_into_result() noexcept; + + bool operator == (const BsnesDebugger_step_into_result & /* rhs */) const + { + return true; + } + bool operator != (const BsnesDebugger_step_into_result &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_step_into_result & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_step_into_presult { + public: + + + virtual ~BsnesDebugger_step_into_presult() noexcept; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + +}; + + +class BsnesDebugger_step_over_args { + public: + + BsnesDebugger_step_over_args(const BsnesDebugger_step_over_args&); + BsnesDebugger_step_over_args& operator=(const BsnesDebugger_step_over_args&); + BsnesDebugger_step_over_args() { + } + + virtual ~BsnesDebugger_step_over_args() noexcept; + + bool operator == (const BsnesDebugger_step_over_args & /* rhs */) const + { + return true; + } + bool operator != (const BsnesDebugger_step_over_args &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_step_over_args & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_step_over_pargs { + public: + + + virtual ~BsnesDebugger_step_over_pargs() noexcept; + + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_step_over_result { + public: + + BsnesDebugger_step_over_result(const BsnesDebugger_step_over_result&); + BsnesDebugger_step_over_result& operator=(const BsnesDebugger_step_over_result&); + BsnesDebugger_step_over_result() { + } + + virtual ~BsnesDebugger_step_over_result() noexcept; + + bool operator == (const BsnesDebugger_step_over_result & /* rhs */) const + { + return true; + } + bool operator != (const BsnesDebugger_step_over_result &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesDebugger_step_over_result & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class BsnesDebugger_step_over_presult { + public: + + + virtual ~BsnesDebugger_step_over_presult() noexcept; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + +}; + +class BsnesDebuggerClient : virtual public BsnesDebuggerIf { + public: + BsnesDebuggerClient(std::shared_ptr< ::apache::thrift::protocol::TProtocol> prot) { + setProtocol(prot); + } + BsnesDebuggerClient(std::shared_ptr< ::apache::thrift::protocol::TProtocol> iprot, std::shared_ptr< ::apache::thrift::protocol::TProtocol> oprot) { + setProtocol(iprot,oprot); + } + private: + void setProtocol(std::shared_ptr< ::apache::thrift::protocol::TProtocol> prot) { + setProtocol(prot,prot); + } + void setProtocol(std::shared_ptr< ::apache::thrift::protocol::TProtocol> iprot, std::shared_ptr< ::apache::thrift::protocol::TProtocol> oprot) { + piprot_=iprot; + poprot_=oprot; + iprot_ = iprot.get(); + oprot_ = oprot.get(); + } + public: + std::shared_ptr< ::apache::thrift::protocol::TProtocol> getInputProtocol() { + return piprot_; + } + std::shared_ptr< ::apache::thrift::protocol::TProtocol> getOutputProtocol() { + return poprot_; + } + int32_t get_cpu_reg(const BsnesRegister::type reg); + void send_get_cpu_reg(const BsnesRegister::type reg); + int32_t recv_get_cpu_reg(); + void get_cpu_regs(BsnesRegisters& _return); + void send_get_cpu_regs(); + void recv_get_cpu_regs(BsnesRegisters& _return); + void set_cpu_reg(const BsnesRegister::type reg, const int32_t value); + void send_set_cpu_reg(const BsnesRegister::type reg, const int32_t value); + void recv_set_cpu_reg(); + void read_memory(std::string& _return, const DbgMemorySource::type src, const int32_t address, const int32_t size); + void send_read_memory(const DbgMemorySource::type src, const int32_t address, const int32_t size); + void recv_read_memory(std::string& _return); + void write_memory(const DbgMemorySource::type src, const int32_t address, const std::string& data); + void send_write_memory(const DbgMemorySource::type src, const int32_t address, const std::string& data); + void recv_write_memory(); + void add_breakpoint(const DbgBreakpoint& bpt); + void send_add_breakpoint(const DbgBreakpoint& bpt); + void recv_add_breakpoint(); + void del_breakpoint(const DbgBreakpoint& bpt); + void send_del_breakpoint(const DbgBreakpoint& bpt); + void recv_del_breakpoint(); + void pause(); + void send_pause(); + void recv_pause(); + void resume(); + void send_resume(); + void recv_resume(); + void start_emulation(); + void send_start_emulation(); + void recv_start_emulation(); + void exit_emulation(); + void send_exit_emulation(); + void recv_exit_emulation(); + void step_into(); + void send_step_into(); + void recv_step_into(); + void step_over(); + void send_step_over(); + void recv_step_over(); + protected: + std::shared_ptr< ::apache::thrift::protocol::TProtocol> piprot_; + std::shared_ptr< ::apache::thrift::protocol::TProtocol> poprot_; + ::apache::thrift::protocol::TProtocol* iprot_; + ::apache::thrift::protocol::TProtocol* oprot_; +}; + +class BsnesDebuggerProcessor : public ::apache::thrift::TDispatchProcessor { + protected: + ::std::shared_ptr iface_; + virtual bool dispatchCall(::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, const std::string& fname, int32_t seqid, void* callContext); + private: + typedef void (BsnesDebuggerProcessor::*ProcessFunction)(int32_t, ::apache::thrift::protocol::TProtocol*, ::apache::thrift::protocol::TProtocol*, void*); + typedef std::map ProcessMap; + ProcessMap processMap_; + void process_get_cpu_reg(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext); + void process_get_cpu_regs(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext); + void process_set_cpu_reg(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext); + void process_read_memory(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext); + void process_write_memory(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext); + void process_add_breakpoint(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext); + void process_del_breakpoint(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext); + void process_pause(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext); + void process_resume(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext); + void process_start_emulation(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext); + void process_exit_emulation(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext); + void process_step_into(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext); + void process_step_over(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext); + public: + BsnesDebuggerProcessor(::std::shared_ptr iface) : + iface_(iface) { + processMap_["get_cpu_reg"] = &BsnesDebuggerProcessor::process_get_cpu_reg; + processMap_["get_cpu_regs"] = &BsnesDebuggerProcessor::process_get_cpu_regs; + processMap_["set_cpu_reg"] = &BsnesDebuggerProcessor::process_set_cpu_reg; + processMap_["read_memory"] = &BsnesDebuggerProcessor::process_read_memory; + processMap_["write_memory"] = &BsnesDebuggerProcessor::process_write_memory; + processMap_["add_breakpoint"] = &BsnesDebuggerProcessor::process_add_breakpoint; + processMap_["del_breakpoint"] = &BsnesDebuggerProcessor::process_del_breakpoint; + processMap_["pause"] = &BsnesDebuggerProcessor::process_pause; + processMap_["resume"] = &BsnesDebuggerProcessor::process_resume; + processMap_["start_emulation"] = &BsnesDebuggerProcessor::process_start_emulation; + processMap_["exit_emulation"] = &BsnesDebuggerProcessor::process_exit_emulation; + processMap_["step_into"] = &BsnesDebuggerProcessor::process_step_into; + processMap_["step_over"] = &BsnesDebuggerProcessor::process_step_over; + } + + virtual ~BsnesDebuggerProcessor() {} +}; + +class BsnesDebuggerProcessorFactory : public ::apache::thrift::TProcessorFactory { + public: + BsnesDebuggerProcessorFactory(const ::std::shared_ptr< BsnesDebuggerIfFactory >& handlerFactory) : + handlerFactory_(handlerFactory) {} + + ::std::shared_ptr< ::apache::thrift::TProcessor > getProcessor(const ::apache::thrift::TConnectionInfo& connInfo); + + protected: + ::std::shared_ptr< BsnesDebuggerIfFactory > handlerFactory_; +}; + +class BsnesDebuggerMultiface : virtual public BsnesDebuggerIf { + public: + BsnesDebuggerMultiface(std::vector >& ifaces) : ifaces_(ifaces) { + } + virtual ~BsnesDebuggerMultiface() {} + protected: + std::vector > ifaces_; + BsnesDebuggerMultiface() {} + void add(::std::shared_ptr iface) { + ifaces_.push_back(iface); + } + public: + int32_t get_cpu_reg(const BsnesRegister::type reg) { + size_t sz = ifaces_.size(); + size_t i = 0; + for (; i < (sz - 1); ++i) { + ifaces_[i]->get_cpu_reg(reg); + } + return ifaces_[i]->get_cpu_reg(reg); + } + + void get_cpu_regs(BsnesRegisters& _return) { + size_t sz = ifaces_.size(); + size_t i = 0; + for (; i < (sz - 1); ++i) { + ifaces_[i]->get_cpu_regs(_return); + } + ifaces_[i]->get_cpu_regs(_return); + return; + } + + void set_cpu_reg(const BsnesRegister::type reg, const int32_t value) { + size_t sz = ifaces_.size(); + size_t i = 0; + for (; i < (sz - 1); ++i) { + ifaces_[i]->set_cpu_reg(reg, value); + } + ifaces_[i]->set_cpu_reg(reg, value); + } + + void read_memory(std::string& _return, const DbgMemorySource::type src, const int32_t address, const int32_t size) { + size_t sz = ifaces_.size(); + size_t i = 0; + for (; i < (sz - 1); ++i) { + ifaces_[i]->read_memory(_return, src, address, size); + } + ifaces_[i]->read_memory(_return, src, address, size); + return; + } + + void write_memory(const DbgMemorySource::type src, const int32_t address, const std::string& data) { + size_t sz = ifaces_.size(); + size_t i = 0; + for (; i < (sz - 1); ++i) { + ifaces_[i]->write_memory(src, address, data); + } + ifaces_[i]->write_memory(src, address, data); + } + + void add_breakpoint(const DbgBreakpoint& bpt) { + size_t sz = ifaces_.size(); + size_t i = 0; + for (; i < (sz - 1); ++i) { + ifaces_[i]->add_breakpoint(bpt); + } + ifaces_[i]->add_breakpoint(bpt); + } + + void del_breakpoint(const DbgBreakpoint& bpt) { + size_t sz = ifaces_.size(); + size_t i = 0; + for (; i < (sz - 1); ++i) { + ifaces_[i]->del_breakpoint(bpt); + } + ifaces_[i]->del_breakpoint(bpt); + } + + void pause() { + size_t sz = ifaces_.size(); + size_t i = 0; + for (; i < (sz - 1); ++i) { + ifaces_[i]->pause(); + } + ifaces_[i]->pause(); + } + + void resume() { + size_t sz = ifaces_.size(); + size_t i = 0; + for (; i < (sz - 1); ++i) { + ifaces_[i]->resume(); + } + ifaces_[i]->resume(); + } + + void start_emulation() { + size_t sz = ifaces_.size(); + size_t i = 0; + for (; i < (sz - 1); ++i) { + ifaces_[i]->start_emulation(); + } + ifaces_[i]->start_emulation(); + } + + void exit_emulation() { + size_t sz = ifaces_.size(); + size_t i = 0; + for (; i < (sz - 1); ++i) { + ifaces_[i]->exit_emulation(); + } + ifaces_[i]->exit_emulation(); + } + + void step_into() { + size_t sz = ifaces_.size(); + size_t i = 0; + for (; i < (sz - 1); ++i) { + ifaces_[i]->step_into(); + } + ifaces_[i]->step_into(); + } + + void step_over() { + size_t sz = ifaces_.size(); + size_t i = 0; + for (; i < (sz - 1); ++i) { + ifaces_[i]->step_over(); + } + ifaces_[i]->step_over(); + } + +}; + +// The 'concurrent' client is a thread safe client that correctly handles +// out of order responses. It is slower than the regular client, so should +// only be used when you need to share a connection among multiple threads +class BsnesDebuggerConcurrentClient : virtual public BsnesDebuggerIf { + public: + BsnesDebuggerConcurrentClient(std::shared_ptr< ::apache::thrift::protocol::TProtocol> prot, std::shared_ptr<::apache::thrift::async::TConcurrentClientSyncInfo> sync) : sync_(sync) +{ + setProtocol(prot); + } + BsnesDebuggerConcurrentClient(std::shared_ptr< ::apache::thrift::protocol::TProtocol> iprot, std::shared_ptr< ::apache::thrift::protocol::TProtocol> oprot, std::shared_ptr<::apache::thrift::async::TConcurrentClientSyncInfo> sync) : sync_(sync) +{ + setProtocol(iprot,oprot); + } + private: + void setProtocol(std::shared_ptr< ::apache::thrift::protocol::TProtocol> prot) { + setProtocol(prot,prot); + } + void setProtocol(std::shared_ptr< ::apache::thrift::protocol::TProtocol> iprot, std::shared_ptr< ::apache::thrift::protocol::TProtocol> oprot) { + piprot_=iprot; + poprot_=oprot; + iprot_ = iprot.get(); + oprot_ = oprot.get(); + } + public: + std::shared_ptr< ::apache::thrift::protocol::TProtocol> getInputProtocol() { + return piprot_; + } + std::shared_ptr< ::apache::thrift::protocol::TProtocol> getOutputProtocol() { + return poprot_; + } + int32_t get_cpu_reg(const BsnesRegister::type reg); + int32_t send_get_cpu_reg(const BsnesRegister::type reg); + int32_t recv_get_cpu_reg(const int32_t seqid); + void get_cpu_regs(BsnesRegisters& _return); + int32_t send_get_cpu_regs(); + void recv_get_cpu_regs(BsnesRegisters& _return, const int32_t seqid); + void set_cpu_reg(const BsnesRegister::type reg, const int32_t value); + int32_t send_set_cpu_reg(const BsnesRegister::type reg, const int32_t value); + void recv_set_cpu_reg(const int32_t seqid); + void read_memory(std::string& _return, const DbgMemorySource::type src, const int32_t address, const int32_t size); + int32_t send_read_memory(const DbgMemorySource::type src, const int32_t address, const int32_t size); + void recv_read_memory(std::string& _return, const int32_t seqid); + void write_memory(const DbgMemorySource::type src, const int32_t address, const std::string& data); + int32_t send_write_memory(const DbgMemorySource::type src, const int32_t address, const std::string& data); + void recv_write_memory(const int32_t seqid); + void add_breakpoint(const DbgBreakpoint& bpt); + int32_t send_add_breakpoint(const DbgBreakpoint& bpt); + void recv_add_breakpoint(const int32_t seqid); + void del_breakpoint(const DbgBreakpoint& bpt); + int32_t send_del_breakpoint(const DbgBreakpoint& bpt); + void recv_del_breakpoint(const int32_t seqid); + void pause(); + int32_t send_pause(); + void recv_pause(const int32_t seqid); + void resume(); + int32_t send_resume(); + void recv_resume(const int32_t seqid); + void start_emulation(); + int32_t send_start_emulation(); + void recv_start_emulation(const int32_t seqid); + void exit_emulation(); + int32_t send_exit_emulation(); + void recv_exit_emulation(const int32_t seqid); + void step_into(); + int32_t send_step_into(); + void recv_step_into(const int32_t seqid); + void step_over(); + int32_t send_step_over(); + void recv_step_over(const int32_t seqid); + protected: + std::shared_ptr< ::apache::thrift::protocol::TProtocol> piprot_; + std::shared_ptr< ::apache::thrift::protocol::TProtocol> poprot_; + ::apache::thrift::protocol::TProtocol* iprot_; + ::apache::thrift::protocol::TProtocol* oprot_; + std::shared_ptr<::apache::thrift::async::TConcurrentClientSyncInfo> sync_; +}; + +#ifdef _MSC_VER + #pragma warning( pop ) +#endif + + + +#endif diff --git a/bsnes/gen-cpp/IdaClient.cpp b/bsnes/gen-cpp/IdaClient.cpp new file mode 100644 index 00000000..fe06f1c6 --- /dev/null +++ b/bsnes/gen-cpp/IdaClient.cpp @@ -0,0 +1,667 @@ +/** + * Autogenerated by Thrift Compiler (0.14.0) + * + * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + * @generated + */ +#include "IdaClient.h" + + + + +IdaClient_start_event_args::~IdaClient_start_event_args() noexcept { +} + + +uint32_t IdaClient_start_event_args::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t IdaClient_start_event_args::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("IdaClient_start_event_args"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +IdaClient_start_event_pargs::~IdaClient_start_event_pargs() noexcept { +} + + +uint32_t IdaClient_start_event_pargs::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("IdaClient_start_event_pargs"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +IdaClient_add_visited_args::~IdaClient_add_visited_args() noexcept { +} + + +uint32_t IdaClient_add_visited_args::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 1: + if (ftype == ::apache::thrift::protocol::T_SET) { + { + this->changed.clear(); + uint32_t _size10; + ::apache::thrift::protocol::TType _etype13; + xfer += iprot->readSetBegin(_etype13, _size10); + uint32_t _i14; + for (_i14 = 0; _i14 < _size10; ++_i14) + { + int32_t _elem15; + xfer += iprot->readI32(_elem15); + this->changed.insert(_elem15); + } + xfer += iprot->readSetEnd(); + } + this->__isset.changed = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 2: + if (ftype == ::apache::thrift::protocol::T_BOOL) { + xfer += iprot->readBool(this->is_step); + this->__isset.is_step = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t IdaClient_add_visited_args::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("IdaClient_add_visited_args"); + + xfer += oprot->writeFieldBegin("changed", ::apache::thrift::protocol::T_SET, 1); + { + xfer += oprot->writeSetBegin(::apache::thrift::protocol::T_I32, static_cast(this->changed.size())); + std::set ::const_iterator _iter16; + for (_iter16 = this->changed.begin(); _iter16 != this->changed.end(); ++_iter16) + { + xfer += oprot->writeI32((*_iter16)); + } + xfer += oprot->writeSetEnd(); + } + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("is_step", ::apache::thrift::protocol::T_BOOL, 2); + xfer += oprot->writeBool(this->is_step); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +IdaClient_add_visited_pargs::~IdaClient_add_visited_pargs() noexcept { +} + + +uint32_t IdaClient_add_visited_pargs::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("IdaClient_add_visited_pargs"); + + xfer += oprot->writeFieldBegin("changed", ::apache::thrift::protocol::T_SET, 1); + { + xfer += oprot->writeSetBegin(::apache::thrift::protocol::T_I32, static_cast((*(this->changed)).size())); + std::set ::const_iterator _iter17; + for (_iter17 = (*(this->changed)).begin(); _iter17 != (*(this->changed)).end(); ++_iter17) + { + xfer += oprot->writeI32((*_iter17)); + } + xfer += oprot->writeSetEnd(); + } + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("is_step", ::apache::thrift::protocol::T_BOOL, 2); + xfer += oprot->writeBool((*(this->is_step))); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +IdaClient_pause_event_args::~IdaClient_pause_event_args() noexcept { +} + + +uint32_t IdaClient_pause_event_args::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 1: + if (ftype == ::apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->address); + this->__isset.address = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t IdaClient_pause_event_args::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("IdaClient_pause_event_args"); + + xfer += oprot->writeFieldBegin("address", ::apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32(this->address); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +IdaClient_pause_event_pargs::~IdaClient_pause_event_pargs() noexcept { +} + + +uint32_t IdaClient_pause_event_pargs::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("IdaClient_pause_event_pargs"); + + xfer += oprot->writeFieldBegin("address", ::apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32((*(this->address))); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +IdaClient_stop_event_args::~IdaClient_stop_event_args() noexcept { +} + + +uint32_t IdaClient_stop_event_args::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + xfer += iprot->skip(ftype); + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t IdaClient_stop_event_args::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("IdaClient_stop_event_args"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + + +IdaClient_stop_event_pargs::~IdaClient_stop_event_pargs() noexcept { +} + + +uint32_t IdaClient_stop_event_pargs::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("IdaClient_stop_event_pargs"); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + +void IdaClientClient::start_event() +{ + send_start_event(); +} + +void IdaClientClient::send_start_event() +{ + int32_t cseqid = 0; + oprot_->writeMessageBegin("start_event", ::apache::thrift::protocol::T_ONEWAY, cseqid); + + IdaClient_start_event_pargs args; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); +} + +void IdaClientClient::add_visited(const std::set & changed, const bool is_step) +{ + send_add_visited(changed, is_step); +} + +void IdaClientClient::send_add_visited(const std::set & changed, const bool is_step) +{ + int32_t cseqid = 0; + oprot_->writeMessageBegin("add_visited", ::apache::thrift::protocol::T_ONEWAY, cseqid); + + IdaClient_add_visited_pargs args; + args.changed = &changed; + args.is_step = &is_step; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); +} + +void IdaClientClient::pause_event(const int32_t address) +{ + send_pause_event(address); +} + +void IdaClientClient::send_pause_event(const int32_t address) +{ + int32_t cseqid = 0; + oprot_->writeMessageBegin("pause_event", ::apache::thrift::protocol::T_ONEWAY, cseqid); + + IdaClient_pause_event_pargs args; + args.address = &address; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); +} + +void IdaClientClient::stop_event() +{ + send_stop_event(); +} + +void IdaClientClient::send_stop_event() +{ + int32_t cseqid = 0; + oprot_->writeMessageBegin("stop_event", ::apache::thrift::protocol::T_ONEWAY, cseqid); + + IdaClient_stop_event_pargs args; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); +} + +bool IdaClientProcessor::dispatchCall(::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, const std::string& fname, int32_t seqid, void* callContext) { + ProcessMap::iterator pfn; + pfn = processMap_.find(fname); + if (pfn == processMap_.end()) { + iprot->skip(::apache::thrift::protocol::T_STRUCT); + iprot->readMessageEnd(); + iprot->getTransport()->readEnd(); + ::apache::thrift::TApplicationException x(::apache::thrift::TApplicationException::UNKNOWN_METHOD, "Invalid method name: '"+fname+"'"); + oprot->writeMessageBegin(fname, ::apache::thrift::protocol::T_EXCEPTION, seqid); + x.write(oprot); + oprot->writeMessageEnd(); + oprot->getTransport()->writeEnd(); + oprot->getTransport()->flush(); + return true; + } + (this->*(pfn->second))(seqid, iprot, oprot, callContext); + return true; +} + +void IdaClientProcessor::process_start_event(int32_t, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol*, void* callContext) +{ + void* ctx = nullptr; + if (this->eventHandler_.get() != nullptr) { + ctx = this->eventHandler_->getContext("IdaClient.start_event", callContext); + } + ::apache::thrift::TProcessorContextFreer freer(this->eventHandler_.get(), ctx, "IdaClient.start_event"); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preRead(ctx, "IdaClient.start_event"); + } + + IdaClient_start_event_args args; + args.read(iprot); + iprot->readMessageEnd(); + uint32_t bytes = iprot->getTransport()->readEnd(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postRead(ctx, "IdaClient.start_event", bytes); + } + + try { + iface_->start_event(); + } catch (const std::exception&) { + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->handlerError(ctx, "IdaClient.start_event"); + } + return; + } + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->asyncComplete(ctx, "IdaClient.start_event"); + } + + return; +} + +void IdaClientProcessor::process_add_visited(int32_t, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol*, void* callContext) +{ + void* ctx = nullptr; + if (this->eventHandler_.get() != nullptr) { + ctx = this->eventHandler_->getContext("IdaClient.add_visited", callContext); + } + ::apache::thrift::TProcessorContextFreer freer(this->eventHandler_.get(), ctx, "IdaClient.add_visited"); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preRead(ctx, "IdaClient.add_visited"); + } + + IdaClient_add_visited_args args; + args.read(iprot); + iprot->readMessageEnd(); + uint32_t bytes = iprot->getTransport()->readEnd(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postRead(ctx, "IdaClient.add_visited", bytes); + } + + try { + iface_->add_visited(args.changed, args.is_step); + } catch (const std::exception&) { + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->handlerError(ctx, "IdaClient.add_visited"); + } + return; + } + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->asyncComplete(ctx, "IdaClient.add_visited"); + } + + return; +} + +void IdaClientProcessor::process_pause_event(int32_t, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol*, void* callContext) +{ + void* ctx = nullptr; + if (this->eventHandler_.get() != nullptr) { + ctx = this->eventHandler_->getContext("IdaClient.pause_event", callContext); + } + ::apache::thrift::TProcessorContextFreer freer(this->eventHandler_.get(), ctx, "IdaClient.pause_event"); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preRead(ctx, "IdaClient.pause_event"); + } + + IdaClient_pause_event_args args; + args.read(iprot); + iprot->readMessageEnd(); + uint32_t bytes = iprot->getTransport()->readEnd(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postRead(ctx, "IdaClient.pause_event", bytes); + } + + try { + iface_->pause_event(args.address); + } catch (const std::exception&) { + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->handlerError(ctx, "IdaClient.pause_event"); + } + return; + } + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->asyncComplete(ctx, "IdaClient.pause_event"); + } + + return; +} + +void IdaClientProcessor::process_stop_event(int32_t, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol*, void* callContext) +{ + void* ctx = nullptr; + if (this->eventHandler_.get() != nullptr) { + ctx = this->eventHandler_->getContext("IdaClient.stop_event", callContext); + } + ::apache::thrift::TProcessorContextFreer freer(this->eventHandler_.get(), ctx, "IdaClient.stop_event"); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->preRead(ctx, "IdaClient.stop_event"); + } + + IdaClient_stop_event_args args; + args.read(iprot); + iprot->readMessageEnd(); + uint32_t bytes = iprot->getTransport()->readEnd(); + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->postRead(ctx, "IdaClient.stop_event", bytes); + } + + try { + iface_->stop_event(); + } catch (const std::exception&) { + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->handlerError(ctx, "IdaClient.stop_event"); + } + return; + } + + if (this->eventHandler_.get() != nullptr) { + this->eventHandler_->asyncComplete(ctx, "IdaClient.stop_event"); + } + + return; +} + +::std::shared_ptr< ::apache::thrift::TProcessor > IdaClientProcessorFactory::getProcessor(const ::apache::thrift::TConnectionInfo& connInfo) { + ::apache::thrift::ReleaseHandler< IdaClientIfFactory > cleanup(handlerFactory_); + ::std::shared_ptr< IdaClientIf > handler(handlerFactory_->getHandler(connInfo), cleanup); + ::std::shared_ptr< ::apache::thrift::TProcessor > processor(new IdaClientProcessor(handler)); + return processor; +} + +void IdaClientConcurrentClient::start_event() +{ + send_start_event(); +} + +void IdaClientConcurrentClient::send_start_event() +{ + int32_t cseqid = 0; + ::apache::thrift::async::TConcurrentSendSentry sentry(this->sync_.get()); + oprot_->writeMessageBegin("start_event", ::apache::thrift::protocol::T_ONEWAY, cseqid); + + IdaClient_start_event_pargs args; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); + + sentry.commit(); +} + +void IdaClientConcurrentClient::add_visited(const std::set & changed, const bool is_step) +{ + send_add_visited(changed, is_step); +} + +void IdaClientConcurrentClient::send_add_visited(const std::set & changed, const bool is_step) +{ + int32_t cseqid = 0; + ::apache::thrift::async::TConcurrentSendSentry sentry(this->sync_.get()); + oprot_->writeMessageBegin("add_visited", ::apache::thrift::protocol::T_ONEWAY, cseqid); + + IdaClient_add_visited_pargs args; + args.changed = &changed; + args.is_step = &is_step; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); + + sentry.commit(); +} + +void IdaClientConcurrentClient::pause_event(const int32_t address) +{ + send_pause_event(address); +} + +void IdaClientConcurrentClient::send_pause_event(const int32_t address) +{ + int32_t cseqid = 0; + ::apache::thrift::async::TConcurrentSendSentry sentry(this->sync_.get()); + oprot_->writeMessageBegin("pause_event", ::apache::thrift::protocol::T_ONEWAY, cseqid); + + IdaClient_pause_event_pargs args; + args.address = &address; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); + + sentry.commit(); +} + +void IdaClientConcurrentClient::stop_event() +{ + send_stop_event(); +} + +void IdaClientConcurrentClient::send_stop_event() +{ + int32_t cseqid = 0; + ::apache::thrift::async::TConcurrentSendSentry sentry(this->sync_.get()); + oprot_->writeMessageBegin("stop_event", ::apache::thrift::protocol::T_ONEWAY, cseqid); + + IdaClient_stop_event_pargs args; + args.write(oprot_); + + oprot_->writeMessageEnd(); + oprot_->getTransport()->writeEnd(); + oprot_->getTransport()->flush(); + + sentry.commit(); +} + + + diff --git a/bsnes/gen-cpp/IdaClient.h b/bsnes/gen-cpp/IdaClient.h new file mode 100644 index 00000000..f0ebfa13 --- /dev/null +++ b/bsnes/gen-cpp/IdaClient.h @@ -0,0 +1,428 @@ +/** + * Autogenerated by Thrift Compiler (0.14.0) + * + * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + * @generated + */ +#ifndef IdaClient_H +#define IdaClient_H + +#include +#include +#include +#include "debug_proto_types.h" + + + +#ifdef _MSC_VER + #pragma warning( push ) + #pragma warning (disable : 4250 ) //inheriting methods via dominance +#endif + +class IdaClientIf { + public: + virtual ~IdaClientIf() {} + virtual void start_event() = 0; + virtual void add_visited(const std::set & changed, const bool is_step) = 0; + virtual void pause_event(const int32_t address) = 0; + virtual void stop_event() = 0; +}; + +class IdaClientIfFactory { + public: + typedef IdaClientIf Handler; + + virtual ~IdaClientIfFactory() {} + + virtual IdaClientIf* getHandler(const ::apache::thrift::TConnectionInfo& connInfo) = 0; + virtual void releaseHandler(IdaClientIf* /* handler */) = 0; +}; + +class IdaClientIfSingletonFactory : virtual public IdaClientIfFactory { + public: + IdaClientIfSingletonFactory(const ::std::shared_ptr& iface) : iface_(iface) {} + virtual ~IdaClientIfSingletonFactory() {} + + virtual IdaClientIf* getHandler(const ::apache::thrift::TConnectionInfo&) { + return iface_.get(); + } + virtual void releaseHandler(IdaClientIf* /* handler */) {} + + protected: + ::std::shared_ptr iface_; +}; + +class IdaClientNull : virtual public IdaClientIf { + public: + virtual ~IdaClientNull() {} + void start_event() { + return; + } + void add_visited(const std::set & /* changed */, const bool /* is_step */) { + return; + } + void pause_event(const int32_t /* address */) { + return; + } + void stop_event() { + return; + } +}; + + +class IdaClient_start_event_args { + public: + + IdaClient_start_event_args(const IdaClient_start_event_args&); + IdaClient_start_event_args& operator=(const IdaClient_start_event_args&); + IdaClient_start_event_args() { + } + + virtual ~IdaClient_start_event_args() noexcept; + + bool operator == (const IdaClient_start_event_args & /* rhs */) const + { + return true; + } + bool operator != (const IdaClient_start_event_args &rhs) const { + return !(*this == rhs); + } + + bool operator < (const IdaClient_start_event_args & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class IdaClient_start_event_pargs { + public: + + + virtual ~IdaClient_start_event_pargs() noexcept; + + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + +typedef struct _IdaClient_add_visited_args__isset { + _IdaClient_add_visited_args__isset() : changed(false), is_step(false) {} + bool changed :1; + bool is_step :1; +} _IdaClient_add_visited_args__isset; + +class IdaClient_add_visited_args { + public: + + IdaClient_add_visited_args(const IdaClient_add_visited_args&); + IdaClient_add_visited_args& operator=(const IdaClient_add_visited_args&); + IdaClient_add_visited_args() : is_step(0) { + } + + virtual ~IdaClient_add_visited_args() noexcept; + std::set changed; + bool is_step; + + _IdaClient_add_visited_args__isset __isset; + + void __set_changed(const std::set & val); + + void __set_is_step(const bool val); + + bool operator == (const IdaClient_add_visited_args & rhs) const + { + if (!(changed == rhs.changed)) + return false; + if (!(is_step == rhs.is_step)) + return false; + return true; + } + bool operator != (const IdaClient_add_visited_args &rhs) const { + return !(*this == rhs); + } + + bool operator < (const IdaClient_add_visited_args & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class IdaClient_add_visited_pargs { + public: + + + virtual ~IdaClient_add_visited_pargs() noexcept; + const std::set * changed; + const bool* is_step; + + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + +typedef struct _IdaClient_pause_event_args__isset { + _IdaClient_pause_event_args__isset() : address(false) {} + bool address :1; +} _IdaClient_pause_event_args__isset; + +class IdaClient_pause_event_args { + public: + + IdaClient_pause_event_args(const IdaClient_pause_event_args&); + IdaClient_pause_event_args& operator=(const IdaClient_pause_event_args&); + IdaClient_pause_event_args() : address(0) { + } + + virtual ~IdaClient_pause_event_args() noexcept; + int32_t address; + + _IdaClient_pause_event_args__isset __isset; + + void __set_address(const int32_t val); + + bool operator == (const IdaClient_pause_event_args & rhs) const + { + if (!(address == rhs.address)) + return false; + return true; + } + bool operator != (const IdaClient_pause_event_args &rhs) const { + return !(*this == rhs); + } + + bool operator < (const IdaClient_pause_event_args & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class IdaClient_pause_event_pargs { + public: + + + virtual ~IdaClient_pause_event_pargs() noexcept; + const int32_t* address; + + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class IdaClient_stop_event_args { + public: + + IdaClient_stop_event_args(const IdaClient_stop_event_args&); + IdaClient_stop_event_args& operator=(const IdaClient_stop_event_args&); + IdaClient_stop_event_args() { + } + + virtual ~IdaClient_stop_event_args() noexcept; + + bool operator == (const IdaClient_stop_event_args & /* rhs */) const + { + return true; + } + bool operator != (const IdaClient_stop_event_args &rhs) const { + return !(*this == rhs); + } + + bool operator < (const IdaClient_stop_event_args & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + + +class IdaClient_stop_event_pargs { + public: + + + virtual ~IdaClient_stop_event_pargs() noexcept; + + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + +}; + +class IdaClientClient : virtual public IdaClientIf { + public: + IdaClientClient(std::shared_ptr< ::apache::thrift::protocol::TProtocol> prot) { + setProtocol(prot); + } + IdaClientClient(std::shared_ptr< ::apache::thrift::protocol::TProtocol> iprot, std::shared_ptr< ::apache::thrift::protocol::TProtocol> oprot) { + setProtocol(iprot,oprot); + } + private: + void setProtocol(std::shared_ptr< ::apache::thrift::protocol::TProtocol> prot) { + setProtocol(prot,prot); + } + void setProtocol(std::shared_ptr< ::apache::thrift::protocol::TProtocol> iprot, std::shared_ptr< ::apache::thrift::protocol::TProtocol> oprot) { + piprot_=iprot; + poprot_=oprot; + iprot_ = iprot.get(); + oprot_ = oprot.get(); + } + public: + std::shared_ptr< ::apache::thrift::protocol::TProtocol> getInputProtocol() { + return piprot_; + } + std::shared_ptr< ::apache::thrift::protocol::TProtocol> getOutputProtocol() { + return poprot_; + } + void start_event(); + void send_start_event(); + void add_visited(const std::set & changed, const bool is_step); + void send_add_visited(const std::set & changed, const bool is_step); + void pause_event(const int32_t address); + void send_pause_event(const int32_t address); + void stop_event(); + void send_stop_event(); + protected: + std::shared_ptr< ::apache::thrift::protocol::TProtocol> piprot_; + std::shared_ptr< ::apache::thrift::protocol::TProtocol> poprot_; + ::apache::thrift::protocol::TProtocol* iprot_; + ::apache::thrift::protocol::TProtocol* oprot_; +}; + +class IdaClientProcessor : public ::apache::thrift::TDispatchProcessor { + protected: + ::std::shared_ptr iface_; + virtual bool dispatchCall(::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, const std::string& fname, int32_t seqid, void* callContext); + private: + typedef void (IdaClientProcessor::*ProcessFunction)(int32_t, ::apache::thrift::protocol::TProtocol*, ::apache::thrift::protocol::TProtocol*, void*); + typedef std::map ProcessMap; + ProcessMap processMap_; + void process_start_event(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext); + void process_add_visited(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext); + void process_pause_event(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext); + void process_stop_event(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot, void* callContext); + public: + IdaClientProcessor(::std::shared_ptr iface) : + iface_(iface) { + processMap_["start_event"] = &IdaClientProcessor::process_start_event; + processMap_["add_visited"] = &IdaClientProcessor::process_add_visited; + processMap_["pause_event"] = &IdaClientProcessor::process_pause_event; + processMap_["stop_event"] = &IdaClientProcessor::process_stop_event; + } + + virtual ~IdaClientProcessor() {} +}; + +class IdaClientProcessorFactory : public ::apache::thrift::TProcessorFactory { + public: + IdaClientProcessorFactory(const ::std::shared_ptr< IdaClientIfFactory >& handlerFactory) : + handlerFactory_(handlerFactory) {} + + ::std::shared_ptr< ::apache::thrift::TProcessor > getProcessor(const ::apache::thrift::TConnectionInfo& connInfo); + + protected: + ::std::shared_ptr< IdaClientIfFactory > handlerFactory_; +}; + +class IdaClientMultiface : virtual public IdaClientIf { + public: + IdaClientMultiface(std::vector >& ifaces) : ifaces_(ifaces) { + } + virtual ~IdaClientMultiface() {} + protected: + std::vector > ifaces_; + IdaClientMultiface() {} + void add(::std::shared_ptr iface) { + ifaces_.push_back(iface); + } + public: + void start_event() { + size_t sz = ifaces_.size(); + size_t i = 0; + for (; i < (sz - 1); ++i) { + ifaces_[i]->start_event(); + } + ifaces_[i]->start_event(); + } + + void add_visited(const std::set & changed, const bool is_step) { + size_t sz = ifaces_.size(); + size_t i = 0; + for (; i < (sz - 1); ++i) { + ifaces_[i]->add_visited(changed, is_step); + } + ifaces_[i]->add_visited(changed, is_step); + } + + void pause_event(const int32_t address) { + size_t sz = ifaces_.size(); + size_t i = 0; + for (; i < (sz - 1); ++i) { + ifaces_[i]->pause_event(address); + } + ifaces_[i]->pause_event(address); + } + + void stop_event() { + size_t sz = ifaces_.size(); + size_t i = 0; + for (; i < (sz - 1); ++i) { + ifaces_[i]->stop_event(); + } + ifaces_[i]->stop_event(); + } + +}; + +// The 'concurrent' client is a thread safe client that correctly handles +// out of order responses. It is slower than the regular client, so should +// only be used when you need to share a connection among multiple threads +class IdaClientConcurrentClient : virtual public IdaClientIf { + public: + IdaClientConcurrentClient(std::shared_ptr< ::apache::thrift::protocol::TProtocol> prot, std::shared_ptr<::apache::thrift::async::TConcurrentClientSyncInfo> sync) : sync_(sync) +{ + setProtocol(prot); + } + IdaClientConcurrentClient(std::shared_ptr< ::apache::thrift::protocol::TProtocol> iprot, std::shared_ptr< ::apache::thrift::protocol::TProtocol> oprot, std::shared_ptr<::apache::thrift::async::TConcurrentClientSyncInfo> sync) : sync_(sync) +{ + setProtocol(iprot,oprot); + } + private: + void setProtocol(std::shared_ptr< ::apache::thrift::protocol::TProtocol> prot) { + setProtocol(prot,prot); + } + void setProtocol(std::shared_ptr< ::apache::thrift::protocol::TProtocol> iprot, std::shared_ptr< ::apache::thrift::protocol::TProtocol> oprot) { + piprot_=iprot; + poprot_=oprot; + iprot_ = iprot.get(); + oprot_ = oprot.get(); + } + public: + std::shared_ptr< ::apache::thrift::protocol::TProtocol> getInputProtocol() { + return piprot_; + } + std::shared_ptr< ::apache::thrift::protocol::TProtocol> getOutputProtocol() { + return poprot_; + } + void start_event(); + void send_start_event(); + void add_visited(const std::set & changed, const bool is_step); + void send_add_visited(const std::set & changed, const bool is_step); + void pause_event(const int32_t address); + void send_pause_event(const int32_t address); + void stop_event(); + void send_stop_event(); + protected: + std::shared_ptr< ::apache::thrift::protocol::TProtocol> piprot_; + std::shared_ptr< ::apache::thrift::protocol::TProtocol> poprot_; + ::apache::thrift::protocol::TProtocol* iprot_; + ::apache::thrift::protocol::TProtocol* oprot_; + std::shared_ptr<::apache::thrift::async::TConcurrentClientSyncInfo> sync_; +}; + +#ifdef _MSC_VER + #pragma warning( pop ) +#endif + + + +#endif diff --git a/bsnes/gen-cpp/debug_proto_types.cpp b/bsnes/gen-cpp/debug_proto_types.cpp new file mode 100644 index 00000000..9f2c9650 --- /dev/null +++ b/bsnes/gen-cpp/debug_proto_types.cpp @@ -0,0 +1,658 @@ +/** + * Autogenerated by Thrift Compiler (0.14.0) + * + * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + * @generated + */ +#include "debug_proto_types.h" + +#include +#include + +#include + + + +int _kBsnesRegisterValues[] = { + BsnesRegister::pc, + BsnesRegister::a, + BsnesRegister::x, + BsnesRegister::y, + BsnesRegister::s, + BsnesRegister::d, + BsnesRegister::db, + BsnesRegister::p, + BsnesRegister::mflag, + BsnesRegister::xflag, + BsnesRegister::eflag +}; +const char* _kBsnesRegisterNames[] = { + "pc", + "a", + "x", + "y", + "s", + "d", + "db", + "p", + "mflag", + "xflag", + "eflag" +}; +const std::map _BsnesRegister_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(11, _kBsnesRegisterValues, _kBsnesRegisterNames), ::apache::thrift::TEnumIterator(-1, nullptr, nullptr)); + +std::ostream& operator<<(std::ostream& out, const BsnesRegister::type& val) { + std::map::const_iterator it = _BsnesRegister_VALUES_TO_NAMES.find(val); + if (it != _BsnesRegister_VALUES_TO_NAMES.end()) { + out << it->second; + } else { + out << static_cast(val); + } + return out; +} + +std::string to_string(const BsnesRegister::type& val) { + std::map::const_iterator it = _BsnesRegister_VALUES_TO_NAMES.find(val); + if (it != _BsnesRegister_VALUES_TO_NAMES.end()) { + return std::string(it->second); + } else { + return std::to_string(static_cast(val)); + } +} + +int _kBpTypeValues[] = { + BpType::BP_PC, + BpType::BP_READ, + BpType::BP_WRITE +}; +const char* _kBpTypeNames[] = { + "BP_PC", + "BP_READ", + "BP_WRITE" +}; +const std::map _BpType_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(3, _kBpTypeValues, _kBpTypeNames), ::apache::thrift::TEnumIterator(-1, nullptr, nullptr)); + +std::ostream& operator<<(std::ostream& out, const BpType::type& val) { + std::map::const_iterator it = _BpType_VALUES_TO_NAMES.find(val); + if (it != _BpType_VALUES_TO_NAMES.end()) { + out << it->second; + } else { + out << static_cast(val); + } + return out; +} + +std::string to_string(const BpType::type& val) { + std::map::const_iterator it = _BpType_VALUES_TO_NAMES.find(val); + if (it != _BpType_VALUES_TO_NAMES.end()) { + return std::string(it->second); + } else { + return std::to_string(static_cast(val)); + } +} + +int _kDbgMemorySourceValues[] = { + DbgMemorySource::CPUBus, + DbgMemorySource::APUBus, + DbgMemorySource::APURAM, + DbgMemorySource::DSP, + DbgMemorySource::VRAM, + DbgMemorySource::OAM, + DbgMemorySource::CGRAM, + DbgMemorySource::CartROM, + DbgMemorySource::CartRAM, + DbgMemorySource::SA1Bus, + DbgMemorySource::SFXBus, + DbgMemorySource::SGBBus, + DbgMemorySource::SGBROM, + DbgMemorySource::SGBRAM +}; +const char* _kDbgMemorySourceNames[] = { + "CPUBus", + "APUBus", + "APURAM", + "DSP", + "VRAM", + "OAM", + "CGRAM", + "CartROM", + "CartRAM", + "SA1Bus", + "SFXBus", + "SGBBus", + "SGBROM", + "SGBRAM" +}; +const std::map _DbgMemorySource_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(14, _kDbgMemorySourceValues, _kDbgMemorySourceNames), ::apache::thrift::TEnumIterator(-1, nullptr, nullptr)); + +std::ostream& operator<<(std::ostream& out, const DbgMemorySource::type& val) { + std::map::const_iterator it = _DbgMemorySource_VALUES_TO_NAMES.find(val); + if (it != _DbgMemorySource_VALUES_TO_NAMES.end()) { + out << it->second; + } else { + out << static_cast(val); + } + return out; +} + +std::string to_string(const DbgMemorySource::type& val) { + std::map::const_iterator it = _DbgMemorySource_VALUES_TO_NAMES.find(val); + if (it != _DbgMemorySource_VALUES_TO_NAMES.end()) { + return std::string(it->second); + } else { + return std::to_string(static_cast(val)); + } +} + +int _kDbgBptSourceValues[] = { + DbgBptSource::CPUBus, + DbgBptSource::APURAM, + DbgBptSource::DSP, + DbgBptSource::VRAM, + DbgBptSource::OAM, + DbgBptSource::CGRAM, + DbgBptSource::SA1Bus, + DbgBptSource::SFXBus, + DbgBptSource::SGBBus +}; +const char* _kDbgBptSourceNames[] = { + "CPUBus", + "APURAM", + "DSP", + "VRAM", + "OAM", + "CGRAM", + "SA1Bus", + "SFXBus", + "SGBBus" +}; +const std::map _DbgBptSource_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(9, _kDbgBptSourceValues, _kDbgBptSourceNames), ::apache::thrift::TEnumIterator(-1, nullptr, nullptr)); + +std::ostream& operator<<(std::ostream& out, const DbgBptSource::type& val) { + std::map::const_iterator it = _DbgBptSource_VALUES_TO_NAMES.find(val); + if (it != _DbgBptSource_VALUES_TO_NAMES.end()) { + out << it->second; + } else { + out << static_cast(val); + } + return out; +} + +std::string to_string(const DbgBptSource::type& val) { + std::map::const_iterator it = _DbgBptSource_VALUES_TO_NAMES.find(val); + if (it != _DbgBptSource_VALUES_TO_NAMES.end()) { + return std::string(it->second); + } else { + return std::to_string(static_cast(val)); + } +} + + +BsnesRegisters::~BsnesRegisters() noexcept { +} + + +void BsnesRegisters::__set_pc(const int32_t val) { + this->pc = val; +} + +void BsnesRegisters::__set_a(const int32_t val) { + this->a = val; +} + +void BsnesRegisters::__set_x(const int32_t val) { + this->x = val; +} + +void BsnesRegisters::__set_y(const int32_t val) { + this->y = val; +} + +void BsnesRegisters::__set_s(const int32_t val) { + this->s = val; +} + +void BsnesRegisters::__set_d(const int32_t val) { + this->d = val; +} + +void BsnesRegisters::__set_db(const int16_t val) { + this->db = val; +} + +void BsnesRegisters::__set_p(const int16_t val) { + this->p = val; +} + +void BsnesRegisters::__set_mflag(const int8_t val) { + this->mflag = val; +} + +void BsnesRegisters::__set_xflag(const int8_t val) { + this->xflag = val; +} + +void BsnesRegisters::__set_eflag(const int8_t val) { + this->eflag = val; +} +std::ostream& operator<<(std::ostream& out, const BsnesRegisters& obj) +{ + obj.printTo(out); + return out; +} + + +uint32_t BsnesRegisters::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 1: + if (ftype == ::apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->pc); + this->__isset.pc = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 2: + if (ftype == ::apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->a); + this->__isset.a = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 3: + if (ftype == ::apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->x); + this->__isset.x = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 4: + if (ftype == ::apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->y); + this->__isset.y = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 5: + if (ftype == ::apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->s); + this->__isset.s = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 6: + if (ftype == ::apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->d); + this->__isset.d = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 7: + if (ftype == ::apache::thrift::protocol::T_I16) { + xfer += iprot->readI16(this->db); + this->__isset.db = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 8: + if (ftype == ::apache::thrift::protocol::T_I16) { + xfer += iprot->readI16(this->p); + this->__isset.p = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 9: + if (ftype == ::apache::thrift::protocol::T_BYTE) { + xfer += iprot->readByte(this->mflag); + this->__isset.mflag = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 10: + if (ftype == ::apache::thrift::protocol::T_BYTE) { + xfer += iprot->readByte(this->xflag); + this->__isset.xflag = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 11: + if (ftype == ::apache::thrift::protocol::T_BYTE) { + xfer += iprot->readByte(this->eflag); + this->__isset.eflag = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t BsnesRegisters::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("BsnesRegisters"); + + xfer += oprot->writeFieldBegin("pc", ::apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32(this->pc); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("a", ::apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeI32(this->a); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("x", ::apache::thrift::protocol::T_I32, 3); + xfer += oprot->writeI32(this->x); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("y", ::apache::thrift::protocol::T_I32, 4); + xfer += oprot->writeI32(this->y); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("s", ::apache::thrift::protocol::T_I32, 5); + xfer += oprot->writeI32(this->s); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("d", ::apache::thrift::protocol::T_I32, 6); + xfer += oprot->writeI32(this->d); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("db", ::apache::thrift::protocol::T_I16, 7); + xfer += oprot->writeI16(this->db); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("p", ::apache::thrift::protocol::T_I16, 8); + xfer += oprot->writeI16(this->p); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("mflag", ::apache::thrift::protocol::T_BYTE, 9); + xfer += oprot->writeByte(this->mflag); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("xflag", ::apache::thrift::protocol::T_BYTE, 10); + xfer += oprot->writeByte(this->xflag); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("eflag", ::apache::thrift::protocol::T_BYTE, 11); + xfer += oprot->writeByte(this->eflag); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + +void swap(BsnesRegisters &a, BsnesRegisters &b) { + using ::std::swap; + swap(a.pc, b.pc); + swap(a.a, b.a); + swap(a.x, b.x); + swap(a.y, b.y); + swap(a.s, b.s); + swap(a.d, b.d); + swap(a.db, b.db); + swap(a.p, b.p); + swap(a.mflag, b.mflag); + swap(a.xflag, b.xflag); + swap(a.eflag, b.eflag); + swap(a.__isset, b.__isset); +} + +BsnesRegisters::BsnesRegisters(const BsnesRegisters& other0) { + pc = other0.pc; + a = other0.a; + x = other0.x; + y = other0.y; + s = other0.s; + d = other0.d; + db = other0.db; + p = other0.p; + mflag = other0.mflag; + xflag = other0.xflag; + eflag = other0.eflag; + __isset = other0.__isset; +} +BsnesRegisters& BsnesRegisters::operator=(const BsnesRegisters& other1) { + pc = other1.pc; + a = other1.a; + x = other1.x; + y = other1.y; + s = other1.s; + d = other1.d; + db = other1.db; + p = other1.p; + mflag = other1.mflag; + xflag = other1.xflag; + eflag = other1.eflag; + __isset = other1.__isset; + return *this; +} +void BsnesRegisters::printTo(std::ostream& out) const { + using ::apache::thrift::to_string; + out << "BsnesRegisters("; + out << "pc=" << to_string(pc); + out << ", " << "a=" << to_string(a); + out << ", " << "x=" << to_string(x); + out << ", " << "y=" << to_string(y); + out << ", " << "s=" << to_string(s); + out << ", " << "d=" << to_string(d); + out << ", " << "db=" << to_string(db); + out << ", " << "p=" << to_string(p); + out << ", " << "mflag=" << to_string(mflag); + out << ", " << "xflag=" << to_string(xflag); + out << ", " << "eflag=" << to_string(eflag); + out << ")"; +} + + +DbgBreakpoint::~DbgBreakpoint() noexcept { +} + + +void DbgBreakpoint::__set_type(const BpType::type val) { + this->type = val; +} + +void DbgBreakpoint::__set_bstart(const int32_t val) { + this->bstart = val; +} + +void DbgBreakpoint::__set_bend(const int32_t val) { + this->bend = val; +} + +void DbgBreakpoint::__set_enabled(const bool val) { + this->enabled = val; +} + +void DbgBreakpoint::__set_src(const DbgBptSource::type val) { + this->src = val; +} +std::ostream& operator<<(std::ostream& out, const DbgBreakpoint& obj) +{ + obj.printTo(out); + return out; +} + + +uint32_t DbgBreakpoint::read(::apache::thrift::protocol::TProtocol* iprot) { + + ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + uint32_t xfer = 0; + std::string fname; + ::apache::thrift::protocol::TType ftype; + int16_t fid; + + xfer += iprot->readStructBegin(fname); + + using ::apache::thrift::protocol::TProtocolException; + + + while (true) + { + xfer += iprot->readFieldBegin(fname, ftype, fid); + if (ftype == ::apache::thrift::protocol::T_STOP) { + break; + } + switch (fid) + { + case 1: + if (ftype == ::apache::thrift::protocol::T_I32) { + int32_t ecast2; + xfer += iprot->readI32(ecast2); + this->type = (BpType::type)ecast2; + this->__isset.type = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 2: + if (ftype == ::apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->bstart); + this->__isset.bstart = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 3: + if (ftype == ::apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->bend); + this->__isset.bend = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 4: + if (ftype == ::apache::thrift::protocol::T_BOOL) { + xfer += iprot->readBool(this->enabled); + this->__isset.enabled = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 5: + if (ftype == ::apache::thrift::protocol::T_I32) { + int32_t ecast3; + xfer += iprot->readI32(ecast3); + this->src = (DbgBptSource::type)ecast3; + this->__isset.src = true; + } else { + xfer += iprot->skip(ftype); + } + break; + default: + xfer += iprot->skip(ftype); + break; + } + xfer += iprot->readFieldEnd(); + } + + xfer += iprot->readStructEnd(); + + return xfer; +} + +uint32_t DbgBreakpoint::write(::apache::thrift::protocol::TProtocol* oprot) const { + uint32_t xfer = 0; + ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("DbgBreakpoint"); + + xfer += oprot->writeFieldBegin("type", ::apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32((int32_t)this->type); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("bstart", ::apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeI32(this->bstart); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("bend", ::apache::thrift::protocol::T_I32, 3); + xfer += oprot->writeI32(this->bend); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("enabled", ::apache::thrift::protocol::T_BOOL, 4); + xfer += oprot->writeBool(this->enabled); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("src", ::apache::thrift::protocol::T_I32, 5); + xfer += oprot->writeI32((int32_t)this->src); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldStop(); + xfer += oprot->writeStructEnd(); + return xfer; +} + +void swap(DbgBreakpoint &a, DbgBreakpoint &b) { + using ::std::swap; + swap(a.type, b.type); + swap(a.bstart, b.bstart); + swap(a.bend, b.bend); + swap(a.enabled, b.enabled); + swap(a.src, b.src); + swap(a.__isset, b.__isset); +} + +DbgBreakpoint::DbgBreakpoint(const DbgBreakpoint& other4) { + type = other4.type; + bstart = other4.bstart; + bend = other4.bend; + enabled = other4.enabled; + src = other4.src; + __isset = other4.__isset; +} +DbgBreakpoint& DbgBreakpoint::operator=(const DbgBreakpoint& other5) { + type = other5.type; + bstart = other5.bstart; + bend = other5.bend; + enabled = other5.enabled; + src = other5.src; + __isset = other5.__isset; + return *this; +} +void DbgBreakpoint::printTo(std::ostream& out) const { + using ::apache::thrift::to_string; + out << "DbgBreakpoint("; + out << "type=" << to_string(type); + out << ", " << "bstart=" << to_string(bstart); + out << ", " << "bend=" << to_string(bend); + out << ", " << "enabled=" << to_string(enabled); + out << ", " << "src=" << to_string(src); + out << ")"; +} + + diff --git a/bsnes/gen-cpp/debug_proto_types.h b/bsnes/gen-cpp/debug_proto_types.h new file mode 100644 index 00000000..7a1630de --- /dev/null +++ b/bsnes/gen-cpp/debug_proto_types.h @@ -0,0 +1,287 @@ +/** + * Autogenerated by Thrift Compiler (0.14.0) + * + * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + * @generated + */ +#ifndef debug_proto_TYPES_H +#define debug_proto_TYPES_H + +#include + +#include +#include +#include +#include +#include + +#include +#include + + + + +struct BsnesRegister { + enum type { + pc = 0, + a = 1, + x = 2, + y = 3, + s = 4, + d = 5, + db = 6, + p = 7, + mflag = 8, + xflag = 9, + eflag = 10 + }; +}; + +extern const std::map _BsnesRegister_VALUES_TO_NAMES; + +std::ostream& operator<<(std::ostream& out, const BsnesRegister::type& val); + +std::string to_string(const BsnesRegister::type& val); + +struct BpType { + enum type { + BP_PC = 1, + BP_READ = 2, + BP_WRITE = 4 + }; +}; + +extern const std::map _BpType_VALUES_TO_NAMES; + +std::ostream& operator<<(std::ostream& out, const BpType::type& val); + +std::string to_string(const BpType::type& val); + +struct DbgMemorySource { + enum type { + CPUBus = 0, + APUBus = 1, + APURAM = 2, + DSP = 3, + VRAM = 4, + OAM = 5, + CGRAM = 6, + CartROM = 7, + CartRAM = 8, + SA1Bus = 9, + SFXBus = 10, + SGBBus = 11, + SGBROM = 12, + SGBRAM = 13 + }; +}; + +extern const std::map _DbgMemorySource_VALUES_TO_NAMES; + +std::ostream& operator<<(std::ostream& out, const DbgMemorySource::type& val); + +std::string to_string(const DbgMemorySource::type& val); + +struct DbgBptSource { + enum type { + CPUBus = 0, + APURAM = 1, + DSP = 2, + VRAM = 3, + OAM = 4, + CGRAM = 5, + SA1Bus = 6, + SFXBus = 7, + SGBBus = 8 + }; +}; + +extern const std::map _DbgBptSource_VALUES_TO_NAMES; + +std::ostream& operator<<(std::ostream& out, const DbgBptSource::type& val); + +std::string to_string(const DbgBptSource::type& val); + +class BsnesRegisters; + +class DbgBreakpoint; + +typedef struct _BsnesRegisters__isset { + _BsnesRegisters__isset() : pc(false), a(false), x(false), y(false), s(false), d(false), db(false), p(false), mflag(false), xflag(false), eflag(false) {} + bool pc :1; + bool a :1; + bool x :1; + bool y :1; + bool s :1; + bool d :1; + bool db :1; + bool p :1; + bool mflag :1; + bool xflag :1; + bool eflag :1; +} _BsnesRegisters__isset; + +class BsnesRegisters : public virtual ::apache::thrift::TBase { + public: + + BsnesRegisters(const BsnesRegisters&); + BsnesRegisters& operator=(const BsnesRegisters&); + BsnesRegisters() : pc(0), a(0), x(0), y(0), s(0), d(0), db(0), p(0), mflag(0), xflag(0), eflag(0) { + } + + virtual ~BsnesRegisters() noexcept; + int32_t pc; + int32_t a; + int32_t x; + int32_t y; + int32_t s; + int32_t d; + int16_t db; + int16_t p; + int8_t mflag; + int8_t xflag; + int8_t eflag; + + _BsnesRegisters__isset __isset; + + void __set_pc(const int32_t val); + + void __set_a(const int32_t val); + + void __set_x(const int32_t val); + + void __set_y(const int32_t val); + + void __set_s(const int32_t val); + + void __set_d(const int32_t val); + + void __set_db(const int16_t val); + + void __set_p(const int16_t val); + + void __set_mflag(const int8_t val); + + void __set_xflag(const int8_t val); + + void __set_eflag(const int8_t val); + + bool operator == (const BsnesRegisters & rhs) const + { + if (!(pc == rhs.pc)) + return false; + if (!(a == rhs.a)) + return false; + if (!(x == rhs.x)) + return false; + if (!(y == rhs.y)) + return false; + if (!(s == rhs.s)) + return false; + if (!(d == rhs.d)) + return false; + if (!(db == rhs.db)) + return false; + if (!(p == rhs.p)) + return false; + if (!(mflag == rhs.mflag)) + return false; + if (!(xflag == rhs.xflag)) + return false; + if (!(eflag == rhs.eflag)) + return false; + return true; + } + bool operator != (const BsnesRegisters &rhs) const { + return !(*this == rhs); + } + + bool operator < (const BsnesRegisters & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + + virtual void printTo(std::ostream& out) const; +}; + +void swap(BsnesRegisters &a, BsnesRegisters &b); + +std::ostream& operator<<(std::ostream& out, const BsnesRegisters& obj); + +typedef struct _DbgBreakpoint__isset { + _DbgBreakpoint__isset() : type(false), bstart(false), bend(false), enabled(false), src(false) {} + bool type :1; + bool bstart :1; + bool bend :1; + bool enabled :1; + bool src :1; +} _DbgBreakpoint__isset; + +class DbgBreakpoint : public virtual ::apache::thrift::TBase { + public: + + DbgBreakpoint(const DbgBreakpoint&); + DbgBreakpoint& operator=(const DbgBreakpoint&); + DbgBreakpoint() : type((BpType::type)0), bstart(0), bend(0), enabled(0), src((DbgBptSource::type)0) { + } + + virtual ~DbgBreakpoint() noexcept; + /** + * + * @see BpType + */ + BpType::type type; + int32_t bstart; + int32_t bend; + bool enabled; + /** + * + * @see DbgBptSource + */ + DbgBptSource::type src; + + _DbgBreakpoint__isset __isset; + + void __set_type(const BpType::type val); + + void __set_bstart(const int32_t val); + + void __set_bend(const int32_t val); + + void __set_enabled(const bool val); + + void __set_src(const DbgBptSource::type val); + + bool operator == (const DbgBreakpoint & rhs) const + { + if (!(type == rhs.type)) + return false; + if (!(bstart == rhs.bstart)) + return false; + if (!(bend == rhs.bend)) + return false; + if (!(enabled == rhs.enabled)) + return false; + if (!(src == rhs.src)) + return false; + return true; + } + bool operator != (const DbgBreakpoint &rhs) const { + return !(*this == rhs); + } + + bool operator < (const DbgBreakpoint & ) const; + + uint32_t read(::apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const; + + virtual void printTo(std::ostream& out) const; +}; + +void swap(DbgBreakpoint &a, DbgBreakpoint &b); + +std::ostream& operator<<(std::ostream& out, const DbgBreakpoint& obj); + + + +#endif diff --git a/bsnes/ruby/video/direct3d.cpp b/bsnes/ruby/video/direct3d.cpp index 353b0e17..588a36f3 100644 --- a/bsnes/ruby/video/direct3d.cpp +++ b/bsnes/ruby/video/direct3d.cpp @@ -1,8 +1,5 @@ -#undef interface -#define interface struct #include #include -#undef interface #define D3DVERTEX (D3DFVF_XYZRHW | D3DFVF_TEX1) diff --git a/bsnes/snes/alt/cpu/cpu.cpp b/bsnes/snes/alt/cpu/cpu.cpp index 0bc39043..85f1861c 100644 --- a/bsnes/snes/alt/cpu/cpu.cpp +++ b/bsnes/snes/alt/cpu/cpu.cpp @@ -1,4 +1,5 @@ #include +#include #define CPU_CPP #define ALT_CPU_CPP diff --git a/bsnes/snes/audio/audio.cpp b/bsnes/snes/audio/audio.cpp index dc6d504e..1657fc8a 100644 --- a/bsnes/snes/audio/audio.cpp +++ b/bsnes/snes/audio/audio.cpp @@ -80,7 +80,7 @@ void Audio::add_stream(Stream* stream) { void Audio::sample(int16 left, int16 right) { if(!streams.size()) { - system.interface->audio_sample(left, right); + system.intf->audio_sample(left, right); } else { dsp_buffer[dsp_wroffset] = ((uint16)left << 0) + ((uint16)right << 16); dsp_wroffset = (dsp_wroffset + 1) & 32767; @@ -108,7 +108,7 @@ void Audio::flush() { right += (int16)(sample >> 16); } - system.interface->audio_sample( + system.intf->audio_sample( sclamp<16>(left / 2), sclamp<16>(right / 2) ); diff --git a/bsnes/snes/cartridge/xml.cpp b/bsnes/snes/cartridge/xml.cpp index 5dd475d2..3a0a602a 100644 --- a/bsnes/snes/cartridge/xml.cpp +++ b/bsnes/snes/cartridge/xml.cpp @@ -235,7 +235,7 @@ void Cartridge::xml_parse_necdsp(xml_element &root) { for(unsigned n = 0; n < dromsize; n++) necdsp.dataROM[n] = fp.readm(2); fp.seek(0); - uint8_t data[filesize]; + uint8_t *data = new uint8_t[filesize]; fp.read(data, filesize); sha256_ctx sha; @@ -245,6 +245,8 @@ void Cartridge::xml_parse_necdsp(xml_element &root) { sha256_final(&sha); sha256_hash(&sha, shahash); foreach(n, shahash) programhash.append(hex<2>(n)); + + delete[] data; } fp.close(); } @@ -281,9 +283,9 @@ void Cartridge::xml_parse_necdsp(xml_element &root) { } if(programhash == "") { - system.interface->message({ "Warning: NEC DSP program ", program, " is missing." }); + system.intf->message({ "Warning: NEC DSP program ", program, " is missing." }); } else if(sha256 != "" && sha256 != programhash) { - system.interface->message({ + system.intf->message({ "Warning: NEC DSP program ", program, " SHA256 is incorrect.\n\n" "Expected:\n", sha256, "\n\n" "Actual:\n", programhash diff --git a/bsnes/snes/cpu/cpu.cpp b/bsnes/snes/cpu/cpu.cpp index 68fb79c2..ee5d7d13 100644 --- a/bsnes/snes/cpu/cpu.cpp +++ b/bsnes/snes/cpu/cpu.cpp @@ -1,4 +1,5 @@ #include +#include #define CPU_CPP namespace SNES { diff --git a/bsnes/snes/cpu/debugger/debugger.cpp b/bsnes/snes/cpu/debugger/debugger.cpp index 4e56d518..f0c618da 100644 --- a/bsnes/snes/cpu/debugger/debugger.cpp +++ b/bsnes/snes/cpu/debugger/debugger.cpp @@ -46,10 +46,14 @@ void CPUDebugger::op_step() { usage[regs.pc] |= UsageOpcode | (regs.p.m << 1) | (regs.p.x << 0); opcode_pc = regs.pc; + extern void send_pause_event(bool is_step); + if(debugger.step_cpu && (debugger.step_type == Debugger::StepType::StepInto || (debugger.step_type >= Debugger::StepType::StepOver && debugger.call_count < 0))) { + send_pause_event(true); + debugger.break_event = Debugger::BreakEvent::CPUStep; debugger.step_type = Debugger::StepType::None; scheduler.exit(Scheduler::ExitReason::DebuggerEvent); @@ -58,6 +62,8 @@ void CPUDebugger::op_step() { if (debugger.break_on_wdm || debugger.break_on_brk) { uint8 opcode = disassembler_read(opcode_pc); if ((opcode == 0x42 && debugger.break_on_wdm) || (opcode == 0x00 && debugger.break_on_brk)) { + send_pause_event(true); + debugger.breakpoint_hit = Debugger::SoftBreakCPU; debugger.break_event = Debugger::BreakEvent::BreakpointHit; scheduler.exit(Scheduler::ExitReason::DebuggerEvent); @@ -65,7 +71,9 @@ void CPUDebugger::op_step() { } debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00); } - if(step_event) step_event(); + if(step_event) { + step_event(); + } uint8 hvb_old; @@ -101,6 +109,9 @@ void CPUDebugger::op_step() { } alwaysinline uint8_t CPUDebugger::op_readpc() { + extern std::set visited; + visited.insert(regs.pc); + usage[regs.pc] |= UsageExec; int offset = cartridge.rom_offset(regs.pc); diff --git a/bsnes/snes/debugger/debugger.cpp b/bsnes/snes/debugger/debugger.cpp index c4375137..ca2b1ff2 100644 --- a/bsnes/snes/debugger/debugger.cpp +++ b/bsnes/snes/debugger/debugger.cpp @@ -49,6 +49,9 @@ void Debugger::breakpoint_test(Debugger::Breakpoint::Source source, Debugger::Br } } if (addr_start > addr_end) continue; + + extern void send_pause_event(bool is_step); + send_pause_event(false); breakpoint[i].counter++; breakpoint_hit = i; diff --git a/bsnes/snes/input/input.cpp b/bsnes/snes/input/input.cpp index bd34c106..af2ad043 100644 --- a/bsnes/snes/input/input.cpp +++ b/bsnes/snes/input/input.cpp @@ -14,9 +14,9 @@ uint8 Input::port_read(bool portnumber) { case Device::SGBCommander: { if(cpu.joylatch() == 0) { if(p.counter0 >= 16) return 1; - return system.interface->input_poll(portnumber, p.device, 0, p.counter0++); + return system.intf->input_poll(portnumber, p.device, 0, p.counter0++); } else { - return system.interface->input_poll(portnumber, p.device, 0, 0); + return system.intf->input_poll(portnumber, p.device, 0, 0); } } //case Device::Joypad @@ -42,8 +42,8 @@ uint8 Input::port_read(bool portnumber) { deviceindex1 = 3; //controller 4 } - return (system.interface->input_poll(portnumber, p.device, deviceindex0, deviceidx) << 0) - | (system.interface->input_poll(portnumber, p.device, deviceindex1, deviceidx) << 1); + return (system.intf->input_poll(portnumber, p.device, deviceindex0, deviceidx) << 0) + | (system.intf->input_poll(portnumber, p.device, deviceindex1, deviceidx) << 1); } //case Device::Multitap case Device::Mouse: { @@ -65,8 +65,8 @@ uint8 Input::port_read(bool portnumber) { case 6: return 0; case 7: return 0; - case 8: return system.interface->input_poll(portnumber, p.device, 0, (unsigned)MouseID::Right); - case 9: return system.interface->input_poll(portnumber, p.device, 0, (unsigned)MouseID::Left); + case 8: return system.intf->input_poll(portnumber, p.device, 0, (unsigned)MouseID::Right); + case 9: return system.intf->input_poll(portnumber, p.device, 0, (unsigned)MouseID::Left); case 10: return (p.mouse.speed >> 1) & 1; //speed (0 = slow, 1 = normal, 2 = fast, 3 = unused) case 11: return (p.mouse.speed >> 0) & 1; // || @@ -101,7 +101,7 @@ uint8 Input::port_read(bool portnumber) { if(p.counter0 == 0) { //turbo is a switch; toggle is edge sensitive - bool turbo = system.interface->input_poll(portnumber, p.device, 0, (unsigned)SuperScopeID::Turbo); + bool turbo = system.intf->input_poll(portnumber, p.device, 0, (unsigned)SuperScopeID::Turbo); if(turbo && !p.superscope.turbolock) { p.superscope.turbo = !p.superscope.turbo; //toggle state p.superscope.turbolock = true; @@ -112,7 +112,7 @@ uint8 Input::port_read(bool portnumber) { //trigger is a button //if turbo is active, trigger is level sensitive; otherwise it is edge sensitive p.superscope.trigger = false; - bool trigger = system.interface->input_poll(portnumber, p.device, 0, (unsigned)SuperScopeID::Trigger); + bool trigger = system.intf->input_poll(portnumber, p.device, 0, (unsigned)SuperScopeID::Trigger); if(trigger && (p.superscope.turbo || !p.superscope.triggerlock)) { p.superscope.trigger = true; p.superscope.triggerlock = true; @@ -121,11 +121,11 @@ uint8 Input::port_read(bool portnumber) { } //cursor is a button; it is always level sensitive - p.superscope.cursor = system.interface->input_poll(portnumber, p.device, 0, (unsigned)SuperScopeID::Cursor); + p.superscope.cursor = system.intf->input_poll(portnumber, p.device, 0, (unsigned)SuperScopeID::Cursor); //pause is a button; it is always edge sensitive p.superscope.pause = false; - bool pause = system.interface->input_poll(portnumber, p.device, 0, (unsigned)SuperScopeID::Pause); + bool pause = system.intf->input_poll(portnumber, p.device, 0, (unsigned)SuperScopeID::Pause); if(pause && !p.superscope.pauselock) { p.superscope.pause = true; p.superscope.pauselock = true; @@ -156,12 +156,12 @@ uint8 Input::port_read(bool portnumber) { if(p.counter0 >= 32) return 1; if(p.counter0 == 0) { - p.justifier.trigger1 = system.interface->input_poll(portnumber, p.device, 0, (unsigned)JustifierID::Trigger); - p.justifier.start1 = system.interface->input_poll(portnumber, p.device, 0, (unsigned)JustifierID::Start); + p.justifier.trigger1 = system.intf->input_poll(portnumber, p.device, 0, (unsigned)JustifierID::Trigger); + p.justifier.start1 = system.intf->input_poll(portnumber, p.device, 0, (unsigned)JustifierID::Start); if(p.device == Device::Justifiers) { - p.justifier.trigger2 = system.interface->input_poll(portnumber, p.device, 1, (unsigned)JustifierID::Trigger); - p.justifier.start2 = system.interface->input_poll(portnumber, p.device, 1, (unsigned)JustifierID::Start); + p.justifier.trigger2 = system.intf->input_poll(portnumber, p.device, 1, (unsigned)JustifierID::Trigger); + p.justifier.start2 = system.intf->input_poll(portnumber, p.device, 1, (unsigned)JustifierID::Start); } else { p.justifier.x2 = -1; p.justifier.y2 = -1; @@ -225,9 +225,9 @@ uint8 Input::port_read(bool portnumber) { return 0; } - return system.interface->input_poll(portnumber, p.device, 0, p.counter0++); + return system.intf->input_poll(portnumber, p.device, 0, p.counter0++); } else { - return system.interface->input_poll(portnumber, p.device, 0, 0); + return system.intf->input_poll(portnumber, p.device, 0, 0); } } //case Device::NTTDataKeypad @@ -240,13 +240,13 @@ uint8 Input::port_read(bool portnumber) { //scan all input; update cursor positions if needed void Input::update() { - system.interface->input_poll(); + system.intf->input_poll(); port_t &p = port[1]; switch(p.device) { case Device::SuperScope: { - int x = system.interface->input_poll(1, p.device, 0, (unsigned)SuperScopeID::X); - int y = system.interface->input_poll(1, p.device, 0, (unsigned)SuperScopeID::Y); + int x = system.intf->input_poll(1, p.device, 0, (unsigned)SuperScopeID::X); + int y = system.intf->input_poll(1, p.device, 0, (unsigned)SuperScopeID::Y); x += p.superscope.x; y += p.superscope.y; p.superscope.x = max(-16, min(256 + 16, x)); @@ -258,15 +258,15 @@ void Input::update() { case Device::Justifier: case Device::Justifiers: { - int x1 = system.interface->input_poll(1, p.device, 0, (unsigned)JustifierID::X); - int y1 = system.interface->input_poll(1, p.device, 0, (unsigned)JustifierID::Y); + int x1 = system.intf->input_poll(1, p.device, 0, (unsigned)JustifierID::X); + int y1 = system.intf->input_poll(1, p.device, 0, (unsigned)JustifierID::Y); x1 += p.justifier.x1; y1 += p.justifier.y1; p.justifier.x1 = max(-16, min(256 + 16, x1)); p.justifier.y1 = max(-16, min(240 + 16, y1)); - int x2 = system.interface->input_poll(1, p.device, 1, (unsigned)JustifierID::X); - int y2 = system.interface->input_poll(1, p.device, 1, (unsigned)JustifierID::Y); + int x2 = system.intf->input_poll(1, p.device, 1, (unsigned)JustifierID::X); + int y2 = system.intf->input_poll(1, p.device, 1, (unsigned)JustifierID::Y); x2 += p.justifier.x2; y2 += p.justifier.y2; p.justifier.x2 = max(-16, min(256 + 16, x2)); @@ -360,8 +360,8 @@ void Input::poll() { port[i].counter1 = 0; if(port[i].device == Device::Mouse) { - int x = system.interface->input_poll(i, port[i].device, 0, (unsigned)MouseID::X); //-n = left, 0 = center, +n = right - int y = system.interface->input_poll(i, port[i].device, 0, (unsigned)MouseID::Y); //-n = up, 0 = center, +n = down + int x = system.intf->input_poll(i, port[i].device, 0, (unsigned)MouseID::X); //-n = left, 0 = center, +n = right + int y = system.intf->input_poll(i, port[i].device, 0, (unsigned)MouseID::Y); //-n = up, 0 = center, +n = down port[i].mouse.dx = x < 0; port[i].mouse.dy = y < 0; diff --git a/bsnes/snes/libsnes/libsnes.cpp b/bsnes/snes/libsnes/libsnes.cpp index 4930fa79..445174ec 100644 --- a/bsnes/snes/libsnes/libsnes.cpp +++ b/bsnes/snes/libsnes/libsnes.cpp @@ -31,7 +31,7 @@ struct Interface : public SNES::Interface { } }; -static Interface interface; +static Interface intf; unsigned snes_library_revision_major(void) { return 1; @@ -42,19 +42,19 @@ unsigned snes_library_revision_minor(void) { } void snes_set_video_refresh(snes_video_refresh_t video_refresh) { - interface.pvideo_refresh = video_refresh; + intf.pvideo_refresh = video_refresh; } void snes_set_audio_sample(snes_audio_sample_t audio_sample) { - interface.paudio_sample = audio_sample; + intf.paudio_sample = audio_sample; } void snes_set_input_poll(snes_input_poll_t input_poll) { - interface.pinput_poll = input_poll; + intf.pinput_poll = input_poll; } void snes_set_input_state(snes_input_state_t input_state) { - interface.pinput_state = input_state; + intf.pinput_state = input_state; } void snes_set_controller_port_device(bool port, unsigned device) { @@ -66,7 +66,7 @@ void snes_set_cartridge_basename(const char *basename) { } void snes_init(void) { - SNES::system.init(&interface); + SNES::system.init(&intf); SNES::input.port_set_device(0, SNES::Input::Device::Joypad); SNES::input.port_set_device(1, SNES::Input::Device::Joypad); } diff --git a/bsnes/snes/ppu/window/window.cpp b/bsnes/snes/ppu/window/window.cpp index f3a29a9a..538b9501 100644 --- a/bsnes/snes/ppu/window/window.cpp +++ b/bsnes/snes/ppu/window/window.cpp @@ -88,7 +88,7 @@ void PPU::Window::test( ) { bool one = Window::one ^ one_invert; bool two = Window::two ^ two_invert; - bool output; + bool output = true; if(one_enable == false && two_enable == false) { output = false; diff --git a/bsnes/snes/system/system.cpp b/bsnes/snes/system/system.cpp index 8a6fa9a9..6f09cd00 100644 --- a/bsnes/snes/system/system.cpp +++ b/bsnes/snes/system/system.cpp @@ -71,8 +71,8 @@ bool System::runthreadtosave(cothread_t& thread) { } void System::init(Interface *interface_) { - interface = interface_; - assert(interface != 0); + intf = interface_; + assert(intf != 0); supergameboy.init(); superfx.init(); @@ -236,7 +236,7 @@ void System::scanline() { void System::frame() { } -System::System() : interface(0) { +System::System() : intf(0) { region = Region::Autodetect; expansion = ExpansionPortDevice::None; } diff --git a/bsnes/snes/system/system.hpp b/bsnes/snes/system/system.hpp index 171e6743..a5a812ad 100644 --- a/bsnes/snes/system/system.hpp +++ b/bsnes/snes/system/system.hpp @@ -30,7 +30,7 @@ class System : property { System(); private: - Interface *interface; + Interface *intf; bool runthreadtosave(cothread_t&); void serialize(serializer&); diff --git a/bsnes/snes/video/video.cpp b/bsnes/snes/video/video.cpp index a36a38b9..c34bf7f8 100644 --- a/bsnes/snes/video/video.cpp +++ b/bsnes/snes/video/video.cpp @@ -72,13 +72,13 @@ void Video::update() { } } - system.interface->video_extras(data, width, height); + system.intf->video_extras(data, width, height); if(frame_interlace) { height <<= 1; } - system.interface->video_refresh(ppu.output + 1024, width, height); + system.intf->video_refresh(ppu.output + 1024, width, height); frame_hires = false; frame_interlace = false; diff --git a/bsnes/thrift/debug_proto.thrift b/bsnes/thrift/debug_proto.thrift new file mode 100644 index 00000000..e6424434 --- /dev/null +++ b/bsnes/thrift/debug_proto.thrift @@ -0,0 +1,97 @@ +enum BsnesRegister { + pc, + a, + x, + y, + s, + d, + db, + p, + mflag, + xflag, + eflag, +} + +struct BsnesRegisters { + 1:i32 pc, + 2:i32 a, + 3:i32 x, + 4:i32 y, + 5:i32 s, + 6:i32 d, + 7:i16 db, + 8:i16 p, + 9:i8 mflag, + 10:i8 xflag, + 11:i8 eflag, +} + +enum BpType { + BP_PC = 1, + BP_READ = 2, + BP_WRITE = 4, +} + +enum DbgMemorySource { + CPUBus, + APUBus, + APURAM, + DSP, + VRAM, + OAM, + CGRAM, + CartROM, + CartRAM, + SA1Bus, + SFXBus, + SGBBus, + SGBROM, + SGBRAM, +} + +enum DbgBptSource { + CPUBus, + APURAM, + DSP, + VRAM, + OAM, + CGRAM, + SA1Bus, + SFXBus, + SGBBus, +} + +struct DbgBreakpoint { + 1:BpType type, + 2:i32 bstart, + 3:i32 bend, + 4:bool enabled, + 5:DbgBptSource src, +} + +service BsnesDebugger { + i32 get_cpu_reg(1:BsnesRegister reg), + BsnesRegisters get_cpu_regs(), + void set_cpu_reg(1:BsnesRegister reg, 2:i32 value), + + binary read_memory(1:DbgMemorySource src, 2:i32 address, 3:i32 size), + void write_memory(1:DbgMemorySource src, 2:i32 address, 3:binary data), + + void add_breakpoint(1:DbgBreakpoint bpt), + void del_breakpoint(1:DbgBreakpoint bpt), + + void pause(), + void resume(), + void start_emulation(), + void exit_emulation(), + + void step_into(), + void step_over(), +} + +service IdaClient { + oneway void start_event(), + oneway void add_visited(1:set changed, 2:bool is_step), + oneway void pause_event(1:i32 address), + oneway void stop_event(), +} diff --git a/bsnes/thrift/libevent/bin/event_rpcgen.py b/bsnes/thrift/libevent/bin/event_rpcgen.py new file mode 100644 index 00000000..0bae3b0f --- /dev/null +++ b/bsnes/thrift/libevent/bin/event_rpcgen.py @@ -0,0 +1,1925 @@ +#!/usr/bin/env python +# +# Copyright (c) 2005-2007 Niels Provos +# Copyright (c) 2007-2012 Niels Provos and Nick Mathewson +# All rights reserved. +# +# Generates marshaling code based on libevent. + +# pylint: disable=too-many-lines +# pylint: disable=too-many-branches +# pylint: disable=too-many-public-methods +# pylint: disable=too-many-statements +# pylint: disable=global-statement + +# TODO: +# 1) propagate the arguments/options parsed by argparse down to the +# instantiated factory objects. +# 2) move the globals into a class that manages execution, including the +# progress outputs that go to stderr at the moment. +# 3) emit other languages. + +import argparse +import re +import sys + +_NAME = "event_rpcgen.py" +_VERSION = "0.1" + +# Globals +LINE_COUNT = 0 + +CPPCOMMENT_RE = re.compile(r"\/\/.*$") +NONIDENT_RE = re.compile(r"\W") +PREPROCESSOR_DEF_RE = re.compile(r"^#define") +STRUCT_REF_RE = re.compile(r"^struct\[(?P[a-zA-Z_][a-zA-Z0-9_]*)\]$") +STRUCT_DEF_RE = re.compile(r"^struct +[a-zA-Z_][a-zA-Z0-9_]* *{$") +WHITESPACE_RE = re.compile(r"\s+") + +HEADER_DIRECT = [] +CPP_DIRECT = [] + +QUIETLY = False + + +def declare(s): + if not QUIETLY: + print(s) + + +def TranslateList(mylist, mydict): + return [x % mydict for x in mylist] + + +class RpcGenError(Exception): + """An Exception class for parse errors.""" + + def __init__(self, why): # pylint: disable=super-init-not-called + self.why = why + + def __str__(self): + return str(self.why) + + +# Holds everything that makes a struct +class Struct(object): + def __init__(self, name): + self._name = name + self._entries = [] + self._tags = {} + declare(" Created struct: %s" % name) + + def AddEntry(self, entry): + if entry.Tag() in self._tags: + raise RpcGenError( + 'Entry "%s" duplicates tag number %d from "%s" ' + "around line %d" + % (entry.Name(), entry.Tag(), self._tags[entry.Tag()], LINE_COUNT) + ) + self._entries.append(entry) + self._tags[entry.Tag()] = entry.Name() + declare(" Added entry: %s" % entry.Name()) + + def Name(self): + return self._name + + def EntryTagName(self, entry): + """Creates the name inside an enumeration for distinguishing data + types.""" + name = "%s_%s" % (self._name, entry.Name()) + return name.upper() + + @staticmethod + def PrintIndented(filep, ident, code): + """Takes an array, add indentation to each entry and prints it.""" + for entry in code: + filep.write("%s%s\n" % (ident, entry)) + + +class StructCCode(Struct): + """ Knows how to generate C code for a struct """ + + def __init__(self, name): + Struct.__init__(self, name) + + def PrintTags(self, filep): + """Prints the tag definitions for a structure.""" + filep.write("/* Tag definition for %s */\n" % self._name) + filep.write("enum %s_ {\n" % self._name.lower()) + for entry in self._entries: + filep.write(" %s=%d,\n" % (self.EntryTagName(entry), entry.Tag())) + filep.write(" %s_MAX_TAGS\n" % (self._name.upper())) + filep.write("};\n\n") + + def PrintForwardDeclaration(self, filep): + filep.write("struct %s;\n" % self._name) + + def PrintDeclaration(self, filep): + filep.write("/* Structure declaration for %s */\n" % self._name) + filep.write("struct %s_access_ {\n" % self._name) + for entry in self._entries: + dcl = entry.AssignDeclaration("(*%s_assign)" % entry.Name()) + dcl.extend(entry.GetDeclaration("(*%s_get)" % entry.Name())) + if entry.Array(): + dcl.extend(entry.AddDeclaration("(*%s_add)" % entry.Name())) + self.PrintIndented(filep, " ", dcl) + filep.write("};\n\n") + + filep.write("struct %s {\n" % self._name) + filep.write(" struct %s_access_ *base;\n\n" % self._name) + for entry in self._entries: + dcl = entry.Declaration() + self.PrintIndented(filep, " ", dcl) + filep.write("\n") + for entry in self._entries: + filep.write(" ev_uint8_t %s_set;\n" % entry.Name()) + filep.write("};\n\n") + + filep.write( + """struct %(name)s *%(name)s_new(void); +struct %(name)s *%(name)s_new_with_arg(void *); +void %(name)s_free(struct %(name)s *); +void %(name)s_clear(struct %(name)s *); +void %(name)s_marshal(struct evbuffer *, const struct %(name)s *); +int %(name)s_unmarshal(struct %(name)s *, struct evbuffer *); +int %(name)s_complete(struct %(name)s *); +void evtag_marshal_%(name)s(struct evbuffer *, ev_uint32_t, + const struct %(name)s *); +int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t, + struct %(name)s *);\n""" + % {"name": self._name} + ) + + # Write a setting function of every variable + for entry in self._entries: + self.PrintIndented( + filep, "", entry.AssignDeclaration(entry.AssignFuncName()) + ) + self.PrintIndented(filep, "", entry.GetDeclaration(entry.GetFuncName())) + if entry.Array(): + self.PrintIndented(filep, "", entry.AddDeclaration(entry.AddFuncName())) + + filep.write("/* --- %s done --- */\n\n" % self._name) + + def PrintCode(self, filep): + filep.write( + """/* + * Implementation of %s + */ +""" + % (self._name) + ) + + filep.write( + """ +static struct %(name)s_access_ %(name)s_base__ = { +""" + % {"name": self._name} + ) + for entry in self._entries: + self.PrintIndented(filep, " ", entry.CodeBase()) + filep.write("};\n\n") + + # Creation + filep.write( + """struct %(name)s * +%(name)s_new(void) +{ + return %(name)s_new_with_arg(NULL); +} + +struct %(name)s * +%(name)s_new_with_arg(void *unused) +{ + struct %(name)s *tmp; + if ((tmp = malloc(sizeof(struct %(name)s))) == NULL) { + event_warn("%%s: malloc", __func__); + return (NULL); + } + tmp->base = &%(name)s_base__; + +""" + % {"name": self._name} + ) + + for entry in self._entries: + self.PrintIndented(filep, " ", entry.CodeInitialize("tmp")) + filep.write(" tmp->%s_set = 0;\n\n" % entry.Name()) + + filep.write( + """ return (tmp); +} + +""" + ) + + # Adding + for entry in self._entries: + if entry.Array(): + self.PrintIndented(filep, "", entry.CodeAdd()) + filep.write("\n") + + # Assigning + for entry in self._entries: + self.PrintIndented(filep, "", entry.CodeAssign()) + filep.write("\n") + + # Getting + for entry in self._entries: + self.PrintIndented(filep, "", entry.CodeGet()) + filep.write("\n") + + # Clearing + filep.write( + """void +%(name)s_clear(struct %(name)s *tmp) +{ +""" + % {"name": self._name} + ) + for entry in self._entries: + self.PrintIndented(filep, " ", entry.CodeClear("tmp")) + + filep.write("}\n\n") + + # Freeing + filep.write( + """void +%(name)s_free(struct %(name)s *tmp) +{ +""" + % {"name": self._name} + ) + + for entry in self._entries: + self.PrintIndented(filep, " ", entry.CodeFree("tmp")) + + filep.write( + """ free(tmp); +} + +""" + ) + + # Marshaling + filep.write( + """void +%(name)s_marshal(struct evbuffer *evbuf, const struct %(name)s *tmp) { +""" + % {"name": self._name} + ) + for entry in self._entries: + indent = " " + # Optional entries do not have to be set + if entry.Optional(): + indent += " " + filep.write(" if (tmp->%s_set) {\n" % entry.Name()) + self.PrintIndented( + filep, + indent, + entry.CodeMarshal( + "evbuf", + self.EntryTagName(entry), + entry.GetVarName("tmp"), + entry.GetVarLen("tmp"), + ), + ) + if entry.Optional(): + filep.write(" }\n") + + filep.write("}\n\n") + + # Unmarshaling + filep.write( + """int +%(name)s_unmarshal(struct %(name)s *tmp, struct evbuffer *evbuf) +{ + ev_uint32_t tag; + while (evbuffer_get_length(evbuf) > 0) { + if (evtag_peek(evbuf, &tag) == -1) + return (-1); + switch (tag) { + +""" + % {"name": self._name} + ) + for entry in self._entries: + filep.write(" case %s:\n" % (self.EntryTagName(entry))) + if not entry.Array(): + filep.write( + """ if (tmp->%s_set) + return (-1); +""" + % (entry.Name()) + ) + + self.PrintIndented( + filep, + " ", + entry.CodeUnmarshal( + "evbuf", + self.EntryTagName(entry), + entry.GetVarName("tmp"), + entry.GetVarLen("tmp"), + ), + ) + + filep.write( + """ tmp->%s_set = 1; + break; +""" + % (entry.Name()) + ) + filep.write( + """ default: + return -1; + } + } + +""" + ) + # Check if it was decoded completely + filep.write( + """ if (%(name)s_complete(tmp) == -1) + return (-1); + return (0); +} +""" + % {"name": self._name} + ) + + # Checking if a structure has all the required data + filep.write( + """ +int +%(name)s_complete(struct %(name)s *msg) +{ +""" + % {"name": self._name} + ) + for entry in self._entries: + if not entry.Optional(): + code = [ + """if (!msg->%(name)s_set) + return (-1);""" + ] + code = TranslateList(code, entry.GetTranslation()) + self.PrintIndented(filep, " ", code) + + self.PrintIndented( + filep, " ", entry.CodeComplete("msg", entry.GetVarName("msg")) + ) + filep.write( + """ return (0); +} +""" + ) + + # Complete message unmarshaling + filep.write( + """ +int +evtag_unmarshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t need_tag, + struct %(name)s *msg) +{ + ev_uint32_t tag; + int res = -1; + + struct evbuffer *tmp = evbuffer_new(); + + if (evtag_unmarshal(evbuf, &tag, tmp) == -1 || tag != need_tag) + goto error; + + if (%(name)s_unmarshal(msg, tmp) == -1) + goto error; + + res = 0; + + error: + evbuffer_free(tmp); + return (res); +} +""" + % {"name": self._name} + ) + + # Complete message marshaling + filep.write( + """ +void +evtag_marshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t tag, + const struct %(name)s *msg) +{ + struct evbuffer *buf_ = evbuffer_new(); + assert(buf_ != NULL); + %(name)s_marshal(buf_, msg); + evtag_marshal_buffer(evbuf, tag, buf_); + evbuffer_free(buf_); +} + +""" + % {"name": self._name} + ) + + +class Entry(object): + def __init__(self, ent_type, name, tag): + self._type = ent_type + self._name = name + self._tag = int(tag) + self._ctype = ent_type + self._optional = False + self._can_be_array = False + self._array = False + self._line_count = -1 + self._struct = None + self._refname = None + + self._optpointer = True + self._optaddarg = True + + @staticmethod + def GetInitializer(): + raise NotImplementedError("Entry does not provide an initializer") + + def SetStruct(self, struct): + self._struct = struct + + def LineCount(self): + assert self._line_count != -1 + return self._line_count + + def SetLineCount(self, number): + self._line_count = number + + def Array(self): + return self._array + + def Optional(self): + return self._optional + + def Tag(self): + return self._tag + + def Name(self): + return self._name + + def Type(self): + return self._type + + def MakeArray(self): + self._array = True + + def MakeOptional(self): + self._optional = True + + def Verify(self): + if self.Array() and not self._can_be_array: + raise RpcGenError( + 'Entry "%s" cannot be created as an array ' + "around line %d" % (self._name, self.LineCount()) + ) + if not self._struct: + raise RpcGenError( + 'Entry "%s" does not know which struct it belongs to ' + "around line %d" % (self._name, self.LineCount()) + ) + if self._optional and self._array: + raise RpcGenError( + 'Entry "%s" has illegal combination of optional and array ' + "around line %d" % (self._name, self.LineCount()) + ) + + def GetTranslation(self, extradict=None): + if extradict is None: + extradict = {} + mapping = { + "parent_name": self._struct.Name(), + "name": self._name, + "ctype": self._ctype, + "refname": self._refname, + "optpointer": self._optpointer and "*" or "", + "optreference": self._optpointer and "&" or "", + "optaddarg": self._optaddarg and ", const %s value" % self._ctype or "", + } + for (k, v) in list(extradict.items()): + mapping[k] = v + + return mapping + + def GetVarName(self, var): + return "%(var)s->%(name)s_data" % self.GetTranslation({"var": var}) + + def GetVarLen(self, _var): + return "sizeof(%s)" % self._ctype + + def GetFuncName(self): + return "%s_%s_get" % (self._struct.Name(), self._name) + + def GetDeclaration(self, funcname): + code = [ + "int %s(struct %s *, %s *);" % (funcname, self._struct.Name(), self._ctype) + ] + return code + + def CodeGet(self): + code = """int +%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, %(ctype)s *value) +{ + if (msg->%(name)s_set != 1) + return (-1); + *value = msg->%(name)s_data; + return (0); +}""" + code = code % self.GetTranslation() + return code.split("\n") + + def AssignFuncName(self): + return "%s_%s_assign" % (self._struct.Name(), self._name) + + def AddFuncName(self): + return "%s_%s_add" % (self._struct.Name(), self._name) + + def AssignDeclaration(self, funcname): + code = [ + "int %s(struct %s *, const %s);" + % (funcname, self._struct.Name(), self._ctype) + ] + return code + + def CodeAssign(self): + code = [ + "int", + "%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg," + " const %(ctype)s value)", + "{", + " msg->%(name)s_set = 1;", + " msg->%(name)s_data = value;", + " return (0);", + "}", + ] + code = "\n".join(code) + code = code % self.GetTranslation() + return code.split("\n") + + def CodeClear(self, structname): + code = ["%s->%s_set = 0;" % (structname, self.Name())] + + return code + + @staticmethod + def CodeComplete(_structname, _var_name): + return [] + + @staticmethod + def CodeFree(_name): + return [] + + def CodeBase(self): + code = ["%(parent_name)s_%(name)s_assign,", "%(parent_name)s_%(name)s_get,"] + if self.Array(): + code.append("%(parent_name)s_%(name)s_add,") + + code = "\n".join(code) + code = code % self.GetTranslation() + return code.split("\n") + + +class EntryBytes(Entry): + def __init__(self, ent_type, name, tag, length): + # Init base class + super(EntryBytes, self).__init__(ent_type, name, tag) + + self._length = length + self._ctype = "ev_uint8_t" + + @staticmethod + def GetInitializer(): + return "NULL" + + def GetVarLen(self, _var): + return "(%s)" % self._length + + @staticmethod + def CodeArrayAdd(varname, _value): + # XXX: copy here + return ["%(varname)s = NULL;" % {"varname": varname}] + + def GetDeclaration(self, funcname): + code = [ + "int %s(struct %s *, %s **);" % (funcname, self._struct.Name(), self._ctype) + ] + return code + + def AssignDeclaration(self, funcname): + code = [ + "int %s(struct %s *, const %s *);" + % (funcname, self._struct.Name(), self._ctype) + ] + return code + + def Declaration(self): + dcl = ["ev_uint8_t %s_data[%s];" % (self._name, self._length)] + + return dcl + + def CodeGet(self): + name = self._name + code = [ + "int", + "%s_%s_get(struct %s *msg, %s **value)" + % (self._struct.Name(), name, self._struct.Name(), self._ctype), + "{", + " if (msg->%s_set != 1)" % name, + " return (-1);", + " *value = msg->%s_data;" % name, + " return (0);", + "}", + ] + return code + + def CodeAssign(self): + name = self._name + code = [ + "int", + "%s_%s_assign(struct %s *msg, const %s *value)" + % (self._struct.Name(), name, self._struct.Name(), self._ctype), + "{", + " msg->%s_set = 1;" % name, + " memcpy(msg->%s_data, value, %s);" % (name, self._length), + " return (0);", + "}", + ] + return code + + def CodeUnmarshal(self, buf, tag_name, var_name, var_len): + code = [ + "if (evtag_unmarshal_fixed(%(buf)s, %(tag)s, " + "%(var)s, %(varlen)s) == -1) {", + ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);', + " return (-1);", + "}", + ] + return TranslateList( + code, + self.GetTranslation( + {"var": var_name, "varlen": var_len, "buf": buf, "tag": tag_name} + ), + ) + + @staticmethod + def CodeMarshal(buf, tag_name, var_name, var_len): + code = ["evtag_marshal(%s, %s, %s, %s);" % (buf, tag_name, var_name, var_len)] + return code + + def CodeClear(self, structname): + code = [ + "%s->%s_set = 0;" % (structname, self.Name()), + "memset(%s->%s_data, 0, sizeof(%s->%s_data));" + % (structname, self._name, structname, self._name), + ] + + return code + + def CodeInitialize(self, name): + code = [ + "memset(%s->%s_data, 0, sizeof(%s->%s_data));" + % (name, self._name, name, self._name) + ] + return code + + def Verify(self): + if not self._length: + raise RpcGenError( + 'Entry "%s" needs a length ' + "around line %d" % (self._name, self.LineCount()) + ) + + super(EntryBytes, self).Verify() + + +class EntryInt(Entry): + def __init__(self, ent_type, name, tag, bits=32): + # Init base class + super(EntryInt, self).__init__(ent_type, name, tag) + + self._can_be_array = True + if bits == 32: + self._ctype = "ev_uint32_t" + self._marshal_type = "int" + if bits == 64: + self._ctype = "ev_uint64_t" + self._marshal_type = "int64" + + @staticmethod + def GetInitializer(): + return "0" + + @staticmethod + def CodeArrayFree(_var): + return [] + + @staticmethod + def CodeArrayAssign(varname, srcvar): + return ["%(varname)s = %(srcvar)s;" % {"varname": varname, "srcvar": srcvar}] + + @staticmethod + def CodeArrayAdd(varname, value): + """Returns a new entry of this type.""" + return ["%(varname)s = %(value)s;" % {"varname": varname, "value": value}] + + def CodeUnmarshal(self, buf, tag_name, var_name, _var_len): + code = [ + "if (evtag_unmarshal_%(ma)s(%(buf)s, %(tag)s, &%(var)s) == -1) {", + ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);', + " return (-1);", + "}", + ] + code = "\n".join(code) % self.GetTranslation( + {"ma": self._marshal_type, "buf": buf, "tag": tag_name, "var": var_name} + ) + return code.split("\n") + + def CodeMarshal(self, buf, tag_name, var_name, _var_len): + code = [ + "evtag_marshal_%s(%s, %s, %s);" + % (self._marshal_type, buf, tag_name, var_name) + ] + return code + + def Declaration(self): + dcl = ["%s %s_data;" % (self._ctype, self._name)] + + return dcl + + def CodeInitialize(self, name): + code = ["%s->%s_data = 0;" % (name, self._name)] + return code + + +class EntryString(Entry): + def __init__(self, ent_type, name, tag): + # Init base class + super(EntryString, self).__init__(ent_type, name, tag) + + self._can_be_array = True + self._ctype = "char *" + + @staticmethod + def GetInitializer(): + return "NULL" + + @staticmethod + def CodeArrayFree(varname): + code = ["if (%(var)s != NULL) free(%(var)s);"] + + return TranslateList(code, {"var": varname}) + + @staticmethod + def CodeArrayAssign(varname, srcvar): + code = [ + "if (%(var)s != NULL)", + " free(%(var)s);", + "%(var)s = strdup(%(srcvar)s);", + "if (%(var)s == NULL) {", + ' event_warnx("%%s: strdup", __func__);', + " return (-1);", + "}", + ] + + return TranslateList(code, {"var": varname, "srcvar": srcvar}) + + @staticmethod + def CodeArrayAdd(varname, value): + code = [ + "if (%(value)s != NULL) {", + " %(var)s = strdup(%(value)s);", + " if (%(var)s == NULL) {", + " goto error;", + " }", + "} else {", + " %(var)s = NULL;", + "}", + ] + + return TranslateList(code, {"var": varname, "value": value}) + + def GetVarLen(self, var): + return "strlen(%s)" % self.GetVarName(var) + + @staticmethod + def CodeMakeInitalize(varname): + return "%(varname)s = NULL;" % {"varname": varname} + + def CodeAssign(self): + code = """int +%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, + const %(ctype)s value) +{ + if (msg->%(name)s_data != NULL) + free(msg->%(name)s_data); + if ((msg->%(name)s_data = strdup(value)) == NULL) + return (-1); + msg->%(name)s_set = 1; + return (0); +}""" % ( + self.GetTranslation() + ) + + return code.split("\n") + + def CodeUnmarshal(self, buf, tag_name, var_name, _var_len): + code = [ + "if (evtag_unmarshal_string(%(buf)s, %(tag)s, &%(var)s) == -1) {", + ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);', + " return (-1);", + "}", + ] + code = "\n".join(code) % self.GetTranslation( + {"buf": buf, "tag": tag_name, "var": var_name} + ) + return code.split("\n") + + @staticmethod + def CodeMarshal(buf, tag_name, var_name, _var_len): + code = ["evtag_marshal_string(%s, %s, %s);" % (buf, tag_name, var_name)] + return code + + def CodeClear(self, structname): + code = [ + "if (%s->%s_set == 1) {" % (structname, self.Name()), + " free(%s->%s_data);" % (structname, self.Name()), + " %s->%s_data = NULL;" % (structname, self.Name()), + " %s->%s_set = 0;" % (structname, self.Name()), + "}", + ] + + return code + + def CodeInitialize(self, name): + code = ["%s->%s_data = NULL;" % (name, self._name)] + return code + + def CodeFree(self, name): + code = [ + "if (%s->%s_data != NULL)" % (name, self._name), + " free (%s->%s_data);" % (name, self._name), + ] + + return code + + def Declaration(self): + dcl = ["char *%s_data;" % self._name] + + return dcl + + +class EntryStruct(Entry): + def __init__(self, ent_type, name, tag, refname): + # Init base class + super(EntryStruct, self).__init__(ent_type, name, tag) + + self._optpointer = False + self._can_be_array = True + self._refname = refname + self._ctype = "struct %s*" % refname + self._optaddarg = False + + def GetInitializer(self): + return "NULL" + + def GetVarLen(self, _var): + return "-1" + + def CodeArrayAdd(self, varname, _value): + code = [ + "%(varname)s = %(refname)s_new();", + "if (%(varname)s == NULL)", + " goto error;", + ] + + return TranslateList(code, self.GetTranslation({"varname": varname})) + + def CodeArrayFree(self, var): + code = ["%(refname)s_free(%(var)s);" % self.GetTranslation({"var": var})] + return code + + def CodeArrayAssign(self, var, srcvar): + code = [ + "int had_error = 0;", + "struct evbuffer *tmp = NULL;", + "%(refname)s_clear(%(var)s);", + "if ((tmp = evbuffer_new()) == NULL) {", + ' event_warn("%%s: evbuffer_new()", __func__);', + " had_error = 1;", + " goto done;", + "}", + "%(refname)s_marshal(tmp, %(srcvar)s);", + "if (%(refname)s_unmarshal(%(var)s, tmp) == -1) {", + ' event_warnx("%%s: %(refname)s_unmarshal", __func__);', + " had_error = 1;", + " goto done;", + "}", + "done:", + "if (tmp != NULL)", + " evbuffer_free(tmp);", + "if (had_error) {", + " %(refname)s_clear(%(var)s);", + " return (-1);", + "}", + ] + + return TranslateList(code, self.GetTranslation({"var": var, "srcvar": srcvar})) + + def CodeGet(self): + name = self._name + code = [ + "int", + "%s_%s_get(struct %s *msg, %s *value)" + % (self._struct.Name(), name, self._struct.Name(), self._ctype), + "{", + " if (msg->%s_set != 1) {" % name, + " msg->%s_data = %s_new();" % (name, self._refname), + " if (msg->%s_data == NULL)" % name, + " return (-1);", + " msg->%s_set = 1;" % name, + " }", + " *value = msg->%s_data;" % name, + " return (0);", + "}", + ] + return code + + def CodeAssign(self): + code = ( + """int +%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, + const %(ctype)s value) +{ + struct evbuffer *tmp = NULL; + if (msg->%(name)s_set) { + %(refname)s_clear(msg->%(name)s_data); + msg->%(name)s_set = 0; + } else { + msg->%(name)s_data = %(refname)s_new(); + if (msg->%(name)s_data == NULL) { + event_warn("%%s: %(refname)s_new()", __func__); + goto error; + } + } + if ((tmp = evbuffer_new()) == NULL) { + event_warn("%%s: evbuffer_new()", __func__); + goto error; + } + %(refname)s_marshal(tmp, value); + if (%(refname)s_unmarshal(msg->%(name)s_data, tmp) == -1) { + event_warnx("%%s: %(refname)s_unmarshal", __func__); + goto error; + } + msg->%(name)s_set = 1; + evbuffer_free(tmp); + return (0); + error: + if (tmp != NULL) + evbuffer_free(tmp); + if (msg->%(name)s_data != NULL) { + %(refname)s_free(msg->%(name)s_data); + msg->%(name)s_data = NULL; + } + return (-1); +}""" + % self.GetTranslation() + ) + return code.split("\n") + + def CodeComplete(self, structname, var_name): + code = [ + "if (%(structname)s->%(name)s_set && " + "%(refname)s_complete(%(var)s) == -1)", + " return (-1);", + ] + + return TranslateList( + code, self.GetTranslation({"structname": structname, "var": var_name}) + ) + + def CodeUnmarshal(self, buf, tag_name, var_name, _var_len): + code = [ + "%(var)s = %(refname)s_new();", + "if (%(var)s == NULL)", + " return (-1);", + "if (evtag_unmarshal_%(refname)s(%(buf)s, %(tag)s, ", + " %(var)s) == -1) {", + ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);', + " return (-1);", + "}", + ] + code = "\n".join(code) % self.GetTranslation( + {"buf": buf, "tag": tag_name, "var": var_name} + ) + return code.split("\n") + + def CodeMarshal(self, buf, tag_name, var_name, _var_len): + code = [ + "evtag_marshal_%s(%s, %s, %s);" % (self._refname, buf, tag_name, var_name) + ] + return code + + def CodeClear(self, structname): + code = [ + "if (%s->%s_set == 1) {" % (structname, self.Name()), + " %s_free(%s->%s_data);" % (self._refname, structname, self.Name()), + " %s->%s_data = NULL;" % (structname, self.Name()), + " %s->%s_set = 0;" % (structname, self.Name()), + "}", + ] + + return code + + def CodeInitialize(self, name): + code = ["%s->%s_data = NULL;" % (name, self._name)] + return code + + def CodeFree(self, name): + code = [ + "if (%s->%s_data != NULL)" % (name, self._name), + " %s_free(%s->%s_data);" % (self._refname, name, self._name), + ] + + return code + + def Declaration(self): + dcl = ["%s %s_data;" % (self._ctype, self._name)] + + return dcl + + +class EntryVarBytes(Entry): + def __init__(self, ent_type, name, tag): + # Init base class + super(EntryVarBytes, self).__init__(ent_type, name, tag) + + self._ctype = "ev_uint8_t *" + + @staticmethod + def GetInitializer(): + return "NULL" + + def GetVarLen(self, var): + return "%(var)s->%(name)s_length" % self.GetTranslation({"var": var}) + + @staticmethod + def CodeArrayAdd(varname, _value): + # xxx: copy + return ["%(varname)s = NULL;" % {"varname": varname}] + + def GetDeclaration(self, funcname): + code = [ + "int %s(struct %s *, %s *, ev_uint32_t *);" + % (funcname, self._struct.Name(), self._ctype) + ] + return code + + def AssignDeclaration(self, funcname): + code = [ + "int %s(struct %s *, const %s, ev_uint32_t);" + % (funcname, self._struct.Name(), self._ctype) + ] + return code + + def CodeAssign(self): + name = self._name + code = [ + "int", + "%s_%s_assign(struct %s *msg, " + "const %s value, ev_uint32_t len)" + % (self._struct.Name(), name, self._struct.Name(), self._ctype), + "{", + " if (msg->%s_data != NULL)" % name, + " free (msg->%s_data);" % name, + " msg->%s_data = malloc(len);" % name, + " if (msg->%s_data == NULL)" % name, + " return (-1);", + " msg->%s_set = 1;" % name, + " msg->%s_length = len;" % name, + " memcpy(msg->%s_data, value, len);" % name, + " return (0);", + "}", + ] + return code + + def CodeGet(self): + name = self._name + code = [ + "int", + "%s_%s_get(struct %s *msg, %s *value, ev_uint32_t *plen)" + % (self._struct.Name(), name, self._struct.Name(), self._ctype), + "{", + " if (msg->%s_set != 1)" % name, + " return (-1);", + " *value = msg->%s_data;" % name, + " *plen = msg->%s_length;" % name, + " return (0);", + "}", + ] + return code + + def CodeUnmarshal(self, buf, tag_name, var_name, var_len): + code = [ + "if (evtag_payload_length(%(buf)s, &%(varlen)s) == -1)", + " return (-1);", + # We do not want DoS opportunities + "if (%(varlen)s > evbuffer_get_length(%(buf)s))", + " return (-1);", + "if ((%(var)s = malloc(%(varlen)s)) == NULL)", + " return (-1);", + "if (evtag_unmarshal_fixed(%(buf)s, %(tag)s, %(var)s, " + "%(varlen)s) == -1) {", + ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);', + " return (-1);", + "}", + ] + code = "\n".join(code) % self.GetTranslation( + {"buf": buf, "tag": tag_name, "var": var_name, "varlen": var_len} + ) + return code.split("\n") + + @staticmethod + def CodeMarshal(buf, tag_name, var_name, var_len): + code = ["evtag_marshal(%s, %s, %s, %s);" % (buf, tag_name, var_name, var_len)] + return code + + def CodeClear(self, structname): + code = [ + "if (%s->%s_set == 1) {" % (structname, self.Name()), + " free (%s->%s_data);" % (structname, self.Name()), + " %s->%s_data = NULL;" % (structname, self.Name()), + " %s->%s_length = 0;" % (structname, self.Name()), + " %s->%s_set = 0;" % (structname, self.Name()), + "}", + ] + + return code + + def CodeInitialize(self, name): + code = [ + "%s->%s_data = NULL;" % (name, self._name), + "%s->%s_length = 0;" % (name, self._name), + ] + return code + + def CodeFree(self, name): + code = [ + "if (%s->%s_data != NULL)" % (name, self._name), + " free(%s->%s_data);" % (name, self._name), + ] + + return code + + def Declaration(self): + dcl = [ + "ev_uint8_t *%s_data;" % self._name, + "ev_uint32_t %s_length;" % self._name, + ] + + return dcl + + +class EntryArray(Entry): + _index = None + + def __init__(self, entry): + # Init base class + super(EntryArray, self).__init__(entry._type, entry._name, entry._tag) + + self._entry = entry + self._refname = entry._refname + self._ctype = self._entry._ctype + self._optional = True + self._optpointer = self._entry._optpointer + self._optaddarg = self._entry._optaddarg + + # provide a new function for accessing the variable name + def GetVarName(var_name): + return "%(var)s->%(name)s_data[%(index)s]" % self._entry.GetTranslation( + {"var": var_name, "index": self._index} + ) + + self._entry.GetVarName = GetVarName + + def GetInitializer(self): + return "NULL" + + def GetVarName(self, var): + return var + + def GetVarLen(self, _var_name): + return "-1" + + def GetDeclaration(self, funcname): + """Allows direct access to elements of the array.""" + code = [ + "int %(funcname)s(struct %(parent_name)s *, int, %(ctype)s *);" + % self.GetTranslation({"funcname": funcname}) + ] + return code + + def AssignDeclaration(self, funcname): + code = [ + "int %s(struct %s *, int, const %s);" + % (funcname, self._struct.Name(), self._ctype) + ] + return code + + def AddDeclaration(self, funcname): + code = [ + "%(ctype)s %(optpointer)s " + "%(funcname)s(struct %(parent_name)s *msg%(optaddarg)s);" + % self.GetTranslation({"funcname": funcname}) + ] + return code + + def CodeGet(self): + code = """int +%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, int offset, + %(ctype)s *value) +{ + if (!msg->%(name)s_set || offset < 0 || offset >= msg->%(name)s_length) + return (-1); + *value = msg->%(name)s_data[offset]; + return (0); +} +""" % ( + self.GetTranslation() + ) + + return code.splitlines() + + def CodeAssign(self): + code = [ + "int", + "%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, int off,", + " const %(ctype)s value)", + "{", + " if (!msg->%(name)s_set || off < 0 || off >= msg->%(name)s_length)", + " return (-1);", + "", + " {", + ] + code = TranslateList(code, self.GetTranslation()) + + codearrayassign = self._entry.CodeArrayAssign( + "msg->%(name)s_data[off]" % self.GetTranslation(), "value" + ) + code += [" " + x for x in codearrayassign] + + code += TranslateList([" }", " return (0);", "}"], self.GetTranslation()) + + return code + + def CodeAdd(self): + codearrayadd = self._entry.CodeArrayAdd( + "msg->%(name)s_data[msg->%(name)s_length - 1]" % self.GetTranslation(), + "value", + ) + code = [ + "static int", + "%(parent_name)s_%(name)s_expand_to_hold_more(" + "struct %(parent_name)s *msg)", + "{", + " int tobe_allocated = msg->%(name)s_num_allocated;", + " %(ctype)s* new_data = NULL;", + " tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;", + " new_data = (%(ctype)s*) realloc(msg->%(name)s_data,", + " tobe_allocated * sizeof(%(ctype)s));", + " if (new_data == NULL)", + " return -1;", + " msg->%(name)s_data = new_data;", + " msg->%(name)s_num_allocated = tobe_allocated;", + " return 0;", + "}", + "", + "%(ctype)s %(optpointer)s", + "%(parent_name)s_%(name)s_add(struct %(parent_name)s *msg%(optaddarg)s)", + "{", + " if (++msg->%(name)s_length >= msg->%(name)s_num_allocated) {", + " if (%(parent_name)s_%(name)s_expand_to_hold_more(msg)<0)", + " goto error;", + " }", + ] + + code = TranslateList(code, self.GetTranslation()) + + code += [" " + x for x in codearrayadd] + + code += TranslateList( + [ + " msg->%(name)s_set = 1;", + " return %(optreference)s(msg->%(name)s_data[" + "msg->%(name)s_length - 1]);", + "error:", + " --msg->%(name)s_length;", + " return (NULL);", + "}", + ], + self.GetTranslation(), + ) + + return code + + def CodeComplete(self, structname, var_name): + self._index = "i" + tmp = self._entry.CodeComplete(structname, self._entry.GetVarName(var_name)) + # skip the whole loop if there is nothing to check + if not tmp: + return [] + + translate = self.GetTranslation({"structname": structname}) + code = [ + "{", + " int i;", + " for (i = 0; i < %(structname)s->%(name)s_length; ++i) {", + ] + + code = TranslateList(code, translate) + + code += [" " + x for x in tmp] + + code += [" }", "}"] + + return code + + def CodeUnmarshal(self, buf, tag_name, var_name, _var_len): + translate = self.GetTranslation( + { + "var": var_name, + "buf": buf, + "tag": tag_name, + "init": self._entry.GetInitializer(), + } + ) + code = [ + "if (%(var)s->%(name)s_length >= %(var)s->%(name)s_num_allocated &&", + " %(parent_name)s_%(name)s_expand_to_hold_more(%(var)s) < 0) {", + ' puts("HEY NOW");', + " return (-1);", + "}", + ] + + # the unmarshal code directly returns + code = TranslateList(code, translate) + + self._index = "%(var)s->%(name)s_length" % translate + code += self._entry.CodeUnmarshal( + buf, + tag_name, + self._entry.GetVarName(var_name), + self._entry.GetVarLen(var_name), + ) + + code += ["++%(var)s->%(name)s_length;" % translate] + + return code + + def CodeMarshal(self, buf, tag_name, var_name, _var_len): + code = ["{", " int i;", " for (i = 0; i < %(var)s->%(name)s_length; ++i) {"] + + self._index = "i" + code += self._entry.CodeMarshal( + buf, + tag_name, + self._entry.GetVarName(var_name), + self._entry.GetVarLen(var_name), + ) + code += [" }", "}"] + + code = "\n".join(code) % self.GetTranslation({"var": var_name}) + + return code.split("\n") + + def CodeClear(self, structname): + translate = self.GetTranslation({"structname": structname}) + codearrayfree = self._entry.CodeArrayFree( + "%(structname)s->%(name)s_data[i]" + % self.GetTranslation({"structname": structname}) + ) + + code = ["if (%(structname)s->%(name)s_set == 1) {"] + + if codearrayfree: + code += [ + " int i;", + " for (i = 0; i < %(structname)s->%(name)s_length; ++i) {", + ] + + code = TranslateList(code, translate) + + if codearrayfree: + code += [" " + x for x in codearrayfree] + code += [" }"] + + code += TranslateList( + [ + " free(%(structname)s->%(name)s_data);", + " %(structname)s->%(name)s_data = NULL;", + " %(structname)s->%(name)s_set = 0;", + " %(structname)s->%(name)s_length = 0;", + " %(structname)s->%(name)s_num_allocated = 0;", + "}", + ], + translate, + ) + + return code + + def CodeInitialize(self, name): + code = [ + "%s->%s_data = NULL;" % (name, self._name), + "%s->%s_length = 0;" % (name, self._name), + "%s->%s_num_allocated = 0;" % (name, self._name), + ] + return code + + def CodeFree(self, structname): + code = self.CodeClear(structname) + + code += TranslateList( + ["free(%(structname)s->%(name)s_data);"], + self.GetTranslation({"structname": structname}), + ) + + return code + + def Declaration(self): + dcl = [ + "%s *%s_data;" % (self._ctype, self._name), + "int %s_length;" % self._name, + "int %s_num_allocated;" % self._name, + ] + + return dcl + + +def NormalizeLine(line): + + line = CPPCOMMENT_RE.sub("", line) + line = line.strip() + line = WHITESPACE_RE.sub(" ", line) + + return line + + +ENTRY_NAME_RE = re.compile(r"(?P[^\[\]]+)(\[(?P.*)\])?") +ENTRY_TAG_NUMBER_RE = re.compile(r"(0x)?\d+", re.I) + + +def ProcessOneEntry(factory, newstruct, entry): + optional = False + array = False + entry_type = "" + name = "" + tag = "" + tag_set = None + separator = "" + fixed_length = "" + + for token in entry.split(" "): + if not entry_type: + if not optional and token == "optional": + optional = True + continue + + if not array and token == "array": + array = True + continue + + if not entry_type: + entry_type = token + continue + + if not name: + res = ENTRY_NAME_RE.match(token) + if not res: + raise RpcGenError( + r"""Cannot parse name: "%s" around line %d""" % (entry, LINE_COUNT) + ) + name = res.group("name") + fixed_length = res.group("fixed_length") + continue + + if not separator: + separator = token + if separator != "=": + raise RpcGenError( + r'''Expected "=" after name "%s" got "%s"''' % (name, token) + ) + continue + + if not tag_set: + tag_set = 1 + if not ENTRY_TAG_NUMBER_RE.match(token): + raise RpcGenError(r'''Expected tag number: "%s"''' % (entry)) + tag = int(token, 0) + continue + + raise RpcGenError(r'''Cannot parse "%s"''' % (entry)) + + if not tag_set: + raise RpcGenError(r'''Need tag number: "%s"''' % (entry)) + + # Create the right entry + if entry_type == "bytes": + if fixed_length: + newentry = factory.EntryBytes(entry_type, name, tag, fixed_length) + else: + newentry = factory.EntryVarBytes(entry_type, name, tag) + elif entry_type == "int" and not fixed_length: + newentry = factory.EntryInt(entry_type, name, tag) + elif entry_type == "int64" and not fixed_length: + newentry = factory.EntryInt(entry_type, name, tag, bits=64) + elif entry_type == "string" and not fixed_length: + newentry = factory.EntryString(entry_type, name, tag) + else: + res = STRUCT_REF_RE.match(entry_type) + if res: + # References another struct defined in our file + newentry = factory.EntryStruct(entry_type, name, tag, res.group("name")) + else: + raise RpcGenError('Bad type: "%s" in "%s"' % (entry_type, entry)) + + structs = [] + + if optional: + newentry.MakeOptional() + if array: + newentry.MakeArray() + + newentry.SetStruct(newstruct) + newentry.SetLineCount(LINE_COUNT) + newentry.Verify() + + if array: + # We need to encapsulate this entry into a struct + newentry = factory.EntryArray(newentry) + newentry.SetStruct(newstruct) + newentry.SetLineCount(LINE_COUNT) + newentry.MakeArray() + + newstruct.AddEntry(newentry) + + return structs + + +def ProcessStruct(factory, data): + tokens = data.split(" ") + + # First three tokens are: 'struct' 'name' '{' + newstruct = factory.Struct(tokens[1]) + + inside = " ".join(tokens[3:-1]) + + tokens = inside.split(";") + + structs = [] + + for entry in tokens: + entry = NormalizeLine(entry) + if not entry: + continue + + # It's possible that new structs get defined in here + structs.extend(ProcessOneEntry(factory, newstruct, entry)) + + structs.append(newstruct) + return structs + + +C_COMMENT_START = "/*" +C_COMMENT_END = "*/" + +C_COMMENT_START_RE = re.compile(re.escape(C_COMMENT_START)) +C_COMMENT_END_RE = re.compile(re.escape(C_COMMENT_END)) + +C_COMMENT_START_SUB_RE = re.compile(r"%s.*$" % (re.escape(C_COMMENT_START))) +C_COMMENT_END_SUB_RE = re.compile(r"%s.*$" % (re.escape(C_COMMENT_END))) + +C_MULTILINE_COMMENT_SUB_RE = re.compile( + r"%s.*?%s" % (re.escape(C_COMMENT_START), re.escape(C_COMMENT_END)) +) +CPP_CONDITIONAL_BLOCK_RE = re.compile(r"#(if( |def)|endif)") +INCLUDE_RE = re.compile(r'#include (".+"|<.+>)') + + +def GetNextStruct(filep): + global CPP_DIRECT + global LINE_COUNT + + got_struct = False + have_c_comment = False + + data = "" + + while True: + line = filep.readline() + if not line: + break + + LINE_COUNT += 1 + line = line[:-1] + + if not have_c_comment and C_COMMENT_START_RE.search(line): + if C_MULTILINE_COMMENT_SUB_RE.search(line): + line = C_MULTILINE_COMMENT_SUB_RE.sub("", line) + else: + line = C_COMMENT_START_SUB_RE.sub("", line) + have_c_comment = True + + if have_c_comment: + if not C_COMMENT_END_RE.search(line): + continue + have_c_comment = False + line = C_COMMENT_END_SUB_RE.sub("", line) + + line = NormalizeLine(line) + + if not line: + continue + + if not got_struct: + if INCLUDE_RE.match(line): + CPP_DIRECT.append(line) + elif CPP_CONDITIONAL_BLOCK_RE.match(line): + CPP_DIRECT.append(line) + elif PREPROCESSOR_DEF_RE.match(line): + HEADER_DIRECT.append(line) + elif not STRUCT_DEF_RE.match(line): + raise RpcGenError("Missing struct on line %d: %s" % (LINE_COUNT, line)) + else: + got_struct = True + data += line + continue + + # We are inside the struct + tokens = line.split("}") + if len(tokens) == 1: + data += " " + line + continue + + if tokens[1]: + raise RpcGenError("Trailing garbage after struct on line %d" % LINE_COUNT) + + # We found the end of the struct + data += " %s}" % tokens[0] + break + + # Remove any comments, that might be in there + data = re.sub(r"/\*.*\*/", "", data) + + return data + + +def Parse(factory, filep): + """ + Parses the input file and returns C code and corresponding header file. + """ + + entities = [] + + while 1: + # Just gets the whole struct nicely formatted + data = GetNextStruct(filep) + + if not data: + break + + entities.extend(ProcessStruct(factory, data)) + + return entities + + +class CCodeGenerator(object): + def __init__(self): + pass + + @staticmethod + def GuardName(name): + # Use the complete provided path to the input file, with all + # non-identifier characters replaced with underscores, to + # reduce the chance of a collision between guard macros. + return "EVENT_RPCOUT_%s_" % (NONIDENT_RE.sub("_", name).upper()) + + def HeaderPreamble(self, name): + guard = self.GuardName(name) + pre = """ +/* + * Automatically generated from %s + */ + +#ifndef %s +#define %s + +""" % ( + name, + guard, + guard, + ) + + if HEADER_DIRECT: + for statement in HEADER_DIRECT: + pre += "%s\n" % statement + pre += "\n" + + pre += """ +#include /* for ev_uint*_t */ +#include +""" + + return pre + + def HeaderPostamble(self, name): + guard = self.GuardName(name) + return "#endif /* %s */" % (guard) + + @staticmethod + def BodyPreamble(name, header_file): + global _NAME + global _VERSION + + slash = header_file.rfind("/") + if slash != -1: + header_file = header_file[slash + 1 :] + + pre = """ +/* + * Automatically generated from %(name)s + * by %(script_name)s/%(script_version)s. DO NOT EDIT THIS FILE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(EVENT__HAVE___func__) +# ifndef __func__ +# define __func__ __func__ +# endif +#elif defined(EVENT__HAVE___FUNCTION__) +# define __func__ __FUNCTION__ +#else +# define __func__ __FILE__ +#endif + +""" % { + "name": name, + "script_name": _NAME, + "script_version": _VERSION, + } + + for statement in CPP_DIRECT: + pre += "%s\n" % statement + + pre += '\n#include "%s"\n\n' % header_file + + pre += "void event_warn(const char *fmt, ...);\n" + pre += "void event_warnx(const char *fmt, ...);\n\n" + + return pre + + @staticmethod + def HeaderFilename(filename): + return ".".join(filename.split(".")[:-1]) + ".h" + + @staticmethod + def CodeFilename(filename): + return ".".join(filename.split(".")[:-1]) + ".gen.c" + + @staticmethod + def Struct(name): + return StructCCode(name) + + @staticmethod + def EntryBytes(entry_type, name, tag, fixed_length): + return EntryBytes(entry_type, name, tag, fixed_length) + + @staticmethod + def EntryVarBytes(entry_type, name, tag): + return EntryVarBytes(entry_type, name, tag) + + @staticmethod + def EntryInt(entry_type, name, tag, bits=32): + return EntryInt(entry_type, name, tag, bits) + + @staticmethod + def EntryString(entry_type, name, tag): + return EntryString(entry_type, name, tag) + + @staticmethod + def EntryStruct(entry_type, name, tag, struct_name): + return EntryStruct(entry_type, name, tag, struct_name) + + @staticmethod + def EntryArray(entry): + return EntryArray(entry) + + +class CommandLine(object): + def __init__(self, argv=None): + """Initialize a command-line to launch event_rpcgen, as if + from a command-line with CommandLine(sys.argv). If you're + calling this directly, remember to provide a dummy value + for sys.argv[0] + """ + global QUIETLY + + self.filename = None + self.header_file = None + self.impl_file = None + self.factory = CCodeGenerator() + + parser = argparse.ArgumentParser( + usage="%(prog)s [options] rpc-file [[h-file] c-file]" + ) + parser.add_argument("--quiet", action="store_true", default=False) + parser.add_argument("rpc_file", type=argparse.FileType("r")) + + args, extra_args = parser.parse_known_args(args=argv) + + QUIETLY = args.quiet + + if extra_args: + if len(extra_args) == 1: + self.impl_file = extra_args[0].replace("\\", "/") + elif len(extra_args) == 2: + self.header_file = extra_args[0].replace("\\", "/") + self.impl_file = extra_args[1].replace("\\", "/") + else: + parser.error("Spurious arguments provided") + + self.rpc_file = args.rpc_file + + if not self.impl_file: + self.impl_file = self.factory.CodeFilename(self.rpc_file.name) + + if not self.header_file: + self.header_file = self.factory.HeaderFilename(self.impl_file) + + if not self.impl_file.endswith(".c"): + parser.error("can only generate C implementation files") + if not self.header_file.endswith(".h"): + parser.error("can only generate C header files") + + def run(self): + filename = self.rpc_file.name + header_file = self.header_file + impl_file = self.impl_file + factory = self.factory + + declare('Reading "%s"' % filename) + + with self.rpc_file: + entities = Parse(factory, self.rpc_file) + + declare('... creating "%s"' % header_file) + with open(header_file, "w") as header_fp: + header_fp.write(factory.HeaderPreamble(filename)) + + # Create forward declarations: allows other structs to reference + # each other + for entry in entities: + entry.PrintForwardDeclaration(header_fp) + header_fp.write("\n") + + for entry in entities: + entry.PrintTags(header_fp) + entry.PrintDeclaration(header_fp) + header_fp.write(factory.HeaderPostamble(filename)) + + declare('... creating "%s"' % impl_file) + with open(impl_file, "w") as impl_fp: + impl_fp.write(factory.BodyPreamble(filename, header_file)) + for entry in entities: + entry.PrintCode(impl_fp) + + +def main(argv=None): + try: + CommandLine(argv=argv).run() + return 0 + except RpcGenError as e: + sys.stderr.write(e) + except EnvironmentError as e: + if e.filename and e.strerror: + sys.stderr.write("%s: %s" % (e.filename, e.strerror)) + elif e.strerror: + sys.stderr.write(e.strerror) + else: + raise + return 1 + + +if __name__ == "__main__": + sys.exit(main(argv=sys.argv[1:])) diff --git a/bsnes/thrift/libevent/include/evdns.h b/bsnes/thrift/libevent/include/evdns.h new file mode 100644 index 00000000..8672db03 --- /dev/null +++ b/bsnes/thrift/libevent/include/evdns.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT1_EVDNS_H_INCLUDED_ +#define EVENT1_EVDNS_H_INCLUDED_ + +/** @file evdns.h + + A dns subsystem for Libevent. + + The header is deprecated in Libevent 2.0 and later; please + use instead. Depending on what functionality you + need, you may also want to include more of the other + headers. + */ + +#include +#include +#include +#include + +#endif /* EVENT1_EVDNS_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/include/event.h b/bsnes/thrift/libevent/include/event.h new file mode 100644 index 00000000..ba518671 --- /dev/null +++ b/bsnes/thrift/libevent/include/event.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT1_EVENT_H_INCLUDED_ +#define EVENT1_EVENT_H_INCLUDED_ + +/** @file event.h + + A library for writing event-driven network servers. + + The header is deprecated in Libevent 2.0 and later; please + use instead. Depending on what functionality you + need, you may also want to include more of the other event2/ + headers. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif +#ifdef EVENT__HAVE_STDINT_H +#include +#endif +#include + +/* For int types. */ +#include + +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#undef WIN32_LEAN_AND_MEAN +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT1_EVENT_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/include/event2/buffer.h b/bsnes/thrift/libevent/include/event2/buffer.h new file mode 100644 index 00000000..88af3ae1 --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/buffer.h @@ -0,0 +1,1077 @@ +/* + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_BUFFER_H_INCLUDED_ +#define EVENT2_BUFFER_H_INCLUDED_ + +/** @file event2/buffer.h + + Functions for buffering data for network sending or receiving. + + An evbuffer can be used for preparing data before sending it to + the network or conversely for reading data from the network. + Evbuffers try to avoid memory copies as much as possible. As a + result, evbuffers can be used to pass data around without actually + incurring the overhead of copying the data. + + A new evbuffer can be allocated with evbuffer_new(), and can be + freed with evbuffer_free(). Most users will be using evbuffers via + the bufferevent interface. To access a bufferevent's evbuffers, use + bufferevent_get_input() and bufferevent_get_output(). + + There are several guidelines for using evbuffers. + + - if you already know how much data you are going to add as a result + of calling evbuffer_add() multiple times, it makes sense to use + evbuffer_expand() first to make sure that enough memory is allocated + before hand. + + - evbuffer_add_buffer() adds the contents of one buffer to the other + without incurring any unnecessary memory copies. + + - evbuffer_add() and evbuffer_add_buffer() do not mix very well: + if you use them, you will wind up with fragmented memory in your + buffer. + + - For high-performance code, you may want to avoid copying data into and out + of buffers. You can skip the copy step by using + evbuffer_reserve_space()/evbuffer_commit_space() when writing into a + buffer, and evbuffer_peek() when reading. + + In Libevent 2.0 and later, evbuffers are represented using a linked + list of memory chunks, with pointers to the first and last chunk in + the chain. + + As the contents of an evbuffer can be stored in multiple different + memory blocks, it cannot be accessed directly. Instead, evbuffer_pullup() + can be used to force a specified number of bytes to be contiguous. This + will cause memory reallocation and memory copies if the data is split + across multiple blocks. It is more efficient, however, to use + evbuffer_peek() if you don't require that the memory to be contiguous. + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_UIO_H +#include +#endif +#include + +/** + An evbuffer is an opaque data type for efficiently buffering data to be + sent or received on the network. + + @see event2/event.h for more information +*/ +struct evbuffer +#ifdef EVENT_IN_DOXYGEN_ +{} +#endif +; + +/** + Pointer to a position within an evbuffer. + + Used when repeatedly searching through a buffer. Calling any function + that modifies or re-packs the buffer contents may invalidate all + evbuffer_ptrs for that buffer. Do not modify or contruct these values + except with evbuffer_ptr_set. + + An evbuffer_ptr can represent any position from the start of a buffer up + to a position immediately after the end of a buffer. + + @see evbuffer_ptr_set() + */ +struct evbuffer_ptr { + ev_ssize_t pos; + + /* Do not alter or rely on the values of fields: they are for internal + * use */ + struct { + void *chain; + size_t pos_in_chain; + } internal_; +}; + +/** Describes a single extent of memory inside an evbuffer. Used for + direct-access functions. + + @see evbuffer_reserve_space, evbuffer_commit_space, evbuffer_peek + */ +#ifdef EVENT__HAVE_SYS_UIO_H +#define evbuffer_iovec iovec +/* Internal use -- defined only if we are using the native struct iovec */ +#define EVBUFFER_IOVEC_IS_NATIVE_ +#else +struct evbuffer_iovec { + /** The start of the extent of memory. */ + void *iov_base; + /** The length of the extent of memory. */ + size_t iov_len; +}; +#endif + +/** + Allocate storage for a new evbuffer. + + @return a pointer to a newly allocated evbuffer struct, or NULL if an error + occurred + */ +EVENT2_EXPORT_SYMBOL +struct evbuffer *evbuffer_new(void); +/** + Deallocate storage for an evbuffer. + + @param buf pointer to the evbuffer to be freed + */ +EVENT2_EXPORT_SYMBOL +void evbuffer_free(struct evbuffer *buf); + +/** + Enable locking on an evbuffer so that it can safely be used by multiple + threads at the same time. + + NOTE: when locking is enabled, the lock will be held when callbacks are + invoked. This could result in deadlock if you aren't careful. Plan + accordingly! + + @param buf An evbuffer to make lockable. + @param lock A lock object, or NULL if we should allocate our own. + @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_enable_locking(struct evbuffer *buf, void *lock); + +/** + Acquire the lock on an evbuffer. Has no effect if locking was not enabled + with evbuffer_enable_locking. +*/ +EVENT2_EXPORT_SYMBOL +void evbuffer_lock(struct evbuffer *buf); + +/** + Release the lock on an evbuffer. Has no effect if locking was not enabled + with evbuffer_enable_locking. +*/ +EVENT2_EXPORT_SYMBOL +void evbuffer_unlock(struct evbuffer *buf); + + +/** If this flag is set, then we will not use evbuffer_peek(), + * evbuffer_remove(), evbuffer_remove_buffer(), and so on to read bytes + * from this buffer: we'll only take bytes out of this buffer by + * writing them to the network (as with evbuffer_write_atmost), by + * removing them without observing them (as with evbuffer_drain), + * or by copying them all out at once (as with evbuffer_add_buffer). + * + * Using this option allows the implementation to use sendfile-based + * operations for evbuffer_add_file(); see that function for more + * information. + * + * This flag is on by default for bufferevents that can take advantage + * of it; you should never actually need to set it on a bufferevent's + * output buffer. + */ +#define EVBUFFER_FLAG_DRAINS_TO_FD 1 + +/** Change the flags that are set for an evbuffer by adding more. + * + * @param buffer the evbuffer that the callback is watching. + * @param cb the callback whose status we want to change. + * @param flags One or more EVBUFFER_FLAG_* options + * @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_set_flags(struct evbuffer *buf, ev_uint64_t flags); +/** Change the flags that are set for an evbuffer by removing some. + * + * @param buffer the evbuffer that the callback is watching. + * @param cb the callback whose status we want to change. + * @param flags One or more EVBUFFER_FLAG_* options + * @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_clear_flags(struct evbuffer *buf, ev_uint64_t flags); + +/** + Returns the total number of bytes stored in the evbuffer + + @param buf pointer to the evbuffer + @return the number of bytes stored in the evbuffer +*/ +EVENT2_EXPORT_SYMBOL +size_t evbuffer_get_length(const struct evbuffer *buf); + +/** + Returns the number of contiguous available bytes in the first buffer chain. + + This is useful when processing data that might be split into multiple + chains, or that might all be in the first chain. Calls to + evbuffer_pullup() that cause reallocation and copying of data can thus be + avoided. + + @param buf pointer to the evbuffer + @return 0 if no data is available, otherwise the number of available bytes + in the first buffer chain. +*/ +EVENT2_EXPORT_SYMBOL +size_t evbuffer_get_contiguous_space(const struct evbuffer *buf); + +/** + Expands the available space in an evbuffer. + + Expands the available space in the evbuffer to at least datlen, so that + appending datlen additional bytes will not require any new allocations. + + @param buf the evbuffer to be expanded + @param datlen the new minimum length requirement + @return 0 if successful, or -1 if an error occurred +*/ +EVENT2_EXPORT_SYMBOL +int evbuffer_expand(struct evbuffer *buf, size_t datlen); + +/** + Reserves space in the last chain or chains of an evbuffer. + + Makes space available in the last chain or chains of an evbuffer that can + be arbitrarily written to by a user. The space does not become + available for reading until it has been committed with + evbuffer_commit_space(). + + The space is made available as one or more extents, represented by + an initial pointer and a length. You can force the memory to be + available as only one extent. Allowing more extents, however, makes the + function more efficient. + + Multiple subsequent calls to this function will make the same space + available until evbuffer_commit_space() has been called. + + It is an error to do anything that moves around the buffer's internal + memory structures before committing the space. + + NOTE: The code currently does not ever use more than two extents. + This may change in future versions. + + @param buf the evbuffer in which to reserve space. + @param size how much space to make available, at minimum. The + total length of the extents may be greater than the requested + length. + @param vec an array of one or more evbuffer_iovec structures to + hold pointers to the reserved extents of memory. + @param n_vec The length of the vec array. Must be at least 1; + 2 is more efficient. + @return the number of provided extents, or -1 on error. + @see evbuffer_commit_space() +*/ +EVENT2_EXPORT_SYMBOL +int +evbuffer_reserve_space(struct evbuffer *buf, ev_ssize_t size, + struct evbuffer_iovec *vec, int n_vec); + +/** + Commits previously reserved space. + + Commits some of the space previously reserved with + evbuffer_reserve_space(). It then becomes available for reading. + + This function may return an error if the pointer in the extents do + not match those returned from evbuffer_reserve_space, or if data + has been added to the buffer since the space was reserved. + + If you want to commit less data than you got reserved space for, + modify the iov_len pointer of the appropriate extent to a smaller + value. Note that you may have received more space than you + requested if it was available! + + @param buf the evbuffer in which to reserve space. + @param vec one or two extents returned by evbuffer_reserve_space. + @param n_vecs the number of extents. + @return 0 on success, -1 on error + @see evbuffer_reserve_space() +*/ +EVENT2_EXPORT_SYMBOL +int evbuffer_commit_space(struct evbuffer *buf, + struct evbuffer_iovec *vec, int n_vecs); + +/** + Append data to the end of an evbuffer. + + @param buf the evbuffer to be appended to + @param data pointer to the beginning of the data buffer + @param datlen the number of bytes to be copied from the data buffer + @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen); + + +/** + Read data from an evbuffer and drain the bytes read. + + If more bytes are requested than are available in the evbuffer, we + only extract as many bytes as were available. + + @param buf the evbuffer to be read from + @param data the destination buffer to store the result + @param datlen the maximum size of the destination buffer + @return the number of bytes read, or -1 if we can't drain the buffer. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen); + +/** + Read data from an evbuffer, and leave the buffer unchanged. + + If more bytes are requested than are available in the evbuffer, we + only extract as many bytes as were available. + + @param buf the evbuffer to be read from + @param data_out the destination buffer to store the result + @param datlen the maximum size of the destination buffer + @return the number of bytes read, or -1 if we can't drain the buffer. + */ +EVENT2_EXPORT_SYMBOL +ev_ssize_t evbuffer_copyout(struct evbuffer *buf, void *data_out, size_t datlen); + +/** + Read data from the middle of an evbuffer, and leave the buffer unchanged. + + If more bytes are requested than are available in the evbuffer, we + only extract as many bytes as were available. + + @param buf the evbuffer to be read from + @param pos the position to start reading from + @param data_out the destination buffer to store the result + @param datlen the maximum size of the destination buffer + @return the number of bytes read, or -1 if we can't drain the buffer. + */ +EVENT2_EXPORT_SYMBOL +ev_ssize_t evbuffer_copyout_from(struct evbuffer *buf, const struct evbuffer_ptr *pos, void *data_out, size_t datlen); + +/** + Read data from an evbuffer into another evbuffer, draining + the bytes from the source buffer. This function avoids copy + operations to the extent possible. + + If more bytes are requested than are available in src, the src + buffer is drained completely. + + @param src the evbuffer to be read from + @param dst the destination evbuffer to store the result into + @param datlen the maximum numbers of bytes to transfer + @return the number of bytes read + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_remove_buffer(struct evbuffer *src, struct evbuffer *dst, + size_t datlen); + +/** Used to tell evbuffer_readln what kind of line-ending to look for. + */ +enum evbuffer_eol_style { + /** Any sequence of CR and LF characters is acceptable as an + * EOL. + * + * Note that this style can produce ambiguous results: the + * sequence "CRLF" will be treated as a single EOL if it is + * all in the buffer at once, but if you first read a CR from + * the network and later read an LF from the network, it will + * be treated as two EOLs. + */ + EVBUFFER_EOL_ANY, + /** An EOL is an LF, optionally preceded by a CR. This style is + * most useful for implementing text-based internet protocols. */ + EVBUFFER_EOL_CRLF, + /** An EOL is a CR followed by an LF. */ + EVBUFFER_EOL_CRLF_STRICT, + /** An EOL is a LF. */ + EVBUFFER_EOL_LF, + /** An EOL is a NUL character (that is, a single byte with value 0) */ + EVBUFFER_EOL_NUL +}; + +/** + * Read a single line from an evbuffer. + * + * Reads a line terminated by an EOL as determined by the evbuffer_eol_style + * argument. Returns a newly allocated nul-terminated string; the caller must + * free the returned value. The EOL is not included in the returned string. + * + * @param buffer the evbuffer to read from + * @param n_read_out if non-NULL, points to a size_t that is set to the + * number of characters in the returned string. This is useful for + * strings that can contain NUL characters. + * @param eol_style the style of line-ending to use. + * @return pointer to a single line, or NULL if an error occurred + */ +EVENT2_EXPORT_SYMBOL +char *evbuffer_readln(struct evbuffer *buffer, size_t *n_read_out, + enum evbuffer_eol_style eol_style); + +/** + Move all data from one evbuffer into another evbuffer. + + This is a destructive add. The data from one buffer moves into + the other buffer. However, no unnecessary memory copies occur. + + @param outbuf the output buffer + @param inbuf the input buffer + @return 0 if successful, or -1 if an error occurred + + @see evbuffer_remove_buffer() + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf); + +/** + Copy data from one evbuffer into another evbuffer. + + This is a non-destructive add. The data from one buffer is copied + into the other buffer. However, no unnecessary memory copies occur. + + Note that buffers already containing buffer references can't be added + to other buffers. + + @param outbuf the output buffer + @param inbuf the input buffer + @return 0 if successful, or -1 if an error occurred + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_add_buffer_reference(struct evbuffer *outbuf, + struct evbuffer *inbuf); + +/** + A cleanup function for a piece of memory added to an evbuffer by + reference. + + @see evbuffer_add_reference() + */ +typedef void (*evbuffer_ref_cleanup_cb)(const void *data, + size_t datalen, void *extra); + +/** + Reference memory into an evbuffer without copying. + + The memory needs to remain valid until all the added data has been + read. This function keeps just a reference to the memory without + actually incurring the overhead of a copy. + + @param outbuf the output buffer + @param data the memory to reference + @param datlen how memory to reference + @param cleanupfn callback to be invoked when the memory is no longer + referenced by this evbuffer. + @param cleanupfn_arg optional argument to the cleanup callback + @return 0 if successful, or -1 if an error occurred + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_add_reference(struct evbuffer *outbuf, + const void *data, size_t datlen, + evbuffer_ref_cleanup_cb cleanupfn, void *cleanupfn_arg); + +/** + Copy data from a file into the evbuffer for writing to a socket. + + This function avoids unnecessary data copies between userland and + kernel. If sendfile is available and the EVBUFFER_FLAG_DRAINS_TO_FD + flag is set, it uses those functions. Otherwise, it tries to use + mmap (or CreateFileMapping on Windows). + + The function owns the resulting file descriptor and will close it + when finished transferring data. + + The results of using evbuffer_remove() or evbuffer_pullup() on + evbuffers whose data was added using this function are undefined. + + For more fine-grained control, use evbuffer_add_file_segment. + + @param outbuf the output buffer + @param fd the file descriptor + @param offset the offset from which to read data + @param length how much data to read, or -1 to read as much as possible. + (-1 requires that 'fd' support fstat.) + @return 0 if successful, or -1 if an error occurred +*/ + +EVENT2_EXPORT_SYMBOL +int evbuffer_add_file(struct evbuffer *outbuf, int fd, ev_off_t offset, + ev_off_t length); + +/** + An evbuffer_file_segment holds a reference to a range of a file -- + possibly the whole file! -- for use in writing from an evbuffer to a + socket. It could be implemented with mmap, sendfile, splice, or (if all + else fails) by just pulling all the data into RAM. A single + evbuffer_file_segment can be added more than once, and to more than one + evbuffer. + */ +struct evbuffer_file_segment; + +/** + Flag for creating evbuffer_file_segment: If this flag is set, then when + the evbuffer_file_segment is freed and no longer in use by any + evbuffer, the underlying fd is closed. + */ +#define EVBUF_FS_CLOSE_ON_FREE 0x01 +/** + Flag for creating evbuffer_file_segment: Disable memory-map based + implementations. + */ +#define EVBUF_FS_DISABLE_MMAP 0x02 +/** + Flag for creating evbuffer_file_segment: Disable direct fd-to-fd + implementations (including sendfile and splice). + + You might want to use this option if data needs to be taken from the + evbuffer by any means other than writing it to the network: the sendfile + backend is fast, but it only works for sending files directly to the + network. + */ +#define EVBUF_FS_DISABLE_SENDFILE 0x04 +/** + Flag for creating evbuffer_file_segment: Do not allocate a lock for this + segment. If this option is set, then neither the segment nor any + evbuffer it is added to may ever be accessed from more than one thread + at a time. + */ +#define EVBUF_FS_DISABLE_LOCKING 0x08 + +/** + A cleanup function for a evbuffer_file_segment added to an evbuffer + for reference. + */ +typedef void (*evbuffer_file_segment_cleanup_cb)( + struct evbuffer_file_segment const* seg, int flags, void* arg); + +/** + Create and return a new evbuffer_file_segment for reading data from a + file and sending it out via an evbuffer. + + This function avoids unnecessary data copies between userland and + kernel. Where available, it uses sendfile or splice. + + The file descriptor must not be closed so long as any evbuffer is using + this segment. + + The results of using evbuffer_remove() or evbuffer_pullup() or any other + function that reads bytes from an evbuffer on any evbuffer containing + the newly returned segment are undefined, unless you pass the + EVBUF_FS_DISABLE_SENDFILE flag to this function. + + @param fd an open file to read from. + @param offset an index within the file at which to start reading + @param length how much data to read, or -1 to read as much as possible. + (-1 requires that 'fd' support fstat.) + @param flags any number of the EVBUF_FS_* flags + @return a new evbuffer_file_segment, or NULL on failure. + **/ +EVENT2_EXPORT_SYMBOL +struct evbuffer_file_segment *evbuffer_file_segment_new( + int fd, ev_off_t offset, ev_off_t length, unsigned flags); + +/** + Free an evbuffer_file_segment + + It is safe to call this function even if the segment has been added to + one or more evbuffers. The evbuffer_file_segment will not be freed + until no more references to it exist. + */ +EVENT2_EXPORT_SYMBOL +void evbuffer_file_segment_free(struct evbuffer_file_segment *seg); + +/** + Add cleanup callback and argument for the callback to an + evbuffer_file_segment. + + The cleanup callback will be invoked when no more references to the + evbuffer_file_segment exist. + **/ +EVENT2_EXPORT_SYMBOL +void evbuffer_file_segment_add_cleanup_cb(struct evbuffer_file_segment *seg, + evbuffer_file_segment_cleanup_cb cb, void* arg); + +/** + Insert some or all of an evbuffer_file_segment at the end of an evbuffer + + Note that the offset and length parameters of this function have a + different meaning from those provided to evbuffer_file_segment_new: When + you create the segment, the offset is the offset _within the file_, and + the length is the length _of the segment_, whereas when you add a + segment to an evbuffer, the offset is _within the segment_ and the + length is the length of the _part of the segment you want to use. + + In other words, if you have a 10 KiB file, and you create an + evbuffer_file_segment for it with offset 20 and length 1000, it will + refer to bytes 20..1019 inclusive. If you then pass this segment to + evbuffer_add_file_segment and specify an offset of 20 and a length of + 50, you will be adding bytes 40..99 inclusive. + + @param buf the evbuffer to append to + @param seg the segment to add + @param offset the offset within the segment to start from + @param length the amount of data to add, or -1 to add it all. + @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_add_file_segment(struct evbuffer *buf, + struct evbuffer_file_segment *seg, ev_off_t offset, ev_off_t length); + +/** + Append a formatted string to the end of an evbuffer. + + The string is formated as printf. + + @param buf the evbuffer that will be appended to + @param fmt a format string + @param ... arguments that will be passed to printf(3) + @return The number of bytes added if successful, or -1 if an error occurred. + + @see evutil_printf(), evbuffer_add_vprintf() + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...) +#ifdef __GNUC__ + __attribute__((format(printf, 2, 3))) +#endif +; + +/** + Append a va_list formatted string to the end of an evbuffer. + + @param buf the evbuffer that will be appended to + @param fmt a format string + @param ap a varargs va_list argument array that will be passed to vprintf(3) + @return The number of bytes added if successful, or -1 if an error occurred. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap) +#ifdef __GNUC__ + __attribute__((format(printf, 2, 0))) +#endif +; + + +/** + Remove a specified number of bytes data from the beginning of an evbuffer. + + @param buf the evbuffer to be drained + @param len the number of bytes to drain from the beginning of the buffer + @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_drain(struct evbuffer *buf, size_t len); + + +/** + Write the contents of an evbuffer to a file descriptor. + + The evbuffer will be drained after the bytes have been successfully written. + + @param buffer the evbuffer to be written and drained + @param fd the file descriptor to be written to + @return the number of bytes written, or -1 if an error occurred + @see evbuffer_read() + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_write(struct evbuffer *buffer, evutil_socket_t fd); + +/** + Write some of the contents of an evbuffer to a file descriptor. + + The evbuffer will be drained after the bytes have been successfully written. + + @param buffer the evbuffer to be written and drained + @param fd the file descriptor to be written to + @param howmuch the largest allowable number of bytes to write, or -1 + to write as many bytes as we can. + @return the number of bytes written, or -1 if an error occurred + @see evbuffer_read() + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_write_atmost(struct evbuffer *buffer, evutil_socket_t fd, + ev_ssize_t howmuch); + +/** + Read from a file descriptor and store the result in an evbuffer. + + @param buffer the evbuffer to store the result + @param fd the file descriptor to read from + @param howmuch the number of bytes to be read. If the given number is negative + or out of maximum bytes per one read, as many bytes as we can will be read. + @return the number of bytes read, or -1 if an error occurred + @see evbuffer_write() + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_read(struct evbuffer *buffer, evutil_socket_t fd, int howmuch); + +/** + Search for a string within an evbuffer. + + @param buffer the evbuffer to be searched + @param what the string to be searched for + @param len the length of the search string + @param start NULL or a pointer to a valid struct evbuffer_ptr. + @return a struct evbuffer_ptr whose 'pos' field has the offset of the + first occurrence of the string in the buffer after 'start'. The 'pos' + field of the result is -1 if the string was not found. + */ +EVENT2_EXPORT_SYMBOL +struct evbuffer_ptr evbuffer_search(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start); + +/** + Search for a string within part of an evbuffer. + + @param buffer the evbuffer to be searched + @param what the string to be searched for + @param len the length of the search string + @param start NULL or a pointer to a valid struct evbuffer_ptr that + indicates where we should start searching. + @param end NULL or a pointer to a valid struct evbuffer_ptr that + indicates where we should stop searching. + @return a struct evbuffer_ptr whose 'pos' field has the offset of the + first occurrence of the string in the buffer after 'start'. The 'pos' + field of the result is -1 if the string was not found. + */ +EVENT2_EXPORT_SYMBOL +struct evbuffer_ptr evbuffer_search_range(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start, const struct evbuffer_ptr *end); + +/** + Defines how to adjust an evbuffer_ptr by evbuffer_ptr_set() + + @see evbuffer_ptr_set() */ +enum evbuffer_ptr_how { + /** Sets the pointer to the position; can be called on with an + uninitialized evbuffer_ptr. */ + EVBUFFER_PTR_SET, + /** Advances the pointer by adding to the current position. */ + EVBUFFER_PTR_ADD +}; + +/** + Sets the search pointer in the buffer to position. + + There are two ways to use this function: you can call + evbuffer_ptr_set(buf, &pos, N, EVBUFFER_PTR_SET) + to move 'pos' to a position 'N' bytes after the start of the buffer, or + evbuffer_ptr_set(buf, &pos, N, EVBUFFER_PTR_ADD) + to move 'pos' forward by 'N' bytes. + + If evbuffer_ptr is not initialized, this function can only be called + with EVBUFFER_PTR_SET. + + An evbuffer_ptr can represent any position from the start of the buffer to + a position immediately after the end of the buffer. + + @param buffer the evbuffer to be search + @param ptr a pointer to a struct evbuffer_ptr + @param position the position at which to start the next search + @param how determines how the pointer should be manipulated. + @returns 0 on success or -1 otherwise +*/ +EVENT2_EXPORT_SYMBOL +int +evbuffer_ptr_set(struct evbuffer *buffer, struct evbuffer_ptr *ptr, + size_t position, enum evbuffer_ptr_how how); + +/** + Search for an end-of-line string within an evbuffer. + + @param buffer the evbuffer to be searched + @param start NULL or a pointer to a valid struct evbuffer_ptr to start + searching at. + @param eol_len_out If non-NULL, the pointed-to value will be set to + the length of the end-of-line string. + @param eol_style The kind of EOL to look for; see evbuffer_readln() for + more information + @return a struct evbuffer_ptr whose 'pos' field has the offset of the + first occurrence EOL in the buffer after 'start'. The 'pos' + field of the result is -1 if the string was not found. + */ +EVENT2_EXPORT_SYMBOL +struct evbuffer_ptr evbuffer_search_eol(struct evbuffer *buffer, + struct evbuffer_ptr *start, size_t *eol_len_out, + enum evbuffer_eol_style eol_style); + +/** Function to peek at data inside an evbuffer without removing it or + copying it out. + + Pointers to the data are returned by filling the 'vec_out' array + with pointers to one or more extents of data inside the buffer. + + The total data in the extents that you get back may be more than + you requested (if there is more data last extent than you asked + for), or less (if you do not provide enough evbuffer_iovecs, or if + the buffer does not have as much data as you asked to see). + + @param buffer the evbuffer to peek into, + @param len the number of bytes to try to peek. If len is negative, we + will try to fill as much of vec_out as we can. If len is negative + and vec_out is not provided, we return the number of evbuffer_iovecs + that would be needed to get all the data in the buffer. + @param start_at an evbuffer_ptr indicating the point at which we + should start looking for data. NULL means, "At the start of the + buffer." + @param vec_out an array of evbuffer_iovec + @param n_vec the length of vec_out. If 0, we only count how many + extents would be necessary to point to the requested amount of + data. + @return The number of extents needed. This may be less than n_vec + if we didn't need all the evbuffer_iovecs we were given, or more + than n_vec if we would need more to return all the data that was + requested. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_peek(struct evbuffer *buffer, ev_ssize_t len, + struct evbuffer_ptr *start_at, + struct evbuffer_iovec *vec_out, int n_vec); + + +/** Structure passed to an evbuffer_cb_func evbuffer callback + + @see evbuffer_cb_func, evbuffer_add_cb() + */ +struct evbuffer_cb_info { + /** The number of bytes in this evbuffer when callbacks were last + * invoked. */ + size_t orig_size; + /** The number of bytes added since callbacks were last invoked. */ + size_t n_added; + /** The number of bytes removed since callbacks were last invoked. */ + size_t n_deleted; +}; + +/** Type definition for a callback that is invoked whenever data is added or + removed from an evbuffer. + + An evbuffer may have one or more callbacks set at a time. The order + in which they are executed is undefined. + + A callback function may add more callbacks, or remove itself from the + list of callbacks, or add or remove data from the buffer. It may not + remove another callback from the list. + + If a callback adds or removes data from the buffer or from another + buffer, this can cause a recursive invocation of your callback or + other callbacks. If you ask for an infinite loop, you might just get + one: watch out! + + @param buffer the buffer whose size has changed + @param info a structure describing how the buffer changed. + @param arg a pointer to user data +*/ +typedef void (*evbuffer_cb_func)(struct evbuffer *buffer, const struct evbuffer_cb_info *info, void *arg); + +struct evbuffer_cb_entry; +/** Add a new callback to an evbuffer. + + Subsequent calls to evbuffer_add_cb() add new callbacks. To remove this + callback, call evbuffer_remove_cb or evbuffer_remove_cb_entry. + + @param buffer the evbuffer to be monitored + @param cb the callback function to invoke when the evbuffer is modified, + or NULL to remove all callbacks. + @param cbarg an argument to be provided to the callback function + @return a handle to the callback on success, or NULL on failure. + */ +EVENT2_EXPORT_SYMBOL +struct evbuffer_cb_entry *evbuffer_add_cb(struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg); + +/** Remove a callback from an evbuffer, given a handle returned from + evbuffer_add_cb. + + Calling this function invalidates the handle. + + @return 0 if a callback was removed, or -1 if no matching callback was + found. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_remove_cb_entry(struct evbuffer *buffer, + struct evbuffer_cb_entry *ent); + +/** Remove a callback from an evbuffer, given the function and argument + used to add it. + + @return 0 if a callback was removed, or -1 if no matching callback was + found. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_remove_cb(struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg); + +/** If this flag is not set, then a callback is temporarily disabled, and + * should not be invoked. + * + * @see evbuffer_cb_set_flags(), evbuffer_cb_clear_flags() + */ +#define EVBUFFER_CB_ENABLED 1 + +/** Change the flags that are set for a callback on a buffer by adding more. + + @param buffer the evbuffer that the callback is watching. + @param cb the callback whose status we want to change. + @param flags EVBUFFER_CB_ENABLED to re-enable the callback. + @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_cb_set_flags(struct evbuffer *buffer, + struct evbuffer_cb_entry *cb, ev_uint32_t flags); + +/** Change the flags that are set for a callback on a buffer by removing some + + @param buffer the evbuffer that the callback is watching. + @param cb the callback whose status we want to change. + @param flags EVBUFFER_CB_ENABLED to disable the callback. + @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_cb_clear_flags(struct evbuffer *buffer, + struct evbuffer_cb_entry *cb, ev_uint32_t flags); + +#if 0 +/** Postpone calling a given callback until unsuspend is called later. + + This is different from disabling the callback, since the callback will get + invoked later if the buffer size changes between now and when we unsuspend + it. + + @param the buffer that the callback is watching. + @param cb the callback we want to suspend. + */ +EVENT2_EXPORT_SYMBOL +void evbuffer_cb_suspend(struct evbuffer *buffer, struct evbuffer_cb_entry *cb); +/** Stop postponing a callback that we postponed with evbuffer_cb_suspend. + + If data was added to or removed from the buffer while the callback was + suspended, the callback will get called once now. + + @param the buffer that the callback is watching. + @param cb the callback we want to stop suspending. + */ +EVENT2_EXPORT_SYMBOL +void evbuffer_cb_unsuspend(struct evbuffer *buffer, struct evbuffer_cb_entry *cb); +#endif + +/** + Makes the data at the beginning of an evbuffer contiguous. + + @param buf the evbuffer to make contiguous + @param size the number of bytes to make contiguous, or -1 to make the + entire buffer contiguous. + @return a pointer to the contiguous memory array, or NULL if param size + requested more data than is present in the buffer. +*/ + +EVENT2_EXPORT_SYMBOL +unsigned char *evbuffer_pullup(struct evbuffer *buf, ev_ssize_t size); + +/** + Prepends data to the beginning of the evbuffer + + @param buf the evbuffer to which to prepend data + @param data a pointer to the memory to prepend + @param size the number of bytes to prepend + @return 0 if successful, or -1 otherwise +*/ + +EVENT2_EXPORT_SYMBOL +int evbuffer_prepend(struct evbuffer *buf, const void *data, size_t size); + +/** + Prepends all data from the src evbuffer to the beginning of the dst + evbuffer. + + @param dst the evbuffer to which to prepend data + @param src the evbuffer to prepend; it will be emptied as a result + @return 0 if successful, or -1 otherwise +*/ +EVENT2_EXPORT_SYMBOL +int evbuffer_prepend_buffer(struct evbuffer *dst, struct evbuffer* src); + +/** + Prevent calls that modify an evbuffer from succeeding. A buffer may + frozen at the front, at the back, or at both the front and the back. + + If the front of a buffer is frozen, operations that drain data from + the front of the buffer, or that prepend data to the buffer, will + fail until it is unfrozen. If the back a buffer is frozen, operations + that append data from the buffer will fail until it is unfrozen. + + @param buf The buffer to freeze + @param at_front If true, we freeze the front of the buffer. If false, + we freeze the back. + @return 0 on success, -1 on failure. +*/ +EVENT2_EXPORT_SYMBOL +int evbuffer_freeze(struct evbuffer *buf, int at_front); +/** + Re-enable calls that modify an evbuffer. + + @param buf The buffer to un-freeze + @param at_front If true, we unfreeze the front of the buffer. If false, + we unfreeze the back. + @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_unfreeze(struct evbuffer *buf, int at_front); + +struct event_base; +/** + Force all the callbacks on an evbuffer to be run, not immediately after + the evbuffer is altered, but instead from inside the event loop. + + This can be used to serialize all the callbacks to a single thread + of execution. + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_defer_callbacks(struct evbuffer *buffer, struct event_base *base); + +/** + Append data from 1 or more iovec's to an evbuffer + + Calculates the number of bytes needed for an iovec structure and guarantees + all data will fit into a single chain. Can be used in lieu of functionality + which calls evbuffer_add() constantly before being used to increase + performance. + + @param buffer the destination buffer + @param vec the source iovec + @param n_vec the number of iovec structures. + @return the number of bytes successfully written to the output buffer. +*/ +EVENT2_EXPORT_SYMBOL +size_t evbuffer_add_iovec(struct evbuffer * buffer, struct evbuffer_iovec * vec, int n_vec); + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_BUFFER_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/include/event2/buffer_compat.h b/bsnes/thrift/libevent/include/event2/buffer_compat.h new file mode 100644 index 00000000..0ce10254 --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/buffer_compat.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EVENT2_BUFFER_COMPAT_H_INCLUDED_ +#define EVENT2_BUFFER_COMPAT_H_INCLUDED_ + +#include + +/** @file event2/buffer_compat.h + + Obsolete and deprecated versions of the functions in buffer.h: provided + only for backward compatibility. + */ + + +/** + Obsolete alias for evbuffer_readln(buffer, NULL, EVBUFFER_EOL_ANY). + + @deprecated This function is deprecated because its behavior is not correct + for almost any protocol, and also because it's wholly subsumed by + evbuffer_readln(). + + @param buffer the evbuffer to read from + @return pointer to a single line, or NULL if an error occurred + +*/ +EVENT2_EXPORT_SYMBOL +char *evbuffer_readline(struct evbuffer *buffer); + +/** Type definition for a callback that is invoked whenever data is added or + removed from an evbuffer. + + An evbuffer may have one or more callbacks set at a time. The order + in which they are executed is undefined. + + A callback function may add more callbacks, or remove itself from the + list of callbacks, or add or remove data from the buffer. It may not + remove another callback from the list. + + If a callback adds or removes data from the buffer or from another + buffer, this can cause a recursive invocation of your callback or + other callbacks. If you ask for an infinite loop, you might just get + one: watch out! + + @param buffer the buffer whose size has changed + @param old_len the previous length of the buffer + @param new_len the current length of the buffer + @param arg a pointer to user data +*/ +typedef void (*evbuffer_cb)(struct evbuffer *buffer, size_t old_len, size_t new_len, void *arg); + +/** + Replace all callbacks on an evbuffer with a single new callback, or + remove them. + + Subsequent calls to evbuffer_setcb() replace callbacks set by previous + calls. Setting the callback to NULL removes any previously set callback. + + @deprecated This function is deprecated because it clears all previous + callbacks set on the evbuffer, which can cause confusing behavior if + multiple parts of the code all want to add their own callbacks on a + buffer. Instead, use evbuffer_add(), evbuffer_del(), and + evbuffer_setflags() to manage your own evbuffer callbacks without + interfering with callbacks set by others. + + @param buffer the evbuffer to be monitored + @param cb the callback function to invoke when the evbuffer is modified, + or NULL to remove all callbacks. + @param cbarg an argument to be provided to the callback function + @return 0 if successful, or -1 on error + */ +EVENT2_EXPORT_SYMBOL +int evbuffer_setcb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg); + + +/** + Find a string within an evbuffer. + + @param buffer the evbuffer to be searched + @param what the string to be searched for + @param len the length of the search string + @return a pointer to the beginning of the search string, or NULL if the search failed. + */ +EVENT2_EXPORT_SYMBOL +unsigned char *evbuffer_find(struct evbuffer *buffer, const unsigned char *what, size_t len); + +/** deprecated in favor of calling the functions directly */ +#define EVBUFFER_LENGTH(x) evbuffer_get_length(x) +/** deprecated in favor of calling the functions directly */ +#define EVBUFFER_DATA(x) evbuffer_pullup((x), -1) + +#endif + diff --git a/bsnes/thrift/libevent/include/event2/bufferevent.h b/bsnes/thrift/libevent/include/event2/bufferevent.h new file mode 100644 index 00000000..48cd1535 --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/bufferevent.h @@ -0,0 +1,1024 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_BUFFEREVENT_H_INCLUDED_ +#define EVENT2_BUFFEREVENT_H_INCLUDED_ + +/** + @file event2/bufferevent.h + + Functions for buffering data for network sending or receiving. Bufferevents + are higher level than evbuffers: each has an underlying evbuffer for reading + and one for writing, and callbacks that are invoked under certain + circumstances. + + A bufferevent provides input and output buffers that get filled and + drained automatically. The user of a bufferevent no longer deals + directly with the I/O, but instead is reading from input and writing + to output buffers. + + Once initialized, the bufferevent structure can be used repeatedly + with bufferevent_enable() and bufferevent_disable(). + + When reading is enabled, the bufferevent will try to read from the + file descriptor onto its input buffer, and call the read callback. + When writing is enabled, the bufferevent will try to write data onto its + file descriptor when the output buffer has enough data, and call the write + callback when the output buffer is sufficiently drained. + + Bufferevents come in several flavors, including: + +
+
Socket-based bufferevents
+
A bufferevent that reads and writes data onto a network + socket. Created with bufferevent_socket_new().
+ +
Paired bufferevents
+
A pair of bufferevents that send and receive data to one + another without touching the network. Created with + bufferevent_pair_new().
+ +
Filtering bufferevents
+
A bufferevent that transforms data, and sends or receives it + over another underlying bufferevent. Created with + bufferevent_filter_new().
+ +
SSL-backed bufferevents
+
A bufferevent that uses the openssl library to send and + receive data over an encrypted connection. Created with + bufferevent_openssl_socket_new() or + bufferevent_openssl_filter_new().
+
+ */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif + +/* For int types. */ +#include + +/** @name Bufferevent event codes + + These flags are passed as arguments to a bufferevent's event callback. + + @{ +*/ +#define BEV_EVENT_READING 0x01 /**< error encountered while reading */ +#define BEV_EVENT_WRITING 0x02 /**< error encountered while writing */ +#define BEV_EVENT_EOF 0x10 /**< eof file reached */ +#define BEV_EVENT_ERROR 0x20 /**< unrecoverable error encountered */ +#define BEV_EVENT_TIMEOUT 0x40 /**< user-specified timeout reached */ +#define BEV_EVENT_CONNECTED 0x80 /**< connect operation finished. */ +/**@}*/ + +/** + An opaque type for handling buffered IO + + @see event2/bufferevent.h + */ +struct bufferevent +#ifdef EVENT_IN_DOXYGEN_ +{} +#endif +; +struct event_base; +struct evbuffer; +struct sockaddr; + +/** + A read or write callback for a bufferevent. + + The read callback is triggered when new data arrives in the input + buffer and the amount of readable data exceed the low watermark + which is 0 by default. + + The write callback is triggered if the write buffer has been + exhausted or fell below its low watermark. + + @param bev the bufferevent that triggered the callback + @param ctx the user-specified context for this bufferevent + */ +typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx); + +/** + An event/error callback for a bufferevent. + + The event callback is triggered if either an EOF condition or another + unrecoverable error was encountered. + + For bufferevents with deferred callbacks, this is a bitwise OR of all errors + that have happened on the bufferevent since the last callback invocation. + + @param bev the bufferevent for which the error condition was reached + @param what a conjunction of flags: BEV_EVENT_READING or BEV_EVENT_WRITING + to indicate if the error was encountered on the read or write path, + and one of the following flags: BEV_EVENT_EOF, BEV_EVENT_ERROR, + BEV_EVENT_TIMEOUT, BEV_EVENT_CONNECTED. + + @param ctx the user-specified context for this bufferevent +*/ +typedef void (*bufferevent_event_cb)(struct bufferevent *bev, short what, void *ctx); + +/** Options that can be specified when creating a bufferevent */ +enum bufferevent_options { + /** If set, we close the underlying file + * descriptor/bufferevent/whatever when this bufferevent is freed. */ + BEV_OPT_CLOSE_ON_FREE = (1<<0), + + /** If set, and threading is enabled, operations on this bufferevent + * are protected by a lock */ + BEV_OPT_THREADSAFE = (1<<1), + + /** If set, callbacks are run deferred in the event loop. */ + BEV_OPT_DEFER_CALLBACKS = (1<<2), + + /** If set, callbacks are executed without locks being held on the + * bufferevent. This option currently requires that + * BEV_OPT_DEFER_CALLBACKS also be set; a future version of Libevent + * might remove the requirement.*/ + BEV_OPT_UNLOCK_CALLBACKS = (1<<3) +}; + +/** + Create a new socket bufferevent over an existing socket. + + @param base the event base to associate with the new bufferevent. + @param fd the file descriptor from which data is read and written to. + This file descriptor is not allowed to be a pipe(2). + It is safe to set the fd to -1, so long as you later + set it with bufferevent_setfd or bufferevent_socket_connect(). + @param options Zero or more BEV_OPT_* flags + @return a pointer to a newly allocated bufferevent struct, or NULL if an + error occurred + @see bufferevent_free() + */ +EVENT2_EXPORT_SYMBOL +struct bufferevent *bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, int options); + +/** + Launch a connect() attempt with a socket-based bufferevent. + + When the connect succeeds, the eventcb will be invoked with + BEV_EVENT_CONNECTED set. + + If the bufferevent does not already have a socket set, we allocate a new + socket here and make it nonblocking before we begin. + + If no address is provided, we assume that the socket is already connecting, + and configure the bufferevent so that a BEV_EVENT_CONNECTED event will be + yielded when it is done connecting. + + @param bufev an existing bufferevent allocated with + bufferevent_socket_new(). + @param addr the address we should connect to + @param socklen The length of the address + @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_socket_connect(struct bufferevent *, const struct sockaddr *, int); + +struct evdns_base; +/** + Resolve the hostname 'hostname' and connect to it as with + bufferevent_socket_connect(). + + @param bufev An existing bufferevent allocated with bufferevent_socket_new() + @param evdns_base Optionally, an evdns_base to use for resolving hostnames + asynchronously. May be set to NULL for a blocking resolve. + @param family A preferred address family to resolve addresses to, or + AF_UNSPEC for no preference. Only AF_INET, AF_INET6, and AF_UNSPEC are + supported. + @param hostname The hostname to resolve; see below for notes on recognized + formats + @param port The port to connect to on the resolved address. + @return 0 if successful, -1 on failure. + + Recognized hostname formats are: + + www.example.com (hostname) + 1.2.3.4 (ipv4address) + ::1 (ipv6address) + [::1] ([ipv6address]) + + Performance note: If you do not provide an evdns_base, this function + may block while it waits for a DNS response. This is probably not + what you want. + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_socket_connect_hostname(struct bufferevent *, + struct evdns_base *, int, const char *, int); + +/** + Return the error code for the last failed DNS lookup attempt made by + bufferevent_socket_connect_hostname(). + + @param bev The bufferevent object. + @return DNS error code. + @see evutil_gai_strerror() +*/ +EVENT2_EXPORT_SYMBOL +int bufferevent_socket_get_dns_error(struct bufferevent *bev); + +/** + Assign a bufferevent to a specific event_base. + + NOTE that only socket bufferevents support this function. + + @param base an event_base returned by event_init() + @param bufev a bufferevent struct returned by bufferevent_new() + or bufferevent_socket_new() + @return 0 if successful, or -1 if an error occurred + @see bufferevent_new() + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_base_set(struct event_base *base, struct bufferevent *bufev); + +/** + Return the event_base used by a bufferevent +*/ +EVENT2_EXPORT_SYMBOL +struct event_base *bufferevent_get_base(struct bufferevent *bev); + +/** + Assign a priority to a bufferevent. + + Only supported for socket bufferevents. + + @param bufev a bufferevent struct + @param pri the priority to be assigned + @return 0 if successful, or -1 if an error occurred + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_priority_set(struct bufferevent *bufev, int pri); + +/** + Return the priority of a bufferevent. + + Only supported for socket bufferevents + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_get_priority(const struct bufferevent *bufev); + +/** + Deallocate the storage associated with a bufferevent structure. + + If there is pending data to write on the bufferevent, it probably won't be + flushed before the bufferevent is freed. + + @param bufev the bufferevent structure to be freed. + */ +EVENT2_EXPORT_SYMBOL +void bufferevent_free(struct bufferevent *bufev); + + +/** + Changes the callbacks for a bufferevent. + + @param bufev the bufferevent object for which to change callbacks + @param readcb callback to invoke when there is data to be read, or NULL if + no callback is desired + @param writecb callback to invoke when the file descriptor is ready for + writing, or NULL if no callback is desired + @param eventcb callback to invoke when there is an event on the file + descriptor + @param cbarg an argument that will be supplied to each of the callbacks + (readcb, writecb, and errorcb) + @see bufferevent_new() + */ +EVENT2_EXPORT_SYMBOL +void bufferevent_setcb(struct bufferevent *bufev, + bufferevent_data_cb readcb, bufferevent_data_cb writecb, + bufferevent_event_cb eventcb, void *cbarg); + +/** + Retrieves the callbacks for a bufferevent. + + @param bufev the bufferevent to examine. + @param readcb_ptr if readcb_ptr is nonnull, *readcb_ptr is set to the current + read callback for the bufferevent. + @param writecb_ptr if writecb_ptr is nonnull, *writecb_ptr is set to the + current write callback for the bufferevent. + @param eventcb_ptr if eventcb_ptr is nonnull, *eventcb_ptr is set to the + current event callback for the bufferevent. + @param cbarg_ptr if cbarg_ptr is nonnull, *cbarg_ptr is set to the current + callback argument for the bufferevent. + @see buffervent_setcb() +*/ +EVENT2_EXPORT_SYMBOL +void bufferevent_getcb(struct bufferevent *bufev, + bufferevent_data_cb *readcb_ptr, + bufferevent_data_cb *writecb_ptr, + bufferevent_event_cb *eventcb_ptr, + void **cbarg_ptr); + +/** + Changes the file descriptor on which the bufferevent operates. + Not supported for all bufferevent types. + + @param bufev the bufferevent object for which to change the file descriptor + @param fd the file descriptor to operate on +*/ +EVENT2_EXPORT_SYMBOL +int bufferevent_setfd(struct bufferevent *bufev, evutil_socket_t fd); + +/** + Returns the file descriptor associated with a bufferevent, or -1 if + no file descriptor is associated with the bufferevent. + */ +EVENT2_EXPORT_SYMBOL +evutil_socket_t bufferevent_getfd(struct bufferevent *bufev); + +/** + Returns the underlying bufferevent associated with a bufferevent (if + the bufferevent is a wrapper), or NULL if there is no underlying bufferevent. + */ +EVENT2_EXPORT_SYMBOL +struct bufferevent *bufferevent_get_underlying(struct bufferevent *bufev); + +/** + Write data to a bufferevent buffer. + + The bufferevent_write() function can be used to write data to the file + descriptor. The data is appended to the output buffer and written to the + descriptor automatically as it becomes available for writing. + + @param bufev the bufferevent to be written to + @param data a pointer to the data to be written + @param size the length of the data, in bytes + @return 0 if successful, or -1 if an error occurred + @see bufferevent_write_buffer() + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_write(struct bufferevent *bufev, + const void *data, size_t size); + + +/** + Write data from an evbuffer to a bufferevent buffer. The evbuffer is + being drained as a result. + + @param bufev the bufferevent to be written to + @param buf the evbuffer to be written + @return 0 if successful, or -1 if an error occurred + @see bufferevent_write() + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf); + + +/** + Read data from a bufferevent buffer. + + The bufferevent_read() function is used to read data from the input buffer. + + @param bufev the bufferevent to be read from + @param data pointer to a buffer that will store the data + @param size the size of the data buffer, in bytes + @return the amount of data read, in bytes. + */ +EVENT2_EXPORT_SYMBOL +size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size); + +/** + Read data from a bufferevent buffer into an evbuffer. This avoids + memory copies. + + @param bufev the bufferevent to be read from + @param buf the evbuffer to which to add data + @return 0 if successful, or -1 if an error occurred. + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_read_buffer(struct bufferevent *bufev, struct evbuffer *buf); + +/** + Returns the input buffer. + + The user MUST NOT set the callback on this buffer. + + @param bufev the bufferevent from which to get the evbuffer + @return the evbuffer object for the input buffer + */ + +EVENT2_EXPORT_SYMBOL +struct evbuffer *bufferevent_get_input(struct bufferevent *bufev); + +/** + Returns the output buffer. + + The user MUST NOT set the callback on this buffer. + + When filters are being used, the filters need to be manually + triggered if the output buffer was manipulated. + + @param bufev the bufferevent from which to get the evbuffer + @return the evbuffer object for the output buffer + */ + +EVENT2_EXPORT_SYMBOL +struct evbuffer *bufferevent_get_output(struct bufferevent *bufev); + +/** + Enable a bufferevent. + + @param bufev the bufferevent to be enabled + @param event any combination of EV_READ | EV_WRITE. + @return 0 if successful, or -1 if an error occurred + @see bufferevent_disable() + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_enable(struct bufferevent *bufev, short event); + +/** + Disable a bufferevent. + + @param bufev the bufferevent to be disabled + @param event any combination of EV_READ | EV_WRITE. + @return 0 if successful, or -1 if an error occurred + @see bufferevent_enable() + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_disable(struct bufferevent *bufev, short event); + +/** + Return the events that are enabled on a given bufferevent. + + @param bufev the bufferevent to inspect + @return A combination of EV_READ | EV_WRITE + */ +EVENT2_EXPORT_SYMBOL +short bufferevent_get_enabled(struct bufferevent *bufev); + +/** + Set the read and write timeout for a bufferevent. + + A bufferevent's timeout will fire the first time that the indicated + amount of time has elapsed since a successful read or write operation, + during which the bufferevent was trying to read or write. + + (In other words, if reading or writing is disabled, or if the + bufferevent's read or write operation has been suspended because + there's no data to write, or not enough bandwidth, or so on, the + timeout isn't active. The timeout only becomes active when we we're + willing to actually read or write.) + + Calling bufferevent_enable or setting a timeout for a bufferevent + whose timeout is already pending resets its timeout. + + If the timeout elapses, the corresponding operation (EV_READ or + EV_WRITE) becomes disabled until you re-enable it again. The + bufferevent's event callback is called with the + BEV_EVENT_TIMEOUT|BEV_EVENT_READING or + BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING. + + @param bufev the bufferevent to be modified + @param timeout_read the read timeout, or NULL + @param timeout_write the write timeout, or NULL + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_set_timeouts(struct bufferevent *bufev, + const struct timeval *timeout_read, const struct timeval *timeout_write); + +/** + Sets the watermarks for read and write events. + + On input, a bufferevent does not invoke the user read callback unless + there is at least low watermark data in the buffer. If the read buffer + is beyond the high watermark, the bufferevent stops reading from the network. + But be aware that bufferevent input/read buffer can overrun high watermark + limit (typical example is openssl bufferevent), so you should not relay in + this. + + On output, the user write callback is invoked whenever the buffered data + falls below the low watermark. Filters that write to this bufev will try + not to write more bytes to this buffer than the high watermark would allow, + except when flushing. + + @param bufev the bufferevent to be modified + @param events EV_READ, EV_WRITE or both + @param lowmark the lower watermark to set + @param highmark the high watermark to set +*/ + +EVENT2_EXPORT_SYMBOL +void bufferevent_setwatermark(struct bufferevent *bufev, short events, + size_t lowmark, size_t highmark); + +/** + Retrieves the watermarks for read or write events. + Returns non-zero if events contains not only EV_READ or EV_WRITE. + Returns zero if events equal EV_READ or EV_WRITE + + @param bufev the bufferevent to be examined + @param events EV_READ or EV_WRITE + @param lowmark receives the lower watermark if not NULL + @param highmark receives the high watermark if not NULL +*/ +EVENT2_EXPORT_SYMBOL +int bufferevent_getwatermark(struct bufferevent *bufev, short events, + size_t *lowmark, size_t *highmark); + +/** + Acquire the lock on a bufferevent. Has no effect if locking was not + enabled with BEV_OPT_THREADSAFE. + */ +EVENT2_EXPORT_SYMBOL +void bufferevent_lock(struct bufferevent *bufev); + +/** + Release the lock on a bufferevent. Has no effect if locking was not + enabled with BEV_OPT_THREADSAFE. + */ +EVENT2_EXPORT_SYMBOL +void bufferevent_unlock(struct bufferevent *bufev); + + +/** + * Public interface to manually increase the reference count of a bufferevent + * this is useful in situations where a user may reference the bufferevent + * somewhere else (unknown to libevent) + * + * @param bufev the bufferevent to increase the refcount on + * + */ +EVENT2_EXPORT_SYMBOL +void bufferevent_incref(struct bufferevent *bufev); + +/** + * Public interface to manually decrement the reference count of a bufferevent + * + * Warning: make sure you know what you're doing. This is mainly used in + * conjunction with bufferevent_incref(). This will free up all data associated + * with a bufferevent if the reference count hits 0. + * + * @param bufev the bufferevent to decrement the refcount on + * + * @return 1 if the bufferevent was freed, otherwise 0 (still referenced) + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_decref(struct bufferevent *bufev); + +/** + Flags that can be passed into filters to let them know how to + deal with the incoming data. +*/ +enum bufferevent_flush_mode { + /** usually set when processing data */ + BEV_NORMAL = 0, + + /** want to checkpoint all data sent. */ + BEV_FLUSH = 1, + + /** encountered EOF on read or done sending data */ + BEV_FINISHED = 2 +}; + +/** + Triggers the bufferevent to produce more data if possible. + + @param bufev the bufferevent object + @param iotype either EV_READ or EV_WRITE or both. + @param mode either BEV_NORMAL or BEV_FLUSH or BEV_FINISHED + @return -1 on failure, 0 if no data was produces, 1 if data was produced + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_flush(struct bufferevent *bufev, + short iotype, + enum bufferevent_flush_mode mode); + +/** + Flags for bufferevent_trigger(_event) that modify when and how to trigger + the callback. +*/ +enum bufferevent_trigger_options { + /** trigger the callback regardless of the watermarks */ + BEV_TRIG_IGNORE_WATERMARKS = (1<<16), + + /** defer even if the callbacks are not */ + BEV_TRIG_DEFER_CALLBACKS = BEV_OPT_DEFER_CALLBACKS + + /* (Note: for internal reasons, these need to be disjoint from + * bufferevent_options, except when they mean the same thing. */ +}; + +/** + Triggers bufferevent data callbacks. + + The function will honor watermarks unless options contain + BEV_TRIG_IGNORE_WATERMARKS. If the options contain BEV_OPT_DEFER_CALLBACKS, + the callbacks are deferred. + + @param bufev the bufferevent object + @param iotype either EV_READ or EV_WRITE or both. + @param options + */ +EVENT2_EXPORT_SYMBOL +void bufferevent_trigger(struct bufferevent *bufev, short iotype, + int options); + +/** + Triggers the bufferevent event callback. + + If the options contain BEV_OPT_DEFER_CALLBACKS, the callbacks are deferred. + + @param bufev the bufferevent object + @param what the flags to pass onto the event callback + @param options + */ +EVENT2_EXPORT_SYMBOL +void bufferevent_trigger_event(struct bufferevent *bufev, short what, + int options); + +/** + @name Filtering support + + @{ +*/ +/** + Values that filters can return. + */ +enum bufferevent_filter_result { + /** everything is okay */ + BEV_OK = 0, + + /** the filter needs to read more data before output */ + BEV_NEED_MORE = 1, + + /** the filter encountered a critical error, no further data + can be processed. */ + BEV_ERROR = 2 +}; + +/** A callback function to implement a filter for a bufferevent. + + @param src An evbuffer to drain data from. + @param dst An evbuffer to add data to. + @param limit A suggested upper bound of bytes to write to dst. + The filter may ignore this value, but doing so means that + it will overflow the high-water mark associated with dst. + -1 means "no limit". + @param mode Whether we should write data as may be convenient + (BEV_NORMAL), or flush as much data as we can (BEV_FLUSH), + or flush as much as we can, possibly including an end-of-stream + marker (BEV_FINISH). + @param ctx A user-supplied pointer. + + @return BEV_OK if we wrote some data; BEV_NEED_MORE if we can't + produce any more output until we get some input; and BEV_ERROR + on an error. + */ +typedef enum bufferevent_filter_result (*bufferevent_filter_cb)( + struct evbuffer *src, struct evbuffer *dst, ev_ssize_t dst_limit, + enum bufferevent_flush_mode mode, void *ctx); + +/** + Allocate a new filtering bufferevent on top of an existing bufferevent. + + @param underlying the underlying bufferevent. + @param input_filter The filter to apply to data we read from the underlying + bufferevent + @param output_filter The filer to apply to data we write to the underlying + bufferevent + @param options A bitfield of bufferevent options. + @param free_context A function to use to free the filter context when + this bufferevent is freed. + @param ctx A context pointer to pass to the filter functions. + */ +EVENT2_EXPORT_SYMBOL +struct bufferevent * +bufferevent_filter_new(struct bufferevent *underlying, + bufferevent_filter_cb input_filter, + bufferevent_filter_cb output_filter, + int options, + void (*free_context)(void *), + void *ctx); +/**@}*/ + +/** + Allocate a pair of linked bufferevents. The bufferevents behave as would + two bufferevent_sock instances connected to opposite ends of a + socketpair(), except that no internal socketpair is allocated. + + @param base The event base to associate with the socketpair. + @param options A set of options for this bufferevent + @param pair A pointer to an array to hold the two new bufferevent objects. + @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_pair_new(struct event_base *base, int options, + struct bufferevent *pair[2]); + +/** + Given one bufferevent returned by bufferevent_pair_new(), returns the + other one if it still exists. Otherwise returns NULL. + */ +EVENT2_EXPORT_SYMBOL +struct bufferevent *bufferevent_pair_get_partner(struct bufferevent *bev); + +/** + Abstract type used to configure rate-limiting on a bufferevent or a group + of bufferevents. + */ +struct ev_token_bucket_cfg; + +/** + A group of bufferevents which are configured to respect the same rate + limit. +*/ +struct bufferevent_rate_limit_group; + +/** Maximum configurable rate- or burst-limit. */ +#define EV_RATE_LIMIT_MAX EV_SSIZE_MAX + +/** + Initialize and return a new object to configure the rate-limiting behavior + of bufferevents. + + @param read_rate The maximum number of bytes to read per tick on + average. + @param read_burst The maximum number of bytes to read in any single tick. + @param write_rate The maximum number of bytes to write per tick on + average. + @param write_burst The maximum number of bytes to write in any single tick. + @param tick_len The length of a single tick. Defaults to one second. + Any fractions of a millisecond are ignored. + + Note that all rate-limits hare are currently best-effort: future versions + of Libevent may implement them more tightly. + */ +EVENT2_EXPORT_SYMBOL +struct ev_token_bucket_cfg *ev_token_bucket_cfg_new( + size_t read_rate, size_t read_burst, + size_t write_rate, size_t write_burst, + const struct timeval *tick_len); + +/** Free all storage held in 'cfg'. + + Note: 'cfg' is not currently reference-counted; it is not safe to free it + until no bufferevent is using it. + */ +EVENT2_EXPORT_SYMBOL +void ev_token_bucket_cfg_free(struct ev_token_bucket_cfg *cfg); + +/** + Set the rate-limit of a the bufferevent 'bev' to the one specified in + 'cfg'. If 'cfg' is NULL, disable any per-bufferevent rate-limiting on + 'bev'. + + Note that only some bufferevent types currently respect rate-limiting. + They are: socket-based bufferevents (normal and IOCP-based), and SSL-based + bufferevents. + + Return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_set_rate_limit(struct bufferevent *bev, + struct ev_token_bucket_cfg *cfg); + +/** + Create a new rate-limit group for bufferevents. A rate-limit group + constrains the maximum number of bytes sent and received, in toto, + by all of its bufferevents. + + @param base An event_base to run any necessary timeouts for the group. + Note that all bufferevents in the group do not necessarily need to share + this event_base. + @param cfg The rate-limit for this group. + + Note that all rate-limits hare are currently best-effort: future versions + of Libevent may implement them more tightly. + + Note also that only some bufferevent types currently respect rate-limiting. + They are: socket-based bufferevents (normal and IOCP-based), and SSL-based + bufferevents. + */ +EVENT2_EXPORT_SYMBOL +struct bufferevent_rate_limit_group *bufferevent_rate_limit_group_new( + struct event_base *base, + const struct ev_token_bucket_cfg *cfg); +/** + Change the rate-limiting settings for a given rate-limiting group. + + Return 0 on success, -1 on failure. +*/ +EVENT2_EXPORT_SYMBOL +int bufferevent_rate_limit_group_set_cfg( + struct bufferevent_rate_limit_group *, + const struct ev_token_bucket_cfg *); + +/** + Change the smallest quantum we're willing to allocate to any single + bufferevent in a group for reading or writing at a time. + + The rationale is that, because of TCP/IP protocol overheads and kernel + behavior, if a rate-limiting group is so tight on bandwidth that you're + only willing to send 1 byte per tick per bufferevent, you might instead + want to batch up the reads and writes so that you send N bytes per + 1/N of the bufferevents (chosen at random) each tick, so you still wind + up send 1 byte per tick per bufferevent on average, but you don't send + so many tiny packets. + + The default min-share is currently 64 bytes. + + Returns 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_rate_limit_group_set_min_share( + struct bufferevent_rate_limit_group *, size_t); + +/** + Free a rate-limiting group. The group must have no members when + this function is called. +*/ +EVENT2_EXPORT_SYMBOL +void bufferevent_rate_limit_group_free(struct bufferevent_rate_limit_group *); + +/** + Add 'bev' to the list of bufferevents whose aggregate reading and writing + is restricted by 'g'. If 'g' is NULL, remove 'bev' from its current group. + + A bufferevent may belong to no more than one rate-limit group at a time. + If 'bev' is already a member of a group, it will be removed from its old + group before being added to 'g'. + + Return 0 on success and -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_add_to_rate_limit_group(struct bufferevent *bev, + struct bufferevent_rate_limit_group *g); + +/** Remove 'bev' from its current rate-limit group (if any). */ +EVENT2_EXPORT_SYMBOL +int bufferevent_remove_from_rate_limit_group(struct bufferevent *bev); + +/** + Set the size limit for single read operation. + + Set to 0 for a reasonable default. + + Return 0 on success and -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_set_max_single_read(struct bufferevent *bev, size_t size); + +/** + Set the size limit for single write operation. + + Set to 0 for a reasonable default. + + Return 0 on success and -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_set_max_single_write(struct bufferevent *bev, size_t size); + +/** Get the current size limit for single read operation. */ +EVENT2_EXPORT_SYMBOL +ev_ssize_t bufferevent_get_max_single_read(struct bufferevent *bev); + +/** Get the current size limit for single write operation. */ +EVENT2_EXPORT_SYMBOL +ev_ssize_t bufferevent_get_max_single_write(struct bufferevent *bev); + +/** + @name Rate limit inspection + + Return the current read or write bucket size for a bufferevent. + If it is not configured with a per-bufferevent ratelimit, return + EV_SSIZE_MAX. This function does not inspect the group limit, if any. + Note that it can return a negative value if the bufferevent has been + made to read or write more than its limit. + + @{ + */ +EVENT2_EXPORT_SYMBOL +ev_ssize_t bufferevent_get_read_limit(struct bufferevent *bev); +EVENT2_EXPORT_SYMBOL +ev_ssize_t bufferevent_get_write_limit(struct bufferevent *bev); +/*@}*/ + +EVENT2_EXPORT_SYMBOL +ev_ssize_t bufferevent_get_max_to_read(struct bufferevent *bev); +EVENT2_EXPORT_SYMBOL +ev_ssize_t bufferevent_get_max_to_write(struct bufferevent *bev); + +EVENT2_EXPORT_SYMBOL +const struct ev_token_bucket_cfg *bufferevent_get_token_bucket_cfg(const struct bufferevent * bev); + +/** + @name Group Rate limit inspection + + Return the read or write bucket size for a bufferevent rate limit + group. Note that it can return a negative value if bufferevents in + the group have been made to read or write more than their limits. + + @{ + */ +EVENT2_EXPORT_SYMBOL +ev_ssize_t bufferevent_rate_limit_group_get_read_limit( + struct bufferevent_rate_limit_group *); +EVENT2_EXPORT_SYMBOL +ev_ssize_t bufferevent_rate_limit_group_get_write_limit( + struct bufferevent_rate_limit_group *); +/*@}*/ + +/** + @name Rate limit manipulation + + Subtract a number of bytes from a bufferevent's read or write bucket. + The decrement value can be negative, if you want to manually refill + the bucket. If the change puts the bucket above or below zero, the + bufferevent will resume or suspend reading writing as appropriate. + These functions make no change in the buckets for the bufferevent's + group, if any. + + Returns 0 on success, -1 on internal error. + + @{ + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_decrement_read_limit(struct bufferevent *bev, ev_ssize_t decr); +EVENT2_EXPORT_SYMBOL +int bufferevent_decrement_write_limit(struct bufferevent *bev, ev_ssize_t decr); +/*@}*/ + +/** + @name Group rate limit manipulation + + Subtract a number of bytes from a bufferevent rate-limiting group's + read or write bucket. The decrement value can be negative, if you + want to manually refill the bucket. If the change puts the bucket + above or below zero, the bufferevents in the group will resume or + suspend reading writing as appropriate. + + Returns 0 on success, -1 on internal error. + + @{ + */ +EVENT2_EXPORT_SYMBOL +int bufferevent_rate_limit_group_decrement_read( + struct bufferevent_rate_limit_group *, ev_ssize_t); +EVENT2_EXPORT_SYMBOL +int bufferevent_rate_limit_group_decrement_write( + struct bufferevent_rate_limit_group *, ev_ssize_t); +/*@}*/ + + +/** + * Inspect the total bytes read/written on a group. + * + * Set the variable pointed to by total_read_out to the total number of bytes + * ever read on grp, and the variable pointed to by total_written_out to the + * total number of bytes ever written on grp. */ +EVENT2_EXPORT_SYMBOL +void bufferevent_rate_limit_group_get_totals( + struct bufferevent_rate_limit_group *grp, + ev_uint64_t *total_read_out, ev_uint64_t *total_written_out); + +/** + * Reset the total bytes read/written on a group. + * + * Reset the number of bytes read or written on grp as given by + * bufferevent_rate_limit_group_reset_totals(). */ +EVENT2_EXPORT_SYMBOL +void +bufferevent_rate_limit_group_reset_totals( + struct bufferevent_rate_limit_group *grp); + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_BUFFEREVENT_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/include/event2/bufferevent_compat.h b/bsnes/thrift/libevent/include/event2/bufferevent_compat.h new file mode 100644 index 00000000..a5a3c720 --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/bufferevent_compat.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2007-2012 Niels Provos, Nick Mathewson + * Copyright (c) 2000-2007 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_BUFFEREVENT_COMPAT_H_INCLUDED_ +#define EVENT2_BUFFEREVENT_COMPAT_H_INCLUDED_ + +#include + +#define evbuffercb bufferevent_data_cb +#define everrorcb bufferevent_event_cb + +/** + Create a new bufferevent for an fd. + + This function is deprecated. Use bufferevent_socket_new and + bufferevent_set_callbacks instead. + + Libevent provides an abstraction on top of the regular event callbacks. + This abstraction is called a buffered event. A buffered event provides + input and output buffers that get filled and drained automatically. The + user of a buffered event no longer deals directly with the I/O, but + instead is reading from input and writing to output buffers. + + Once initialized, the bufferevent structure can be used repeatedly with + bufferevent_enable() and bufferevent_disable(). + + When read enabled the bufferevent will try to read from the file descriptor + and call the read callback. The write callback is executed whenever the + output buffer is drained below the write low watermark, which is 0 by + default. + + If multiple bases are in use, bufferevent_base_set() must be called before + enabling the bufferevent for the first time. + + @deprecated This function is deprecated because it uses the current + event base, and as such can be error prone for multithreaded programs. + Use bufferevent_socket_new() instead. + + @param fd the file descriptor from which data is read and written to. + This file descriptor is not allowed to be a pipe(2). + @param readcb callback to invoke when there is data to be read, or NULL if + no callback is desired + @param writecb callback to invoke when the file descriptor is ready for + writing, or NULL if no callback is desired + @param errorcb callback to invoke when there is an error on the file + descriptor + @param cbarg an argument that will be supplied to each of the callbacks + (readcb, writecb, and errorcb) + @return a pointer to a newly allocated bufferevent struct, or NULL if an + error occurred + @see bufferevent_base_set(), bufferevent_free() + */ +EVENT2_EXPORT_SYMBOL +struct bufferevent *bufferevent_new(evutil_socket_t fd, + evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg); + + +/** + Set the read and write timeout for a buffered event. + + @param bufev the bufferevent to be modified + @param timeout_read the read timeout + @param timeout_write the write timeout + */ +EVENT2_EXPORT_SYMBOL +void bufferevent_settimeout(struct bufferevent *bufev, + int timeout_read, int timeout_write); + +#define EVBUFFER_READ BEV_EVENT_READING +#define EVBUFFER_WRITE BEV_EVENT_WRITING +#define EVBUFFER_EOF BEV_EVENT_EOF +#define EVBUFFER_ERROR BEV_EVENT_ERROR +#define EVBUFFER_TIMEOUT BEV_EVENT_TIMEOUT + +/** macro for getting access to the input buffer of a bufferevent */ +#define EVBUFFER_INPUT(x) bufferevent_get_input(x) +/** macro for getting access to the output buffer of a bufferevent */ +#define EVBUFFER_OUTPUT(x) bufferevent_get_output(x) + +#endif diff --git a/bsnes/thrift/libevent/include/event2/bufferevent_struct.h b/bsnes/thrift/libevent/include/event2/bufferevent_struct.h new file mode 100644 index 00000000..e84c082c --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/bufferevent_struct.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_BUFFEREVENT_STRUCT_H_INCLUDED_ +#define EVENT2_BUFFEREVENT_STRUCT_H_INCLUDED_ + +/** @file event2/bufferevent_struct.h + + Data structures for bufferevents. Using these structures may hurt forward + compatibility with later versions of Libevent: be careful! + + @deprecated Use of bufferevent_struct.h is completely deprecated; these + structures are only exposed for backward compatibility with programs + written before Libevent 2.0 that used them. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif + +/* For int types. */ +#include +/* For struct event */ +#include + +struct event_watermark { + size_t low; + size_t high; +}; + +/** + Shared implementation of a bufferevent. + + This type is exposed only because it was exposed in previous versions, + and some people's code may rely on manipulating it. Otherwise, you + should really not rely on the layout, size, or contents of this structure: + it is fairly volatile, and WILL change in future versions of the code. +**/ +struct bufferevent { + /** Event base for which this bufferevent was created. */ + struct event_base *ev_base; + /** Pointer to a table of function pointers to set up how this + bufferevent behaves. */ + const struct bufferevent_ops *be_ops; + + /** A read event that triggers when a timeout has happened or a socket + is ready to read data. Only used by some subtypes of + bufferevent. */ + struct event ev_read; + /** A write event that triggers when a timeout has happened or a socket + is ready to write data. Only used by some subtypes of + bufferevent. */ + struct event ev_write; + + /** An input buffer. Only the bufferevent is allowed to add data to + this buffer, though the user is allowed to drain it. */ + struct evbuffer *input; + + /** An input buffer. Only the bufferevent is allowed to drain data + from this buffer, though the user is allowed to add it. */ + struct evbuffer *output; + + struct event_watermark wm_read; + struct event_watermark wm_write; + + bufferevent_data_cb readcb; + bufferevent_data_cb writecb; + /* This should be called 'eventcb', but renaming it would break + * backward compatibility */ + bufferevent_event_cb errorcb; + void *cbarg; + + struct timeval timeout_read; + struct timeval timeout_write; + + /** Events that are currently enabled: currently EV_READ and EV_WRITE + are supported. */ + short enabled; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_BUFFEREVENT_STRUCT_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/include/event2/dns.h b/bsnes/thrift/libevent/include/event2/dns.h new file mode 100644 index 00000000..13ce027e --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/dns.h @@ -0,0 +1,751 @@ +/* + * Copyright (c) 2006-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * The original DNS code is due to Adam Langley with heavy + * modifications by Nick Mathewson. Adam put his DNS software in the + * public domain. You can find his original copyright below. Please, + * aware that the code as part of Libevent is governed by the 3-clause + * BSD license above. + * + * This software is Public Domain. To view a copy of the public domain dedication, + * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to + * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA. + * + * I ask and expect, but do not require, that all derivative works contain an + * attribution similar to: + * Parts developed by Adam Langley + * + * You may wish to replace the word "Parts" with something else depending on + * the amount of original code. + * + * (Derivative works does not include programs which link against, run or include + * the source verbatim in their source distributions) + */ + +/** @file event2/dns.h + * + * Welcome, gentle reader + * + * Async DNS lookups are really a whole lot harder than they should be, + * mostly stemming from the fact that the libc resolver has never been + * very good at them. Before you use this library you should see if libc + * can do the job for you with the modern async call getaddrinfo_a + * (see http://www.imperialviolet.org/page25.html#e498). Otherwise, + * please continue. + * + * The library keeps track of the state of nameservers and will avoid + * them when they go down. Otherwise it will round robin between them. + * + * Quick start guide: + * #include "evdns.h" + * void callback(int result, char type, int count, int ttl, + * void *addresses, void *arg); + * evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf"); + * evdns_resolve("www.hostname.com", 0, callback, NULL); + * + * When the lookup is complete the callback function is called. The + * first argument will be one of the DNS_ERR_* defines in evdns.h. + * Hopefully it will be DNS_ERR_NONE, in which case type will be + * DNS_IPv4_A, count will be the number of IP addresses, ttl is the time + * which the data can be cached for (in seconds), addresses will point + * to an array of uint32_t's and arg will be whatever you passed to + * evdns_resolve. + * + * Searching: + * + * In order for this library to be a good replacement for glibc's resolver it + * supports searching. This involves setting a list of default domains, in + * which names will be queried for. The number of dots in the query name + * determines the order in which this list is used. + * + * Searching appears to be a single lookup from the point of view of the API, + * although many DNS queries may be generated from a single call to + * evdns_resolve. Searching can also drastically slow down the resolution + * of names. + * + * To disable searching: + * 1. Never set it up. If you never call evdns_resolv_conf_parse or + * evdns_search_add then no searching will occur. + * + * 2. If you do call evdns_resolv_conf_parse then don't pass + * DNS_OPTION_SEARCH (or DNS_OPTIONS_ALL, which implies it). + * + * 3. When calling evdns_resolve, pass the DNS_QUERY_NO_SEARCH flag. + * + * The order of searches depends on the number of dots in the name. If the + * number is greater than the ndots setting then the names is first tried + * globally. Otherwise each search domain is appended in turn. + * + * The ndots setting can either be set from a resolv.conf, or by calling + * evdns_search_ndots_set. + * + * For example, with ndots set to 1 (the default) and a search domain list of + * ["myhome.net"]: + * Query: www + * Order: www.myhome.net, www. + * + * Query: www.abc + * Order: www.abc., www.abc.myhome.net + * + * Internals: + * + * Requests are kept in two queues. The first is the inflight queue. In + * this queue requests have an allocated transaction id and nameserver. + * They will soon be transmitted if they haven't already been. + * + * The second is the waiting queue. The size of the inflight ring is + * limited and all other requests wait in waiting queue for space. This + * bounds the number of concurrent requests so that we don't flood the + * nameserver. Several algorithms require a full walk of the inflight + * queue and so bounding its size keeps thing going nicely under huge + * (many thousands of requests) loads. + * + * If a nameserver loses too many requests it is considered down and we + * try not to use it. After a while we send a probe to that nameserver + * (a lookup for google.com) and, if it replies, we consider it working + * again. If the nameserver fails a probe we wait longer to try again + * with the next probe. + */ + +#ifndef EVENT2_DNS_H_INCLUDED_ +#define EVENT2_DNS_H_INCLUDED_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* For integer types. */ +#include + +/** Error codes 0-5 are as described in RFC 1035. */ +#define DNS_ERR_NONE 0 +/** The name server was unable to interpret the query */ +#define DNS_ERR_FORMAT 1 +/** The name server was unable to process this query due to a problem with the + * name server */ +#define DNS_ERR_SERVERFAILED 2 +/** The domain name does not exist */ +#define DNS_ERR_NOTEXIST 3 +/** The name server does not support the requested kind of query */ +#define DNS_ERR_NOTIMPL 4 +/** The name server refuses to reform the specified operation for policy + * reasons */ +#define DNS_ERR_REFUSED 5 +/** The reply was truncated or ill-formatted */ +#define DNS_ERR_TRUNCATED 65 +/** An unknown error occurred */ +#define DNS_ERR_UNKNOWN 66 +/** Communication with the server timed out */ +#define DNS_ERR_TIMEOUT 67 +/** The request was canceled because the DNS subsystem was shut down. */ +#define DNS_ERR_SHUTDOWN 68 +/** The request was canceled via a call to evdns_cancel_request */ +#define DNS_ERR_CANCEL 69 +/** There were no answers and no error condition in the DNS packet. + * This can happen when you ask for an address that exists, but a record + * type that doesn't. */ +#define DNS_ERR_NODATA 70 + +#define DNS_IPv4_A 1 +#define DNS_PTR 2 +#define DNS_IPv6_AAAA 3 + +#define DNS_QUERY_NO_SEARCH 1 + +/* Allow searching */ +#define DNS_OPTION_SEARCH 1 +/* Parse "nameserver" and add default if no such section */ +#define DNS_OPTION_NAMESERVERS 2 +/* Parse additional options like: + * - timeout: + * - getaddrinfo-allow-skew: + * - max-timeouts: + * - max-inflight: + * - attempts: + * - randomize-case: + * - initial-probe-timeout: + */ +#define DNS_OPTION_MISC 4 +/* Load hosts file (i.e. "/etc/hosts") */ +#define DNS_OPTION_HOSTSFILE 8 +/** + * All above: + * - DNS_OPTION_SEARCH + * - DNS_OPTION_NAMESERVERS + * - DNS_OPTION_MISC + * - DNS_OPTION_HOSTSFILE + */ +#define DNS_OPTIONS_ALL ( \ + DNS_OPTION_SEARCH | \ + DNS_OPTION_NAMESERVERS | \ + DNS_OPTION_MISC | \ + DNS_OPTION_HOSTSFILE | \ + 0 \ +) +/* Do not "default" nameserver (i.e. "127.0.0.1:53") if there is no nameservers + * in resolv.conf, (iff DNS_OPTION_NAMESERVERS is set) */ +#define DNS_OPTION_NAMESERVERS_NO_DEFAULT 16 + +/* Obsolete name for DNS_QUERY_NO_SEARCH */ +#define DNS_NO_SEARCH DNS_QUERY_NO_SEARCH + +/** + * The callback that contains the results from a lookup. + * - result is one of the DNS_ERR_* values (DNS_ERR_NONE for success) + * - type is either DNS_IPv4_A or DNS_PTR or DNS_IPv6_AAAA + * - count contains the number of addresses of form type + * - ttl is the number of seconds the resolution may be cached for. + * - addresses needs to be cast according to type. It will be an array of + * 4-byte sequences for ipv4, or an array of 16-byte sequences for ipv6, + * or a nul-terminated string for PTR. + */ +typedef void (*evdns_callback_type) (int result, char type, int count, int ttl, void *addresses, void *arg); + +struct evdns_base; +struct event_base; + +/** Flag for evdns_base_new: process resolv.conf. */ +#define EVDNS_BASE_INITIALIZE_NAMESERVERS 1 +/** Flag for evdns_base_new: Do not prevent the libevent event loop from + * exiting when we have no active dns requests. */ +#define EVDNS_BASE_DISABLE_WHEN_INACTIVE 0x8000 +/** Flag for evdns_base_new: If EVDNS_BASE_INITIALIZE_NAMESERVERS isset, do not + * add default nameserver if there are no nameservers in resolv.conf + * @see DNS_OPTION_NAMESERVERS_NO_DEFAULT */ +#define EVDNS_BASE_NAMESERVERS_NO_DEFAULT 0x10000 + +/** + Initialize the asynchronous DNS library. + + This function initializes support for non-blocking name resolution by + calling evdns_resolv_conf_parse() on UNIX and + evdns_config_windows_nameservers() on Windows. + + @param event_base the event base to associate the dns client with + @param flags any of EVDNS_BASE_INITIALIZE_NAMESERVERS| + EVDNS_BASE_DISABLE_WHEN_INACTIVE|EVDNS_BASE_NAMESERVERS_NO_DEFAULT + @return evdns_base object if successful, or NULL if an error occurred. + @see evdns_base_free() + */ +EVENT2_EXPORT_SYMBOL +struct evdns_base * evdns_base_new(struct event_base *event_base, int initialize_nameservers); + + +/** + Shut down the asynchronous DNS resolver and terminate all active requests. + + If the 'fail_requests' option is enabled, all active requests will return + an empty result with the error flag set to DNS_ERR_SHUTDOWN. Otherwise, + the requests will be silently discarded. + + @param evdns_base the evdns base to free + @param fail_requests if zero, active requests will be aborted; if non-zero, + active requests will return DNS_ERR_SHUTDOWN. + @see evdns_base_new() + */ +EVENT2_EXPORT_SYMBOL +void evdns_base_free(struct evdns_base *base, int fail_requests); + +/** + Remove all hosts entries that have been loaded into the event_base via + evdns_base_load_hosts or via event_base_resolv_conf_parse. + + @param evdns_base the evdns base to remove outdated host addresses from + */ +EVENT2_EXPORT_SYMBOL +void evdns_base_clear_host_addresses(struct evdns_base *base); + +/** + Convert a DNS error code to a string. + + @param err the DNS error code + @return a string containing an explanation of the error code +*/ +EVENT2_EXPORT_SYMBOL +const char *evdns_err_to_string(int err); + + +/** + Add a nameserver. + + The address should be an IPv4 address in network byte order. + The type of address is chosen so that it matches in_addr.s_addr. + + @param base the evdns_base to which to add the name server + @param address an IP address in network byte order + @return 0 if successful, or -1 if an error occurred + @see evdns_base_nameserver_ip_add() + */ +EVENT2_EXPORT_SYMBOL +int evdns_base_nameserver_add(struct evdns_base *base, + unsigned long int address); + +/** + Get the number of configured nameservers. + + This returns the number of configured nameservers (not necessarily the + number of running nameservers). This is useful for double-checking + whether our calls to the various nameserver configuration functions + have been successful. + + @param base the evdns_base to which to apply this operation + @return the number of configured nameservers + @see evdns_base_nameserver_add() + */ +EVENT2_EXPORT_SYMBOL +int evdns_base_count_nameservers(struct evdns_base *base); + +/** + Remove all configured nameservers, and suspend all pending resolves. + + Resolves will not necessarily be re-attempted until evdns_base_resume() is called. + + @param base the evdns_base to which to apply this operation + @return 0 if successful, or -1 if an error occurred + @see evdns_base_resume() + */ +EVENT2_EXPORT_SYMBOL +int evdns_base_clear_nameservers_and_suspend(struct evdns_base *base); + + +/** + Resume normal operation and continue any suspended resolve requests. + + Re-attempt resolves left in limbo after an earlier call to + evdns_base_clear_nameservers_and_suspend(). + + @param base the evdns_base to which to apply this operation + @return 0 if successful, or -1 if an error occurred + @see evdns_base_clear_nameservers_and_suspend() + */ +EVENT2_EXPORT_SYMBOL +int evdns_base_resume(struct evdns_base *base); + +/** + Add a nameserver by string address. + + This function parses a n IPv4 or IPv6 address from a string and adds it as a + nameserver. It supports the following formats: + - [IPv6Address]:port + - [IPv6Address] + - IPv6Address + - IPv4Address:port + - IPv4Address + + If no port is specified, it defaults to 53. + + @param base the evdns_base to which to apply this operation + @return 0 if successful, or -1 if an error occurred + @see evdns_base_nameserver_add() + */ +EVENT2_EXPORT_SYMBOL +int evdns_base_nameserver_ip_add(struct evdns_base *base, + const char *ip_as_string); + +/** + Add a nameserver by sockaddr. + **/ +EVENT2_EXPORT_SYMBOL +int +evdns_base_nameserver_sockaddr_add(struct evdns_base *base, + const struct sockaddr *sa, ev_socklen_t len, unsigned flags); + +struct evdns_request; + +/** + Lookup an A record for a given name. + + @param base the evdns_base to which to apply this operation + @param name a DNS hostname + @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. + @param callback a callback function to invoke when the request is completed + @param ptr an argument to pass to the callback function + @return an evdns_request object if successful, or NULL if an error occurred. + @see evdns_resolve_ipv6(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6(), evdns_cancel_request() + */ +EVENT2_EXPORT_SYMBOL +struct evdns_request *evdns_base_resolve_ipv4(struct evdns_base *base, const char *name, int flags, evdns_callback_type callback, void *ptr); + +/** + Lookup an AAAA record for a given name. + + @param base the evdns_base to which to apply this operation + @param name a DNS hostname + @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. + @param callback a callback function to invoke when the request is completed + @param ptr an argument to pass to the callback function + @return an evdns_request object if successful, or NULL if an error occurred. + @see evdns_resolve_ipv4(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6(), evdns_cancel_request() + */ +EVENT2_EXPORT_SYMBOL +struct evdns_request *evdns_base_resolve_ipv6(struct evdns_base *base, const char *name, int flags, evdns_callback_type callback, void *ptr); + +struct in_addr; +struct in6_addr; + +/** + Lookup a PTR record for a given IP address. + + @param base the evdns_base to which to apply this operation + @param in an IPv4 address + @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. + @param callback a callback function to invoke when the request is completed + @param ptr an argument to pass to the callback function + @return an evdns_request object if successful, or NULL if an error occurred. + @see evdns_resolve_reverse_ipv6(), evdns_cancel_request() + */ +EVENT2_EXPORT_SYMBOL +struct evdns_request *evdns_base_resolve_reverse(struct evdns_base *base, const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr); + + +/** + Lookup a PTR record for a given IPv6 address. + + @param base the evdns_base to which to apply this operation + @param in an IPv6 address + @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. + @param callback a callback function to invoke when the request is completed + @param ptr an argument to pass to the callback function + @return an evdns_request object if successful, or NULL if an error occurred. + @see evdns_resolve_reverse_ipv6(), evdns_cancel_request() + */ +EVENT2_EXPORT_SYMBOL +struct evdns_request *evdns_base_resolve_reverse_ipv6(struct evdns_base *base, const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr); + +/** + Cancels a pending DNS resolution request. + + @param base the evdns_base that was used to make the request + @param req the evdns_request that was returned by calling a resolve function + @see evdns_base_resolve_ipv4(), evdns_base_resolve_ipv6, evdns_base_resolve_reverse +*/ +EVENT2_EXPORT_SYMBOL +void evdns_cancel_request(struct evdns_base *base, struct evdns_request *req); + +/** + Set the value of a configuration option. + + The currently available configuration options are: + + ndots, timeout, max-timeouts, max-inflight, attempts, randomize-case, + bind-to, initial-probe-timeout, getaddrinfo-allow-skew, + so-rcvbuf, so-sndbuf. + + In versions before Libevent 2.0.3-alpha, the option name needed to end with + a colon. + + @param base the evdns_base to which to apply this operation + @param option the name of the configuration option to be modified + @param val the value to be set + @return 0 if successful, or -1 if an error occurred + */ +EVENT2_EXPORT_SYMBOL +int evdns_base_set_option(struct evdns_base *base, const char *option, const char *val); + + +/** + Parse a resolv.conf file. + + The 'flags' parameter determines what information is parsed from the + resolv.conf file. See the man page for resolv.conf for the format of this + file. + + The following directives are not parsed from the file: sortlist, rotate, + no-check-names, inet6, debug. + + If this function encounters an error, the possible return values are: 1 = + failed to open file, 2 = failed to stat file, 3 = file too large, 4 = out of + memory, 5 = short read from file, 6 = no nameservers listed in the file + + @param base the evdns_base to which to apply this operation + @param flags any of DNS_OPTION_NAMESERVERS|DNS_OPTION_SEARCH|DNS_OPTION_MISC| + DNS_OPTION_HOSTSFILE|DNS_OPTIONS_ALL|DNS_OPTION_NAMESERVERS_NO_DEFAULT + @param filename the path to the resolv.conf file + @return 0 if successful, or various positive error codes if an error + occurred (see above) + @see resolv.conf(3), evdns_config_windows_nameservers() + */ +EVENT2_EXPORT_SYMBOL +int evdns_base_resolv_conf_parse(struct evdns_base *base, int flags, const char *const filename); + +/** + Load an /etc/hosts-style file from 'hosts_fname' into 'base'. + + If hosts_fname is NULL, add minimal entries for localhost, and nothing + else. + + Note that only evdns_getaddrinfo uses the /etc/hosts entries. + + This function does not replace previously loaded hosts entries; to do that, + call evdns_base_clear_host_addresses first. + + Return 0 on success, negative on failure. +*/ +EVENT2_EXPORT_SYMBOL +int evdns_base_load_hosts(struct evdns_base *base, const char *hosts_fname); + +#if defined(EVENT_IN_DOXYGEN_) || defined(_WIN32) +/** + Obtain nameserver information using the Windows API. + + Attempt to configure a set of nameservers based on platform settings on + a win32 host. Preferentially tries to use GetNetworkParams; if that fails, + looks in the registry. + + @return 0 if successful, or -1 if an error occurred + @see evdns_resolv_conf_parse() + */ +EVENT2_EXPORT_SYMBOL +int evdns_base_config_windows_nameservers(struct evdns_base *); +#define EVDNS_BASE_CONFIG_WINDOWS_NAMESERVERS_IMPLEMENTED +#endif + + +/** + Clear the list of search domains. + */ +EVENT2_EXPORT_SYMBOL +void evdns_base_search_clear(struct evdns_base *base); + + +/** + Add a domain to the list of search domains + + @param domain the domain to be added to the search list + */ +EVENT2_EXPORT_SYMBOL +void evdns_base_search_add(struct evdns_base *base, const char *domain); + + +/** + Set the 'ndots' parameter for searches. + + Sets the number of dots which, when found in a name, causes + the first query to be without any search domain. + + @param ndots the new ndots parameter + */ +EVENT2_EXPORT_SYMBOL +void evdns_base_search_ndots_set(struct evdns_base *base, const int ndots); + +/** + A callback that is invoked when a log message is generated + + @param is_warning indicates if the log message is a 'warning' + @param msg the content of the log message + */ +typedef void (*evdns_debug_log_fn_type)(int is_warning, const char *msg); + + +/** + Set the callback function to handle DNS log messages. If this + callback is not set, evdns log messages are handled with the regular + Libevent logging system. + + @param fn the callback to be invoked when a log message is generated + */ +EVENT2_EXPORT_SYMBOL +void evdns_set_log_fn(evdns_debug_log_fn_type fn); + +/** + Set a callback that will be invoked to generate transaction IDs. By + default, we pick transaction IDs based on the current clock time, which + is bad for security. + + @param fn the new callback, or NULL to use the default. + + NOTE: This function has no effect in Libevent 2.0.4-alpha and later, + since Libevent now provides its own secure RNG. + */ +EVENT2_EXPORT_SYMBOL +void evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void)); + +/** + Set a callback used to generate random bytes. By default, we use + the same function as passed to evdns_set_transaction_id_fn to generate + bytes two at a time. If a function is provided here, it's also used + to generate transaction IDs. + + NOTE: This function has no effect in Libevent 2.0.4-alpha and later, + since Libevent now provides its own secure RNG. +*/ +EVENT2_EXPORT_SYMBOL +void evdns_set_random_bytes_fn(void (*fn)(char *, size_t)); + +/* + * Functions used to implement a DNS server. + */ + +struct evdns_server_request; +struct evdns_server_question; + +/** + A callback to implement a DNS server. The callback function receives a DNS + request. It should then optionally add a number of answers to the reply + using the evdns_server_request_add_*_reply functions, before calling either + evdns_server_request_respond to send the reply back, or + evdns_server_request_drop to decline to answer the request. + + @param req A newly received request + @param user_data A pointer that was passed to + evdns_add_server_port_with_base(). + */ +typedef void (*evdns_request_callback_fn_type)(struct evdns_server_request *, void *); +#define EVDNS_ANSWER_SECTION 0 +#define EVDNS_AUTHORITY_SECTION 1 +#define EVDNS_ADDITIONAL_SECTION 2 + +#define EVDNS_TYPE_A 1 +#define EVDNS_TYPE_NS 2 +#define EVDNS_TYPE_CNAME 5 +#define EVDNS_TYPE_SOA 6 +#define EVDNS_TYPE_PTR 12 +#define EVDNS_TYPE_MX 15 +#define EVDNS_TYPE_TXT 16 +#define EVDNS_TYPE_AAAA 28 + +#define EVDNS_QTYPE_AXFR 252 +#define EVDNS_QTYPE_ALL 255 + +#define EVDNS_CLASS_INET 1 + +/* flags that can be set in answers; as part of the err parameter */ +#define EVDNS_FLAGS_AA 0x400 +#define EVDNS_FLAGS_RD 0x080 + +/** Create a new DNS server port. + + @param base The event base to handle events for the server port. + @param socket A UDP socket to accept DNS requests. + @param flags Always 0 for now. + @param callback A function to invoke whenever we get a DNS request + on the socket. + @param user_data Data to pass to the callback. + @return an evdns_server_port structure for this server port or NULL if + an error occurred. + */ +EVENT2_EXPORT_SYMBOL +struct evdns_server_port *evdns_add_server_port_with_base(struct event_base *base, evutil_socket_t socket, int flags, evdns_request_callback_fn_type callback, void *user_data); +/** Close down a DNS server port, and free associated structures. */ +EVENT2_EXPORT_SYMBOL +void evdns_close_server_port(struct evdns_server_port *port); + +/** Sets some flags in a reply we're building. + Allows setting of the AA or RD flags + */ +EVENT2_EXPORT_SYMBOL +void evdns_server_request_set_flags(struct evdns_server_request *req, int flags); + +/* Functions to add an answer to an in-progress DNS reply. + */ +EVENT2_EXPORT_SYMBOL +int evdns_server_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int dns_class, int ttl, int datalen, int is_name, const char *data); +EVENT2_EXPORT_SYMBOL +int evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl); +EVENT2_EXPORT_SYMBOL +int evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl); +EVENT2_EXPORT_SYMBOL +int evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl); +EVENT2_EXPORT_SYMBOL +int evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl); + +/** + Send back a response to a DNS request, and free the request structure. +*/ +EVENT2_EXPORT_SYMBOL +int evdns_server_request_respond(struct evdns_server_request *req, int err); +/** + Free a DNS request without sending back a reply. +*/ +EVENT2_EXPORT_SYMBOL +int evdns_server_request_drop(struct evdns_server_request *req); +struct sockaddr; +/** + Get the address that made a DNS request. + */ +EVENT2_EXPORT_SYMBOL +int evdns_server_request_get_requesting_addr(struct evdns_server_request *req, struct sockaddr *sa, int addr_len); + +/** Callback for evdns_getaddrinfo. */ +typedef void (*evdns_getaddrinfo_cb)(int result, struct evutil_addrinfo *res, void *arg); + +struct evdns_base; +struct evdns_getaddrinfo_request; +/** Make a non-blocking getaddrinfo request using the dns_base in 'dns_base'. + * + * If we can answer the request immediately (with an error or not!), then we + * invoke cb immediately and return NULL. Otherwise we return + * an evdns_getaddrinfo_request and invoke cb later. + * + * When the callback is invoked, we pass as its first argument the error code + * that getaddrinfo would return (or 0 for no error). As its second argument, + * we pass the evutil_addrinfo structures we found (or NULL on error). We + * pass 'arg' as the third argument. + * + * Limitations: + * + * - The AI_V4MAPPED and AI_ALL flags are not currently implemented. + * - For ai_socktype, we only handle SOCKTYPE_STREAM, SOCKTYPE_UDP, and 0. + * - For ai_protocol, we only handle IPPROTO_TCP, IPPROTO_UDP, and 0. + */ +EVENT2_EXPORT_SYMBOL +struct evdns_getaddrinfo_request *evdns_getaddrinfo( + struct evdns_base *dns_base, + const char *nodename, const char *servname, + const struct evutil_addrinfo *hints_in, + evdns_getaddrinfo_cb cb, void *arg); + +/* Cancel an in-progress evdns_getaddrinfo. This MUST NOT be called after the + * getaddrinfo's callback has been invoked. The resolves will be canceled, + * and the callback will be invoked with the error EVUTIL_EAI_CANCEL. */ +EVENT2_EXPORT_SYMBOL +void evdns_getaddrinfo_cancel(struct evdns_getaddrinfo_request *req); + +/** + Retrieve the address of the 'idx'th configured nameserver. + + @param base The evdns_base to examine. + @param idx The index of the nameserver to get the address of. + @param sa A location to receive the server's address. + @param len The number of bytes available at sa. + + @return the number of bytes written into sa on success. On failure, returns + -1 if idx is greater than the number of configured nameservers, or a + value greater than 'len' if len was not high enough. + */ +EVENT2_EXPORT_SYMBOL +int evdns_base_get_nameserver_addr(struct evdns_base *base, int idx, + struct sockaddr *sa, ev_socklen_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* !EVENT2_DNS_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/include/event2/dns_compat.h b/bsnes/thrift/libevent/include/event2/dns_compat.h new file mode 100644 index 00000000..a58c4b29 --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/dns_compat.h @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2006-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_DNS_COMPAT_H_INCLUDED_ +#define EVENT2_DNS_COMPAT_H_INCLUDED_ + +/** @file event2/dns_compat.h + + Potentially non-threadsafe versions of the functions in dns.h: provided + only for backwards compatibility. + + + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif + +/* For int types. */ +#include +#include + +/** + Initialize the asynchronous DNS library. + + This function initializes support for non-blocking name resolution by + calling evdns_resolv_conf_parse() on UNIX and + evdns_config_windows_nameservers() on Windows. + + @deprecated This function is deprecated because it always uses the current + event base, and is easily confused by multiple calls to event_init(), and + so is not safe for multithreaded use. Additionally, it allocates a global + structure that only one thread can use. The replacement is + evdns_base_new(). + + @return 0 if successful, or -1 if an error occurred + @see evdns_shutdown() + */ +EVENT2_EXPORT_SYMBOL +int evdns_init(void); + +struct evdns_base; +/** + Return the global evdns_base created by event_init() and used by the other + deprecated functions. + + @deprecated This function is deprecated because use of the global + evdns_base is error-prone. + */ +EVENT2_EXPORT_SYMBOL +struct evdns_base *evdns_get_global_base(void); + +/** + Shut down the asynchronous DNS resolver and terminate all active requests. + + If the 'fail_requests' option is enabled, all active requests will return + an empty result with the error flag set to DNS_ERR_SHUTDOWN. Otherwise, + the requests will be silently discarded. + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_shutdown(). + + @param fail_requests if zero, active requests will be aborted; if non-zero, + active requests will return DNS_ERR_SHUTDOWN. + @see evdns_init() + */ +EVENT2_EXPORT_SYMBOL +void evdns_shutdown(int fail_requests); + +/** + Add a nameserver. + + The address should be an IPv4 address in network byte order. + The type of address is chosen so that it matches in_addr.s_addr. + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_nameserver_add(). + + @param address an IP address in network byte order + @return 0 if successful, or -1 if an error occurred + @see evdns_nameserver_ip_add() + */ +EVENT2_EXPORT_SYMBOL +int evdns_nameserver_add(unsigned long int address); + +/** + Get the number of configured nameservers. + + This returns the number of configured nameservers (not necessarily the + number of running nameservers). This is useful for double-checking + whether our calls to the various nameserver configuration functions + have been successful. + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_count_nameservers(). + + @return the number of configured nameservers + @see evdns_nameserver_add() + */ +EVENT2_EXPORT_SYMBOL +int evdns_count_nameservers(void); + +/** + Remove all configured nameservers, and suspend all pending resolves. + + Resolves will not necessarily be re-attempted until evdns_resume() is called. + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_clear_nameservers_and_suspend(). + + @return 0 if successful, or -1 if an error occurred + @see evdns_resume() + */ +EVENT2_EXPORT_SYMBOL +int evdns_clear_nameservers_and_suspend(void); + +/** + Resume normal operation and continue any suspended resolve requests. + + Re-attempt resolves left in limbo after an earlier call to + evdns_clear_nameservers_and_suspend(). + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_resume(). + + @return 0 if successful, or -1 if an error occurred + @see evdns_clear_nameservers_and_suspend() + */ +EVENT2_EXPORT_SYMBOL +int evdns_resume(void); + +/** + Add a nameserver. + + This wraps the evdns_nameserver_add() function by parsing a string as an IP + address and adds it as a nameserver. + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_nameserver_ip_add(). + + @return 0 if successful, or -1 if an error occurred + @see evdns_nameserver_add() + */ +EVENT2_EXPORT_SYMBOL +int evdns_nameserver_ip_add(const char *ip_as_string); + +/** + Lookup an A record for a given name. + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_resolve_ipv4(). + + @param name a DNS hostname + @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. + @param callback a callback function to invoke when the request is completed + @param ptr an argument to pass to the callback function + @return 0 if successful, or -1 if an error occurred + @see evdns_resolve_ipv6(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6() + */ +EVENT2_EXPORT_SYMBOL +int evdns_resolve_ipv4(const char *name, int flags, evdns_callback_type callback, void *ptr); + +/** + Lookup an AAAA record for a given name. + + @param name a DNS hostname + @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. + @param callback a callback function to invoke when the request is completed + @param ptr an argument to pass to the callback function + @return 0 if successful, or -1 if an error occurred + @see evdns_resolve_ipv4(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6() + */ +EVENT2_EXPORT_SYMBOL +int evdns_resolve_ipv6(const char *name, int flags, evdns_callback_type callback, void *ptr); + +struct in_addr; +struct in6_addr; + +/** + Lookup a PTR record for a given IP address. + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_resolve_reverse(). + + @param in an IPv4 address + @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. + @param callback a callback function to invoke when the request is completed + @param ptr an argument to pass to the callback function + @return 0 if successful, or -1 if an error occurred + @see evdns_resolve_reverse_ipv6() + */ +EVENT2_EXPORT_SYMBOL +int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr); + +/** + Lookup a PTR record for a given IPv6 address. + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_resolve_reverse_ipv6(). + + @param in an IPv6 address + @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. + @param callback a callback function to invoke when the request is completed + @param ptr an argument to pass to the callback function + @return 0 if successful, or -1 if an error occurred + @see evdns_resolve_reverse_ipv6() + */ +EVENT2_EXPORT_SYMBOL +int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr); + +/** + Set the value of a configuration option. + + The currently available configuration options are: + + ndots, timeout, max-timeouts, max-inflight, and attempts + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_set_option(). + + @param option the name of the configuration option to be modified + @param val the value to be set + @param flags Ignored. + @return 0 if successful, or -1 if an error occurred + */ +EVENT2_EXPORT_SYMBOL +int evdns_set_option(const char *option, const char *val, int flags); + +/** + Parse a resolv.conf file. + + The 'flags' parameter determines what information is parsed from the + resolv.conf file. See the man page for resolv.conf for the format of this + file. + + The following directives are not parsed from the file: sortlist, rotate, + no-check-names, inet6, debug. + + If this function encounters an error, the possible return values are: 1 = + failed to open file, 2 = failed to stat file, 3 = file too large, 4 = out of + memory, 5 = short read from file, 6 = no nameservers listed in the file + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_resolv_conf_parse(). + + @param flags any of DNS_OPTION_NAMESERVERS|DNS_OPTION_SEARCH|DNS_OPTION_MISC| + DNS_OPTIONS_ALL + @param filename the path to the resolv.conf file + @return 0 if successful, or various positive error codes if an error + occurred (see above) + @see resolv.conf(3), evdns_config_windows_nameservers() + */ +EVENT2_EXPORT_SYMBOL +int evdns_resolv_conf_parse(int flags, const char *const filename); + +/** + Clear the list of search domains. + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_search_clear(). + */ +EVENT2_EXPORT_SYMBOL +void evdns_search_clear(void); + +/** + Add a domain to the list of search domains + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_search_add(). + + @param domain the domain to be added to the search list + */ +EVENT2_EXPORT_SYMBOL +void evdns_search_add(const char *domain); + +/** + Set the 'ndots' parameter for searches. + + Sets the number of dots which, when found in a name, causes + the first query to be without any search domain. + + @deprecated This function is deprecated because it does not allow the + caller to specify which evdns_base it applies to. The recommended + function is evdns_base_search_ndots_set(). + + @param ndots the new ndots parameter + */ +EVENT2_EXPORT_SYMBOL +void evdns_search_ndots_set(const int ndots); + +/** + As evdns_server_new_with_base. + + @deprecated This function is deprecated because it does not allow the + caller to specify which even_base it uses. The recommended + function is evdns_add_server_port_with_base(). + +*/ +EVENT2_EXPORT_SYMBOL +struct evdns_server_port * +evdns_add_server_port(evutil_socket_t socket, int flags, + evdns_request_callback_fn_type callback, void *user_data); + +#ifdef _WIN32 +EVENT2_EXPORT_SYMBOL +int evdns_config_windows_nameservers(void); +#define EVDNS_CONFIG_WINDOWS_NAMESERVERS_IMPLEMENTED +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_EVENT_COMPAT_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/include/event2/dns_struct.h b/bsnes/thrift/libevent/include/event2/dns_struct.h new file mode 100644 index 00000000..593a8a70 --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/dns_struct.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_DNS_STRUCT_H_INCLUDED_ +#define EVENT2_DNS_STRUCT_H_INCLUDED_ + +/** @file event2/dns_struct.h + + Data structures for dns. Using these structures may hurt forward + compatibility with later versions of Libevent: be careful! + + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif + +/* For int types. */ +#include + +/* + * Structures used to implement a DNS server. + */ + +struct evdns_server_request { + int flags; + int nquestions; + struct evdns_server_question **questions; +}; +struct evdns_server_question { + int type; +#ifdef __cplusplus + int dns_question_class; +#else + /* You should refer to this field as "dns_question_class". The + * name "class" works in C for backward compatibility, and will be + * removed in a future version. (1.5 or later). */ + int class; +#define dns_question_class class +#endif + char name[1]; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_DNS_STRUCT_H_INCLUDED_ */ + diff --git a/bsnes/thrift/libevent/include/event2/event-config.h b/bsnes/thrift/libevent/include/event2/event-config.h new file mode 100644 index 00000000..874e6829 --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/event-config.h @@ -0,0 +1,513 @@ +/* event-config.h + * + * This file was generated by cmake when the makefiles were generated. + * + * DO NOT EDIT THIS FILE. + * + * Do not rely on macros in this file existing in later versions. + */ +#ifndef EVENT2_EVENT_CONFIG_H_INCLUDED_ +#define EVENT2_EVENT_CONFIG_H_INCLUDED_ + +/* Numeric representation of the version */ +#define EVENT__NUMERIC_VERSION 0x02010c00 +#define EVENT__PACKAGE_VERSION "2.1.12" + +#define EVENT__VERSION_MAJOR 2 +#define EVENT__VERSION_MINOR 1 +#define EVENT__VERSION_PATCH 12 + +/* Version number of package */ +#define EVENT__VERSION "2.1.12-stable" + +/* Name of package */ +#define EVENT__PACKAGE "libevent" + +/* Define to the address where bug reports for this package should be sent. */ +#define EVENT__PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define EVENT__PACKAGE_NAME "" + +/* Define to the full name and version of this package. */ +#define EVENT__PACKAGE_STRING "" + +/* Define to the one symbol short name of this package. */ +#define EVENT__PACKAGE_TARNAME "" + +/* Define if libevent should build without support for a debug mode */ +#define EVENT__DISABLE_DEBUG_MODE 1 + +/* Define if libevent should not allow replacing the mm functions */ +#define EVENT__DISABLE_MM_REPLACEMENT 1 + +/* Define if libevent should not be compiled with thread support */ +/* #undef EVENT__DISABLE_THREAD_SUPPORT */ + +/* Define to 1 if you have the `accept4' function. */ +/* #undef EVENT__HAVE_ACCEPT4 */ + +/* Define to 1 if you have the `arc4random' function. */ +/* #undef EVENT__HAVE_ARC4RANDOM */ + +/* Define to 1 if you have the `arc4random_buf' function. */ +/* #undef EVENT__HAVE_ARC4RANDOM_BUF */ + +/* Define to 1 if you have the `arc4random_addrandom' function. */ +/* #undef EVENT__HAVE_ARC4RANDOM_ADDRANDOM */ + +/* Define if clock_gettime is available in libc */ +/* #undef EVENT__DNS_USE_CPU_CLOCK_FOR_ID */ + +/* Define is no secure id variant is available */ +/* #undef EVENT__DNS_USE_GETTIMEOFDAY_FOR_ID */ +#define EVENT__DNS_USE_FTIME_FOR_ID 1 + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_ARPA_INET_H */ + +/* Define to 1 if you have the `clock_gettime' function. */ +/* #undef EVENT__HAVE_CLOCK_GETTIME */ + +/* Define to 1 if you have the declaration of `CTL_KERN'. */ +#define EVENT__HAVE_DECL_CTL_KERN 0 + +/* Define to 1 if you have the declaration of `KERN_ARND'. */ +#define EVENT__HAVE_DECL_KERN_ARND 0 + +/* Define to 1 if you have `getrandom' function. */ +/* #undef EVENT__HAVE_GETRANDOM */ + +/* Define if /dev/poll is available */ +/* #undef EVENT__HAVE_DEVPOLL */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_NETDB_H */ + +/* Define to 1 if fd_mask type is defined */ +/* #undef EVENT__HAVE_FD_MASK */ + +/* Define to 1 if the header file defines TAILQ_FOREACH. */ +/* #undef EVENT__HAVE_TAILQFOREACH */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_DLFCN_H */ + +/* Define if your system supports the epoll system calls */ +/* #undef EVENT__HAVE_EPOLL */ + +/* Define to 1 if you have the `epoll_create1' function. */ +/* #undef EVENT__HAVE_EPOLL_CREATE1 */ + +/* Define to 1 if you have the `epoll_ctl' function. */ +/* #undef EVENT__HAVE_EPOLL_CTL */ + +/* Define to 1 if you have the `eventfd' function. */ +/* #undef EVENT__HAVE_EVENTFD */ + +/* Define if your system supports event ports */ +/* #undef EVENT__HAVE_EVENT_PORTS */ + +/* Define to 1 if you have the `fcntl' function. */ +/* #undef EVENT__HAVE_FCNTL */ + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `getaddrinfo' function. */ +#define EVENT__HAVE_GETADDRINFO 1 + +/* Define to 1 if you have the `getegid' function. */ +/* #undef EVENT__HAVE_GETEGID */ + +/* Define to 1 if you have the `geteuid' function. */ +/* #undef EVENT__HAVE_GETEUID */ + +/* TODO: Check for different gethostname argument counts. CheckPrototypeDefinition.cmake can be used. */ +/* Define this if you have any gethostbyname_r() */ +/* #undef EVENT__HAVE_GETHOSTBYNAME_R */ + +/* Define this if gethostbyname_r takes 3 arguments */ +/* #undef EVENT__HAVE_GETHOSTBYNAME_R_3_ARG */ + +/* Define this if gethostbyname_r takes 5 arguments */ +/* #undef EVENT__HAVE_GETHOSTBYNAME_R_5_ARG */ + +/* Define this if gethostbyname_r takes 6 arguments */ +/* #undef EVENT__HAVE_GETHOSTBYNAME_R_6_ARG */ + +/* Define to 1 if you have the `getifaddrs' function. */ +/* #undef EVENT__HAVE_GETIFADDRS */ + +/* Define to 1 if you have the `getnameinfo' function. */ +#define EVENT__HAVE_GETNAMEINFO 1 + +/* Define to 1 if you have the `getprotobynumber' function. */ +#define EVENT__HAVE_GETPROTOBYNUMBER 1 + +/* Define to 1 if you have the `getservbyname' function. */ +#define EVENT__HAVE_GETSERVBYNAME 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +/* #undef EVENT__HAVE_GETTIMEOFDAY */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_IFADDRS_H */ + +/* Define to 1 if you have the `inet_ntop' function. */ +/* #undef EVENT__HAVE_INET_NTOP */ + +/* Define to 1 if you have the `inet_pton' function. */ +/* #undef EVENT__HAVE_INET_PTON */ + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `issetugid' function. */ +/* #undef EVENT__HAVE_ISSETUGID */ + +/* Define to 1 if you have the `kqueue' function. */ +/* #undef EVENT__HAVE_KQUEUE */ + +/* Define if the system has zlib */ +/* #undef EVENT__HAVE_LIBZ */ + +/* Define to 1 if you have the `mach_absolute_time' function. */ +/* #undef EVENT__HAVE_MACH_ABSOLUTE_TIME */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_MACH_MACH_TIME_H */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_MACH_MACH_H */ + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mmap' function. */ +/* #undef EVENT__HAVE_MMAP */ + +/* Define to 1 if you have the `nanosleep' function. */ +/* #undef EVENT__HAVE_NANOSLEEP */ + +/* Define to 1 if you have the `usleep' function. */ +/* #undef EVENT__HAVE_USLEEP */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_NETINET_IN6_H */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_NETINET_IN_H */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_NETINET_TCP_H */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_SYS_UN_H */ + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_AFUNIX_H 1 + +/* Define if the system has openssl */ +/* #undef EVENT__HAVE_OPENSSL */ + +/* Define to 1 if you have the `pipe' function. */ +/* #undef EVENT__HAVE_PIPE */ + +/* Define to 1 if you have the `pipe2' function. */ +/* #undef EVENT__HAVE_PIPE2 */ + +/* Define to 1 if you have the `poll' function. */ +/* #undef EVENT__HAVE_POLL */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_POLL_H */ + +/* Define to 1 if you have the `port_create' function. */ +/* #undef EVENT__HAVE_PORT_CREATE */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_PORT_H */ + +/* Define if we have pthreads on this system */ +/* #undef EVENT__HAVE_PTHREADS */ + +/* Define to 1 if you have the `putenv' function. */ +#define EVENT__HAVE_PUTENV 1 + +/* Define to 1 if the system has the type `sa_family_t'. */ +/* #undef EVENT__HAVE_SA_FAMILY_T */ + +/* Define to 1 if you have the `select' function. */ +/* #undef EVENT__HAVE_SELECT */ + +/* Define to 1 if you have the `setenv' function. */ +/* #undef EVENT__HAVE_SETENV */ + +/* Define if F_SETFD is defined in */ +/* #undef EVENT__HAVE_SETFD */ + +/* Define to 1 if you have the `setrlimit' function. */ +/* #undef EVENT__HAVE_SETRLIMIT */ + +/* Define to 1 if you have the `sendfile' function. */ +/* #undef EVENT__HAVE_SENDFILE */ + +/* Define to 1 if you have the `sigaction' function. */ +/* #undef EVENT__HAVE_SIGACTION */ + +/* Define to 1 if you have the `signal' function. */ +#define EVENT__HAVE_SIGNAL 1 + +/* Define to 1 if you have the `splice' function. */ +/* #undef EVENT__HAVE_SPLICE */ + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_STDDEF_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_STRING_H 1 + +/* Define to 1 if you have the `strlcpy' function. */ +/* #undef EVENT__HAVE_STRLCPY */ + +/* Define to 1 if you have the `strsep' function. */ +/* #undef EVENT__HAVE_STRSEP */ + +/* Define to 1 if you have the `strtok_r' function. */ +/* #undef EVENT__HAVE_STRTOK_R */ + +/* Define to 1 if you have the `strtoll' function. */ +#define EVENT__HAVE_STRTOLL 1 + +/* Define to 1 if you have the `_gmtime64_s' function. */ +#define EVENT__HAVE__GMTIME64_S 1 + +/* Define to 1 if you have the `_gmtime64' function. */ +#define EVENT__HAVE__GMTIME64 1 + +/* Define to 1 if the system has the type `struct addrinfo'. */ +#define EVENT__HAVE_STRUCT_ADDRINFO 1 + +/* Define to 1 if the system has the type `struct in6_addr'. */ +#define EVENT__HAVE_STRUCT_IN6_ADDR 1 + +/* Define to 1 if `s6_addr16' is member of `struct in6_addr'. */ +/* #undef EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR16 */ + +/* Define to 1 if `s6_addr32' is member of `struct in6_addr'. */ +/* #undef EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR32 */ + +/* Define to 1 if the system has the type `struct sockaddr_in6'. */ +#define EVENT__HAVE_STRUCT_SOCKADDR_IN6 1 + +/* Define to 1 if `sin6_len' is member of `struct sockaddr_in6'. */ +/* #undef EVENT__HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN */ + +/* Define to 1 if `sin_len' is member of `struct sockaddr_in'. */ +/* #undef EVENT__HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ + +/* Define to 1 if the system has the type `struct sockaddr_un'. */ +#define EVENT__HAVE_STRUCT_SOCKADDR_UN 1 + +/* Define to 1 if the system has the type `struct sockaddr_storage'. */ +#define EVENT__HAVE_STRUCT_SOCKADDR_STORAGE 1 + +/* Define to 1 if `ss_family' is a member of `struct sockaddr_storage'. */ +#define EVENT__HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY 1 + +/* Define to 1 if `__ss_family' is a member of `struct sockaddr_storage'. */ +/* #undef EVENT__HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY */ + +/* Define to 1 if the system has the type `struct linger'. */ +#define EVENT__HAVE_STRUCT_LINGER 1 + +/* Define to 1 if you have the `sysctl' function. */ +/* #undef EVENT__HAVE_SYSCTL */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_SYS_EPOLL_H */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_SYS_EVENTFD_H */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_SYS_EVENT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_SYS_IOCTL_H */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_SYS_MMAN_H */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_SYS_PARAM_H */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_SYS_QUEUE_H */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_SYS_RESOURCE_H */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_SYS_SELECT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_SYS_SENDFILE_H */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_SYS_SOCKET_H */ + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_SYS_RANDOM_H */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_SYS_SYSCTL_H */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_SYS_TIMERFD_H */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_SYS_TIME_H */ + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_SYS_UIO_H */ + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_SYS_WAIT_H */ + +/* Define to 1 if you have the header file. */ +#define EVENT__HAVE_ERRNO_H 1 + +/* Define if TAILQ_FOREACH is defined in */ +/* #undef EVENT__HAVE_TAILQFOREACH */ + +/* Define if timeradd is defined in */ +/* #undef EVENT__HAVE_TIMERADD */ + +/* Define if timerclear is defined in */ +#define EVENT__HAVE_TIMERCLEAR 1 + +/* Define if timercmp is defined in */ +#define EVENT__HAVE_TIMERCMP 1 + + +/* Define to 1 if you have the `timerfd_create' function. */ +/* #undef EVENT__HAVE_TIMERFD_CREATE */ + +/* Define if timerisset is defined in */ +#define EVENT__HAVE_TIMERISSET 1 + +/* Define to 1 if the system has the type `uint8_t'. */ +#define EVENT__HAVE_UINT8_T 1 + +/* Define to 1 if the system has the type `uint16_t'. */ +#define EVENT__HAVE_UINT16_T 1 + +/* Define to 1 if the system has the type `uint32_t'. */ +#define EVENT__HAVE_UINT32_T 1 + +/* Define to 1 if the system has the type `uint64_t'. */ +#define EVENT__HAVE_UINT64_T 1 + +/* Define to 1 if the system has the type `uintptr_t'. */ +#define EVENT__HAVE_UINTPTR_T 1 + +/* Define to 1 if you have the `umask' function. */ +#define EVENT__HAVE_UMASK 1 + +/* Define to 1 if you have the header file. */ +/* #undef EVENT__HAVE_UNISTD_H */ + +/* Define to 1 if you have the `unsetenv' function. */ +/* #undef EVENT__HAVE_UNSETENV */ + +/* Define to 1 if you have the `vasprintf' function. */ +/* #undef EVENT__HAVE_VASPRINTF */ + +/* Define if kqueue works correctly with pipes */ +/* #undef EVENT__HAVE_WORKING_KQUEUE */ + +#ifdef __USE_UNUSED_DEFINITIONS__ +/* Define to necessary symbol if this constant uses a non-standard name on your system. */ +/* XXX: Hello, this isn't even used, nor is it defined anywhere... - Ellzey */ +#define EVENT__PTHREAD_CREATE_JOINABLE +#endif + +/* The size of `pthread_t', as computed by sizeof. */ +#define EVENT__SIZEOF_PTHREAD_T + +/* The size of a `int', as computed by sizeof. */ +#define EVENT__SIZEOF_INT 4 + +/* The size of a `long', as computed by sizeof. */ +#define EVENT__SIZEOF_LONG 4 + +/* The size of a `long long', as computed by sizeof. */ +#define EVENT__SIZEOF_LONG_LONG 8 + +/* The size of `off_t', as computed by sizeof. */ +#define EVENT__SIZEOF_OFF_T 4 + +#define EVENT__SIZEOF_SSIZE_T 8 + + +/* The size of a `short', as computed by sizeof. */ +#define EVENT__SIZEOF_SHORT 2 + +/* The size of `size_t', as computed by sizeof. */ +#define EVENT__SIZEOF_SIZE_T 8 + +/* Define to 1 if you can safely include both and . */ +/* #undef EVENT__TIME_WITH_SYS_TIME */ + +/* The size of `socklen_t', as computed by sizeof. */ +#define EVENT__SIZEOF_SOCKLEN_T 4 + +/* The size of 'void *', as computer by sizeof */ +#define EVENT__SIZEOF_VOID_P 8 + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* why not c++? + * + * and are we really expected to use EVENT__inline everywhere, + * shouldn't we just do: + * ifdef EVENT__inline + * define inline EVENT__inline + * + * - Ellzey + */ + +#define EVENT__inline inline +#endif + +#define EVENT__HAVE___func__ 1 +#define EVENT__HAVE___FUNCTION__ 1 + +/* Define to `unsigned' if does not define. */ +#define EVENT__size_t size_t + +/* Define to unsigned int if you dont have it */ +#define EVENT__socklen_t socklen_t + +/* Define to `int' if does not define. */ +#define EVENT__ssize_t SSIZE_T + +#endif /* \EVENT2_EVENT_CONFIG_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/include/event2/event.h b/bsnes/thrift/libevent/include/event2/event.h new file mode 100644 index 00000000..a6b6144a --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/event.h @@ -0,0 +1,1672 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_EVENT_H_INCLUDED_ +#define EVENT2_EVENT_H_INCLUDED_ + +/** + @mainpage + + @section intro Introduction + + Libevent is an event notification library for developing scalable network + servers. The Libevent API provides a mechanism to execute a callback + function when a specific event occurs on a file descriptor or after a + timeout has been reached. Furthermore, Libevent also support callbacks due + to signals or regular timeouts. + + Libevent is meant to replace the event loop found in event driven network + servers. An application just needs to call event_base_dispatch() and then add or + remove events dynamically without having to change the event loop. + + + Currently, Libevent supports /dev/poll, kqueue(2), select(2), poll(2), + epoll(4), and evports. The internal event mechanism is completely + independent of the exposed event API, and a simple update of Libevent can + provide new functionality without having to redesign the applications. As a + result, Libevent allows for portable application development and provides + the most scalable event notification mechanism available on an operating + system. Libevent can also be used for multithreaded programs. Libevent + should compile on Linux, *BSD, Mac OS X, Solaris and, Windows. + + @section usage Standard usage + + Every program that uses Libevent must include the + header, and pass the -levent flag to the linker. (You can instead link + -levent_core if you only want the main event and buffered IO-based code, + and don't want to link any protocol code.) + + @section setup Library setup + + Before you call any other Libevent functions, you need to set up the + library. If you're going to use Libevent from multiple threads in a + multithreaded application, you need to initialize thread support -- + typically by using evthread_use_pthreads() or + evthread_use_windows_threads(). See for more + information. + + This is also the point where you can replace Libevent's memory + management functions with event_set_mem_functions, and enable debug mode + with event_enable_debug_mode(). + + @section base Creating an event base + + Next, you need to create an event_base structure, using event_base_new() + or event_base_new_with_config(). The event_base is responsible for + keeping track of which events are "pending" (that is to say, being + watched to see if they become active) and which events are "active". + Every event is associated with a single event_base. + + @section event Event notification + + For each file descriptor that you wish to monitor, you must create an + event structure with event_new(). (You may also declare an event + structure and call event_assign() to initialize the members of the + structure.) To enable notification, you add the structure to the list + of monitored events by calling event_add(). The event structure must + remain allocated as long as it is active, so it should generally be + allocated on the heap. + + @section loop Dispatching events. + + Finally, you call event_base_dispatch() to loop and dispatch events. + You can also use event_base_loop() for more fine-grained control. + + Currently, only one thread can be dispatching a given event_base at a + time. If you want to run events in multiple threads at once, you can + either have a single event_base whose events add work to a work queue, + or you can create multiple event_base objects. + + @section bufferevent I/O Buffers + + Libevent provides a buffered I/O abstraction on top of the regular event + callbacks. This abstraction is called a bufferevent. A bufferevent + provides input and output buffers that get filled and drained + automatically. The user of a buffered event no longer deals directly + with the I/O, but instead is reading from input and writing to output + buffers. + + Once initialized via bufferevent_socket_new(), the bufferevent structure + can be used repeatedly with bufferevent_enable() and + bufferevent_disable(). Instead of reading and writing directly to a + socket, you would call bufferevent_read() and bufferevent_write(). + + When read enabled the bufferevent will try to read from the file descriptor + and call the read callback. The write callback is executed whenever the + output buffer is drained below the write low watermark, which is 0 by + default. + + See for more information. + + @section timers Timers + + Libevent can also be used to create timers that invoke a callback after a + certain amount of time has expired. The evtimer_new() macro returns + an event struct to use as a timer. To activate the timer, call + evtimer_add(). Timers can be deactivated by calling evtimer_del(). + (These macros are thin wrappers around event_new(), event_add(), + and event_del(); you can also use those instead.) + + @section evdns Asynchronous DNS resolution + + Libevent provides an asynchronous DNS resolver that should be used instead + of the standard DNS resolver functions. See the + functions for more detail. + + @section evhttp Event-driven HTTP servers + + Libevent provides a very simple event-driven HTTP server that can be + embedded in your program and used to service HTTP requests. + + To use this capability, you need to include the header in your + program. See that header for more information. + + @section evrpc A framework for RPC servers and clients + + Libevent provides a framework for creating RPC servers and clients. It + takes care of marshaling and unmarshaling all data structures. + + @section api API Reference + + To browse the complete documentation of the libevent API, click on any of + the following links. + + event2/event.h + The primary libevent header + + event2/thread.h + Functions for use by multithreaded programs + + event2/buffer.h and event2/bufferevent.h + Buffer management for network reading and writing + + event2/util.h + Utility functions for portable nonblocking network code + + event2/dns.h + Asynchronous DNS resolution + + event2/http.h + An embedded libevent-based HTTP server + + event2/rpc.h + A framework for creating RPC servers and clients + + */ + +/** @file event2/event.h + + Core functions for waiting for and receiving events, and using event bases. +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif + +#include + +/* For int types. */ +#include + +/** + * Structure to hold information and state for a Libevent dispatch loop. + * + * The event_base lies at the center of Libevent; every application will + * have one. It keeps track of all pending and active events, and + * notifies your application of the active ones. + * + * This is an opaque structure; you can allocate one using + * event_base_new() or event_base_new_with_config(). + * + * @see event_base_new(), event_base_free(), event_base_loop(), + * event_base_new_with_config() + */ +struct event_base +#ifdef EVENT_IN_DOXYGEN_ +{/*Empty body so that doxygen will generate documentation here.*/} +#endif +; + +/** + * @struct event + * + * Structure to represent a single event. + * + * An event can have some underlying condition it represents: a socket + * becoming readable or writeable (or both), or a signal becoming raised. + * (An event that represents no underlying condition is still useful: you + * can use one to implement a timer, or to communicate between threads.) + * + * Generally, you can create events with event_new(), then make them + * pending with event_add(). As your event_base runs, it will run the + * callbacks of an events whose conditions are triggered. When you no + * longer want the event, free it with event_free(). + * + * In more depth: + * + * An event may be "pending" (one whose condition we are watching), + * "active" (one whose condition has triggered and whose callback is about + * to run), neither, or both. Events come into existence via + * event_assign() or event_new(), and are then neither active nor pending. + * + * To make an event pending, pass it to event_add(). When doing so, you + * can also set a timeout for the event. + * + * Events become active during an event_base_loop() call when either their + * condition has triggered, or when their timeout has elapsed. You can + * also activate an event manually using event_active(). The even_base + * loop will run the callbacks of active events; after it has done so, it + * marks them as no longer active. + * + * You can make an event non-pending by passing it to event_del(). This + * also makes the event non-active. + * + * Events can be "persistent" or "non-persistent". A non-persistent event + * becomes non-pending as soon as it is triggered: thus, it only runs at + * most once per call to event_add(). A persistent event remains pending + * even when it becomes active: you'll need to event_del() it manually in + * order to make it non-pending. When a persistent event with a timeout + * becomes active, its timeout is reset: this means you can use persistent + * events to implement periodic timeouts. + * + * This should be treated as an opaque structure; you should never read or + * write any of its fields directly. For backward compatibility with old + * code, it is defined in the event2/event_struct.h header; including this + * header may make your code incompatible with other versions of Libevent. + * + * @see event_new(), event_free(), event_assign(), event_get_assignment(), + * event_add(), event_del(), event_active(), event_pending(), + * event_get_fd(), event_get_base(), event_get_events(), + * event_get_callback(), event_get_callback_arg(), + * event_priority_set() + */ +struct event +#ifdef EVENT_IN_DOXYGEN_ +{/*Empty body so that doxygen will generate documentation here.*/} +#endif +; + +/** + * Configuration for an event_base. + * + * There are many options that can be used to alter the behavior and + * implementation of an event_base. To avoid having to pass them all in a + * complex many-argument constructor, we provide an abstract data type + * where you set up configuration information before passing it to + * event_base_new_with_config(). + * + * @see event_config_new(), event_config_free(), event_base_new_with_config(), + * event_config_avoid_method(), event_config_require_features(), + * event_config_set_flag(), event_config_set_num_cpus_hint() + */ +struct event_config +#ifdef EVENT_IN_DOXYGEN_ +{/*Empty body so that doxygen will generate documentation here.*/} +#endif +; + +/** + * Enable some relatively expensive debugging checks in Libevent that + * would normally be turned off. Generally, these checks cause code that + * would otherwise crash mysteriously to fail earlier with an assertion + * failure. Note that this method MUST be called before any events or + * event_bases have been created. + * + * Debug mode can currently catch the following errors: + * An event is re-assigned while it is added + * Any function is called on a non-assigned event + * + * Note that debugging mode uses memory to track every event that has been + * initialized (via event_assign, event_set, or event_new) but not yet + * released (via event_free or event_debug_unassign). If you want to use + * debug mode, and you find yourself running out of memory, you will need + * to use event_debug_unassign to explicitly stop tracking events that + * are no longer considered set-up. + * + * @see event_debug_unassign() + */ +EVENT2_EXPORT_SYMBOL +void event_enable_debug_mode(void); + +/** + * When debugging mode is enabled, informs Libevent that an event should no + * longer be considered as assigned. When debugging mode is not enabled, does + * nothing. + * + * This function must only be called on a non-added event. + * + * @see event_enable_debug_mode() + */ +EVENT2_EXPORT_SYMBOL +void event_debug_unassign(struct event *); + +/** + * Create and return a new event_base to use with the rest of Libevent. + * + * @return a new event_base on success, or NULL on failure. + * + * @see event_base_free(), event_base_new_with_config() + */ +EVENT2_EXPORT_SYMBOL +struct event_base *event_base_new(void); + +/** + Reinitialize the event base after a fork + + Some event mechanisms do not survive across fork. The event base needs + to be reinitialized with the event_reinit() function. + + @param base the event base that needs to be re-initialized + @return 0 if successful, or -1 if some events could not be re-added. + @see event_base_new() +*/ +EVENT2_EXPORT_SYMBOL +int event_reinit(struct event_base *base); + +/** + Event dispatching loop + + This loop will run the event base until either there are no more pending or + active, or until something calls event_base_loopbreak() or + event_base_loopexit(). + + @param base the event_base structure returned by event_base_new() or + event_base_new_with_config() + @return 0 if successful, -1 if an error occurred, or 1 if we exited because + no events were pending or active. + @see event_base_loop() + */ +EVENT2_EXPORT_SYMBOL +int event_base_dispatch(struct event_base *); + +/** + Get the kernel event notification mechanism used by Libevent. + + @param eb the event_base structure returned by event_base_new() + @return a string identifying the kernel event mechanism (kqueue, epoll, etc.) + */ +EVENT2_EXPORT_SYMBOL +const char *event_base_get_method(const struct event_base *); + +/** + Gets all event notification mechanisms supported by Libevent. + + This functions returns the event mechanism in order preferred by + Libevent. Note that this list will include all backends that + Libevent has compiled-in support for, and will not necessarily check + your OS to see whether it has the required resources. + + @return an array with pointers to the names of support methods. + The end of the array is indicated by a NULL pointer. If an + error is encountered NULL is returned. +*/ +EVENT2_EXPORT_SYMBOL +const char **event_get_supported_methods(void); + +/** Query the current monotonic time from a the timer for a struct + * event_base. + */ +EVENT2_EXPORT_SYMBOL +int event_gettime_monotonic(struct event_base *base, struct timeval *tp); + +/** + @name event type flag + + Flags to pass to event_base_get_num_events() to specify the kinds of events + we want to aggregate counts for +*/ +/**@{*/ +/** count the number of active events, which have been triggered.*/ +#define EVENT_BASE_COUNT_ACTIVE 1U +/** count the number of virtual events, which is used to represent an internal + * condition, other than a pending event, that keeps the loop from exiting. */ +#define EVENT_BASE_COUNT_VIRTUAL 2U +/** count the number of events which have been added to event base, including + * internal events. */ +#define EVENT_BASE_COUNT_ADDED 4U +/**@}*/ + +/** + Gets the number of events in event_base, as specified in the flags. + + Since event base has some internal events added to make some of its + functionalities work, EVENT_BASE_COUNT_ADDED may return more than the + number of events you added using event_add(). + + If you pass EVENT_BASE_COUNT_ACTIVE and EVENT_BASE_COUNT_ADDED together, an + active event will be counted twice. However, this might not be the case in + future libevent versions. The return value is an indication of the work + load, but the user shouldn't rely on the exact value as this may change in + the future. + + @param eb the event_base structure returned by event_base_new() + @param flags a bitwise combination of the kinds of events to aggregate + counts for + @return the number of events specified in the flags +*/ +EVENT2_EXPORT_SYMBOL +int event_base_get_num_events(struct event_base *, unsigned int); + +/** + Get the maximum number of events in a given event_base as specified in the + flags. + + @param eb the event_base structure returned by event_base_new() + @param flags a bitwise combination of the kinds of events to aggregate + counts for + @param clear option used to reset the maximum count. + @return the number of events specified in the flags + */ +EVENT2_EXPORT_SYMBOL +int event_base_get_max_events(struct event_base *, unsigned int, int); + +/** + Allocates a new event configuration object. + + The event configuration object can be used to change the behavior of + an event base. + + @return an event_config object that can be used to store configuration, or + NULL if an error is encountered. + @see event_base_new_with_config(), event_config_free(), event_config +*/ +EVENT2_EXPORT_SYMBOL +struct event_config *event_config_new(void); + +/** + Deallocates all memory associated with an event configuration object + + @param cfg the event configuration object to be freed. +*/ +EVENT2_EXPORT_SYMBOL +void event_config_free(struct event_config *cfg); + +/** + Enters an event method that should be avoided into the configuration. + + This can be used to avoid event mechanisms that do not support certain + file descriptor types, or for debugging to avoid certain event + mechanisms. An application can make use of multiple event bases to + accommodate incompatible file descriptor types. + + @param cfg the event configuration object + @param method the name of the event method to avoid + @return 0 on success, -1 on failure. +*/ +EVENT2_EXPORT_SYMBOL +int event_config_avoid_method(struct event_config *cfg, const char *method); + +/** + A flag used to describe which features an event_base (must) provide. + + Because of OS limitations, not every Libevent backend supports every + possible feature. You can use this type with + event_config_require_features() to tell Libevent to only proceed if your + event_base implements a given feature, and you can receive this type from + event_base_get_features() to see which features are available. +*/ +enum event_method_feature { + /** Require an event method that allows edge-triggered events with EV_ET. */ + EV_FEATURE_ET = 0x01, + /** Require an event method where having one event triggered among + * many is [approximately] an O(1) operation. This excludes (for + * example) select and poll, which are approximately O(N) for N + * equal to the total number of possible events. */ + EV_FEATURE_O1 = 0x02, + /** Require an event method that allows file descriptors as well as + * sockets. */ + EV_FEATURE_FDS = 0x04, + /** Require an event method that allows you to use EV_CLOSED to detect + * connection close without the necessity of reading all the pending data. + * + * Methods that do support EV_CLOSED may not be able to provide support on + * all kernel versions. + **/ + EV_FEATURE_EARLY_CLOSE = 0x08 +}; + +/** + A flag passed to event_config_set_flag(). + + These flags change the behavior of an allocated event_base. + + @see event_config_set_flag(), event_base_new_with_config(), + event_method_feature + */ +enum event_base_config_flag { + /** Do not allocate a lock for the event base, even if we have + locking set up. + + Setting this option will make it unsafe and nonfunctional to call + functions on the base concurrently from multiple threads. + */ + EVENT_BASE_FLAG_NOLOCK = 0x01, + /** Do not check the EVENT_* environment variables when configuring + an event_base */ + EVENT_BASE_FLAG_IGNORE_ENV = 0x02, + /** Windows only: enable the IOCP dispatcher at startup + + If this flag is set then bufferevent_socket_new() and + evconn_listener_new() will use IOCP-backed implementations + instead of the usual select-based one on Windows. + */ + EVENT_BASE_FLAG_STARTUP_IOCP = 0x04, + /** Instead of checking the current time every time the event loop is + ready to run timeout callbacks, check after each timeout callback. + */ + EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08, + + /** If we are using the epoll backend, this flag says that it is + safe to use Libevent's internal change-list code to batch up + adds and deletes in order to try to do as few syscalls as + possible. Setting this flag can make your code run faster, but + it may trigger a Linux bug: it is not safe to use this flag + if you have any fds cloned by dup() or its variants. Doing so + will produce strange and hard-to-diagnose bugs. + + This flag can also be activated by setting the + EVENT_EPOLL_USE_CHANGELIST environment variable. + + This flag has no effect if you wind up using a backend other than + epoll. + */ + EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10, + + /** Ordinarily, Libevent implements its time and timeout code using + the fastest monotonic timer that we have. If this flag is set, + however, we use less efficient more precise timer, assuming one is + present. + */ + EVENT_BASE_FLAG_PRECISE_TIMER = 0x20 +}; + +/** + Return a bitmask of the features implemented by an event base. This + will be a bitwise OR of one or more of the values of + event_method_feature + + @see event_method_feature + */ +EVENT2_EXPORT_SYMBOL +int event_base_get_features(const struct event_base *base); + +/** + Enters a required event method feature that the application demands. + + Note that not every feature or combination of features is supported + on every platform. Code that requests features should be prepared + to handle the case where event_base_new_with_config() returns NULL, as in: +
+     event_config_require_features(cfg, EV_FEATURE_ET);
+     base = event_base_new_with_config(cfg);
+     if (base == NULL) {
+       // We can't get edge-triggered behavior here.
+       event_config_require_features(cfg, 0);
+       base = event_base_new_with_config(cfg);
+     }
+   
+ + @param cfg the event configuration object + @param feature a bitfield of one or more event_method_feature values. + Replaces values from previous calls to this function. + @return 0 on success, -1 on failure. + @see event_method_feature, event_base_new_with_config() +*/ +EVENT2_EXPORT_SYMBOL +int event_config_require_features(struct event_config *cfg, int feature); + +/** + * Sets one or more flags to configure what parts of the eventual event_base + * will be initialized, and how they'll work. + * + * @see event_base_config_flags, event_base_new_with_config() + **/ +EVENT2_EXPORT_SYMBOL +int event_config_set_flag(struct event_config *cfg, int flag); + +/** + * Records a hint for the number of CPUs in the system. This is used for + * tuning thread pools, etc, for optimal performance. In Libevent 2.0, + * it is only on Windows, and only when IOCP is in use. + * + * @param cfg the event configuration object + * @param cpus the number of cpus + * @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int event_config_set_num_cpus_hint(struct event_config *cfg, int cpus); + +/** + * Record an interval and/or a number of callbacks after which the event base + * should check for new events. By default, the event base will run as many + * events are as activated at the highest activated priority before checking + * for new events. If you configure it by setting max_interval, it will check + * the time after each callback, and not allow more than max_interval to + * elapse before checking for new events. If you configure it by setting + * max_callbacks to a value >= 0, it will run no more than max_callbacks + * callbacks before checking for new events. + * + * This option can decrease the latency of high-priority events, and + * avoid priority inversions where multiple low-priority events keep us from + * polling for high-priority events, but at the expense of slightly decreasing + * the throughput. Use it with caution! + * + * @param cfg The event_base configuration object. + * @param max_interval An interval after which Libevent should stop running + * callbacks and check for more events, or NULL if there should be + * no such interval. + * @param max_callbacks A number of callbacks after which Libevent should + * stop running callbacks and check for more events, or -1 if there + * should be no such limit. + * @param min_priority A priority below which max_interval and max_callbacks + * should not be enforced. If this is set to 0, they are enforced + * for events of every priority; if it's set to 1, they're enforced + * for events of priority 1 and above, and so on. + * @return 0 on success, -1 on failure. + **/ +EVENT2_EXPORT_SYMBOL +int event_config_set_max_dispatch_interval(struct event_config *cfg, + const struct timeval *max_interval, int max_callbacks, + int min_priority); + +/** + Initialize the event API. + + Use event_base_new_with_config() to initialize a new event base, taking + the specified configuration under consideration. The configuration object + can currently be used to avoid certain event notification mechanisms. + + @param cfg the event configuration object + @return an initialized event_base that can be used to registering events, + or NULL if no event base can be created with the requested event_config. + @see event_base_new(), event_base_free(), event_init(), event_assign() +*/ +EVENT2_EXPORT_SYMBOL +struct event_base *event_base_new_with_config(const struct event_config *); + +/** + Deallocate all memory associated with an event_base, and free the base. + + Note that this function will not close any fds or free any memory passed + to event_new as the argument to callback. + + If there are any pending finalizer callbacks, this function will invoke + them. + + @param eb an event_base to be freed + */ +EVENT2_EXPORT_SYMBOL +void event_base_free(struct event_base *); + +/** + As event_base_free, but do not run finalizers. + */ +EVENT2_EXPORT_SYMBOL +void event_base_free_nofinalize(struct event_base *); + +/** @name Log severities + */ +/**@{*/ +#define EVENT_LOG_DEBUG 0 +#define EVENT_LOG_MSG 1 +#define EVENT_LOG_WARN 2 +#define EVENT_LOG_ERR 3 +/**@}*/ + +/* Obsolete names: these are deprecated, but older programs might use them. + * They violate the reserved-identifier namespace. */ +#define _EVENT_LOG_DEBUG EVENT_LOG_DEBUG +#define _EVENT_LOG_MSG EVENT_LOG_MSG +#define _EVENT_LOG_WARN EVENT_LOG_WARN +#define _EVENT_LOG_ERR EVENT_LOG_ERR + +/** + A callback function used to intercept Libevent's log messages. + + @see event_set_log_callback + */ +typedef void (*event_log_cb)(int severity, const char *msg); +/** + Redirect Libevent's log messages. + + @param cb a function taking two arguments: an integer severity between + EVENT_LOG_DEBUG and EVENT_LOG_ERR, and a string. If cb is NULL, + then the default log is used. + + NOTE: The function you provide *must not* call any other libevent + functionality. Doing so can produce undefined behavior. + */ +EVENT2_EXPORT_SYMBOL +void event_set_log_callback(event_log_cb cb); + +/** + A function to be called if Libevent encounters a fatal internal error. + + @see event_set_fatal_callback + */ +typedef void (*event_fatal_cb)(int err); + +/** + Override Libevent's behavior in the event of a fatal internal error. + + By default, Libevent will call exit(1) if a programming error makes it + impossible to continue correct operation. This function allows you to supply + another callback instead. Note that if the function is ever invoked, + something is wrong with your program, or with Libevent: any subsequent calls + to Libevent may result in undefined behavior. + + Libevent will (almost) always log an EVENT_LOG_ERR message before calling + this function; look at the last log message to see why Libevent has died. + */ +EVENT2_EXPORT_SYMBOL +void event_set_fatal_callback(event_fatal_cb cb); + +#define EVENT_DBG_ALL 0xffffffffu +#define EVENT_DBG_NONE 0 + +/** + Turn on debugging logs and have them sent to the default log handler. + + This is a global setting; if you are going to call it, you must call this + before any calls that create an event-base. You must call it before any + multithreaded use of Libevent. + + Debug logs are verbose. + + @param which Controls which debug messages are turned on. This option is + unused for now; for forward compatibility, you must pass in the constant + "EVENT_DBG_ALL" to turn debugging logs on, or "EVENT_DBG_NONE" to turn + debugging logs off. + */ +EVENT2_EXPORT_SYMBOL +void event_enable_debug_logging(ev_uint32_t which); + +/** + Associate a different event base with an event. + + The event to be associated must not be currently active or pending. + + @param eb the event base + @param ev the event + @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int event_base_set(struct event_base *, struct event *); + +/** @name Loop flags + + These flags control the behavior of event_base_loop(). + */ +/**@{*/ +/** Block until we have an active event, then exit once all active events + * have had their callbacks run. */ +#define EVLOOP_ONCE 0x01 +/** Do not block: see which events are ready now, run the callbacks + * of the highest-priority ones, then exit. */ +#define EVLOOP_NONBLOCK 0x02 +/** Do not exit the loop because we have no pending events. Instead, keep + * running until event_base_loopexit() or event_base_loopbreak() makes us + * stop. + */ +#define EVLOOP_NO_EXIT_ON_EMPTY 0x04 +/**@}*/ + +/** + Wait for events to become active, and run their callbacks. + + This is a more flexible version of event_base_dispatch(). + + By default, this loop will run the event base until either there are no more + pending or active events, or until something calls event_base_loopbreak() or + event_base_loopexit(). You can override this behavior with the 'flags' + argument. + + @param eb the event_base structure returned by event_base_new() or + event_base_new_with_config() + @param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK + @return 0 if successful, -1 if an error occurred, or 1 if we exited because + no events were pending or active. + @see event_base_loopexit(), event_base_dispatch(), EVLOOP_ONCE, + EVLOOP_NONBLOCK + */ +EVENT2_EXPORT_SYMBOL +int event_base_loop(struct event_base *, int); + +/** + Exit the event loop after the specified time + + The next event_base_loop() iteration after the given timer expires will + complete normally (handling all queued events) then exit without + blocking for events again. + + Subsequent invocations of event_base_loop() will proceed normally. + + @param eb the event_base structure returned by event_init() + @param tv the amount of time after which the loop should terminate, + or NULL to exit after running all currently active events. + @return 0 if successful, or -1 if an error occurred + @see event_base_loopbreak() + */ +EVENT2_EXPORT_SYMBOL +int event_base_loopexit(struct event_base *, const struct timeval *); + +/** + Abort the active event_base_loop() immediately. + + event_base_loop() will abort the loop after the next event is completed; + event_base_loopbreak() is typically invoked from this event's callback. + This behavior is analogous to the "break;" statement. + + Subsequent invocations of event_base_loop() will proceed normally. + + @param eb the event_base structure returned by event_init() + @return 0 if successful, or -1 if an error occurred + @see event_base_loopexit() + */ +EVENT2_EXPORT_SYMBOL +int event_base_loopbreak(struct event_base *); + +/** + Tell the active event_base_loop() to scan for new events immediately. + + Calling this function makes the currently active event_base_loop() + start the loop over again (scanning for new events) after the current + event callback finishes. If the event loop is not running, this + function has no effect. + + event_base_loopbreak() is typically invoked from this event's callback. + This behavior is analogous to the "continue;" statement. + + Subsequent invocations of event loop will proceed normally. + + @param eb the event_base structure returned by event_init() + @return 0 if successful, or -1 if an error occurred + @see event_base_loopbreak() + */ +EVENT2_EXPORT_SYMBOL +int event_base_loopcontinue(struct event_base *); + +/** + Checks if the event loop was told to exit by event_base_loopexit(). + + This function will return true for an event_base at every point after + event_loopexit() is called, until the event loop is next entered. + + @param eb the event_base structure returned by event_init() + @return true if event_base_loopexit() was called on this event base, + or 0 otherwise + @see event_base_loopexit() + @see event_base_got_break() + */ +EVENT2_EXPORT_SYMBOL +int event_base_got_exit(struct event_base *); + +/** + Checks if the event loop was told to abort immediately by event_base_loopbreak(). + + This function will return true for an event_base at every point after + event_base_loopbreak() is called, until the event loop is next entered. + + @param eb the event_base structure returned by event_init() + @return true if event_base_loopbreak() was called on this event base, + or 0 otherwise + @see event_base_loopbreak() + @see event_base_got_exit() + */ +EVENT2_EXPORT_SYMBOL +int event_base_got_break(struct event_base *); + +/** + * @name event flags + * + * Flags to pass to event_new(), event_assign(), event_pending(), and + * anything else with an argument of the form "short events" + */ +/**@{*/ +/** Indicates that a timeout has occurred. It's not necessary to pass + * this flag to event_for new()/event_assign() to get a timeout. */ +#define EV_TIMEOUT 0x01 +/** Wait for a socket or FD to become readable */ +#define EV_READ 0x02 +/** Wait for a socket or FD to become writeable */ +#define EV_WRITE 0x04 +/** Wait for a POSIX signal to be raised*/ +#define EV_SIGNAL 0x08 +/** + * Persistent event: won't get removed automatically when activated. + * + * When a persistent event with a timeout becomes activated, its timeout + * is reset to 0. + */ +#define EV_PERSIST 0x10 +/** Select edge-triggered behavior, if supported by the backend. */ +#define EV_ET 0x20 +/** + * If this option is provided, then event_del() will not block in one thread + * while waiting for the event callback to complete in another thread. + * + * To use this option safely, you may need to use event_finalize() or + * event_free_finalize() in order to safely tear down an event in a + * multithreaded application. See those functions for more information. + **/ +#define EV_FINALIZE 0x40 +/** + * Detects connection close events. You can use this to detect when a + * connection has been closed, without having to read all the pending data + * from a connection. + * + * Not all backends support EV_CLOSED. To detect or require it, use the + * feature flag EV_FEATURE_EARLY_CLOSE. + **/ +#define EV_CLOSED 0x80 +/**@}*/ + +/** + @name evtimer_* macros + + Aliases for working with one-shot timer events + If you need EV_PERSIST timer use event_*() functions. + */ +/**@{*/ +#define evtimer_assign(ev, b, cb, arg) \ + event_assign((ev), (b), -1, 0, (cb), (arg)) +#define evtimer_new(b, cb, arg) event_new((b), -1, 0, (cb), (arg)) +#define evtimer_add(ev, tv) event_add((ev), (tv)) +#define evtimer_del(ev) event_del(ev) +#define evtimer_pending(ev, tv) event_pending((ev), EV_TIMEOUT, (tv)) +#define evtimer_initialized(ev) event_initialized(ev) +/**@}*/ + +/** + @name evsignal_* macros + + Aliases for working with signal events + */ +/**@{*/ +#define evsignal_add(ev, tv) event_add((ev), (tv)) +#define evsignal_assign(ev, b, x, cb, arg) \ + event_assign((ev), (b), (x), EV_SIGNAL|EV_PERSIST, cb, (arg)) +#define evsignal_new(b, x, cb, arg) \ + event_new((b), (x), EV_SIGNAL|EV_PERSIST, (cb), (arg)) +#define evsignal_del(ev) event_del(ev) +#define evsignal_pending(ev, tv) event_pending((ev), EV_SIGNAL, (tv)) +#define evsignal_initialized(ev) event_initialized(ev) +/**@}*/ + +/** + @name evuser_* macros + + Aliases for working with user-triggered events + If you need EV_PERSIST event use event_*() functions. + */ +/**@{*/ +#define evuser_new(b, cb, arg) event_new((b), -1, 0, (cb), (arg)) +#define evuser_del(ev) event_del(ev) +#define evuser_pending(ev, tv) event_pending((ev), 0, (tv)) +#define evuser_initialized(ev) event_initialized(ev) +#define evuser_trigger(ev) event_active((ev), 0, 0) +/**@}*/ + +/** + A callback function for an event. + + It receives three arguments: + + @param fd An fd or signal + @param events One or more EV_* flags + @param arg A user-supplied argument. + + @see event_new() + */ +typedef void (*event_callback_fn)(evutil_socket_t, short, void *); + +/** + Return a value used to specify that the event itself must be used as the callback argument. + + The function event_new() takes a callback argument which is passed + to the event's callback function. To specify that the argument to be + passed to the callback function is the event that event_new() returns, + pass in the return value of event_self_cbarg() as the callback argument + for event_new(). + + For example: +
+      struct event *ev = event_new(base, sock, events, callback, %event_self_cbarg());
+  
+ + For consistency with event_new(), it is possible to pass the return value + of this function as the callback argument for event_assign() – this + achieves the same result as passing the event in directly. + + @return a value to be passed as the callback argument to event_new() or + event_assign(). + @see event_new(), event_assign() + */ +EVENT2_EXPORT_SYMBOL +void *event_self_cbarg(void); + +/** + Allocate and assign a new event structure, ready to be added. + + The function event_new() returns a new event that can be used in + future calls to event_add() and event_del(). The fd and events + arguments determine which conditions will trigger the event; the + callback and callback_arg arguments tell Libevent what to do when the + event becomes active. + + If events contains one of EV_READ, EV_WRITE, or EV_READ|EV_WRITE, then + fd is a file descriptor or socket that should get monitored for + readiness to read, readiness to write, or readiness for either operation + (respectively). If events contains EV_SIGNAL, then fd is a signal + number to wait for. If events contains none of those flags, then the + event can be triggered only by a timeout or by manual activation with + event_active(): In this case, fd must be -1. + + The EV_PERSIST flag can also be passed in the events argument: it makes + event_add() persistent until event_del() is called. + + The EV_ET flag is compatible with EV_READ and EV_WRITE, and supported + only by certain backends. It tells Libevent to use edge-triggered + events. + + The EV_TIMEOUT flag has no effect here. + + It is okay to have multiple events all listening on the same fds; but + they must either all be edge-triggered, or all not be edge triggered. + + When the event becomes active, the event loop will run the provided + callback function, with three arguments. The first will be the provided + fd value. The second will be a bitfield of the events that triggered: + EV_READ, EV_WRITE, or EV_SIGNAL. Here the EV_TIMEOUT flag indicates + that a timeout occurred, and EV_ET indicates that an edge-triggered + event occurred. The third event will be the callback_arg pointer that + you provide. + + @param base the event base to which the event should be attached. + @param fd the file descriptor or signal to be monitored, or -1. + @param events desired events to monitor: bitfield of EV_READ, EV_WRITE, + EV_SIGNAL, EV_PERSIST, EV_ET. + @param callback callback function to be invoked when the event occurs + @param callback_arg an argument to be passed to the callback function + + @return a newly allocated struct event that must later be freed with + event_free() or NULL if an error occurred. + @see event_free(), event_add(), event_del(), event_assign() + */ +EVENT2_EXPORT_SYMBOL +struct event *event_new(struct event_base *, evutil_socket_t, short, event_callback_fn, void *); + + +/** + Prepare a new, already-allocated event structure to be added. + + The function event_assign() prepares the event structure ev to be used + in future calls to event_add() and event_del(). Unlike event_new(), it + doesn't allocate memory itself: it requires that you have already + allocated a struct event, probably on the heap. Doing this will + typically make your code depend on the size of the event structure, and + thereby create incompatibility with future versions of Libevent. + + The easiest way to avoid this problem is just to use event_new() and + event_free() instead. + + A slightly harder way to future-proof your code is to use + event_get_struct_event_size() to determine the required size of an event + at runtime. + + Note that it is NOT safe to call this function on an event that is + active or pending. Doing so WILL corrupt internal data structures in + Libevent, and lead to strange, hard-to-diagnose bugs. You _can_ use + event_assign to change an existing event, but only if it is not active + or pending! + + The arguments for this function, and the behavior of the events that it + makes, are as for event_new(). + + @param ev an event struct to be modified + @param base the event base to which ev should be attached. + @param fd the file descriptor to be monitored + @param events desired events to monitor; can be EV_READ and/or EV_WRITE + @param callback callback function to be invoked when the event occurs + @param callback_arg an argument to be passed to the callback function + + @return 0 if success, or -1 on invalid arguments. + + @see event_new(), event_add(), event_del(), event_base_once(), + event_get_struct_event_size() + */ +EVENT2_EXPORT_SYMBOL +int event_assign(struct event *, struct event_base *, evutil_socket_t, short, event_callback_fn, void *); + +/** + Deallocate a struct event * returned by event_new(). + + If the event is pending or active, this function makes it non-pending + and non-active first. + */ +EVENT2_EXPORT_SYMBOL +void event_free(struct event *); + +/** + * Callback type for event_finalize and event_free_finalize(). + **/ +typedef void (*event_finalize_callback_fn)(struct event *, void *); +/** + @name Finalization functions + + These functions are used to safely tear down an event in a multithreaded + application. If you construct your events with EV_FINALIZE to avoid + deadlocks, you will need a way to remove an event in the certainty that + it will definitely not be running its callback when you deallocate it + and its callback argument. + + To do this, call one of event_finalize() or event_free_finalize with + 0 for its first argument, the event to tear down as its second argument, + and a callback function as its third argument. The callback will be + invoked as part of the event loop, with the event's priority. + + After you call a finalizer function, event_add() and event_active() will + no longer work on the event, and event_del() will produce a no-op. You + must not try to change the event's fields with event_assign() or + event_set() while the finalize callback is in progress. Once the + callback has been invoked, you should treat the event structure as + containing uninitialized memory. + + The event_free_finalize() function frees the event after it's finalized; + event_finalize() does not. + + A finalizer callback must not make events pending or active. It must not + add events, activate events, or attempt to "resuscitate" the event being + finalized in any way. + + @return 0 on success, -1 on failure. + */ +/**@{*/ +EVENT2_EXPORT_SYMBOL +int event_finalize(unsigned, struct event *, event_finalize_callback_fn); +EVENT2_EXPORT_SYMBOL +int event_free_finalize(unsigned, struct event *, event_finalize_callback_fn); +/**@}*/ + +/** + Schedule a one-time event + + The function event_base_once() is similar to event_new(). However, it + schedules a callback to be called exactly once, and does not require the + caller to prepare an event structure. + + Note that in Libevent 2.0 and earlier, if the event is never triggered, the + internal memory used to hold it will never be freed. In Libevent 2.1, + the internal memory will get freed by event_base_free() if the event + is never triggered. The 'arg' value, however, will not get freed in either + case--you'll need to free that on your own if you want it to go away. + + @param base an event_base + @param fd a file descriptor to monitor, or -1 for no fd. + @param events event(s) to monitor; can be any of EV_READ | + EV_WRITE, or EV_TIMEOUT + @param callback callback function to be invoked when the event occurs + @param arg an argument to be passed to the callback function + @param timeout the maximum amount of time to wait for the event. NULL + makes an EV_READ/EV_WRITE event make forever; NULL makes an + EV_TIMEOUT event success immediately. + @return 0 if successful, or -1 if an error occurred + */ +EVENT2_EXPORT_SYMBOL +int event_base_once(struct event_base *, evutil_socket_t, short, event_callback_fn, void *, const struct timeval *); + +/** + Add an event to the set of pending events. + + The function event_add() schedules the execution of the event 'ev' when the + condition specified by event_assign() or event_new() occurs, or when the time + specified in timeout has elapsed. If a timeout is NULL, no timeout + occurs and the function will only be + called if a matching event occurs. The event in the + ev argument must be already initialized by event_assign() or event_new() + and may not be used + in calls to event_assign() until it is no longer pending. + + If the event in the ev argument already has a scheduled timeout, calling + event_add() replaces the old timeout with the new one if tv is non-NULL. + + @param ev an event struct initialized via event_assign() or event_new() + @param timeout the maximum amount of time to wait for the event, or NULL + to wait forever + @return 0 if successful, or -1 if an error occurred + @see event_del(), event_assign(), event_new() + */ +EVENT2_EXPORT_SYMBOL +int event_add(struct event *ev, const struct timeval *timeout); + +/** + Remove a timer from a pending event without removing the event itself. + + If the event has a scheduled timeout, this function unschedules it but + leaves the event otherwise pending. + + @param ev an event struct initialized via event_assign() or event_new() + @return 0 on success, or -1 if an error occurred. +*/ +EVENT2_EXPORT_SYMBOL +int event_remove_timer(struct event *ev); + +/** + Remove an event from the set of monitored events. + + The function event_del() will cancel the event in the argument ev. If the + event has already executed or has never been added the call will have no + effect. + + @param ev an event struct to be removed from the working set + @return 0 if successful, or -1 if an error occurred + @see event_add() + */ +EVENT2_EXPORT_SYMBOL +int event_del(struct event *); + +/** + As event_del(), but never blocks while the event's callback is running + in another thread, even if the event was constructed without the + EV_FINALIZE flag. + */ +EVENT2_EXPORT_SYMBOL +int event_del_noblock(struct event *ev); +/** + As event_del(), but always blocks while the event's callback is running + in another thread, even if the event was constructed with the + EV_FINALIZE flag. + */ +EVENT2_EXPORT_SYMBOL +int event_del_block(struct event *ev); + +/** + Make an event active. + + You can use this function on a pending or a non-pending event to make it + active, so that its callback will be run by event_base_dispatch() or + event_base_loop(). + + One common use in multithreaded programs is to wake the thread running + event_base_loop() from another thread. + + @param ev an event to make active. + @param res a set of flags to pass to the event's callback. + @param ncalls an obsolete argument: this is ignored. + **/ +EVENT2_EXPORT_SYMBOL +void event_active(struct event *ev, int res, short ncalls); + +/** + Checks if a specific event is pending or scheduled. + + @param ev an event struct previously passed to event_add() + @param events the requested event type; any of EV_TIMEOUT|EV_READ| + EV_WRITE|EV_SIGNAL + @param tv if this field is not NULL, and the event has a timeout, + this field is set to hold the time at which the timeout will + expire. + + @return true if the event is pending on any of the events in 'what', (that + is to say, it has been added), or 0 if the event is not added. + */ +EVENT2_EXPORT_SYMBOL +int event_pending(const struct event *ev, short events, struct timeval *tv); + +/** + If called from within the callback for an event, returns that event. + + The behavior of this function is not defined when called from outside the + callback function for an event. + */ +EVENT2_EXPORT_SYMBOL +struct event *event_base_get_running_event(struct event_base *base); + +/** + Test if an event structure might be initialized. + + The event_initialized() function can be used to check if an event has been + initialized. + + Warning: This function is only useful for distinguishing a zeroed-out + piece of memory from an initialized event, it can easily be confused by + uninitialized memory. Thus, it should ONLY be used to distinguish an + initialized event from zero. + + @param ev an event structure to be tested + @return 1 if the structure might be initialized, or 0 if it has not been + initialized + */ +EVENT2_EXPORT_SYMBOL +int event_initialized(const struct event *ev); + +/** + Get the signal number assigned to a signal event +*/ +#define event_get_signal(ev) ((int)event_get_fd(ev)) + +/** + Get the socket or signal assigned to an event, or -1 if the event has + no socket. +*/ +EVENT2_EXPORT_SYMBOL +evutil_socket_t event_get_fd(const struct event *ev); + +/** + Get the event_base associated with an event. +*/ +EVENT2_EXPORT_SYMBOL +struct event_base *event_get_base(const struct event *ev); + +/** + Return the events (EV_READ, EV_WRITE, etc) assigned to an event. +*/ +EVENT2_EXPORT_SYMBOL +short event_get_events(const struct event *ev); + +/** + Return the callback assigned to an event. +*/ +EVENT2_EXPORT_SYMBOL +event_callback_fn event_get_callback(const struct event *ev); + +/** + Return the callback argument assigned to an event. +*/ +EVENT2_EXPORT_SYMBOL +void *event_get_callback_arg(const struct event *ev); + +/** + Return the priority of an event. + @see event_priority_init(), event_get_priority() +*/ +EVENT2_EXPORT_SYMBOL +int event_get_priority(const struct event *ev); + +/** + Extract _all_ of arguments given to construct a given event. The + event_base is copied into *base_out, the fd is copied into *fd_out, and so + on. + + If any of the "_out" arguments is NULL, it will be ignored. + */ +EVENT2_EXPORT_SYMBOL +void event_get_assignment(const struct event *event, + struct event_base **base_out, evutil_socket_t *fd_out, short *events_out, + event_callback_fn *callback_out, void **arg_out); + +/** + Return the size of struct event that the Libevent library was compiled + with. + + This will be NO GREATER than sizeof(struct event) if you're running with + the same version of Libevent that your application was built with, but + otherwise might not. + + Note that it might be SMALLER than sizeof(struct event) if some future + version of Libevent adds extra padding to the end of struct event. + We might do this to help ensure ABI-compatibility between different + versions of Libevent. + */ +EVENT2_EXPORT_SYMBOL +size_t event_get_struct_event_size(void); + +/** + Get the Libevent version. + + Note that this will give you the version of the library that you're + currently linked against, not the version of the headers that you've + compiled against. + + @return a string containing the version number of Libevent +*/ +EVENT2_EXPORT_SYMBOL +const char *event_get_version(void); + +/** + Return a numeric representation of Libevent's version. + + Note that this will give you the version of the library that you're + currently linked against, not the version of the headers you've used to + compile. + + The format uses one byte each for the major, minor, and patchlevel parts of + the version number. The low-order byte is unused. For example, version + 2.0.1-alpha has a numeric representation of 0x02000100 +*/ +EVENT2_EXPORT_SYMBOL +ev_uint32_t event_get_version_number(void); + +/** As event_get_version, but gives the version of Libevent's headers. */ +#define LIBEVENT_VERSION EVENT__VERSION +/** As event_get_version_number, but gives the version number of Libevent's + * headers. */ +#define LIBEVENT_VERSION_NUMBER EVENT__NUMERIC_VERSION + +/** Largest number of priorities that Libevent can support. */ +#define EVENT_MAX_PRIORITIES 256 +/** + Set the number of different event priorities + + By default Libevent schedules all active events with the same priority. + However, some time it is desirable to process some events with a higher + priority than others. For that reason, Libevent supports strict priority + queues. Active events with a lower priority are always processed before + events with a higher priority. + + The number of different priorities can be set initially with the + event_base_priority_init() function. This function should be called + before the first call to event_base_dispatch(). The + event_priority_set() function can be used to assign a priority to an + event. By default, Libevent assigns the middle priority to all events + unless their priority is explicitly set. + + Note that urgent-priority events can starve less-urgent events: after + running all urgent-priority callbacks, Libevent checks for more urgent + events again, before running less-urgent events. Less-urgent events + will not have their callbacks run until there are no events more urgent + than them that want to be active. + + @param eb the event_base structure returned by event_base_new() + @param npriorities the maximum number of priorities + @return 0 if successful, or -1 if an error occurred + @see event_priority_set() + */ +EVENT2_EXPORT_SYMBOL +int event_base_priority_init(struct event_base *, int); + +/** + Get the number of different event priorities. + + @param eb the event_base structure returned by event_base_new() + @return Number of different event priorities + @see event_base_priority_init() +*/ +EVENT2_EXPORT_SYMBOL +int event_base_get_npriorities(struct event_base *eb); + +/** + Assign a priority to an event. + + @param ev an event struct + @param priority the new priority to be assigned + @return 0 if successful, or -1 if an error occurred + @see event_priority_init(), event_get_priority() + */ +EVENT2_EXPORT_SYMBOL +int event_priority_set(struct event *, int); + +/** + Prepare an event_base to use a large number of timeouts with the same + duration. + + Libevent's default scheduling algorithm is optimized for having a large + number of timeouts with their durations more or less randomly + distributed. But if you have a large number of timeouts that all have + the same duration (for example, if you have a large number of + connections that all have a 10-second timeout), then you can improve + Libevent's performance by telling Libevent about it. + + To do this, call this function with the common duration. It will return a + pointer to a different, opaque timeout value. (Don't depend on its actual + contents!) When you use this timeout value in event_add(), Libevent will + schedule the event more efficiently. + + (This optimization probably will not be worthwhile until you have thousands + or tens of thousands of events with the same timeout.) + */ +EVENT2_EXPORT_SYMBOL +const struct timeval *event_base_init_common_timeout(struct event_base *base, + const struct timeval *duration); + +#if !defined(EVENT__DISABLE_MM_REPLACEMENT) || defined(EVENT_IN_DOXYGEN_) +/** + Override the functions that Libevent uses for memory management. + + Usually, Libevent uses the standard libc functions malloc, realloc, and + free to allocate memory. Passing replacements for those functions to + event_set_mem_functions() overrides this behavior. + + Note that all memory returned from Libevent will be allocated by the + replacement functions rather than by malloc() and realloc(). Thus, if you + have replaced those functions, it will not be appropriate to free() memory + that you get from Libevent. Instead, you must use the free_fn replacement + that you provided. + + Note also that if you are going to call this function, you should do so + before any call to any Libevent function that does allocation. + Otherwise, those functions will allocate their memory using malloc(), but + then later free it using your provided free_fn. + + @param malloc_fn A replacement for malloc. + @param realloc_fn A replacement for realloc + @param free_fn A replacement for free. + **/ +EVENT2_EXPORT_SYMBOL +void event_set_mem_functions( + void *(*malloc_fn)(size_t sz), + void *(*realloc_fn)(void *ptr, size_t sz), + void (*free_fn)(void *ptr)); +/** This definition is present if Libevent was built with support for + event_set_mem_functions() */ +#define EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED +#endif + +/** + Writes a human-readable description of all inserted and/or active + events to a provided stdio stream. + + This is intended for debugging; its format is not guaranteed to be the same + between libevent versions. + + @param base An event_base on which to scan the events. + @param output A stdio file to write on. + */ +EVENT2_EXPORT_SYMBOL +void event_base_dump_events(struct event_base *, FILE *); + + +/** + Activates all pending events for the given fd and event mask. + + This function activates pending events only. Events which have not been + added will not become active. + + @param base the event_base on which to activate the events. + @param fd An fd to active events on. + @param events One or more of EV_{READ,WRITE,TIMEOUT}. + */ +EVENT2_EXPORT_SYMBOL +void event_base_active_by_fd(struct event_base *base, evutil_socket_t fd, short events); + +/** + Activates all pending signals with a given signal number + + This function activates pending events only. Events which have not been + added will not become active. + + @param base the event_base on which to activate the events. + @param fd The signal to active events on. + */ +EVENT2_EXPORT_SYMBOL +void event_base_active_by_signal(struct event_base *base, int sig); + +/** + * Callback for iterating events in an event base via event_base_foreach_event + */ +typedef int (*event_base_foreach_event_cb)(const struct event_base *, const struct event *, void *); + +/** + Iterate over all added or active events events in an event loop, and invoke + a given callback on each one. + + The callback must not call any function that modifies the event base, that + modifies any event in the event base, or that adds or removes any event to + the event base. Doing so is unsupported and will lead to undefined + behavior -- likely, to crashes. + + event_base_foreach_event() holds a lock on the event_base() for the whole + time it's running: slow callbacks are not advisable. + + Note that Libevent adds some events of its own to make pieces of its + functionality work. You must not assume that the only events you'll + encounter will be the ones you added yourself. + + The callback function must return 0 to continue iteration, or some other + integer to stop iterating. + + @param base An event_base on which to scan the events. + @param fn A callback function to receive the events. + @param arg An argument passed to the callback function. + @return 0 if we iterated over every event, or the value returned by the + callback function if the loop exited early. +*/ +EVENT2_EXPORT_SYMBOL +int event_base_foreach_event(struct event_base *base, event_base_foreach_event_cb fn, void *arg); + + +/** Sets 'tv' to the current time (as returned by gettimeofday()), + looking at the cached value in 'base' if possible, and calling + gettimeofday() or clock_gettime() as appropriate if there is no + cached time. + + Generally, this value will only be cached while actually + processing event callbacks, and may be very inaccurate if your + callbacks take a long time to execute. + + Returns 0 on success, negative on failure. + */ +EVENT2_EXPORT_SYMBOL +int event_base_gettimeofday_cached(struct event_base *base, + struct timeval *tv); + +/** Update cached_tv in the 'base' to the current time + * + * You can use this function is useful for selectively increasing + * the accuracy of the cached time value in 'base' during callbacks + * that take a long time to execute. + * + * This function has no effect if the base is currently not in its + * event loop, or if timeval caching is disabled via + * EVENT_BASE_FLAG_NO_CACHE_TIME. + * + * @return 0 on success, -1 on failure + */ +EVENT2_EXPORT_SYMBOL +int event_base_update_cache_time(struct event_base *base); + +/** Release up all globally-allocated resources allocated by Libevent. + + This function does not free developer-controlled resources like + event_bases, events, bufferevents, listeners, and so on. It only releases + resources like global locks that there is no other way to free. + + It is not actually necessary to call this function before exit: every + resource that it frees would be released anyway on exit. It mainly exists + so that resource-leak debugging tools don't see Libevent as holding + resources at exit. + + You should only call this function when no other Libevent functions will + be invoked -- e.g., when cleanly exiting a program. + */ +EVENT2_EXPORT_SYMBOL +void libevent_global_shutdown(void); + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_EVENT_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/include/event2/event_compat.h b/bsnes/thrift/libevent/include/event2/event_compat.h new file mode 100644 index 00000000..5110175a --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/event_compat.h @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_EVENT_COMPAT_H_INCLUDED_ +#define EVENT2_EVENT_COMPAT_H_INCLUDED_ + +/** @file event2/event_compat.h + + Potentially non-threadsafe versions of the functions in event.h: provided + only for backwards compatibility. + + In the oldest versions of Libevent, event_base was not a first-class + structure. Instead, there was a single event base that every function + manipulated. Later, when separate event bases were added, the old functions + that didn't take an event_base argument needed to work by manipulating the + "current" event base. This could lead to thread-safety issues, and obscure, + hard-to-diagnose bugs. + + @deprecated All functions in this file are by definition deprecated. + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif + +/* For int types. */ +#include + +/** + Initialize the event API. + + The event API needs to be initialized with event_init() before it can be + used. Sets the global current base that gets used for events that have no + base associated with them. + + @deprecated This function is deprecated because it replaces the "current" + event_base, and is totally unsafe for multithreaded use. The replacement + is event_base_new(). + + @see event_base_set(), event_base_new() + */ +EVENT2_EXPORT_SYMBOL +struct event_base *event_init(void); + +/** + Loop to process events. + + Like event_base_dispatch(), but uses the "current" base. + + @deprecated This function is deprecated because it is easily confused by + multiple calls to event_init(), and because it is not safe for + multithreaded use. The replacement is event_base_dispatch(). + + @see event_base_dispatch(), event_init() + */ +EVENT2_EXPORT_SYMBOL +int event_dispatch(void); + +/** + Handle events. + + This function behaves like event_base_loop(), but uses the "current" base + + @deprecated This function is deprecated because it uses the event base from + the last call to event_init, and is therefore not safe for multithreaded + use. The replacement is event_base_loop(). + + @see event_base_loop(), event_init() +*/ +EVENT2_EXPORT_SYMBOL +int event_loop(int); + + +/** + Exit the event loop after the specified time. + + This function behaves like event_base_loopexit(), except that it uses the + "current" base. + + @deprecated This function is deprecated because it uses the event base from + the last call to event_init, and is therefore not safe for multithreaded + use. The replacement is event_base_loopexit(). + + @see event_init, event_base_loopexit() + */ +EVENT2_EXPORT_SYMBOL +int event_loopexit(const struct timeval *); + + +/** + Abort the active event_loop() immediately. + + This function behaves like event_base_loopbreakt(), except that it uses the + "current" base. + + @deprecated This function is deprecated because it uses the event base from + the last call to event_init, and is therefore not safe for multithreaded + use. The replacement is event_base_loopbreak(). + + @see event_base_loopbreak(), event_init() + */ +EVENT2_EXPORT_SYMBOL +int event_loopbreak(void); + +/** + Schedule a one-time event to occur. + + @deprecated This function is obsolete, and has been replaced by + event_base_once(). Its use is deprecated because it relies on the + "current" base configured by event_init(). + + @see event_base_once() + */ +EVENT2_EXPORT_SYMBOL +int event_once(evutil_socket_t , short, + void (*)(evutil_socket_t, short, void *), void *, const struct timeval *); + + +/** + Get the kernel event notification mechanism used by Libevent. + + @deprecated This function is obsolete, and has been replaced by + event_base_get_method(). Its use is deprecated because it relies on the + "current" base configured by event_init(). + + @see event_base_get_method() + */ +EVENT2_EXPORT_SYMBOL +const char *event_get_method(void); + + +/** + Set the number of different event priorities. + + @deprecated This function is deprecated because it is easily confused by + multiple calls to event_init(), and because it is not safe for + multithreaded use. The replacement is event_base_priority_init(). + + @see event_base_priority_init() + */ +EVENT2_EXPORT_SYMBOL +int event_priority_init(int); + +/** + Prepare an event structure to be added. + + @deprecated event_set() is not recommended for new code, because it requires + a subsequent call to event_base_set() to be safe under most circumstances. + Use event_assign() or event_new() instead. + */ +EVENT2_EXPORT_SYMBOL +void event_set(struct event *, evutil_socket_t, short, void (*)(evutil_socket_t, short, void *), void *); + +#define evtimer_set(ev, cb, arg) event_set((ev), -1, 0, (cb), (arg)) +#define evsignal_set(ev, x, cb, arg) \ + event_set((ev), (x), EV_SIGNAL|EV_PERSIST, (cb), (arg)) + + +/** + @name timeout_* macros + + @deprecated These macros are deprecated because their naming is inconsistent + with the rest of Libevent. Use the evtimer_* macros instead. + @{ + */ +#define timeout_add(ev, tv) event_add((ev), (tv)) +#define timeout_set(ev, cb, arg) event_set((ev), -1, 0, (cb), (arg)) +#define timeout_del(ev) event_del(ev) +#define timeout_pending(ev, tv) event_pending((ev), EV_TIMEOUT, (tv)) +#define timeout_initialized(ev) event_initialized(ev) +/**@}*/ + +/** + @name signal_* macros + + @deprecated These macros are deprecated because their naming is inconsistent + with the rest of Libevent. Use the evsignal_* macros instead. + @{ + */ +#define signal_add(ev, tv) event_add((ev), (tv)) +#define signal_set(ev, x, cb, arg) \ + event_set((ev), (x), EV_SIGNAL|EV_PERSIST, (cb), (arg)) +#define signal_del(ev) event_del(ev) +#define signal_pending(ev, tv) event_pending((ev), EV_SIGNAL, (tv)) +#define signal_initialized(ev) event_initialized(ev) +/**@}*/ + +#ifndef EVENT_FD +/* These macros are obsolete; use event_get_fd and event_get_signal instead. */ +#define EVENT_FD(ev) ((int)event_get_fd(ev)) +#define EVENT_SIGNAL(ev) event_get_signal(ev) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_EVENT_COMPAT_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/include/event2/event_struct.h b/bsnes/thrift/libevent/include/event2/event_struct.h new file mode 100644 index 00000000..1c8b71b6 --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/event_struct.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_EVENT_STRUCT_H_INCLUDED_ +#define EVENT2_EVENT_STRUCT_H_INCLUDED_ + +/** @file event2/event_struct.h + + Structures used by event.h. Using these structures directly WILL harm + forward compatibility: be careful. + + No field declared in this file should be used directly in user code. Except + for historical reasons, these fields would not be exposed at all. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif + +/* For int types. */ +#include + +/* For evkeyvalq */ +#include + +#define EVLIST_TIMEOUT 0x01 +#define EVLIST_INSERTED 0x02 +#define EVLIST_SIGNAL 0x04 +#define EVLIST_ACTIVE 0x08 +#define EVLIST_INTERNAL 0x10 +#define EVLIST_ACTIVE_LATER 0x20 +#define EVLIST_FINALIZING 0x40 +#define EVLIST_INIT 0x80 + +#define EVLIST_ALL 0xff + +/* Fix so that people don't have to run with */ +#ifndef TAILQ_ENTRY +#define EVENT_DEFINED_TQENTRY_ +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} +#endif /* !TAILQ_ENTRY */ + +#ifndef TAILQ_HEAD +#define EVENT_DEFINED_TQHEAD_ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; \ + struct type **tqh_last; \ +} +#endif + +/* Fix so that people don't have to run with */ +#ifndef LIST_ENTRY +#define EVENT_DEFINED_LISTENTRY_ +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} +#endif /* !LIST_ENTRY */ + +#ifndef LIST_HEAD +#define EVENT_DEFINED_LISTHEAD_ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ + } +#endif /* !LIST_HEAD */ + +struct event; + +struct event_callback { + TAILQ_ENTRY(event_callback) evcb_active_next; + short evcb_flags; + ev_uint8_t evcb_pri; /* smaller numbers are higher priority */ + ev_uint8_t evcb_closure; + /* allows us to adopt for different types of events */ + union { + void (*evcb_callback)(evutil_socket_t, short, void *); + void (*evcb_selfcb)(struct event_callback *, void *); + void (*evcb_evfinalize)(struct event *, void *); + void (*evcb_cbfinalize)(struct event_callback *, void *); + } evcb_cb_union; + void *evcb_arg; +}; + +struct event_base; +struct event { + struct event_callback ev_evcallback; + + /* for managing timeouts */ + union { + TAILQ_ENTRY(event) ev_next_with_common_timeout; + int min_heap_idx; + } ev_timeout_pos; + evutil_socket_t ev_fd; + + struct event_base *ev_base; + + union { + /* used for io events */ + struct { + LIST_ENTRY (event) ev_io_next; + struct timeval ev_timeout; + } ev_io; + + /* used by signal events */ + struct { + LIST_ENTRY (event) ev_signal_next; + short ev_ncalls; + /* Allows deletes in callback */ + short *ev_pncalls; + } ev_signal; + } ev_; + + short ev_events; + short ev_res; /* result passed to event callback */ + struct timeval ev_timeout; +}; + +TAILQ_HEAD (event_list, event); + +#ifdef EVENT_DEFINED_TQENTRY_ +#undef TAILQ_ENTRY +#endif + +#ifdef EVENT_DEFINED_TQHEAD_ +#undef TAILQ_HEAD +#endif + +LIST_HEAD (event_dlist, event); + +#ifdef EVENT_DEFINED_LISTENTRY_ +#undef LIST_ENTRY +#endif + +#ifdef EVENT_DEFINED_LISTHEAD_ +#undef LIST_HEAD +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_EVENT_STRUCT_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/include/event2/http.h b/bsnes/thrift/libevent/include/event2/http.h new file mode 100644 index 00000000..2a41303e --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/http.h @@ -0,0 +1,1192 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_HTTP_H_INCLUDED_ +#define EVENT2_HTTP_H_INCLUDED_ + +/* For int types. */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* In case we haven't included the right headers yet. */ +struct evbuffer; +struct event_base; +struct bufferevent; +struct evhttp_connection; + +/** @file event2/http.h + * + * Basic support for HTTP serving. + * + * As Libevent is a library for dealing with event notification and most + * interesting applications are networked today, I have often found the + * need to write HTTP code. The following prototypes and definitions provide + * an application with a minimal interface for making HTTP requests and for + * creating a very simple HTTP server. + */ + +/* Response codes */ +#define HTTP_OK 200 /**< request completed ok */ +#define HTTP_NOCONTENT 204 /**< request does not have content */ +#define HTTP_MOVEPERM 301 /**< the uri moved permanently */ +#define HTTP_MOVETEMP 302 /**< the uri moved temporarily */ +#define HTTP_NOTMODIFIED 304 /**< page was not modified from last */ +#define HTTP_BADREQUEST 400 /**< invalid http request was made */ +#define HTTP_NOTFOUND 404 /**< could not find content for uri */ +#define HTTP_BADMETHOD 405 /**< method not allowed for this uri */ +#define HTTP_ENTITYTOOLARGE 413 /**< */ +#define HTTP_EXPECTATIONFAILED 417 /**< we can't handle this expectation */ +#define HTTP_INTERNAL 500 /**< internal error */ +#define HTTP_NOTIMPLEMENTED 501 /**< not implemented */ +#define HTTP_SERVUNAVAIL 503 /**< the server is not available */ + +struct evhttp; +struct evhttp_request; +struct evkeyvalq; +struct evhttp_bound_socket; +struct evconnlistener; +struct evdns_base; + +/** + * Create a new HTTP server. + * + * @param base (optional) the event base to receive the HTTP events + * @return a pointer to a newly initialized evhttp server structure or NULL + * on error + * @see evhttp_free() + */ +EVENT2_EXPORT_SYMBOL +struct evhttp *evhttp_new(struct event_base *base); + +/** + * Binds an HTTP server on the specified address and port. + * + * Can be called multiple times to bind the same http server + * to multiple different ports. + * + * @param http a pointer to an evhttp object + * @param address a string containing the IP address to listen(2) on + * @param port the port number to listen on + * @return 0 on success, -1 on failure. + * @see evhttp_accept_socket() + */ +EVENT2_EXPORT_SYMBOL +int evhttp_bind_socket(struct evhttp *http, const char *address, ev_uint16_t port); + +/** + * Like evhttp_bind_socket(), but returns a handle for referencing the socket. + * + * The returned pointer is not valid after \a http is freed. + * + * @param http a pointer to an evhttp object + * @param address a string containing the IP address to listen(2) on + * @param port the port number to listen on + * @return Handle for the socket on success, NULL on failure. + * @see evhttp_bind_socket(), evhttp_del_accept_socket() + */ +EVENT2_EXPORT_SYMBOL +struct evhttp_bound_socket *evhttp_bind_socket_with_handle(struct evhttp *http, const char *address, ev_uint16_t port); + +/** + * Makes an HTTP server accept connections on the specified socket. + * + * This may be useful to create a socket and then fork multiple instances + * of an http server, or when a socket has been communicated via file + * descriptor passing in situations where an http servers does not have + * permissions to bind to a low-numbered port. + * + * Can be called multiple times to have the http server listen to + * multiple different sockets. + * + * @param http a pointer to an evhttp object + * @param fd a socket fd that is ready for accepting connections + * @return 0 on success, -1 on failure. + * @see evhttp_bind_socket() + */ +EVENT2_EXPORT_SYMBOL +int evhttp_accept_socket(struct evhttp *http, evutil_socket_t fd); + +/** + * Like evhttp_accept_socket(), but returns a handle for referencing the socket. + * + * The returned pointer is not valid after \a http is freed. + * + * @param http a pointer to an evhttp object + * @param fd a socket fd that is ready for accepting connections + * @return Handle for the socket on success, NULL on failure. + * @see evhttp_accept_socket(), evhttp_del_accept_socket() + */ +EVENT2_EXPORT_SYMBOL +struct evhttp_bound_socket *evhttp_accept_socket_with_handle(struct evhttp *http, evutil_socket_t fd); + +/** + * The most low-level evhttp_bind/accept method: takes an evconnlistener, and + * returns an evhttp_bound_socket. The listener will be freed when the bound + * socket is freed. + */ +EVENT2_EXPORT_SYMBOL +struct evhttp_bound_socket *evhttp_bind_listener(struct evhttp *http, struct evconnlistener *listener); + +/** + * Return the listener used to implement a bound socket. + */ +EVENT2_EXPORT_SYMBOL +struct evconnlistener *evhttp_bound_socket_get_listener(struct evhttp_bound_socket *bound); + +typedef void evhttp_bound_socket_foreach_fn(struct evhttp_bound_socket *, void *); +/** + * Applies the function specified in the first argument to all + * evhttp_bound_sockets associated with "http". The user must not + * attempt to free or remove any connections, sockets or listeners + * in the callback "function". + * + * @param http pointer to an evhttp object + * @param function function to apply to every bound socket + * @param argument pointer value passed to function for every socket iterated + */ +EVENT2_EXPORT_SYMBOL +void evhttp_foreach_bound_socket(struct evhttp *http, evhttp_bound_socket_foreach_fn *function, void *argument); + +/** + * Makes an HTTP server stop accepting connections on the specified socket + * + * This may be useful when a socket has been sent via file descriptor passing + * and is no longer needed by the current process. + * + * If you created this bound socket with evhttp_bind_socket_with_handle or + * evhttp_accept_socket_with_handle, this function closes the fd you provided. + * If you created this bound socket with evhttp_bind_listener, this function + * frees the listener you provided. + * + * \a bound_socket is an invalid pointer after this call returns. + * + * @param http a pointer to an evhttp object + * @param bound_socket a handle returned by evhttp_{bind,accept}_socket_with_handle + * @see evhttp_bind_socket_with_handle(), evhttp_accept_socket_with_handle() + */ +EVENT2_EXPORT_SYMBOL +void evhttp_del_accept_socket(struct evhttp *http, struct evhttp_bound_socket *bound_socket); + +/** + * Get the raw file descriptor referenced by an evhttp_bound_socket. + * + * @param bound_socket a handle returned by evhttp_{bind,accept}_socket_with_handle + * @return the file descriptor used by the bound socket + * @see evhttp_bind_socket_with_handle(), evhttp_accept_socket_with_handle() + */ +EVENT2_EXPORT_SYMBOL +evutil_socket_t evhttp_bound_socket_get_fd(struct evhttp_bound_socket *bound_socket); + +/** + * Free the previously created HTTP server. + * + * Works only if no requests are currently being served. + * + * @param http the evhttp server object to be freed + * @see evhttp_start() + */ +EVENT2_EXPORT_SYMBOL +void evhttp_free(struct evhttp* http); + +/** XXX Document. */ +EVENT2_EXPORT_SYMBOL +void evhttp_set_max_headers_size(struct evhttp* http, ev_ssize_t max_headers_size); +/** XXX Document. */ +EVENT2_EXPORT_SYMBOL +void evhttp_set_max_body_size(struct evhttp* http, ev_ssize_t max_body_size); + +/** + Set the value to use for the Content-Type header when none was provided. If + the content type string is NULL, the Content-Type header will not be + automatically added. + + @param http the http server on which to set the default content type + @param content_type the value for the Content-Type header +*/ +EVENT2_EXPORT_SYMBOL +void evhttp_set_default_content_type(struct evhttp *http, + const char *content_type); + +/** + Sets the what HTTP methods are supported in requests accepted by this + server, and passed to user callbacks. + + If not supported they will generate a "405 Method not allowed" response. + + By default this includes the following methods: GET, POST, HEAD, PUT, DELETE + + @param http the http server on which to set the methods + @param methods bit mask constructed from evhttp_cmd_type values +*/ +EVENT2_EXPORT_SYMBOL +void evhttp_set_allowed_methods(struct evhttp* http, ev_uint16_t methods); + +/** + Set a callback for a specified URI + + @param http the http sever on which to set the callback + @param path the path for which to invoke the callback + @param cb the callback function that gets invoked on requesting path + @param cb_arg an additional context argument for the callback + @return 0 on success, -1 if the callback existed already, -2 on failure +*/ +EVENT2_EXPORT_SYMBOL +int evhttp_set_cb(struct evhttp *http, const char *path, + void (*cb)(struct evhttp_request *, void *), void *cb_arg); + +/** Removes the callback for a specified URI */ +EVENT2_EXPORT_SYMBOL +int evhttp_del_cb(struct evhttp *, const char *); + +/** + Set a callback for all requests that are not caught by specific callbacks + + Invokes the specified callback for all requests that do not match any of + the previously specified request paths. This is catchall for requests not + specifically configured with evhttp_set_cb(). + + @param http the evhttp server object for which to set the callback + @param cb the callback to invoke for any unmatched requests + @param arg an context argument for the callback +*/ +EVENT2_EXPORT_SYMBOL +void evhttp_set_gencb(struct evhttp *http, + void (*cb)(struct evhttp_request *, void *), void *arg); + +/** + Set a callback used to create new bufferevents for connections + to a given evhttp object. + + You can use this to override the default bufferevent type -- for example, + to make this evhttp object use SSL bufferevents rather than unencrypted + ones. + + New bufferevents must be allocated with no fd set on them. + + @param http the evhttp server object for which to set the callback + @param cb the callback to invoke for incoming connections + @param arg an context argument for the callback + */ +EVENT2_EXPORT_SYMBOL +void evhttp_set_bevcb(struct evhttp *http, + struct bufferevent *(*cb)(struct event_base *, void *), void *arg); + +/** + Adds a virtual host to the http server. + + A virtual host is a newly initialized evhttp object that has request + callbacks set on it via evhttp_set_cb() or evhttp_set_gencb(). It + most not have any listing sockets associated with it. + + If the virtual host has not been removed by the time that evhttp_free() + is called on the main http server, it will be automatically freed, too. + + It is possible to have hierarchical vhosts. For example: A vhost + with the pattern *.example.com may have other vhosts with patterns + foo.example.com and bar.example.com associated with it. + + @param http the evhttp object to which to add a virtual host + @param pattern the glob pattern against which the hostname is matched. + The match is case insensitive and follows otherwise regular shell + matching. + @param vhost the virtual host to add the regular http server. + @return 0 on success, -1 on failure + @see evhttp_remove_virtual_host() +*/ +EVENT2_EXPORT_SYMBOL +int evhttp_add_virtual_host(struct evhttp* http, const char *pattern, + struct evhttp* vhost); + +/** + Removes a virtual host from the http server. + + @param http the evhttp object from which to remove the virtual host + @param vhost the virtual host to remove from the regular http server. + @return 0 on success, -1 on failure + @see evhttp_add_virtual_host() +*/ +EVENT2_EXPORT_SYMBOL +int evhttp_remove_virtual_host(struct evhttp* http, struct evhttp* vhost); + +/** + Add a server alias to an http object. The http object can be a virtual + host or the main server. + + @param http the evhttp object + @param alias the alias to add + @see evhttp_add_remove_alias() +*/ +EVENT2_EXPORT_SYMBOL +int evhttp_add_server_alias(struct evhttp *http, const char *alias); + +/** + Remove a server alias from an http object. + + @param http the evhttp object + @param alias the alias to remove + @see evhttp_add_server_alias() +*/ +EVENT2_EXPORT_SYMBOL +int evhttp_remove_server_alias(struct evhttp *http, const char *alias); + +/** + * Set the timeout for an HTTP request. + * + * @param http an evhttp object + * @param timeout_in_secs the timeout, in seconds + */ +EVENT2_EXPORT_SYMBOL +void evhttp_set_timeout(struct evhttp *http, int timeout_in_secs); + +/** + * Set the timeout for an HTTP request. + * + * @param http an evhttp object + * @param tv the timeout, or NULL + */ +EVENT2_EXPORT_SYMBOL +void evhttp_set_timeout_tv(struct evhttp *http, const struct timeval* tv); + +/* Read all the clients body, and only after this respond with an error if the + * clients body exceed max_body_size */ +#define EVHTTP_SERVER_LINGERING_CLOSE 0x0001 +/** + * Set connection flags for HTTP server. + * + * @see EVHTTP_SERVER_* + * @return 0 on success, otherwise non zero (for example if flag doesn't + * supported). + */ +EVENT2_EXPORT_SYMBOL +int evhttp_set_flags(struct evhttp *http, int flags); + +/* Request/Response functionality */ + +/** + * Send an HTML error message to the client. + * + * @param req a request object + * @param error the HTTP error code + * @param reason a brief explanation of the error. If this is NULL, we'll + * just use the standard meaning of the error code. + */ +EVENT2_EXPORT_SYMBOL +void evhttp_send_error(struct evhttp_request *req, int error, + const char *reason); + +/** + * Send an HTML reply to the client. + * + * The body of the reply consists of the data in databuf. After calling + * evhttp_send_reply() databuf will be empty, but the buffer is still + * owned by the caller and needs to be deallocated by the caller if + * necessary. + * + * @param req a request object + * @param code the HTTP response code to send + * @param reason a brief message to send with the response code + * @param databuf the body of the response + */ +EVENT2_EXPORT_SYMBOL +void evhttp_send_reply(struct evhttp_request *req, int code, + const char *reason, struct evbuffer *databuf); + +/* Low-level response interface, for streaming/chunked replies */ + +/** + Initiate a reply that uses Transfer-Encoding chunked. + + This allows the caller to stream the reply back to the client and is + useful when either not all of the reply data is immediately available + or when sending very large replies. + + The caller needs to supply data chunks with evhttp_send_reply_chunk() + and complete the reply by calling evhttp_send_reply_end(). + + @param req a request object + @param code the HTTP response code to send + @param reason a brief message to send with the response code +*/ +EVENT2_EXPORT_SYMBOL +void evhttp_send_reply_start(struct evhttp_request *req, int code, + const char *reason); + +/** + Send another data chunk as part of an ongoing chunked reply. + + The reply chunk consists of the data in databuf. After calling + evhttp_send_reply_chunk() databuf will be empty, but the buffer is + still owned by the caller and needs to be deallocated by the caller + if necessary. + + @param req a request object + @param databuf the data chunk to send as part of the reply. +*/ +EVENT2_EXPORT_SYMBOL +void evhttp_send_reply_chunk(struct evhttp_request *req, + struct evbuffer *databuf); + +/** + Send another data chunk as part of an ongoing chunked reply. + + The reply chunk consists of the data in databuf. After calling + evhttp_send_reply_chunk() databuf will be empty, but the buffer is + still owned by the caller and needs to be deallocated by the caller + if necessary. + + @param req a request object + @param databuf the data chunk to send as part of the reply. + @param cb callback funcion + @param call back's argument. +*/ +EVENT2_EXPORT_SYMBOL +void evhttp_send_reply_chunk_with_cb(struct evhttp_request *, struct evbuffer *, + void (*cb)(struct evhttp_connection *, void *), void *arg); + +/** + Complete a chunked reply, freeing the request as appropriate. + + @param req a request object +*/ +EVENT2_EXPORT_SYMBOL +void evhttp_send_reply_end(struct evhttp_request *req); + +/* + * Interfaces for making requests + */ + +/** The different request types supported by evhttp. These are as specified + * in RFC2616, except for PATCH which is specified by RFC5789. + * + * By default, only some of these methods are accepted and passed to user + * callbacks; use evhttp_set_allowed_methods() to change which methods + * are allowed. + */ +enum evhttp_cmd_type { + EVHTTP_REQ_GET = 1 << 0, + EVHTTP_REQ_POST = 1 << 1, + EVHTTP_REQ_HEAD = 1 << 2, + EVHTTP_REQ_PUT = 1 << 3, + EVHTTP_REQ_DELETE = 1 << 4, + EVHTTP_REQ_OPTIONS = 1 << 5, + EVHTTP_REQ_TRACE = 1 << 6, + EVHTTP_REQ_CONNECT = 1 << 7, + EVHTTP_REQ_PATCH = 1 << 8 +}; + +/** a request object can represent either a request or a reply */ +enum evhttp_request_kind { EVHTTP_REQUEST, EVHTTP_RESPONSE }; + +/** + * Create and return a connection object that can be used to for making HTTP + * requests. The connection object tries to resolve address and establish the + * connection when it is given an http request object. + * + * @param base the event_base to use for handling the connection + * @param dnsbase the dns_base to use for resolving host names; if not + * specified host name resolution will block. + * @param bev a bufferevent to use for connecting to the server; if NULL, a + * socket-based bufferevent will be created. This buffrevent will be freed + * when the connection closes. It must have no fd set on it. + * @param address the address to which to connect + * @param port the port to connect to + * @return an evhttp_connection object that can be used for making requests or + * NULL on error + */ +EVENT2_EXPORT_SYMBOL +struct evhttp_connection *evhttp_connection_base_bufferevent_new( + struct event_base *base, struct evdns_base *dnsbase, struct bufferevent* bev, const char *address, ev_uint16_t port); + +/** + * Return the bufferevent that an evhttp_connection is using. + */ +EVENT2_EXPORT_SYMBOL +struct bufferevent* evhttp_connection_get_bufferevent(struct evhttp_connection *evcon); + +/** + * Return the HTTP server associated with this connection, or NULL. + */ +EVENT2_EXPORT_SYMBOL +struct evhttp *evhttp_connection_get_server(struct evhttp_connection *evcon); + +/** + * Creates a new request object that needs to be filled in with the request + * parameters. The callback is executed when the request completed or an + * error occurred. + */ +EVENT2_EXPORT_SYMBOL +struct evhttp_request *evhttp_request_new( + void (*cb)(struct evhttp_request *, void *), void *arg); + +/** + * Enable delivery of chunks to requestor. + * @param cb will be called after every read of data with the same argument + * as the completion callback. Will never be called on an empty + * response. May drain the input buffer; it will be drained + * automatically on return. + */ +EVENT2_EXPORT_SYMBOL +void evhttp_request_set_chunked_cb(struct evhttp_request *, + void (*cb)(struct evhttp_request *, void *)); + +/** + * Register callback for additional parsing of request headers. + * @param cb will be called after receiving and parsing the full header. + * It allows analyzing the header and possibly closing the connection + * by returning a value < 0. + */ +EVENT2_EXPORT_SYMBOL +void evhttp_request_set_header_cb(struct evhttp_request *, + int (*cb)(struct evhttp_request *, void *)); + +/** + * The different error types supported by evhttp + * + * @see evhttp_request_set_error_cb() + */ +enum evhttp_request_error { + /** + * Timeout reached, also @see evhttp_connection_set_timeout() + */ + EVREQ_HTTP_TIMEOUT, + /** + * EOF reached + */ + EVREQ_HTTP_EOF, + /** + * Error while reading header, or invalid header + */ + EVREQ_HTTP_INVALID_HEADER, + /** + * Error encountered while reading or writing + */ + EVREQ_HTTP_BUFFER_ERROR, + /** + * The evhttp_cancel_request() called on this request. + */ + EVREQ_HTTP_REQUEST_CANCEL, + /** + * Body is greater then evhttp_connection_set_max_body_size() + */ + EVREQ_HTTP_DATA_TOO_LONG +}; +/** + * Set a callback for errors + * @see evhttp_request_error for error types. + * + * On error, both the error callback and the regular callback will be called, + * error callback is called before the regular callback. + **/ +EVENT2_EXPORT_SYMBOL +void evhttp_request_set_error_cb(struct evhttp_request *, + void (*)(enum evhttp_request_error, void *)); + +/** + * Set a callback to be called on request completion of evhttp_send_* function. + * + * The callback function will be called on the completion of the request after + * the output data has been written and before the evhttp_request object + * is destroyed. This can be useful for tracking resources associated with a + * request (ex: timing metrics). + * + * @param req a request object + * @param cb callback function that will be called on request completion + * @param cb_arg an additional context argument for the callback + */ +EVENT2_EXPORT_SYMBOL +void evhttp_request_set_on_complete_cb(struct evhttp_request *req, + void (*cb)(struct evhttp_request *, void *), void *cb_arg); + +/** Frees the request object and removes associated events. */ +EVENT2_EXPORT_SYMBOL +void evhttp_request_free(struct evhttp_request *req); + +/** + * Create and return a connection object that can be used to for making HTTP + * requests. The connection object tries to resolve address and establish the + * connection when it is given an http request object. + * + * @param base the event_base to use for handling the connection + * @param dnsbase the dns_base to use for resolving host names; if not + * specified host name resolution will block. + * @param address the address to which to connect + * @param port the port to connect to + * @return an evhttp_connection object that can be used for making requests or + * NULL on error + */ +EVENT2_EXPORT_SYMBOL +struct evhttp_connection *evhttp_connection_base_new( + struct event_base *base, struct evdns_base *dnsbase, + const char *address, ev_uint16_t port); + +/** + * Set family hint for DNS requests. + */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_family(struct evhttp_connection *evcon, + int family); + +/* reuse connection address on retry */ +#define EVHTTP_CON_REUSE_CONNECTED_ADDR 0x0008 +/* Try to read error, since server may already send and close + * connection, but if at that time we have some data to send then we + * can send get EPIPE and fail, while we can read that HTTP error. */ +#define EVHTTP_CON_READ_ON_WRITE_ERROR 0x0010 +/* @see EVHTTP_SERVER_LINGERING_CLOSE */ +#define EVHTTP_CON_LINGERING_CLOSE 0x0020 +/* Padding for public flags, @see EVHTTP_CON_* in http-internal.h */ +#define EVHTTP_CON_PUBLIC_FLAGS_END 0x100000 +/** + * Set connection flags. + * + * @see EVHTTP_CON_* + * @return 0 on success, otherwise non zero (for example if flag doesn't + * supported). + */ +EVENT2_EXPORT_SYMBOL +int evhttp_connection_set_flags(struct evhttp_connection *evcon, + int flags); + +/** Takes ownership of the request object + * + * Can be used in a request callback to keep onto the request until + * evhttp_request_free() is explicitly called by the user. + */ +EVENT2_EXPORT_SYMBOL +void evhttp_request_own(struct evhttp_request *req); + +/** Returns 1 if the request is owned by the user */ +EVENT2_EXPORT_SYMBOL +int evhttp_request_is_owned(struct evhttp_request *req); + +/** + * Returns the connection object associated with the request or NULL + * + * The user needs to either free the request explicitly or call + * evhttp_send_reply_end(). + */ +EVENT2_EXPORT_SYMBOL +struct evhttp_connection *evhttp_request_get_connection(struct evhttp_request *req); + +/** + * Returns the underlying event_base for this connection + */ +EVENT2_EXPORT_SYMBOL +struct event_base *evhttp_connection_get_base(struct evhttp_connection *req); + +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_max_headers_size(struct evhttp_connection *evcon, + ev_ssize_t new_max_headers_size); + +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_max_body_size(struct evhttp_connection* evcon, + ev_ssize_t new_max_body_size); + +/** Frees an http connection */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_free(struct evhttp_connection *evcon); + +/** Disowns a given connection object + * + * Can be used to tell libevent to free the connection object after + * the last request has completed or failed. + */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_free_on_completion(struct evhttp_connection *evcon); + +/** sets the ip address from which http connections are made */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_local_address(struct evhttp_connection *evcon, + const char *address); + +/** sets the local port from which http connections are made */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_local_port(struct evhttp_connection *evcon, + ev_uint16_t port); + +/** Sets the timeout in seconds for events related to this connection */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_timeout(struct evhttp_connection *evcon, + int timeout_in_secs); + +/** Sets the timeout for events related to this connection. Takes a struct + * timeval. */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_timeout_tv(struct evhttp_connection *evcon, + const struct timeval *tv); + +/** Sets the delay before retrying requests on this connection. This is only + * used if evhttp_connection_set_retries is used to make the number of retries + * at least one. Each retry after the first is twice as long as the one before + * it. */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_initial_retry_tv(struct evhttp_connection *evcon, + const struct timeval *tv); + +/** Sets the retry limit for this connection - -1 repeats indefinitely */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_retries(struct evhttp_connection *evcon, + int retry_max); + +/** Set a callback for connection close. */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_closecb(struct evhttp_connection *evcon, + void (*)(struct evhttp_connection *, void *), void *); + +/** Get the remote address and port associated with this connection. */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_get_peer(struct evhttp_connection *evcon, + char **address, ev_uint16_t *port); + +/** Get the remote address associated with this connection. + * extracted from getpeername() OR from nameserver. + * + * @return NULL if getpeername() return non success, + * or connection is not connected, + * otherwise it return pointer to struct sockaddr_storage */ +EVENT2_EXPORT_SYMBOL +const struct sockaddr* +evhttp_connection_get_addr(struct evhttp_connection *evcon); + +/** + Make an HTTP request over the specified connection. + + The connection gets ownership of the request. On failure, the + request object is no longer valid as it has been freed. + + @param evcon the evhttp_connection object over which to send the request + @param req the previously created and configured request object + @param type the request type EVHTTP_REQ_GET, EVHTTP_REQ_POST, etc. + @param uri the URI associated with the request + @return 0 on success, -1 on failure + @see evhttp_cancel_request() +*/ +EVENT2_EXPORT_SYMBOL +int evhttp_make_request(struct evhttp_connection *evcon, + struct evhttp_request *req, + enum evhttp_cmd_type type, const char *uri); + +/** + Cancels a pending HTTP request. + + Cancels an ongoing HTTP request. The callback associated with this request + is not executed and the request object is freed. If the request is + currently being processed, e.g. it is ongoing, the corresponding + evhttp_connection object is going to get reset. + + A request cannot be canceled if its callback has executed already. A request + may be canceled reentrantly from its chunked callback. + + @param req the evhttp_request to cancel; req becomes invalid after this call. +*/ +EVENT2_EXPORT_SYMBOL +void evhttp_cancel_request(struct evhttp_request *req); + +/** + * A structure to hold a parsed URI or Relative-Ref conforming to RFC3986. + */ +struct evhttp_uri; + +/** Returns the request URI */ +EVENT2_EXPORT_SYMBOL +const char *evhttp_request_get_uri(const struct evhttp_request *req); +/** Returns the request URI (parsed) */ +EVENT2_EXPORT_SYMBOL +const struct evhttp_uri *evhttp_request_get_evhttp_uri(const struct evhttp_request *req); +/** Returns the request command */ +EVENT2_EXPORT_SYMBOL +enum evhttp_cmd_type evhttp_request_get_command(const struct evhttp_request *req); + +EVENT2_EXPORT_SYMBOL +int evhttp_request_get_response_code(const struct evhttp_request *req); +EVENT2_EXPORT_SYMBOL +const char * evhttp_request_get_response_code_line(const struct evhttp_request *req); + +/** Returns the input headers */ +EVENT2_EXPORT_SYMBOL +struct evkeyvalq *evhttp_request_get_input_headers(struct evhttp_request *req); +/** Returns the output headers */ +EVENT2_EXPORT_SYMBOL +struct evkeyvalq *evhttp_request_get_output_headers(struct evhttp_request *req); +/** Returns the input buffer */ +EVENT2_EXPORT_SYMBOL +struct evbuffer *evhttp_request_get_input_buffer(struct evhttp_request *req); +/** Returns the output buffer */ +EVENT2_EXPORT_SYMBOL +struct evbuffer *evhttp_request_get_output_buffer(struct evhttp_request *req); +/** Returns the host associated with the request. If a client sends an absolute + URI, the host part of that is preferred. Otherwise, the input headers are + searched for a Host: header. NULL is returned if no absolute URI or Host: + header is provided. */ +EVENT2_EXPORT_SYMBOL +const char *evhttp_request_get_host(struct evhttp_request *req); + +/* Interfaces for dealing with HTTP headers */ + +/** + Finds the value belonging to a header. + + @param headers the evkeyvalq object in which to find the header + @param key the name of the header to find + @returns a pointer to the value for the header or NULL if the header + could not be found. + @see evhttp_add_header(), evhttp_remove_header() +*/ +EVENT2_EXPORT_SYMBOL +const char *evhttp_find_header(const struct evkeyvalq *headers, + const char *key); + +/** + Removes a header from a list of existing headers. + + @param headers the evkeyvalq object from which to remove a header + @param key the name of the header to remove + @returns 0 if the header was removed, -1 otherwise. + @see evhttp_find_header(), evhttp_add_header() +*/ +EVENT2_EXPORT_SYMBOL +int evhttp_remove_header(struct evkeyvalq *headers, const char *key); + +/** + Adds a header to a list of existing headers. + + @param headers the evkeyvalq object to which to add a header + @param key the name of the header + @param value the value belonging to the header + @returns 0 on success, -1 otherwise. + @see evhttp_find_header(), evhttp_clear_headers() +*/ +EVENT2_EXPORT_SYMBOL +int evhttp_add_header(struct evkeyvalq *headers, const char *key, const char *value); + +/** + Removes all headers from the header list. + + @param headers the evkeyvalq object from which to remove all headers +*/ +EVENT2_EXPORT_SYMBOL +void evhttp_clear_headers(struct evkeyvalq *headers); + +/* Miscellaneous utility functions */ + + +/** + Helper function to encode a string for inclusion in a URI. All + characters are replaced by their hex-escaped (%22) equivalents, + except for characters explicitly unreserved by RFC3986 -- that is, + ASCII alphanumeric characters, hyphen, dot, underscore, and tilde. + + The returned string must be freed by the caller. + + @param str an unencoded string + @return a newly allocated URI-encoded string or NULL on failure + */ +EVENT2_EXPORT_SYMBOL +char *evhttp_encode_uri(const char *str); + +/** + As evhttp_encode_uri, but if 'size' is nonnegative, treat the string + as being 'size' bytes long. This allows you to encode strings that + may contain 0-valued bytes. + + The returned string must be freed by the caller. + + @param str an unencoded string + @param size the length of the string to encode, or -1 if the string + is NUL-terminated + @param space_to_plus if true, space characters in 'str' are encoded + as +, not %20. + @return a newly allocate URI-encoded string, or NULL on failure. + */ +EVENT2_EXPORT_SYMBOL +char *evhttp_uriencode(const char *str, ev_ssize_t size, int space_to_plus); + +/** + Helper function to sort of decode a URI-encoded string. Unlike + evhttp_uridecode, it decodes all plus characters that appear + _after_ the first question mark character, but no plusses that occur + before. This is not a good way to decode URIs in whole or in part. + + The returned string must be freed by the caller + + @deprecated This function is deprecated; you probably want to use + evhttp_uridecode instead. + + @param uri an encoded URI + @return a newly allocated unencoded URI or NULL on failure + */ +EVENT2_EXPORT_SYMBOL +char *evhttp_decode_uri(const char *uri); + +/** + Helper function to decode a URI-escaped string or HTTP parameter. + + If 'decode_plus' is 1, then we decode the string as an HTTP parameter + value, and convert all plus ('+') characters to spaces. If + 'decode_plus' is 0, we leave all plus characters unchanged. + + The returned string must be freed by the caller. + + @param uri a URI-encode encoded URI + @param decode_plus determines whether we convert '+' to space. + @param size_out if size_out is not NULL, *size_out is set to the size of the + returned string + @return a newly allocated unencoded URI or NULL on failure + */ +EVENT2_EXPORT_SYMBOL +char *evhttp_uridecode(const char *uri, int decode_plus, + size_t *size_out); + +/** + Helper function to parse out arguments in a query. + + Parsing a URI like + + http://foo.com/?q=test&s=some+thing + + will result in two entries in the key value queue. + + The first entry is: key="q", value="test" + The second entry is: key="s", value="some thing" + + @deprecated This function is deprecated as of Libevent 2.0.9. Use + evhttp_uri_parse and evhttp_parse_query_str instead. + + @param uri the request URI + @param headers the head of the evkeyval queue + @return 0 on success, -1 on failure + */ +EVENT2_EXPORT_SYMBOL +int evhttp_parse_query(const char *uri, struct evkeyvalq *headers); + +/** + Helper function to parse out arguments from the query portion of an + HTTP URI. + + Parsing a query string like + + q=test&s=some+thing + + will result in two entries in the key value queue. + + The first entry is: key="q", value="test" + The second entry is: key="s", value="some thing" + + @param query_parse the query portion of the URI + @param headers the head of the evkeyval queue + @return 0 on success, -1 on failure + */ +EVENT2_EXPORT_SYMBOL +int evhttp_parse_query_str(const char *uri, struct evkeyvalq *headers); + +/** + * Escape HTML character entities in a string. + * + * Replaces <, >, ", ' and & with <, >, ", + * ' and & correspondingly. + * + * The returned string needs to be freed by the caller. + * + * @param html an unescaped HTML string + * @return an escaped HTML string or NULL on error + */ +EVENT2_EXPORT_SYMBOL +char *evhttp_htmlescape(const char *html); + +/** + * Return a new empty evhttp_uri with no fields set. + */ +EVENT2_EXPORT_SYMBOL +struct evhttp_uri *evhttp_uri_new(void); + +/** + * Changes the flags set on a given URI. See EVHTTP_URI_* for + * a list of flags. + **/ +EVENT2_EXPORT_SYMBOL +void evhttp_uri_set_flags(struct evhttp_uri *uri, unsigned flags); + +/** Return the scheme of an evhttp_uri, or NULL if there is no scheme has + * been set and the evhttp_uri contains a Relative-Ref. */ +EVENT2_EXPORT_SYMBOL +const char *evhttp_uri_get_scheme(const struct evhttp_uri *uri); +/** + * Return the userinfo part of an evhttp_uri, or NULL if it has no userinfo + * set. + */ +EVENT2_EXPORT_SYMBOL +const char *evhttp_uri_get_userinfo(const struct evhttp_uri *uri); +/** + * Return the host part of an evhttp_uri, or NULL if it has no host set. + * The host may either be a regular hostname (conforming to the RFC 3986 + * "regname" production), or an IPv4 address, or the empty string, or a + * bracketed IPv6 address, or a bracketed 'IP-Future' address. + * + * Note that having a NULL host means that the URI has no authority + * section, but having an empty-string host means that the URI has an + * authority section with no host part. For example, + * "mailto:user@example.com" has a host of NULL, but "file:///etc/motd" + * has a host of "". + */ +EVENT2_EXPORT_SYMBOL +const char *evhttp_uri_get_host(const struct evhttp_uri *uri); +/** Return the port part of an evhttp_uri, or -1 if there is no port set. */ +EVENT2_EXPORT_SYMBOL +int evhttp_uri_get_port(const struct evhttp_uri *uri); +/** Return the path part of an evhttp_uri, or NULL if it has no path set */ +EVENT2_EXPORT_SYMBOL +const char *evhttp_uri_get_path(const struct evhttp_uri *uri); +/** Return the query part of an evhttp_uri (excluding the leading "?"), or + * NULL if it has no query set */ +EVENT2_EXPORT_SYMBOL +const char *evhttp_uri_get_query(const struct evhttp_uri *uri); +/** Return the fragment part of an evhttp_uri (excluding the leading "#"), + * or NULL if it has no fragment set */ +EVENT2_EXPORT_SYMBOL +const char *evhttp_uri_get_fragment(const struct evhttp_uri *uri); + +/** Set the scheme of an evhttp_uri, or clear the scheme if scheme==NULL. + * Returns 0 on success, -1 if scheme is not well-formed. */ +EVENT2_EXPORT_SYMBOL +int evhttp_uri_set_scheme(struct evhttp_uri *uri, const char *scheme); +/** Set the userinfo of an evhttp_uri, or clear the userinfo if userinfo==NULL. + * Returns 0 on success, -1 if userinfo is not well-formed. */ +EVENT2_EXPORT_SYMBOL +int evhttp_uri_set_userinfo(struct evhttp_uri *uri, const char *userinfo); +/** Set the host of an evhttp_uri, or clear the host if host==NULL. + * Returns 0 on success, -1 if host is not well-formed. */ +EVENT2_EXPORT_SYMBOL +int evhttp_uri_set_host(struct evhttp_uri *uri, const char *host); +/** Set the port of an evhttp_uri, or clear the port if port==-1. + * Returns 0 on success, -1 if port is not well-formed. */ +EVENT2_EXPORT_SYMBOL +int evhttp_uri_set_port(struct evhttp_uri *uri, int port); +/** Set the path of an evhttp_uri, or clear the path if path==NULL. + * Returns 0 on success, -1 if path is not well-formed. */ +EVENT2_EXPORT_SYMBOL +int evhttp_uri_set_path(struct evhttp_uri *uri, const char *path); +/** Set the query of an evhttp_uri, or clear the query if query==NULL. + * The query should not include a leading "?". + * Returns 0 on success, -1 if query is not well-formed. */ +EVENT2_EXPORT_SYMBOL +int evhttp_uri_set_query(struct evhttp_uri *uri, const char *query); +/** Set the fragment of an evhttp_uri, or clear the fragment if fragment==NULL. + * The fragment should not include a leading "#". + * Returns 0 on success, -1 if fragment is not well-formed. */ +EVENT2_EXPORT_SYMBOL +int evhttp_uri_set_fragment(struct evhttp_uri *uri, const char *fragment); + +/** + * Helper function to parse a URI-Reference as specified by RFC3986. + * + * This function matches the URI-Reference production from RFC3986, + * which includes both URIs like + * + * scheme://[[userinfo]@]foo.com[:port]]/[path][?query][#fragment] + * + * and relative-refs like + * + * [path][?query][#fragment] + * + * Any optional elements portions not present in the original URI are + * left set to NULL in the resulting evhttp_uri. If no port is + * specified, the port is set to -1. + * + * Note that no decoding is performed on percent-escaped characters in + * the string; if you want to parse them, use evhttp_uridecode or + * evhttp_parse_query_str as appropriate. + * + * Note also that most URI schemes will have additional constraints that + * this function does not know about, and cannot check. For example, + * mailto://www.example.com/cgi-bin/fortune.pl is not a reasonable + * mailto url, http://www.example.com:99999/ is not a reasonable HTTP + * URL, and ftp:username@example.com is not a reasonable FTP URL. + * Nevertheless, all of these URLs conform to RFC3986, and this function + * accepts all of them as valid. + * + * @param source_uri the request URI + * @param flags Zero or more EVHTTP_URI_* flags to affect the behavior + * of the parser. + * @return uri container to hold parsed data, or NULL if there is error + * @see evhttp_uri_free() + */ +EVENT2_EXPORT_SYMBOL +struct evhttp_uri *evhttp_uri_parse_with_flags(const char *source_uri, + unsigned flags); + +/** Tolerate URIs that do not conform to RFC3986. + * + * Unfortunately, some HTTP clients generate URIs that, according to RFC3986, + * are not conformant URIs. If you need to support these URIs, you can + * do so by passing this flag to evhttp_uri_parse_with_flags. + * + * Currently, these changes are: + *
    + *
  • Nonconformant URIs are allowed to contain otherwise unreasonable + * characters in their path, query, and fragment components. + *
+ */ +#define EVHTTP_URI_NONCONFORMANT 0x01 + +/** Alias for evhttp_uri_parse_with_flags(source_uri, 0) */ +EVENT2_EXPORT_SYMBOL +struct evhttp_uri *evhttp_uri_parse(const char *source_uri); + +/** + * Free all memory allocated for a parsed uri. Only use this for URIs + * generated by evhttp_uri_parse. + * + * @param uri container with parsed data + * @see evhttp_uri_parse() + */ +EVENT2_EXPORT_SYMBOL +void evhttp_uri_free(struct evhttp_uri *uri); + +/** + * Join together the uri parts from parsed data to form a URI-Reference. + * + * Note that no escaping of reserved characters is done on the members + * of the evhttp_uri, so the generated string might not be a valid URI + * unless the members of evhttp_uri are themselves valid. + * + * @param uri container with parsed data + * @param buf destination buffer + * @param limit destination buffer size + * @return an joined uri as string or NULL on error + * @see evhttp_uri_parse() + */ +EVENT2_EXPORT_SYMBOL +char *evhttp_uri_join(struct evhttp_uri *uri, char *buf, size_t limit); + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_HTTP_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/include/event2/http_compat.h b/bsnes/thrift/libevent/include/event2/http_compat.h new file mode 100644 index 00000000..794a5810 --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/http_compat.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_HTTP_COMPAT_H_INCLUDED_ +#define EVENT2_HTTP_COMPAT_H_INCLUDED_ + +/** @file event2/http_compat.h + + Potentially non-threadsafe versions of the functions in http.h: provided + only for backwards compatibility. + + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif + +/* For int types. */ +#include + +/** + * Start an HTTP server on the specified address and port + * + * @deprecated It does not allow an event base to be specified + * + * @param address the address to which the HTTP server should be bound + * @param port the port number on which the HTTP server should listen + * @return a pointer to a newly initialized evhttp server structure + * or NULL on error + */ +EVENT2_EXPORT_SYMBOL +struct evhttp *evhttp_start(const char *address, ev_uint16_t port); + +/** + * A connection object that can be used to for making HTTP requests. The + * connection object tries to establish the connection when it is given an + * http request object. + * + * @deprecated It does not allow an event base to be specified + */ +EVENT2_EXPORT_SYMBOL +struct evhttp_connection *evhttp_connection_new( + const char *address, ev_uint16_t port); + +/** + * Associates an event base with the connection - can only be called + * on a freshly created connection object that has not been used yet. + * + * @deprecated XXXX Why? + */ +EVENT2_EXPORT_SYMBOL +void evhttp_connection_set_base(struct evhttp_connection *evcon, + struct event_base *base); + + +/** Returns the request URI */ +#define evhttp_request_uri evhttp_request_get_uri + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_EVENT_COMPAT_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/include/event2/http_struct.h b/bsnes/thrift/libevent/include/event2/http_struct.h new file mode 100644 index 00000000..4bf5b1ff --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/http_struct.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_HTTP_STRUCT_H_INCLUDED_ +#define EVENT2_HTTP_STRUCT_H_INCLUDED_ + +/** @file event2/http_struct.h + + Data structures for http. Using these structures may hurt forward + compatibility with later versions of Libevent: be careful! + + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif + +/* For int types. */ +#include + +/** + * the request structure that a server receives. + * WARNING: expect this structure to change. I will try to provide + * reasonable accessors. + */ +struct evhttp_request { +#if defined(TAILQ_ENTRY) + TAILQ_ENTRY(evhttp_request) next; +#else +struct { + struct evhttp_request *tqe_next; + struct evhttp_request **tqe_prev; +} next; +#endif + + /* the connection object that this request belongs to */ + struct evhttp_connection *evcon; + int flags; +/** The request obj owns the evhttp connection and needs to free it */ +#define EVHTTP_REQ_OWN_CONNECTION 0x0001 +/** Request was made via a proxy */ +#define EVHTTP_PROXY_REQUEST 0x0002 +/** The request object is owned by the user; the user must free it */ +#define EVHTTP_USER_OWNED 0x0004 +/** The request will be used again upstack; freeing must be deferred */ +#define EVHTTP_REQ_DEFER_FREE 0x0008 +/** The request should be freed upstack */ +#define EVHTTP_REQ_NEEDS_FREE 0x0010 + + struct evkeyvalq *input_headers; + struct evkeyvalq *output_headers; + + /* address of the remote host and the port connection came from */ + char *remote_host; + ev_uint16_t remote_port; + + /* cache of the hostname for evhttp_request_get_host */ + char *host_cache; + + enum evhttp_request_kind kind; + enum evhttp_cmd_type type; + + size_t headers_size; + size_t body_size; + + char *uri; /* uri after HTTP request was parsed */ + struct evhttp_uri *uri_elems; /* uri elements */ + + char major; /* HTTP Major number */ + char minor; /* HTTP Minor number */ + + int response_code; /* HTTP Response code */ + char *response_code_line; /* Readable response */ + + struct evbuffer *input_buffer; /* read data */ + ev_int64_t ntoread; + unsigned chunked:1, /* a chunked request */ + userdone:1; /* the user has sent all data */ + + struct evbuffer *output_buffer; /* outgoing post or data */ + + /* Callback */ + void (*cb)(struct evhttp_request *, void *); + void *cb_arg; + + /* + * Chunked data callback - call for each completed chunk if + * specified. If not specified, all the data is delivered via + * the regular callback. + */ + void (*chunk_cb)(struct evhttp_request *, void *); + + /* + * Callback added for forked-daapd so they can collect ICY + * (shoutcast) metadata from the http header. If return + * int is negative the connection will be closed. + */ + int (*header_cb)(struct evhttp_request *, void *); + + /* + * Error callback - called when error is occured. + * @see evhttp_request_error for error types. + * + * @see evhttp_request_set_error_cb() + */ + void (*error_cb)(enum evhttp_request_error, void *); + + /* + * Send complete callback - called when the request is actually + * sent and completed. + */ + void (*on_complete_cb)(struct evhttp_request *, void *); + void *on_complete_cb_arg; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_HTTP_STRUCT_H_INCLUDED_ */ + diff --git a/bsnes/thrift/libevent/include/event2/keyvalq_struct.h b/bsnes/thrift/libevent/include/event2/keyvalq_struct.h new file mode 100644 index 00000000..bffa54b3 --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/keyvalq_struct.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_KEYVALQ_STRUCT_H_INCLUDED_ +#define EVENT2_KEYVALQ_STRUCT_H_INCLUDED_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Fix so that people don't have to run with */ +/* XXXX This code is duplicated with event_struct.h */ +#ifndef TAILQ_ENTRY +#define EVENT_DEFINED_TQENTRY_ +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} +#endif /* !TAILQ_ENTRY */ + +#ifndef TAILQ_HEAD +#define EVENT_DEFINED_TQHEAD_ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; \ + struct type **tqh_last; \ +} +#endif + +/* + * Key-Value pairs. Can be used for HTTP headers but also for + * query argument parsing. + */ +struct evkeyval { + TAILQ_ENTRY(evkeyval) next; + + char *key; + char *value; +}; + +TAILQ_HEAD (evkeyvalq, evkeyval); + +/* XXXX This code is duplicated with event_struct.h */ +#ifdef EVENT_DEFINED_TQENTRY_ +#undef TAILQ_ENTRY +#endif + +#ifdef EVENT_DEFINED_TQHEAD_ +#undef TAILQ_HEAD +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/bsnes/thrift/libevent/include/event2/listener.h b/bsnes/thrift/libevent/include/event2/listener.h new file mode 100644 index 00000000..789a27c2 --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/listener.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_LISTENER_H_INCLUDED_ +#define EVENT2_LISTENER_H_INCLUDED_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct sockaddr; +struct evconnlistener; + +/** + A callback that we invoke when a listener has a new connection. + + @param listener The evconnlistener + @param fd The new file descriptor + @param addr The source address of the connection + @param socklen The length of addr + @param user_arg the pointer passed to evconnlistener_new() + */ +typedef void (*evconnlistener_cb)(struct evconnlistener *, evutil_socket_t, struct sockaddr *, int socklen, void *); + +/** + A callback that we invoke when a listener encounters a non-retriable error. + + @param listener The evconnlistener + @param user_arg the pointer passed to evconnlistener_new() + */ +typedef void (*evconnlistener_errorcb)(struct evconnlistener *, void *); + +/** Flag: Indicates that we should not make incoming sockets nonblocking + * before passing them to the callback. */ +#define LEV_OPT_LEAVE_SOCKETS_BLOCKING (1u<<0) +/** Flag: Indicates that freeing the listener should close the underlying + * socket. */ +#define LEV_OPT_CLOSE_ON_FREE (1u<<1) +/** Flag: Indicates that we should set the close-on-exec flag, if possible */ +#define LEV_OPT_CLOSE_ON_EXEC (1u<<2) +/** Flag: Indicates that we should disable the timeout (if any) between when + * this socket is closed and when we can listen again on the same port. */ +#define LEV_OPT_REUSEABLE (1u<<3) +/** Flag: Indicates that the listener should be locked so it's safe to use + * from multiple threadcs at once. */ +#define LEV_OPT_THREADSAFE (1u<<4) +/** Flag: Indicates that the listener should be created in disabled + * state. Use evconnlistener_enable() to enable it later. */ +#define LEV_OPT_DISABLED (1u<<5) +/** Flag: Indicates that the listener should defer accept() until data is + * available, if possible. Ignored on platforms that do not support this. + * + * This option can help performance for protocols where the client transmits + * immediately after connecting. Do not use this option if your protocol + * _doesn't_ start out with the client transmitting data, since in that case + * this option will sometimes cause the kernel to never tell you about the + * connection. + * + * This option is only supported by evconnlistener_new_bind(): it can't + * work with evconnlistener_new_fd(), since the listener needs to be told + * to use the option before it is actually bound. + */ +#define LEV_OPT_DEFERRED_ACCEPT (1u<<6) +/** Flag: Indicates that we ask to allow multiple servers (processes or + * threads) to bind to the same port if they each set the option. + * + * SO_REUSEPORT is what most people would expect SO_REUSEADDR to be, however + * SO_REUSEPORT does not imply SO_REUSEADDR. + * + * This is only available on Linux and kernel 3.9+ + */ +#define LEV_OPT_REUSEABLE_PORT (1u<<7) +/** Flag: Indicates that the listener wants to work only in IPv6 socket. + * + * According to RFC3493 and most Linux distributions, default value is to + * work in IPv4-mapped mode. If there is a requirement to bind same port + * on same ip addresses but different handlers for both IPv4 and IPv6, + * it is required to set IPV6_V6ONLY socket option to be sure that the + * code works as expected without affected by bindv6only sysctl setting in + * system. + * + * This socket option also supported by Windows. + */ +#define LEV_OPT_BIND_IPV6ONLY (1u<<8) + +/** + Allocate a new evconnlistener object to listen for incoming TCP connections + on a given file descriptor. + + @param base The event base to associate the listener with. + @param cb A callback to be invoked when a new connection arrives. If the + callback is NULL, the listener will be treated as disabled until the + callback is set. + @param ptr A user-supplied pointer to give to the callback. + @param flags Any number of LEV_OPT_* flags + @param backlog Passed to the listen() call to determine the length of the + acceptable connection backlog. Set to -1 for a reasonable default. + Set to 0 if the socket is already listening. + @param fd The file descriptor to listen on. It must be a nonblocking + file descriptor, and it should already be bound to an appropriate + port and address. +*/ +EVENT2_EXPORT_SYMBOL +struct evconnlistener *evconnlistener_new(struct event_base *base, + evconnlistener_cb cb, void *ptr, unsigned flags, int backlog, + evutil_socket_t fd); +/** + Allocate a new evconnlistener object to listen for incoming TCP connections + on a given address. + + @param base The event base to associate the listener with. + @param cb A callback to be invoked when a new connection arrives. If the + callback is NULL, the listener will be treated as disabled until the + callback is set. + @param ptr A user-supplied pointer to give to the callback. + @param flags Any number of LEV_OPT_* flags + @param backlog Passed to the listen() call to determine the length of the + acceptable connection backlog. Set to -1 for a reasonable default. + @param addr The address to listen for connections on. + @param socklen The length of the address. + */ +EVENT2_EXPORT_SYMBOL +struct evconnlistener *evconnlistener_new_bind(struct event_base *base, + evconnlistener_cb cb, void *ptr, unsigned flags, int backlog, + const struct sockaddr *sa, int socklen); +/** + Disable and deallocate an evconnlistener. + */ +EVENT2_EXPORT_SYMBOL +void evconnlistener_free(struct evconnlistener *lev); +/** + Re-enable an evconnlistener that has been disabled. + */ +EVENT2_EXPORT_SYMBOL +int evconnlistener_enable(struct evconnlistener *lev); +/** + Stop listening for connections on an evconnlistener. + */ +EVENT2_EXPORT_SYMBOL +int evconnlistener_disable(struct evconnlistener *lev); + +/** Return an evconnlistener's associated event_base. */ +EVENT2_EXPORT_SYMBOL +struct event_base *evconnlistener_get_base(struct evconnlistener *lev); + +/** Return the socket that an evconnlistner is listening on. */ +EVENT2_EXPORT_SYMBOL +evutil_socket_t evconnlistener_get_fd(struct evconnlistener *lev); + +/** Change the callback on the listener to cb and its user_data to arg. + */ +EVENT2_EXPORT_SYMBOL +void evconnlistener_set_cb(struct evconnlistener *lev, + evconnlistener_cb cb, void *arg); + +/** Set an evconnlistener's error callback. */ +EVENT2_EXPORT_SYMBOL +void evconnlistener_set_error_cb(struct evconnlistener *lev, + evconnlistener_errorcb errorcb); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/bsnes/thrift/libevent/include/event2/rpc.h b/bsnes/thrift/libevent/include/event2/rpc.h new file mode 100644 index 00000000..1bc31d57 --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/rpc.h @@ -0,0 +1,626 @@ +/* + * Copyright (c) 2006-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_RPC_H_INCLUDED_ +#define EVENT2_RPC_H_INCLUDED_ + +/* For int types. */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @file rpc.h + * + * This header files provides basic support for an RPC server and client. + * + * To support RPCs in a server, every supported RPC command needs to be + * defined and registered. + * + * EVRPC_HEADER(SendCommand, Request, Reply); + * + * SendCommand is the name of the RPC command. + * Request is the name of a structure generated by event_rpcgen.py. + * It contains all parameters relating to the SendCommand RPC. The + * server needs to fill in the Reply structure. + * Reply is the name of a structure generated by event_rpcgen.py. It + * contains the answer to the RPC. + * + * To register an RPC with an HTTP server, you need to first create an RPC + * base with: + * + * struct evrpc_base *base = evrpc_init(http); + * + * A specific RPC can then be registered with + * + * EVRPC_REGISTER(base, SendCommand, Request, Reply, FunctionCB, arg); + * + * when the server receives an appropriately formatted RPC, the user callback + * is invoked. The callback needs to fill in the reply structure. + * + * void FunctionCB(EVRPC_STRUCT(SendCommand)* rpc, void *arg); + * + * To send the reply, call EVRPC_REQUEST_DONE(rpc); + * + * See the regression test for an example. + */ + +/** + Determines if the member has been set in the message + + @param msg the message to inspect + @param member the member variable to test for presences + @return 1 if it's present or 0 otherwise. +*/ +#define EVTAG_HAS(msg, member) \ + ((msg)->member##_set == 1) + +#ifndef EVENT2_RPC_COMPAT_H_INCLUDED_ + +/** + Assigns a value to the member in the message. + + @param msg the message to which to assign a value + @param member the name of the member variable + @param value the value to assign +*/ +#define EVTAG_ASSIGN(msg, member, value) \ + (*(msg)->base->member##_assign)((msg), (value)) +/** + Assigns a value to the member in the message. + + @param msg the message to which to assign a value + @param member the name of the member variable + @param value the value to assign + @param len the length of the value +*/ +#define EVTAG_ASSIGN_WITH_LEN(msg, member, value, len) \ + (*(msg)->base->member##_assign)((msg), (value), (len)) +/** + Returns the value for a member. + + @param msg the message from which to get the value + @param member the name of the member variable + @param pvalue a pointer to the variable to hold the value + @return 0 on success, -1 otherwise. +*/ +#define EVTAG_GET(msg, member, pvalue) \ + (*(msg)->base->member##_get)((msg), (pvalue)) +/** + Returns the value for a member. + + @param msg the message from which to get the value + @param member the name of the member variable + @param pvalue a pointer to the variable to hold the value + @param plen a pointer to the length of the value + @return 0 on success, -1 otherwise. +*/ +#define EVTAG_GET_WITH_LEN(msg, member, pvalue, plen) \ + (*(msg)->base->member##_get)((msg), (pvalue), (plen)) + +#endif /* EVENT2_RPC_COMPAT_H_INCLUDED_ */ + +/** + Adds a value to an array. +*/ +#define EVTAG_ARRAY_ADD_VALUE(msg, member, value) \ + (*(msg)->base->member##_add)((msg), (value)) +/** + Allocates a new entry in the array and returns it. +*/ +#define EVTAG_ARRAY_ADD(msg, member) \ + (*(msg)->base->member##_add)(msg) +/** + Gets a variable at the specified offset from the array. +*/ +#define EVTAG_ARRAY_GET(msg, member, offset, pvalue) \ + (*(msg)->base->member##_get)((msg), (offset), (pvalue)) +/** + Returns the number of entries in the array. +*/ +#define EVTAG_ARRAY_LEN(msg, member) ((msg)->member##_length) + + +struct evbuffer; +struct event_base; +struct evrpc_req_generic; +struct evrpc_request_wrapper; +struct evrpc; + +/** The type of a specific RPC Message + * + * @param rpcname the name of the RPC message + */ +#define EVRPC_STRUCT(rpcname) struct evrpc_req__##rpcname + +struct evhttp_request; +struct evrpc_status; +struct evrpc_hook_meta; + +/** Creates the definitions and prototypes for an RPC + * + * You need to use EVRPC_HEADER to create structures and function prototypes + * needed by the server and client implementation. The structures have to be + * defined in an .rpc file and converted to source code via event_rpcgen.py + * + * @param rpcname the name of the RPC + * @param reqstruct the name of the RPC request structure + * @param replystruct the name of the RPC reply structure + * @see EVRPC_GENERATE() + */ +#define EVRPC_HEADER(rpcname, reqstruct, rplystruct) \ +EVRPC_STRUCT(rpcname) { \ + struct evrpc_hook_meta *hook_meta; \ + struct reqstruct* request; \ + struct rplystruct* reply; \ + struct evrpc* rpc; \ + struct evhttp_request* http_req; \ + struct evbuffer* rpc_data; \ +}; \ +EVENT2_EXPORT_SYMBOL \ +int evrpc_send_request_##rpcname(struct evrpc_pool *, \ + struct reqstruct *, struct rplystruct *, \ + void (*)(struct evrpc_status *, \ + struct reqstruct *, struct rplystruct *, void *cbarg), \ + void *); + +struct evrpc_pool; + +/** use EVRPC_GENERATE instead */ +EVENT2_EXPORT_SYMBOL +struct evrpc_request_wrapper *evrpc_make_request_ctx( + struct evrpc_pool *pool, void *request, void *reply, + const char *rpcname, + void (*req_marshal)(struct evbuffer*, void *), + void (*rpl_clear)(void *), + int (*rpl_unmarshal)(void *, struct evbuffer *), + void (*cb)(struct evrpc_status *, void *, void *, void *), + void *cbarg); + +/** Creates a context structure that contains rpc specific information. + * + * EVRPC_MAKE_CTX is used to populate a RPC specific context that + * contains information about marshaling the RPC data types. + * + * @param rpcname the name of the RPC + * @param reqstruct the name of the RPC request structure + * @param replystruct the name of the RPC reply structure + * @param pool the evrpc_pool over which to make the request + * @param request a pointer to the RPC request structure object + * @param reply a pointer to the RPC reply structure object + * @param cb the callback function to call when the RPC has completed + * @param cbarg the argument to supply to the callback + */ +#define EVRPC_MAKE_CTX(rpcname, reqstruct, rplystruct, \ + pool, request, reply, cb, cbarg) \ + evrpc_make_request_ctx(pool, request, reply, \ + #rpcname, \ + (void (*)(struct evbuffer *, void *))reqstruct##_marshal, \ + (void (*)(void *))rplystruct##_clear, \ + (int (*)(void *, struct evbuffer *))rplystruct##_unmarshal, \ + (void (*)(struct evrpc_status *, void *, void *, void *))cb, \ + cbarg) + +/** Generates the code for receiving and sending an RPC message + * + * EVRPC_GENERATE is used to create the code corresponding to sending + * and receiving a particular RPC message + * + * @param rpcname the name of the RPC + * @param reqstruct the name of the RPC request structure + * @param replystruct the name of the RPC reply structure + * @see EVRPC_HEADER() + */ +#define EVRPC_GENERATE(rpcname, reqstruct, rplystruct) \ + int evrpc_send_request_##rpcname(struct evrpc_pool *pool, \ + struct reqstruct *request, struct rplystruct *reply, \ + void (*cb)(struct evrpc_status *, \ + struct reqstruct *, struct rplystruct *, void *cbarg), \ + void *cbarg) { \ + return evrpc_send_request_generic(pool, request, reply, \ + (void (*)(struct evrpc_status *, void *, void *, void *))cb, \ + cbarg, \ + #rpcname, \ + (void (*)(struct evbuffer *, void *))reqstruct##_marshal, \ + (void (*)(void *))rplystruct##_clear, \ + (int (*)(void *, struct evbuffer *))rplystruct##_unmarshal); \ +} + +/** Provides access to the HTTP request object underlying an RPC + * + * Access to the underlying http object; can be used to look at headers or + * for getting the remote ip address + * + * @param rpc_req the rpc request structure provided to the server callback + * @return an struct evhttp_request object that can be inspected for + * HTTP headers or sender information. + */ +#define EVRPC_REQUEST_HTTP(rpc_req) (rpc_req)->http_req + +/** completes the server response to an rpc request */ +EVENT2_EXPORT_SYMBOL +void evrpc_request_done(struct evrpc_req_generic *req); + +/** accessors for request and reply */ +EVENT2_EXPORT_SYMBOL +void *evrpc_get_request(struct evrpc_req_generic *req); +EVENT2_EXPORT_SYMBOL +void *evrpc_get_reply(struct evrpc_req_generic *req); + +/** Creates the reply to an RPC request + * + * EVRPC_REQUEST_DONE is used to answer a request; the reply is expected + * to have been filled in. The request and reply pointers become invalid + * after this call has finished. + * + * @param rpc_req the rpc request structure provided to the server callback + */ +#define EVRPC_REQUEST_DONE(rpc_req) do { \ + struct evrpc_req_generic *req_ = (struct evrpc_req_generic *)(rpc_req); \ + evrpc_request_done(req_); \ +} while (0) + + +struct evrpc_base; +struct evhttp; + +/* functions to start up the rpc system */ + +/** Creates a new rpc base from which RPC requests can be received + * + * @param server a pointer to an existing HTTP server + * @return a newly allocated evrpc_base struct or NULL if an error occurred + * @see evrpc_free() + */ +EVENT2_EXPORT_SYMBOL +struct evrpc_base *evrpc_init(struct evhttp *server); + +/** + * Frees the evrpc base + * + * For now, you are responsible for making sure that no rpcs are ongoing. + * + * @param base the evrpc_base object to be freed + * @see evrpc_init + */ +EVENT2_EXPORT_SYMBOL +void evrpc_free(struct evrpc_base *base); + +/** register RPCs with the HTTP Server + * + * registers a new RPC with the HTTP server, each RPC needs to have + * a unique name under which it can be identified. + * + * @param base the evrpc_base structure in which the RPC should be + * registered. + * @param name the name of the RPC + * @param request the name of the RPC request structure + * @param reply the name of the RPC reply structure + * @param callback the callback that should be invoked when the RPC + * is received. The callback has the following prototype + * void (*callback)(EVRPC_STRUCT(Message)* rpc, void *arg) + * @param cbarg an additional parameter that can be passed to the callback. + * The parameter can be used to carry around state. + */ +#define EVRPC_REGISTER(base, name, request, reply, callback, cbarg) \ + evrpc_register_generic(base, #name, \ + (void (*)(struct evrpc_req_generic *, void *))callback, cbarg, \ + (void *(*)(void *))request##_new_with_arg, NULL, \ + (void (*)(void *))request##_free, \ + (int (*)(void *, struct evbuffer *))request##_unmarshal, \ + (void *(*)(void *))reply##_new_with_arg, NULL, \ + (void (*)(void *))reply##_free, \ + (int (*)(void *))reply##_complete, \ + (void (*)(struct evbuffer *, void *))reply##_marshal) + +/** + Low level function for registering an RPC with a server. + + Use EVRPC_REGISTER() instead. + + @see EVRPC_REGISTER() +*/ +EVENT2_EXPORT_SYMBOL +int evrpc_register_rpc(struct evrpc_base *, struct evrpc *, + void (*)(struct evrpc_req_generic*, void *), void *); + +/** + * Unregisters an already registered RPC + * + * @param base the evrpc_base object from which to unregister an RPC + * @param name the name of the rpc to unregister + * @return -1 on error or 0 when successful. + * @see EVRPC_REGISTER() + */ +#define EVRPC_UNREGISTER(base, name) evrpc_unregister_rpc((base), #name) + +EVENT2_EXPORT_SYMBOL +int evrpc_unregister_rpc(struct evrpc_base *base, const char *name); + +/* + * Client-side RPC support + */ + +struct evhttp_connection; +struct evrpc_status; + +/** launches an RPC and sends it to the server + * + * EVRPC_MAKE_REQUEST() is used by the client to send an RPC to the server. + * + * @param name the name of the RPC + * @param pool the evrpc_pool that contains the connection objects over which + * the request should be sent. + * @param request a pointer to the RPC request structure - it contains the + * data to be sent to the server. + * @param reply a pointer to the RPC reply structure. It is going to be filled + * if the request was answered successfully + * @param cb the callback to invoke when the RPC request has been answered + * @param cbarg an additional argument to be passed to the client + * @return 0 on success, -1 on failure + */ +#define EVRPC_MAKE_REQUEST(name, pool, request, reply, cb, cbarg) \ + evrpc_send_request_##name((pool), (request), (reply), (cb), (cbarg)) + +/** + Makes an RPC request based on the provided context. + + This is a low-level function and should not be used directly + unless a custom context object is provided. Use EVRPC_MAKE_REQUEST() + instead. + + @param ctx a context from EVRPC_MAKE_CTX() + @returns 0 on success, -1 otherwise. + @see EVRPC_MAKE_REQUEST(), EVRPC_MAKE_CTX() +*/ +EVENT2_EXPORT_SYMBOL +int evrpc_make_request(struct evrpc_request_wrapper *ctx); + +/** creates an rpc connection pool + * + * a pool has a number of connections associated with it. + * rpc requests are always made via a pool. + * + * @param base a pointer to an struct event_based object; can be left NULL + * in singled-threaded applications + * @return a newly allocated struct evrpc_pool object or NULL if an error + * occurred + * @see evrpc_pool_free() + */ +EVENT2_EXPORT_SYMBOL +struct evrpc_pool *evrpc_pool_new(struct event_base *base); +/** frees an rpc connection pool + * + * @param pool a pointer to an evrpc_pool allocated via evrpc_pool_new() + * @see evrpc_pool_new() + */ +EVENT2_EXPORT_SYMBOL +void evrpc_pool_free(struct evrpc_pool *pool); + +/** + * Adds a connection over which rpc can be dispatched to the pool. + * + * The connection object must have been newly created. + * + * @param pool the pool to which to add the connection + * @param evcon the connection to add to the pool. + */ +EVENT2_EXPORT_SYMBOL +void evrpc_pool_add_connection(struct evrpc_pool *pool, + struct evhttp_connection *evcon); + +/** + * Removes a connection from the pool. + * + * The connection object must have been newly created. + * + * @param pool the pool from which to remove the connection + * @param evcon the connection to remove from the pool. + */ +EVENT2_EXPORT_SYMBOL +void evrpc_pool_remove_connection(struct evrpc_pool *pool, + struct evhttp_connection *evcon); + +/** + * Sets the timeout in secs after which a request has to complete. The + * RPC is completely aborted if it does not complete by then. Setting + * the timeout to 0 means that it never timeouts and can be used to + * implement callback type RPCs. + * + * Any connection already in the pool will be updated with the new + * timeout. Connections added to the pool after set_timeout has be + * called receive the pool timeout only if no timeout has been set + * for the connection itself. + * + * @param pool a pointer to a struct evrpc_pool object + * @param timeout_in_secs the number of seconds after which a request should + * timeout and a failure be returned to the callback. + */ +EVENT2_EXPORT_SYMBOL +void evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs); + +/** + * Hooks for changing the input and output of RPCs; this can be used to + * implement compression, authentication, encryption, ... + */ + +enum EVRPC_HOOK_TYPE { + EVRPC_INPUT, /**< apply the function to an input hook */ + EVRPC_OUTPUT /**< apply the function to an output hook */ +}; + +#ifndef _WIN32 +/** Deprecated alias for EVRPC_INPUT. Not available on windows, where it + * conflicts with platform headers. */ +#define INPUT EVRPC_INPUT +/** Deprecated alias for EVRPC_OUTPUT. Not available on windows, where it + * conflicts with platform headers. */ +#define OUTPUT EVRPC_OUTPUT +#endif + +/** + * Return value from hook processing functions + */ + +enum EVRPC_HOOK_RESULT { + EVRPC_TERMINATE = -1, /**< indicates the rpc should be terminated */ + EVRPC_CONTINUE = 0, /**< continue processing the rpc */ + EVRPC_PAUSE = 1 /**< pause processing request until resumed */ +}; + +/** adds a processing hook to either an rpc base or rpc pool + * + * If a hook returns TERMINATE, the processing is aborted. On CONTINUE, + * the request is immediately processed after the hook returns. If the + * hook returns PAUSE, request processing stops until evrpc_resume_request() + * has been called. + * + * The add functions return handles that can be used for removing hooks. + * + * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool + * @param hook_type either INPUT or OUTPUT + * @param cb the callback to call when the hook is activated + * @param cb_arg an additional argument for the callback + * @return a handle to the hook so it can be removed later + * @see evrpc_remove_hook() + */ +EVENT2_EXPORT_SYMBOL +void *evrpc_add_hook(void *vbase, + enum EVRPC_HOOK_TYPE hook_type, + int (*cb)(void *, struct evhttp_request *, struct evbuffer *, void *), + void *cb_arg); + +/** removes a previously added hook + * + * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool + * @param hook_type either INPUT or OUTPUT + * @param handle a handle returned by evrpc_add_hook() + * @return 1 on success or 0 on failure + * @see evrpc_add_hook() + */ +EVENT2_EXPORT_SYMBOL +int evrpc_remove_hook(void *vbase, + enum EVRPC_HOOK_TYPE hook_type, + void *handle); + +/** resume a paused request + * + * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool + * @param ctx the context pointer provided to the original hook call + */ +EVENT2_EXPORT_SYMBOL +int evrpc_resume_request(void *vbase, void *ctx, enum EVRPC_HOOK_RESULT res); + +/** adds meta data to request + * + * evrpc_hook_add_meta() allows hooks to add meta data to a request. for + * a client request, the meta data can be inserted by an outgoing request hook + * and retrieved by the incoming request hook. + * + * @param ctx the context provided to the hook call + * @param key a NUL-terminated c-string + * @param data the data to be associated with the key + * @param data_size the size of the data + */ +EVENT2_EXPORT_SYMBOL +void evrpc_hook_add_meta(void *ctx, const char *key, + const void *data, size_t data_size); + +/** retrieves meta data previously associated + * + * evrpc_hook_find_meta() can be used to retrieve meta data associated to a + * request by a previous hook. + * @param ctx the context provided to the hook call + * @param key a NUL-terminated c-string + * @param data pointer to a data pointer that will contain the retrieved data + * @param data_size pointer to the size of the data + * @return 0 on success or -1 on failure + */ +EVENT2_EXPORT_SYMBOL +int evrpc_hook_find_meta(void *ctx, const char *key, + void **data, size_t *data_size); + +/** + * returns the connection object associated with the request + * + * @param ctx the context provided to the hook call + * @return a pointer to the evhttp_connection object or NULL if an error + * occurred + */ +EVENT2_EXPORT_SYMBOL +struct evhttp_connection *evrpc_hook_get_connection(void *ctx); + +/** + Function for sending a generic RPC request. + + Do not call this function directly, use EVRPC_MAKE_REQUEST() instead. + + @see EVRPC_MAKE_REQUEST() + */ +EVENT2_EXPORT_SYMBOL +int evrpc_send_request_generic(struct evrpc_pool *pool, + void *request, void *reply, + void (*cb)(struct evrpc_status *, void *, void *, void *), + void *cb_arg, + const char *rpcname, + void (*req_marshal)(struct evbuffer *, void *), + void (*rpl_clear)(void *), + int (*rpl_unmarshal)(void *, struct evbuffer *)); + +/** + Function for registering a generic RPC with the RPC base. + + Do not call this function directly, use EVRPC_REGISTER() instead. + + @see EVRPC_REGISTER() + */ +EVENT2_EXPORT_SYMBOL +int evrpc_register_generic(struct evrpc_base *base, const char *name, + void (*callback)(struct evrpc_req_generic *, void *), void *cbarg, + void *(*req_new)(void *), void *req_new_arg, void (*req_free)(void *), + int (*req_unmarshal)(void *, struct evbuffer *), + void *(*rpl_new)(void *), void *rpl_new_arg, void (*rpl_free)(void *), + int (*rpl_complete)(void *), + void (*rpl_marshal)(struct evbuffer *, void *)); + +/** accessors for obscure and undocumented functionality */ +EVENT2_EXPORT_SYMBOL +struct evrpc_pool* evrpc_request_get_pool(struct evrpc_request_wrapper *ctx); +EVENT2_EXPORT_SYMBOL +void evrpc_request_set_pool(struct evrpc_request_wrapper *ctx, + struct evrpc_pool *pool); +EVENT2_EXPORT_SYMBOL +void evrpc_request_set_cb(struct evrpc_request_wrapper *ctx, + void (*cb)(struct evrpc_status*, void *request, void *reply, void *arg), + void *cb_arg); + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_RPC_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/include/event2/rpc_compat.h b/bsnes/thrift/libevent/include/event2/rpc_compat.h new file mode 100644 index 00000000..8d8334d2 --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/rpc_compat.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2006-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_RPC_COMPAT_H_INCLUDED_ +#define EVENT2_RPC_COMPAT_H_INCLUDED_ + +/** @file event2/rpc_compat.h + + Deprecated versions of the functions in rpc.h: provided only for + backwards compatibility. + + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** backwards compatible accessors that work only with gcc */ +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) + +#undef EVTAG_ASSIGN +#undef EVTAG_GET +#undef EVTAG_ADD + +#define EVTAG_ASSIGN(msg, member, args...) \ + (*(msg)->base->member##_assign)(msg, ## args) +#define EVTAG_GET(msg, member, args...) \ + (*(msg)->base->member##_get)(msg, ## args) +#define EVTAG_ADD(msg, member, args...) \ + (*(msg)->base->member##_add)(msg, ## args) +#endif +#define EVTAG_LEN(msg, member) ((msg)->member##_length) + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_EVENT_COMPAT_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/include/event2/rpc_struct.h b/bsnes/thrift/libevent/include/event2/rpc_struct.h new file mode 100644 index 00000000..f3cb460a --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/rpc_struct.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2006-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_RPC_STRUCT_H_INCLUDED_ +#define EVENT2_RPC_STRUCT_H_INCLUDED_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** @file event2/rpc_struct.h + + Structures used by rpc.h. Using these structures directly may harm + forward compatibility: be careful! + + */ + +/* Fix so that people don't have to run with */ +#ifndef TAILQ_ENTRY +#define EVENT_DEFINED_TQENTRY_ +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} +#endif /* !TAILQ_ENTRY */ + +/** + * provides information about the completed RPC request. + */ +struct evrpc_status { +#define EVRPC_STATUS_ERR_NONE 0 +#define EVRPC_STATUS_ERR_TIMEOUT 1 +#define EVRPC_STATUS_ERR_BADPAYLOAD 2 +#define EVRPC_STATUS_ERR_UNSTARTED 3 +#define EVRPC_STATUS_ERR_HOOKABORTED 4 + int error; + + /* for looking at headers or other information */ + struct evhttp_request *http_req; +}; + +/* the structure below needs to be synchronized with evrpc_req_generic */ + +/* Encapsulates a request */ +struct evrpc { + TAILQ_ENTRY(evrpc) next; + + /* the URI at which the request handler lives */ + const char* uri; + + /* creates a new request structure */ + void *(*request_new)(void *); + void *request_new_arg; + + /* frees the request structure */ + void (*request_free)(void *); + + /* unmarshals the buffer into the proper request structure */ + int (*request_unmarshal)(void *, struct evbuffer *); + + /* creates a new reply structure */ + void *(*reply_new)(void *); + void *reply_new_arg; + + /* frees the reply structure */ + void (*reply_free)(void *); + + /* verifies that the reply is valid */ + int (*reply_complete)(void *); + + /* marshals the reply into a buffer */ + void (*reply_marshal)(struct evbuffer*, void *); + + /* the callback invoked for each received rpc */ + void (*cb)(struct evrpc_req_generic *, void *); + void *cb_arg; + + /* reference for further configuration */ + struct evrpc_base *base; +}; + +#ifdef EVENT_DEFINED_TQENTRY_ +#undef TAILQ_ENTRY +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_RPC_STRUCT_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/include/event2/tag.h b/bsnes/thrift/libevent/include/event2/tag.h new file mode 100644 index 00000000..2f73bfc0 --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/tag.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_TAG_H_INCLUDED_ +#define EVENT2_TAG_H_INCLUDED_ + +/** @file event2/tag.h + + Helper functions for reading and writing tagged data onto buffers. + + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif + +/* For int types. */ +#include + +struct evbuffer; + +/* + * Marshaling tagged data - We assume that all tags are inserted in their + * numeric order - so that unknown tags will always be higher than the + * known ones - and we can just ignore the end of an event buffer. + */ + +EVENT2_EXPORT_SYMBOL +void evtag_init(void); + +/** + Unmarshals the header and returns the length of the payload + + @param evbuf the buffer from which to unmarshal data + @param ptag a pointer in which the tag id is being stored + @returns -1 on failure or the number of bytes in the remaining payload. +*/ +EVENT2_EXPORT_SYMBOL +int evtag_unmarshal_header(struct evbuffer *evbuf, ev_uint32_t *ptag); + +EVENT2_EXPORT_SYMBOL +void evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag, const void *data, + ev_uint32_t len); +EVENT2_EXPORT_SYMBOL +void evtag_marshal_buffer(struct evbuffer *evbuf, ev_uint32_t tag, + struct evbuffer *data); + +/** + Encode an integer and store it in an evbuffer. + + We encode integers by nybbles; the first nibble contains the number + of significant nibbles - 1; this allows us to encode up to 64-bit + integers. This function is byte-order independent. + + @param evbuf evbuffer to store the encoded number + @param number a 32-bit integer + */ +EVENT2_EXPORT_SYMBOL +void evtag_encode_int(struct evbuffer *evbuf, ev_uint32_t number); +EVENT2_EXPORT_SYMBOL +void evtag_encode_int64(struct evbuffer *evbuf, ev_uint64_t number); + +EVENT2_EXPORT_SYMBOL +void evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, + ev_uint32_t integer); +EVENT2_EXPORT_SYMBOL +void evtag_marshal_int64(struct evbuffer *evbuf, ev_uint32_t tag, + ev_uint64_t integer); + +EVENT2_EXPORT_SYMBOL +void evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag, + const char *string); + +EVENT2_EXPORT_SYMBOL +void evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag, + struct timeval *tv); + +EVENT2_EXPORT_SYMBOL +int evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag, + struct evbuffer *dst); +EVENT2_EXPORT_SYMBOL +int evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag); +EVENT2_EXPORT_SYMBOL +int evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength); +EVENT2_EXPORT_SYMBOL +int evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength); +EVENT2_EXPORT_SYMBOL +int evtag_consume(struct evbuffer *evbuf); + +EVENT2_EXPORT_SYMBOL +int evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag, + ev_uint32_t *pinteger); +EVENT2_EXPORT_SYMBOL +int evtag_unmarshal_int64(struct evbuffer *evbuf, ev_uint32_t need_tag, + ev_uint64_t *pinteger); + +EVENT2_EXPORT_SYMBOL +int evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag, + void *data, size_t len); + +EVENT2_EXPORT_SYMBOL +int evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag, + char **pstring); + +EVENT2_EXPORT_SYMBOL +int evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag, + struct timeval *ptv); + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_TAG_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/include/event2/tag_compat.h b/bsnes/thrift/libevent/include/event2/tag_compat.h new file mode 100644 index 00000000..a276c0d3 --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/tag_compat.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_TAG_COMPAT_H_INCLUDED_ +#define EVENT2_TAG_COMPAT_H_INCLUDED_ + +/** @file event2/tag_compat.h + + Obsolete/deprecated functions from tag.h; provided only for backwards + compatibility. + */ + +/** + @name Misnamed functions + + @deprecated These macros are deprecated because their names don't follow + Libevent's naming conventions. Use evtag_encode_int and + evtag_encode_int64 instead. + + @{ +*/ +#define encode_int(evbuf, number) evtag_encode_int((evbuf), (number)) +#define encode_int64(evbuf, number) evtag_encode_int64((evbuf), (number)) +/**@}*/ + +#endif /* EVENT2_TAG_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/include/event2/thread.h b/bsnes/thrift/libevent/include/event2/thread.h new file mode 100644 index 00000000..b5199863 --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/thread.h @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2008-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_THREAD_H_INCLUDED_ +#define EVENT2_THREAD_H_INCLUDED_ + +/** @file event2/thread.h + + Functions for multi-threaded applications using Libevent. + + When using a multi-threaded application in which multiple threads + add and delete events from a single event base, Libevent needs to + lock its data structures. + + Like the memory-management function hooks, all of the threading functions + _must_ be set up before an event_base is created if you want the base to + use them. + + Most programs will either be using Windows threads or Posix threads. You + can configure Libevent to use one of these event_use_windows_threads() or + event_use_pthreads() respectively. If you're using another threading + library, you'll need to configure threading functions manually using + evthread_set_lock_callbacks() and evthread_set_condition_callbacks(). + + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + @name Flags passed to lock functions + + @{ +*/ +/** A flag passed to a locking callback when the lock was allocated as a + * read-write lock, and we want to acquire or release the lock for writing. */ +#define EVTHREAD_WRITE 0x04 +/** A flag passed to a locking callback when the lock was allocated as a + * read-write lock, and we want to acquire or release the lock for reading. */ +#define EVTHREAD_READ 0x08 +/** A flag passed to a locking callback when we don't want to block waiting + * for the lock; if we can't get the lock immediately, we will instead + * return nonzero from the locking callback. */ +#define EVTHREAD_TRY 0x10 +/**@}*/ + +#if !defined(EVENT__DISABLE_THREAD_SUPPORT) || defined(EVENT_IN_DOXYGEN_) + +#define EVTHREAD_LOCK_API_VERSION 1 + +/** + @name Types of locks + + @{*/ +/** A recursive lock is one that can be acquired multiple times at once by the + * same thread. No other process can allocate the lock until the thread that + * has been holding it has unlocked it as many times as it locked it. */ +#define EVTHREAD_LOCKTYPE_RECURSIVE 1 +/* A read-write lock is one that allows multiple simultaneous readers, but + * where any one writer excludes all other writers and readers. */ +#define EVTHREAD_LOCKTYPE_READWRITE 2 +/**@}*/ + +/** This structure describes the interface a threading library uses for + * locking. It's used to tell evthread_set_lock_callbacks() how to use + * locking on this platform. + */ +struct evthread_lock_callbacks { + /** The current version of the locking API. Set this to + * EVTHREAD_LOCK_API_VERSION */ + int lock_api_version; + /** Which kinds of locks does this version of the locking API + * support? A bitfield of EVTHREAD_LOCKTYPE_RECURSIVE and + * EVTHREAD_LOCKTYPE_READWRITE. + * + * (Note that RECURSIVE locks are currently mandatory, and + * READWRITE locks are not currently used.) + **/ + unsigned supported_locktypes; + /** Function to allocate and initialize new lock of type 'locktype'. + * Returns NULL on failure. */ + void *(*alloc)(unsigned locktype); + /** Funtion to release all storage held in 'lock', which was created + * with type 'locktype'. */ + void (*free)(void *lock, unsigned locktype); + /** Acquire an already-allocated lock at 'lock' with mode 'mode'. + * Returns 0 on success, and nonzero on failure. */ + int (*lock)(unsigned mode, void *lock); + /** Release a lock at 'lock' using mode 'mode'. Returns 0 on success, + * and nonzero on failure. */ + int (*unlock)(unsigned mode, void *lock); +}; + +/** Sets a group of functions that Libevent should use for locking. + * For full information on the required callback API, see the + * documentation for the individual members of evthread_lock_callbacks. + * + * Note that if you're using Windows or the Pthreads threading library, you + * probably shouldn't call this function; instead, use + * evthread_use_windows_threads() or evthread_use_posix_threads() if you can. + */ +EVENT2_EXPORT_SYMBOL +int evthread_set_lock_callbacks(const struct evthread_lock_callbacks *); + +#define EVTHREAD_CONDITION_API_VERSION 1 + +struct timeval; + +/** This structure describes the interface a threading library uses for + * condition variables. It's used to tell evthread_set_condition_callbacks + * how to use locking on this platform. + */ +struct evthread_condition_callbacks { + /** The current version of the conditions API. Set this to + * EVTHREAD_CONDITION_API_VERSION */ + int condition_api_version; + /** Function to allocate and initialize a new condition variable. + * Returns the condition variable on success, and NULL on failure. + * The 'condtype' argument will be 0 with this API version. + */ + void *(*alloc_condition)(unsigned condtype); + /** Function to free a condition variable. */ + void (*free_condition)(void *cond); + /** Function to signal a condition variable. If 'broadcast' is 1, all + * threads waiting on 'cond' should be woken; otherwise, only on one + * thread is worken. Should return 0 on success, -1 on failure. + * This function will only be called while holding the associated + * lock for the condition. + */ + int (*signal_condition)(void *cond, int broadcast); + /** Function to wait for a condition variable. The lock 'lock' + * will be held when this function is called; should be released + * while waiting for the condition to be come signalled, and + * should be held again when this function returns. + * If timeout is provided, it is interval of seconds to wait for + * the event to become signalled; if it is NULL, the function + * should wait indefinitely. + * + * The function should return -1 on error; 0 if the condition + * was signalled, or 1 on a timeout. */ + int (*wait_condition)(void *cond, void *lock, + const struct timeval *timeout); +}; + +/** Sets a group of functions that Libevent should use for condition variables. + * For full information on the required callback API, see the + * documentation for the individual members of evthread_condition_callbacks. + * + * Note that if you're using Windows or the Pthreads threading library, you + * probably shouldn't call this function; instead, use + * evthread_use_windows_threads() or evthread_use_pthreads() if you can. + */ +EVENT2_EXPORT_SYMBOL +int evthread_set_condition_callbacks( + const struct evthread_condition_callbacks *); + +/** + Sets the function for determining the thread id. + + @param base the event base for which to set the id function + @param id_fn the identify function Libevent should invoke to + determine the identity of a thread. +*/ +EVENT2_EXPORT_SYMBOL +void evthread_set_id_callback( + unsigned long (*id_fn)(void)); + +#if (defined(_WIN32) && !defined(EVENT__DISABLE_THREAD_SUPPORT)) || defined(EVENT_IN_DOXYGEN_) +/** Sets up Libevent for use with Windows builtin locking and thread ID + functions. Unavailable if Libevent is not built for Windows. + + @return 0 on success, -1 on failure. */ +EVENT2_EXPORT_SYMBOL +int evthread_use_windows_threads(void); +/** + Defined if Libevent was built with support for evthread_use_windows_threads() +*/ +#define EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED 1 +#endif + +#if defined(EVENT__HAVE_PTHREADS) || defined(EVENT_IN_DOXYGEN_) +/** Sets up Libevent for use with Pthreads locking and thread ID functions. + Unavailable if Libevent is not build for use with pthreads. Requires + libraries to link against Libevent_pthreads as well as Libevent. + + @return 0 on success, -1 on failure. */ +EVENT2_EXPORT_SYMBOL +int evthread_use_pthreads(void); +/** Defined if Libevent was built with support for evthread_use_pthreads() */ +#define EVTHREAD_USE_PTHREADS_IMPLEMENTED 1 + +#endif + +/** Enable debugging wrappers around the current lock callbacks. If Libevent + * makes one of several common locking errors, exit with an assertion failure. + * + * If you're going to call this function, you must do so before any locks are + * allocated. + **/ +EVENT2_EXPORT_SYMBOL +void evthread_enable_lock_debugging(void); + +/* Old (misspelled) version: This is deprecated; use + * evthread_enable_log_debugging instead. */ +EVENT2_EXPORT_SYMBOL +void evthread_enable_lock_debuging(void); + +#endif /* EVENT__DISABLE_THREAD_SUPPORT */ + +struct event_base; +/** Make sure it's safe to tell an event base to wake up from another thread + or a signal handler. + + You shouldn't need to call this by hand; configuring the base with thread + support should be necessary and sufficient. + + @return 0 on success, -1 on failure. + */ +EVENT2_EXPORT_SYMBOL +int evthread_make_base_notifiable(struct event_base *base); + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT2_THREAD_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/include/event2/util.h b/bsnes/thrift/libevent/include/event2/util.h new file mode 100644 index 00000000..02aa7ba9 --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/util.h @@ -0,0 +1,888 @@ +/* + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_UTIL_H_INCLUDED_ +#define EVENT2_UTIL_H_INCLUDED_ + +/** @file event2/util.h + + Common convenience functions for cross-platform portability and + related socket manipulations. + + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#ifdef EVENT__HAVE_SYS_TIME_H +#include +#endif +#ifdef EVENT__HAVE_STDINT_H +#include +#elif defined(EVENT__HAVE_INTTYPES_H) +#include +#endif +#ifdef EVENT__HAVE_SYS_TYPES_H +#include +#endif +#ifdef EVENT__HAVE_STDDEF_H +#include +#endif +#ifdef _MSC_VER +#include +#endif +#include +#ifdef EVENT__HAVE_NETDB_H +#include +#endif + +#ifdef _WIN32 +#include +#ifdef EVENT__HAVE_GETADDRINFO +/* for EAI_* definitions. */ +#include +#endif +#else +#ifdef EVENT__HAVE_ERRNO_H +#include +#endif +#include +#endif + +#include + +/* Some openbsd autoconf versions get the name of this macro wrong. */ +#if defined(EVENT__SIZEOF_VOID__) && !defined(EVENT__SIZEOF_VOID_P) +#define EVENT__SIZEOF_VOID_P EVENT__SIZEOF_VOID__ +#endif + +/** + * @name Standard integer types. + * + * Integer type definitions for types that are supposed to be defined in the + * C99-specified stdint.h. Shamefully, some platforms do not include + * stdint.h, so we need to replace it. (If you are on a platform like this, + * your C headers are now over 10 years out of date. You should bug them to + * do something about this.) + * + * We define: + * + *
+ *
ev_uint64_t, ev_uint32_t, ev_uint16_t, ev_uint8_t
+ *
unsigned integer types of exactly 64, 32, 16, and 8 bits + * respectively.
+ *
ev_int64_t, ev_int32_t, ev_int16_t, ev_int8_t
+ *
signed integer types of exactly 64, 32, 16, and 8 bits + * respectively.
+ *
ev_uintptr_t, ev_intptr_t
+ *
unsigned/signed integers large enough + * to hold a pointer without loss of bits.
+ *
ev_ssize_t
+ *
A signed type of the same size as size_t
+ *
ev_off_t
+ *
A signed type typically used to represent offsets within a + * (potentially large) file
+ * + * @{ + */ +#ifdef EVENT__HAVE_UINT64_T +#define ev_uint64_t uint64_t +#define ev_int64_t int64_t +#elif defined(_WIN32) +#define ev_uint64_t unsigned __int64 +#define ev_int64_t signed __int64 +#elif EVENT__SIZEOF_LONG_LONG == 8 +#define ev_uint64_t unsigned long long +#define ev_int64_t long long +#elif EVENT__SIZEOF_LONG == 8 +#define ev_uint64_t unsigned long +#define ev_int64_t long +#elif defined(EVENT_IN_DOXYGEN_) +#define ev_uint64_t ... +#define ev_int64_t ... +#else +#error "No way to define ev_uint64_t" +#endif + +#ifdef EVENT__HAVE_UINT32_T +#define ev_uint32_t uint32_t +#define ev_int32_t int32_t +#elif defined(_WIN32) +#define ev_uint32_t unsigned int +#define ev_int32_t signed int +#elif EVENT__SIZEOF_LONG == 4 +#define ev_uint32_t unsigned long +#define ev_int32_t signed long +#elif EVENT__SIZEOF_INT == 4 +#define ev_uint32_t unsigned int +#define ev_int32_t signed int +#elif defined(EVENT_IN_DOXYGEN_) +#define ev_uint32_t ... +#define ev_int32_t ... +#else +#error "No way to define ev_uint32_t" +#endif + +#ifdef EVENT__HAVE_UINT16_T +#define ev_uint16_t uint16_t +#define ev_int16_t int16_t +#elif defined(_WIN32) +#define ev_uint16_t unsigned short +#define ev_int16_t signed short +#elif EVENT__SIZEOF_INT == 2 +#define ev_uint16_t unsigned int +#define ev_int16_t signed int +#elif EVENT__SIZEOF_SHORT == 2 +#define ev_uint16_t unsigned short +#define ev_int16_t signed short +#elif defined(EVENT_IN_DOXYGEN_) +#define ev_uint16_t ... +#define ev_int16_t ... +#else +#error "No way to define ev_uint16_t" +#endif + +#ifdef EVENT__HAVE_UINT8_T +#define ev_uint8_t uint8_t +#define ev_int8_t int8_t +#elif defined(EVENT_IN_DOXYGEN_) +#define ev_uint8_t ... +#define ev_int8_t ... +#else +#define ev_uint8_t unsigned char +#define ev_int8_t signed char +#endif + +#ifdef EVENT__HAVE_UINTPTR_T +#define ev_uintptr_t uintptr_t +#define ev_intptr_t intptr_t +#elif EVENT__SIZEOF_VOID_P <= 4 +#define ev_uintptr_t ev_uint32_t +#define ev_intptr_t ev_int32_t +#elif EVENT__SIZEOF_VOID_P <= 8 +#define ev_uintptr_t ev_uint64_t +#define ev_intptr_t ev_int64_t +#elif defined(EVENT_IN_DOXYGEN_) +#define ev_uintptr_t ... +#define ev_intptr_t ... +#else +#error "No way to define ev_uintptr_t" +#endif + +#ifdef EVENT__ssize_t +#define ev_ssize_t EVENT__ssize_t +#else +#define ev_ssize_t ssize_t +#endif + +/* Note that we define ev_off_t based on the compile-time size of off_t that + * we used to build Libevent, and not based on the current size of off_t. + * (For example, we don't define ev_off_t to off_t.). We do this because + * some systems let you build your software with different off_t sizes + * at runtime, and so putting in any dependency on off_t would risk API + * mismatch. + */ +#ifdef _WIN32 +#define ev_off_t ev_int64_t +#elif EVENT__SIZEOF_OFF_T == 8 +#define ev_off_t ev_int64_t +#elif EVENT__SIZEOF_OFF_T == 4 +#define ev_off_t ev_int32_t +#elif defined(EVENT_IN_DOXYGEN_) +#define ev_off_t ... +#else +#define ev_off_t off_t +#endif +/**@}*/ + +/* Limits for integer types. + + We're making two assumptions here: + - The compiler does constant folding properly. + - The platform does signed arithmetic in two's complement. +*/ + +/** + @name Limits for integer types + + These macros hold the largest or smallest values possible for the + ev_[u]int*_t types. + + @{ +*/ +#ifndef EVENT__HAVE_STDINT_H +#define EV_UINT64_MAX ((((ev_uint64_t)0xffffffffUL) << 32) | 0xffffffffUL) +#define EV_INT64_MAX ((((ev_int64_t) 0x7fffffffL) << 32) | 0xffffffffL) +#define EV_INT64_MIN ((-EV_INT64_MAX) - 1) +#define EV_UINT32_MAX ((ev_uint32_t)0xffffffffUL) +#define EV_INT32_MAX ((ev_int32_t) 0x7fffffffL) +#define EV_INT32_MIN ((-EV_INT32_MAX) - 1) +#define EV_UINT16_MAX ((ev_uint16_t)0xffffUL) +#define EV_INT16_MAX ((ev_int16_t) 0x7fffL) +#define EV_INT16_MIN ((-EV_INT16_MAX) - 1) +#define EV_UINT8_MAX 255 +#define EV_INT8_MAX 127 +#define EV_INT8_MIN ((-EV_INT8_MAX) - 1) +#else +#define EV_UINT64_MAX UINT64_MAX +#define EV_INT64_MAX INT64_MAX +#define EV_INT64_MIN INT64_MIN +#define EV_UINT32_MAX UINT32_MAX +#define EV_INT32_MAX INT32_MAX +#define EV_INT32_MIN INT32_MIN +#define EV_UINT16_MAX UINT16_MAX +#define EV_INT16_MIN INT16_MIN +#define EV_INT16_MAX INT16_MAX +#define EV_UINT8_MAX UINT8_MAX +#define EV_INT8_MAX INT8_MAX +#define EV_INT8_MIN INT8_MIN +/** @} */ +#endif + + +/** + @name Limits for SIZE_T and SSIZE_T + + @{ +*/ +#if EVENT__SIZEOF_SIZE_T == 8 +#define EV_SIZE_MAX EV_UINT64_MAX +#define EV_SSIZE_MAX EV_INT64_MAX +#elif EVENT__SIZEOF_SIZE_T == 4 +#define EV_SIZE_MAX EV_UINT32_MAX +#define EV_SSIZE_MAX EV_INT32_MAX +#elif defined(EVENT_IN_DOXYGEN_) +#define EV_SIZE_MAX ... +#define EV_SSIZE_MAX ... +#else +#error "No way to define SIZE_MAX" +#endif + +#define EV_SSIZE_MIN ((-EV_SSIZE_MAX) - 1) +/**@}*/ + +#ifdef _WIN32 +#define ev_socklen_t int +#elif defined(EVENT__socklen_t) +#define ev_socklen_t EVENT__socklen_t +#else +#define ev_socklen_t socklen_t +#endif + +#ifdef EVENT__HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY +#if !defined(EVENT__HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY) \ + && !defined(ss_family) +#define ss_family __ss_family +#endif +#endif + +/** + * A type wide enough to hold the output of "socket()" or "accept()". On + * Windows, this is an intptr_t; elsewhere, it is an int. */ +#ifdef _WIN32 +#define evutil_socket_t intptr_t +#else +#define evutil_socket_t int +#endif + +/** + * Structure to hold information about a monotonic timer + * + * Use this with evutil_configure_monotonic_time() and + * evutil_gettime_monotonic(). + * + * This is an opaque structure; you can allocate one using + * evutil_monotonic_timer_new(). + * + * @see evutil_monotonic_timer_new(), evutil_monotonic_timer_free(), + * evutil_configure_monotonic_time(), evutil_gettime_monotonic() + */ +struct evutil_monotonic_timer +#ifdef EVENT_IN_DOXYGEN_ +{/*Empty body so that doxygen will generate documentation here.*/} +#endif +; + +#define EV_MONOT_PRECISE 1 +#define EV_MONOT_FALLBACK 2 + +/** Format a date string using RFC 1123 format (used in HTTP). + * If `tm` is NULL, current system's time will be used. + * The number of characters written will be returned. + * One should check if the return value is smaller than `datelen` to check if + * the result is truncated or not. + */ +EVENT2_EXPORT_SYMBOL int +evutil_date_rfc1123(char *date, const size_t datelen, const struct tm *tm); + +/** Allocate a new struct evutil_monotonic_timer for use with the + * evutil_configure_monotonic_time() and evutil_gettime_monotonic() + * functions. You must configure the timer with + * evutil_configure_monotonic_time() before using it. + */ +EVENT2_EXPORT_SYMBOL +struct evutil_monotonic_timer * evutil_monotonic_timer_new(void); + +/** Free a struct evutil_monotonic_timer that was allocated using + * evutil_monotonic_timer_new(). + */ +EVENT2_EXPORT_SYMBOL +void evutil_monotonic_timer_free(struct evutil_monotonic_timer *timer); + +/** Set up a struct evutil_monotonic_timer; flags can include + * EV_MONOT_PRECISE and EV_MONOT_FALLBACK. + */ +EVENT2_EXPORT_SYMBOL +int evutil_configure_monotonic_time(struct evutil_monotonic_timer *timer, + int flags); + +/** Query the current monotonic time from a struct evutil_monotonic_timer + * previously configured with evutil_configure_monotonic_time(). Monotonic + * time is guaranteed never to run in reverse, but is not necessarily epoch- + * based, or relative to any other definite point. Use it to make reliable + * measurements of elapsed time between events even when the system time + * may be changed. + * + * It is not safe to use this funtion on the same timer from multiple + * threads. + */ +EVENT2_EXPORT_SYMBOL +int evutil_gettime_monotonic(struct evutil_monotonic_timer *timer, + struct timeval *tp); + +/** Create two new sockets that are connected to each other. + + On Unix, this simply calls socketpair(). On Windows, it uses the + loopback network interface on 127.0.0.1, and only + AF_INET,SOCK_STREAM are supported. + + (This may fail on some Windows hosts where firewall software has cleverly + decided to keep 127.0.0.1 from talking to itself.) + + Parameters and return values are as for socketpair() +*/ +EVENT2_EXPORT_SYMBOL +int evutil_socketpair(int d, int type, int protocol, evutil_socket_t sv[2]); +/** Do platform-specific operations as needed to make a socket nonblocking. + + @param sock The socket to make nonblocking + @return 0 on success, -1 on failure + */ +EVENT2_EXPORT_SYMBOL +int evutil_make_socket_nonblocking(evutil_socket_t sock); + +/** Do platform-specific operations to make a listener socket reusable. + + Specifically, we want to make sure that another program will be able + to bind this address right after we've closed the listener. + + This differs from Windows's interpretation of "reusable", which + allows multiple listeners to bind the same address at the same time. + + @param sock The socket to make reusable + @return 0 on success, -1 on failure + */ +EVENT2_EXPORT_SYMBOL +int evutil_make_listen_socket_reuseable(evutil_socket_t sock); + +/** Do platform-specific operations to make a listener port reusable. + + Specifically, we want to make sure that multiple programs which also + set the same socket option will be able to bind, listen at the same time. + + This is a feature available only to Linux 3.9+ + + @param sock The socket to make reusable + @return 0 on success, -1 on failure + */ +EVENT2_EXPORT_SYMBOL +int evutil_make_listen_socket_reuseable_port(evutil_socket_t sock); + +/** Set ipv6 only bind socket option to make listener work only in ipv6 sockets. + + According to RFC3493 and most Linux distributions, default value for the + sockets is to work in IPv4-mapped mode. In IPv4-mapped mode, it is not possible + to bind same port from different IPv4 and IPv6 handlers. + + @param sock The socket to make in ipv6only working mode + @return 0 on success, -1 on failure + */ +EVENT2_EXPORT_SYMBOL +int evutil_make_listen_socket_ipv6only(evutil_socket_t sock); + +/** Do platform-specific operations as needed to close a socket upon a + successful execution of one of the exec*() functions. + + @param sock The socket to be closed + @return 0 on success, -1 on failure + */ +EVENT2_EXPORT_SYMBOL +int evutil_make_socket_closeonexec(evutil_socket_t sock); + +/** Do the platform-specific call needed to close a socket returned from + socket() or accept(). + + @param sock The socket to be closed + @return 0 on success (whether the operation is supported or not), + -1 on failure + */ +EVENT2_EXPORT_SYMBOL +int evutil_closesocket(evutil_socket_t sock); +#define EVUTIL_CLOSESOCKET(s) evutil_closesocket(s) + +/** Do platform-specific operations, if possible, to make a tcp listener + * socket defer accept()s until there is data to read. + * + * Not all platforms support this. You don't want to do this for every + * listener socket: only the ones that implement a protocol where the + * client transmits before the server needs to respond. + * + * @param sock The listening socket to to make deferred + * @return 0 on success (whether the operation is supported or not), + * -1 on failure +*/ +EVENT2_EXPORT_SYMBOL +int evutil_make_tcp_listen_socket_deferred(evutil_socket_t sock); + +#ifdef _WIN32 +/** Return the most recent socket error. Not idempotent on all platforms. */ +#define EVUTIL_SOCKET_ERROR() WSAGetLastError() +/** Replace the most recent socket error with errcode */ +#define EVUTIL_SET_SOCKET_ERROR(errcode) \ + do { WSASetLastError(errcode); } while (0) +/** Return the most recent socket error to occur on sock. */ +EVENT2_EXPORT_SYMBOL +int evutil_socket_geterror(evutil_socket_t sock); +/** Convert a socket error to a string. */ +EVENT2_EXPORT_SYMBOL +const char *evutil_socket_error_to_string(int errcode); +#define EVUTIL_INVALID_SOCKET INVALID_SOCKET +#elif defined(EVENT_IN_DOXYGEN_) +/** + @name Socket error functions + + These functions are needed for making programs compatible between + Windows and Unix-like platforms. + + You see, Winsock handles socket errors differently from the rest of + the world. Elsewhere, a socket error is like any other error and is + stored in errno. But winsock functions require you to retrieve the + error with a special function, and don't let you use strerror for + the error codes. And handling EWOULDBLOCK is ... different. + + @{ +*/ +/** Return the most recent socket error. Not idempotent on all platforms. */ +#define EVUTIL_SOCKET_ERROR() ... +/** Replace the most recent socket error with errcode */ +#define EVUTIL_SET_SOCKET_ERROR(errcode) ... +/** Return the most recent socket error to occur on sock. */ +#define evutil_socket_geterror(sock) ... +/** Convert a socket error to a string. */ +#define evutil_socket_error_to_string(errcode) ... +#define EVUTIL_INVALID_SOCKET -1 +/**@}*/ +#else /** !EVENT_IN_DOXYGEN_ && !_WIN32 */ +#define EVUTIL_SOCKET_ERROR() (errno) +#define EVUTIL_SET_SOCKET_ERROR(errcode) \ + do { errno = (errcode); } while (0) +#define evutil_socket_geterror(sock) (errno) +#define evutil_socket_error_to_string(errcode) (strerror(errcode)) +#define EVUTIL_INVALID_SOCKET -1 +#endif /** !_WIN32 */ + + +/** + * @name Manipulation macros for struct timeval. + * + * We define replacements + * for timeradd, timersub, timerclear, timercmp, and timerisset. + * + * @{ + */ +#ifdef EVENT__HAVE_TIMERADD +#define evutil_timeradd(tvp, uvp, vvp) timeradd((tvp), (uvp), (vvp)) +#define evutil_timersub(tvp, uvp, vvp) timersub((tvp), (uvp), (vvp)) +#else +#define evutil_timeradd(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ + if ((vvp)->tv_usec >= 1000000) { \ + (vvp)->tv_sec++; \ + (vvp)->tv_usec -= 1000000; \ + } \ + } while (0) +#define evutil_timersub(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ + if ((vvp)->tv_usec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_usec += 1000000; \ + } \ + } while (0) +#endif /* !EVENT__HAVE_TIMERADD */ + +#ifdef EVENT__HAVE_TIMERCLEAR +#define evutil_timerclear(tvp) timerclear(tvp) +#else +#define evutil_timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 +#endif +/**@}*/ + +/** Return true iff the tvp is related to uvp according to the relational + * operator cmp. Recognized values for cmp are ==, <=, <, >=, and >. */ +#define evutil_timercmp(tvp, uvp, cmp) \ + (((tvp)->tv_sec == (uvp)->tv_sec) ? \ + ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ + ((tvp)->tv_sec cmp (uvp)->tv_sec)) + +#ifdef EVENT__HAVE_TIMERISSET +#define evutil_timerisset(tvp) timerisset(tvp) +#else +#define evutil_timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) +#endif + +/** Replacement for offsetof on platforms that don't define it. */ +#ifdef offsetof +#define evutil_offsetof(type, field) offsetof(type, field) +#else +#define evutil_offsetof(type, field) ((off_t)(&((type *)0)->field)) +#endif + +/* big-int related functions */ +/** Parse a 64-bit value from a string. Arguments are as for strtol. */ +EVENT2_EXPORT_SYMBOL +ev_int64_t evutil_strtoll(const char *s, char **endptr, int base); + +/** Replacement for gettimeofday on platforms that lack it. */ +#ifdef EVENT__HAVE_GETTIMEOFDAY +#define evutil_gettimeofday(tv, tz) gettimeofday((tv), (tz)) +#else +struct timezone; +EVENT2_EXPORT_SYMBOL +int evutil_gettimeofday(struct timeval *tv, struct timezone *tz); +#endif + +/** Replacement for snprintf to get consistent behavior on platforms for + which the return value of snprintf does not conform to C99. + */ +EVENT2_EXPORT_SYMBOL +int evutil_snprintf(char *buf, size_t buflen, const char *format, ...) +#ifdef __GNUC__ + __attribute__((format(printf, 3, 4))) +#endif +; +/** Replacement for vsnprintf to get consistent behavior on platforms for + which the return value of snprintf does not conform to C99. + */ +EVENT2_EXPORT_SYMBOL +int evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap) +#ifdef __GNUC__ + __attribute__((format(printf, 3, 0))) +#endif +; + +/** Replacement for inet_ntop for platforms which lack it. */ +EVENT2_EXPORT_SYMBOL +const char *evutil_inet_ntop(int af, const void *src, char *dst, size_t len); +/** Variation of inet_pton that also parses IPv6 scopes. Public for + unit tests. No reason to call this directly. + */ +EVENT2_EXPORT_SYMBOL +int evutil_inet_pton_scope(int af, const char *src, void *dst, + unsigned *indexp); +/** Replacement for inet_pton for platforms which lack it. */ +EVENT2_EXPORT_SYMBOL +int evutil_inet_pton(int af, const char *src, void *dst); +struct sockaddr; + +/** Parse an IPv4 or IPv6 address, with optional port, from a string. + + Recognized formats are: + - [IPv6Address]:port + - [IPv6Address] + - IPv6Address + - IPv4Address:port + - IPv4Address + + If no port is specified, the port in the output is set to 0. + + @param str The string to parse. + @param out A struct sockaddr to hold the result. This should probably be + a struct sockaddr_storage. + @param outlen A pointer to the number of bytes that that 'out' can safely + hold. Set to the number of bytes used in 'out' on success. + @return -1 if the address is not well-formed, if the port is out of range, + or if out is not large enough to hold the result. Otherwise returns + 0 on success. +*/ +EVENT2_EXPORT_SYMBOL +int evutil_parse_sockaddr_port(const char *str, struct sockaddr *out, int *outlen); + +/** Compare two sockaddrs; return 0 if they are equal, or less than 0 if sa1 + * preceeds sa2, or greater than 0 if sa1 follows sa2. If include_port is + * true, consider the port as well as the address. Only implemented for + * AF_INET and AF_INET6 addresses. The ordering is not guaranteed to remain + * the same between Libevent versions. */ +EVENT2_EXPORT_SYMBOL +int evutil_sockaddr_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2, + int include_port); + +/** As strcasecmp, but always compares the characters in locale-independent + ASCII. That's useful if you're handling data in ASCII-based protocols. + */ +EVENT2_EXPORT_SYMBOL +int evutil_ascii_strcasecmp(const char *str1, const char *str2); +/** As strncasecmp, but always compares the characters in locale-independent + ASCII. That's useful if you're handling data in ASCII-based protocols. + */ +EVENT2_EXPORT_SYMBOL +int evutil_ascii_strncasecmp(const char *str1, const char *str2, size_t n); + +/* Here we define evutil_addrinfo to the native addrinfo type, or redefine it + * if this system has no getaddrinfo(). */ +#ifdef EVENT__HAVE_STRUCT_ADDRINFO +#define evutil_addrinfo addrinfo +#else +/** A definition of struct addrinfo for systems that lack it. + + (This is just an alias for struct addrinfo if the system defines + struct addrinfo.) +*/ +struct evutil_addrinfo { + int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */ + int ai_family; /* PF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + size_t ai_addrlen; /* length of ai_addr */ + char *ai_canonname; /* canonical name for nodename */ + struct sockaddr *ai_addr; /* binary address */ + struct evutil_addrinfo *ai_next; /* next structure in linked list */ +}; +#endif +/** @name evutil_getaddrinfo() error codes + + These values are possible error codes for evutil_getaddrinfo() and + related functions. + + @{ +*/ +#if defined(EAI_ADDRFAMILY) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_EAI_ADDRFAMILY EAI_ADDRFAMILY +#else +#define EVUTIL_EAI_ADDRFAMILY -901 +#endif +#if defined(EAI_AGAIN) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_EAI_AGAIN EAI_AGAIN +#else +#define EVUTIL_EAI_AGAIN -902 +#endif +#if defined(EAI_BADFLAGS) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_EAI_BADFLAGS EAI_BADFLAGS +#else +#define EVUTIL_EAI_BADFLAGS -903 +#endif +#if defined(EAI_FAIL) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_EAI_FAIL EAI_FAIL +#else +#define EVUTIL_EAI_FAIL -904 +#endif +#if defined(EAI_FAMILY) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_EAI_FAMILY EAI_FAMILY +#else +#define EVUTIL_EAI_FAMILY -905 +#endif +#if defined(EAI_MEMORY) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_EAI_MEMORY EAI_MEMORY +#else +#define EVUTIL_EAI_MEMORY -906 +#endif +/* This test is a bit complicated, since some MS SDKs decide to + * remove NODATA or redefine it to be the same as NONAME, in a + * fun interpretation of RFC 2553 and RFC 3493. */ +#if defined(EAI_NODATA) && defined(EVENT__HAVE_GETADDRINFO) && (!defined(EAI_NONAME) || EAI_NODATA != EAI_NONAME) +#define EVUTIL_EAI_NODATA EAI_NODATA +#else +#define EVUTIL_EAI_NODATA -907 +#endif +#if defined(EAI_NONAME) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_EAI_NONAME EAI_NONAME +#else +#define EVUTIL_EAI_NONAME -908 +#endif +#if defined(EAI_SERVICE) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_EAI_SERVICE EAI_SERVICE +#else +#define EVUTIL_EAI_SERVICE -909 +#endif +#if defined(EAI_SOCKTYPE) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_EAI_SOCKTYPE EAI_SOCKTYPE +#else +#define EVUTIL_EAI_SOCKTYPE -910 +#endif +#if defined(EAI_SYSTEM) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_EAI_SYSTEM EAI_SYSTEM +#else +#define EVUTIL_EAI_SYSTEM -911 +#endif + +#define EVUTIL_EAI_CANCEL -90001 + +#if defined(AI_PASSIVE) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_AI_PASSIVE AI_PASSIVE +#else +#define EVUTIL_AI_PASSIVE 0x1000 +#endif +#if defined(AI_CANONNAME) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_AI_CANONNAME AI_CANONNAME +#else +#define EVUTIL_AI_CANONNAME 0x2000 +#endif +#if defined(AI_NUMERICHOST) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_AI_NUMERICHOST AI_NUMERICHOST +#else +#define EVUTIL_AI_NUMERICHOST 0x4000 +#endif +#if defined(AI_NUMERICSERV) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_AI_NUMERICSERV AI_NUMERICSERV +#else +#define EVUTIL_AI_NUMERICSERV 0x8000 +#endif +#if defined(AI_V4MAPPED) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_AI_V4MAPPED AI_V4MAPPED +#else +#define EVUTIL_AI_V4MAPPED 0x10000 +#endif +#if defined(AI_ALL) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_AI_ALL AI_ALL +#else +#define EVUTIL_AI_ALL 0x20000 +#endif +#if defined(AI_ADDRCONFIG) && defined(EVENT__HAVE_GETADDRINFO) +#define EVUTIL_AI_ADDRCONFIG AI_ADDRCONFIG +#else +#define EVUTIL_AI_ADDRCONFIG 0x40000 +#endif +/**@}*/ + +struct evutil_addrinfo; +/** + * This function clones getaddrinfo for systems that don't have it. For full + * details, see RFC 3493, section 6.1. + * + * Limitations: + * - When the system has no getaddrinfo, we fall back to gethostbyname_r or + * gethostbyname, with their attendant issues. + * - The AI_V4MAPPED and AI_ALL flags are not currently implemented. + * + * For a nonblocking variant, see evdns_getaddrinfo. + */ +EVENT2_EXPORT_SYMBOL +int evutil_getaddrinfo(const char *nodename, const char *servname, + const struct evutil_addrinfo *hints_in, struct evutil_addrinfo **res); + +/** Release storage allocated by evutil_getaddrinfo or evdns_getaddrinfo. */ +EVENT2_EXPORT_SYMBOL +void evutil_freeaddrinfo(struct evutil_addrinfo *ai); + +EVENT2_EXPORT_SYMBOL +const char *evutil_gai_strerror(int err); + +/** Generate n bytes of secure pseudorandom data, and store them in buf. + * + * Current versions of Libevent use an ARC4-based random number generator, + * seeded using the platform's entropy source (/dev/urandom on Unix-like + * systems; CryptGenRandom on Windows). This is not actually as secure as it + * should be: ARC4 is a pretty lousy cipher, and the current implementation + * provides only rudimentary prediction- and backtracking-resistance. Don't + * use this for serious cryptographic applications. + */ +EVENT2_EXPORT_SYMBOL +void evutil_secure_rng_get_bytes(void *buf, size_t n); + +/** + * Seed the secure random number generator if needed, and return 0 on + * success or -1 on failure. + * + * It is okay to call this function more than once; it will still return + * 0 if the RNG has been successfully seeded and -1 if it can't be + * seeded. + * + * Ordinarily you don't need to call this function from your own code; + * Libevent will seed the RNG itself the first time it needs good random + * numbers. You only need to call it if (a) you want to double-check + * that one of the seeding methods did succeed, or (b) you plan to drop + * the capability to seed (by chrooting, or dropping capabilities, or + * whatever), and you want to make sure that seeding happens before your + * program loses the ability to do it. + */ +EVENT2_EXPORT_SYMBOL +int evutil_secure_rng_init(void); + +/** + * Set a filename to use in place of /dev/urandom for seeding the secure + * PRNG. Return 0 on success, -1 on failure. + * + * Call this function BEFORE calling any other initialization or RNG + * functions. + * + * (This string will _NOT_ be copied internally. Do not free it while any + * user of the secure RNG might be running. Don't pass anything other than a + * real /dev/...random device file here, or you might lose security.) + * + * This API is unstable, and might change in a future libevent version. + */ +EVENT2_EXPORT_SYMBOL +int evutil_secure_rng_set_urandom_device_file(char *fname); + +#if !defined(EVENT__HAVE_ARC4RANDOM) || defined(EVENT__HAVE_ARC4RANDOM_ADDRANDOM) +/** Seed the random number generator with extra random bytes. + + You should almost never need to call this function; it should be + sufficient to invoke evutil_secure_rng_init(), or let Libevent take + care of calling evutil_secure_rng_init() on its own. + + If you call this function as a _replacement_ for the regular + entropy sources, then you need to be sure that your input + contains a fairly large amount of strong entropy. Doing so is + notoriously hard: most people who try get it wrong. Watch out! + + @param dat a buffer full of a strong source of random numbers + @param datlen the number of bytes to read from datlen + */ +EVENT2_EXPORT_SYMBOL +void evutil_secure_rng_add_bytes(const char *dat, size_t datlen); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT1_EVUTIL_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/include/event2/visibility.h b/bsnes/thrift/libevent/include/event2/visibility.h new file mode 100644 index 00000000..006bbf06 --- /dev/null +++ b/bsnes/thrift/libevent/include/event2/visibility.h @@ -0,0 +1,67 @@ +/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT2_VISIBILITY_H_INCLUDED_ +#define EVENT2_VISIBILITY_H_INCLUDED_ + +#include + +#if defined(event_shared_EXPORTS) || \ + defined(event_extra_shared_EXPORTS) || \ + defined(event_core_shared_EXPORTS) || \ + defined(event_pthreads_shared_EXPORTS) || \ + defined(event_openssl_shared_EXPORTS) + +# if defined (__SUNPRO_C) && (__SUNPRO_C >= 0x550) +# define EVENT2_EXPORT_SYMBOL __global +# elif defined __GNUC__ +# define EVENT2_EXPORT_SYMBOL __attribute__ ((visibility("default"))) +# elif defined(_MSC_VER) +# define EVENT2_EXPORT_SYMBOL __declspec(dllexport) +# else +# define EVENT2_EXPORT_SYMBOL /* unknown compiler */ +# endif + +#else /* event_*_EXPORTS */ + +# define EVENT2_EXPORT_SYMBOL + +#endif /* event_*_EXPORTS */ + +/** We need to dllimport event_debug_logging_mask_ into event_extra */ +#if defined(_MSC_VER) +# if defined(event_core_shared_EXPORTS) /** from core export */ +# define EVENT2_CORE_EXPORT_SYMBOL __declspec(dllexport) +# elif defined(event_extra_shared_EXPORTS) || /** from extra import */ \ + defined(EVENT_VISIBILITY_WANT_DLLIMPORT) +# define EVENT2_CORE_EXPORT_SYMBOL __declspec(dllimport) +# endif +#endif /* _MSC_VER */ +#if !defined(EVENT2_CORE_EXPORT_SYMBOL) +# define EVENT2_CORE_EXPORT_SYMBOL EVENT2_EXPORT_SYMBOL +#endif + +#endif /* EVENT2_VISIBILITY_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/include/evhttp.h b/bsnes/thrift/libevent/include/evhttp.h new file mode 100644 index 00000000..549bc9b1 --- /dev/null +++ b/bsnes/thrift/libevent/include/evhttp.h @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2007 Niels Provos + * Copyright 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT1_EVHTTP_H_INCLUDED_ +#define EVENT1_EVHTTP_H_INCLUDED_ + +/** @file evhttp.h + + An http implementation subsystem for Libevent. + + The header is deprecated in Libevent 2.0 and later; please + use instead. Depending on what functionality you + need, you may also want to include more of the other + headers. + */ + +#include +#include +#include +#include + +#endif /* EVENT1_EVHTTP_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/include/evrpc.h b/bsnes/thrift/libevent/include/evrpc.h new file mode 100644 index 00000000..7e986f7d --- /dev/null +++ b/bsnes/thrift/libevent/include/evrpc.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000-2007 Niels Provos + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT1_EVRPC_H_INCLUDED_ +#define EVENT1_EVRPC_H_INCLUDED_ + +/** @file evrpc.h + + An RPC system for Libevent. + + The header is deprecated in Libevent 2.0 and later; please + use instead. Depending on what functionality you + need, you may also want to include more of the other + headers. + */ + +#include +#include +#include +#include + +#endif /* EVENT1_EVRPC_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/include/evutil.h b/bsnes/thrift/libevent/include/evutil.h new file mode 100644 index 00000000..12c137d7 --- /dev/null +++ b/bsnes/thrift/libevent/include/evutil.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EVENT1_EVUTIL_H_INCLUDED_ +#define EVENT1_EVUTIL_H_INCLUDED_ + +/** @file evutil.h + + Utility and compatibility functions for Libevent. + + The header is deprecated in Libevent 2.0 and later; please + use instead. +*/ + +#include + +#endif /* EVENT1_EVUTIL_H_INCLUDED_ */ diff --git a/bsnes/thrift/libevent/lib/cmake/libevent/LibeventConfig.cmake b/bsnes/thrift/libevent/lib/cmake/libevent/LibeventConfig.cmake new file mode 100644 index 00000000..26fdc72a --- /dev/null +++ b/bsnes/thrift/libevent/lib/cmake/libevent/LibeventConfig.cmake @@ -0,0 +1,183 @@ +# - Config file for the Libevent package +# It defines the following variables +# LIBEVENT_FOUND - true if libevent and all required components found on the system +# LIBEVENT_xxx_FOUND - true if component xxx(see available components) found on the system +# LIBEVENT_VERSION - libevent version in format Major.Minor.Patch +# LIBEVENT_INCLUDE_DIRS - directories where libevent header is located. +# LIBEVENT_INCLUDE_DIR - same as DIRS +# LIBEVENT_LIBRARIES - libevent library to link against. +# LIBEVENT_LIBRARY - same as LIBRARIES +# +# These variables are deprecated, don't use them. +# LIBEVENT_STATIC_LIBRARIES - libraries to link against (archive/static) +# LIBEVENT_SHARED_LIBRARIES - libraries to link against (shared) +# +# When you try to locate the libevent libraries, you should specify which components you want to use. +# The following table lists all available components. If none is given, all imported targets will used. +# core - the core functons of libevent +# extra - extra functions, contains http, dns and rpc +# pthreads - multiple threads for libevent, not exists on Windows +# openssl - openssl support for libevent +# +# By default, the shared libraries of libevent will be found. To find the static ones instead, +# you must set the LIBEVENT_STATIC_LINK variable to TRUE before calling find_package(Libevent ...). +# If no component provided, all components will be used. +# example: +# set(LIBEVENT_STATIC_LINK TRUE) +# find_package(Libevent 2.2 REQUIRED COMPONENTS core) +# include_directories(${LIBEVENT_INCLUDE_DIRS}) # Can be omitted +# target_link_libraries(myapp ${LIBEVENT_LIBRARIES}) +# or target_link_libraries(myapp libevent::core) +# +# find_package() can handle dependencies automatically. For example, given the 'openssl' component, +# all dependencies (libevent_core, libssl, libcrypto and openssl include directories) will be found. + +set(CONFIG_FOR_INSTALL_TREE 1) + +set(LIBEVENT_VERSION 2.1.12) + +# IMPORTED targets from LibeventTargets.cmake +set(LIBEVENT_STATIC_LIBRARIES "core;extra") +set(LIBEVENT_SHARED_LIBRARIES "") + +# Default to the same type as libevent was built: +if(NOT DEFINED LIBEVENT_STATIC_LINK) + set(LIBEVENT_STATIC_LINK NOT OFF) +endif() + +set(CMAKE_FIND_LIBRARY_SUFFIXES_SAVE "${CMAKE_FIND_LIBRARY_SUFFIXES}") +if(${LIBEVENT_STATIC_LINK}) + set(_LIB_TYPE static) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX}) + set(_AVAILABLE_LIBS "${LIBEVENT_STATIC_LIBRARIES}") +else() + set(_LIB_TYPE shared) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_SHARED_LIBRARY_SUFFIX}) + set(_AVAILABLE_LIBS "${LIBEVENT_SHARED_LIBRARIES}") +endif() + +# Get the path of the current file. +get_filename_component(LIBEVENT_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_INSTALL_PREFIX "${LIBEVENT_CMAKE_DIR}/../../.." ABSOLUTE) + +macro(message_if_needed _flag _msg) + if (NOT ${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY) + message(${_flag} "${_msg}") + endif() +endmacro() + +macro(no_component_msg _comp) + if(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED_${_comp}) + set(pthreadlib) + if(NOT WIN32) + set(pthreadlib ", pthreads") + endif() + message(FATAL_ERROR "Your libevent library does not contain a ${_comp} component!\n" + "The valid components are core, extra${pthreadlib} and openssl.") + else() + message_if_needed(WARNING "Your libevent library does not contain a ${_comp} component!") + endif() +endmacro() + +set(_EVENT_COMPONENTS) +if(${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS) + list(REMOVE_DUPLICATES ${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS) + foreach(_comp ${${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS}) + list(FIND _AVAILABLE_LIBS ${_comp} _INDEX) + if(_INDEX GREATER -1) + list(APPEND _EVENT_COMPONENTS ${_comp}) + else() + no_component_msg(${_comp}) + endif() + endforeach() +else() + set(_EVENT_COMPONENTS ${_AVAILABLE_LIBS}) +endif() + +set(_POSSIBLE_PKG_NAMES) +list(APPEND _POSSIBLE_PKG_NAMES ${CMAKE_FIND_PACKAGE_NAME} LIBEVENT Libevent libevent) +list(REMOVE_DUPLICATES _POSSIBLE_PKG_NAMES) + +macro(set_case_insensitive_found _comp) + foreach(name ${_POSSIBLE_PKG_NAMES}) + if("${_comp}" STREQUAL "") + set(${name}_FOUND TRUE) + set(${name}_NOTFOUND FALSE) + else() + set(${name}_${_comp}_FOUND TRUE) + set(${name}_${_comp}_NOTFOUND FALSE) + endif() + endforeach() +endmacro() + +if(CONFIG_FOR_INSTALL_TREE) + ## Config for install tree ---------------------------------------- + # Find includes + unset(_event_h CACHE) + find_path(_event_h + NAMES event2/event.h + PATHS "${_INSTALL_PREFIX}/include" + NO_DEFAULT_PATH) + if(_event_h) + set(LIBEVENT_INCLUDE_DIRS "${_event_h}") + message_if_needed(STATUS "Found libevent include directory: ${_event_h}") + else() + message_if_needed(WARNING "Your libevent library does not contain header files!") + endif() + + # Find libraries + macro(find_event_lib _comp) + unset(_event_lib CACHE) + find_library(_event_lib + NAMES "event_${_comp}" + PATHS "${_INSTALL_PREFIX}/lib" + NO_DEFAULT_PATH) + if(_event_lib) + list(APPEND LIBEVENT_LIBRARIES "libevent::${_comp}") + set_case_insensitive_found(${_comp}) + message_if_needed(STATUS "Found libevent component: ${_event_lib}") + else() + no_component_msg(${_comp}) + endif() + endmacro() + + foreach(comp ${_EVENT_COMPONENTS}) + find_event_lib(${comp}) + endforeach() +else() + ## Config for build tree ---------------------------------------- + set(LIBEVENT_INCLUDE_DIRS "D:/git/blastem/thrift/libevent-2.1.12-stable/include;D:/git/blastem/thrift/libevent-2.1.12-stable/build/include") + foreach(_comp ${_EVENT_COMPONENTS}) + list(APPEND LIBEVENT_LIBRARIES "libevent::${_comp}") + set_case_insensitive_found(${_comp}) + endforeach() +endif() + +set(LIBEVENT_INCLUDE_DIR ${LIBEVENT_INCLUDE_DIRS}) +if(LIBEVENT_LIBRARIES) + set(LIBEVENT_LIBRARY ${LIBEVENT_LIBRARIES}) + if(CONFIG_FOR_INSTALL_TREE) + message_if_needed(STATUS "Found libevent ${LIBEVENT_VERSION} in ${_INSTALL_PREFIX}") + else() + message_if_needed(STATUS "Found libevent ${LIBEVENT_VERSION} in ${LIBEVENT_CMAKE_DIR}") + endif() + + # Avoid including targets more than one times + if(NOT TARGET event_core_${_LIB_TYPE}) + # Include the project Targets file, this contains definitions for IMPORTED targets. + include(${LIBEVENT_CMAKE_DIR}/LibeventTargets-${_LIB_TYPE}.cmake) + endif() +else() + if(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED) + message(FATAL_ERROR "Can not find any libraries for libevent.") + else() + message_if_needed(WARNING "Can not find any libraries for libevent.") + endif() +endif() + +set(CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_FIND_LIBRARY_SUFFIXES_SAVE}") +unset(_LIB_TYPE) +unset(_AVAILABLE_LIBS) +unset(_EVENT_COMPONENTS) +unset(_POSSIBLE_PKG_NAMES) +unset(_INSTALL_PREFIX) diff --git a/bsnes/thrift/libevent/lib/cmake/libevent/LibeventConfigVersion.cmake b/bsnes/thrift/libevent/lib/cmake/libevent/LibeventConfigVersion.cmake new file mode 100644 index 00000000..0e4084f9 --- /dev/null +++ b/bsnes/thrift/libevent/lib/cmake/libevent/LibeventConfigVersion.cmake @@ -0,0 +1,11 @@ +set(PACKAGE_VERSION "2.1.12") + +# Check whether the requested PACKAGE_FIND_VERSION is compatible +if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_EXACT TRUE) + endif() +endif() diff --git a/bsnes/thrift/libevent/lib/cmake/libevent/LibeventTargets-static-release.cmake b/bsnes/thrift/libevent/lib/cmake/libevent/LibeventTargets-static-release.cmake new file mode 100644 index 00000000..1fddfd66 --- /dev/null +++ b/bsnes/thrift/libevent/lib/cmake/libevent/LibeventTargets-static-release.cmake @@ -0,0 +1,29 @@ +#---------------------------------------------------------------- +# Generated CMake target import file for configuration "Release". +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Import target "libevent::core" for configuration "Release" +set_property(TARGET libevent::core APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) +set_target_properties(libevent::core PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C" + IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/event_core.lib" + ) + +list(APPEND _IMPORT_CHECK_TARGETS libevent::core ) +list(APPEND _IMPORT_CHECK_FILES_FOR_libevent::core "${_IMPORT_PREFIX}/lib/event_core.lib" ) + +# Import target "libevent::extra" for configuration "Release" +set_property(TARGET libevent::extra APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) +set_target_properties(libevent::extra PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C" + IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/event_extra.lib" + ) + +list(APPEND _IMPORT_CHECK_TARGETS libevent::extra ) +list(APPEND _IMPORT_CHECK_FILES_FOR_libevent::extra "${_IMPORT_PREFIX}/lib/event_extra.lib" ) + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) diff --git a/bsnes/thrift/libevent/lib/cmake/libevent/LibeventTargets-static.cmake b/bsnes/thrift/libevent/lib/cmake/libevent/LibeventTargets-static.cmake new file mode 100644 index 00000000..569e42af --- /dev/null +++ b/bsnes/thrift/libevent/lib/cmake/libevent/LibeventTargets-static.cmake @@ -0,0 +1,101 @@ +# Generated by CMake + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5) + message(FATAL_ERROR "CMake >= 2.6.0 required") +endif() +cmake_policy(PUSH) +cmake_policy(VERSION 2.6...3.18) +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Protect against multiple inclusion, which would fail when already imported targets are added once more. +set(_targetsDefined) +set(_targetsNotDefined) +set(_expectedTargets) +foreach(_expectedTarget libevent::core libevent::extra) + list(APPEND _expectedTargets ${_expectedTarget}) + if(NOT TARGET ${_expectedTarget}) + list(APPEND _targetsNotDefined ${_expectedTarget}) + endif() + if(TARGET ${_expectedTarget}) + list(APPEND _targetsDefined ${_expectedTarget}) + endif() +endforeach() +if("${_targetsDefined}" STREQUAL "${_expectedTargets}") + unset(_targetsDefined) + unset(_targetsNotDefined) + unset(_expectedTargets) + set(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() +if(NOT "${_targetsDefined}" STREQUAL "") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n") +endif() +unset(_targetsDefined) +unset(_targetsNotDefined) +unset(_expectedTargets) + + +# The installation prefix configured by this project. +set(_IMPORT_PREFIX "D:/git/smd_ida_tools2/Gensida/libevent") + +# Create imported target libevent::core +add_library(libevent::core STATIC IMPORTED) + +set_target_properties(libevent::core PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include" + INTERFACE_LINK_LIBRARIES "ws2_32;shell32;advapi32;iphlpapi" +) + +# Create imported target libevent::extra +add_library(libevent::extra STATIC IMPORTED) + +set_target_properties(libevent::extra PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include" + INTERFACE_LINK_LIBRARIES "ws2_32;shell32;advapi32;libevent::core" +) + +if(CMAKE_VERSION VERSION_LESS 2.8.12) + message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.") +endif() + +# Load information for each installed configuration. +get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +file(GLOB CONFIG_FILES "${_DIR}/LibeventTargets-static-*.cmake") +foreach(f ${CONFIG_FILES}) + include(${f}) +endforeach() + +# Cleanup temporary variables. +set(_IMPORT_PREFIX) + +# Loop over all imported files and verify that they actually exist +foreach(target ${_IMPORT_CHECK_TARGETS} ) + foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} ) + if(NOT EXISTS "${file}" ) + message(FATAL_ERROR "The imported target \"${target}\" references the file + \"${file}\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained + \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") + endif() + endforeach() + unset(_IMPORT_CHECK_FILES_FOR_${target}) +endforeach() +unset(_IMPORT_CHECK_TARGETS) + +# This file does not depend on other imported targets which have +# been exported from the same project but in a separate export set. + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) diff --git a/bsnes/thrift/libevent/lib/event_32.lib b/bsnes/thrift/libevent/lib/event_32.lib new file mode 100644 index 00000000..a95035a4 Binary files /dev/null and b/bsnes/thrift/libevent/lib/event_32.lib differ diff --git a/bsnes/thrift/libevent/lib/event_64.lib b/bsnes/thrift/libevent/lib/event_64.lib new file mode 100644 index 00000000..225b570f Binary files /dev/null and b/bsnes/thrift/libevent/lib/event_64.lib differ diff --git a/bsnes/thrift/libevent/lib/event_core_32.lib b/bsnes/thrift/libevent/lib/event_core_32.lib new file mode 100644 index 00000000..5f68c947 Binary files /dev/null and b/bsnes/thrift/libevent/lib/event_core_32.lib differ diff --git a/bsnes/thrift/libevent/lib/event_core_64.lib b/bsnes/thrift/libevent/lib/event_core_64.lib new file mode 100644 index 00000000..ab7a5385 Binary files /dev/null and b/bsnes/thrift/libevent/lib/event_core_64.lib differ diff --git a/bsnes/thrift/libevent/lib/event_extra_32.lib b/bsnes/thrift/libevent/lib/event_extra_32.lib new file mode 100644 index 00000000..a3bbda1d Binary files /dev/null and b/bsnes/thrift/libevent/lib/event_extra_32.lib differ diff --git a/bsnes/thrift/libevent/lib/event_extra_64.lib b/bsnes/thrift/libevent/lib/event_extra_64.lib new file mode 100644 index 00000000..3cbaec3e Binary files /dev/null and b/bsnes/thrift/libevent/lib/event_extra_64.lib differ diff --git a/bsnes/thrift/libevent/lib/pkgconfig/libevent.pc b/bsnes/thrift/libevent/lib/pkgconfig/libevent.pc new file mode 100644 index 00000000..9daedd3e --- /dev/null +++ b/bsnes/thrift/libevent/lib/pkgconfig/libevent.pc @@ -0,0 +1,16 @@ +#libevent pkg-config source file + +prefix=D:/git/smd_ida_tools2/Gensida/libevent +exec_prefix=D:/git/smd_ida_tools2/Gensida/libevent +libdir=D:/git/smd_ida_tools2/Gensida/libevent/lib +includedir=D:/git/smd_ida_tools2/Gensida/libevent/include + +Name: libevent +Description: libevent is an asynchronous notification event loop library +Version: 2.1.12 +Requires: +Conflicts: +Libs: -L${libdir} -levent +Libs.private: -Lws2_32 -Lshell32 -Ladvapi32 +Cflags: -I${includedir} + diff --git a/bsnes/thrift/libevent/lib/pkgconfig/libevent_core.pc b/bsnes/thrift/libevent/lib/pkgconfig/libevent_core.pc new file mode 100644 index 00000000..5797ec2e --- /dev/null +++ b/bsnes/thrift/libevent/lib/pkgconfig/libevent_core.pc @@ -0,0 +1,16 @@ +#libevent pkg-config source file + +prefix=D:/git/smd_ida_tools2/Gensida/libevent +exec_prefix=D:/git/smd_ida_tools2/Gensida/libevent +libdir=D:/git/smd_ida_tools2/Gensida/libevent/lib +includedir=D:/git/smd_ida_tools2/Gensida/libevent/include + +Name: libevent_core +Description: libevent_core +Version: 2.1.12 +Requires: +Conflicts: +Libs: -L${libdir} -levent_core +Libs.private: -Lws2_32 -Lshell32 -Ladvapi32 +Cflags: -I${includedir} + diff --git a/bsnes/thrift/libevent/lib/pkgconfig/libevent_extra.pc b/bsnes/thrift/libevent/lib/pkgconfig/libevent_extra.pc new file mode 100644 index 00000000..c0927669 --- /dev/null +++ b/bsnes/thrift/libevent/lib/pkgconfig/libevent_extra.pc @@ -0,0 +1,16 @@ +#libevent pkg-config source file + +prefix=D:/git/smd_ida_tools2/Gensida/libevent +exec_prefix=D:/git/smd_ida_tools2/Gensida/libevent +libdir=D:/git/smd_ida_tools2/Gensida/libevent/lib +includedir=D:/git/smd_ida_tools2/Gensida/libevent/include + +Name: libevent_extra +Description: libevent_extra +Version: 2.1.12 +Requires: +Conflicts: +Libs: -L${libdir} -levent_extra +Libs.private: -Lws2_32 -Lshell32 -Ladvapi32 +Cflags: -I${includedir} + diff --git a/bsnes/thrift/thrift/TApplicationException.h b/bsnes/thrift/thrift/TApplicationException.h new file mode 100644 index 00000000..cd1b3e7c --- /dev/null +++ b/bsnes/thrift/thrift/TApplicationException.h @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TAPPLICATIONEXCEPTION_H_ +#define _THRIFT_TAPPLICATIONEXCEPTION_H_ 1 + +#include + +namespace apache { +namespace thrift { + +namespace protocol { +class TProtocol; +} + +class TApplicationException : public TException { +public: + /** + * Error codes for the various types of exceptions. + */ + enum TApplicationExceptionType { + UNKNOWN = 0, + UNKNOWN_METHOD = 1, + INVALID_MESSAGE_TYPE = 2, + WRONG_METHOD_NAME = 3, + BAD_SEQUENCE_ID = 4, + MISSING_RESULT = 5, + INTERNAL_ERROR = 6, + PROTOCOL_ERROR = 7, + INVALID_TRANSFORM = 8, + INVALID_PROTOCOL = 9, + UNSUPPORTED_CLIENT_TYPE = 10 + }; + + TApplicationException() : TException(), type_(UNKNOWN) {} + + TApplicationException(TApplicationExceptionType type) : TException(), type_(type) {} + + TApplicationException(const std::string& message) : TException(message), type_(UNKNOWN) {} + + TApplicationException(TApplicationExceptionType type, const std::string& message) + : TException(message), type_(type) {} + + ~TApplicationException() noexcept override = default; + + /** + * Returns an error code that provides information about the type of error + * that has occurred. + * + * @return Error code + */ + TApplicationExceptionType getType() const { return type_; } + + const char* what() const noexcept override { + if (message_.empty()) { + switch (type_) { + case UNKNOWN: + return "TApplicationException: Unknown application exception"; + case UNKNOWN_METHOD: + return "TApplicationException: Unknown method"; + case INVALID_MESSAGE_TYPE: + return "TApplicationException: Invalid message type"; + case WRONG_METHOD_NAME: + return "TApplicationException: Wrong method name"; + case BAD_SEQUENCE_ID: + return "TApplicationException: Bad sequence identifier"; + case MISSING_RESULT: + return "TApplicationException: Missing result"; + case INTERNAL_ERROR: + return "TApplicationException: Internal error"; + case PROTOCOL_ERROR: + return "TApplicationException: Protocol error"; + case INVALID_TRANSFORM: + return "TApplicationException: Invalid transform"; + case INVALID_PROTOCOL: + return "TApplicationException: Invalid protocol"; + case UNSUPPORTED_CLIENT_TYPE: + return "TApplicationException: Unsupported client type"; + default: + return "TApplicationException: (Invalid exception type)"; + }; + } else { + return message_.c_str(); + } + } + + uint32_t read(protocol::TProtocol* iprot); + uint32_t write(protocol::TProtocol* oprot) const; + +protected: + /** + * Error code + */ + TApplicationExceptionType type_; +}; +} +} // apache::thrift + +#endif // #ifndef _THRIFT_TAPPLICATIONEXCEPTION_H_ diff --git a/bsnes/thrift/thrift/TBase.h b/bsnes/thrift/thrift/TBase.h new file mode 100644 index 00000000..e2e78e72 --- /dev/null +++ b/bsnes/thrift/thrift/TBase.h @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TBASE_H_ +#define _THRIFT_TBASE_H_ 1 + +#include +#include + +namespace apache { +namespace thrift { + +class TBase { +public: + virtual ~TBase() = default; + virtual uint32_t read(protocol::TProtocol* iprot) = 0; + virtual uint32_t write(protocol::TProtocol* oprot) const = 0; +}; +} +} // apache::thrift + +#endif // #ifndef _THRIFT_TBASE_H_ diff --git a/bsnes/thrift/thrift/TConfiguration.h b/bsnes/thrift/thrift/TConfiguration.h new file mode 100644 index 00000000..5bff440a --- /dev/null +++ b/bsnes/thrift/thrift/TConfiguration.h @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef THRIFT_TCONFIGURATION_H +#define THRIFT_TCONFIGURATION_H + +namespace apache { +namespace thrift { + +class TConfiguration +{ +public: + TConfiguration(int maxMessageSize = DEFAULT_MAX_MESSAGE_SIZE, + int maxFrameSize = DEFAULT_MAX_FRAME_SIZE, int recursionLimit = DEFAULT_RECURSION_DEPTH) + : maxMessageSize_(maxMessageSize), maxFrameSize_(maxFrameSize), recursionLimit_(recursionLimit) {} + + const static int DEFAULT_MAX_MESSAGE_SIZE = 100 * 1024 * 1024; + const static int DEFAULT_MAX_FRAME_SIZE = 16384000; // this value is used consistently across all Thrift libraries + const static int DEFAULT_RECURSION_DEPTH = 64; + + inline int getMaxMessageSize() { return maxMessageSize_; } + inline void setMaxMessageSize(int maxMessageSize) { maxMessageSize_ = maxMessageSize; } + inline int getMaxFrameSize() { return maxFrameSize_; } + inline void setMaxFrameSize(int maxFrameSize) { maxFrameSize_ = maxFrameSize; } + inline int getRecursionLimit() { return recursionLimit_; } + inline void setRecursionLimit(int recursionLimit) { recursionLimit_ = recursionLimit; } + +private: + int maxMessageSize_ = DEFAULT_MAX_MESSAGE_SIZE; + int maxFrameSize_ = DEFAULT_MAX_FRAME_SIZE; + int recursionLimit_ = DEFAULT_RECURSION_DEPTH; + + // TODO(someone_smart): add connection and i/o timeouts +}; +} +} // apache::thrift + +#endif /* THRIFT_TCONFIGURATION_H */ + diff --git a/bsnes/thrift/thrift/TDispatchProcessor.h b/bsnes/thrift/thrift/TDispatchProcessor.h new file mode 100644 index 00000000..ae522b2d --- /dev/null +++ b/bsnes/thrift/thrift/TDispatchProcessor.h @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#ifndef _THRIFT_TDISPATCHPROCESSOR_H_ +#define _THRIFT_TDISPATCHPROCESSOR_H_ 1 + +#include + +namespace apache { +namespace thrift { + +/** + * TDispatchProcessor is a helper class to parse the message header then call + * another function to dispatch based on the function name. + * + * Subclasses must implement dispatchCall() to dispatch on the function name. + */ +template +class TDispatchProcessorT : public TProcessor { +public: + bool process(std::shared_ptr in, + std::shared_ptr out, + void* connectionContext) override { + protocol::TProtocol* inRaw = in.get(); + protocol::TProtocol* outRaw = out.get(); + + // Try to dynamic cast to the template protocol type + auto* specificIn = dynamic_cast(inRaw); + auto* specificOut = dynamic_cast(outRaw); + if (specificIn && specificOut) { + return processFast(specificIn, specificOut, connectionContext); + } + + // Log the fact that we have to use the slow path + T_GENERIC_PROTOCOL(this, inRaw, specificIn); + T_GENERIC_PROTOCOL(this, outRaw, specificOut); + + std::string fname; + protocol::TMessageType mtype; + int32_t seqid; + inRaw->readMessageBegin(fname, mtype, seqid); + + // If this doesn't look like a valid call, log an error and return false so + // that the server will close the connection. + // + // (The old generated processor code used to try to skip a T_STRUCT and + // continue. However, that seems unsafe.) + if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) { + GlobalOutput.printf("received invalid message type %d from client", mtype); + return false; + } + + return this->dispatchCall(inRaw, outRaw, fname, seqid, connectionContext); + } + +protected: + bool processFast(Protocol_* in, Protocol_* out, void* connectionContext) { + std::string fname; + protocol::TMessageType mtype; + int32_t seqid; + in->readMessageBegin(fname, mtype, seqid); + + if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) { + GlobalOutput.printf("received invalid message type %d from client", mtype); + return false; + } + + return this->dispatchCallTemplated(in, out, fname, seqid, connectionContext); + } + + /** + * dispatchCall() methods must be implemented by subclasses + */ + virtual bool dispatchCall(apache::thrift::protocol::TProtocol* in, + apache::thrift::protocol::TProtocol* out, + const std::string& fname, + int32_t seqid, + void* callContext) = 0; + + virtual bool dispatchCallTemplated(Protocol_* in, + Protocol_* out, + const std::string& fname, + int32_t seqid, + void* callContext) = 0; +}; + +/** + * Non-templatized version of TDispatchProcessor, that doesn't bother trying to + * perform a dynamic_cast. + */ +class TDispatchProcessor : public TProcessor { +public: + bool process(std::shared_ptr in, + std::shared_ptr out, + void* connectionContext) override { + std::string fname; + protocol::TMessageType mtype; + int32_t seqid; + in->readMessageBegin(fname, mtype, seqid); + + if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) { + GlobalOutput.printf("received invalid message type %d from client", mtype); + return false; + } + + return dispatchCall(in.get(), out.get(), fname, seqid, connectionContext); + } + +protected: + virtual bool dispatchCall(apache::thrift::protocol::TProtocol* in, + apache::thrift::protocol::TProtocol* out, + const std::string& fname, + int32_t seqid, + void* callContext) = 0; +}; + +// Specialize TDispatchProcessorT for TProtocol and TDummyProtocol just to use +// the generic TDispatchProcessor. +template <> +class TDispatchProcessorT : public TDispatchProcessor {}; +template <> +class TDispatchProcessorT : public TDispatchProcessor {}; +} +} // apache::thrift + +#endif // _THRIFT_TDISPATCHPROCESSOR_H_ diff --git a/bsnes/thrift/thrift/TLogging.h b/bsnes/thrift/thrift/TLogging.h new file mode 100644 index 00000000..07ff030f --- /dev/null +++ b/bsnes/thrift/thrift/TLogging.h @@ -0,0 +1,195 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TLOGGING_H_ +#define _THRIFT_TLOGGING_H_ 1 + +#include + +/** + * Contains utility macros for debugging and logging. + * + */ + +#include + +#ifdef HAVE_STDINT_H +#include +#endif + +/** + * T_GLOBAL_DEBUGGING_LEVEL = 0: all debugging turned off, debug macros undefined + * T_GLOBAL_DEBUGGING_LEVEL = 1: all debugging turned on + */ +#define T_GLOBAL_DEBUGGING_LEVEL 0 + +/** + * T_GLOBAL_LOGGING_LEVEL = 0: all logging turned off, logging macros undefined + * T_GLOBAL_LOGGING_LEVEL = 1: all logging turned on + */ +#define T_GLOBAL_LOGGING_LEVEL 1 + +/** + * Standard wrapper around fprintf what will prefix the file name and line + * number to the line. Uses T_GLOBAL_DEBUGGING_LEVEL to control whether it is + * turned on or off. + * + * @param format_string + */ +#if T_GLOBAL_DEBUGGING_LEVEL > 0 +#define T_DEBUG(format_string, ...) \ + if (T_GLOBAL_DEBUGGING_LEVEL > 0) { \ + fprintf(stderr, "[%s,%d] " format_string " \n", __FILE__, __LINE__, ##__VA_ARGS__); \ + } +#else +#define T_DEBUG(format_string, ...) +#endif + +/** + * analogous to T_DEBUG but also prints the time + * + * @param string format_string input: printf style format string + */ +#if T_GLOBAL_DEBUGGING_LEVEL > 0 +#define T_DEBUG_T(format_string, ...) \ + { \ + if (T_GLOBAL_DEBUGGING_LEVEL > 0) { \ + time_t now; \ + char dbgtime[26]; \ + time(&now); \ + THRIFT_CTIME_R(&now, dbgtime); \ + dbgtime[24] = '\0'; \ + fprintf(stderr, \ + "[%s,%d] [%s] " format_string " \n", \ + __FILE__, \ + __LINE__, \ + dbgtime, \ + ##__VA_ARGS__); \ + } \ + } +#else +#define T_DEBUG_T(format_string, ...) +#endif + +/** + * analogous to T_DEBUG but uses input level to determine whether or not the string + * should be logged. + * + * @param int level: specified debug level + * @param string format_string input: format string + */ +#define T_DEBUG_L(level, format_string, ...) \ + if ((level) > 0) { \ + fprintf(stderr, "[%s,%d] " format_string " \n", __FILE__, __LINE__, ##__VA_ARGS__); \ + } + +/** + * Explicit error logging. Prints time, file name and line number + * + * @param string format_string input: printf style format string + */ +#define T_ERROR(format_string, ...) \ + { \ + time_t now; \ + char dbgtime[26]; \ + time(&now); \ + THRIFT_CTIME_R(&now, dbgtime); \ + dbgtime[24] = '\0'; \ + fprintf(stderr, \ + "[%s,%d] [%s] ERROR: " format_string " \n", \ + __FILE__, \ + __LINE__, \ + dbgtime, \ + ##__VA_ARGS__); \ + } + +/** + * Analogous to T_ERROR, additionally aborting the process. + * WARNING: macro calls abort(), ending program execution + * + * @param string format_string input: printf style format string + */ +#define T_ERROR_ABORT(format_string, ...) \ + { \ + time_t now; \ + char dbgtime[26]; \ + time(&now); \ + THRIFT_CTIME_R(&now, dbgtime); \ + dbgtime[24] = '\0'; \ + fprintf(stderr, \ + "[%s,%d] [%s] ERROR: Going to abort " format_string " \n", \ + __FILE__, \ + __LINE__, \ + dbgtime, \ + ##__VA_ARGS__); \ + exit(1); \ + } + +/** + * Log input message + * + * @param string format_string input: printf style format string + */ +#if T_GLOBAL_LOGGING_LEVEL > 0 +#define T_LOG_OPER(format_string, ...) \ + { \ + if (T_GLOBAL_LOGGING_LEVEL > 0) { \ + time_t now; \ + char dbgtime[26]; \ + time(&now); \ + THRIFT_CTIME_R(&now, dbgtime); \ + dbgtime[24] = '\0'; \ + fprintf(stderr, "[%s] " format_string " \n", dbgtime, ##__VA_ARGS__); \ + } \ + } +#else +#define T_LOG_OPER(format_string, ...) +#endif + +/** + * T_GLOBAL_DEBUG_VIRTUAL = 0 or unset: normal operation, + * virtual call debug messages disabled + * T_GLOBAL_DEBUG_VIRTUAL = 1: log a debug messages whenever an + * avoidable virtual call is made + * T_GLOBAL_DEBUG_VIRTUAL = 2: record detailed info that can be + * printed by calling + * apache::thrift::profile_print_info() + */ +#if T_GLOBAL_DEBUG_VIRTUAL > 1 +#define T_VIRTUAL_CALL() ::apache::thrift::profile_virtual_call(typeid(*this)) +#define T_GENERIC_PROTOCOL(template_class, generic_prot, specific_prot) \ + do { \ + if (!(specific_prot)) { \ + ::apache::thrift::profile_generic_protocol(typeid(*template_class), typeid(*generic_prot)); \ + } \ + } while (0) +#elif T_GLOBAL_DEBUG_VIRTUAL == 1 +#define T_VIRTUAL_CALL() fprintf(stderr, "[%s,%d] virtual call\n", __FILE__, __LINE__) +#define T_GENERIC_PROTOCOL(template_class, generic_prot, specific_prot) \ + do { \ + if (!(specific_prot)) { \ + fprintf(stderr, "[%s,%d] failed to cast to specific protocol type\n", __FILE__, __LINE__); \ + } \ + } while (0) +#else +#define T_VIRTUAL_CALL() +#define T_GENERIC_PROTOCOL(template_class, generic_prot, specific_prot) +#endif + +#endif // #ifndef _THRIFT_TLOGGING_H_ diff --git a/bsnes/thrift/thrift/TOutput.h b/bsnes/thrift/thrift/TOutput.h new file mode 100644 index 00000000..26c9a563 --- /dev/null +++ b/bsnes/thrift/thrift/TOutput.h @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_OUTPUT_H_ +#define _THRIFT_OUTPUT_H_ 1 + +#include + +namespace apache { +namespace thrift { + +class TOutput { +public: + TOutput(); + + inline void setOutputFunction(void (*function)(const char*)) { f_ = function; } + + inline void operator()(const char* message) { f_(message); } + + // It is important to have a const char* overload here instead of + // just the string version, otherwise errno could be corrupted + // if there is some problem allocating memory when constructing + // the string. + void perror(const char* message, int errno_copy); + inline void perror(const std::string& message, int errno_copy) { + perror(message.c_str(), errno_copy); + } + + void printf(const char* message, ...); + + static void errorTimeWrapper(const char* msg); + + /** Just like strerror_r but returns a C++ string object. */ + static std::string strerror_s(int errno_copy); + +private: + void (*f_)(const char*); +}; + +THRIFT_EXPORT extern TOutput GlobalOutput; +} +} // namespace apache::thrift + +#endif //_THRIFT_OUTPUT_H_ diff --git a/bsnes/thrift/thrift/TProcessor.h b/bsnes/thrift/thrift/TProcessor.h new file mode 100644 index 00000000..65bf3d4a --- /dev/null +++ b/bsnes/thrift/thrift/TProcessor.h @@ -0,0 +1,229 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TPROCESSOR_H_ +#define _THRIFT_TPROCESSOR_H_ 1 + +#include +#include + +namespace apache { +namespace thrift { + +/** + * Virtual interface class that can handle events from the processor. To + * use this you should subclass it and implement the methods that you care + * about. Your subclass can also store local data that you may care about, + * such as additional "arguments" to these methods (stored in the object + * instance's state). + */ +class TProcessorEventHandler { +public: + virtual ~TProcessorEventHandler() = default; + + /** + * Called before calling other callback methods. + * Expected to return some sort of context object. + * The return value is passed to all other callbacks + * for that function invocation. + */ + virtual void* getContext(const char* fn_name, void* serverContext) { + (void)fn_name; + (void)serverContext; + return nullptr; + } + + /** + * Expected to free resources associated with a context. + */ + virtual void freeContext(void* ctx, const char* fn_name) { + (void)ctx; + (void)fn_name; + } + + /** + * Called before reading arguments. + */ + virtual void preRead(void* ctx, const char* fn_name) { + (void)ctx; + (void)fn_name; + } + + /** + * Called between reading arguments and calling the handler. + */ + virtual void postRead(void* ctx, const char* fn_name, uint32_t bytes) { + (void)ctx; + (void)fn_name; + (void)bytes; + } + + /** + * Called between calling the handler and writing the response. + */ + virtual void preWrite(void* ctx, const char* fn_name) { + (void)ctx; + (void)fn_name; + } + + /** + * Called after writing the response. + */ + virtual void postWrite(void* ctx, const char* fn_name, uint32_t bytes) { + (void)ctx; + (void)fn_name; + (void)bytes; + } + + /** + * Called when an async function call completes successfully. + */ + virtual void asyncComplete(void* ctx, const char* fn_name) { + (void)ctx; + (void)fn_name; + } + + /** + * Called if the handler throws an undeclared exception. + */ + virtual void handlerError(void* ctx, const char* fn_name) { + (void)ctx; + (void)fn_name; + } + +protected: + TProcessorEventHandler() = default; +}; + +/** + * A helper class used by the generated code to free each context. + */ +class TProcessorContextFreer { +public: + TProcessorContextFreer(TProcessorEventHandler* handler, void* context, const char* method) + : handler_(handler), context_(context), method_(method) {} + ~TProcessorContextFreer() { + if (handler_ != nullptr) + handler_->freeContext(context_, method_); + } + void unregister() { handler_ = nullptr; } + +private: + apache::thrift::TProcessorEventHandler* handler_; + void* context_; + const char* method_; +}; + +/** + * A processor is a generic object that acts upon two streams of data, one + * an input and the other an output. The definition of this object is loose, + * though the typical case is for some sort of server that either generates + * responses to an input stream or forwards data from one pipe onto another. + * + */ +class TProcessor { +public: + virtual ~TProcessor() = default; + + virtual bool process(std::shared_ptr in, + std::shared_ptr out, + void* connectionContext) = 0; + + bool process(std::shared_ptr io, void* connectionContext) { + return process(io, io, connectionContext); + } + + std::shared_ptr getEventHandler() const { return eventHandler_; } + + void setEventHandler(std::shared_ptr eventHandler) { + eventHandler_ = eventHandler; + } + +protected: + TProcessor() = default; + + std::shared_ptr eventHandler_; +}; + +/** + * This is a helper class to allow std::shared_ptr to be used with handler + * pointers returned by the generated handler factories. + * + * The handler factory classes generated by the thrift compiler return raw + * pointers, and factory->releaseHandler() must be called when the handler is + * no longer needed. + * + * A ReleaseHandler object can be instantiated and passed as the second + * parameter to a shared_ptr, so that factory->releaseHandler() will be called + * when the object is no longer needed, instead of deleting the pointer. + */ +template +class ReleaseHandler { +public: + ReleaseHandler(const std::shared_ptr& handlerFactory) + : handlerFactory_(handlerFactory) {} + + void operator()(typename HandlerFactory_::Handler* handler) { + if (handler) { + handlerFactory_->releaseHandler(handler); + } + } + +private: + std::shared_ptr handlerFactory_; +}; + +struct TConnectionInfo { + // The input and output protocols + std::shared_ptr input; + std::shared_ptr output; + // The underlying transport used for the connection + // This is the transport that was returned by TServerTransport::accept(), + // and it may be different than the transport pointed to by the input and + // output protocols. + std::shared_ptr transport; +}; + +class TProcessorFactory { +public: + virtual ~TProcessorFactory() = default; + + /** + * Get the TProcessor to use for a particular connection. + * + * This method is always invoked in the same thread that the connection was + * accepted on. This generally means that this call does not need to be + * thread safe, as it will always be invoked from a single thread. + */ + virtual std::shared_ptr getProcessor(const TConnectionInfo& connInfo) = 0; +}; + +class TSingletonProcessorFactory : public TProcessorFactory { +public: + TSingletonProcessorFactory(std::shared_ptr processor) : processor_(processor) {} + + std::shared_ptr getProcessor(const TConnectionInfo&) override { return processor_; } + +private: + std::shared_ptr processor_; +}; +} +} // apache::thrift + +#endif // #ifndef _THRIFT_TPROCESSOR_H_ diff --git a/bsnes/thrift/thrift/TToString.h b/bsnes/thrift/thrift/TToString.h new file mode 100644 index 00000000..25780f9d --- /dev/null +++ b/bsnes/thrift/thrift/TToString.h @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TOSTRING_H_ +#define _THRIFT_TOSTRING_H_ 1 + +#include +#include +#include +#include +#include +#include +#include + +namespace apache { +namespace thrift { + +template +std::string to_string(const T& t) { + std::ostringstream o; + o << t; + return o.str(); +} + +// TODO: replace the computations below with std::numeric_limits::max_digits10 once C++11 +// is enabled. +inline std::string to_string(const float& t) { + std::ostringstream o; + o.precision(static_cast(std::ceil(static_cast(std::numeric_limits::digits * std::log10(2.0f) + 1)))); + o << t; + return o.str(); +} + +inline std::string to_string(const double& t) { + std::ostringstream o; + o.precision(static_cast(std::ceil(static_cast(std::numeric_limits::digits * std::log10(2.0f) + 1)))); + o << t; + return o.str(); +} + +inline std::string to_string(const long double& t) { + std::ostringstream o; + o.precision(static_cast(std::ceil(static_cast(std::numeric_limits::digits * std::log10(2.0f) + 1)))); + o << t; + return o.str(); +} + +template +std::string to_string(const std::map& m); + +template +std::string to_string(const std::set& s); + +template +std::string to_string(const std::vector& t); + +template +std::string to_string(const typename std::pair& v) { + std::ostringstream o; + o << to_string(v.first) << ": " << to_string(v.second); + return o.str(); +} + +template +std::string to_string(const T& beg, const T& end) { + std::ostringstream o; + for (T it = beg; it != end; ++it) { + if (it != beg) + o << ", "; + o << to_string(*it); + } + return o.str(); +} + +template +std::string to_string(const std::vector& t) { + std::ostringstream o; + o << "[" << to_string(t.begin(), t.end()) << "]"; + return o.str(); +} + +template +std::string to_string(const std::map& m) { + std::ostringstream o; + o << "{" << to_string(m.begin(), m.end()) << "}"; + return o.str(); +} + +template +std::string to_string(const std::set& s) { + std::ostringstream o; + o << "{" << to_string(s.begin(), s.end()) << "}"; + return o.str(); +} +} +} // apache::thrift + +#endif // _THRIFT_TOSTRING_H_ diff --git a/bsnes/thrift/thrift/Thrift.h b/bsnes/thrift/thrift/Thrift.h new file mode 100644 index 00000000..d5066ee7 --- /dev/null +++ b/bsnes/thrift/thrift/Thrift.h @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_THRIFT_H_ +#define _THRIFT_THRIFT_H_ 1 + +#include + +#include + +#include +#include + +#include +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_INTTYPES_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define THRIFT_UNUSED_VARIABLE(x) ((void)(x)) + +namespace apache { +namespace thrift { + +class TEnumIterator + : public std::iterator > { +public: + TEnumIterator(int n, int* enums, const char** names) + : ii_(0), n_(n), enums_(enums), names_(names) {} + + int operator++() { return ++ii_; } + + bool operator!=(const TEnumIterator& end) { + THRIFT_UNUSED_VARIABLE(end); + assert(end.n_ == -1); + return (ii_ != n_); + } + + std::pair operator*() const { return std::make_pair(enums_[ii_], names_[ii_]); } + +private: + int ii_; + const int n_; + int* enums_; + const char** names_; +}; + +class TException : public std::exception { +public: + TException() : message_() {} + + TException(const std::string& message) : message_(message) {} + + virtual ~TException() noexcept override = default; + + const char* what() const noexcept override { + if (message_.empty()) { + return "Default TException."; + } else { + return message_.c_str(); + } + } + +protected: + std::string message_; +}; + +class TDelayedException { +public: + template + static TDelayedException* delayException(const E& e); + virtual void throw_it() = 0; + virtual ~TDelayedException() = default; +}; + +template +class TExceptionWrapper : public TDelayedException { +public: + TExceptionWrapper(const E& e) : e_(e) {} + void throw_it() override { + E temp(e_); + delete this; + throw temp; + } + +private: + E e_; +}; + +template +TDelayedException* TDelayedException::delayException(const E& e) { + return new TExceptionWrapper(e); +} + +#if T_GLOBAL_DEBUG_VIRTUAL > 1 +void profile_virtual_call(const std::type_info& info); +void profile_generic_protocol(const std::type_info& template_type, const std::type_info& prot_type); +void profile_print_info(FILE* f); +void profile_print_info(); +void profile_write_pprof(FILE* gen_calls_f, FILE* virtual_calls_f); +#endif +} +} // apache::thrift + +#endif // #ifndef _THRIFT_THRIFT_H_ diff --git a/bsnes/thrift/thrift/async/TAsyncBufferProcessor.h b/bsnes/thrift/thrift/async/TAsyncBufferProcessor.h new file mode 100644 index 00000000..e3c3597c --- /dev/null +++ b/bsnes/thrift/thrift/async/TAsyncBufferProcessor.h @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TASYNC_BUFFER_PROCESSOR_H_ +#define _THRIFT_TASYNC_BUFFER_PROCESSOR_H_ 1 + +#include +#include + +namespace apache { +namespace thrift { +namespace async { + +class TAsyncBufferProcessor { +public: + // Process data in "in", putting the result in "out". + // Call _return(true) when done, or _return(false) to + // forcefully close the connection (if applicable). + // "in" and "out" should be TMemoryBuffer or similar, + // not a wrapper around a socket. + virtual void process(std::function _return, + std::shared_ptr ibuf, + std::shared_ptr obuf) = 0; + virtual ~TAsyncBufferProcessor() = default; +}; +} +} +} // apache::thrift::async + +#endif // #ifndef _THRIFT_TASYNC_BUFFER_PROCESSOR_H_ diff --git a/bsnes/thrift/thrift/async/TAsyncChannel.h b/bsnes/thrift/thrift/async/TAsyncChannel.h new file mode 100644 index 00000000..22cf3838 --- /dev/null +++ b/bsnes/thrift/thrift/async/TAsyncChannel.h @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_ASYNC_TASYNCCHANNEL_H_ +#define _THRIFT_ASYNC_TASYNCCHANNEL_H_ 1 + +#include +#include +#include + +namespace apache { +namespace thrift { +namespace transport { +class TMemoryBuffer; +} +} +} + +namespace apache { +namespace thrift { +namespace async { +using apache::thrift::transport::TMemoryBuffer; + +class TAsyncChannel { +public: + typedef std::function VoidCallback; + + virtual ~TAsyncChannel() = default; + + // is the channel in a good state? + virtual bool good() const = 0; + virtual bool error() const = 0; + virtual bool timedOut() const = 0; + + /** + * Send a message over the channel. + */ + virtual void sendMessage(const VoidCallback& cob, + apache::thrift::transport::TMemoryBuffer* message) = 0; + + /** + * Receive a message from the channel. + */ + virtual void recvMessage(const VoidCallback& cob, + apache::thrift::transport::TMemoryBuffer* message) = 0; + + /** + * Send a message over the channel and receive a response. + */ + virtual void sendAndRecvMessage(const VoidCallback& cob, + apache::thrift::transport::TMemoryBuffer* sendBuf, + apache::thrift::transport::TMemoryBuffer* recvBuf); +}; +} +} +} // apache::thrift::async + +#endif // #ifndef _THRIFT_ASYNC_TASYNCCHANNEL_H_ diff --git a/bsnes/thrift/thrift/async/TAsyncDispatchProcessor.h b/bsnes/thrift/thrift/async/TAsyncDispatchProcessor.h new file mode 100644 index 00000000..2a694ac5 --- /dev/null +++ b/bsnes/thrift/thrift/async/TAsyncDispatchProcessor.h @@ -0,0 +1,151 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#ifndef _THRIFT_ASYNC_TASYNCDISPATCHPROCESSOR_H_ +#define _THRIFT_ASYNC_TASYNCDISPATCHPROCESSOR_H_ 1 + +#include + +namespace apache { +namespace thrift { +namespace async { + +/** + * TAsyncDispatchProcessor is a helper class to parse the message header then + * call another function to dispatch based on the function name. + * + * Subclasses must implement dispatchCall() to dispatch on the function name. + */ +template +class TAsyncDispatchProcessorT : public TAsyncProcessor { +public: + void process(std::function _return, + std::shared_ptr in, + std::shared_ptr out) override { + protocol::TProtocol* inRaw = in.get(); + protocol::TProtocol* outRaw = out.get(); + + // Try to dynamic cast to the template protocol type + auto* specificIn = dynamic_cast(inRaw); + auto* specificOut = dynamic_cast(outRaw); + if (specificIn && specificOut) { + return processFast(_return, specificIn, specificOut); + } + + // Log the fact that we have to use the slow path + T_GENERIC_PROTOCOL(this, inRaw, specificIn); + T_GENERIC_PROTOCOL(this, outRaw, specificOut); + + std::string fname; + protocol::TMessageType mtype; + int32_t seqid; + inRaw->readMessageBegin(fname, mtype, seqid); + + // If this doesn't look like a valid call, log an error and return false so + // that the server will close the connection. + // + // (The old generated processor code used to try to skip a T_STRUCT and + // continue. However, that seems unsafe.) + if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) { + GlobalOutput.printf("received invalid message type %d from client", mtype); + _return(false); + return; + } + + return this->dispatchCall(_return, inRaw, outRaw, fname, seqid); + } + + void processFast(std::function _return, + Protocol_* in, + Protocol_* out) { + std::string fname; + protocol::TMessageType mtype; + int32_t seqid; + in->readMessageBegin(fname, mtype, seqid); + + if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) { + GlobalOutput.printf("received invalid message type %d from client", mtype); + _return(false); + return; + } + + return this->dispatchCallTemplated(_return, in, out, fname, seqid); + } + + virtual void dispatchCall(std::function _return, + apache::thrift::protocol::TProtocol* in, + apache::thrift::protocol::TProtocol* out, + const std::string& fname, + int32_t seqid) = 0; + + virtual void dispatchCallTemplated(std::function _return, + Protocol_* in, + Protocol_* out, + const std::string& fname, + int32_t seqid) = 0; +}; + +/** + * Non-templatized version of TAsyncDispatchProcessor, + * that doesn't bother trying to perform a dynamic_cast. + */ +class TAsyncDispatchProcessor : public TAsyncProcessor { +public: + void process(std::function _return, + std::shared_ptr in, + std::shared_ptr out) override { + protocol::TProtocol* inRaw = in.get(); + protocol::TProtocol* outRaw = out.get(); + + std::string fname; + protocol::TMessageType mtype; + int32_t seqid; + inRaw->readMessageBegin(fname, mtype, seqid); + + // If this doesn't look like a valid call, log an error and return false so + // that the server will close the connection. + // + // (The old generated processor code used to try to skip a T_STRUCT and + // continue. However, that seems unsafe.) + if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) { + GlobalOutput.printf("received invalid message type %d from client", mtype); + _return(false); + return; + } + + return dispatchCall(_return, inRaw, outRaw, fname, seqid); + } + + virtual void dispatchCall(std::function _return, + apache::thrift::protocol::TProtocol* in, + apache::thrift::protocol::TProtocol* out, + const std::string& fname, + int32_t seqid) = 0; +}; + +// Specialize TAsyncDispatchProcessorT for TProtocol and TDummyProtocol just to +// use the generic TDispatchProcessor. +template <> +class TAsyncDispatchProcessorT : public TAsyncDispatchProcessor {}; +template <> +class TAsyncDispatchProcessorT : public TAsyncDispatchProcessor {}; +} +} +} // apache::thrift::async + +#endif // _THRIFT_ASYNC_TASYNCDISPATCHPROCESSOR_H_ diff --git a/bsnes/thrift/thrift/async/TAsyncProcessor.h b/bsnes/thrift/thrift/async/TAsyncProcessor.h new file mode 100644 index 00000000..01923394 --- /dev/null +++ b/bsnes/thrift/thrift/async/TAsyncProcessor.h @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TASYNCPROCESSOR_H_ +#define _THRIFT_TASYNCPROCESSOR_H_ 1 + +#include +#include +#include + +namespace apache { +namespace thrift { +namespace async { + +/** + * Async version of a TProcessor. It is not expected to complete by the time + * the call to process returns. Instead, it calls a cob to signal completion. + */ + +class TAsyncProcessor { +public: + virtual ~TAsyncProcessor() = default; + + virtual void process(std::function _return, + std::shared_ptr in, + std::shared_ptr out) = 0; + + void process(std::function _return, + std::shared_ptr io) { + return process(_return, io, io); + } + + std::shared_ptr getEventHandler() const { return eventHandler_; } + + void setEventHandler(std::shared_ptr eventHandler) { + eventHandler_ = eventHandler; + } + +protected: + TAsyncProcessor() = default; + + std::shared_ptr eventHandler_; +}; + +class TAsyncProcessorFactory { +public: + virtual ~TAsyncProcessorFactory() = default; + + /** + * Get the TAsyncProcessor to use for a particular connection. + * + * This method is always invoked in the same thread that the connection was + * accepted on. This generally means that this call does not need to be + * thread safe, as it will always be invoked from a single thread. + */ + virtual std::shared_ptr getProcessor(const TConnectionInfo& connInfo) = 0; +}; +} +} +} // apache::thrift::async + +namespace apache { +namespace thrift { + using apache::thrift::async::TAsyncProcessor; +} +} + +#endif // #ifndef _THRIFT_TASYNCPROCESSOR_H_ diff --git a/bsnes/thrift/thrift/async/TAsyncProtocolProcessor.h b/bsnes/thrift/thrift/async/TAsyncProtocolProcessor.h new file mode 100644 index 00000000..ace72b6d --- /dev/null +++ b/bsnes/thrift/thrift/async/TAsyncProtocolProcessor.h @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TNAME_ME_H_ +#define _THRIFT_TNAME_ME_H_ 1 + +#include +#include +#include + +namespace apache { +namespace thrift { +namespace async { + +class TAsyncProtocolProcessor : public TAsyncBufferProcessor { +public: + TAsyncProtocolProcessor(std::shared_ptr underlying, + std::shared_ptr pfact) + : underlying_(underlying), pfact_(pfact) {} + + void process(std::function _return, + std::shared_ptr ibuf, + std::shared_ptr obuf) override; + + ~TAsyncProtocolProcessor() override = default; + +private: + static void finish(std::function _return, + std::shared_ptr oprot, + bool healthy); + + std::shared_ptr underlying_; + std::shared_ptr pfact_; +}; +} +} +} // apache::thrift::async + +#endif // #ifndef _THRIFT_TNAME_ME_H_ diff --git a/bsnes/thrift/thrift/async/TConcurrentClientSyncInfo.h b/bsnes/thrift/thrift/async/TConcurrentClientSyncInfo.h new file mode 100644 index 00000000..0bc5eb56 --- /dev/null +++ b/bsnes/thrift/thrift/async/TConcurrentClientSyncInfo.h @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#ifndef _THRIFT_TCONCURRENTCLIENTSYNCINFO_H_ +#define _THRIFT_TCONCURRENTCLIENTSYNCINFO_H_ 1 + +#include +#include +#include +#include +#include +#include +#include + +namespace apache { +namespace thrift { +namespace async { + +class TConcurrentClientSyncInfo; + +class TConcurrentSendSentry { +public: + explicit TConcurrentSendSentry(TConcurrentClientSyncInfo* sync); + ~TConcurrentSendSentry(); + + void commit(); + +private: + TConcurrentClientSyncInfo& sync_; + bool committed_; +}; + +class TConcurrentRecvSentry { +public: + TConcurrentRecvSentry(TConcurrentClientSyncInfo* sync, int32_t seqid); + ~TConcurrentRecvSentry(); + + void commit(); + +private: + TConcurrentClientSyncInfo& sync_; + int32_t seqid_; + bool committed_; +}; + +class TConcurrentClientSyncInfo { +private: // typedefs + typedef std::shared_ptr< ::apache::thrift::concurrency::Monitor> MonitorPtr; + typedef std::map MonitorMap; + +public: + TConcurrentClientSyncInfo(); + + int32_t generateSeqId(); + + bool getPending(std::string& fname, + ::apache::thrift::protocol::TMessageType& mtype, + int32_t& rseqid); /* requires readMutex_ */ + + void updatePending(const std::string& fname, + ::apache::thrift::protocol::TMessageType mtype, + int32_t rseqid); /* requires readMutex_ */ + + void waitForWork(int32_t seqid); /* requires readMutex_ */ + + ::apache::thrift::concurrency::Mutex& getReadMutex() { return readMutex_; } + ::apache::thrift::concurrency::Mutex& getWriteMutex() { return writeMutex_; } + +private: // constants + enum { MONITOR_CACHE_SIZE = 10 }; + +private: // functions + MonitorPtr newMonitor_( + const ::apache::thrift::concurrency::Guard& seqidGuard); /* requires seqidMutex_ */ + void deleteMonitor_(const ::apache::thrift::concurrency::Guard& seqidGuard, MonitorPtr& m); + /*noexcept*/ /* requires seqidMutex_ */ + void wakeupAnyone_( + const ::apache::thrift::concurrency::Guard& seqidGuard); /* requires seqidMutex_ */ + void markBad_(const ::apache::thrift::concurrency::Guard& seqidGuard); /* requires seqidMutex_ */ + void throwBadSeqId_(); + void throwDeadConnection_(); + +private: // data members + volatile bool stop_; + + ::apache::thrift::concurrency::Mutex seqidMutex_; + // begin seqidMutex_ protected members + int32_t nextseqid_; + MonitorMap seqidToMonitorMap_; + std::vector freeMonitors_; + // end seqidMutex_ protected members + + ::apache::thrift::concurrency::Mutex writeMutex_; + + ::apache::thrift::concurrency::Mutex readMutex_; + // begin readMutex_ protected members + bool recvPending_; + bool wakeupSomeone_; + int32_t seqidPending_; + std::string fnamePending_; + ::apache::thrift::protocol::TMessageType mtypePending_; + // end readMutex_ protected members + + friend class TConcurrentSendSentry; + friend class TConcurrentRecvSentry; +}; +} +} +} // apache::thrift::async + +#endif // _THRIFT_TCONCURRENTCLIENTSYNCINFO_H_ diff --git a/bsnes/thrift/thrift/async/TEvhttpClientChannel.h b/bsnes/thrift/thrift/async/TEvhttpClientChannel.h new file mode 100644 index 00000000..f7427266 --- /dev/null +++ b/bsnes/thrift/thrift/async/TEvhttpClientChannel.h @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TEVHTTP_CLIENT_CHANNEL_H_ +#define _THRIFT_TEVHTTP_CLIENT_CHANNEL_H_ 1 + +#include +#include +#include +#include +#include + +struct event_base; +struct evdns_base; +struct evhttp_connection; +struct evhttp_request; + +namespace apache { +namespace thrift { +namespace transport { +class TMemoryBuffer; +} +} +} + +namespace apache { +namespace thrift { +namespace async { + +class TEvhttpClientChannel : public TAsyncChannel { +public: + using TAsyncChannel::VoidCallback; + + TEvhttpClientChannel(const std::string& host, + const std::string& path, + const char* address, + int port, + struct event_base* eb, + struct evdns_base *dnsbase = nullptr); + ~TEvhttpClientChannel() override; + + void sendAndRecvMessage(const VoidCallback& cob, + apache::thrift::transport::TMemoryBuffer* sendBuf, + apache::thrift::transport::TMemoryBuffer* recvBuf) override; + + void sendMessage(const VoidCallback& cob, + apache::thrift::transport::TMemoryBuffer* message) override; + void recvMessage(const VoidCallback& cob, + apache::thrift::transport::TMemoryBuffer* message) override; + + void finish(struct evhttp_request* req); + + // XXX + bool good() const override { return true; } + bool error() const override { return false; } + bool timedOut() const override { return false; } + +private: + static void response(struct evhttp_request* req, void* arg); + + std::string host_; + std::string path_; + typedef std::pair Completion; + typedef std::queue CompletionQueue; + CompletionQueue completionQueue_; + struct evhttp_connection* conn_; +}; +} +} +} // apache::thrift::async + +#endif // #ifndef _THRIFT_TEVHTTP_CLIENT_CHANNEL_H_ diff --git a/bsnes/thrift/thrift/async/TEvhttpServer.h b/bsnes/thrift/thrift/async/TEvhttpServer.h new file mode 100644 index 00000000..c5bf3b6e --- /dev/null +++ b/bsnes/thrift/thrift/async/TEvhttpServer.h @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TEVHTTP_SERVER_H_ +#define _THRIFT_TEVHTTP_SERVER_H_ 1 + +#include + +struct event_base; +struct evhttp; +struct evhttp_request; + +namespace apache { +namespace thrift { +namespace async { + +class TAsyncBufferProcessor; + +class TEvhttpServer { +public: + /** + * Create a TEvhttpServer for use with an external evhttp instance. + * Must be manually installed with evhttp_set_cb, using + * TEvhttpServer::request as the callback and the + * address of the server as the extra arg. + * Do not call "serve" on this server. + */ + TEvhttpServer(std::shared_ptr processor); + + /** + * Create a TEvhttpServer with an embedded event_base and evhttp, + * listening on port and responding on the endpoint "/". + * Call "serve" on this server to serve forever. + */ + TEvhttpServer(std::shared_ptr processor, int port); + + ~TEvhttpServer(); + + static void request(struct evhttp_request* req, void* self); + int serve(); + + struct event_base* getEventBase(); + +private: + struct RequestContext; + + void process(struct evhttp_request* req); + void complete(RequestContext* ctx, bool success); + + std::shared_ptr processor_; + struct event_base* eb_; + struct evhttp* eh_; +}; +} +} +} // apache::thrift::async + +#endif // #ifndef _THRIFT_TEVHTTP_SERVER_H_ diff --git a/bsnes/thrift/thrift/concurrency/Exception.h b/bsnes/thrift/thrift/concurrency/Exception.h new file mode 100644 index 00000000..947fc9f0 --- /dev/null +++ b/bsnes/thrift/thrift/concurrency/Exception.h @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_CONCURRENCY_EXCEPTION_H_ +#define _THRIFT_CONCURRENCY_EXCEPTION_H_ 1 + +#include +#include + +namespace apache { +namespace thrift { +namespace concurrency { + +class NoSuchTaskException : public apache::thrift::TException {}; + +class UncancellableTaskException : public apache::thrift::TException {}; + +class InvalidArgumentException : public apache::thrift::TException {}; + +class IllegalStateException : public apache::thrift::TException { +public: + IllegalStateException() = default; + IllegalStateException(const std::string& message) : TException(message) {} +}; + +class TimedOutException : public apache::thrift::TException { +public: + TimedOutException() : TException("TimedOutException"){}; + TimedOutException(const std::string& message) : TException(message) {} +}; + +class TooManyPendingTasksException : public apache::thrift::TException { +public: + TooManyPendingTasksException() : TException("TooManyPendingTasksException"){}; + TooManyPendingTasksException(const std::string& message) : TException(message) {} +}; + +class SystemResourceException : public apache::thrift::TException { +public: + SystemResourceException() = default; + + SystemResourceException(const std::string& message) : TException(message) {} +}; +} +} +} // apache::thrift::concurrency + +#endif // #ifndef _THRIFT_CONCURRENCY_EXCEPTION_H_ diff --git a/bsnes/thrift/thrift/concurrency/FunctionRunner.h b/bsnes/thrift/thrift/concurrency/FunctionRunner.h new file mode 100644 index 00000000..46883441 --- /dev/null +++ b/bsnes/thrift/thrift/concurrency/FunctionRunner.h @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_CONCURRENCY_FUNCTION_RUNNER_H +#define _THRIFT_CONCURRENCY_FUNCTION_RUNNER_H 1 + +#include +#include + +namespace apache { +namespace thrift { +namespace concurrency { + +/** + * Convenient implementation of Runnable that will execute arbitrary callbacks. + * Interfaces are provided to accept both a generic 'void(void)' callback, and + * a 'void* (void*)' pthread_create-style callback. + * + * Example use: + * void* my_thread_main(void* arg); + * shared_ptr factory = ...; + * // To create a thread that executes my_thread_main once: + * shared_ptr thread = factory->newThread( + * FunctionRunner::create(my_thread_main, some_argument)); + * thread->start(); + * + * bool A::foo(); + * A* a = new A(); + * // To create a thread that executes a.foo() every 100 milliseconds: + * factory->newThread(FunctionRunner::create( + * std::bind(&A::foo, a), 100))->start(); + * + */ + +class FunctionRunner : public Runnable { +public: + // This is the type of callback 'pthread_create()' expects. + typedef void* (*PthreadFuncPtr)(void* arg); + // This a fully-generic void(void) callback for custom bindings. + typedef std::function VoidFunc; + + typedef std::function BoolFunc; + + /** + * Syntactic sugar to make it easier to create new FunctionRunner + * objects wrapped in shared_ptr. + */ + static std::shared_ptr create(const VoidFunc& cob) { + return std::shared_ptr(new FunctionRunner(cob)); + } + + static std::shared_ptr create(PthreadFuncPtr func, void* arg) { + return std::shared_ptr(new FunctionRunner(func, arg)); + } + +private: + static void pthread_func_wrapper(PthreadFuncPtr func, void* arg) { + // discard return value + func(arg); + } + +public: + /** + * Given a 'pthread_create' style callback, this FunctionRunner will + * execute the given callback. Note that the 'void*' return value is ignored. + */ + FunctionRunner(PthreadFuncPtr func, void* arg) + : func_(std::bind(pthread_func_wrapper, func, arg)), intervalMs_(-1) {} + + /** + * Given a generic callback, this FunctionRunner will execute it. + */ + FunctionRunner(const VoidFunc& cob) : func_(cob), intervalMs_(-1) {} + + /** + * Given a bool foo(...) type callback, FunctionRunner will execute + * the callback repeatedly with 'intervalMs' milliseconds between the calls, + * until it returns false. Note that the actual interval between calls will + * be intervalMs plus execution time of the callback. + */ + FunctionRunner(const BoolFunc& cob, int intervalMs) : repFunc_(cob), intervalMs_(intervalMs) {} + + void run() override { + if (repFunc_) { + while (repFunc_()) { + THRIFT_SLEEP_USEC(intervalMs_ * 1000); + } + } else { + func_(); + } + } + +private: + VoidFunc func_; + BoolFunc repFunc_; + int intervalMs_; +}; +} +} +} // apache::thrift::concurrency + +#endif // #ifndef _THRIFT_CONCURRENCY_FUNCTION_RUNNER_H diff --git a/bsnes/thrift/thrift/concurrency/Monitor.h b/bsnes/thrift/thrift/concurrency/Monitor.h new file mode 100644 index 00000000..b3939cb0 --- /dev/null +++ b/bsnes/thrift/thrift/concurrency/Monitor.h @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_CONCURRENCY_MONITOR_H_ +#define _THRIFT_CONCURRENCY_MONITOR_H_ 1 + +#include +#include +#include + +namespace apache { +namespace thrift { +namespace concurrency { + +/** + * A monitor is a combination mutex and condition-event. Waiting and + * notifying condition events requires that the caller own the mutex. Mutex + * lock and unlock operations can be performed independently of condition + * events. This is more or less analogous to java.lang.Object multi-thread + * operations. + * + * Note the Monitor can create a new, internal mutex; alternatively, a + * separate Mutex can be passed in and the Monitor will re-use it without + * taking ownership. It's the user's responsibility to make sure that the + * Mutex is not deallocated before the Monitor. + * + * Note that all methods are const. Monitors implement logical constness, not + * bit constness. This allows const methods to call monitor methods without + * needing to cast away constness or change to non-const signatures. + * + * @version $Id:$ + */ +class Monitor : boost::noncopyable { +public: + /** Creates a new mutex, and takes ownership of it. */ + Monitor(); + + /** Uses the provided mutex without taking ownership. */ + explicit Monitor(Mutex* mutex); + + /** Uses the mutex inside the provided Monitor without taking ownership. */ + explicit Monitor(Monitor* monitor); + + /** Deallocates the mutex only if we own it. */ + virtual ~Monitor(); + + Mutex& mutex() const; + + virtual void lock() const; + + virtual void unlock() const; + + /** + * Waits a maximum of the specified timeout in milliseconds for the condition + * to occur, or waits forever if timeout is zero. + * + * Returns 0 if condition occurs, THRIFT_ETIMEDOUT on timeout, or an error code. + */ + int waitForTimeRelative(const std::chrono::milliseconds &timeout) const; + + int waitForTimeRelative(uint64_t timeout_ms) const { return waitForTimeRelative(std::chrono::milliseconds(timeout_ms)); } + + /** + * Waits until the absolute time specified by abstime. + * Returns 0 if condition occurs, THRIFT_ETIMEDOUT on timeout, or an error code. + */ + int waitForTime(const std::chrono::time_point& abstime) const; + + /** + * Waits forever until the condition occurs. + * Returns 0 if condition occurs, or an error code otherwise. + */ + int waitForever() const; + + /** + * Exception-throwing version of waitForTimeRelative(), called simply + * wait(std::chrono::milliseconds) for historical reasons. Timeout is in milliseconds. + * + * If the condition occurs, this function returns cleanly; on timeout or + * error an exception is thrown. + */ + void wait(const std::chrono::milliseconds &timeout) const; + + void wait(uint64_t timeout_ms = 0ULL) const { this->wait(std::chrono::milliseconds(timeout_ms)); } + + /** Wakes up one thread waiting on this monitor. */ + virtual void notify() const; + + /** Wakes up all waiting threads on this monitor. */ + virtual void notifyAll() const; + +private: + class Impl; + + Impl* impl_; +}; + +class Synchronized { +public: + Synchronized(const Monitor* monitor) : g(monitor->mutex()) {} + Synchronized(const Monitor& monitor) : g(monitor.mutex()) {} + +private: + Guard g; +}; +} +} +} // apache::thrift::concurrency + +#endif // #ifndef _THRIFT_CONCURRENCY_MONITOR_H_ diff --git a/bsnes/thrift/thrift/concurrency/Mutex.h b/bsnes/thrift/thrift/concurrency/Mutex.h new file mode 100644 index 00000000..27e386ed --- /dev/null +++ b/bsnes/thrift/thrift/concurrency/Mutex.h @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_CONCURRENCY_MUTEX_H_ +#define _THRIFT_CONCURRENCY_MUTEX_H_ 1 + +#include +#include + +namespace apache { +namespace thrift { +namespace concurrency { + +/** + * NOTE: All mutex implementations throw an exception on failure. See each + * specific implementation to understand the exception type(s) used. + */ + +/** + * A simple mutex class + * + * @version $Id:$ + */ +class Mutex { +public: + Mutex(); + virtual ~Mutex() = default; + + virtual void lock() const; + virtual bool trylock() const; + virtual bool timedlock(int64_t milliseconds) const; + virtual void unlock() const; + + void* getUnderlyingImpl() const; + +private: + class impl; + std::shared_ptr impl_; +}; + + +class Guard : boost::noncopyable { +public: + Guard(const Mutex& value, int64_t timeout = 0) : mutex_(&value) { + if (timeout == 0) { + value.lock(); + } else if (timeout < 0) { + if (!value.trylock()) { + mutex_ = nullptr; + } + } else { + if (!value.timedlock(timeout)) { + mutex_ = nullptr; + } + } + } + ~Guard() { + if (mutex_) { + mutex_->unlock(); + } + } + + operator bool() const { return (mutex_ != nullptr); } + +private: + const Mutex* mutex_; +}; + +} +} +} // apache::thrift::concurrency + +#endif // #ifndef _THRIFT_CONCURRENCY_MUTEX_H_ diff --git a/bsnes/thrift/thrift/concurrency/Thread.h b/bsnes/thrift/thrift/concurrency/Thread.h new file mode 100644 index 00000000..344d2ca3 --- /dev/null +++ b/bsnes/thrift/thrift/concurrency/Thread.h @@ -0,0 +1,181 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_CONCURRENCY_THREAD_H_ +#define _THRIFT_CONCURRENCY_THREAD_H_ 1 + +#include +#include + +#include + +namespace apache { +namespace thrift { +namespace concurrency { + +class Thread; + +/** + * Minimal runnable class. More or less analogous to java.lang.Runnable. + * + * @version $Id:$ + */ +class Runnable { + +public: + virtual ~Runnable() = default; + virtual void run() = 0; + + /** + * Gets the thread object that is hosting this runnable object - can return + * an empty boost::shared pointer if no references remain on that thread object + */ + virtual std::shared_ptr thread() { return thread_.lock(); } + + /** + * Sets the thread that is executing this object. This is only meant for + * use by concrete implementations of Thread. + */ + virtual void thread(std::shared_ptr value) { thread_ = value; } + +private: + std::weak_ptr thread_; +}; + +/** + * Minimal thread class. Returned by thread factory bound to a Runnable object + * and ready to start execution. More or less analogous to java.lang.Thread + * (minus all the thread group, priority, mode and other baggage, since that + * is difficult to abstract across platforms and is left for platform-specific + * ThreadFactory implementations to deal with + * + * @see apache::thrift::concurrency::ThreadFactory) + */ +class Thread : public std::enable_shared_from_this { + +public: + typedef std::thread::id id_t; + typedef void (*thread_funct_t)(std::shared_ptr ); + + enum STATE { uninitialized, starting, started, stopping, stopped }; + + static void threadMain(std::shared_ptr thread); + + static inline bool is_current(id_t t) { return t == std::this_thread::get_id(); } + static inline id_t get_current() { return std::this_thread::get_id(); } + + Thread(bool detached, std::shared_ptr runnable) + : state_(uninitialized), detached_(detached) { + this->_runnable = runnable; + } + + virtual ~Thread() { + if (!detached_ && thread_->joinable()) { + try { + join(); + } catch (...) { + // We're really hosed. + } + } + } + + STATE getState() const + { + Synchronized sync(monitor_); + return state_; + } + + void setState(STATE newState) + { + Synchronized sync(monitor_); + state_ = newState; + + // unblock start() with the knowledge that the thread has actually + // started running, which avoids a race in detached threads. + if (newState == started) { + monitor_.notify(); + } + } + + /** + * Starts the thread. Does platform specific thread creation and + * configuration then invokes the run method of the Runnable object bound + * to this thread. + */ + virtual void start() { + if (getState() != uninitialized) { + return; + } + + std::shared_ptr selfRef = shared_from_this(); + setState(starting); + + Synchronized sync(monitor_); + thread_ = std::unique_ptr(new std::thread(getThreadFunc(), selfRef)); + + if (detached_) + thread_->detach(); + + // Wait for the thread to start and get far enough to grab everything + // that it needs from the calling context, thus absolving the caller + // from being required to hold on to runnable indefinitely. + monitor_.wait(); + } + + /** + * Join this thread. If this thread is joinable, the calling thread blocks + * until this thread completes. If the target thread is not joinable, then + * nothing happens. + */ + virtual void join() { + if (!detached_ && state_ != uninitialized) { + thread_->join(); + } + } + + /** + * Gets the thread's platform-specific ID + */ + Thread::id_t getId() const { return thread_.get() ? thread_->get_id() : std::thread::id(); } + + /** + * Gets the runnable object this thread is hosting + */ + std::shared_ptr runnable() const { return _runnable; } + +protected: + + virtual thread_funct_t getThreadFunc() const { + return threadMain; + } + +private: + std::shared_ptr _runnable; + std::unique_ptr thread_; + Monitor monitor_; + STATE state_; + bool detached_; +}; + + +} +} +} // apache::thrift::concurrency + +#endif // #ifndef _THRIFT_CONCURRENCY_THREAD_H_ diff --git a/bsnes/thrift/thrift/concurrency/ThreadFactory.h b/bsnes/thrift/thrift/concurrency/ThreadFactory.h new file mode 100644 index 00000000..9db832e3 --- /dev/null +++ b/bsnes/thrift/thrift/concurrency/ThreadFactory.h @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_CONCURRENCY_THREADFACTORY_H_ +#define _THRIFT_CONCURRENCY_THREADFACTORY_H_ 1 + +#include + +#include +namespace apache { +namespace thrift { +namespace concurrency { + +/** + * Factory to create thread object and bind them to Runnable + * object for execution + */ +class ThreadFactory { +public: + /** + * All threads created by a factory are reference-counted + * via std::shared_ptr. The factory guarantees that threads and the Runnable tasks + * they host will be properly cleaned up once the last strong reference + * to both is given up. + * + * By default threads are not joinable. + */ + ThreadFactory(bool detached = true) : detached_(detached) { } + + virtual ~ThreadFactory() = default; + + /** + * Gets current detached mode + */ + bool isDetached() const { return detached_; } + + /** + * Sets the detached disposition of newly created threads. + */ + void setDetached(bool detached) { detached_ = detached; } + + /** + * Create a new thread. + */ + virtual std::shared_ptr newThread(std::shared_ptr runnable) const; + + /** + * Gets the current thread id or unknown_thread_id if the current thread is not a thrift thread + */ + Thread::id_t getCurrentThreadId() const; + +private: + bool detached_; +}; + +} +} +} // apache::thrift::concurrency + +#endif // #ifndef _THRIFT_CONCURRENCY_THREADFACTORY_H_ diff --git a/bsnes/thrift/thrift/concurrency/ThreadManager.h b/bsnes/thrift/thrift/concurrency/ThreadManager.h new file mode 100644 index 00000000..7b202ca6 --- /dev/null +++ b/bsnes/thrift/thrift/concurrency/ThreadManager.h @@ -0,0 +1,213 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_CONCURRENCY_THREADMANAGER_H_ +#define _THRIFT_CONCURRENCY_THREADMANAGER_H_ 1 + +#include +#include +#include + +namespace apache { +namespace thrift { +namespace concurrency { + +/** + * Thread Pool Manager and related classes + * + * @version $Id:$ + */ +class ThreadManager; + +/** + * ThreadManager class + * + * This class manages a pool of threads. It uses a ThreadFactory to create + * threads. It never actually creates or destroys worker threads, rather + * it maintains statistics on number of idle threads, number of active threads, + * task backlog, and average wait and service times and informs the PoolPolicy + * object bound to instances of this manager of interesting transitions. It is + * then up the PoolPolicy object to decide if the thread pool size needs to be + * adjusted and call this object addWorker and removeWorker methods to make + * changes. + * + * This design allows different policy implementations to use this code to + * handle basic worker thread management and worker task execution and focus on + * policy issues. The simplest policy, StaticPolicy, does nothing other than + * create a fixed number of threads. + */ +class ThreadManager { + +protected: + ThreadManager() = default; + +public: + typedef std::function)> ExpireCallback; + + virtual ~ThreadManager() = default; + + /** + * Starts the thread manager. Verifies all attributes have been properly + * initialized, then allocates necessary resources to begin operation + */ + virtual void start() = 0; + + /** + * Stops the thread manager. Aborts all remaining unprocessed task, shuts + * down all created worker threads, and releases all allocated resources. + * This method blocks for all worker threads to complete, thus it can + * potentially block forever if a worker thread is running a task that + * won't terminate. + * + * Worker threads will be joined depending on the threadFactory's detached + * disposition. + */ + virtual void stop() = 0; + + enum STATE { UNINITIALIZED, STARTING, STARTED, JOINING, STOPPING, STOPPED }; + + virtual STATE state() const = 0; + + /** + * \returns the current thread factory + */ + virtual std::shared_ptr threadFactory() const = 0; + + /** + * Set the thread factory. + * \throws InvalidArgumentException if the new thread factory has a different + * detached disposition than the one replacing it + */ + virtual void threadFactory(std::shared_ptr value) = 0; + + /** + * Adds worker thread(s). + */ + virtual void addWorker(size_t value = 1) = 0; + + /** + * Removes worker thread(s). + * Threads are joined if the thread factory detached disposition allows it. + * Blocks until the number of worker threads reaches the new limit. + * \param[in] value the number to remove + * \throws InvalidArgumentException if the value is greater than the number + * of workers + */ + virtual void removeWorker(size_t value = 1) = 0; + + /** + * Gets the current number of idle worker threads + */ + virtual size_t idleWorkerCount() const = 0; + + /** + * Gets the current number of total worker threads + */ + virtual size_t workerCount() const = 0; + + /** + * Gets the current number of pending tasks + */ + virtual size_t pendingTaskCount() const = 0; + + /** + * Gets the current number of pending and executing tasks + */ + virtual size_t totalTaskCount() const = 0; + + /** + * Gets the maximum pending task count. 0 indicates no maximum + */ + virtual size_t pendingTaskCountMax() const = 0; + + /** + * Gets the number of tasks which have been expired without being run + * since start() was called. + */ + virtual size_t expiredTaskCount() const = 0; + + /** + * Adds a task to be executed at some time in the future by a worker thread. + * + * This method will block if pendingTaskCountMax() in not zero and pendingTaskCount() + * is greater than or equalt to pendingTaskCountMax(). If this method is called in the + * context of a ThreadManager worker thread it will throw a + * TooManyPendingTasksException + * + * @param task The task to queue for execution + * + * @param timeout Time to wait in milliseconds to add a task when a pending-task-count + * is specified. Specific cases: + * timeout = 0 : Wait forever to queue task. + * timeout = -1 : Return immediately if pending task count exceeds specified max + * @param expiration when nonzero, the number of milliseconds the task is valid + * to be run; if exceeded, the task will be dropped off the queue and not run. + * + * @throws TooManyPendingTasksException Pending task count exceeds max pending task count + */ + virtual void add(std::shared_ptr task, + int64_t timeout = 0LL, + int64_t expiration = 0LL) = 0; + + /** + * Removes a pending task + */ + virtual void remove(std::shared_ptr task) = 0; + + /** + * Remove the next pending task which would be run. + * + * @return the task removed. + */ + virtual std::shared_ptr removeNextPending() = 0; + + /** + * Remove tasks from front of task queue that have expired. + */ + virtual void removeExpiredTasks() = 0; + + /** + * Set a callback to be called when a task is expired and not run. + * + * @param expireCallback a function called with the shared_ptr for + * the expired task. + */ + virtual void setExpireCallback(ExpireCallback expireCallback) = 0; + + static std::shared_ptr newThreadManager(); + + /** + * Creates a simple thread manager the uses count number of worker threads and has + * a pendingTaskCountMax maximum pending tasks. The default, 0, specified no limit + * on pending tasks + */ + static std::shared_ptr newSimpleThreadManager(size_t count = 4, + size_t pendingTaskCountMax = 0); + + class Task; + + class Worker; + + class Impl; +}; +} +} +} // apache::thrift::concurrency + +#endif // #ifndef _THRIFT_CONCURRENCY_THREADMANAGER_H_ diff --git a/bsnes/thrift/thrift/concurrency/TimerManager.h b/bsnes/thrift/thrift/concurrency/TimerManager.h new file mode 100644 index 00000000..44d4738d --- /dev/null +++ b/bsnes/thrift/thrift/concurrency/TimerManager.h @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_CONCURRENCY_TIMERMANAGER_H_ +#define _THRIFT_CONCURRENCY_TIMERMANAGER_H_ 1 + +#include +#include + +#include +#include + +namespace apache { +namespace thrift { +namespace concurrency { + +/** + * Timer Manager + * + * This class dispatches timer tasks when they fall due. + * + * @version $Id:$ + */ +class TimerManager { + +public: + class Task; + typedef std::weak_ptr Timer; + + TimerManager(); + + virtual ~TimerManager(); + + virtual std::shared_ptr threadFactory() const; + + virtual void threadFactory(std::shared_ptr value); + + /** + * Starts the timer manager service + * + * @throws IllegalArgumentException Missing thread factory attribute + */ + virtual void start(); + + /** + * Stops the timer manager service + */ + virtual void stop(); + + virtual size_t taskCount() const; + + /** + * Adds a task to be executed at some time in the future by a worker thread. + * + * @param task The task to execute + * @param timeout Time in milliseconds to delay before executing task + * @return Handle of the timer, which can be used to remove the timer. + */ + virtual Timer add(std::shared_ptr task, const std::chrono::milliseconds &timeout); + Timer add(std::shared_ptr task, uint64_t timeout) { return add(task,std::chrono::milliseconds(timeout)); } + + /** + * Adds a task to be executed at some time in the future by a worker thread. + * + * @param task The task to execute + * @param abstime Absolute time in the future to execute task. + * @return Handle of the timer, which can be used to remove the timer. + */ + virtual Timer add(std::shared_ptr task, const std::chrono::time_point& abstime); + + /** + * Removes a pending task + * + * @param task The task to remove. All timers which execute this task will + * be removed. + * @throws NoSuchTaskException Specified task doesn't exist. It was either + * processed already or this call was made for a + * task that was never added to this timer + * + * @throws UncancellableTaskException Specified task is already being + * executed or has completed execution. + */ + virtual void remove(std::shared_ptr task); + + /** + * Removes a single pending task + * + * @param timer The timer to remove. The timer is returned when calling the + * add() method. + * @throws NoSuchTaskException Specified task doesn't exist. It was either + * processed already or this call was made for a + * task that was never added to this timer + * + * @throws UncancellableTaskException Specified task is already being + * executed or has completed execution. + */ + virtual void remove(Timer timer); + + enum STATE { UNINITIALIZED, STARTING, STARTED, STOPPING, STOPPED }; + + virtual STATE state() const; + +private: + std::shared_ptr threadFactory_; + friend class Task; + std::multimap, std::shared_ptr > taskMap_; + size_t taskCount_; + Monitor monitor_; + STATE state_; + class Dispatcher; + friend class Dispatcher; + std::shared_ptr dispatcher_; + std::shared_ptr dispatcherThread_; + using task_iterator = decltype(taskMap_)::iterator; + typedef std::pair task_range; +}; +} +} +} // apache::thrift::concurrency + +#endif // #ifndef _THRIFT_CONCURRENCY_TIMERMANAGER_H_ diff --git a/bsnes/thrift/thrift/processor/PeekProcessor.h b/bsnes/thrift/thrift/processor/PeekProcessor.h new file mode 100644 index 00000000..ae565fc4 --- /dev/null +++ b/bsnes/thrift/thrift/processor/PeekProcessor.h @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef PEEKPROCESSOR_H +#define PEEKPROCESSOR_H + +#include +#include +#include +#include +#include +#include + +namespace apache { +namespace thrift { +namespace processor { + +/* + * Class for peeking at the raw data that is being processed by another processor + * and gives the derived class a chance to change behavior accordingly + * + */ +class PeekProcessor : public apache::thrift::TProcessor { + +public: + PeekProcessor(); + ~PeekProcessor() override; + + // Input here: actualProcessor - the underlying processor + // protocolFactory - the protocol factory used to wrap the memory buffer + // transportFactory - this TPipedTransportFactory is used to wrap the source transport + // via a call to getPipedTransport + void initialize( + std::shared_ptr actualProcessor, + std::shared_ptr protocolFactory, + std::shared_ptr transportFactory); + + std::shared_ptr getPipedTransport( + std::shared_ptr in); + + void setTargetTransport(std::shared_ptr targetTransport); + + bool process(std::shared_ptr in, + std::shared_ptr out, + void* connectionContext) override; + + // The following three functions can be overloaded by child classes to + // achieve desired peeking behavior + virtual void peekName(const std::string& fname); + virtual void peekBuffer(uint8_t* buffer, uint32_t size); + virtual void peek(std::shared_ptr in, + apache::thrift::protocol::TType ftype, + int16_t fid); + virtual void peekEnd(); + +private: + std::shared_ptr actualProcessor_; + std::shared_ptr pipedProtocol_; + std::shared_ptr transportFactory_; + std::shared_ptr memoryBuffer_; + std::shared_ptr targetTransport_; +}; +} +} +} // apache::thrift::processor + +#endif diff --git a/bsnes/thrift/thrift/processor/StatsProcessor.h b/bsnes/thrift/thrift/processor/StatsProcessor.h new file mode 100644 index 00000000..e98efb82 --- /dev/null +++ b/bsnes/thrift/thrift/processor/StatsProcessor.h @@ -0,0 +1,242 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef STATSPROCESSOR_H +#define STATSPROCESSOR_H + +#include +#include +#include +#include + +namespace apache { +namespace thrift { +namespace processor { + +/* + * Class for keeping track of function call statistics and printing them if desired + * + */ +class StatsProcessor : public apache::thrift::TProcessor { +public: + StatsProcessor(bool print, bool frequency) : print_(print), frequency_(frequency) {} + virtual ~StatsProcessor(){}; + + virtual bool process(std::shared_ptr piprot, + std::shared_ptr poprot, + void* serverContext) { + + piprot_ = piprot; + + std::string fname; + apache::thrift::protocol::TMessageType mtype; + int32_t seqid; + + piprot_->readMessageBegin(fname, mtype, seqid); + if (mtype != apache::thrift::protocol::T_CALL && mtype != apache::thrift::protocol::T_ONEWAY) { + if (print_) { + printf("Unknown message type\n"); + } + throw apache::thrift::TException("Unexpected message type"); + } + if (print_) { + printf("%s (", fname.c_str()); + } + if (frequency_) { + if (frequency_map_.find(fname) != frequency_map_.end()) { + frequency_map_[fname]++; + } else { + frequency_map_[fname] = 1; + } + } + + apache::thrift::protocol::TType ftype; + int16_t fid; + + while (true) { + piprot_->readFieldBegin(fname, ftype, fid); + if (ftype == apache::thrift::protocol::T_STOP) { + break; + } + + printAndPassToBuffer(ftype); + if (print_) { + printf(", "); + } + } + + if (print_) { + printf("\b\b)\n"); + } + return true; + } + + const std::map& get_frequency_map() { return frequency_map_; } + +protected: + void printAndPassToBuffer(apache::thrift::protocol::TType ftype) { + switch (ftype) { + case apache::thrift::protocol::T_BOOL: { + bool boolv; + piprot_->readBool(boolv); + if (print_) { + printf("%d", boolv); + } + } break; + case apache::thrift::protocol::T_BYTE: { + int8_t bytev; + piprot_->readByte(bytev); + if (print_) { + printf("%d", bytev); + } + } break; + case apache::thrift::protocol::T_I16: { + int16_t i16; + piprot_->readI16(i16); + if (print_) { + printf("%d", i16); + } + } break; + case apache::thrift::protocol::T_I32: { + int32_t i32; + piprot_->readI32(i32); + if (print_) { + printf("%d", i32); + } + } break; + case apache::thrift::protocol::T_I64: { + int64_t i64; + piprot_->readI64(i64); + if (print_) { + printf("%ld", i64); + } + } break; + case apache::thrift::protocol::T_DOUBLE: { + double dub; + piprot_->readDouble(dub); + if (print_) { + printf("%f", dub); + } + } break; + case apache::thrift::protocol::T_STRING: { + std::string str; + piprot_->readString(str); + if (print_) { + printf("%s", str.c_str()); + } + } break; + case apache::thrift::protocol::T_STRUCT: { + std::string name; + int16_t fid; + apache::thrift::protocol::TType ftype; + piprot_->readStructBegin(name); + if (print_) { + printf("<"); + } + while (true) { + piprot_->readFieldBegin(name, ftype, fid); + if (ftype == apache::thrift::protocol::T_STOP) { + break; + } + printAndPassToBuffer(ftype); + if (print_) { + printf(","); + } + piprot_->readFieldEnd(); + } + piprot_->readStructEnd(); + if (print_) { + printf("\b>"); + } + } break; + case apache::thrift::protocol::T_MAP: { + apache::thrift::protocol::TType keyType; + apache::thrift::protocol::TType valType; + uint32_t i, size; + piprot_->readMapBegin(keyType, valType, size); + if (print_) { + printf("{"); + } + for (i = 0; i < size; i++) { + printAndPassToBuffer(keyType); + if (print_) { + printf("=>"); + } + printAndPassToBuffer(valType); + if (print_) { + printf(","); + } + } + piprot_->readMapEnd(); + if (print_) { + printf("\b}"); + } + } break; + case apache::thrift::protocol::T_SET: { + apache::thrift::protocol::TType elemType; + uint32_t i, size; + piprot_->readSetBegin(elemType, size); + if (print_) { + printf("{"); + } + for (i = 0; i < size; i++) { + printAndPassToBuffer(elemType); + if (print_) { + printf(","); + } + } + piprot_->readSetEnd(); + if (print_) { + printf("\b}"); + } + } break; + case apache::thrift::protocol::T_LIST: { + apache::thrift::protocol::TType elemType; + uint32_t i, size; + piprot_->readListBegin(elemType, size); + if (print_) { + printf("["); + } + for (i = 0; i < size; i++) { + printAndPassToBuffer(elemType); + if (print_) { + printf(","); + } + } + piprot_->readListEnd(); + if (print_) { + printf("\b]"); + } + } break; + default: + break; + } + } + + std::shared_ptr piprot_; + std::map frequency_map_; + + bool print_; + bool frequency_; +}; +} +} +} // apache::thrift::processor + +#endif diff --git a/bsnes/thrift/thrift/processor/TMultiplexedProcessor.h b/bsnes/thrift/thrift/processor/TMultiplexedProcessor.h new file mode 100644 index 00000000..85c0affc --- /dev/null +++ b/bsnes/thrift/thrift/processor/TMultiplexedProcessor.h @@ -0,0 +1,224 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef THRIFT_TMULTIPLEXEDPROCESSOR_H_ +#define THRIFT_TMULTIPLEXEDPROCESSOR_H_ 1 + +#include +#include +#include +#include + +namespace apache { +namespace thrift { +namespace protocol { + +/** + * To be able to work with any protocol, we needed + * to allow them to call readMessageBegin() and get a TMessage in exactly + * the standard format, without the service name prepended to TMessage.name. + */ +class StoredMessageProtocol : public TProtocolDecorator { +public: + StoredMessageProtocol(std::shared_ptr _protocol, + const std::string& _name, + const TMessageType _type, + const int32_t _seqid) + : TProtocolDecorator(_protocol), name(_name), type(_type), seqid(_seqid) {} + + uint32_t readMessageBegin_virt(std::string& _name, TMessageType& _type, int32_t& _seqid) override { + + _name = name; + _type = type; + _seqid = seqid; + + return 0; // (Normal TProtocol read functions return number of bytes read) + } + + std::string name; + TMessageType type; + int32_t seqid; +}; +} // namespace protocol + +/** + * TMultiplexedProcessor is a TProcessor allowing + * a single TServer to provide multiple services. + * + *

To do so, you instantiate the processor and then register additional + * processors with it, as shown in the following example:

+ * + *
+ * std::shared_ptr processor(new TMultiplexedProcessor()); + * + * processor->registerProcessor( + * "Calculator", + * std::shared_ptr( new CalculatorProcessor( + * std::shared_ptr( new CalculatorHandler())))); + * + * processor->registerProcessor( + * "WeatherReport", + * std::shared_ptr( new WeatherReportProcessor( + * std::shared_ptr( new WeatherReportHandler())))); + * + * std::shared_ptr transport(new TServerSocket(9090)); + * TSimpleServer server(processor, transport); + * + * server.serve(); + *
+ */ +class TMultiplexedProcessor : public TProcessor { +public: + typedef std::map > services_t; + + /** + * 'Register' a service with this TMultiplexedProcessor. This + * allows us to broker requests to individual services by using the service + * name to select them at request time. + * + * \param [in] serviceName Name of a service, has to be identical to the name + * declared in the Thrift IDL, e.g. "WeatherReport". + * \param [in] processor Implementation of a service, usually referred to + * as "handlers", e.g. WeatherReportHandler, + * implementing WeatherReportIf interface. + */ + void registerProcessor(const std::string& serviceName, std::shared_ptr processor) { + services[serviceName] = processor; + } + + /** + * Register a service to be called to process queries without service name + * \param [in] processor Implementation of a service. + */ + void registerDefault(const std::shared_ptr& processor) { + defaultProcessor = processor; + } + + /** + * Chew up invalid input and return an exception to throw. + */ + TException protocol_error(std::shared_ptr in, + std::shared_ptr out, + const std::string& name, + int32_t seqid, + const std::string& msg) const { + in->skip(::apache::thrift::protocol::T_STRUCT); + in->readMessageEnd(); + in->getTransport()->readEnd(); + ::apache::thrift::TApplicationException + x(::apache::thrift::TApplicationException::PROTOCOL_ERROR, + "TMultiplexedProcessor: " + msg); + out->writeMessageBegin(name, ::apache::thrift::protocol::T_EXCEPTION, seqid); + x.write(out.get()); + out->writeMessageEnd(); + out->getTransport()->writeEnd(); + out->getTransport()->flush(); + return TException(msg); +} + + /** + * This implementation of process performs the following steps: + * + *
    + *
  1. Read the beginning of the message.
  2. + *
  3. Extract the service name from the message.
  4. + *
  5. Using the service name to locate the appropriate processor.
  6. + *
  7. Dispatch to the processor, with a decorated instance of TProtocol + * that allows readMessageBegin() to return the original TMessage.
  8. + *
+ * + * \throws TException If the message type is not T_CALL or T_ONEWAY, if + * the service name was not found in the message, or if the service + * name was not found in the service map. + */ + bool process(std::shared_ptr in, + std::shared_ptr out, + void* connectionContext) override { + std::string name; + protocol::TMessageType type; + int32_t seqid; + + // Use the actual underlying protocol (e.g. TBinaryProtocol) to read the + // message header. This pulls the message "off the wire", which we'll + // deal with at the end of this method. + in->readMessageBegin(name, type, seqid); + + if (type != protocol::T_CALL && type != protocol::T_ONEWAY) { + // Unexpected message type. + throw protocol_error(in, out, name, seqid, "Unexpected message type"); + } + + // Extract the service name + boost::tokenizer > tok(name, boost::char_separator(":")); + + std::vector tokens; + std::copy(tok.begin(), tok.end(), std::back_inserter(tokens)); + + // A valid message should consist of two tokens: the service + // name and the name of the method to call. + if (tokens.size() == 2) { + // Search for a processor associated with this service name. + auto it = services.find(tokens[0]); + + if (it != services.end()) { + std::shared_ptr processor = it->second; + // Let the processor registered for this service name + // process the message. + return processor + ->process(std::shared_ptr( + new protocol::StoredMessageProtocol(in, tokens[1], type, seqid)), + out, + connectionContext); + } else { + // Unknown service. + throw protocol_error(in, out, name, seqid, + "Unknown service: " + tokens[0] + + ". Did you forget to call registerProcessor()?"); + } + } else if (tokens.size() == 1) { + if (defaultProcessor) { + // non-multiplexed client forwards to default processor + return defaultProcessor + ->process(std::shared_ptr( + new protocol::StoredMessageProtocol(in, tokens[0], type, seqid)), + out, + connectionContext); + } else { + throw protocol_error(in, out, name, seqid, + "Non-multiplexed client request dropped. " + "Did you forget to call defaultProcessor()?"); + } + } else { + throw protocol_error(in, out, name, seqid, + "Wrong number of tokens."); + } + } + +private: + /** Map of service processor objects, indexed by service names. */ + services_t services; + + //! If a non-multi client requests something, it goes to the + //! default processor (if one is defined) for backwards compatibility. + std::shared_ptr defaultProcessor; +}; +} +} + +#endif // THRIFT_TMULTIPLEXEDPROCESSOR_H_ diff --git a/bsnes/thrift/thrift/protocol/TBase64Utils.h b/bsnes/thrift/thrift/protocol/TBase64Utils.h new file mode 100644 index 00000000..1ea67440 --- /dev/null +++ b/bsnes/thrift/thrift/protocol/TBase64Utils.h @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_PROTOCOL_TBASE64UTILS_H_ +#define _THRIFT_PROTOCOL_TBASE64UTILS_H_ + +#include +#include + +namespace apache { +namespace thrift { +namespace protocol { + +// in must be at least len bytes +// len must be 1, 2, or 3 +// buf must be a buffer of at least 4 bytes and may not overlap in +// the data is not padded with '='; the caller can do this if desired +void base64_encode(const uint8_t* in, uint32_t len, uint8_t* buf); + +// buf must be a buffer of at least 4 bytes and contain base64 encoded values +// buf will be changed to contain output bytes +// len is number of bytes to consume from input (must be 2, 3, or 4) +// no '=' padding should be included in the input +void base64_decode(uint8_t* buf, uint32_t len); +} +} +} // apache::thrift::protocol + +#endif // #define _THRIFT_PROTOCOL_TBASE64UTILS_H_ diff --git a/bsnes/thrift/thrift/protocol/TBinaryProtocol.h b/bsnes/thrift/thrift/protocol/TBinaryProtocol.h new file mode 100644 index 00000000..b4314401 --- /dev/null +++ b/bsnes/thrift/thrift/protocol/TBinaryProtocol.h @@ -0,0 +1,268 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_PROTOCOL_TBINARYPROTOCOL_H_ +#define _THRIFT_PROTOCOL_TBINARYPROTOCOL_H_ 1 + +#include +#include + +#include + +namespace apache { +namespace thrift { +namespace protocol { + +/** + * The default binary protocol for thrift. Writes all data in a very basic + * binary format, essentially just spitting out the raw bytes. + * + */ +template +class TBinaryProtocolT : public TVirtualProtocol > { +public: + static const int32_t VERSION_MASK = ((int32_t)0xffff0000); + static const int32_t VERSION_1 = ((int32_t)0x80010000); + // VERSION_2 (0x80020000) was taken by TDenseProtocol (which has since been removed) + + TBinaryProtocolT(std::shared_ptr trans) + : TVirtualProtocol >(trans), + trans_(trans.get()), + string_limit_(0), + container_limit_(0), + strict_read_(false), + strict_write_(true) {} + + TBinaryProtocolT(std::shared_ptr trans, + int32_t string_limit, + int32_t container_limit, + bool strict_read, + bool strict_write) + : TVirtualProtocol >(trans), + trans_(trans.get()), + string_limit_(string_limit), + container_limit_(container_limit), + strict_read_(strict_read), + strict_write_(strict_write) {} + + void setStringSizeLimit(int32_t string_limit) { string_limit_ = string_limit; } + + void setContainerSizeLimit(int32_t container_limit) { container_limit_ = container_limit; } + + void setStrict(bool strict_read, bool strict_write) { + strict_read_ = strict_read; + strict_write_ = strict_write; + } + + /** + * Writing functions. + */ + + /*ol*/ uint32_t writeMessageBegin(const std::string& name, + const TMessageType messageType, + const int32_t seqid); + + /*ol*/ uint32_t writeMessageEnd(); + + inline uint32_t writeStructBegin(const char* name); + + inline uint32_t writeStructEnd(); + + inline uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId); + + inline uint32_t writeFieldEnd(); + + inline uint32_t writeFieldStop(); + + inline uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size); + + inline uint32_t writeMapEnd(); + + inline uint32_t writeListBegin(const TType elemType, const uint32_t size); + + inline uint32_t writeListEnd(); + + inline uint32_t writeSetBegin(const TType elemType, const uint32_t size); + + inline uint32_t writeSetEnd(); + + inline uint32_t writeBool(const bool value); + + inline uint32_t writeByte(const int8_t byte); + + inline uint32_t writeI16(const int16_t i16); + + inline uint32_t writeI32(const int32_t i32); + + inline uint32_t writeI64(const int64_t i64); + + inline uint32_t writeDouble(const double dub); + + template + inline uint32_t writeString(const StrType& str); + + inline uint32_t writeBinary(const std::string& str); + + /** + * Reading functions + */ + + /*ol*/ uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid); + + /*ol*/ uint32_t readMessageEnd(); + + inline uint32_t readStructBegin(std::string& name); + + inline uint32_t readStructEnd(); + + inline uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId); + + inline uint32_t readFieldEnd(); + + inline uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size); + + inline uint32_t readMapEnd(); + + inline uint32_t readListBegin(TType& elemType, uint32_t& size); + + inline uint32_t readListEnd(); + + inline uint32_t readSetBegin(TType& elemType, uint32_t& size); + + inline uint32_t readSetEnd(); + + inline uint32_t readBool(bool& value); + // Provide the default readBool() implementation for std::vector + using TVirtualProtocol >::readBool; + + inline uint32_t readByte(int8_t& byte); + + inline uint32_t readI16(int16_t& i16); + + inline uint32_t readI32(int32_t& i32); + + inline uint32_t readI64(int64_t& i64); + + inline uint32_t readDouble(double& dub); + + template + inline uint32_t readString(StrType& str); + + inline uint32_t readBinary(std::string& str); + + int getMinSerializedSize(TType type); + + void checkReadBytesAvailable(TSet& set) + { + trans_->checkReadBytesAvailable(set.size_ * getMinSerializedSize(set.elemType_)); + } + + void checkReadBytesAvailable(TList& list) + { + trans_->checkReadBytesAvailable(list.size_ * getMinSerializedSize(list.elemType_)); + } + + void checkReadBytesAvailable(TMap& map) + { + int elmSize = getMinSerializedSize(map.keyType_) + getMinSerializedSize(map.valueType_); + trans_->checkReadBytesAvailable(map.size_ * elmSize); + } + +protected: + template + uint32_t readStringBody(StrType& str, int32_t sz); + + Transport_* trans_; + + int32_t string_limit_; + int32_t container_limit_; + + // Enforce presence of version identifier + bool strict_read_; + bool strict_write_; +}; + +typedef TBinaryProtocolT TBinaryProtocol; +typedef TBinaryProtocolT TLEBinaryProtocol; + +/** + * Constructs binary protocol handlers + */ +template +class TBinaryProtocolFactoryT : public TProtocolFactory { +public: + TBinaryProtocolFactoryT() + : string_limit_(0), container_limit_(0), strict_read_(false), strict_write_(true) {} + + TBinaryProtocolFactoryT(int32_t string_limit, + int32_t container_limit, + bool strict_read, + bool strict_write) + : string_limit_(string_limit), + container_limit_(container_limit), + strict_read_(strict_read), + strict_write_(strict_write) {} + + ~TBinaryProtocolFactoryT() override = default; + + void setStringSizeLimit(int32_t string_limit) { string_limit_ = string_limit; } + + void setContainerSizeLimit(int32_t container_limit) { container_limit_ = container_limit; } + + void setStrict(bool strict_read, bool strict_write) { + strict_read_ = strict_read; + strict_write_ = strict_write; + } + + std::shared_ptr getProtocol(std::shared_ptr trans) override { + std::shared_ptr specific_trans = std::dynamic_pointer_cast(trans); + TProtocol* prot; + if (specific_trans) { + prot = new TBinaryProtocolT(specific_trans, + string_limit_, + container_limit_, + strict_read_, + strict_write_); + } else { + prot = new TBinaryProtocolT(trans, + string_limit_, + container_limit_, + strict_read_, + strict_write_); + } + + return std::shared_ptr(prot); + } + +private: + int32_t string_limit_; + int32_t container_limit_; + bool strict_read_; + bool strict_write_; +}; + +typedef TBinaryProtocolFactoryT TBinaryProtocolFactory; +typedef TBinaryProtocolFactoryT TLEBinaryProtocolFactory; +} +} +} // apache::thrift::protocol + +#include + +#endif // #ifndef _THRIFT_PROTOCOL_TBINARYPROTOCOL_H_ diff --git a/bsnes/thrift/thrift/protocol/TBinaryProtocol.tcc b/bsnes/thrift/thrift/protocol/TBinaryProtocol.tcc new file mode 100644 index 00000000..755f2438 --- /dev/null +++ b/bsnes/thrift/thrift/protocol/TBinaryProtocol.tcc @@ -0,0 +1,491 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_ +#define _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_ 1 + +#include +#include + +#include + +namespace apache { +namespace thrift { +namespace protocol { + +template +uint32_t TBinaryProtocolT::writeMessageBegin(const std::string& name, + const TMessageType messageType, + const int32_t seqid) { + if (this->strict_write_) { + int32_t version = (VERSION_1) | ((int32_t)messageType); + uint32_t wsize = 0; + wsize += writeI32(version); + wsize += writeString(name); + wsize += writeI32(seqid); + return wsize; + } else { + uint32_t wsize = 0; + wsize += writeString(name); + wsize += writeByte((int8_t)messageType); + wsize += writeI32(seqid); + return wsize; + } +} + +template +uint32_t TBinaryProtocolT::writeMessageEnd() { + return 0; +} + +template +uint32_t TBinaryProtocolT::writeStructBegin(const char* name) { + (void)name; + return 0; +} + +template +uint32_t TBinaryProtocolT::writeStructEnd() { + return 0; +} + +template +uint32_t TBinaryProtocolT::writeFieldBegin(const char* name, + const TType fieldType, + const int16_t fieldId) { + (void)name; + uint32_t wsize = 0; + wsize += writeByte((int8_t)fieldType); + wsize += writeI16(fieldId); + return wsize; +} + +template +uint32_t TBinaryProtocolT::writeFieldEnd() { + return 0; +} + +template +uint32_t TBinaryProtocolT::writeFieldStop() { + return writeByte((int8_t)T_STOP); +} + +template +uint32_t TBinaryProtocolT::writeMapBegin(const TType keyType, + const TType valType, + const uint32_t size) { + uint32_t wsize = 0; + wsize += writeByte((int8_t)keyType); + wsize += writeByte((int8_t)valType); + wsize += writeI32((int32_t)size); + return wsize; +} + +template +uint32_t TBinaryProtocolT::writeMapEnd() { + return 0; +} + +template +uint32_t TBinaryProtocolT::writeListBegin(const TType elemType, + const uint32_t size) { + uint32_t wsize = 0; + wsize += writeByte((int8_t)elemType); + wsize += writeI32((int32_t)size); + return wsize; +} + +template +uint32_t TBinaryProtocolT::writeListEnd() { + return 0; +} + +template +uint32_t TBinaryProtocolT::writeSetBegin(const TType elemType, + const uint32_t size) { + uint32_t wsize = 0; + wsize += writeByte((int8_t)elemType); + wsize += writeI32((int32_t)size); + return wsize; +} + +template +uint32_t TBinaryProtocolT::writeSetEnd() { + return 0; +} + +template +uint32_t TBinaryProtocolT::writeBool(const bool value) { + uint8_t tmp = value ? 1 : 0; + this->trans_->write(&tmp, 1); + return 1; +} + +template +uint32_t TBinaryProtocolT::writeByte(const int8_t byte) { + this->trans_->write((uint8_t*)&byte, 1); + return 1; +} + +template +uint32_t TBinaryProtocolT::writeI16(const int16_t i16) { + auto net = (int16_t)ByteOrder_::toWire16(i16); + this->trans_->write((uint8_t*)&net, 2); + return 2; +} + +template +uint32_t TBinaryProtocolT::writeI32(const int32_t i32) { + auto net = (int32_t)ByteOrder_::toWire32(i32); + this->trans_->write((uint8_t*)&net, 4); + return 4; +} + +template +uint32_t TBinaryProtocolT::writeI64(const int64_t i64) { + auto net = (int64_t)ByteOrder_::toWire64(i64); + this->trans_->write((uint8_t*)&net, 8); + return 8; +} + +template +uint32_t TBinaryProtocolT::writeDouble(const double dub) { + static_assert(sizeof(double) == sizeof(uint64_t), "sizeof(double) == sizeof(uint64_t)"); + static_assert(std::numeric_limits::is_iec559, "std::numeric_limits::is_iec559"); + + auto bits = bitwise_cast(dub); + bits = ByteOrder_::toWire64(bits); + this->trans_->write((uint8_t*)&bits, 8); + return 8; +} + +template +template +uint32_t TBinaryProtocolT::writeString(const StrType& str) { + if (str.size() > static_cast((std::numeric_limits::max)())) + throw TProtocolException(TProtocolException::SIZE_LIMIT); + auto size = static_cast(str.size()); + uint32_t result = writeI32((int32_t)size); + if (size > 0) { + this->trans_->write((uint8_t*)str.data(), size); + } + return result + size; +} + +template +uint32_t TBinaryProtocolT::writeBinary(const std::string& str) { + return TBinaryProtocolT::writeString(str); +} + +/** + * Reading functions + */ + +template +uint32_t TBinaryProtocolT::readMessageBegin(std::string& name, + TMessageType& messageType, + int32_t& seqid) { + uint32_t result = 0; + int32_t sz; + result += readI32(sz); + + if (sz < 0) { + // Check for correct version number + int32_t version = sz & VERSION_MASK; + if (version != VERSION_1) { + throw TProtocolException(TProtocolException::BAD_VERSION, "Bad version identifier"); + } + messageType = (TMessageType)(sz & 0x000000ff); + result += readString(name); + result += readI32(seqid); + } else { + if (this->strict_read_) { + throw TProtocolException(TProtocolException::BAD_VERSION, + "No version identifier... old protocol client in strict mode?"); + } else { + // Handle pre-versioned input + int8_t type; + result += readStringBody(name, sz); + result += readByte(type); + messageType = (TMessageType)type; + result += readI32(seqid); + } + } + return result; +} + +template +uint32_t TBinaryProtocolT::readMessageEnd() { + return 0; +} + +template +uint32_t TBinaryProtocolT::readStructBegin(std::string& name) { + name = ""; + return 0; +} + +template +uint32_t TBinaryProtocolT::readStructEnd() { + return 0; +} + +template +uint32_t TBinaryProtocolT::readFieldBegin(std::string& name, + TType& fieldType, + int16_t& fieldId) { + (void)name; + uint32_t result = 0; + int8_t type; + result += readByte(type); + fieldType = (TType)type; + if (fieldType == T_STOP) { + fieldId = 0; + return result; + } + result += readI16(fieldId); + return result; +} + +template +uint32_t TBinaryProtocolT::readFieldEnd() { + return 0; +} + +template +uint32_t TBinaryProtocolT::readMapBegin(TType& keyType, + TType& valType, + uint32_t& size) { + int8_t k, v; + uint32_t result = 0; + int32_t sizei; + result += readByte(k); + keyType = (TType)k; + result += readByte(v); + valType = (TType)v; + result += readI32(sizei); + if (sizei < 0) { + throw TProtocolException(TProtocolException::NEGATIVE_SIZE); + } else if (this->container_limit_ && sizei > this->container_limit_) { + throw TProtocolException(TProtocolException::SIZE_LIMIT); + } + size = (uint32_t)sizei; + + TMap map(keyType, valType, size); + checkReadBytesAvailable(map); + + return result; +} + +template +uint32_t TBinaryProtocolT::readMapEnd() { + return 0; +} + +template +uint32_t TBinaryProtocolT::readListBegin(TType& elemType, uint32_t& size) { + int8_t e; + uint32_t result = 0; + int32_t sizei; + result += readByte(e); + elemType = (TType)e; + result += readI32(sizei); + if (sizei < 0) { + throw TProtocolException(TProtocolException::NEGATIVE_SIZE); + } else if (this->container_limit_ && sizei > this->container_limit_) { + throw TProtocolException(TProtocolException::SIZE_LIMIT); + } + size = (uint32_t)sizei; + + TList list(elemType, size); + checkReadBytesAvailable(list); + + return result; +} + +template +uint32_t TBinaryProtocolT::readListEnd() { + return 0; +} + +template +uint32_t TBinaryProtocolT::readSetBegin(TType& elemType, uint32_t& size) { + int8_t e; + uint32_t result = 0; + int32_t sizei; + result += readByte(e); + elemType = (TType)e; + result += readI32(sizei); + if (sizei < 0) { + throw TProtocolException(TProtocolException::NEGATIVE_SIZE); + } else if (this->container_limit_ && sizei > this->container_limit_) { + throw TProtocolException(TProtocolException::SIZE_LIMIT); + } + size = (uint32_t)sizei; + + TSet set(elemType, size); + checkReadBytesAvailable(set); + + return result; +} + +template +uint32_t TBinaryProtocolT::readSetEnd() { + return 0; +} + +template +uint32_t TBinaryProtocolT::readBool(bool& value) { + uint8_t b[1]; + this->trans_->readAll(b, 1); + value = *(int8_t*)b != 0; + return 1; +} + +template +uint32_t TBinaryProtocolT::readByte(int8_t& byte) { + uint8_t b[1]; + this->trans_->readAll(b, 1); + byte = *(int8_t*)b; + return 1; +} + +template +uint32_t TBinaryProtocolT::readI16(int16_t& i16) { + union bytes { + uint8_t b[2]; + int16_t all; + } theBytes; + this->trans_->readAll(theBytes.b, 2); + i16 = (int16_t)ByteOrder_::fromWire16(theBytes.all); + return 2; +} + +template +uint32_t TBinaryProtocolT::readI32(int32_t& i32) { + union bytes { + uint8_t b[4]; + int32_t all; + } theBytes; + this->trans_->readAll(theBytes.b, 4); + i32 = (int32_t)ByteOrder_::fromWire32(theBytes.all); + return 4; +} + +template +uint32_t TBinaryProtocolT::readI64(int64_t& i64) { + union bytes { + uint8_t b[8]; + int64_t all; + } theBytes; + this->trans_->readAll(theBytes.b, 8); + i64 = (int64_t)ByteOrder_::fromWire64(theBytes.all); + return 8; +} + +template +uint32_t TBinaryProtocolT::readDouble(double& dub) { + static_assert(sizeof(double) == sizeof(uint64_t), "sizeof(double) == sizeof(uint64_t)"); + static_assert(std::numeric_limits::is_iec559, "std::numeric_limits::is_iec559"); + + union bytes { + uint8_t b[8]; + uint64_t all; + } theBytes; + this->trans_->readAll(theBytes.b, 8); + theBytes.all = ByteOrder_::fromWire64(theBytes.all); + dub = bitwise_cast(theBytes.all); + return 8; +} + +template +template +uint32_t TBinaryProtocolT::readString(StrType& str) { + uint32_t result; + int32_t size; + result = readI32(size); + return result + readStringBody(str, size); +} + +template +uint32_t TBinaryProtocolT::readBinary(std::string& str) { + return TBinaryProtocolT::readString(str); +} + +template +template +uint32_t TBinaryProtocolT::readStringBody(StrType& str, int32_t size) { + uint32_t result = 0; + + // Catch error cases + if (size < 0) { + throw TProtocolException(TProtocolException::NEGATIVE_SIZE); + } + if (this->string_limit_ > 0 && size > this->string_limit_) { + throw TProtocolException(TProtocolException::SIZE_LIMIT); + } + + // Catch empty string case + if (size == 0) { + str.clear(); + return result; + } + + // Try to borrow first + const uint8_t* borrow_buf; + uint32_t got = size; + if ((borrow_buf = this->trans_->borrow(nullptr, &got))) { + str.assign((const char*)borrow_buf, size); + this->trans_->consume(size); + return size; + } + + str.resize(size); + this->trans_->readAll(reinterpret_cast(&str[0]), size); + return (uint32_t)size; +} + +// Return the minimum number of bytes a type will consume on the wire +template +int TBinaryProtocolT::getMinSerializedSize(TType type) +{ + switch (type) + { + case T_STOP: return 0; + case T_VOID: return 0; + case T_BOOL: return sizeof(int8_t); + case T_BYTE: return sizeof(int8_t); + case T_DOUBLE: return sizeof(double); + case T_I16: return sizeof(short); + case T_I32: return sizeof(int); + case T_I64: return sizeof(long); + case T_STRING: return sizeof(int); // string length + case T_STRUCT: return 0; // empty struct + case T_MAP: return sizeof(int); // element count + case T_SET: return sizeof(int); // element count + case T_LIST: return sizeof(int); // element count + default: throw TProtocolException(TProtocolException::UNKNOWN, "unrecognized type code"); + } +} + +} +} +} // apache::thrift::protocol + +#endif // #ifndef _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_ diff --git a/bsnes/thrift/thrift/protocol/TCompactProtocol.h b/bsnes/thrift/thrift/protocol/TCompactProtocol.h new file mode 100644 index 00000000..6f990b2d --- /dev/null +++ b/bsnes/thrift/thrift/protocol/TCompactProtocol.h @@ -0,0 +1,284 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_PROTOCOL_TCOMPACTPROTOCOL_H_ +#define _THRIFT_PROTOCOL_TCOMPACTPROTOCOL_H_ 1 + +#include + +#include +#include + +namespace apache { +namespace thrift { +namespace protocol { + +/** + * C++ Implementation of the Compact Protocol as described in THRIFT-110 + */ +template +class TCompactProtocolT : public TVirtualProtocol > { +public: + static const int8_t PROTOCOL_ID = (int8_t)0x82u; + static const int8_t VERSION_N = 1; + static const int8_t VERSION_MASK = 0x1f; // 0001 1111 + +protected: + static const int8_t TYPE_MASK = (int8_t)0xE0u; // 1110 0000 + static const int8_t TYPE_BITS = 0x07; // 0000 0111 + static const int32_t TYPE_SHIFT_AMOUNT = 5; + + Transport_* trans_; + + /** + * (Writing) If we encounter a boolean field begin, save the TField here + * so it can have the value incorporated. + */ + struct { + const char* name; + TType fieldType; + int16_t fieldId; + } booleanField_; + + /** + * (Reading) If we read a field header, and it's a boolean field, save + * the boolean value here so that readBool can use it. + */ + struct { + bool hasBoolValue; + bool boolValue; + } boolValue_; + + /** + * Used to keep track of the last field for the current and previous structs, + * so we can do the delta stuff. + */ + + std::stack lastField_; + int16_t lastFieldId_; + +public: + TCompactProtocolT(std::shared_ptr trans) + : TVirtualProtocol >(trans), + trans_(trans.get()), + lastFieldId_(0), + string_limit_(0), + string_buf_(nullptr), + string_buf_size_(0), + container_limit_(0) { + booleanField_.name = nullptr; + boolValue_.hasBoolValue = false; + } + + TCompactProtocolT(std::shared_ptr trans, + int32_t string_limit, + int32_t container_limit) + : TVirtualProtocol >(trans), + trans_(trans.get()), + lastFieldId_(0), + string_limit_(string_limit), + string_buf_(nullptr), + string_buf_size_(0), + container_limit_(container_limit) { + booleanField_.name = nullptr; + boolValue_.hasBoolValue = false; + } + + ~TCompactProtocolT() override { free(string_buf_); } + + /** + * Writing functions + */ + + virtual uint32_t writeMessageBegin(const std::string& name, + const TMessageType messageType, + const int32_t seqid); + + uint32_t writeStructBegin(const char* name); + + uint32_t writeStructEnd(); + + uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId); + + uint32_t writeFieldStop(); + + uint32_t writeListBegin(const TType elemType, const uint32_t size); + + uint32_t writeSetBegin(const TType elemType, const uint32_t size); + + virtual uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size); + + uint32_t writeBool(const bool value); + + uint32_t writeByte(const int8_t byte); + + uint32_t writeI16(const int16_t i16); + + uint32_t writeI32(const int32_t i32); + + uint32_t writeI64(const int64_t i64); + + uint32_t writeDouble(const double dub); + + uint32_t writeString(const std::string& str); + + uint32_t writeBinary(const std::string& str); + + int getMinSerializedSize(TType type); + + void checkReadBytesAvailable(TSet& set) + { + trans_->checkReadBytesAvailable(set.size_ * getMinSerializedSize(set.elemType_)); + } + + void checkReadBytesAvailable(TList& list) + { + trans_->checkReadBytesAvailable(list.size_ * getMinSerializedSize(list.elemType_)); + } + + void checkReadBytesAvailable(TMap& map) + { + int elmSize = getMinSerializedSize(map.keyType_) + getMinSerializedSize(map.valueType_); + trans_->checkReadBytesAvailable(map.size_ * elmSize); + } + + /** + * These methods are called by structs, but don't actually have any wired + * output or purpose + */ + virtual uint32_t writeMessageEnd() { return 0; } + uint32_t writeMapEnd() { return 0; } + uint32_t writeListEnd() { return 0; } + uint32_t writeSetEnd() { return 0; } + uint32_t writeFieldEnd() { return 0; } + +protected: + int32_t writeFieldBeginInternal(const char* name, + const TType fieldType, + const int16_t fieldId, + int8_t typeOverride); + uint32_t writeCollectionBegin(const TType elemType, int32_t size); + uint32_t writeVarint32(uint32_t n); + uint32_t writeVarint64(uint64_t n); + uint64_t i64ToZigzag(const int64_t l); + uint32_t i32ToZigzag(const int32_t n); + inline int8_t getCompactType(const TType ttype); + +public: + uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid); + + uint32_t readStructBegin(std::string& name); + + uint32_t readStructEnd(); + + uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId); + + uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size); + + uint32_t readListBegin(TType& elemType, uint32_t& size); + + uint32_t readSetBegin(TType& elemType, uint32_t& size); + + uint32_t readBool(bool& value); + // Provide the default readBool() implementation for std::vector + using TVirtualProtocol >::readBool; + + uint32_t readByte(int8_t& byte); + + uint32_t readI16(int16_t& i16); + + uint32_t readI32(int32_t& i32); + + uint32_t readI64(int64_t& i64); + + uint32_t readDouble(double& dub); + + uint32_t readString(std::string& str); + + uint32_t readBinary(std::string& str); + + /* + *These methods are here for the struct to call, but don't have any wire + * encoding. + */ + uint32_t readMessageEnd() { return 0; } + uint32_t readFieldEnd() { return 0; } + uint32_t readMapEnd() { return 0; } + uint32_t readListEnd() { return 0; } + uint32_t readSetEnd() { return 0; } + +protected: + uint32_t readVarint32(int32_t& i32); + uint32_t readVarint64(int64_t& i64); + int32_t zigzagToI32(uint32_t n); + int64_t zigzagToI64(uint64_t n); + TType getTType(int8_t type); + + // Buffer for reading strings, save for the lifetime of the protocol to + // avoid memory churn allocating memory on every string read + int32_t string_limit_; + uint8_t* string_buf_; + int32_t string_buf_size_; + int32_t container_limit_; +}; + +typedef TCompactProtocolT TCompactProtocol; + +/** + * Constructs compact protocol handlers + */ +template +class TCompactProtocolFactoryT : public TProtocolFactory { +public: + TCompactProtocolFactoryT() : string_limit_(0), container_limit_(0) {} + + TCompactProtocolFactoryT(int32_t string_limit, int32_t container_limit) + : string_limit_(string_limit), container_limit_(container_limit) {} + + ~TCompactProtocolFactoryT() override = default; + + void setStringSizeLimit(int32_t string_limit) { string_limit_ = string_limit; } + + void setContainerSizeLimit(int32_t container_limit) { container_limit_ = container_limit; } + + std::shared_ptr getProtocol(std::shared_ptr trans) override { + std::shared_ptr specific_trans = std::dynamic_pointer_cast(trans); + TProtocol* prot; + if (specific_trans) { + prot = new TCompactProtocolT(specific_trans, string_limit_, container_limit_); + } else { + prot = new TCompactProtocol(trans, string_limit_, container_limit_); + } + + return std::shared_ptr(prot); + } + +private: + int32_t string_limit_; + int32_t container_limit_; +}; + +typedef TCompactProtocolFactoryT TCompactProtocolFactory; +} +} +} // apache::thrift::protocol + +#include + +#endif diff --git a/bsnes/thrift/thrift/protocol/TCompactProtocol.tcc b/bsnes/thrift/thrift/protocol/TCompactProtocol.tcc new file mode 100644 index 00000000..16780911 --- /dev/null +++ b/bsnes/thrift/thrift/protocol/TCompactProtocol.tcc @@ -0,0 +1,858 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#ifndef _THRIFT_PROTOCOL_TCOMPACTPROTOCOL_TCC_ +#define _THRIFT_PROTOCOL_TCOMPACTPROTOCOL_TCC_ 1 + +#include + +#include "thrift/config.h" + +/* + * TCompactProtocol::i*ToZigzag depend on the fact that the right shift + * operator on a signed integer is an arithmetic (sign-extending) shift. + * If this is not the case, the current implementation will not work. + * If anyone encounters this error, we can try to figure out the best + * way to implement an arithmetic right shift on their platform. + */ +#if !defined(SIGNED_RIGHT_SHIFT_IS) || !defined(ARITHMETIC_RIGHT_SHIFT) +# error "Unable to determine the behavior of a signed right shift" +#endif +#if SIGNED_RIGHT_SHIFT_IS != ARITHMETIC_RIGHT_SHIFT +# error "TCompactProtocol currently only works if a signed right shift is arithmetic" +#endif + +#ifdef __GNUC__ +#define UNLIKELY(val) (__builtin_expect((val), 0)) +#else +#define UNLIKELY(val) (val) +#endif + +namespace apache { namespace thrift { namespace protocol { + +namespace detail { namespace compact { + +enum Types { + CT_STOP = 0x00, + CT_BOOLEAN_TRUE = 0x01, + CT_BOOLEAN_FALSE = 0x02, + CT_BYTE = 0x03, + CT_I16 = 0x04, + CT_I32 = 0x05, + CT_I64 = 0x06, + CT_DOUBLE = 0x07, + CT_BINARY = 0x08, + CT_LIST = 0x09, + CT_SET = 0x0A, + CT_MAP = 0x0B, + CT_STRUCT = 0x0C +}; + +const int8_t TTypeToCType[16] = { + CT_STOP, // T_STOP + 0, // unused + CT_BOOLEAN_TRUE, // T_BOOL + CT_BYTE, // T_BYTE + CT_DOUBLE, // T_DOUBLE + 0, // unused + CT_I16, // T_I16 + 0, // unused + CT_I32, // T_I32 + 0, // unused + CT_I64, // T_I64 + CT_BINARY, // T_STRING + CT_STRUCT, // T_STRUCT + CT_MAP, // T_MAP + CT_SET, // T_SET + CT_LIST, // T_LIST +}; + +}} // end detail::compact namespace + + +template +uint32_t TCompactProtocolT::writeMessageBegin( + const std::string& name, + const TMessageType messageType, + const int32_t seqid) { + uint32_t wsize = 0; + wsize += writeByte(PROTOCOL_ID); + wsize += writeByte((VERSION_N & VERSION_MASK) | (((int32_t)messageType << TYPE_SHIFT_AMOUNT) & TYPE_MASK)); + wsize += writeVarint32(seqid); + wsize += writeString(name); + return wsize; +} + +/** + * Write a field header containing the field id and field type. If the + * difference between the current field id and the last one is small (< 15), + * then the field id will be encoded in the 4 MSB as a delta. Otherwise, the + * field id will follow the type header as a zigzag varint. + */ +template +uint32_t TCompactProtocolT::writeFieldBegin(const char* name, + const TType fieldType, + const int16_t fieldId) { + if (fieldType == T_BOOL) { + booleanField_.name = name; + booleanField_.fieldType = fieldType; + booleanField_.fieldId = fieldId; + } else { + return writeFieldBeginInternal(name, fieldType, fieldId, -1); + } + return 0; +} + +/** + * Write the STOP symbol so we know there are no more fields in this struct. + */ +template +uint32_t TCompactProtocolT::writeFieldStop() { + return writeByte(T_STOP); +} + +/** + * Write a struct begin. This doesn't actually put anything on the wire. We + * use it as an opportunity to put special placeholder markers on the field + * stack so we can get the field id deltas correct. + */ +template +uint32_t TCompactProtocolT::writeStructBegin(const char* name) { + (void) name; + lastField_.push(lastFieldId_); + lastFieldId_ = 0; + return 0; +} + +/** + * Write a struct end. This doesn't actually put anything on the wire. We use + * this as an opportunity to pop the last field from the current struct off + * of the field stack. + */ +template +uint32_t TCompactProtocolT::writeStructEnd() { + lastFieldId_ = lastField_.top(); + lastField_.pop(); + return 0; +} + +/** + * Write a List header. + */ +template +uint32_t TCompactProtocolT::writeListBegin(const TType elemType, + const uint32_t size) { + return writeCollectionBegin(elemType, size); +} + +/** + * Write a set header. + */ +template +uint32_t TCompactProtocolT::writeSetBegin(const TType elemType, + const uint32_t size) { + return writeCollectionBegin(elemType, size); +} + +/** + * Write a map header. If the map is empty, omit the key and value type + * headers, as we don't need any additional information to skip it. + */ +template +uint32_t TCompactProtocolT::writeMapBegin(const TType keyType, + const TType valType, + const uint32_t size) { + uint32_t wsize = 0; + + if (size == 0) { + wsize += writeByte(0); + } else { + wsize += writeVarint32(size); + wsize += writeByte(getCompactType(keyType) << 4 | getCompactType(valType)); + } + return wsize; +} + +/** + * Write a boolean value. Potentially, this could be a boolean field, in + * which case the field header info isn't written yet. If so, decide what the + * right type header is for the value and then write the field header. + * Otherwise, write a single byte. + */ +template +uint32_t TCompactProtocolT::writeBool(const bool value) { + uint32_t wsize = 0; + + if (booleanField_.name != nullptr) { + // we haven't written the field header yet + wsize + += writeFieldBeginInternal(booleanField_.name, + booleanField_.fieldType, + booleanField_.fieldId, + static_cast(value + ? detail::compact::CT_BOOLEAN_TRUE + : detail::compact::CT_BOOLEAN_FALSE)); + booleanField_.name = nullptr; + } else { + // we're not part of a field, so just write the value + wsize + += writeByte(static_cast(value + ? detail::compact::CT_BOOLEAN_TRUE + : detail::compact::CT_BOOLEAN_FALSE)); + } + return wsize; +} + +template +uint32_t TCompactProtocolT::writeByte(const int8_t byte) { + trans_->write((uint8_t*)&byte, 1); + return 1; +} + +/** + * Write an i16 as a zigzag varint. + */ +template +uint32_t TCompactProtocolT::writeI16(const int16_t i16) { + return writeVarint32(i32ToZigzag(i16)); +} + +/** + * Write an i32 as a zigzag varint. + */ +template +uint32_t TCompactProtocolT::writeI32(const int32_t i32) { + return writeVarint32(i32ToZigzag(i32)); +} + +/** + * Write an i64 as a zigzag varint. + */ +template +uint32_t TCompactProtocolT::writeI64(const int64_t i64) { + return writeVarint64(i64ToZigzag(i64)); +} + +/** + * Write a double to the wire as 8 bytes. + */ +template +uint32_t TCompactProtocolT::writeDouble(const double dub) { + static_assert(sizeof(double) == sizeof(uint64_t), "sizeof(double) == sizeof(uint64_t)"); + static_assert(std::numeric_limits::is_iec559, "std::numeric_limits::is_iec559"); + + auto bits = bitwise_cast(dub); + bits = THRIFT_htolell(bits); + trans_->write((uint8_t*)&bits, 8); + return 8; +} + +/** + * Write a string to the wire with a varint size preceding. + */ +template +uint32_t TCompactProtocolT::writeString(const std::string& str) { + return writeBinary(str); +} + +template +uint32_t TCompactProtocolT::writeBinary(const std::string& str) { + if(str.size() > (std::numeric_limits::max)()) + throw TProtocolException(TProtocolException::SIZE_LIMIT); + auto ssize = static_cast(str.size()); + uint32_t wsize = writeVarint32(ssize) ; + // checking ssize + wsize > uint_max, but we don't want to overflow while checking for overflows. + // transforming the check to ssize > uint_max - wsize + if(ssize > (std::numeric_limits::max)() - wsize) + throw TProtocolException(TProtocolException::SIZE_LIMIT); + wsize += ssize; + trans_->write((uint8_t*)str.data(), ssize); + return wsize; +} + +// +// Internal Writing methods +// + +/** + * The workhorse of writeFieldBegin. It has the option of doing a + * 'type override' of the type header. This is used specifically in the + * boolean field case. + */ +template +int32_t TCompactProtocolT::writeFieldBeginInternal( + const char* name, + const TType fieldType, + const int16_t fieldId, + int8_t typeOverride) { + (void) name; + uint32_t wsize = 0; + + // if there's a type override, use that. + int8_t typeToWrite = (typeOverride == -1 ? getCompactType(fieldType) : typeOverride); + + // check if we can use delta encoding for the field id + if (fieldId > lastFieldId_ && fieldId - lastFieldId_ <= 15) { + // write them together + wsize += writeByte(static_cast((fieldId - lastFieldId_) + << 4 | typeToWrite)); + } else { + // write them separate + wsize += writeByte(typeToWrite); + wsize += writeI16(fieldId); + } + + lastFieldId_ = fieldId; + return wsize; +} + +/** + * Abstract method for writing the start of lists and sets. List and sets on + * the wire differ only by the type indicator. + */ +template +uint32_t TCompactProtocolT::writeCollectionBegin(const TType elemType, + int32_t size) { + uint32_t wsize = 0; + if (size <= 14) { + wsize += writeByte(static_cast(size + << 4 | getCompactType(elemType))); + } else { + wsize += writeByte(0xf0 | getCompactType(elemType)); + wsize += writeVarint32(size); + } + return wsize; +} + +/** + * Write an i32 as a varint. Results in 1-5 bytes on the wire. + */ +template +uint32_t TCompactProtocolT::writeVarint32(uint32_t n) { + uint8_t buf[5]; + uint32_t wsize = 0; + + while (true) { + if ((n & ~0x7F) == 0) { + buf[wsize++] = (int8_t)n; + break; + } else { + buf[wsize++] = (int8_t)((n & 0x7F) | 0x80); + n >>= 7; + } + } + trans_->write(buf, wsize); + return wsize; +} + +/** + * Write an i64 as a varint. Results in 1-10 bytes on the wire. + */ +template +uint32_t TCompactProtocolT::writeVarint64(uint64_t n) { + uint8_t buf[10]; + uint32_t wsize = 0; + + while (true) { + if ((n & ~0x7FL) == 0) { + buf[wsize++] = (int8_t)n; + break; + } else { + buf[wsize++] = (int8_t)((n & 0x7F) | 0x80); + n >>= 7; + } + } + trans_->write(buf, wsize); + return wsize; +} + +/** + * Convert l into a zigzag long. This allows negative numbers to be + * represented compactly as a varint. + */ +template +uint64_t TCompactProtocolT::i64ToZigzag(const int64_t l) { + return (static_cast(l) << 1) ^ (l >> 63); +} + +/** + * Convert n into a zigzag int. This allows negative numbers to be + * represented compactly as a varint. + */ +template +uint32_t TCompactProtocolT::i32ToZigzag(const int32_t n) { + return (static_cast(n) << 1) ^ (n >> 31); +} + +/** + * Given a TType value, find the appropriate detail::compact::Types value + */ +template +int8_t TCompactProtocolT::getCompactType(const TType ttype) { + return detail::compact::TTypeToCType[ttype]; +} + +// +// Reading Methods +// + +/** + * Read a message header. + */ +template +uint32_t TCompactProtocolT::readMessageBegin( + std::string& name, + TMessageType& messageType, + int32_t& seqid) { + uint32_t rsize = 0; + int8_t protocolId; + int8_t versionAndType; + int8_t version; + + rsize += readByte(protocolId); + if (protocolId != PROTOCOL_ID) { + throw TProtocolException(TProtocolException::BAD_VERSION, "Bad protocol identifier"); + } + + rsize += readByte(versionAndType); + version = (int8_t)(versionAndType & VERSION_MASK); + if (version != VERSION_N) { + throw TProtocolException(TProtocolException::BAD_VERSION, "Bad protocol version"); + } + + messageType = (TMessageType)((versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS); + rsize += readVarint32(seqid); + rsize += readString(name); + + return rsize; +} + +/** + * Read a struct begin. There's nothing on the wire for this, but it is our + * opportunity to push a new struct begin marker on the field stack. + */ +template +uint32_t TCompactProtocolT::readStructBegin(std::string& name) { + name = ""; + lastField_.push(lastFieldId_); + lastFieldId_ = 0; + return 0; +} + +/** + * Doesn't actually consume any wire data, just removes the last field for + * this struct from the field stack. + */ +template +uint32_t TCompactProtocolT::readStructEnd() { + lastFieldId_ = lastField_.top(); + lastField_.pop(); + return 0; +} + +/** + * Read a field header off the wire. + */ +template +uint32_t TCompactProtocolT::readFieldBegin(std::string& name, + TType& fieldType, + int16_t& fieldId) { + (void) name; + uint32_t rsize = 0; + int8_t byte; + int8_t type; + + rsize += readByte(byte); + type = (byte & 0x0f); + + // if it's a stop, then we can return immediately, as the struct is over. + if (type == T_STOP) { + fieldType = T_STOP; + fieldId = 0; + return rsize; + } + + // mask off the 4 MSB of the type header. it could contain a field id delta. + auto modifier = (int16_t)(((uint8_t)byte & 0xf0) >> 4); + if (modifier == 0) { + // not a delta, look ahead for the zigzag varint field id. + rsize += readI16(fieldId); + } else { + fieldId = (int16_t)(lastFieldId_ + modifier); + } + fieldType = getTType(type); + + // if this happens to be a boolean field, the value is encoded in the type + if (type == detail::compact::CT_BOOLEAN_TRUE || + type == detail::compact::CT_BOOLEAN_FALSE) { + // save the boolean value in a special instance variable. + boolValue_.hasBoolValue = true; + boolValue_.boolValue = + (type == detail::compact::CT_BOOLEAN_TRUE ? true : false); + } + + // push the new field onto the field stack so we can keep the deltas going. + lastFieldId_ = fieldId; + return rsize; +} + +/** + * Read a map header off the wire. If the size is zero, skip reading the key + * and value type. This means that 0-length maps will yield TMaps without the + * "correct" types. + */ +template +uint32_t TCompactProtocolT::readMapBegin(TType& keyType, + TType& valType, + uint32_t& size) { + uint32_t rsize = 0; + int8_t kvType = 0; + int32_t msize = 0; + + rsize += readVarint32(msize); + if (msize != 0) + rsize += readByte(kvType); + + if (msize < 0) { + throw TProtocolException(TProtocolException::NEGATIVE_SIZE); + } else if (container_limit_ && msize > container_limit_) { + throw TProtocolException(TProtocolException::SIZE_LIMIT); + } + + keyType = getTType((int8_t)((uint8_t)kvType >> 4)); + valType = getTType((int8_t)((uint8_t)kvType & 0xf)); + size = (uint32_t)msize; + + TMap map(keyType, valType, size); + checkReadBytesAvailable(map); + + return rsize; +} + +/** + * Read a list header off the wire. If the list size is 0-14, the size will + * be packed into the element type header. If it's a longer list, the 4 MSB + * of the element type header will be 0xF, and a varint will follow with the + * true size. + */ +template +uint32_t TCompactProtocolT::readListBegin(TType& elemType, + uint32_t& size) { + int8_t size_and_type; + uint32_t rsize = 0; + int32_t lsize; + + rsize += readByte(size_and_type); + + lsize = ((uint8_t)size_and_type >> 4) & 0x0f; + if (lsize == 15) { + rsize += readVarint32(lsize); + } + + if (lsize < 0) { + throw TProtocolException(TProtocolException::NEGATIVE_SIZE); + } else if (container_limit_ && lsize > container_limit_) { + throw TProtocolException(TProtocolException::SIZE_LIMIT); + } + + elemType = getTType((int8_t)(size_and_type & 0x0f)); + size = (uint32_t)lsize; + + TList list(elemType, size); + checkReadBytesAvailable(list); + + return rsize; +} + +/** + * Read a set header off the wire. If the set size is 0-14, the size will + * be packed into the element type header. If it's a longer set, the 4 MSB + * of the element type header will be 0xF, and a varint will follow with the + * true size. + */ +template +uint32_t TCompactProtocolT::readSetBegin(TType& elemType, + uint32_t& size) { + return readListBegin(elemType, size); +} + +/** + * Read a boolean off the wire. If this is a boolean field, the value should + * already have been read during readFieldBegin, so we'll just consume the + * pre-stored value. Otherwise, read a byte. + */ +template +uint32_t TCompactProtocolT::readBool(bool& value) { + if (boolValue_.hasBoolValue == true) { + value = boolValue_.boolValue; + boolValue_.hasBoolValue = false; + return 0; + } else { + int8_t val; + readByte(val); + value = (val == detail::compact::CT_BOOLEAN_TRUE); + return 1; + } +} + +/** + * Read a single byte off the wire. Nothing interesting here. + */ +template +uint32_t TCompactProtocolT::readByte(int8_t& byte) { + uint8_t b[1]; + trans_->readAll(b, 1); + byte = *(int8_t*)b; + return 1; +} + +/** + * Read an i16 from the wire as a zigzag varint. + */ +template +uint32_t TCompactProtocolT::readI16(int16_t& i16) { + int32_t value; + uint32_t rsize = readVarint32(value); + i16 = (int16_t)zigzagToI32(value); + return rsize; +} + +/** + * Read an i32 from the wire as a zigzag varint. + */ +template +uint32_t TCompactProtocolT::readI32(int32_t& i32) { + int32_t value; + uint32_t rsize = readVarint32(value); + i32 = zigzagToI32(value); + return rsize; +} + +/** + * Read an i64 from the wire as a zigzag varint. + */ +template +uint32_t TCompactProtocolT::readI64(int64_t& i64) { + int64_t value; + uint32_t rsize = readVarint64(value); + i64 = zigzagToI64(value); + return rsize; +} + +/** + * No magic here - just read a double off the wire. + */ +template +uint32_t TCompactProtocolT::readDouble(double& dub) { + static_assert(sizeof(double) == sizeof(uint64_t), "sizeof(double) == sizeof(uint64_t)"); + static_assert(std::numeric_limits::is_iec559, "std::numeric_limits::is_iec559"); + + union { + uint64_t bits; + uint8_t b[8]; + } u; + trans_->readAll(u.b, 8); + u.bits = THRIFT_letohll(u.bits); + dub = bitwise_cast(u.bits); + return 8; +} + +template +uint32_t TCompactProtocolT::readString(std::string& str) { + return readBinary(str); +} + +/** + * Read a byte[] from the wire. + */ +template +uint32_t TCompactProtocolT::readBinary(std::string& str) { + int32_t rsize = 0; + int32_t size; + + rsize += readVarint32(size); + // Catch empty string case + if (size == 0) { + str = ""; + return rsize; + } + + // Catch error cases + if (size < 0) { + throw TProtocolException(TProtocolException::NEGATIVE_SIZE); + } + if (string_limit_ > 0 && size > string_limit_) { + throw TProtocolException(TProtocolException::SIZE_LIMIT); + } + + // Use the heap here to prevent stack overflow for v. large strings + if (size > string_buf_size_ || string_buf_ == nullptr) { + void* new_string_buf = std::realloc(string_buf_, (uint32_t)size); + if (new_string_buf == nullptr) { + throw std::bad_alloc(); + } + string_buf_ = (uint8_t*)new_string_buf; + string_buf_size_ = size; + } + trans_->readAll(string_buf_, size); + str.assign((char*)string_buf_, size); + + trans_->checkReadBytesAvailable(rsize + (uint32_t)size); + + return rsize + (uint32_t)size; +} + +/** + * Read an i32 from the wire as a varint. The MSB of each byte is set + * if there is another byte to follow. This can read up to 5 bytes. + */ +template +uint32_t TCompactProtocolT::readVarint32(int32_t& i32) { + int64_t val; + uint32_t rsize = readVarint64(val); + i32 = (int32_t)val; + return rsize; +} + +/** + * Read an i64 from the wire as a proper varint. The MSB of each byte is set + * if there is another byte to follow. This can read up to 10 bytes. + */ +template +uint32_t TCompactProtocolT::readVarint64(int64_t& i64) { + uint32_t rsize = 0; + uint64_t val = 0; + int shift = 0; + uint8_t buf[10]; // 64 bits / (7 bits/byte) = 10 bytes. + uint32_t buf_size = sizeof(buf); + const uint8_t* borrowed = trans_->borrow(buf, &buf_size); + + // Fast path. + if (borrowed != nullptr) { + while (true) { + uint8_t byte = borrowed[rsize]; + rsize++; + val |= (uint64_t)(byte & 0x7f) << shift; + shift += 7; + if (!(byte & 0x80)) { + i64 = val; + trans_->consume(rsize); + return rsize; + } + // Have to check for invalid data so we don't crash. + if (UNLIKELY(rsize == sizeof(buf))) { + throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes."); + } + } + } + + // Slow path. + else { + while (true) { + uint8_t byte; + rsize += trans_->readAll(&byte, 1); + val |= (uint64_t)(byte & 0x7f) << shift; + shift += 7; + if (!(byte & 0x80)) { + i64 = val; + return rsize; + } + // Might as well check for invalid data on the slow path too. + if (UNLIKELY(rsize >= sizeof(buf))) { + throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes."); + } + } + } +} + +/** + * Convert from zigzag int to int. + */ +template +int32_t TCompactProtocolT::zigzagToI32(uint32_t n) { + return (n >> 1) ^ static_cast(-static_cast(n & 1)); +} + +/** + * Convert from zigzag long to long. + */ +template +int64_t TCompactProtocolT::zigzagToI64(uint64_t n) { + return (n >> 1) ^ static_cast(-static_cast(n & 1)); +} + +template +TType TCompactProtocolT::getTType(int8_t type) { + switch (type) { + case T_STOP: + return T_STOP; + case detail::compact::CT_BOOLEAN_FALSE: + case detail::compact::CT_BOOLEAN_TRUE: + return T_BOOL; + case detail::compact::CT_BYTE: + return T_BYTE; + case detail::compact::CT_I16: + return T_I16; + case detail::compact::CT_I32: + return T_I32; + case detail::compact::CT_I64: + return T_I64; + case detail::compact::CT_DOUBLE: + return T_DOUBLE; + case detail::compact::CT_BINARY: + return T_STRING; + case detail::compact::CT_LIST: + return T_LIST; + case detail::compact::CT_SET: + return T_SET; + case detail::compact::CT_MAP: + return T_MAP; + case detail::compact::CT_STRUCT: + return T_STRUCT; + default: + throw TException(std::string("don't know what type: ") + (char)type); + } +} + +// Return the minimum number of bytes a type will consume on the wire +template +int TCompactProtocolT::getMinSerializedSize(TType type) +{ + switch (type) + { + case T_STOP: return 0; + case T_VOID: return 0; + case T_BOOL: return sizeof(int8_t); + case T_DOUBLE: return 8; // uses fixedLongToBytes() which always writes 8 bytes + case T_BYTE: return sizeof(int8_t); + case T_I16: return sizeof(int8_t); // zigzag + case T_I32: return sizeof(int8_t); // zigzag + case T_I64: return sizeof(int8_t); // zigzag + case T_STRING: return sizeof(int8_t); // string length + case T_STRUCT: return 0; // empty struct + case T_MAP: return sizeof(int8_t); // element count + case T_SET: return sizeof(int8_t); // element count + case T_LIST: return sizeof(int8_t); // element count + default: throw TProtocolException(TProtocolException::UNKNOWN, "unrecognized type code"); + } +} + + +}}} // apache::thrift::protocol + +#endif // _THRIFT_PROTOCOL_TCOMPACTPROTOCOL_TCC_ diff --git a/bsnes/thrift/thrift/protocol/TDebugProtocol.h b/bsnes/thrift/thrift/protocol/TDebugProtocol.h new file mode 100644 index 00000000..41bb0d4e --- /dev/null +++ b/bsnes/thrift/thrift/protocol/TDebugProtocol.h @@ -0,0 +1,204 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_PROTOCOL_TDEBUGPROTOCOL_H_ +#define _THRIFT_PROTOCOL_TDEBUGPROTOCOL_H_ 1 + +#include + +#include + +namespace apache { +namespace thrift { +namespace protocol { + +/* + +!!! EXPERIMENTAL CODE !!! + +This protocol is very much a work in progress. +It doesn't handle many cases properly. +It throws exceptions in many cases. +It probably segfaults in many cases. +Bug reports and feature requests are welcome. +Complaints are not. :R + +*/ + +/** + * Protocol that prints the payload in a nice human-readable format. + * Reading from this protocol is not supported. + * + */ +class TDebugProtocol : public TVirtualProtocol { +private: + enum write_state_t { UNINIT, STRUCT, LIST, SET, MAP_KEY, MAP_VALUE }; + +public: + TDebugProtocol(std::shared_ptr trans) + : TVirtualProtocol(trans), + trans_(trans.get()), + string_limit_(DEFAULT_STRING_LIMIT), + string_prefix_size_(DEFAULT_STRING_PREFIX_SIZE) { + write_state_.push_back(UNINIT); + } + + static const int32_t DEFAULT_STRING_LIMIT = 256; + static const int32_t DEFAULT_STRING_PREFIX_SIZE = 16; + + void setStringSizeLimit(int32_t string_limit) { string_limit_ = string_limit; } + + void setStringPrefixSize(int32_t string_prefix_size) { string_prefix_size_ = string_prefix_size; } + + uint32_t writeMessageBegin(const std::string& name, + const TMessageType messageType, + const int32_t seqid); + + uint32_t writeMessageEnd(); + + uint32_t writeStructBegin(const char* name); + + uint32_t writeStructEnd(); + + uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId); + + uint32_t writeFieldEnd(); + + uint32_t writeFieldStop(); + + uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size); + + uint32_t writeMapEnd(); + + uint32_t writeListBegin(const TType elemType, const uint32_t size); + + uint32_t writeListEnd(); + + uint32_t writeSetBegin(const TType elemType, const uint32_t size); + + uint32_t writeSetEnd(); + + uint32_t writeBool(const bool value); + + uint32_t writeByte(const int8_t byte); + + uint32_t writeI16(const int16_t i16); + + uint32_t writeI32(const int32_t i32); + + uint32_t writeI64(const int64_t i64); + + uint32_t writeDouble(const double dub); + + uint32_t writeString(const std::string& str); + + uint32_t writeBinary(const std::string& str); + +private: + void indentUp(); + void indentDown(); + uint32_t writePlain(const std::string& str); + uint32_t writeIndented(const std::string& str); + uint32_t startItem(); + uint32_t endItem(); + uint32_t writeItem(const std::string& str); + + static std::string fieldTypeName(TType type); + + TTransport* trans_; + + int32_t string_limit_; + int32_t string_prefix_size_; + + std::string indent_str_; + static const int indent_inc = 2; + + std::vector write_state_; + std::vector list_idx_; +}; + +/** + * Constructs debug protocol handlers + */ +class TDebugProtocolFactory : public TProtocolFactory { +public: + TDebugProtocolFactory() = default; + ~TDebugProtocolFactory() override = default; + + std::shared_ptr getProtocol(std::shared_ptr trans) override { + return std::shared_ptr(new TDebugProtocol(trans)); + } +}; +} +} +} // apache::thrift::protocol + +// TODO(dreiss): Move (part of) ThriftDebugString into a .cpp file and remove this. +#include + +namespace apache { +namespace thrift { + +template +std::string ThriftDebugString(const ThriftStruct& ts) { + using namespace apache::thrift::transport; + using namespace apache::thrift::protocol; + auto* buffer = new TMemoryBuffer; + std::shared_ptr trans(buffer); + TDebugProtocol protocol(trans); + + ts.write(&protocol); + + uint8_t* buf; + uint32_t size; + buffer->getBuffer(&buf, &size); + return std::string((char*)buf, (unsigned int)size); +} + +// TODO(dreiss): This is badly broken. Don't use it unless you are me. +#if 0 +template +std::string DebugString(const std::vector& vec) { + using namespace apache::thrift::transport; + using namespace apache::thrift::protocol; + TMemoryBuffer* buffer = new TMemoryBuffer; + std::shared_ptr trans(buffer); + TDebugProtocol protocol(trans); + + // I am gross! + protocol.writeStructBegin("SomeRandomVector"); + + // TODO: Fix this with a trait. + protocol.writeListBegin((TType)99, vec.size()); + typename std::vector::const_iterator it; + for (it = vec.begin(); it != vec.end(); ++it) { + it->write(&protocol); + } + protocol.writeListEnd(); + + uint8_t* buf; + uint32_t size; + buffer->getBuffer(&buf, &size); + return std::string((char*)buf, (unsigned int)size); +} +#endif // 0 +} +} // apache::thrift + +#endif // #ifndef _THRIFT_PROTOCOL_TDEBUGPROTOCOL_H_ diff --git a/bsnes/thrift/thrift/protocol/TEnum.h b/bsnes/thrift/thrift/protocol/TEnum.h new file mode 100644 index 00000000..9636785e --- /dev/null +++ b/bsnes/thrift/thrift/protocol/TEnum.h @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_ENUM_H_ +#define _THRIFT_ENUM_H_ + +namespace apache { +namespace thrift { +namespace protocol { + +/** + * Enumerated definition of the types that the Thrift protocol supports. + * Take special note of the T_END type which is used specifically to mark + * the end of a sequence of fields. + */ +enum TType { + T_STOP = 0, + T_VOID = 1, + T_BOOL = 2, + T_BYTE = 3, + T_I08 = 3, + T_I16 = 6, + T_I32 = 8, + T_U64 = 9, + T_I64 = 10, + T_DOUBLE = 4, + T_STRING = 11, + T_UTF7 = 11, + T_STRUCT = 12, + T_MAP = 13, + T_SET = 14, + T_LIST = 15, + T_UTF8 = 16, + T_UTF16 = 17 +}; + +/** + * Enumerated definition of the message types that the Thrift protocol + * supports. + */ +enum TMessageType { + T_CALL = 1, + T_REPLY = 2, + T_EXCEPTION = 3, + T_ONEWAY = 4 +}; + +}}} // apache::thrift::protocol + +#endif // #define _THRIFT_ENUM_H_ diff --git a/bsnes/thrift/thrift/protocol/THeaderProtocol.h b/bsnes/thrift/thrift/protocol/THeaderProtocol.h new file mode 100644 index 00000000..0d501859 --- /dev/null +++ b/bsnes/thrift/thrift/protocol/THeaderProtocol.h @@ -0,0 +1,210 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef THRIFT_PROTOCOL_THEADERPROTOCOL_H_ +#define THRIFT_PROTOCOL_THEADERPROTOCOL_H_ 1 + +#include +#include +#include +#include + +#include + +using apache::thrift::transport::THeaderTransport; + +namespace apache { +namespace thrift { +namespace protocol { + +/** + * The header protocol for thrift. Reads unframed, framed, header format, + * and http + * + */ +class THeaderProtocol : public TVirtualProtocol { +protected: +public: + void resetProtocol(); + + explicit THeaderProtocol(const std::shared_ptr& trans, + uint16_t protoId = T_COMPACT_PROTOCOL) + : TVirtualProtocol(std::shared_ptr(new THeaderTransport(trans))), + trans_(std::dynamic_pointer_cast(getTransport())), + protoId_(protoId) { + trans_->setProtocolId(protoId); + resetProtocol(); + } + + THeaderProtocol(const std::shared_ptr& inTrans, + const std::shared_ptr& outTrans, + uint16_t protoId = T_COMPACT_PROTOCOL) + : TVirtualProtocol( + std::shared_ptr(new THeaderTransport(inTrans, outTrans))), + trans_(std::dynamic_pointer_cast(getTransport())), + protoId_(protoId) { + trans_->setProtocolId(protoId); + resetProtocol(); + } + + ~THeaderProtocol() override = default; + + /** + * Functions to work with headers by calling into THeaderTransport + */ + void setProtocolId(uint16_t protoId) { + trans_->setProtocolId(protoId); + resetProtocol(); + } + + typedef THeaderTransport::StringToStringMap StringToStringMap; + + // these work with write headers + void setHeader(const std::string& key, const std::string& value) { + trans_->setHeader(key, value); + } + + void clearHeaders() { trans_->clearHeaders(); } + + StringToStringMap& getWriteHeaders() { return trans_->getWriteHeaders(); } + + // these work with read headers + const StringToStringMap& getHeaders() const { return trans_->getHeaders(); } + + /** + * Writing functions. + */ + + /*ol*/ uint32_t writeMessageBegin(const std::string& name, + const TMessageType messageType, + const int32_t seqId); + + /*ol*/ uint32_t writeMessageEnd(); + + uint32_t writeStructBegin(const char* name); + + uint32_t writeStructEnd(); + + uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId); + + uint32_t writeFieldEnd(); + + uint32_t writeFieldStop(); + + uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size); + + uint32_t writeMapEnd(); + + uint32_t writeListBegin(const TType elemType, const uint32_t size); + + uint32_t writeListEnd(); + + uint32_t writeSetBegin(const TType elemType, const uint32_t size); + + uint32_t writeSetEnd(); + + uint32_t writeBool(const bool value); + + uint32_t writeByte(const int8_t byte); + + uint32_t writeI16(const int16_t i16); + + uint32_t writeI32(const int32_t i32); + + uint32_t writeI64(const int64_t i64); + + uint32_t writeDouble(const double dub); + + uint32_t writeString(const std::string& str); + + uint32_t writeBinary(const std::string& str); + + /** + * Reading functions + */ + + /*ol*/ uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqId); + + /*ol*/ uint32_t readMessageEnd(); + + uint32_t readStructBegin(std::string& name); + + uint32_t readStructEnd(); + + uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId); + + uint32_t readFieldEnd(); + + uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size); + + uint32_t readMapEnd(); + + uint32_t readListBegin(TType& elemType, uint32_t& size); + + uint32_t readListEnd(); + + uint32_t readSetBegin(TType& elemType, uint32_t& size); + + uint32_t readSetEnd(); + + uint32_t readBool(bool& value); + // Provide the default readBool() implementation for std::vector + using TVirtualProtocol::readBool; + + uint32_t readByte(int8_t& byte); + + uint32_t readI16(int16_t& i16); + + uint32_t readI32(int32_t& i32); + + uint32_t readI64(int64_t& i64); + + uint32_t readDouble(double& dub); + + uint32_t readString(std::string& str); + + uint32_t readBinary(std::string& binary); + +protected: + std::shared_ptr trans_; + + std::shared_ptr proto_; + uint32_t protoId_; +}; + +class THeaderProtocolFactory : public TProtocolFactory { +public: + std::shared_ptr getProtocol(std::shared_ptr trans) override { + auto* headerProtocol + = new THeaderProtocol(trans, trans, T_BINARY_PROTOCOL); + return std::shared_ptr(headerProtocol); + } + + std::shared_ptr getProtocol( + std::shared_ptr inTrans, + std::shared_ptr outTrans) override { + auto* headerProtocol = new THeaderProtocol(inTrans, outTrans, T_BINARY_PROTOCOL); + return std::shared_ptr(headerProtocol); + } +}; +} +} +} // apache::thrift::protocol + +#endif // #ifndef THRIFT_PROTOCOL_THEADERPROTOCOL_H_ diff --git a/bsnes/thrift/thrift/protocol/TJSONProtocol.h b/bsnes/thrift/thrift/protocol/TJSONProtocol.h new file mode 100644 index 00000000..e775240a --- /dev/null +++ b/bsnes/thrift/thrift/protocol/TJSONProtocol.h @@ -0,0 +1,343 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_PROTOCOL_TJSONPROTOCOL_H_ +#define _THRIFT_PROTOCOL_TJSONPROTOCOL_H_ 1 + +#include + +#include + +namespace apache { +namespace thrift { +namespace protocol { + +// Forward declaration +class TJSONContext; + +/** + * JSON protocol for Thrift. + * + * Implements a protocol which uses JSON as the wire-format. + * + * Thrift types are represented as described below: + * + * 1. Every Thrift integer type is represented as a JSON number. + * + * 2. Thrift doubles are represented as JSON numbers. Some special values are + * represented as strings: + * a. "NaN" for not-a-number values + * b. "Infinity" for positive infinity + * c. "-Infinity" for negative infinity + * + * 3. Thrift string values are emitted as JSON strings, with appropriate + * escaping. + * + * 4. Thrift binary values are encoded into Base64 and emitted as JSON strings. + * The readBinary() method is written such that it will properly skip if + * called on a Thrift string (although it will decode garbage data). + * + * NOTE: Base64 padding is optional for Thrift binary value encoding. So + * the readBinary() method needs to decode both input strings with padding + * and those without one. + * + * 5. Thrift structs are represented as JSON objects, with the field ID as the + * key, and the field value represented as a JSON object with a single + * key-value pair. The key is a short string identifier for that type, + * followed by the value. The valid type identifiers are: "tf" for bool, + * "i8" for byte, "i16" for 16-bit integer, "i32" for 32-bit integer, "i64" + * for 64-bit integer, "dbl" for double-precision loating point, "str" for + * string (including binary), "rec" for struct ("records"), "map" for map, + * "lst" for list, "set" for set. + * + * 6. Thrift lists and sets are represented as JSON arrays, with the first + * element of the JSON array being the string identifier for the Thrift + * element type and the second element of the JSON array being the count of + * the Thrift elements. The Thrift elements then follow. + * + * 7. Thrift maps are represented as JSON arrays, with the first two elements + * of the JSON array being the string identifiers for the Thrift key type + * and value type, followed by the count of the Thrift pairs, followed by a + * JSON object containing the key-value pairs. Note that JSON keys can only + * be strings, which means that the key type of the Thrift map should be + * restricted to numeric or string types -- in the case of numerics, they + * are serialized as strings. + * + * 8. Thrift messages are represented as JSON arrays, with the protocol + * version #, the message name, the message type, and the sequence ID as + * the first 4 elements. + * + * More discussion of the double handling is probably warranted. The aim of + * the current implementation is to match as closely as possible the behavior + * of Java's Double.toString(), which has no precision loss. Implementors in + * other languages should strive to achieve that where possible. I have not + * yet verified whether std::istringstream::operator>>, which is doing that + * work for me in C++, loses any precision, but I am leaving this as a future + * improvement. I may try to provide a C component for this, so that other + * languages could bind to the same underlying implementation for maximum + * consistency. + * + */ +class TJSONProtocol : public TVirtualProtocol { +public: + TJSONProtocol(std::shared_ptr ptrans); + + ~TJSONProtocol() override; + +private: + void pushContext(std::shared_ptr c); + + void popContext(); + + uint32_t writeJSONEscapeChar(uint8_t ch); + + uint32_t writeJSONChar(uint8_t ch); + + uint32_t writeJSONString(const std::string& str); + + uint32_t writeJSONBase64(const std::string& str); + + template + uint32_t writeJSONInteger(NumberType num); + + uint32_t writeJSONDouble(double num); + + uint32_t writeJSONObjectStart(); + + uint32_t writeJSONObjectEnd(); + + uint32_t writeJSONArrayStart(); + + uint32_t writeJSONArrayEnd(); + + uint32_t readJSONSyntaxChar(uint8_t ch); + + uint32_t readJSONEscapeChar(uint16_t* out); + + uint32_t readJSONString(std::string& str, bool skipContext = false); + + uint32_t readJSONBase64(std::string& str); + + uint32_t readJSONNumericChars(std::string& str); + + template + uint32_t readJSONInteger(NumberType& num); + + uint32_t readJSONDouble(double& num); + + uint32_t readJSONObjectStart(); + + uint32_t readJSONObjectEnd(); + + uint32_t readJSONArrayStart(); + + uint32_t readJSONArrayEnd(); + +public: + /** + * Writing functions. + */ + + uint32_t writeMessageBegin(const std::string& name, + const TMessageType messageType, + const int32_t seqid); + + uint32_t writeMessageEnd(); + + uint32_t writeStructBegin(const char* name); + + uint32_t writeStructEnd(); + + uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId); + + uint32_t writeFieldEnd(); + + uint32_t writeFieldStop(); + + uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size); + + uint32_t writeMapEnd(); + + uint32_t writeListBegin(const TType elemType, const uint32_t size); + + uint32_t writeListEnd(); + + uint32_t writeSetBegin(const TType elemType, const uint32_t size); + + uint32_t writeSetEnd(); + + uint32_t writeBool(const bool value); + + uint32_t writeByte(const int8_t byte); + + uint32_t writeI16(const int16_t i16); + + uint32_t writeI32(const int32_t i32); + + uint32_t writeI64(const int64_t i64); + + uint32_t writeDouble(const double dub); + + uint32_t writeString(const std::string& str); + + uint32_t writeBinary(const std::string& str); + + /** + * Reading functions + */ + + uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid); + + uint32_t readMessageEnd(); + + uint32_t readStructBegin(std::string& name); + + uint32_t readStructEnd(); + + uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId); + + uint32_t readFieldEnd(); + + uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size); + + uint32_t readMapEnd(); + + uint32_t readListBegin(TType& elemType, uint32_t& size); + + uint32_t readListEnd(); + + uint32_t readSetBegin(TType& elemType, uint32_t& size); + + uint32_t readSetEnd(); + + uint32_t readBool(bool& value); + + // Provide the default readBool() implementation for std::vector + using TVirtualProtocol::readBool; + + uint32_t readByte(int8_t& byte); + + uint32_t readI16(int16_t& i16); + + uint32_t readI32(int32_t& i32); + + uint32_t readI64(int64_t& i64); + + uint32_t readDouble(double& dub); + + uint32_t readString(std::string& str); + + uint32_t readBinary(std::string& str); + + int getMinSerializedSize(TType type); + + void checkReadBytesAvailable(TSet& set) + { + trans_->checkReadBytesAvailable(set.size_ * getMinSerializedSize(set.elemType_)); + } + + void checkReadBytesAvailable(TList& list) + { + trans_->checkReadBytesAvailable(list.size_ * getMinSerializedSize(list.elemType_)); + } + + void checkReadBytesAvailable(TMap& map) + { + int elmSize = getMinSerializedSize(map.keyType_) + getMinSerializedSize(map.valueType_); + trans_->checkReadBytesAvailable(map.size_ * elmSize); + } + + class LookaheadReader { + + public: + LookaheadReader(TTransport& trans) : trans_(&trans), hasData_(false), data_(0) {} + + uint8_t read() { + if (hasData_) { + hasData_ = false; + } else { + trans_->readAll(&data_, 1); + } + return data_; + } + + uint8_t peek() { + if (!hasData_) { + trans_->readAll(&data_, 1); + } + hasData_ = true; + return data_; + } + + private: + TTransport* trans_; + bool hasData_; + uint8_t data_; + }; + +private: + TTransport* trans_; + + std::stack > contexts_; + std::shared_ptr context_; + LookaheadReader reader_; +}; + +/** + * Constructs input and output protocol objects given transports. + */ +class TJSONProtocolFactory : public TProtocolFactory { +public: + TJSONProtocolFactory() = default; + + ~TJSONProtocolFactory() override = default; + + std::shared_ptr getProtocol(std::shared_ptr trans) override { + return std::shared_ptr(new TJSONProtocol(trans)); + } +}; +} +} +} // apache::thrift::protocol + +// TODO(dreiss): Move part of ThriftJSONString into a .cpp file and remove this. +#include + +namespace apache { +namespace thrift { + +template +std::string ThriftJSONString(const ThriftStruct& ts) { + using namespace apache::thrift::transport; + using namespace apache::thrift::protocol; + auto* buffer = new TMemoryBuffer; + std::shared_ptr trans(buffer); + TJSONProtocol protocol(trans); + + ts.write(&protocol); + + uint8_t* buf; + uint32_t size; + buffer->getBuffer(&buf, &size); + return std::string((char*)buf, (unsigned int)size); +} +} +} // apache::thrift + +#endif // #define _THRIFT_PROTOCOL_TJSONPROTOCOL_H_ 1 diff --git a/bsnes/thrift/thrift/protocol/TList.h b/bsnes/thrift/thrift/protocol/TList.h new file mode 100644 index 00000000..bf2c1f9d --- /dev/null +++ b/bsnes/thrift/thrift/protocol/TList.h @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TLIST_H_ +#define _THRIFT_TLIST_H_ + +#include + +namespace apache { +namespace thrift { +namespace protocol { + +// using namespace apache::thrift::protocol; + +/** + * Helper class that encapsulates list metadata. + * + */ +class TList { +public: + TList() : elemType_(T_STOP), + size_(0) { + + } + + TList(TType t = T_STOP, int s = 0) + : elemType_(t), + size_(s) { + + } + + TType elemType_; + int size_; +}; +} +} +} // apache::thrift::protocol + +#endif // #ifndef _THRIFT_TLIST_H_ diff --git a/bsnes/thrift/thrift/protocol/TMap.h b/bsnes/thrift/thrift/protocol/TMap.h new file mode 100644 index 00000000..b52ea8fa --- /dev/null +++ b/bsnes/thrift/thrift/protocol/TMap.h @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TMAP_H_ +#define _THRIFT_TMAP_H_ + +#include + +namespace apache { +namespace thrift { +namespace protocol { + +using namespace apache::thrift::protocol; + +/** + * Helper class that encapsulates map metadata. + * + */ +class TMap { +public: + TMap() + : keyType_(T_STOP), + valueType_(T_STOP), + size_(0) { + + } + + TMap(TType k, TType v, int s) + : keyType_(k), + valueType_(v), + size_(s) { + + } + + TType keyType_; + TType valueType_; + int size_; +}; +} +} +} // apache::thrift::protocol + +#endif // #ifndef _THRIFT_TMAP_H_ diff --git a/bsnes/thrift/thrift/protocol/TMultiplexedProtocol.h b/bsnes/thrift/thrift/protocol/TMultiplexedProtocol.h new file mode 100644 index 00000000..0dc96058 --- /dev/null +++ b/bsnes/thrift/thrift/protocol/TMultiplexedProtocol.h @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef THRIFT_TMULTIPLEXEDPROTOCOL_H_ +#define THRIFT_TMULTIPLEXEDPROTOCOL_H_ 1 + +#include + +namespace apache { +namespace thrift { +namespace protocol { +using std::shared_ptr; + +/** + * TMultiplexedProtocol is a protocol-independent concrete decorator + * that allows a Thrift client to communicate with a multiplexing Thrift server, + * by prepending the service name to the function name during function calls. + * + * \note THIS IS NOT USED BY SERVERS. On the server, use + * {@link apache::thrift::TMultiplexedProcessor TMultiplexedProcessor} to handle requests + * from a multiplexing client. + * + * This example uses a single socket transport to invoke two services: + * + *
+ * shared_ptr transport(new TSocket("localhost", 9090)); + * transport->open(); + * + * shared_ptr protocol(new TBinaryProtocol(transport)); + * + * shared_ptr mp1(new TMultiplexedProtocol(protocol, "Calculator")); + * shared_ptr service1(new CalculatorClient(mp1)); + * + * shared_ptr mp2(new TMultiplexedProtocol(protocol, "WeatherReport")); + * shared_ptr service2(new WeatherReportClient(mp2)); + * + * service1->add(2,2); + * int temp = service2->getTemperature(); + *
+ * + * @see apache::thrift::protocol::TProtocolDecorator + */ +class TMultiplexedProtocol : public TProtocolDecorator { +public: + /** + * Wrap the specified protocol, allowing it to be used to communicate with a + * multiplexing server. The serviceName is required as it is + * prepended to the message header so that the multiplexing server can broker + * the function call to the proper service. + * + * \param _protocol Your communication protocol of choice, e.g. TBinaryProtocol. + * \param _serviceName The service name of the service communicating via this protocol. + */ + TMultiplexedProtocol(shared_ptr _protocol, const std::string& _serviceName) + : TProtocolDecorator(_protocol), serviceName(_serviceName), separator(":") {} + ~TMultiplexedProtocol() override = default; + + /** + * Prepends the service name to the function name, separated by TMultiplexedProtocol::SEPARATOR. + * + * \param [in] _name The name of the method to be called in the service. + * \param [in] _type The type of message + * \param [in] _name The sequential id of the message + * + * \throws TException Passed through from wrapped TProtocol instance. + */ + uint32_t writeMessageBegin_virt(const std::string& _name, + const TMessageType _type, + const int32_t _seqid) override; + +private: + const std::string serviceName; + const std::string separator; +}; +} +} +} + +#endif // THRIFT_TMULTIPLEXEDPROTOCOL_H_ diff --git a/bsnes/thrift/thrift/protocol/TProtocol.h b/bsnes/thrift/thrift/protocol/TProtocol.h new file mode 100644 index 00000000..867ceb07 --- /dev/null +++ b/bsnes/thrift/thrift/protocol/TProtocol.h @@ -0,0 +1,750 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_PROTOCOL_TPROTOCOL_H_ +#define _THRIFT_PROTOCOL_TPROTOCOL_H_ 1 + +#ifdef _WIN32 +// Need to come before any Windows.h includes +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#include +#include +#include +#include +#include + +// Use this to get around strict aliasing rules. +// For example, uint64_t i = bitwise_cast(returns_double()); +// The most obvious implementation is to just cast a pointer, +// but that doesn't work. +// For a pretty in-depth explanation of the problem, see +// http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html +template +static inline To bitwise_cast(From from) { + static_assert(sizeof(From) == sizeof(To), "sizeof(From) == sizeof(To)"); + + // BAD!!! These are all broken with -O2. + //return *reinterpret_cast(&from); // BAD!!! + //return *static_cast(static_cast(&from)); // BAD!!! + //return *(To*)(void*)&from; // BAD!!! + + // Super clean and paritally blessed by section 3.9 of the standard. + //unsigned char c[sizeof(from)]; + //memcpy(c, &from, sizeof(from)); + //To to; + //memcpy(&to, c, sizeof(c)); + //return to; + + // Slightly more questionable. + // Same code emitted by GCC. + //To to; + //memcpy(&to, &from, sizeof(from)); + //return to; + + // Technically undefined, but almost universally supported, + // and the most efficient implementation. + union { + From f; + To t; + } u; + u.f = from; + return u.t; +} + + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifndef __THRIFT_BYTE_ORDER +# if defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN) +# define __THRIFT_BYTE_ORDER BYTE_ORDER +# define __THRIFT_LITTLE_ENDIAN LITTLE_ENDIAN +# define __THRIFT_BIG_ENDIAN BIG_ENDIAN +# else +# include +# if BOOST_ENDIAN_BIG_BYTE +# define __THRIFT_BYTE_ORDER 4321 +# define __THRIFT_LITTLE_ENDIAN 0 +# define __THRIFT_BIG_ENDIAN __THRIFT_BYTE_ORDER +# elif BOOST_ENDIAN_LITTLE_BYTE +# define __THRIFT_BYTE_ORDER 1234 +# define __THRIFT_LITTLE_ENDIAN __THRIFT_BYTE_ORDER +# define __THRIFT_BIG_ENDIAN 0 +# endif +# ifdef BOOST_LITTLE_ENDIAN +# else +# endif +# endif +#endif + +#if __THRIFT_BYTE_ORDER == __THRIFT_BIG_ENDIAN +# if !defined(THRIFT_ntohll) +# define THRIFT_ntohll(n) (n) +# define THRIFT_htonll(n) (n) +# endif +# if defined(__GNUC__) && defined(__GLIBC__) +# include +# define THRIFT_htolell(n) bswap_64(n) +# define THRIFT_letohll(n) bswap_64(n) +# define THRIFT_htolel(n) bswap_32(n) +# define THRIFT_letohl(n) bswap_32(n) +# define THRIFT_htoles(n) bswap_16(n) +# define THRIFT_letohs(n) bswap_16(n) +# else /* GNUC & GLIBC */ +# define bswap_64(n) \ + ( (((n) & 0xff00000000000000ull) >> 56) \ + | (((n) & 0x00ff000000000000ull) >> 40) \ + | (((n) & 0x0000ff0000000000ull) >> 24) \ + | (((n) & 0x000000ff00000000ull) >> 8) \ + | (((n) & 0x00000000ff000000ull) << 8) \ + | (((n) & 0x0000000000ff0000ull) << 24) \ + | (((n) & 0x000000000000ff00ull) << 40) \ + | (((n) & 0x00000000000000ffull) << 56) ) +# define bswap_32(n) \ + ( (((n) & 0xff000000ul) >> 24) \ + | (((n) & 0x00ff0000ul) >> 8) \ + | (((n) & 0x0000ff00ul) << 8) \ + | (((n) & 0x000000fful) << 24) ) +# define bswap_16(n) \ + ( (((n) & ((unsigned short)0xff00ul)) >> 8) \ + | (((n) & ((unsigned short)0x00fful)) << 8) ) +# define THRIFT_htolell(n) bswap_64(n) +# define THRIFT_letohll(n) bswap_64(n) +# define THRIFT_htolel(n) bswap_32(n) +# define THRIFT_letohl(n) bswap_32(n) +# define THRIFT_htoles(n) bswap_16(n) +# define THRIFT_letohs(n) bswap_16(n) +# endif /* GNUC & GLIBC */ +#elif __THRIFT_BYTE_ORDER == __THRIFT_LITTLE_ENDIAN +# define THRIFT_htolell(n) (n) +# define THRIFT_letohll(n) (n) +# define THRIFT_htolel(n) (n) +# define THRIFT_letohl(n) (n) +# define THRIFT_htoles(n) (n) +# define THRIFT_letohs(n) (n) +# if defined(__GNUC__) && defined(__GLIBC__) +# include +# define THRIFT_ntohll(n) bswap_64(n) +# define THRIFT_htonll(n) bswap_64(n) +# elif defined(_MSC_VER) /* Microsoft Visual C++ */ +# define THRIFT_ntohll(n) ( _byteswap_uint64((uint64_t)n) ) +# define THRIFT_htonll(n) ( _byteswap_uint64((uint64_t)n) ) +# elif !defined(THRIFT_ntohll) /* Not GNUC/GLIBC or MSVC */ +# define THRIFT_ntohll(n) ( (((uint64_t)ntohl((uint32_t)n)) << 32) + ntohl((uint32_t)(n >> 32)) ) +# define THRIFT_htonll(n) ( (((uint64_t)htonl((uint32_t)n)) << 32) + htonl((uint32_t)(n >> 32)) ) +# endif /* GNUC/GLIBC or MSVC or something else */ +#else /* __THRIFT_BYTE_ORDER */ +# error "Can't define THRIFT_htonll or THRIFT_ntohll!" +#endif + +namespace apache { +namespace thrift { +namespace protocol { + +using apache::thrift::transport::TTransport; + +/** + * Abstract class for a thrift protocol driver. These are all the methods that + * a protocol must implement. Essentially, there must be some way of reading + * and writing all the base types, plus a mechanism for writing out structs + * with indexed fields. + * + * TProtocol objects should not be shared across multiple encoding contexts, + * as they may need to maintain internal state in some protocols (i.e. XML). + * Note that is is acceptable for the TProtocol module to do its own internal + * buffered reads/writes to the underlying TTransport where appropriate (i.e. + * when parsing an input XML stream, reading should be batched rather than + * looking ahead character by character for a close tag). + * + */ +class TProtocol { +public: + virtual ~TProtocol(); + + /** + * Writing functions. + */ + + virtual uint32_t writeMessageBegin_virt(const std::string& name, + const TMessageType messageType, + const int32_t seqid) = 0; + + virtual uint32_t writeMessageEnd_virt() = 0; + + virtual uint32_t writeStructBegin_virt(const char* name) = 0; + + virtual uint32_t writeStructEnd_virt() = 0; + + virtual uint32_t writeFieldBegin_virt(const char* name, + const TType fieldType, + const int16_t fieldId) = 0; + + virtual uint32_t writeFieldEnd_virt() = 0; + + virtual uint32_t writeFieldStop_virt() = 0; + + virtual uint32_t writeMapBegin_virt(const TType keyType, const TType valType, const uint32_t size) + = 0; + + virtual uint32_t writeMapEnd_virt() = 0; + + virtual uint32_t writeListBegin_virt(const TType elemType, const uint32_t size) = 0; + + virtual uint32_t writeListEnd_virt() = 0; + + virtual uint32_t writeSetBegin_virt(const TType elemType, const uint32_t size) = 0; + + virtual uint32_t writeSetEnd_virt() = 0; + + virtual uint32_t writeBool_virt(const bool value) = 0; + + virtual uint32_t writeByte_virt(const int8_t byte) = 0; + + virtual uint32_t writeI16_virt(const int16_t i16) = 0; + + virtual uint32_t writeI32_virt(const int32_t i32) = 0; + + virtual uint32_t writeI64_virt(const int64_t i64) = 0; + + virtual uint32_t writeDouble_virt(const double dub) = 0; + + virtual uint32_t writeString_virt(const std::string& str) = 0; + + virtual uint32_t writeBinary_virt(const std::string& str) = 0; + + uint32_t writeMessageBegin(const std::string& name, + const TMessageType messageType, + const int32_t seqid) { + T_VIRTUAL_CALL(); + return writeMessageBegin_virt(name, messageType, seqid); + } + + uint32_t writeMessageEnd() { + T_VIRTUAL_CALL(); + return writeMessageEnd_virt(); + } + + uint32_t writeStructBegin(const char* name) { + T_VIRTUAL_CALL(); + return writeStructBegin_virt(name); + } + + uint32_t writeStructEnd() { + T_VIRTUAL_CALL(); + return writeStructEnd_virt(); + } + + uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId) { + T_VIRTUAL_CALL(); + return writeFieldBegin_virt(name, fieldType, fieldId); + } + + uint32_t writeFieldEnd() { + T_VIRTUAL_CALL(); + return writeFieldEnd_virt(); + } + + uint32_t writeFieldStop() { + T_VIRTUAL_CALL(); + return writeFieldStop_virt(); + } + + uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size) { + T_VIRTUAL_CALL(); + return writeMapBegin_virt(keyType, valType, size); + } + + uint32_t writeMapEnd() { + T_VIRTUAL_CALL(); + return writeMapEnd_virt(); + } + + uint32_t writeListBegin(const TType elemType, const uint32_t size) { + T_VIRTUAL_CALL(); + return writeListBegin_virt(elemType, size); + } + + uint32_t writeListEnd() { + T_VIRTUAL_CALL(); + return writeListEnd_virt(); + } + + uint32_t writeSetBegin(const TType elemType, const uint32_t size) { + T_VIRTUAL_CALL(); + return writeSetBegin_virt(elemType, size); + } + + uint32_t writeSetEnd() { + T_VIRTUAL_CALL(); + return writeSetEnd_virt(); + } + + uint32_t writeBool(const bool value) { + T_VIRTUAL_CALL(); + return writeBool_virt(value); + } + + uint32_t writeByte(const int8_t byte) { + T_VIRTUAL_CALL(); + return writeByte_virt(byte); + } + + uint32_t writeI16(const int16_t i16) { + T_VIRTUAL_CALL(); + return writeI16_virt(i16); + } + + uint32_t writeI32(const int32_t i32) { + T_VIRTUAL_CALL(); + return writeI32_virt(i32); + } + + uint32_t writeI64(const int64_t i64) { + T_VIRTUAL_CALL(); + return writeI64_virt(i64); + } + + uint32_t writeDouble(const double dub) { + T_VIRTUAL_CALL(); + return writeDouble_virt(dub); + } + + uint32_t writeString(const std::string& str) { + T_VIRTUAL_CALL(); + return writeString_virt(str); + } + + uint32_t writeBinary(const std::string& str) { + T_VIRTUAL_CALL(); + return writeBinary_virt(str); + } + + /** + * Reading functions + */ + + virtual uint32_t readMessageBegin_virt(std::string& name, + TMessageType& messageType, + int32_t& seqid) = 0; + + virtual uint32_t readMessageEnd_virt() = 0; + + virtual uint32_t readStructBegin_virt(std::string& name) = 0; + + virtual uint32_t readStructEnd_virt() = 0; + + virtual uint32_t readFieldBegin_virt(std::string& name, TType& fieldType, int16_t& fieldId) = 0; + + virtual uint32_t readFieldEnd_virt() = 0; + + virtual uint32_t readMapBegin_virt(TType& keyType, TType& valType, uint32_t& size) = 0; + + virtual uint32_t readMapEnd_virt() = 0; + + virtual uint32_t readListBegin_virt(TType& elemType, uint32_t& size) = 0; + + virtual uint32_t readListEnd_virt() = 0; + + virtual uint32_t readSetBegin_virt(TType& elemType, uint32_t& size) = 0; + + virtual uint32_t readSetEnd_virt() = 0; + + virtual uint32_t readBool_virt(bool& value) = 0; + + virtual uint32_t readBool_virt(std::vector::reference value) = 0; + + virtual uint32_t readByte_virt(int8_t& byte) = 0; + + virtual uint32_t readI16_virt(int16_t& i16) = 0; + + virtual uint32_t readI32_virt(int32_t& i32) = 0; + + virtual uint32_t readI64_virt(int64_t& i64) = 0; + + virtual uint32_t readDouble_virt(double& dub) = 0; + + virtual uint32_t readString_virt(std::string& str) = 0; + + virtual uint32_t readBinary_virt(std::string& str) = 0; + + uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid) { + T_VIRTUAL_CALL(); + return readMessageBegin_virt(name, messageType, seqid); + } + + uint32_t readMessageEnd() { + T_VIRTUAL_CALL(); + return readMessageEnd_virt(); + } + + uint32_t readStructBegin(std::string& name) { + T_VIRTUAL_CALL(); + return readStructBegin_virt(name); + } + + uint32_t readStructEnd() { + T_VIRTUAL_CALL(); + return readStructEnd_virt(); + } + + uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId) { + T_VIRTUAL_CALL(); + return readFieldBegin_virt(name, fieldType, fieldId); + } + + uint32_t readFieldEnd() { + T_VIRTUAL_CALL(); + return readFieldEnd_virt(); + } + + uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size) { + T_VIRTUAL_CALL(); + return readMapBegin_virt(keyType, valType, size); + } + + uint32_t readMapEnd() { + T_VIRTUAL_CALL(); + return readMapEnd_virt(); + } + + uint32_t readListBegin(TType& elemType, uint32_t& size) { + T_VIRTUAL_CALL(); + return readListBegin_virt(elemType, size); + } + + uint32_t readListEnd() { + T_VIRTUAL_CALL(); + return readListEnd_virt(); + } + + uint32_t readSetBegin(TType& elemType, uint32_t& size) { + T_VIRTUAL_CALL(); + return readSetBegin_virt(elemType, size); + } + + uint32_t readSetEnd() { + T_VIRTUAL_CALL(); + return readSetEnd_virt(); + } + + uint32_t readBool(bool& value) { + T_VIRTUAL_CALL(); + return readBool_virt(value); + } + + uint32_t readByte(int8_t& byte) { + T_VIRTUAL_CALL(); + return readByte_virt(byte); + } + + uint32_t readI16(int16_t& i16) { + T_VIRTUAL_CALL(); + return readI16_virt(i16); + } + + uint32_t readI32(int32_t& i32) { + T_VIRTUAL_CALL(); + return readI32_virt(i32); + } + + uint32_t readI64(int64_t& i64) { + T_VIRTUAL_CALL(); + return readI64_virt(i64); + } + + uint32_t readDouble(double& dub) { + T_VIRTUAL_CALL(); + return readDouble_virt(dub); + } + + uint32_t readString(std::string& str) { + T_VIRTUAL_CALL(); + return readString_virt(str); + } + + uint32_t readBinary(std::string& str) { + T_VIRTUAL_CALL(); + return readBinary_virt(str); + } + + /* + * std::vector is specialized for bool, and its elements are individual bits + * rather than bools. We need to define a different version of readBool() + * to work with std::vector. + */ + uint32_t readBool(std::vector::reference value) { + T_VIRTUAL_CALL(); + return readBool_virt(value); + } + + /** + * Method to arbitrarily skip over data. + */ + uint32_t skip(TType type) { + T_VIRTUAL_CALL(); + return skip_virt(type); + } + virtual uint32_t skip_virt(TType type); + + inline std::shared_ptr getTransport() { return ptrans_; } + + // TODO: remove these two calls, they are for backwards + // compatibility + inline std::shared_ptr getInputTransport() { return ptrans_; } + inline std::shared_ptr getOutputTransport() { return ptrans_; } + + // input and output recursion depth are kept separate so that one protocol + // can be used concurrently for both input and output. + void incrementInputRecursionDepth() { + if (recursion_limit_ < ++input_recursion_depth_) { + throw TProtocolException(TProtocolException::DEPTH_LIMIT); + } + } + void decrementInputRecursionDepth() { --input_recursion_depth_; } + + void incrementOutputRecursionDepth() { + if (recursion_limit_ < ++output_recursion_depth_) { + throw TProtocolException(TProtocolException::DEPTH_LIMIT); + } + } + void decrementOutputRecursionDepth() { --output_recursion_depth_; } + + uint32_t getRecursionLimit() const {return recursion_limit_;} + void setRecurisionLimit(uint32_t depth) {recursion_limit_ = depth;} + + // Returns the minimum amount of bytes needed to store the smallest possible instance of TType. + virtual int getMinSerializedSize(TType type) { + THRIFT_UNUSED_VARIABLE(type); + return 0; + } + +protected: + TProtocol(std::shared_ptr ptrans) + : ptrans_(ptrans), input_recursion_depth_(0), output_recursion_depth_(0), + recursion_limit_(ptrans->getConfiguration()->getRecursionLimit()) + {} + + virtual void checkReadBytesAvailable(TSet& set) + { + ptrans_->checkReadBytesAvailable(set.size_ * getMinSerializedSize(set.elemType_)); + } + + virtual void checkReadBytesAvailable(TList& list) + { + ptrans_->checkReadBytesAvailable(list.size_ * getMinSerializedSize(list.elemType_)); + } + + virtual void checkReadBytesAvailable(TMap& map) + { + int elmSize = getMinSerializedSize(map.keyType_) + getMinSerializedSize(map.valueType_); + ptrans_->checkReadBytesAvailable(map.size_ * elmSize); + } + + std::shared_ptr ptrans_; + +private: + TProtocol() = default; + uint32_t input_recursion_depth_; + uint32_t output_recursion_depth_; + uint32_t recursion_limit_; +}; + +/** + * Constructs input and output protocol objects given transports. + */ +class TProtocolFactory { +public: + TProtocolFactory() = default; + + virtual ~TProtocolFactory(); + + virtual std::shared_ptr getProtocol(std::shared_ptr trans) = 0; + virtual std::shared_ptr getProtocol(std::shared_ptr inTrans, + std::shared_ptr outTrans) { + (void)outTrans; + return getProtocol(inTrans); + } +}; + +/** + * Dummy protocol class. + * + * This class does nothing, and should never be instantiated. + * It is used only by the generator code. + */ +class TDummyProtocol : public TProtocol {}; + +// This is the default / legacy choice +struct TNetworkBigEndian +{ + static uint16_t toWire16(uint16_t x) {return htons(x);} + static uint32_t toWire32(uint32_t x) {return htonl(x);} + static uint64_t toWire64(uint64_t x) {return THRIFT_htonll(x);} + static uint16_t fromWire16(uint16_t x) {return ntohs(x);} + static uint32_t fromWire32(uint32_t x) {return ntohl(x);} + static uint64_t fromWire64(uint64_t x) {return THRIFT_ntohll(x);} +}; + +// On most systems, this will be a bit faster than TNetworkBigEndian +struct TNetworkLittleEndian +{ + static uint16_t toWire16(uint16_t x) {return THRIFT_htoles(x);} + static uint32_t toWire32(uint32_t x) {return THRIFT_htolel(x);} + static uint64_t toWire64(uint64_t x) {return THRIFT_htolell(x);} + static uint16_t fromWire16(uint16_t x) {return THRIFT_letohs(x);} + static uint32_t fromWire32(uint32_t x) {return THRIFT_letohl(x);} + static uint64_t fromWire64(uint64_t x) {return THRIFT_letohll(x);} +}; + +struct TOutputRecursionTracker { + TProtocol &prot_; + TOutputRecursionTracker(TProtocol &prot) : prot_(prot) { + prot_.incrementOutputRecursionDepth(); + } + ~TOutputRecursionTracker() { + prot_.decrementOutputRecursionDepth(); + } +}; + +struct TInputRecursionTracker { + TProtocol &prot_; + TInputRecursionTracker(TProtocol &prot) : prot_(prot) { + prot_.incrementInputRecursionDepth(); + } + ~TInputRecursionTracker() { + prot_.decrementInputRecursionDepth(); + } +}; + +/** + * Helper template for implementing TProtocol::skip(). + * + * Templatized to avoid having to make virtual function calls. + */ +template +uint32_t skip(Protocol_& prot, TType type) { + TInputRecursionTracker tracker(prot); + + switch (type) { + case T_BOOL: { + bool boolv; + return prot.readBool(boolv); + } + case T_BYTE: { + int8_t bytev = 0; + return prot.readByte(bytev); + } + case T_I16: { + int16_t i16; + return prot.readI16(i16); + } + case T_I32: { + int32_t i32; + return prot.readI32(i32); + } + case T_I64: { + int64_t i64; + return prot.readI64(i64); + } + case T_DOUBLE: { + double dub; + return prot.readDouble(dub); + } + case T_STRING: { + std::string str; + return prot.readBinary(str); + } + case T_STRUCT: { + uint32_t result = 0; + std::string name; + int16_t fid; + TType ftype; + result += prot.readStructBegin(name); + while (true) { + result += prot.readFieldBegin(name, ftype, fid); + if (ftype == T_STOP) { + break; + } + result += skip(prot, ftype); + result += prot.readFieldEnd(); + } + result += prot.readStructEnd(); + return result; + } + case T_MAP: { + uint32_t result = 0; + TType keyType; + TType valType; + uint32_t i, size; + result += prot.readMapBegin(keyType, valType, size); + for (i = 0; i < size; i++) { + result += skip(prot, keyType); + result += skip(prot, valType); + } + result += prot.readMapEnd(); + return result; + } + case T_SET: { + uint32_t result = 0; + TType elemType; + uint32_t i, size; + result += prot.readSetBegin(elemType, size); + for (i = 0; i < size; i++) { + result += skip(prot, elemType); + } + result += prot.readSetEnd(); + return result; + } + case T_LIST: { + uint32_t result = 0; + TType elemType; + uint32_t i, size; + result += prot.readListBegin(elemType, size); + for (i = 0; i < size; i++) { + result += skip(prot, elemType); + } + result += prot.readListEnd(); + return result; + } + default: + break; + } + + throw TProtocolException(TProtocolException::INVALID_DATA, + "invalid TType"); +} + +}}} // apache::thrift::protocol + +#endif // #define _THRIFT_PROTOCOL_TPROTOCOL_H_ 1 diff --git a/bsnes/thrift/thrift/protocol/TProtocolDecorator.h b/bsnes/thrift/thrift/protocol/TProtocolDecorator.h new file mode 100644 index 00000000..5258159f --- /dev/null +++ b/bsnes/thrift/thrift/protocol/TProtocolDecorator.h @@ -0,0 +1,151 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef THRIFT_TPROTOCOLDECORATOR_H_ +#define THRIFT_TPROTOCOLDECORATOR_H_ 1 + +#include +#include + +namespace apache { +namespace thrift { +namespace protocol { +using std::shared_ptr; + +/** + * TProtocolDecorator forwards all requests to an enclosed + * TProtocol instance, providing a way to author concise + * concrete decorator subclasses. + * + *

See p.175 of Design Patterns (by Gamma et al.)

+ * + * @see apache::thrift::protocol::TMultiplexedProtocol + */ +class TProtocolDecorator : public TProtocol { +public: + ~TProtocolDecorator() override = default; + + // Desc: Initializes the protocol decorator object. + TProtocolDecorator(shared_ptr proto) + : TProtocol(proto->getTransport()), protocol(proto) {} + + uint32_t writeMessageBegin_virt(const std::string& name, + const TMessageType messageType, + const int32_t seqid) override { + return protocol->writeMessageBegin(name, messageType, seqid); + } + uint32_t writeMessageEnd_virt() override { return protocol->writeMessageEnd(); } + uint32_t writeStructBegin_virt(const char* name) override { + return protocol->writeStructBegin(name); + } + uint32_t writeStructEnd_virt() override { return protocol->writeStructEnd(); } + + uint32_t writeFieldBegin_virt(const char* name, + const TType fieldType, + const int16_t fieldId) override { + return protocol->writeFieldBegin(name, fieldType, fieldId); + } + + uint32_t writeFieldEnd_virt() override { return protocol->writeFieldEnd(); } + uint32_t writeFieldStop_virt() override { return protocol->writeFieldStop(); } + + uint32_t writeMapBegin_virt(const TType keyType, + const TType valType, + const uint32_t size) override { + return protocol->writeMapBegin(keyType, valType, size); + } + + uint32_t writeMapEnd_virt() override { return protocol->writeMapEnd(); } + + uint32_t writeListBegin_virt(const TType elemType, const uint32_t size) override { + return protocol->writeListBegin(elemType, size); + } + uint32_t writeListEnd_virt() override { return protocol->writeListEnd(); } + + uint32_t writeSetBegin_virt(const TType elemType, const uint32_t size) override { + return protocol->writeSetBegin(elemType, size); + } + uint32_t writeSetEnd_virt() override { return protocol->writeSetEnd(); } + + uint32_t writeBool_virt(const bool value) override { return protocol->writeBool(value); } + uint32_t writeByte_virt(const int8_t byte) override { return protocol->writeByte(byte); } + uint32_t writeI16_virt(const int16_t i16) override { return protocol->writeI16(i16); } + uint32_t writeI32_virt(const int32_t i32) override { return protocol->writeI32(i32); } + uint32_t writeI64_virt(const int64_t i64) override { return protocol->writeI64(i64); } + + uint32_t writeDouble_virt(const double dub) override { return protocol->writeDouble(dub); } + uint32_t writeString_virt(const std::string& str) override { return protocol->writeString(str); } + uint32_t writeBinary_virt(const std::string& str) override { return protocol->writeBinary(str); } + + uint32_t readMessageBegin_virt(std::string& name, + TMessageType& messageType, + int32_t& seqid) override { + return protocol->readMessageBegin(name, messageType, seqid); + } + uint32_t readMessageEnd_virt() override { return protocol->readMessageEnd(); } + + uint32_t readStructBegin_virt(std::string& name) override { + return protocol->readStructBegin(name); + } + uint32_t readStructEnd_virt() override { return protocol->readStructEnd(); } + + uint32_t readFieldBegin_virt(std::string& name, TType& fieldType, int16_t& fieldId) override { + return protocol->readFieldBegin(name, fieldType, fieldId); + } + uint32_t readFieldEnd_virt() override { return protocol->readFieldEnd(); } + + uint32_t readMapBegin_virt(TType& keyType, TType& valType, uint32_t& size) override { + return protocol->readMapBegin(keyType, valType, size); + } + uint32_t readMapEnd_virt() override { return protocol->readMapEnd(); } + + uint32_t readListBegin_virt(TType& elemType, uint32_t& size) override { + return protocol->readListBegin(elemType, size); + } + uint32_t readListEnd_virt() override { return protocol->readListEnd(); } + + uint32_t readSetBegin_virt(TType& elemType, uint32_t& size) override { + return protocol->readSetBegin(elemType, size); + } + uint32_t readSetEnd_virt() override { return protocol->readSetEnd(); } + + uint32_t readBool_virt(bool& value) override { return protocol->readBool(value); } + uint32_t readBool_virt(std::vector::reference value) override { + return protocol->readBool(value); + } + + uint32_t readByte_virt(int8_t& byte) override { return protocol->readByte(byte); } + + uint32_t readI16_virt(int16_t& i16) override { return protocol->readI16(i16); } + uint32_t readI32_virt(int32_t& i32) override { return protocol->readI32(i32); } + uint32_t readI64_virt(int64_t& i64) override { return protocol->readI64(i64); } + + uint32_t readDouble_virt(double& dub) override { return protocol->readDouble(dub); } + + uint32_t readString_virt(std::string& str) override { return protocol->readString(str); } + uint32_t readBinary_virt(std::string& str) override { return protocol->readBinary(str); } + +private: + shared_ptr protocol; +}; +} +} +} + +#endif // THRIFT_TPROTOCOLDECORATOR_H_ diff --git a/bsnes/thrift/thrift/protocol/TProtocolException.h b/bsnes/thrift/thrift/protocol/TProtocolException.h new file mode 100644 index 00000000..4ace9046 --- /dev/null +++ b/bsnes/thrift/thrift/protocol/TProtocolException.h @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_PROTOCOL_TPROTOCOLEXCEPTION_H_ +#define _THRIFT_PROTOCOL_TPROTOCOLEXCEPTION_H_ 1 + +#include + +namespace apache { +namespace thrift { +namespace protocol { + +/** + * Class to encapsulate all the possible types of protocol errors that may + * occur in various protocol systems. This provides a sort of generic + * wrapper around the vague UNIX E_ error codes that lets a common code + * base of error handling to be used for various types of protocols, i.e. + * pipes etc. + * + */ +class TProtocolException : public apache::thrift::TException { +public: + /** + * Error codes for the various types of exceptions. + */ + enum TProtocolExceptionType { + UNKNOWN = 0, + INVALID_DATA = 1, + NEGATIVE_SIZE = 2, + SIZE_LIMIT = 3, + BAD_VERSION = 4, + NOT_IMPLEMENTED = 5, + DEPTH_LIMIT = 6 + }; + + TProtocolException() : apache::thrift::TException(), type_(UNKNOWN) {} + + TProtocolException(TProtocolExceptionType type) : apache::thrift::TException(), type_(type) {} + + TProtocolException(const std::string& message) + : apache::thrift::TException(message), type_(UNKNOWN) {} + + TProtocolException(TProtocolExceptionType type, const std::string& message) + : apache::thrift::TException(message), type_(type) {} + + ~TProtocolException() noexcept override = default; + + /** + * Returns an error code that provides information about the type of error + * that has occurred. + * + * @return Error code + */ + TProtocolExceptionType getType() const { return type_; } + + const char* what() const noexcept override { + if (message_.empty()) { + switch (type_) { + case UNKNOWN: + return "TProtocolException: Unknown protocol exception"; + case INVALID_DATA: + return "TProtocolException: Invalid data"; + case NEGATIVE_SIZE: + return "TProtocolException: Negative size"; + case SIZE_LIMIT: + return "TProtocolException: Exceeded size limit"; + case BAD_VERSION: + return "TProtocolException: Invalid version"; + case NOT_IMPLEMENTED: + return "TProtocolException: Not implemented"; + case DEPTH_LIMIT: + return "TProtocolException: Exceeded depth limit"; + default: + return "TProtocolException: (Invalid exception type)"; + } + } else { + return message_.c_str(); + } + } + +protected: + /** + * Error code + */ + TProtocolExceptionType type_; +}; +} +} +} // apache::thrift::protocol + +#endif // #ifndef _THRIFT_PROTOCOL_TPROTOCOLEXCEPTION_H_ diff --git a/bsnes/thrift/thrift/protocol/TProtocolTap.h b/bsnes/thrift/thrift/protocol/TProtocolTap.h new file mode 100644 index 00000000..d000ba61 --- /dev/null +++ b/bsnes/thrift/thrift/protocol/TProtocolTap.h @@ -0,0 +1,177 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_PROTOCOL_TPROTOCOLTAP_H_ +#define _THRIFT_PROTOCOL_TPROTOCOLTAP_H_ 1 + +#include + +namespace apache { +namespace thrift { +namespace protocol { + +using apache::thrift::transport::TTransport; + +/** + * Puts a wiretap on a protocol object. Any reads to this class are passed + * through to an enclosed protocol object, but also mirrored as write to a + * second protocol object. + * + */ +class TProtocolTap : public TVirtualProtocol { +public: + TProtocolTap(std::shared_ptr source, std::shared_ptr sink) + : TVirtualProtocol(source->getTransport()), source_(source), sink_(sink) {} + + uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid) { + uint32_t rv = source_->readMessageBegin(name, messageType, seqid); + sink_->writeMessageBegin(name, messageType, seqid); + return rv; + } + + uint32_t readMessageEnd() { + uint32_t rv = source_->readMessageEnd(); + sink_->writeMessageEnd(); + return rv; + } + + uint32_t readStructBegin(std::string& name) { + uint32_t rv = source_->readStructBegin(name); + sink_->writeStructBegin(name.c_str()); + return rv; + } + + uint32_t readStructEnd() { + uint32_t rv = source_->readStructEnd(); + sink_->writeStructEnd(); + return rv; + } + + uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId) { + uint32_t rv = source_->readFieldBegin(name, fieldType, fieldId); + if (fieldType == T_STOP) { + sink_->writeFieldStop(); + } else { + sink_->writeFieldBegin(name.c_str(), fieldType, fieldId); + } + return rv; + } + + uint32_t readFieldEnd() { + uint32_t rv = source_->readFieldEnd(); + sink_->writeFieldEnd(); + return rv; + } + + uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size) { + uint32_t rv = source_->readMapBegin(keyType, valType, size); + sink_->writeMapBegin(keyType, valType, size); + return rv; + } + + uint32_t readMapEnd() { + uint32_t rv = source_->readMapEnd(); + sink_->writeMapEnd(); + return rv; + } + + uint32_t readListBegin(TType& elemType, uint32_t& size) { + uint32_t rv = source_->readListBegin(elemType, size); + sink_->writeListBegin(elemType, size); + return rv; + } + + uint32_t readListEnd() { + uint32_t rv = source_->readListEnd(); + sink_->writeListEnd(); + return rv; + } + + uint32_t readSetBegin(TType& elemType, uint32_t& size) { + uint32_t rv = source_->readSetBegin(elemType, size); + sink_->writeSetBegin(elemType, size); + return rv; + } + + uint32_t readSetEnd() { + uint32_t rv = source_->readSetEnd(); + sink_->writeSetEnd(); + return rv; + } + + uint32_t readBool(bool& value) { + uint32_t rv = source_->readBool(value); + sink_->writeBool(value); + return rv; + } + + // Provide the default readBool() implementation for std::vector + using TVirtualProtocol::readBool; + + uint32_t readByte(int8_t& byte) { + uint32_t rv = source_->readByte(byte); + sink_->writeByte(byte); + return rv; + } + + uint32_t readI16(int16_t& i16) { + uint32_t rv = source_->readI16(i16); + sink_->writeI16(i16); + return rv; + } + + uint32_t readI32(int32_t& i32) { + uint32_t rv = source_->readI32(i32); + sink_->writeI32(i32); + return rv; + } + + uint32_t readI64(int64_t& i64) { + uint32_t rv = source_->readI64(i64); + sink_->writeI64(i64); + return rv; + } + + uint32_t readDouble(double& dub) { + uint32_t rv = source_->readDouble(dub); + sink_->writeDouble(dub); + return rv; + } + + uint32_t readString(std::string& str) { + uint32_t rv = source_->readString(str); + sink_->writeString(str); + return rv; + } + + uint32_t readBinary(std::string& str) { + uint32_t rv = source_->readBinary(str); + sink_->writeBinary(str); + return rv; + } + +private: + std::shared_ptr source_; + std::shared_ptr sink_; +}; +} +} +} // apache::thrift::protocol + +#endif // #define _THRIFT_PROTOCOL_TPROTOCOLTAP_H_ 1 diff --git a/bsnes/thrift/thrift/protocol/TProtocolTypes.h b/bsnes/thrift/thrift/protocol/TProtocolTypes.h new file mode 100644 index 00000000..6898b24e --- /dev/null +++ b/bsnes/thrift/thrift/protocol/TProtocolTypes.h @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef THRIFT_PROTOCOL_TPROTOCOLTYPES_H_ +#define THRIFT_PROTOCOL_TPROTOCOLTYPES_H_ 1 + +namespace apache { +namespace thrift { +namespace protocol { + +enum PROTOCOL_TYPES { + T_BINARY_PROTOCOL = 0, + T_JSON_PROTOCOL = 1, + T_COMPACT_PROTOCOL = 2, +}; +} +} +} // apache::thrift::protocol + +#endif // #define _THRIFT_PROTOCOL_TPROTOCOLTYPES_H_ 1 diff --git a/bsnes/thrift/thrift/protocol/TSet.h b/bsnes/thrift/thrift/protocol/TSet.h new file mode 100644 index 00000000..3a4718cd --- /dev/null +++ b/bsnes/thrift/thrift/protocol/TSet.h @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TSET_H_ +#define _THRIFT_TSET_H_ + +#include +#include + +namespace apache { +namespace thrift { +namespace protocol { + +using namespace apache::thrift::protocol; + +/** + * Helper class that encapsulates set metadata. + * + */ +class TSet { +public: + TSet() : elemType_(T_STOP), size_(0) { + + } + + TSet(TType t, int s) + : elemType_(t), + size_(s) { + + } + + TSet(TList list) + : elemType_(list.elemType_), + size_(list.size_) { + + } + + TType elemType_; + int size_; +}; +} +} +} // apache::thrift::protocol + +#endif // #ifndef _THRIFT_TSET_H_ diff --git a/bsnes/thrift/thrift/protocol/TVirtualProtocol.h b/bsnes/thrift/thrift/protocol/TVirtualProtocol.h new file mode 100644 index 00000000..b7fe929a --- /dev/null +++ b/bsnes/thrift/thrift/protocol/TVirtualProtocol.h @@ -0,0 +1,513 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_PROTOCOL_TVIRTUALPROTOCOL_H_ +#define _THRIFT_PROTOCOL_TVIRTUALPROTOCOL_H_ 1 + +#include + +namespace apache { +namespace thrift { +namespace protocol { + +using apache::thrift::transport::TTransport; + +/** + * Helper class that provides default implementations of TProtocol methods. + * + * This class provides default implementations of the non-virtual TProtocol + * methods. It exists primarily so TVirtualProtocol can derive from it. It + * prevents TVirtualProtocol methods from causing infinite recursion if the + * non-virtual methods are not overridden by the TVirtualProtocol subclass. + * + * You probably don't want to use this class directly. Use TVirtualProtocol + * instead. + */ +class TProtocolDefaults : public TProtocol { +public: + uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid) { + (void)name; + (void)messageType; + (void)seqid; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support reading (yet)."); + } + + uint32_t readMessageEnd() { + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support reading (yet)."); + } + + uint32_t readStructBegin(std::string& name) { + (void)name; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support reading (yet)."); + } + + uint32_t readStructEnd() { + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support reading (yet)."); + } + + uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId) { + (void)name; + (void)fieldType; + (void)fieldId; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support reading (yet)."); + } + + uint32_t readFieldEnd() { + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support reading (yet)."); + } + + uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size) { + (void)keyType; + (void)valType; + (void)size; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support reading (yet)."); + } + + uint32_t readMapEnd() { + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support reading (yet)."); + } + + uint32_t readListBegin(TType& elemType, uint32_t& size) { + (void)elemType; + (void)size; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support reading (yet)."); + } + + uint32_t readListEnd() { + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support reading (yet)."); + } + + uint32_t readSetBegin(TType& elemType, uint32_t& size) { + (void)elemType; + (void)size; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support reading (yet)."); + } + + uint32_t readSetEnd() { + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support reading (yet)."); + } + + uint32_t readBool(bool& value) { + (void)value; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support reading (yet)."); + } + + uint32_t readBool(std::vector::reference value) { + (void)value; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support reading (yet)."); + } + + uint32_t readByte(int8_t& byte) { + (void)byte; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support reading (yet)."); + } + + uint32_t readI16(int16_t& i16) { + (void)i16; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support reading (yet)."); + } + + uint32_t readI32(int32_t& i32) { + (void)i32; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support reading (yet)."); + } + + uint32_t readI64(int64_t& i64) { + (void)i64; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support reading (yet)."); + } + + uint32_t readDouble(double& dub) { + (void)dub; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support reading (yet)."); + } + + uint32_t readString(std::string& str) { + (void)str; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support reading (yet)."); + } + + uint32_t readBinary(std::string& str) { + (void)str; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support reading (yet)."); + } + + uint32_t writeMessageBegin(const std::string& name, + const TMessageType messageType, + const int32_t seqid) { + (void)name; + (void)messageType; + (void)seqid; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support writing (yet)."); + } + + uint32_t writeMessageEnd() { + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support writing (yet)."); + } + + uint32_t writeStructBegin(const char* name) { + (void)name; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support writing (yet)."); + } + + uint32_t writeStructEnd() { + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support writing (yet)."); + } + + uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId) { + (void)name; + (void)fieldType; + (void)fieldId; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support writing (yet)."); + } + + uint32_t writeFieldEnd() { + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support writing (yet)."); + } + + uint32_t writeFieldStop() { + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support writing (yet)."); + } + + uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size) { + (void)keyType; + (void)valType; + (void)size; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support writing (yet)."); + } + + uint32_t writeMapEnd() { + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support writing (yet)."); + } + + uint32_t writeListBegin(const TType elemType, const uint32_t size) { + (void)elemType; + (void)size; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support writing (yet)."); + } + + uint32_t writeListEnd() { + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support writing (yet)."); + } + + uint32_t writeSetBegin(const TType elemType, const uint32_t size) { + (void)elemType; + (void)size; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support writing (yet)."); + } + + uint32_t writeSetEnd() { + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support writing (yet)."); + } + + uint32_t writeBool(const bool value) { + (void)value; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support writing (yet)."); + } + + uint32_t writeByte(const int8_t byte) { + (void)byte; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support writing (yet)."); + } + + uint32_t writeI16(const int16_t i16) { + (void)i16; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support writing (yet)."); + } + + uint32_t writeI32(const int32_t i32) { + (void)i32; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support writing (yet)."); + } + + uint32_t writeI64(const int64_t i64) { + (void)i64; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support writing (yet)."); + } + + uint32_t writeDouble(const double dub) { + (void)dub; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support writing (yet)."); + } + + uint32_t writeString(const std::string& str) { + (void)str; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support writing (yet)."); + } + + uint32_t writeBinary(const std::string& str) { + (void)str; + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "this protocol does not support writing (yet)."); + } + + uint32_t skip(TType type) { return ::apache::thrift::protocol::skip(*this, type); } + +protected: + TProtocolDefaults(std::shared_ptr ptrans) : TProtocol(ptrans) {} +}; + +/** + * Concrete TProtocol classes should inherit from TVirtualProtocol + * so they don't have to manually override virtual methods. + */ +template +class TVirtualProtocol : public Super_ { +public: + /** + * Writing functions. + */ + + uint32_t writeMessageBegin_virt(const std::string& name, + const TMessageType messageType, + const int32_t seqid) override { + return static_cast(this)->writeMessageBegin(name, messageType, seqid); + } + + uint32_t writeMessageEnd_virt() override { + return static_cast(this)->writeMessageEnd(); + } + + uint32_t writeStructBegin_virt(const char* name) override { + return static_cast(this)->writeStructBegin(name); + } + + uint32_t writeStructEnd_virt() override { return static_cast(this)->writeStructEnd(); } + + uint32_t writeFieldBegin_virt(const char* name, + const TType fieldType, + const int16_t fieldId) override { + return static_cast(this)->writeFieldBegin(name, fieldType, fieldId); + } + + uint32_t writeFieldEnd_virt() override { return static_cast(this)->writeFieldEnd(); } + + uint32_t writeFieldStop_virt() override { return static_cast(this)->writeFieldStop(); } + + uint32_t writeMapBegin_virt(const TType keyType, + const TType valType, + const uint32_t size) override { + return static_cast(this)->writeMapBegin(keyType, valType, size); + } + + uint32_t writeMapEnd_virt() override { return static_cast(this)->writeMapEnd(); } + + uint32_t writeListBegin_virt(const TType elemType, const uint32_t size) override { + return static_cast(this)->writeListBegin(elemType, size); + } + + uint32_t writeListEnd_virt() override { return static_cast(this)->writeListEnd(); } + + uint32_t writeSetBegin_virt(const TType elemType, const uint32_t size) override { + return static_cast(this)->writeSetBegin(elemType, size); + } + + uint32_t writeSetEnd_virt() override { return static_cast(this)->writeSetEnd(); } + + uint32_t writeBool_virt(const bool value) override { + return static_cast(this)->writeBool(value); + } + + uint32_t writeByte_virt(const int8_t byte) override { + return static_cast(this)->writeByte(byte); + } + + uint32_t writeI16_virt(const int16_t i16) override { + return static_cast(this)->writeI16(i16); + } + + uint32_t writeI32_virt(const int32_t i32) override { + return static_cast(this)->writeI32(i32); + } + + uint32_t writeI64_virt(const int64_t i64) override { + return static_cast(this)->writeI64(i64); + } + + uint32_t writeDouble_virt(const double dub) override { + return static_cast(this)->writeDouble(dub); + } + + uint32_t writeString_virt(const std::string& str) override { + return static_cast(this)->writeString(str); + } + + uint32_t writeBinary_virt(const std::string& str) override { + return static_cast(this)->writeBinary(str); + } + + /** + * Reading functions + */ + + uint32_t readMessageBegin_virt(std::string& name, + TMessageType& messageType, + int32_t& seqid) override { + return static_cast(this)->readMessageBegin(name, messageType, seqid); + } + + uint32_t readMessageEnd_virt() override { return static_cast(this)->readMessageEnd(); } + + uint32_t readStructBegin_virt(std::string& name) override { + return static_cast(this)->readStructBegin(name); + } + + uint32_t readStructEnd_virt() override { return static_cast(this)->readStructEnd(); } + + uint32_t readFieldBegin_virt(std::string& name, TType& fieldType, int16_t& fieldId) override { + return static_cast(this)->readFieldBegin(name, fieldType, fieldId); + } + + uint32_t readFieldEnd_virt() override { return static_cast(this)->readFieldEnd(); } + + uint32_t readMapBegin_virt(TType& keyType, TType& valType, uint32_t& size) override { + return static_cast(this)->readMapBegin(keyType, valType, size); + } + + uint32_t readMapEnd_virt() override { return static_cast(this)->readMapEnd(); } + + uint32_t readListBegin_virt(TType& elemType, uint32_t& size) override { + return static_cast(this)->readListBegin(elemType, size); + } + + uint32_t readListEnd_virt() override { return static_cast(this)->readListEnd(); } + + uint32_t readSetBegin_virt(TType& elemType, uint32_t& size) override { + return static_cast(this)->readSetBegin(elemType, size); + } + + uint32_t readSetEnd_virt() override { return static_cast(this)->readSetEnd(); } + + uint32_t readBool_virt(bool& value) override { + return static_cast(this)->readBool(value); + } + + uint32_t readBool_virt(std::vector::reference value) override { + return static_cast(this)->readBool(value); + } + + uint32_t readByte_virt(int8_t& byte) override { + return static_cast(this)->readByte(byte); + } + + uint32_t readI16_virt(int16_t& i16) override { + return static_cast(this)->readI16(i16); + } + + uint32_t readI32_virt(int32_t& i32) override { + return static_cast(this)->readI32(i32); + } + + uint32_t readI64_virt(int64_t& i64) override { + return static_cast(this)->readI64(i64); + } + + uint32_t readDouble_virt(double& dub) override { + return static_cast(this)->readDouble(dub); + } + + uint32_t readString_virt(std::string& str) override { + return static_cast(this)->readString(str); + } + + uint32_t readBinary_virt(std::string& str) override { + return static_cast(this)->readBinary(str); + } + + uint32_t skip_virt(TType type) override { return static_cast(this)->skip(type); } + + /* + * Provide a default skip() implementation that uses non-virtual read + * methods. + * + * Note: subclasses that use TVirtualProtocol to derive from another protocol + * implementation (i.e., not TProtocolDefaults) should beware that this may + * override any non-default skip() implementation provided by the parent + * transport class. They may need to explicitly redefine skip() to call the + * correct parent implementation, if desired. + */ + uint32_t skip(TType type) { + auto* const prot = static_cast(this); + return ::apache::thrift::protocol::skip(*prot, type); + } + + /* + * Provide a default readBool() implementation for use with + * std::vector, that behaves the same as reading into a normal bool. + * + * Subclasses can override this if desired, but there normally shouldn't + * be a need to. + */ + uint32_t readBool(std::vector::reference value) { + bool b = false; + uint32_t ret = static_cast(this)->readBool(b); + value = b; + return ret; + } + using Super_::readBool; // so we don't hide readBool(bool&) + +protected: + TVirtualProtocol(std::shared_ptr ptrans) : Super_(ptrans) {} +}; +} +} +} // apache::thrift::protocol + +#endif // #define _THRIFT_PROTOCOL_TVIRTUALPROTOCOL_H_ 1 diff --git a/bsnes/thrift/thrift/qt/CMakeLists.txt b/bsnes/thrift/thrift/qt/CMakeLists.txt new file mode 100644 index 00000000..04a9a316 --- /dev/null +++ b/bsnes/thrift/thrift/qt/CMakeLists.txt @@ -0,0 +1,28 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +set( thriftcppqt5_SOURCES + TQIODeviceTransport.cpp + TQTcpServer.cpp +) +set(CMAKE_AUTOMOC ON) +find_package(Qt5 REQUIRED COMPONENTS Core Network) +ADD_LIBRARY_THRIFT(thriftqt5 ${thriftcppqt5_SOURCES}) +TARGET_LINK_LIBRARIES_THRIFT(thriftqt5 Qt5::Core Qt5::Network) +TARGET_LINK_LIBRARIES_THRIFT_AGAINST_THRIFT_LIBRARY(thriftqt5 thrift) diff --git a/bsnes/thrift/thrift/qt/TQIODeviceTransport.h b/bsnes/thrift/thrift/qt/TQIODeviceTransport.h new file mode 100644 index 00000000..a3b511de --- /dev/null +++ b/bsnes/thrift/thrift/qt/TQIODeviceTransport.h @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_ASYNC_TQIODEVICE_TRANSPORT_H_ +#define _THRIFT_ASYNC_TQIODEVICE_TRANSPORT_H_ 1 + +#include + +#include + +class QIODevice; + +namespace apache { +namespace thrift { +namespace transport { + +/** + * Transport that operates on a QIODevice (socket, file, etc). + */ +class TQIODeviceTransport + : public apache::thrift::transport::TVirtualTransport { +public: + explicit TQIODeviceTransport(std::shared_ptr dev); + ~TQIODeviceTransport() override; + + void open() override; + bool isOpen() const override; + bool peek() override; + void close() override; + + uint32_t readAll(uint8_t* buf, uint32_t len); + uint32_t read(uint8_t* buf, uint32_t len); + + void write(const uint8_t* buf, uint32_t len); + uint32_t write_partial(const uint8_t* buf, uint32_t len); + + void flush() override; + + uint8_t* borrow(uint8_t* buf, uint32_t* len); + void consume(uint32_t len); + +private: + TQIODeviceTransport(const TQIODeviceTransport&); + TQIODeviceTransport& operator=(const TQIODeviceTransport&); + + std::shared_ptr dev_; +}; +} +} +} // apache::thrift::transport + +#endif // #ifndef _THRIFT_ASYNC_TQIODEVICE_TRANSPORT_H_ diff --git a/bsnes/thrift/thrift/qt/TQTcpServer.h b/bsnes/thrift/thrift/qt/TQTcpServer.h new file mode 100644 index 00000000..25994ab8 --- /dev/null +++ b/bsnes/thrift/thrift/qt/TQTcpServer.h @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TASYNC_QTCP_SERVER_H_ +#define _THRIFT_TASYNC_QTCP_SERVER_H_ + +#include +#include + +#include + +namespace apache { +namespace thrift { +namespace protocol { +class TProtocolFactory; +} +} +} // apache::thrift::protocol + +namespace apache { +namespace thrift { +namespace async { + +class TAsyncProcessor; + +/** + * Server that uses Qt to listen for connections. + * Simply give it a QTcpServer that is listening, along with an async + * processor and a protocol factory, and then run the Qt event loop. + */ +class TQTcpServer : public QObject { + Q_OBJECT +public: + TQTcpServer(std::shared_ptr server, + std::shared_ptr processor, + std::shared_ptr protocolFactory, + QObject* parent = nullptr); + ~TQTcpServer() override; + +private Q_SLOTS: + void processIncoming(); + void beginDecode(); + void socketClosed(); + void deleteConnectionContext(QTcpSocket* connection); + +private: + Q_DISABLE_COPY(TQTcpServer) + + struct ConnectionContext; + + void scheduleDeleteConnectionContext(QTcpSocket* connection); + void finish(std::shared_ptr ctx, bool healthy); + + std::shared_ptr server_; + std::shared_ptr processor_; + std::shared_ptr pfact_; + + typedef std::map > ConnectionContextMap; + ConnectionContextMap ctxMap_; +}; +} +} +} // apache::thrift::async + +#endif // #ifndef _THRIFT_TASYNC_QTCP_SERVER_H_ diff --git a/bsnes/thrift/thrift/server/TConnectedClient.h b/bsnes/thrift/thrift/server/TConnectedClient.h new file mode 100644 index 00000000..071571a8 --- /dev/null +++ b/bsnes/thrift/thrift/server/TConnectedClient.h @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_SERVER_TCONNECTEDCLIENT_H_ +#define _THRIFT_SERVER_TCONNECTEDCLIENT_H_ 1 + +#include +#include +#include +#include +#include + +namespace apache { +namespace thrift { +namespace server { + +/** + * This represents a client connected to a TServer. The + * processing loop for a client must provide some required + * functionality common to all implementations so it is + * encapsulated here. + */ + +class TConnectedClient : public apache::thrift::concurrency::Runnable { +public: + /** + * Constructor. + * + * @param[in] processor the TProcessor + * @param[in] inputProtocol the input TProtocol + * @param[in] outputProtocol the output TProtocol + * @param[in] eventHandler the server event handler + * @param[in] client the TTransport representing the client + */ + TConnectedClient( + const std::shared_ptr& processor, + const std::shared_ptr& inputProtocol, + const std::shared_ptr& outputProtocol, + const std::shared_ptr& eventHandler, + const std::shared_ptr& client); + + /** + * Destructor. + */ + ~TConnectedClient() override; + + /** + * Drive the client until it is done. + * The client processing loop is: + * + * [optional] call eventHandler->createContext once + * [optional] call eventHandler->processContext per request + * call processor->process per request + * handle expected transport exceptions: + * END_OF_FILE means the client is gone + * INTERRUPTED means the client was interrupted + * by TServerTransport::interruptChildren() + * handle unexpected transport exceptions by logging + * handle standard exceptions by logging + * handle unexpected exceptions by logging + * cleanup() + */ + void run() override /* override */; + +protected: + /** + * Cleanup after a client. This happens if the client disconnects, + * or if the server is stopped, or if an exception occurs. + * + * The cleanup processing is: + * [optional] call eventHandler->deleteContext once + * close the inputProtocol's TTransport + * close the outputProtocol's TTransport + * close the client + */ + virtual void cleanup(); + +private: + std::shared_ptr processor_; + std::shared_ptr inputProtocol_; + std::shared_ptr outputProtocol_; + std::shared_ptr eventHandler_; + std::shared_ptr client_; + + /** + * Context acquired from the eventHandler_ if one exists. + */ + void* opaqueContext_; +}; +} +} +} + +#endif // #ifndef _THRIFT_SERVER_TCONNECTEDCLIENT_H_ diff --git a/bsnes/thrift/thrift/server/TNonblockingServer.h b/bsnes/thrift/thrift/server/TNonblockingServer.h new file mode 100644 index 00000000..65e569dc --- /dev/null +++ b/bsnes/thrift/thrift/server/TNonblockingServer.h @@ -0,0 +1,859 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_SERVER_TNONBLOCKINGSERVER_H_ +#define _THRIFT_SERVER_TNONBLOCKINGSERVER_H_ 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include + +namespace apache { +namespace thrift { +namespace server { + +using apache::thrift::transport::TMemoryBuffer; +using apache::thrift::transport::TSocket; +using apache::thrift::transport::TNonblockingServerTransport; +using apache::thrift::protocol::TProtocol; +using apache::thrift::concurrency::Runnable; +using apache::thrift::concurrency::ThreadManager; +using apache::thrift::concurrency::ThreadFactory; +using apache::thrift::concurrency::Thread; +using apache::thrift::concurrency::Mutex; +using apache::thrift::concurrency::Guard; + +#ifdef LIBEVENT_VERSION_NUMBER +#define LIBEVENT_VERSION_MAJOR (LIBEVENT_VERSION_NUMBER >> 24) +#define LIBEVENT_VERSION_MINOR ((LIBEVENT_VERSION_NUMBER >> 16) & 0xFF) +#define LIBEVENT_VERSION_REL ((LIBEVENT_VERSION_NUMBER >> 8) & 0xFF) +#else +// assume latest version 1 series +#define LIBEVENT_VERSION_MAJOR 1 +#define LIBEVENT_VERSION_MINOR 14 +#define LIBEVENT_VERSION_REL 13 +#define LIBEVENT_VERSION_NUMBER \ + ((LIBEVENT_VERSION_MAJOR << 24) | (LIBEVENT_VERSION_MINOR << 16) | (LIBEVENT_VERSION_REL << 8)) +#endif + +#if LIBEVENT_VERSION_NUMBER < 0x02000000 +typedef THRIFT_SOCKET evutil_socket_t; +#endif + +#ifndef SOCKOPT_CAST_T +#ifndef _WIN32 +#define SOCKOPT_CAST_T void +#else +#define SOCKOPT_CAST_T char +#endif // _WIN32 +#endif + +template +inline const SOCKOPT_CAST_T* const_cast_sockopt(const T* v) { + return reinterpret_cast(v); +} + +template +inline SOCKOPT_CAST_T* cast_sockopt(T* v) { + return reinterpret_cast(v); +} + +/** + * This is a non-blocking server in C++ for high performance that + * operates a set of IO threads (by default only one). It assumes that + * all incoming requests are framed with a 4 byte length indicator and + * writes out responses using the same framing. + */ + +/// Overload condition actions. +enum TOverloadAction { + T_OVERLOAD_NO_ACTION, ///< Don't handle overload */ + T_OVERLOAD_CLOSE_ON_ACCEPT, ///< Drop new connections immediately */ + T_OVERLOAD_DRAIN_TASK_QUEUE ///< Drop some tasks from head of task queue */ +}; + +class TNonblockingIOThread; + +class TNonblockingServer : public TServer { +private: + class TConnection; + + friend class TNonblockingIOThread; + +private: + /// Listen backlog + static const int LISTEN_BACKLOG = 1024; + + /// Default limit on size of idle connection pool + static const size_t CONNECTION_STACK_LIMIT = 1024; + + /// Default limit on frame size + static const int MAX_FRAME_SIZE = 256 * 1024 * 1024; + + /// Default limit on total number of connected sockets + static const int MAX_CONNECTIONS = INT_MAX; + + /// Default limit on connections in handler/task processing + static const int MAX_ACTIVE_PROCESSORS = INT_MAX; + + /// Default size of write buffer + static const int WRITE_BUFFER_DEFAULT_SIZE = 1024; + + /// Maximum size of read buffer allocated to idle connection (0 = unlimited) + static const int IDLE_READ_BUFFER_LIMIT = 1024; + + /// Maximum size of write buffer allocated to idle connection (0 = unlimited) + static const int IDLE_WRITE_BUFFER_LIMIT = 1024; + + /// # of calls before resizing oversized buffers (0 = check only on close) + static const int RESIZE_BUFFER_EVERY_N = 512; + + /// # of IO threads to use by default + static const int DEFAULT_IO_THREADS = 1; + + /// # of IO threads this server will use + size_t numIOThreads_; + + /// Whether to set high scheduling priority for IO threads + bool useHighPriorityIOThreads_; + + /// Server socket file descriptor + THRIFT_SOCKET serverSocket_; + + /// The optional user-provided event-base (for single-thread servers) + event_base* userEventBase_; + + /// For processing via thread pool, may be nullptr + std::shared_ptr threadManager_; + + /// Is thread pool processing? + bool threadPoolProcessing_; + + // Factory to create the IO threads + std::shared_ptr ioThreadFactory_; + + // Vector of IOThread objects that will handle our IO + std::vector > ioThreads_; + + // Index of next IO Thread to be used (for round-robin) + uint32_t nextIOThread_; + + // Synchronizes access to connection stack and similar data + Mutex connMutex_; + + /// Number of TConnection object we've created + size_t numTConnections_; + + /// Number of Connections processing or waiting to process + size_t numActiveProcessors_; + + /// Limit for how many TConnection objects to cache + size_t connectionStackLimit_; + + /// Limit for number of connections processing or waiting to process + size_t maxActiveProcessors_; + + /// Limit for number of open connections + size_t maxConnections_; + + /// Limit for frame size + size_t maxFrameSize_; + + /// Time in milliseconds before an unperformed task expires (0 == infinite). + int64_t taskExpireTime_; + + /** + * Hysteresis for overload state. This is the fraction of the overload + * value that needs to be reached before the overload state is cleared; + * must be <= 1.0. + */ + double overloadHysteresis_; + + /// Action to take when we're overloaded. + TOverloadAction overloadAction_; + + /** + * The write buffer is initialized (and when idleWriteBufferLimit_ is checked + * and found to be exceeded, reinitialized) to this size. + */ + size_t writeBufferDefaultSize_; + + /** + * Max read buffer size for an idle TConnection. When we place an idle + * TConnection into connectionStack_ or on every resizeBufferEveryN_ calls, + * we will free the buffer (such that it will be reinitialized by the next + * received frame) if it has exceeded this limit. 0 disables this check. + */ + size_t idleReadBufferLimit_; + + /** + * Max write buffer size for an idle connection. When we place an idle + * TConnection into connectionStack_ or on every resizeBufferEveryN_ calls, + * we insure that its write buffer is <= to this size; otherwise we + * replace it with a new one of writeBufferDefaultSize_ bytes to insure that + * idle connections don't hog memory. 0 disables this check. + */ + size_t idleWriteBufferLimit_; + + /** + * Every N calls we check the buffer size limits on a connected TConnection. + * 0 disables (i.e. the checks are only done when a connection closes). + */ + int32_t resizeBufferEveryN_; + + /// Set if we are currently in an overloaded state. + bool overloaded_; + + /// Count of connections dropped since overload started + uint32_t nConnectionsDropped_; + + /// Count of connections dropped on overload since server started + uint64_t nTotalConnectionsDropped_; + + /** + * This is a stack of all the objects that have been created but that + * are NOT currently in use. When we close a connection, we place it on this + * stack so that the object can be reused later, rather than freeing the + * memory and reallocating a new object later. + */ + std::stack connectionStack_; + + /** + * This container holds pointers to all active connections. This container + * allows the server to clean up unlcosed connection objects at destruction, + * which in turn allows their transports, protocols, processors and handlers + * to deallocate and clean up correctly. + */ + std::vector activeConnections_; + + /* + */ + std::shared_ptr serverTransport_; + + /** + * Called when server socket had something happen. We accept all waiting + * client connections on listen socket fd and assign TConnection objects + * to handle those requests. + * + * @param which the event flag that triggered the handler. + */ + void handleEvent(THRIFT_SOCKET fd, short which); + + void init() { + serverSocket_ = THRIFT_INVALID_SOCKET; + numIOThreads_ = DEFAULT_IO_THREADS; + nextIOThread_ = 0; + useHighPriorityIOThreads_ = false; + userEventBase_ = nullptr; + threadPoolProcessing_ = false; + numTConnections_ = 0; + numActiveProcessors_ = 0; + connectionStackLimit_ = CONNECTION_STACK_LIMIT; + maxActiveProcessors_ = MAX_ACTIVE_PROCESSORS; + maxConnections_ = MAX_CONNECTIONS; + maxFrameSize_ = MAX_FRAME_SIZE; + taskExpireTime_ = 0; + overloadHysteresis_ = 0.8; + overloadAction_ = T_OVERLOAD_NO_ACTION; + writeBufferDefaultSize_ = WRITE_BUFFER_DEFAULT_SIZE; + idleReadBufferLimit_ = IDLE_READ_BUFFER_LIMIT; + idleWriteBufferLimit_ = IDLE_WRITE_BUFFER_LIMIT; + resizeBufferEveryN_ = RESIZE_BUFFER_EVERY_N; + overloaded_ = false; + nConnectionsDropped_ = 0; + nTotalConnectionsDropped_ = 0; + } + +public: + TNonblockingServer(const std::shared_ptr& processorFactory, + const std::shared_ptr& serverTransport) + : TServer(processorFactory), serverTransport_(serverTransport) { + init(); + } + + TNonblockingServer(const std::shared_ptr& processor, + const std::shared_ptr& serverTransport) + : TServer(processor), serverTransport_(serverTransport) { + init(); + } + + + TNonblockingServer(const std::shared_ptr& processorFactory, + const std::shared_ptr& protocolFactory, + const std::shared_ptr& serverTransport, + const std::shared_ptr& threadManager + = std::shared_ptr()) + : TServer(processorFactory), serverTransport_(serverTransport) { + init(); + + setInputProtocolFactory(protocolFactory); + setOutputProtocolFactory(protocolFactory); + setThreadManager(threadManager); + } + + TNonblockingServer(const std::shared_ptr& processor, + const std::shared_ptr& protocolFactory, + const std::shared_ptr& serverTransport, + const std::shared_ptr& threadManager + = std::shared_ptr()) + : TServer(processor), serverTransport_(serverTransport) { + init(); + + setInputProtocolFactory(protocolFactory); + setOutputProtocolFactory(protocolFactory); + setThreadManager(threadManager); + } + + TNonblockingServer(const std::shared_ptr& processorFactory, + const std::shared_ptr& inputTransportFactory, + const std::shared_ptr& outputTransportFactory, + const std::shared_ptr& inputProtocolFactory, + const std::shared_ptr& outputProtocolFactory, + const std::shared_ptr& serverTransport, + const std::shared_ptr& threadManager + = std::shared_ptr()) + : TServer(processorFactory), serverTransport_(serverTransport) { + init(); + + setInputTransportFactory(inputTransportFactory); + setOutputTransportFactory(outputTransportFactory); + setInputProtocolFactory(inputProtocolFactory); + setOutputProtocolFactory(outputProtocolFactory); + setThreadManager(threadManager); + } + + TNonblockingServer(const std::shared_ptr& processor, + const std::shared_ptr& inputTransportFactory, + const std::shared_ptr& outputTransportFactory, + const std::shared_ptr& inputProtocolFactory, + const std::shared_ptr& outputProtocolFactory, + const std::shared_ptr& serverTransport, + const std::shared_ptr& threadManager + = std::shared_ptr()) + : TServer(processor), serverTransport_(serverTransport) { + init(); + + setInputTransportFactory(inputTransportFactory); + setOutputTransportFactory(outputTransportFactory); + setInputProtocolFactory(inputProtocolFactory); + setOutputProtocolFactory(outputProtocolFactory); + setThreadManager(threadManager); + } + + ~TNonblockingServer() override; + + void setThreadManager(std::shared_ptr threadManager); + + int getListenPort() { return serverTransport_->getListenPort(); } + + std::shared_ptr getThreadManager() { return threadManager_; } + + /** + * Sets the number of IO threads used by this server. Can only be used before + * the call to serve() and has no effect afterwards. + */ + void setNumIOThreads(size_t numThreads) { + numIOThreads_ = numThreads; + // User-provided event-base doesn't works for multi-threaded servers + assert(numIOThreads_ <= 1 || !userEventBase_); + } + + /** Return whether the IO threads will get high scheduling priority */ + bool useHighPriorityIOThreads() const { return useHighPriorityIOThreads_; } + + /** Set whether the IO threads will get high scheduling priority. */ + void setUseHighPriorityIOThreads(bool val) { useHighPriorityIOThreads_ = val; } + + /** Return the number of IO threads used by this server. */ + size_t getNumIOThreads() const { return numIOThreads_; } + + /** + * Get the maximum number of unused TConnection we will hold in reserve. + * + * @return the current limit on TConnection pool size. + */ + size_t getConnectionStackLimit() const { return connectionStackLimit_; } + + /** + * Set the maximum number of unused TConnection we will hold in reserve. + * + * @param sz the new limit for TConnection pool size. + */ + void setConnectionStackLimit(size_t sz) { connectionStackLimit_ = sz; } + + bool isThreadPoolProcessing() const { return threadPoolProcessing_; } + + void addTask(std::shared_ptr task) { + threadManager_->add(task, 0LL, taskExpireTime_); + } + + /** + * Return the count of sockets currently connected to. + * + * @return count of connected sockets. + */ + size_t getNumConnections() const { return numTConnections_; } + + /** + * Return the count of sockets currently connected to. + * + * @return count of connected sockets. + */ + size_t getNumActiveConnections() const { return getNumConnections() - getNumIdleConnections(); } + + /** + * Return the count of connection objects allocated but not in use. + * + * @return count of idle connection objects. + */ + size_t getNumIdleConnections() const { return connectionStack_.size(); } + + /** + * Return count of number of connections which are currently processing. + * This is defined as a connection where all data has been received and + * either assigned a task (when threading) or passed to a handler (when + * not threading), and where the handler has not yet returned. + * + * @return # of connections currently processing. + */ + size_t getNumActiveProcessors() const { return numActiveProcessors_; } + + /// Increment the count of connections currently processing. + void incrementActiveProcessors() { + Guard g(connMutex_); + ++numActiveProcessors_; + } + + /// Decrement the count of connections currently processing. + void decrementActiveProcessors() { + Guard g(connMutex_); + if (numActiveProcessors_ > 0) { + --numActiveProcessors_; + } + } + + /** + * Get the maximum # of connections allowed before overload. + * + * @return current setting. + */ + size_t getMaxConnections() const { return maxConnections_; } + + /** + * Set the maximum # of connections allowed before overload. + * + * @param maxConnections new setting for maximum # of connections. + */ + void setMaxConnections(size_t maxConnections) { maxConnections_ = maxConnections; } + + /** + * Get the maximum # of connections waiting in handler/task before overload. + * + * @return current setting. + */ + size_t getMaxActiveProcessors() const { return maxActiveProcessors_; } + + /** + * Set the maximum # of connections waiting in handler/task before overload. + * + * @param maxActiveProcessors new setting for maximum # of active processes. + */ + void setMaxActiveProcessors(size_t maxActiveProcessors) { + maxActiveProcessors_ = maxActiveProcessors; + } + + /** + * Get the maximum allowed frame size. + * + * If a client tries to send a message larger than this limit, + * its connection will be closed. + * + * @return Maxium frame size, in bytes. + */ + size_t getMaxFrameSize() const { return maxFrameSize_; } + + /** + * Set the maximum allowed frame size. + * + * @param maxFrameSize The new maximum frame size. + */ + void setMaxFrameSize(size_t maxFrameSize) { maxFrameSize_ = maxFrameSize; } + + /** + * Get fraction of maximum limits before an overload condition is cleared. + * + * @return hysteresis fraction + */ + double getOverloadHysteresis() const { return overloadHysteresis_; } + + /** + * Set fraction of maximum limits before an overload condition is cleared. + * A good value would probably be between 0.5 and 0.9. + * + * @param hysteresisFraction fraction <= 1.0. + */ + void setOverloadHysteresis(double hysteresisFraction) { + if (hysteresisFraction <= 1.0 && hysteresisFraction > 0.0) { + overloadHysteresis_ = hysteresisFraction; + } + } + + /** + * Get the action the server will take on overload. + * + * @return a TOverloadAction enum value for the currently set action. + */ + TOverloadAction getOverloadAction() const { return overloadAction_; } + + /** + * Set the action the server is to take on overload. + * + * @param overloadAction a TOverloadAction enum value for the action. + */ + void setOverloadAction(TOverloadAction overloadAction) { overloadAction_ = overloadAction; } + + /** + * Get the time in milliseconds after which a task expires (0 == infinite). + * + * @return a 64-bit time in milliseconds. + */ + int64_t getTaskExpireTime() const { return taskExpireTime_; } + + /** + * Set the time in milliseconds after which a task expires (0 == infinite). + * + * @param taskExpireTime a 64-bit time in milliseconds. + */ + void setTaskExpireTime(int64_t taskExpireTime) { taskExpireTime_ = taskExpireTime; } + + /** + * Determine if the server is currently overloaded. + * This function checks the maximums for open connections and connections + * currently in processing, and sets an overload condition if they are + * exceeded. The overload will persist until both values are below the + * current hysteresis fraction of their maximums. + * + * @return true if an overload condition exists, false if not. + */ + bool serverOverloaded(); + + /** Pop and discard next task on threadpool wait queue. + * + * @return true if a task was discarded, false if the wait queue was empty. + */ + bool drainPendingTask(); + + /** + * Get the starting size of a TConnection object's write buffer. + * + * @return # bytes we initialize a TConnection object's write buffer to. + */ + size_t getWriteBufferDefaultSize() const { return writeBufferDefaultSize_; } + + /** + * Set the starting size of a TConnection object's write buffer. + * + * @param size # bytes we initialize a TConnection object's write buffer to. + */ + void setWriteBufferDefaultSize(size_t size) { writeBufferDefaultSize_ = size; } + + /** + * Get the maximum size of read buffer allocated to idle TConnection objects. + * + * @return # bytes beyond which we will dealloc idle buffer. + */ + size_t getIdleReadBufferLimit() const { return idleReadBufferLimit_; } + + /** + * [NOTE: This is for backwards compatibility, use getIdleReadBufferLimit().] + * Get the maximum size of read buffer allocated to idle TConnection objects. + * + * @return # bytes beyond which we will dealloc idle buffer. + */ + size_t getIdleBufferMemLimit() const { return idleReadBufferLimit_; } + + /** + * Set the maximum size read buffer allocated to idle TConnection objects. + * If a TConnection object is found (either on connection close or between + * calls when resizeBufferEveryN_ is set) with more than this much memory + * allocated to its read buffer, we free it and allow it to be reinitialized + * on the next received frame. + * + * @param limit of bytes beyond which we will shrink buffers when checked. + */ + void setIdleReadBufferLimit(size_t limit) { idleReadBufferLimit_ = limit; } + + /** + * [NOTE: This is for backwards compatibility, use setIdleReadBufferLimit().] + * Set the maximum size read buffer allocated to idle TConnection objects. + * If a TConnection object is found (either on connection close or between + * calls when resizeBufferEveryN_ is set) with more than this much memory + * allocated to its read buffer, we free it and allow it to be reinitialized + * on the next received frame. + * + * @param limit of bytes beyond which we will shrink buffers when checked. + */ + void setIdleBufferMemLimit(size_t limit) { idleReadBufferLimit_ = limit; } + + /** + * Get the maximum size of write buffer allocated to idle TConnection objects. + * + * @return # bytes beyond which we will reallocate buffers when checked. + */ + size_t getIdleWriteBufferLimit() const { return idleWriteBufferLimit_; } + + /** + * Set the maximum size write buffer allocated to idle TConnection objects. + * If a TConnection object is found (either on connection close or between + * calls when resizeBufferEveryN_ is set) with more than this much memory + * allocated to its write buffer, we destroy and construct that buffer with + * writeBufferDefaultSize_ bytes. + * + * @param limit of bytes beyond which we will shrink buffers when idle. + */ + void setIdleWriteBufferLimit(size_t limit) { idleWriteBufferLimit_ = limit; } + + /** + * Get # of calls made between buffer size checks. 0 means disabled. + * + * @return # of calls between buffer size checks. + */ + int32_t getResizeBufferEveryN() const { return resizeBufferEveryN_; } + + /** + * Check buffer sizes every "count" calls. This allows buffer limits + * to be enforced for persistent connections with a controllable degree + * of overhead. 0 disables checks except at connection close. + * + * @param count the number of calls between checks, or 0 to disable + */ + void setResizeBufferEveryN(int32_t count) { resizeBufferEveryN_ = count; } + + /** + * Main workhorse function, starts up the server listening on a port and + * loops over the libevent handler. + */ + void serve() override; + + /** + * Causes the server to terminate gracefully (can be called from any thread). + */ + void stop() override; + + /// Creates a socket to listen on and binds it to the local port. + void createAndListenOnSocket(); + + /** + * Register the optional user-provided event-base (for single-thread servers) + * + * This method should be used when the server is running in a single-thread + * mode, and the event base is provided by the user (i.e., the caller). + * + * @param user_event_base the user-provided event-base. The user is + * responsible for freeing the event base memory. + */ + void registerEvents(event_base* user_event_base); + + /** + * Returns the optional user-provided event-base (for single-thread servers). + */ + event_base* getUserEventBase() const { return userEventBase_; } + + /** Some transports, like THeaderTransport, require passing through + * the framing size instead of stripping it. + */ + bool getHeaderTransport(); + +private: + /** + * Callback function that the threadmanager calls when a task reaches + * its expiration time. It is needed to clean up the expired connection. + * + * @param task the runnable associated with the expired task. + */ + void expireClose(std::shared_ptr task); + + /** + * Return an initialized connection object. Creates or recovers from + * pool a TConnection and initializes it with the provided socket FD + * and flags. + * + * @param socket FD of socket associated with this connection. + * @param addr the sockaddr of the client + * @param addrLen the length of addr + * @return pointer to initialized TConnection object. + */ + TConnection* createConnection(std::shared_ptr socket); + + /** + * Returns a connection to pool or deletion. If the connection pool + * (a stack) isn't full, place the connection object on it, otherwise + * just delete it. + * + * @param connection the TConection being returned. + */ + void returnConnection(TConnection* connection); +}; + +class TNonblockingIOThread : public Runnable { +public: + // Creates an IO thread and sets up the event base. The listenSocket should + // be a valid FD on which listen() has already been called. If the + // listenSocket is < 0, accepting will not be done. + TNonblockingIOThread(TNonblockingServer* server, + int number, + THRIFT_SOCKET listenSocket, + bool useHighPriority); + + ~TNonblockingIOThread() override; + + // Returns the event-base for this thread. + event_base* getEventBase() const { return eventBase_; } + + // Returns the server for this thread. + TNonblockingServer* getServer() const { return server_; } + + // Returns the number of this IO thread. + int getThreadNumber() const { return number_; } + + // Returns the thread id associated with this object. This should + // only be called after the thread has been started. + Thread::id_t getThreadId() const { return threadId_; } + + // Returns the send-fd for task complete notifications. + evutil_socket_t getNotificationSendFD() const { return notificationPipeFDs_[1]; } + + // Returns the read-fd for task complete notifications. + evutil_socket_t getNotificationRecvFD() const { return notificationPipeFDs_[0]; } + + // Returns the actual thread object associated with this IO thread. + std::shared_ptr getThread() const { return thread_; } + + // Sets the actual thread object associated with this IO thread. + void setThread(const std::shared_ptr& t) { thread_ = t; } + + // Used by TConnection objects to indicate processing has finished. + bool notify(TNonblockingServer::TConnection* conn); + + // Enters the event loop and does not return until a call to stop(). + void run() override; + + // Exits the event loop as soon as possible. + void stop(); + + // Ensures that the event-loop thread is fully finished and shut down. + void join(); + + /// Registers the events for the notification & listen sockets + void registerEvents(); + +private: + /** + * C-callable event handler for signaling task completion. Provides a + * callback that libevent can understand that will read a connection + * object's address from a pipe and call connection->transition() for + * that object. + * + * @param fd the descriptor the event occurred on. + */ + static void notifyHandler(evutil_socket_t fd, short which, void* v); + + /** + * C-callable event handler for listener events. Provides a callback + * that libevent can understand which invokes server->handleEvent(). + * + * @param fd the descriptor the event occurred on. + * @param which the flags associated with the event. + * @param v void* callback arg where we placed TNonblockingServer's "this". + */ + static void listenHandler(evutil_socket_t fd, short which, void* v) { + ((TNonblockingServer*)v)->handleEvent(fd, which); + } + + /// Exits the loop ASAP in case of shutdown or error. + void breakLoop(bool error); + + /// Create the pipe used to notify I/O process of task completion. + void createNotificationPipe(); + + /// Unregisters our events for notification and listen sockets. + void cleanupEvents(); + + /// Sets (or clears) high priority scheduling status for the current thread. + void setCurrentThreadHighPriority(bool value); + +private: + /// associated server + TNonblockingServer* server_; + + /// thread number (for debugging). + const int number_; + + /// The actual physical thread id. + Thread::id_t threadId_; + + /// If listenSocket_ >= 0, adds an event on the event_base to accept conns + THRIFT_SOCKET listenSocket_; + + /// Sets a high scheduling priority when running + bool useHighPriority_; + + /// pointer to eventbase to be used for looping + event_base* eventBase_; + + /// Set to true if this class is responsible for freeing the event base + /// memory. + bool ownEventBase_; + + /// Used with eventBase_ for connection events (only in listener thread) + struct event serverEvent_; + + /// Used with eventBase_ for task completion notification + struct event notificationEvent_; + + /// File descriptors for pipe used for task completion notification. + evutil_socket_t notificationPipeFDs_[2]; + + /// Actual IO Thread + std::shared_ptr thread_; +}; +} +} +} // apache::thrift::server + +#endif // #ifndef _THRIFT_SERVER_TNONBLOCKINGSERVER_H_ diff --git a/bsnes/thrift/thrift/server/TServer.h b/bsnes/thrift/thrift/server/TServer.h new file mode 100644 index 00000000..d2eabde1 --- /dev/null +++ b/bsnes/thrift/thrift/server/TServer.h @@ -0,0 +1,273 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_SERVER_TSERVER_H_ +#define _THRIFT_SERVER_TSERVER_H_ 1 + +#include +#include +#include +#include + +#include + +namespace apache { +namespace thrift { +namespace server { + +using apache::thrift::TProcessor; +using apache::thrift::protocol::TBinaryProtocolFactory; +using apache::thrift::protocol::TProtocol; +using apache::thrift::protocol::TProtocolFactory; +using apache::thrift::transport::TServerTransport; +using apache::thrift::transport::TTransport; +using apache::thrift::transport::TTransportFactory; + +/** + * Virtual interface class that can handle events from the server core. To + * use this you should subclass it and implement the methods that you care + * about. Your subclass can also store local data that you may care about, + * such as additional "arguments" to these methods (stored in the object + * instance's state). + */ +class TServerEventHandler { +public: + virtual ~TServerEventHandler() = default; + + /** + * Called before the server begins. + */ + virtual void preServe() {} + + /** + * Called when a new client has connected and is about to being processing. + */ + virtual void* createContext(std::shared_ptr input, + std::shared_ptr output) { + (void)input; + (void)output; + return nullptr; + } + + /** + * Called when a client has finished request-handling to delete server + * context. + */ + virtual void deleteContext(void* serverContext, + std::shared_ptr input, + std::shared_ptr output) { + (void)serverContext; + (void)input; + (void)output; + } + + /** + * Called when a client is about to call the processor. + */ + virtual void processContext(void* serverContext, std::shared_ptr transport) { + (void)serverContext; + (void)transport; + } + +protected: + /** + * Prevent direct instantiation. + */ + TServerEventHandler() = default; +}; + +/** + * Thrift server. + * + */ +class TServer : public concurrency::Runnable { +public: + ~TServer() override = default; + + virtual void serve() = 0; + + virtual void stop() {} + + // Allows running the server as a Runnable thread + void run() override { serve(); } + + std::shared_ptr getProcessorFactory() { return processorFactory_; } + + std::shared_ptr getServerTransport() { return serverTransport_; } + + std::shared_ptr getInputTransportFactory() { return inputTransportFactory_; } + + std::shared_ptr getOutputTransportFactory() { + return outputTransportFactory_; + } + + std::shared_ptr getInputProtocolFactory() { return inputProtocolFactory_; } + + std::shared_ptr getOutputProtocolFactory() { return outputProtocolFactory_; } + + std::shared_ptr getEventHandler() { return eventHandler_; } + +protected: + TServer(const std::shared_ptr& processorFactory) + : processorFactory_(processorFactory) { + setInputTransportFactory(std::shared_ptr(new TTransportFactory())); + setOutputTransportFactory(std::shared_ptr(new TTransportFactory())); + setInputProtocolFactory(std::shared_ptr(new TBinaryProtocolFactory())); + setOutputProtocolFactory(std::shared_ptr(new TBinaryProtocolFactory())); + } + + TServer(const std::shared_ptr& processor) + : processorFactory_(new TSingletonProcessorFactory(processor)) { + setInputTransportFactory(std::shared_ptr(new TTransportFactory())); + setOutputTransportFactory(std::shared_ptr(new TTransportFactory())); + setInputProtocolFactory(std::shared_ptr(new TBinaryProtocolFactory())); + setOutputProtocolFactory(std::shared_ptr(new TBinaryProtocolFactory())); + } + + TServer(const std::shared_ptr& processorFactory, + const std::shared_ptr& serverTransport) + : processorFactory_(processorFactory), serverTransport_(serverTransport) { + setInputTransportFactory(std::shared_ptr(new TTransportFactory())); + setOutputTransportFactory(std::shared_ptr(new TTransportFactory())); + setInputProtocolFactory(std::shared_ptr(new TBinaryProtocolFactory())); + setOutputProtocolFactory(std::shared_ptr(new TBinaryProtocolFactory())); + } + + TServer(const std::shared_ptr& processor, + const std::shared_ptr& serverTransport) + : processorFactory_(new TSingletonProcessorFactory(processor)), + serverTransport_(serverTransport) { + setInputTransportFactory(std::shared_ptr(new TTransportFactory())); + setOutputTransportFactory(std::shared_ptr(new TTransportFactory())); + setInputProtocolFactory(std::shared_ptr(new TBinaryProtocolFactory())); + setOutputProtocolFactory(std::shared_ptr(new TBinaryProtocolFactory())); + } + + TServer(const std::shared_ptr& processorFactory, + const std::shared_ptr& serverTransport, + const std::shared_ptr& transportFactory, + const std::shared_ptr& protocolFactory) + : processorFactory_(processorFactory), + serverTransport_(serverTransport), + inputTransportFactory_(transportFactory), + outputTransportFactory_(transportFactory), + inputProtocolFactory_(protocolFactory), + outputProtocolFactory_(protocolFactory) {} + + TServer(const std::shared_ptr& processor, + const std::shared_ptr& serverTransport, + const std::shared_ptr& transportFactory, + const std::shared_ptr& protocolFactory) + : processorFactory_(new TSingletonProcessorFactory(processor)), + serverTransport_(serverTransport), + inputTransportFactory_(transportFactory), + outputTransportFactory_(transportFactory), + inputProtocolFactory_(protocolFactory), + outputProtocolFactory_(protocolFactory) {} + + TServer(const std::shared_ptr& processorFactory, + const std::shared_ptr& serverTransport, + const std::shared_ptr& inputTransportFactory, + const std::shared_ptr& outputTransportFactory, + const std::shared_ptr& inputProtocolFactory, + const std::shared_ptr& outputProtocolFactory) + : processorFactory_(processorFactory), + serverTransport_(serverTransport), + inputTransportFactory_(inputTransportFactory), + outputTransportFactory_(outputTransportFactory), + inputProtocolFactory_(inputProtocolFactory), + outputProtocolFactory_(outputProtocolFactory) {} + + TServer(const std::shared_ptr& processor, + const std::shared_ptr& serverTransport, + const std::shared_ptr& inputTransportFactory, + const std::shared_ptr& outputTransportFactory, + const std::shared_ptr& inputProtocolFactory, + const std::shared_ptr& outputProtocolFactory) + : processorFactory_(new TSingletonProcessorFactory(processor)), + serverTransport_(serverTransport), + inputTransportFactory_(inputTransportFactory), + outputTransportFactory_(outputTransportFactory), + inputProtocolFactory_(inputProtocolFactory), + outputProtocolFactory_(outputProtocolFactory) {} + + /** + * Get a TProcessor to handle calls on a particular connection. + * + * This method should only be called once per connection (never once per + * call). This allows the TProcessorFactory to return a different processor + * for each connection if it desires. + */ + std::shared_ptr getProcessor(std::shared_ptr inputProtocol, + std::shared_ptr outputProtocol, + std::shared_ptr transport) { + TConnectionInfo connInfo; + connInfo.input = inputProtocol; + connInfo.output = outputProtocol; + connInfo.transport = transport; + return processorFactory_->getProcessor(connInfo); + } + + // Class variables + std::shared_ptr processorFactory_; + std::shared_ptr serverTransport_; + + std::shared_ptr inputTransportFactory_; + std::shared_ptr outputTransportFactory_; + + std::shared_ptr inputProtocolFactory_; + std::shared_ptr outputProtocolFactory_; + + std::shared_ptr eventHandler_; + +public: + void setInputTransportFactory(std::shared_ptr inputTransportFactory) { + inputTransportFactory_ = inputTransportFactory; + } + + void setOutputTransportFactory(std::shared_ptr outputTransportFactory) { + outputTransportFactory_ = outputTransportFactory; + } + + void setInputProtocolFactory(std::shared_ptr inputProtocolFactory) { + inputProtocolFactory_ = inputProtocolFactory; + } + + void setOutputProtocolFactory(std::shared_ptr outputProtocolFactory) { + outputProtocolFactory_ = outputProtocolFactory; + } + + void setServerEventHandler(std::shared_ptr eventHandler) { + eventHandler_ = eventHandler; + } +}; + +/** + * Helper function to increase the max file descriptors limit + * for the current process and all of its children. + * By default, tries to increase it to as much as 2^24. + */ +#ifdef HAVE_SYS_RESOURCE_H +int increase_max_fds(int max_fds = (1 << 24)); +#endif +} +} +} // apache::thrift::server + +#endif // #ifndef _THRIFT_SERVER_TSERVER_H_ diff --git a/bsnes/thrift/thrift/server/TServerFramework.h b/bsnes/thrift/thrift/server/TServerFramework.h new file mode 100644 index 00000000..dac79ef5 --- /dev/null +++ b/bsnes/thrift/thrift/server/TServerFramework.h @@ -0,0 +1,184 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_SERVER_TSERVERFRAMEWORK_H_ +#define _THRIFT_SERVER_TSERVERFRAMEWORK_H_ 1 + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace apache { +namespace thrift { +namespace server { + +/** + * TServerFramework provides a single consolidated processing loop for + * servers. By having a single processing loop, behavior between servers + * is more predictable and maintenance cost is lowered. Implementations + * of TServerFramework must provide a method to deal with a client that + * connects and one that disconnects. + * + * While this functionality could be rolled directly into TServer, and + * probably should be, it would break the TServer interface contract so + * to maintain backwards compatibility for third party servers, no TServers + * were harmed in the making of this class. + */ +class TServerFramework : public TServer { +public: + TServerFramework( + const std::shared_ptr& processorFactory, + const std::shared_ptr& serverTransport, + const std::shared_ptr& transportFactory, + const std::shared_ptr& protocolFactory); + + TServerFramework( + const std::shared_ptr& processor, + const std::shared_ptr& serverTransport, + const std::shared_ptr& transportFactory, + const std::shared_ptr& protocolFactory); + + TServerFramework( + const std::shared_ptr& processorFactory, + const std::shared_ptr& serverTransport, + const std::shared_ptr& inputTransportFactory, + const std::shared_ptr& outputTransportFactory, + const std::shared_ptr& inputProtocolFactory, + const std::shared_ptr& outputProtocolFactory); + + TServerFramework( + const std::shared_ptr& processor, + const std::shared_ptr& serverTransport, + const std::shared_ptr& inputTransportFactory, + const std::shared_ptr& outputTransportFactory, + const std::shared_ptr& inputProtocolFactory, + const std::shared_ptr& outputProtocolFactory); + + ~TServerFramework() override; + + /** + * Accept clients from the TServerTransport and add them for processing. + * Call stop() on another thread to interrupt processing + * and return control to the caller. + * Post-conditions (return guarantees): + * The serverTransport will be closed. + */ + void serve() override; + + /** + * Interrupt serve() so that it meets post-conditions and returns. + */ + void stop() override; + + /** + * Get the concurrent client limit. + * \returns the concurrent client limit + */ + virtual int64_t getConcurrentClientLimit() const; + + /** + * Get the number of currently connected clients. + * \returns the number of currently connected clients + */ + virtual int64_t getConcurrentClientCount() const; + + /** + * Get the highest number of concurrent clients. + * \returns the highest number of concurrent clients + */ + virtual int64_t getConcurrentClientCountHWM() const; + + /** + * Set the concurrent client limit. This can be changed while + * the server is serving however it will not necessarily be + * enforced until the next client is accepted and added. If the + * limit is lowered below the number of connected clients, no + * action is taken to disconnect the clients. + * The default value used if this is not called is INT64_MAX. + * \param[in] newLimit the new limit of concurrent clients + * \throws std::invalid_argument if newLimit is less than 1 + */ + virtual void setConcurrentClientLimit(int64_t newLimit); + +protected: + /** + * A client has connected. The implementation is responsible for managing the + * lifetime of the client object. This is called during the serve() thread, + * therefore a failure to return quickly will result in new client connection + * delays. + * + * \param[in] pClient the newly connected client + */ + virtual void onClientConnected(const std::shared_ptr& pClient) = 0; + + /** + * A client has disconnected. + * When called: + * The server no longer tracks the client. + * The client TTransport has already been closed. + * The implementation must not delete the pointer. + * + * \param[in] pClient the disconnected client + */ + virtual void onClientDisconnected(TConnectedClient* pClient) = 0; + +private: + /** + * Common handling for new connected clients. Implements concurrent + * client rate limiting after onClientConnected returns by blocking the + * serve() thread if the limit has been reached. + */ + void newlyConnectedClient(const std::shared_ptr& pClient); + + /** + * Smart pointer client deletion. + * Calls onClientDisconnected and then deletes pClient. + */ + void disposeConnectedClient(TConnectedClient* pClient); + + /** + * Monitor for limiting the number of concurrent clients. + */ + apache::thrift::concurrency::Monitor mon_; + + /** + * The number of concurrent clients. + */ + int64_t clients_; + + /** + * The high water mark of concurrent clients. + */ + int64_t hwm_; + + /** + * The limit on the number of concurrent clients. + */ + int64_t limit_; +}; +} +} +} // apache::thrift::server + +#endif // #ifndef _THRIFT_SERVER_TSERVERFRAMEWORK_H_ diff --git a/bsnes/thrift/thrift/server/TSimpleServer.h b/bsnes/thrift/thrift/server/TSimpleServer.h new file mode 100644 index 00000000..3afeb79d --- /dev/null +++ b/bsnes/thrift/thrift/server/TSimpleServer.h @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_SERVER_TSIMPLESERVER_H_ +#define _THRIFT_SERVER_TSIMPLESERVER_H_ 1 + +#include + +namespace apache { +namespace thrift { +namespace server { + +/** + * This is the most basic simple server. It is single-threaded and runs a + * continuous loop of accepting a single connection, processing requests on + * that connection until it closes, and then repeating. + */ +class TSimpleServer : public TServerFramework { +public: + TSimpleServer( + const std::shared_ptr& processorFactory, + const std::shared_ptr& serverTransport, + const std::shared_ptr& transportFactory, + const std::shared_ptr& protocolFactory); + + TSimpleServer( + const std::shared_ptr& processor, + const std::shared_ptr& serverTransport, + const std::shared_ptr& transportFactory, + const std::shared_ptr& protocolFactory); + + TSimpleServer( + const std::shared_ptr& processorFactory, + const std::shared_ptr& serverTransport, + const std::shared_ptr& inputTransportFactory, + const std::shared_ptr& outputTransportFactory, + const std::shared_ptr& inputProtocolFactory, + const std::shared_ptr& outputProtocolFactory); + + TSimpleServer( + const std::shared_ptr& processor, + const std::shared_ptr& serverTransport, + const std::shared_ptr& inputTransportFactory, + const std::shared_ptr& outputTransportFactory, + const std::shared_ptr& inputProtocolFactory, + const std::shared_ptr& outputProtocolFactory); + + ~TSimpleServer() override; + +protected: + void onClientConnected(const std::shared_ptr& pClient) override /* override */; + void onClientDisconnected(TConnectedClient* pClient) override /* override */; + +private: + void setConcurrentClientLimit(int64_t newLimit) override; // hide +}; +} +} +} // apache::thrift::server + +#endif // #ifndef _THRIFT_SERVER_TSIMPLESERVER_H_ diff --git a/bsnes/thrift/thrift/server/TThreadPoolServer.h b/bsnes/thrift/thrift/server/TThreadPoolServer.h new file mode 100644 index 00000000..a9411b86 --- /dev/null +++ b/bsnes/thrift/thrift/server/TThreadPoolServer.h @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_SERVER_TTHREADPOOLSERVER_H_ +#define _THRIFT_SERVER_TTHREADPOOLSERVER_H_ 1 + +#include +#include +#include + +namespace apache { +namespace thrift { +namespace server { + +/** + * Manage clients using a thread pool. + */ +class TThreadPoolServer : public TServerFramework { +public: + TThreadPoolServer( + const std::shared_ptr& processorFactory, + const std::shared_ptr& serverTransport, + const std::shared_ptr& transportFactory, + const std::shared_ptr& protocolFactory, + const std::shared_ptr& threadManager + = apache::thrift::concurrency::ThreadManager::newSimpleThreadManager()); + + TThreadPoolServer( + const std::shared_ptr& processor, + const std::shared_ptr& serverTransport, + const std::shared_ptr& transportFactory, + const std::shared_ptr& protocolFactory, + const std::shared_ptr& threadManager + = apache::thrift::concurrency::ThreadManager::newSimpleThreadManager()); + + TThreadPoolServer( + const std::shared_ptr& processorFactory, + const std::shared_ptr& serverTransport, + const std::shared_ptr& inputTransportFactory, + const std::shared_ptr& outputTransportFactory, + const std::shared_ptr& inputProtocolFactory, + const std::shared_ptr& outputProtocolFactory, + const std::shared_ptr& threadManager + = apache::thrift::concurrency::ThreadManager::newSimpleThreadManager()); + + TThreadPoolServer( + const std::shared_ptr& processor, + const std::shared_ptr& serverTransport, + const std::shared_ptr& inputTransportFactory, + const std::shared_ptr& outputTransportFactory, + const std::shared_ptr& inputProtocolFactory, + const std::shared_ptr& outputProtocolFactory, + const std::shared_ptr& threadManager + = apache::thrift::concurrency::ThreadManager::newSimpleThreadManager()); + + ~TThreadPoolServer() override; + + /** + * Post-conditions (return guarantees): + * There will be no clients connected. + */ + void serve() override; + + virtual int64_t getTimeout() const; + virtual void setTimeout(int64_t value); + + virtual int64_t getTaskExpiration() const; + virtual void setTaskExpiration(int64_t value); + + virtual std::shared_ptr getThreadManager() const; + +protected: + void onClientConnected(const std::shared_ptr& pClient) override /* override */; + void onClientDisconnected(TConnectedClient* pClient) override /* override */; + + std::shared_ptr threadManager_; + std::atomic timeout_; + std::atomic taskExpiration_; +}; + +} +} +} // apache::thrift::server + +#endif // #ifndef _THRIFT_SERVER_TTHREADPOOLSERVER_H_ diff --git a/bsnes/thrift/thrift/server/TThreadedServer.h b/bsnes/thrift/thrift/server/TThreadedServer.h new file mode 100644 index 00000000..756e5a06 --- /dev/null +++ b/bsnes/thrift/thrift/server/TThreadedServer.h @@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_SERVER_TTHREADEDSERVER_H_ +#define _THRIFT_SERVER_TTHREADEDSERVER_H_ 1 + +#include +#include +#include +#include +#include + +namespace apache { +namespace thrift { +namespace server { + +/** + * Manage clients using threads - threads are created one for each client and are + * released when the client disconnects. This server is used to make a dynamically + * scalable server up to the concurrent connection limit. + */ +class TThreadedServer : public TServerFramework { +public: + TThreadedServer( + const std::shared_ptr& processorFactory, + const std::shared_ptr& serverTransport, + const std::shared_ptr& transportFactory, + const std::shared_ptr& protocolFactory, + const std::shared_ptr& threadFactory + = std::shared_ptr( + new apache::thrift::concurrency::ThreadFactory(false))); + + TThreadedServer( + const std::shared_ptr& processor, + const std::shared_ptr& serverTransport, + const std::shared_ptr& transportFactory, + const std::shared_ptr& protocolFactory, + const std::shared_ptr& threadFactory + = std::shared_ptr( + new apache::thrift::concurrency::ThreadFactory(false))); + + TThreadedServer( + const std::shared_ptr& processorFactory, + const std::shared_ptr& serverTransport, + const std::shared_ptr& inputTransportFactory, + const std::shared_ptr& outputTransportFactory, + const std::shared_ptr& inputProtocolFactory, + const std::shared_ptr& outputProtocolFactory, + const std::shared_ptr& threadFactory + = std::shared_ptr( + new apache::thrift::concurrency::ThreadFactory(false))); + + TThreadedServer( + const std::shared_ptr& processor, + const std::shared_ptr& serverTransport, + const std::shared_ptr& inputTransportFactory, + const std::shared_ptr& outputTransportFactory, + const std::shared_ptr& inputProtocolFactory, + const std::shared_ptr& outputProtocolFactory, + const std::shared_ptr& threadFactory + = std::shared_ptr( + new apache::thrift::concurrency::ThreadFactory(false))); + + ~TThreadedServer() override; + + /** + * Post-conditions (return guarantees): + * There will be no clients connected. + */ + void serve() override; + +protected: + /** + * Drain recently connected clients by joining their threads - this is done lazily because + * we cannot do it inside the thread context that is disconnecting. + */ + virtual void drainDeadClients(); + + /** + * Implementation of TServerFramework::onClientConnected + */ + void onClientConnected(const std::shared_ptr& pClient) override /* override */; + + /** + * Implementation of TServerFramework::onClientDisconnected + */ + void onClientDisconnected(TConnectedClient *pClient) override /* override */; + + std::shared_ptr threadFactory_; + + /** + * A helper wrapper used to wrap the client in something we can use to maintain + * the lifetime of the connected client within a detached thread. We cannot simply + * track the threads because a shared_ptr hangs on to the Runnable it is + * passed, and TServerFramework requires the runnable (TConnectedClient) to be + * destroyed in order to work properly. + */ + class TConnectedClientRunner : public apache::thrift::concurrency::Runnable + { + public: + TConnectedClientRunner(const std::shared_ptr& pClient); + ~TConnectedClientRunner() override; + void run() override /* override */; + private: + std::shared_ptr pClient_; + }; + + apache::thrift::concurrency::Monitor clientMonitor_; + + typedef std::map > ClientMap; + + /** + * A map of active clients + */ + ClientMap activeClientMap_; + + /** + * A map of clients that have disconnected but their threads have not been joined + */ + ClientMap deadClientMap_; +}; + +} +} +} // apache::thrift::server + +#endif // #ifndef _THRIFT_SERVER_TTHREADEDSERVER_H_ diff --git a/bsnes/thrift/thrift/thrift-config.h b/bsnes/thrift/thrift/thrift-config.h new file mode 100644 index 00000000..d648706c --- /dev/null +++ b/bsnes/thrift/thrift/thrift-config.h @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifdef _WIN32 +#include +#else +#include +#endif diff --git a/bsnes/thrift/thrift/thrift_export.h b/bsnes/thrift/thrift/thrift_export.h new file mode 100644 index 00000000..f5c059fb --- /dev/null +++ b/bsnes/thrift/thrift/thrift_export.h @@ -0,0 +1,20 @@ +#ifndef THRIFT_EXPORT_H +#define THRIFT_EXPORT_H + +#ifdef THRIFT_STATIC_DEFINE +# define THRIFT_EXPORT +#elif defined(_MSC_VER ) +# ifndef THRIFT_EXPORT +# ifdef thrift_EXPORTS + /* We are building this library */ +# define THRIFT_EXPORT __declspec(dllexport) +# else + /* We are using this library */ +# define THRIFT_EXPORT __declspec(dllimport) +# endif +# endif +#else +# define THRIFT_EXPORT +#endif + +#endif /* THRIFT_EXPORT_H */ diff --git a/bsnes/thrift/thrift/transport/PlatformSocket.h b/bsnes/thrift/thrift/transport/PlatformSocket.h new file mode 100644 index 00000000..10df9446 --- /dev/null +++ b/bsnes/thrift/thrift/transport/PlatformSocket.h @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// clang-format off + +#ifndef _THRIFT_TRANSPORT_PLATFORM_SOCKET_H_ +# define _THRIFT_TRANSPORT_PLATFORM_SOCKET_H_ + +#ifdef _WIN32 +# include +# define THRIFT_GET_SOCKET_ERROR ::WSAGetLastError() +# define THRIFT_ERRNO (*_errno()) +# define THRIFT_EINPROGRESS WSAEINPROGRESS +# define THRIFT_EAGAIN WSAEWOULDBLOCK +# define THRIFT_EINTR WSAEINTR +# define THRIFT_ECONNRESET WSAECONNRESET +# define THRIFT_ENOTCONN WSAENOTCONN +# define THRIFT_ETIMEDOUT WSAETIMEDOUT +# define THRIFT_EWOULDBLOCK WSAEWOULDBLOCK +# define THRIFT_EPIPE WSAECONNRESET +# define THRIFT_NO_SOCKET_CACHING SO_EXCLUSIVEADDRUSE +# define THRIFT_SOCKET SOCKET +# define THRIFT_INVALID_SOCKET INVALID_SOCKET +# define THRIFT_SOCKETPAIR thrift_socketpair +# define THRIFT_FCNTL thrift_fcntl +# define THRIFT_O_NONBLOCK 1 +# define THRIFT_F_GETFL 0 +# define THRIFT_F_SETFL 1 +# define THRIFT_GETTIMEOFDAY thrift_gettimeofday +# define THRIFT_CLOSESOCKET closesocket +# define THRIFT_CLOSE _close +# define THRIFT_OPEN _open +# define THRIFT_FTRUNCATE _chsize_s +# define THRIFT_FSYNC _commit +# define THRIFT_LSEEK _lseek +# define THRIFT_WRITE _write +# define THRIFT_READ _read +# define THRIFT_IOCTL_SOCKET ioctlsocket +# define THRIFT_IOCTL_SOCKET_NUM_BYTES_TYPE u_long +# define THRIFT_FSTAT _fstat +# define THRIFT_STAT _stat +# ifdef _WIN32_WCE +# define THRIFT_GAI_STRERROR(...) thrift_wstr2str(gai_strerrorW(__VA_ARGS__)) +# else +# define THRIFT_GAI_STRERROR gai_strerrorA +# endif +# define THRIFT_SSIZET ptrdiff_t +# if (_MSC_VER < 1900) +# define THRIFT_SNPRINTF _snprintf +# else +# define THRIFT_SNPRINTF snprintf +# endif +# define THRIFT_SLEEP_SEC thrift_sleep +# define THRIFT_SLEEP_USEC thrift_usleep +# define THRIFT_TIMESPEC thrift_timespec +# define THRIFT_CTIME_R thrift_ctime_r +# define THRIFT_POLL WSAPoll +# define THRIFT_POLLFD pollfd +# define THRIFT_POLLIN POLLIN +# define THRIFT_POLLOUT POLLOUT +# define THRIFT_SHUT_RDWR SD_BOTH +# if !defined(AI_ADDRCONFIG) +# define AI_ADDRCONFIG 0x00000400 +# endif +#else //not _WIN32 +# include +# define THRIFT_GET_SOCKET_ERROR errno +# define THRIFT_ERRNO errno +# define THRIFT_EINTR EINTR +# define THRIFT_EINPROGRESS EINPROGRESS +# define THRIFT_ECONNRESET ECONNRESET +# define THRIFT_ENOTCONN ENOTCONN +# define THRIFT_ETIMEDOUT ETIMEDOUT +# define THRIFT_EWOULDBLOCK EWOULDBLOCK +# define THRIFT_EAGAIN EAGAIN +# define THRIFT_EPIPE EPIPE +# define THRIFT_NO_SOCKET_CACHING SO_REUSEADDR +# define THRIFT_SOCKET int +# define THRIFT_INVALID_SOCKET (-1) +# define THRIFT_SOCKETPAIR socketpair +# define THRIFT_FCNTL fcntl +# define THRIFT_O_NONBLOCK O_NONBLOCK +# define THRIFT_F_GETFL F_GETFL +# define THRIFT_F_SETFL F_SETFL +# define THRIFT_GETTIMEOFDAY gettimeofday +# define THRIFT_CLOSESOCKET close +# define THRIFT_CLOSE close +# define THRIFT_OPEN open +# define THRIFT_FTRUNCATE ftruncate +# define THRIFT_FSYNC fsync +# define THRIFT_LSEEK lseek +# define THRIFT_WRITE write +# define THRIFT_READ read +# define THRIFT_IOCTL_SOCKET ioctl +# define THRIFT_IOCTL_SOCKET_NUM_BYTES_TYPE int +# define THRIFT_STAT stat +# define THRIFT_FSTAT fstat +# define THRIFT_GAI_STRERROR gai_strerror +# define THRIFT_SSIZET ssize_t +# define THRIFT_SNPRINTF snprintf +# define THRIFT_SLEEP_SEC sleep +# define THRIFT_SLEEP_USEC usleep +# define THRIFT_TIMESPEC timespec +# define THRIFT_CTIME_R ctime_r +# define THRIFT_POLL poll +# define THRIFT_POLLFD pollfd +# define THRIFT_POLLIN POLLIN +# define THRIFT_POLLOUT POLLOUT +# define THRIFT_SHUT_RDWR SHUT_RDWR +#endif + +#endif // _THRIFT_TRANSPORT_PLATFORM_SOCKET_H_ diff --git a/bsnes/thrift/thrift/transport/SocketCommon.h b/bsnes/thrift/thrift/transport/SocketCommon.h new file mode 100644 index 00000000..78839c4e --- /dev/null +++ b/bsnes/thrift/thrift/transport/SocketCommon.h @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * @author: David Suárez + */ + +#ifndef THRIFT_SOCKETCOMMON_H +#define THRIFT_SOCKETCOMMON_H + +#ifndef _WIN32 + +#include + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_SYS_UN_H +#include +#endif + +#include + +namespace apache { +namespace thrift { +namespace transport { + +socklen_t fillUnixSocketAddr(struct sockaddr_un& address, std::string& path); + +} +} +} // apache::thrift::transport + +#endif // _WIN32 + +#endif //THRIFT_SOCKETCOMMON_H diff --git a/bsnes/thrift/thrift/transport/TBufferTransports.h b/bsnes/thrift/thrift/transport/TBufferTransports.h new file mode 100644 index 00000000..179934ba --- /dev/null +++ b/bsnes/thrift/thrift/transport/TBufferTransports.h @@ -0,0 +1,765 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_TBUFFERTRANSPORTS_H_ +#define _THRIFT_TRANSPORT_TBUFFERTRANSPORTS_H_ 1 + +#include +#include +#include +#include + +#include +#include + +#ifdef __GNUC__ +#define TDB_LIKELY(val) (__builtin_expect((val), 1)) +#define TDB_UNLIKELY(val) (__builtin_expect((val), 0)) +#else +#define TDB_LIKELY(val) (val) +#define TDB_UNLIKELY(val) (val) +#endif + +namespace apache { +namespace thrift { +namespace transport { + +/** + * Base class for all transports that use read/write buffers for performance. + * + * TBufferBase is designed to implement the fast-path "memcpy" style + * operations that work in the common case. It does so with small and + * (eventually) nonvirtual, inlinable methods. TBufferBase is an abstract + * class. Subclasses are expected to define the "slow path" operations + * that have to be done when the buffers are full or empty. + * + */ +class TBufferBase : public TVirtualTransport { + +public: + /** + * Fast-path read. + * + * When we have enough data buffered to fulfill the read, we can satisfy it + * with a single memcpy, then adjust our internal pointers. If the buffer + * is empty, we call out to our slow path, implemented by a subclass. + * This method is meant to eventually be nonvirtual and inlinable. + */ + uint32_t read(uint8_t* buf, uint32_t len) { + checkReadBytesAvailable(len); + uint8_t* new_rBase = rBase_ + len; + if (TDB_LIKELY(new_rBase <= rBound_)) { + std::memcpy(buf, rBase_, len); + rBase_ = new_rBase; + return len; + } + return readSlow(buf, len); + } + + /** + * Shortcutted version of readAll. + */ + uint32_t readAll(uint8_t* buf, uint32_t len) { + uint8_t* new_rBase = rBase_ + len; + if (TDB_LIKELY(new_rBase <= rBound_)) { + std::memcpy(buf, rBase_, len); + rBase_ = new_rBase; + return len; + } + return apache::thrift::transport::readAll(*this, buf, len); + } + + /** + * Fast-path write. + * + * When we have enough empty space in our buffer to accommodate the write, we + * can satisfy it with a single memcpy, then adjust our internal pointers. + * If the buffer is full, we call out to our slow path, implemented by a + * subclass. This method is meant to eventually be nonvirtual and + * inlinable. + */ + void write(const uint8_t* buf, uint32_t len) { + uint8_t* new_wBase = wBase_ + len; + if (TDB_LIKELY(new_wBase <= wBound_)) { + std::memcpy(wBase_, buf, len); + wBase_ = new_wBase; + return; + } + writeSlow(buf, len); + } + + /** + * Fast-path borrow. A lot like the fast-path read. + */ + const uint8_t* borrow(uint8_t* buf, uint32_t* len) { + if (TDB_LIKELY(static_cast(*len) <= rBound_ - rBase_)) { + // With strict aliasing, writing to len shouldn't force us to + // refetch rBase_ from memory. TODO(dreiss): Verify this. + *len = static_cast(rBound_ - rBase_); + return rBase_; + } + return borrowSlow(buf, len); + } + + /** + * Consume doesn't require a slow path. + */ + void consume(uint32_t len) { + countConsumedMessageBytes(len); + if (TDB_LIKELY(static_cast(len) <= rBound_ - rBase_)) { + rBase_ += len; + } else { + throw TTransportException(TTransportException::BAD_ARGS, "consume did not follow a borrow."); + } + } + +protected: + /// Slow path read. + virtual uint32_t readSlow(uint8_t* buf, uint32_t len) = 0; + + /// Slow path write. + virtual void writeSlow(const uint8_t* buf, uint32_t len) = 0; + + /** + * Slow path borrow. + * + * POSTCONDITION: return == nullptr || rBound_ - rBase_ >= *len + */ + virtual const uint8_t* borrowSlow(uint8_t* buf, uint32_t* len) = 0; + + /** + * Trivial constructor. + * + * Initialize pointers safely. Constructing is not a very + * performance-sensitive operation, so it is okay to just leave it to + * the concrete class to set up pointers correctly. + */ + TBufferBase(std::shared_ptr config = nullptr) + : TVirtualTransport(config), rBase_(nullptr), rBound_(nullptr), wBase_(nullptr), wBound_(nullptr) {} + + /// Convenience mutator for setting the read buffer. + void setReadBuffer(uint8_t* buf, uint32_t len) { + rBase_ = buf; + rBound_ = buf + len; + } + + /// Convenience mutator for setting the write buffer. + void setWriteBuffer(uint8_t* buf, uint32_t len) { + wBase_ = buf; + wBound_ = buf + len; + } + + ~TBufferBase() override = default; + + /// Reads begin here. + uint8_t* rBase_; + /// Reads may extend to just before here. + uint8_t* rBound_; + + /// Writes begin here. + uint8_t* wBase_; + /// Writes may extend to just before here. + uint8_t* wBound_; +}; + +/** + * Buffered transport. For reads it will read more data than is requested + * and will serve future data out of a local buffer. For writes, data is + * stored to an in memory buffer before being written out. + * + */ +class TBufferedTransport : public TVirtualTransport { +public: + static const int DEFAULT_BUFFER_SIZE = 512; + + /// Use default buffer sizes. + TBufferedTransport(std::shared_ptr transport, std::shared_ptr config = nullptr) + : TVirtualTransport(config), + transport_(transport), + rBufSize_(DEFAULT_BUFFER_SIZE), + wBufSize_(DEFAULT_BUFFER_SIZE), + rBuf_(new uint8_t[rBufSize_]), + wBuf_(new uint8_t[wBufSize_]) { + initPointers(); + } + + /// Use specified buffer sizes. + TBufferedTransport(std::shared_ptr transport, uint32_t sz, std::shared_ptr config = nullptr) + : TVirtualTransport(config), + transport_(transport), + rBufSize_(sz), + wBufSize_(sz), + rBuf_(new uint8_t[rBufSize_]), + wBuf_(new uint8_t[wBufSize_]) { + initPointers(); + } + + /// Use specified read and write buffer sizes. + TBufferedTransport(std::shared_ptr transport, uint32_t rsz, uint32_t wsz, + std::shared_ptr config = nullptr) + : TVirtualTransport(config), + transport_(transport), + rBufSize_(rsz), + wBufSize_(wsz), + rBuf_(new uint8_t[rBufSize_]), + wBuf_(new uint8_t[wBufSize_]) { + initPointers(); + } + + void open() override { transport_->open(); } + + bool isOpen() const override { return transport_->isOpen(); } + + bool peek() override { + if (rBase_ == rBound_) { + setReadBuffer(rBuf_.get(), transport_->read(rBuf_.get(), rBufSize_)); + } + return (rBound_ > rBase_); + } + + void close() override { + flush(); + transport_->close(); + } + + uint32_t readSlow(uint8_t* buf, uint32_t len) override; + + void writeSlow(const uint8_t* buf, uint32_t len) override; + + void flush() override; + + /** + * Returns the origin of the underlying transport + */ + const std::string getOrigin() const override { return transport_->getOrigin(); } + + /** + * The following behavior is currently implemented by TBufferedTransport, + * but that may change in a future version: + * 1/ If len is at most rBufSize_, borrow will never return nullptr. + * Depending on the underlying transport, it could throw an exception + * or hang forever. + * 2/ Some borrow requests may copy bytes internally. However, + * if len is at most rBufSize_/2, none of the copied bytes + * will ever have to be copied again. For optimial performance, + * stay under this limit. + */ + const uint8_t* borrowSlow(uint8_t* buf, uint32_t* len) override; + + std::shared_ptr getUnderlyingTransport() { return transport_; } + + /* + * TVirtualTransport provides a default implementation of readAll(). + * We want to use the TBufferBase version instead. + */ + uint32_t readAll(uint8_t* buf, uint32_t len) { return TBufferBase::readAll(buf, len); } + +protected: + void initPointers() { + setReadBuffer(rBuf_.get(), 0); + setWriteBuffer(wBuf_.get(), wBufSize_); + // Write size never changes. + } + + std::shared_ptr transport_; + + uint32_t rBufSize_; + uint32_t wBufSize_; + boost::scoped_array rBuf_; + boost::scoped_array wBuf_; +}; + +/** + * Wraps a transport into a buffered one. + * + */ +class TBufferedTransportFactory : public TTransportFactory { +public: + TBufferedTransportFactory() = default; + + ~TBufferedTransportFactory() override = default; + + /** + * Wraps the transport into a buffered one. + */ + std::shared_ptr getTransport(std::shared_ptr trans) override { + return std::shared_ptr(new TBufferedTransport(trans)); + } +}; + +/** + * Framed transport. All writes go into an in-memory buffer until flush is + * called, at which point the transport writes the length of the entire + * binary chunk followed by the data payload. This allows the receiver on the + * other end to always do fixed-length reads. + * + */ +class TFramedTransport : public TVirtualTransport { +public: + static const int DEFAULT_BUFFER_SIZE = 512; + static const int DEFAULT_MAX_FRAME_SIZE = 256 * 1024 * 1024; + + /// Use default buffer sizes. + TFramedTransport(std::shared_ptr config = nullptr) + : TVirtualTransport(config), + transport_(), + rBufSize_(0), + wBufSize_(DEFAULT_BUFFER_SIZE), + rBuf_(), + wBuf_(new uint8_t[wBufSize_]), + bufReclaimThresh_((std::numeric_limits::max)()) { + initPointers(); + } + + TFramedTransport(std::shared_ptr transport, std::shared_ptr config = nullptr) + : TVirtualTransport(config), + transport_(transport), + rBufSize_(0), + wBufSize_(DEFAULT_BUFFER_SIZE), + rBuf_(), + wBuf_(new uint8_t[wBufSize_]), + bufReclaimThresh_((std::numeric_limits::max)()), + maxFrameSize_(configuration_->getMaxFrameSize()) { + initPointers(); + } + + TFramedTransport(std::shared_ptr transport, + uint32_t sz, + uint32_t bufReclaimThresh = (std::numeric_limits::max)(), + std::shared_ptr config = nullptr) + : TVirtualTransport(config), + transport_(transport), + rBufSize_(0), + wBufSize_(sz), + rBuf_(), + wBuf_(new uint8_t[wBufSize_]), + bufReclaimThresh_(bufReclaimThresh), + maxFrameSize_(configuration_->getMaxFrameSize()) { + initPointers(); + } + + void open() override { transport_->open(); } + + bool isOpen() const override { return transport_->isOpen(); } + + bool peek() override { return (rBase_ < rBound_) || transport_->peek(); } + + void close() override { + flush(); + transport_->close(); + } + + uint32_t readSlow(uint8_t* buf, uint32_t len) override; + + void writeSlow(const uint8_t* buf, uint32_t len) override; + + void flush() override; + + uint32_t readEnd() override; + + uint32_t writeEnd() override; + + const uint8_t* borrowSlow(uint8_t* buf, uint32_t* len) override; + + std::shared_ptr getUnderlyingTransport() { return transport_; } + + /* + * TVirtualTransport provides a default implementation of readAll(). + * We want to use the TBufferBase version instead. + */ + using TBufferBase::readAll; + + /** + * Returns the origin of the underlying transport + */ + const std::string getOrigin() const override { return transport_->getOrigin(); } + + /** + * Set the maximum size of the frame at read + */ + void setMaxFrameSize(uint32_t maxFrameSize) { maxFrameSize_ = maxFrameSize; } + + /** + * Get the maximum size of the frame at read + */ + uint32_t getMaxFrameSize() { return maxFrameSize_; } + +protected: + /** + * Reads a frame of input from the underlying stream. + * + * Returns true if a frame was read successfully, or false on EOF. + * (Raises a TTransportException if EOF occurs after a partial frame.) + */ + virtual bool readFrame(); + + void initPointers() { + setReadBuffer(nullptr, 0); + setWriteBuffer(wBuf_.get(), wBufSize_); + + // Pad the buffer so we can insert the size later. + int32_t pad = 0; + this->write((uint8_t*)&pad, sizeof(pad)); + } + + std::shared_ptr transport_; + + uint32_t rBufSize_; + uint32_t wBufSize_; + boost::scoped_array rBuf_; + boost::scoped_array wBuf_; + uint32_t bufReclaimThresh_; + uint32_t maxFrameSize_; +}; + +/** + * Wraps a transport into a framed one. + * + */ +class TFramedTransportFactory : public TTransportFactory { +public: + TFramedTransportFactory() = default; + + ~TFramedTransportFactory() override = default; + + /** + * Wraps the transport into a framed one. + */ + std::shared_ptr getTransport(std::shared_ptr trans) override { + return std::shared_ptr(new TFramedTransport(trans)); + } +}; + +/** + * A memory buffer is a tranpsort that simply reads from and writes to an + * in memory buffer. Anytime you call write on it, the data is simply placed + * into a buffer, and anytime you call read, data is read from that buffer. + * + * The buffers are allocated using C constructs malloc,realloc, and the size + * doubles as necessary. We've considered using scoped + * + */ +class TMemoryBuffer : public TVirtualTransport { +private: + // Common initialization done by all constructors. + void initCommon(uint8_t* buf, uint32_t size, bool owner, uint32_t wPos) { + + maxBufferSize_ = (std::numeric_limits::max)(); + + if (buf == nullptr && size != 0) { + assert(owner); + buf = (uint8_t*)std::malloc(size); + if (buf == nullptr) { + throw std::bad_alloc(); + } + } + + buffer_ = buf; + bufferSize_ = size; + + rBase_ = buffer_; + rBound_ = buffer_ + wPos; + // TODO(dreiss): Investigate NULL-ing this if !owner. + wBase_ = buffer_ + wPos; + wBound_ = buffer_ + bufferSize_; + + owner_ = owner; + + // rBound_ is really an artifact. In principle, it should always be + // equal to wBase_. We update it in a few places (computeRead, etc.). + } + +public: + static const uint32_t defaultSize = 1024; + + /** + * This enum specifies how a TMemoryBuffer should treat + * memory passed to it via constructors or resetBuffer. + * + * OBSERVE: + * TMemoryBuffer will simply store a pointer to the memory. + * It is the callers responsibility to ensure that the pointer + * remains valid for the lifetime of the TMemoryBuffer, + * and that it is properly cleaned up. + * Note that no data can be written to observed buffers. + * + * COPY: + * TMemoryBuffer will make an internal copy of the buffer. + * The caller has no responsibilities. + * + * TAKE_OWNERSHIP: + * TMemoryBuffer will become the "owner" of the buffer, + * and will be responsible for freeing it. + * The membory must have been allocated with malloc. + */ + enum MemoryPolicy { OBSERVE = 1, COPY = 2, TAKE_OWNERSHIP = 3 }; + + /** + * Construct a TMemoryBuffer with a default-sized buffer, + * owned by the TMemoryBuffer object. + */ + TMemoryBuffer(std::shared_ptr config = nullptr) + : TVirtualTransport(config) { + initCommon(nullptr, defaultSize, true, 0); + } + + /** + * Construct a TMemoryBuffer with a buffer of a specified size, + * owned by the TMemoryBuffer object. + * + * @param sz The initial size of the buffer. + */ + TMemoryBuffer(uint32_t sz, std::shared_ptr config = nullptr) + : TVirtualTransport(config) { + initCommon(nullptr, sz, true, 0); + } + + /** + * Construct a TMemoryBuffer with buf as its initial contents. + * + * @param buf The initial contents of the buffer. + * Note that, while buf is a non-const pointer, + * TMemoryBuffer will not write to it if policy == OBSERVE, + * so it is safe to const_cast(whatever). + * @param sz The size of @c buf. + * @param policy See @link MemoryPolicy @endlink . + */ + TMemoryBuffer(uint8_t* buf, uint32_t sz, MemoryPolicy policy = OBSERVE, std::shared_ptr config = nullptr) + : TVirtualTransport(config) { + if (buf == nullptr && sz != 0) { + throw TTransportException(TTransportException::BAD_ARGS, + "TMemoryBuffer given null buffer with non-zero size."); + } + + switch (policy) { + case OBSERVE: + case TAKE_OWNERSHIP: + initCommon(buf, sz, policy == TAKE_OWNERSHIP, sz); + break; + case COPY: + initCommon(nullptr, sz, true, 0); + this->write(buf, sz); + break; + default: + throw TTransportException(TTransportException::BAD_ARGS, + "Invalid MemoryPolicy for TMemoryBuffer"); + } + } + + ~TMemoryBuffer() override { + if (owner_) { + std::free(buffer_); + } + } + + bool isOpen() const override { return true; } + + bool peek() override { return (rBase_ < wBase_); } + + void open() override {} + + void close() override {} + + // TODO(dreiss): Make bufPtr const. + void getBuffer(uint8_t** bufPtr, uint32_t* sz) { + *bufPtr = rBase_; + *sz = static_cast(wBase_ - rBase_); + } + + std::string getBufferAsString() { + if (buffer_ == nullptr) { + return ""; + } + uint8_t* buf; + uint32_t sz; + getBuffer(&buf, &sz); + return std::string((char*)buf, (std::string::size_type)sz); + } + + void appendBufferToString(std::string& str) { + if (buffer_ == nullptr) { + return; + } + uint8_t* buf; + uint32_t sz; + getBuffer(&buf, &sz); + str.append((char*)buf, sz); + } + + void resetBuffer() { + rBase_ = buffer_; + rBound_ = buffer_; + wBase_ = buffer_; + // It isn't safe to write into a buffer we don't own. + if (!owner_) { + wBound_ = wBase_; + bufferSize_ = 0; + } + } + + /// See constructor documentation. + void resetBuffer(uint8_t* buf, uint32_t sz, MemoryPolicy policy = OBSERVE) { + // Use a variant of the copy-and-swap trick for assignment operators. + // This is sub-optimal in terms of performance for two reasons: + // 1/ The constructing and swapping of the (small) values + // in the temporary object takes some time, and is not necessary. + // 2/ If policy == COPY, we allocate the new buffer before + // freeing the old one, precluding the possibility of + // reusing that memory. + // I doubt that either of these problems could be optimized away, + // but the second is probably no a common case, and the first is minor. + // I don't expect resetBuffer to be a common operation, so I'm willing to + // bite the performance bullet to make the method this simple. + + // Construct the new buffer. + TMemoryBuffer new_buffer(buf, sz, policy); + // Move it into ourself. + this->swap(new_buffer); + // Our old self gets destroyed. + } + + /// See constructor documentation. + void resetBuffer(uint32_t sz) { + // Construct the new buffer. + TMemoryBuffer new_buffer(sz); + // Move it into ourself. + this->swap(new_buffer); + // Our old self gets destroyed. + } + + std::string readAsString(uint32_t len) { + std::string str; + (void)readAppendToString(str, len); + return str; + } + + uint32_t readAppendToString(std::string& str, uint32_t len); + + // return number of bytes read + uint32_t readEnd() override { + // This cast should be safe, because buffer_'s size is a uint32_t + auto bytes = static_cast(rBase_ - buffer_); + if (rBase_ == wBase_) { + resetBuffer(); + } + return bytes; + } + + // Return number of bytes written + uint32_t writeEnd() override { + // This cast should be safe, because buffer_'s size is a uint32_t + return static_cast(wBase_ - buffer_); + } + + uint32_t available_read() const { + // Remember, wBase_ is the real rBound_. + return static_cast(wBase_ - rBase_); + } + + uint32_t available_write() const { return static_cast(wBound_ - wBase_); } + + // Returns a pointer to where the client can write data to append to + // the TMemoryBuffer, and ensures the buffer is big enough to accommodate a + // write of the provided length. The returned pointer is very convenient for + // passing to read(), recv(), or similar. You must call wroteBytes() as soon + // as data is written or the buffer will not be aware that data has changed. + uint8_t* getWritePtr(uint32_t len) { + ensureCanWrite(len); + return wBase_; + } + + // Informs the buffer that the client has written 'len' bytes into storage + // that had been provided by getWritePtr(). + void wroteBytes(uint32_t len); + + /* + * TVirtualTransport provides a default implementation of readAll(). + * We want to use the TBufferBase version instead. + */ + uint32_t readAll(uint8_t* buf, uint32_t len) { return TBufferBase::readAll(buf, len); } + + //! \brief Get the current buffer size + //! \returns the current buffer size + uint32_t getBufferSize() const { + return bufferSize_; + } + + //! \brief Get the current maximum buffer size + //! \returns the current maximum buffer size + uint32_t getMaxBufferSize() const { + return maxBufferSize_; + } + + //! \brief Change the maximum buffer size + //! \param[in] maxSize the new maximum buffer size allowed to grow to + //! \throws TTransportException(BAD_ARGS) if maxSize is less than the current buffer size + void setMaxBufferSize(uint32_t maxSize) { + if (maxSize < bufferSize_) { + throw TTransportException(TTransportException::BAD_ARGS, + "Maximum buffer size would be less than current buffer size"); + } + maxBufferSize_ = maxSize; + } + +protected: + void swap(TMemoryBuffer& that) { + using std::swap; + swap(buffer_, that.buffer_); + swap(bufferSize_, that.bufferSize_); + + swap(rBase_, that.rBase_); + swap(rBound_, that.rBound_); + swap(wBase_, that.wBase_); + swap(wBound_, that.wBound_); + + swap(owner_, that.owner_); + } + + // Make sure there's at least 'len' bytes available for writing. + void ensureCanWrite(uint32_t len); + + // Compute the position and available data for reading. + void computeRead(uint32_t len, uint8_t** out_start, uint32_t* out_give); + + uint32_t readSlow(uint8_t* buf, uint32_t len) override; + + void writeSlow(const uint8_t* buf, uint32_t len) override; + + const uint8_t* borrowSlow(uint8_t* buf, uint32_t* len) override; + + // Data buffer + uint8_t* buffer_; + + // Allocated buffer size + uint32_t bufferSize_; + + // Maximum allowed size + uint32_t maxBufferSize_; + + // Is this object the owner of the buffer? + bool owner_; + + // Don't forget to update constrctors, initCommon, and swap if + // you add new members. +}; +} +} +} // apache::thrift::transport + +#endif // #ifndef _THRIFT_TRANSPORT_TBUFFERTRANSPORTS_H_ diff --git a/bsnes/thrift/thrift/transport/TFDTransport.h b/bsnes/thrift/thrift/transport/TFDTransport.h new file mode 100644 index 00000000..fb84c9d8 --- /dev/null +++ b/bsnes/thrift/thrift/transport/TFDTransport.h @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_TFDTRANSPORT_H_ +#define _THRIFT_TRANSPORT_TFDTRANSPORT_H_ 1 + +#include +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#include +#include + +namespace apache { +namespace thrift { +namespace transport { + +/** + * Dead-simple wrapper around a file descriptor. + * + */ +class TFDTransport : public TVirtualTransport { +public: + enum ClosePolicy { NO_CLOSE_ON_DESTROY = 0, CLOSE_ON_DESTROY = 1 }; + + TFDTransport(int fd, ClosePolicy close_policy = NO_CLOSE_ON_DESTROY, + std::shared_ptr config = nullptr) + : TVirtualTransport(config), fd_(fd), close_policy_(close_policy) { + } + + ~TFDTransport() override { + if (close_policy_ == CLOSE_ON_DESTROY) { + try { + close(); + } catch (TTransportException& ex) { + GlobalOutput.printf("~TFDTransport TTransportException: '%s'", ex.what()); + } + } + } + + bool isOpen() const override { return fd_ >= 0; } + + void open() override {} + + void close() override; + + uint32_t read(uint8_t* buf, uint32_t len); + + void write(const uint8_t* buf, uint32_t len); + + void setFD(int fd) { fd_ = fd; } + int getFD() { return fd_; } + +protected: + int fd_; + ClosePolicy close_policy_; +}; +} +} +} // apache::thrift::transport + +#endif // #ifndef _THRIFT_TRANSPORT_TFDTRANSPORT_H_ diff --git a/bsnes/thrift/thrift/transport/TFileTransport.h b/bsnes/thrift/thrift/transport/TFileTransport.h new file mode 100644 index 00000000..608cff18 --- /dev/null +++ b/bsnes/thrift/thrift/transport/TFileTransport.h @@ -0,0 +1,439 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_TFILETRANSPORT_H_ +#define _THRIFT_TRANSPORT_TFILETRANSPORT_H_ 1 + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +namespace apache { +namespace thrift { +namespace transport { + +using apache::thrift::TProcessor; +using apache::thrift::protocol::TProtocolFactory; +using apache::thrift::concurrency::Mutex; +using apache::thrift::concurrency::Monitor; + +// Data pertaining to a single event +typedef struct eventInfo { + uint8_t* eventBuff_; + uint32_t eventSize_; + uint32_t eventBuffPos_; + + eventInfo() : eventBuff_(nullptr), eventSize_(0), eventBuffPos_(0){}; + ~eventInfo() { + if (eventBuff_) { + delete[] eventBuff_; + } + } +} eventInfo; + +// information about current read state +typedef struct readState { + eventInfo* event_; + + // keep track of event size + uint8_t eventSizeBuff_[4]; + uint8_t eventSizeBuffPos_; + bool readingSize_; + + // read buffer variables + int32_t bufferPtr_; + int32_t bufferLen_; + + // last successful dispatch point + int32_t lastDispatchPtr_; + + void resetState(uint32_t lastDispatchPtr) { + readingSize_ = true; + eventSizeBuffPos_ = 0; + lastDispatchPtr_ = lastDispatchPtr; + } + + void resetAllValues() { + resetState(0); + bufferPtr_ = 0; + bufferLen_ = 0; + if (event_) { + delete (event_); + } + event_ = nullptr; + } + + inline uint32_t getEventSize() { + const void* buffer = reinterpret_cast(eventSizeBuff_); + return *reinterpret_cast(buffer); + } + + readState() { + event_ = nullptr; + resetAllValues(); + } + + ~readState() { + if (event_) { + delete (event_); + } + } + +} readState; + +/** + * TFileTransportBuffer - buffer class used by TFileTransport for queueing up events + * to be written to disk. Should be used in the following way: + * 1) Buffer created + * 2) Buffer written to (addEvent) + * 3) Buffer read from (getNext) + * 4) Buffer reset (reset) + * 5) Go back to 2, or destroy buffer + * + * The buffer should never be written to after it is read from, unless it is reset first. + * Note: The above rules are enforced mainly for debugging its sole client TFileTransport + * which uses the buffer in this way. + * + */ +class TFileTransportBuffer { +public: + TFileTransportBuffer(uint32_t size); + ~TFileTransportBuffer(); + + bool addEvent(eventInfo* event); + eventInfo* getNext(); + void reset(); + bool isFull(); + bool isEmpty(); + +private: + TFileTransportBuffer(); // should not be used + + enum mode { WRITE, READ }; + mode bufferMode_; + + uint32_t writePoint_; + uint32_t readPoint_; + uint32_t size_; + eventInfo** buffer_; +}; + +/** + * Abstract interface for transports used to read files + */ +class TFileReaderTransport : virtual public TTransport { +public: + virtual int32_t getReadTimeout() = 0; + virtual void setReadTimeout(int32_t readTimeout) = 0; + + virtual uint32_t getNumChunks() = 0; + virtual uint32_t getCurChunk() = 0; + virtual void seekToChunk(int32_t chunk) = 0; + virtual void seekToEnd() = 0; +}; + +/** + * Abstract interface for transports used to write files + */ +class TFileWriterTransport : virtual public TTransport { +public: + virtual uint32_t getChunkSize() = 0; + virtual void setChunkSize(uint32_t chunkSize) = 0; +}; + +/** + * File implementation of a transport. Reads and writes are done to a + * file on disk. + * + */ +class TFileTransport : public TFileReaderTransport, public TFileWriterTransport { +public: + TFileTransport(std::string path, bool readOnly = false, std::shared_ptr config = nullptr); + ~TFileTransport() override; + + // TODO: what is the correct behaviour for this? + // the log file is generally always open + bool isOpen() const override { return true; } + + void write(const uint8_t* buf, uint32_t len); + void flush() override; + + uint32_t readAll(uint8_t* buf, uint32_t len); + uint32_t read(uint8_t* buf, uint32_t len); + bool peek() override; + + // log-file specific functions + void seekToChunk(int32_t chunk) override; + void seekToEnd() override; + uint32_t getNumChunks() override; + uint32_t getCurChunk() override; + + // for changing the output file + void resetOutputFile(int fd, std::string filename, off_t offset); + + // Setter/Getter functions for user-controllable options + void setReadBuffSize(uint32_t readBuffSize) { + if (readBuffSize) { + readBuffSize_ = readBuffSize; + } + } + uint32_t getReadBuffSize() { return readBuffSize_; } + + static const int32_t TAIL_READ_TIMEOUT = -1; + static const int32_t NO_TAIL_READ_TIMEOUT = 0; + void setReadTimeout(int32_t readTimeout) override { readTimeout_ = readTimeout; } + int32_t getReadTimeout() override { return readTimeout_; } + + void setChunkSize(uint32_t chunkSize) override { + if (chunkSize) { + chunkSize_ = chunkSize; + } + } + uint32_t getChunkSize() override { return chunkSize_; } + + void setEventBufferSize(uint32_t bufferSize) { + if (bufferAndThreadInitialized_) { + GlobalOutput("Cannot change the buffer size after writer thread started"); + return; + } + eventBufferSize_ = bufferSize; + } + + uint32_t getEventBufferSize() { return eventBufferSize_; } + + void setFlushMaxUs(uint32_t flushMaxUs) { + if (flushMaxUs) { + flushMaxUs_ = flushMaxUs; + } + } + uint32_t getFlushMaxUs() { return flushMaxUs_; } + + void setFlushMaxBytes(uint32_t flushMaxBytes) { + if (flushMaxBytes) { + flushMaxBytes_ = flushMaxBytes; + } + } + uint32_t getFlushMaxBytes() { return flushMaxBytes_; } + + void setMaxEventSize(uint32_t maxEventSize) { maxEventSize_ = maxEventSize; } + uint32_t getMaxEventSize() { return maxEventSize_; } + + void setMaxCorruptedEvents(uint32_t maxCorruptedEvents) { + maxCorruptedEvents_ = maxCorruptedEvents; + } + uint32_t getMaxCorruptedEvents() { return maxCorruptedEvents_; } + + void setEofSleepTimeUs(uint32_t eofSleepTime) { + if (eofSleepTime) { + eofSleepTime_ = eofSleepTime; + } + } + uint32_t getEofSleepTimeUs() { return eofSleepTime_; } + + /* + * Override TTransport *_virt() functions to invoke our implementations. + * We cannot use TVirtualTransport to provide these, since we need to inherit + * virtually from TTransport. + */ + uint32_t read_virt(uint8_t* buf, uint32_t len) override { return this->read(buf, len); } + uint32_t readAll_virt(uint8_t* buf, uint32_t len) override { return this->readAll(buf, len); } + void write_virt(const uint8_t* buf, uint32_t len) override { this->write(buf, len); } + +private: + // helper functions for writing to a file + void enqueueEvent(const uint8_t* buf, uint32_t eventLen); + bool swapEventBuffers(const std::chrono::time_point *deadline); + bool initBufferAndWriteThread(); + + // control for writer thread + static void* startWriterThread(void* ptr) { + static_cast(ptr)->writerThread(); + return nullptr; + } + void writerThread(); + + // helper functions for reading from a file + eventInfo* readEvent(); + + // event corruption-related functions + bool isEventCorrupted(); + void performRecovery(); + + // Utility functions + void openLogFile(); + std::chrono::time_point getNextFlushTime(); + + // Class variables + readState readState_; + uint8_t* readBuff_; + eventInfo* currentEvent_; + + uint32_t readBuffSize_; + static const uint32_t DEFAULT_READ_BUFF_SIZE = 1 * 1024 * 1024; + + int32_t readTimeout_; + static const int32_t DEFAULT_READ_TIMEOUT_MS = 200; + + // size of chunks that file will be split up into + uint32_t chunkSize_; + static const uint32_t DEFAULT_CHUNK_SIZE = 16 * 1024 * 1024; + + // size of event buffers + uint32_t eventBufferSize_; + static const uint32_t DEFAULT_EVENT_BUFFER_SIZE = 10000; + + // max number of microseconds that can pass without flushing + uint32_t flushMaxUs_; + static const uint32_t DEFAULT_FLUSH_MAX_US = 3000000; + + // max number of bytes that can be written without flushing + uint32_t flushMaxBytes_; + static const uint32_t DEFAULT_FLUSH_MAX_BYTES = 1000 * 1024; + + // max event size + uint32_t maxEventSize_; + static const uint32_t DEFAULT_MAX_EVENT_SIZE = 0; + + // max number of corrupted events per chunk + uint32_t maxCorruptedEvents_; + static const uint32_t DEFAULT_MAX_CORRUPTED_EVENTS = 0; + + // sleep duration when EOF is hit + uint32_t eofSleepTime_; + static const uint32_t DEFAULT_EOF_SLEEP_TIME_US = 500 * 1000; + + // sleep duration when a corrupted event is encountered + uint32_t corruptedEventSleepTime_; + static const uint32_t DEFAULT_CORRUPTED_SLEEP_TIME_US = 1 * 1000 * 1000; + + // sleep duration in seconds when an IO error is encountered in the writer thread + uint32_t writerThreadIOErrorSleepTime_; + static const uint32_t DEFAULT_WRITER_THREAD_SLEEP_TIME_US = 60 * 1000 * 1000; + + // writer thread + apache::thrift::concurrency::ThreadFactory threadFactory_; + std::shared_ptr writerThread_; + + // buffers to hold data before it is flushed. Each element of the buffer stores a msg that + // needs to be written to the file. The buffers are swapped by the writer thread. + TFileTransportBuffer* dequeueBuffer_; + TFileTransportBuffer* enqueueBuffer_; + + // conditions used to block when the buffer is full or empty + Monitor notFull_, notEmpty_; + std::atomic closing_; + + // To keep track of whether the buffer has been flushed + Monitor flushed_; + std::atomic forceFlush_; + + // Mutex that is grabbed when enqueueing and swapping the read/write buffers + Mutex mutex_; + + // File information + std::string filename_; + int fd_; + + // Whether the writer thread and buffers have been initialized + bool bufferAndThreadInitialized_; + + // Offset within the file + off_t offset_; + + // event corruption information + uint32_t lastBadChunk_; + uint32_t numCorruptedEventsInChunk_; + + bool readOnly_; +}; + +// Exception thrown when EOF is hit +class TEOFException : public TTransportException { +public: + TEOFException() : TTransportException(TTransportException::END_OF_FILE){}; +}; + +// wrapper class to process events from a file containing thrift events +class TFileProcessor { +public: + /** + * Constructor that defaults output transport to null transport + * + * @param processor processes log-file events + * @param protocolFactory protocol factory + * @param inputTransport file transport + */ + TFileProcessor(std::shared_ptr processor, + std::shared_ptr protocolFactory, + std::shared_ptr inputTransport); + + TFileProcessor(std::shared_ptr processor, + std::shared_ptr inputProtocolFactory, + std::shared_ptr outputProtocolFactory, + std::shared_ptr inputTransport); + + /** + * Constructor + * + * @param processor processes log-file events + * @param protocolFactory protocol factory + * @param inputTransport input file transport + * @param output output transport + */ + TFileProcessor(std::shared_ptr processor, + std::shared_ptr protocolFactory, + std::shared_ptr inputTransport, + std::shared_ptr outputTransport); + + /** + * processes events from the file + * + * @param numEvents number of events to process (0 for unlimited) + * @param tail tails the file if true + */ + void process(uint32_t numEvents, bool tail); + + /** + * process events until the end of the chunk + * + */ + void processChunk(); + +private: + std::shared_ptr processor_; + std::shared_ptr inputProtocolFactory_; + std::shared_ptr outputProtocolFactory_; + std::shared_ptr inputTransport_; + std::shared_ptr outputTransport_; +}; +} +} +} // apache::thrift::transport + +#endif // _THRIFT_TRANSPORT_TFILETRANSPORT_H_ + diff --git a/bsnes/thrift/thrift/transport/THeaderTransport.h b/bsnes/thrift/thrift/transport/THeaderTransport.h new file mode 100644 index 00000000..63a4ac88 --- /dev/null +++ b/bsnes/thrift/thrift/transport/THeaderTransport.h @@ -0,0 +1,277 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef THRIFT_TRANSPORT_THEADERTRANSPORT_H_ +#define THRIFT_TRANSPORT_THEADERTRANSPORT_H_ 1 + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_STDINT_H +#include +#elif HAVE_INTTYPES_H +#include +#endif + +#include + +#include +#include +#include +#include + +enum CLIENT_TYPE { + THRIFT_HEADER_CLIENT_TYPE = 0, + THRIFT_FRAMED_BINARY = 1, + THRIFT_UNFRAMED_BINARY = 2, + THRIFT_FRAMED_COMPACT = 3, + THRIFT_UNFRAMED_COMPACT = 4, + THRIFT_UNKNOWN_CLIENT_TYPE = 5, +}; + +namespace apache { +namespace thrift { +namespace transport { + +using apache::thrift::protocol::T_COMPACT_PROTOCOL; + +/** + * Header transport. All writes go into an in-memory buffer until flush is + * called, at which point the transport writes the length of the entire + * binary chunk followed by the data payload. This allows the receiver on the + * other end to always do fixed-length reads. + * + * Subclass TFramedTransport because most of the read/write methods are similar + * and need similar buffers. Major changes are readFrame & flush. + * + * Header Transport *must* be the same transport for both input and + * output when used on the server side - client responses should be + * the same protocol as those in the request. + */ +class THeaderTransport : public TVirtualTransport { +public: + static const int DEFAULT_BUFFER_SIZE = 512u; + static const int THRIFT_MAX_VARINT32_BYTES = 5; + + /// Use default buffer sizes. + explicit THeaderTransport(const std::shared_ptr& transport, + std::shared_ptr config = nullptr) + : TVirtualTransport(transport, config), + outTransport_(transport), + protoId(T_COMPACT_PROTOCOL), + clientType(THRIFT_HEADER_CLIENT_TYPE), + seqId(0), + flags(0), + tBufSize_(0), + tBuf_(nullptr) { + if (!transport_) throw std::invalid_argument("transport is empty"); + initBuffers(); + } + + THeaderTransport(const std::shared_ptr inTransport, + const std::shared_ptr outTransport, + std::shared_ptr config = nullptr) + : TVirtualTransport(inTransport, config), + outTransport_(outTransport), + protoId(T_COMPACT_PROTOCOL), + clientType(THRIFT_HEADER_CLIENT_TYPE), + seqId(0), + flags(0), + tBufSize_(0), + tBuf_(nullptr) { + if (!transport_) throw std::invalid_argument("inTransport is empty"); + if (!outTransport_) throw std::invalid_argument("outTransport is empty"); + initBuffers(); + } + + uint32_t readSlow(uint8_t* buf, uint32_t len) override; + void flush() override; + + void resizeTransformBuffer(uint32_t additionalSize = 0); + + uint16_t getProtocolId() const; + void setProtocolId(uint16_t protoId) { this->protoId = protoId; } + + void resetProtocol(); + + /** + * We know we got a packet in header format here, try to parse the header + * + * @param headerSize size of the header portion + * @param sz Size of the whole message, including header + */ + void readHeaderFormat(uint16_t headerSize, uint32_t sz); + + /** + * Untransform the data based on the received header flags + * On conclusion of function, setReadBuffer is called with the + * untransformed data. + * + * @param ptr ptr to data + * @param size of data + */ + void untransform(uint8_t* ptr, uint32_t sz); + + /** + * Transform the data based on our write transform flags + * At conclusion of function the write buffer is set to the + * transformed data. + * + * @param ptr Ptr to data to transform + * @param sz Size of data buffer + */ + void transform(uint8_t* ptr, uint32_t sz); + + uint16_t getNumTransforms() const { + return safe_numeric_cast(writeTrans_.size()); + } + + void setTransform(uint16_t transId) { writeTrans_.push_back(transId); } + + // Info headers + + typedef std::map StringToStringMap; + + // these work with write headers + void setHeader(const std::string& key, const std::string& value); + + void clearHeaders(); + + StringToStringMap& getWriteHeaders() { return writeHeaders_; } + + // these work with read headers + const StringToStringMap& getHeaders() const { return readHeaders_; } + + // accessors for seqId + int32_t getSequenceNumber() const { return seqId; } + void setSequenceNumber(int32_t seqId) { this->seqId = seqId; } + + enum TRANSFORMS { + ZLIB_TRANSFORM = 0x01, + }; + +protected: + /** + * Reads a frame of input from the underlying stream. + * + * Returns true if a frame was read successfully, or false on EOF. + * (Raises a TTransportException if EOF occurs after a partial frame.) + */ + bool readFrame() override; + + void ensureReadBuffer(uint32_t sz); + uint32_t getWriteBytes(); + + void initBuffers() { + setReadBuffer(nullptr, 0); + setWriteBuffer(wBuf_.get(), wBufSize_); + } + + std::shared_ptr outTransport_; + + // 0 and 16th bits must be 0 to differentiate from framed & unframed + static const uint32_t HEADER_MAGIC = 0x0FFF0000; + static const uint32_t HEADER_MASK = 0xFFFF0000; + static const uint32_t FLAGS_MASK = 0x0000FFFF; + + static const uint32_t MAX_FRAME_SIZE = 0x3FFFFFFF; + + int16_t protoId; + uint16_t clientType; + uint32_t seqId; + uint16_t flags; + + std::vector readTrans_; + std::vector writeTrans_; + + // Map to use for headers + StringToStringMap readHeaders_; + StringToStringMap writeHeaders_; + + /** + * Returns the maximum number of bytes that write k/v headers can take + */ + uint32_t getMaxWriteHeadersSize() const; + + struct infoIdType { + enum idType { + // start at 1 to avoid confusing header padding for an infoId + KEYVALUE = 1, + END // signal the end of infoIds we can handle + }; + }; + + // Buffers to use for transform processing + uint32_t tBufSize_; + boost::scoped_array tBuf_; + + void readString(uint8_t*& ptr, /* out */ std::string& str, uint8_t const* headerBoundary); + + void writeString(uint8_t*& ptr, const std::string& str); + + // Varint utils + /** + * Read an i16 from the wire as a varint. The MSB of each byte is set + * if there is another byte to follow. This can read up to 3 bytes. + */ + uint32_t readVarint16(uint8_t const* ptr, int16_t* i16, uint8_t const* boundary); + + /** + * Read an i32 from the wire as a varint. The MSB of each byte is set + * if there is another byte to follow. This can read up to 5 bytes. + */ + uint32_t readVarint32(uint8_t const* ptr, int32_t* i32, uint8_t const* boundary); + + /** + * Write an i32 as a varint. Results in 1-5 bytes on the wire. + */ + uint32_t writeVarint32(int32_t n, uint8_t* pkt); + + /** + * Write an i16 as a varint. Results in 1-3 bytes on the wire. + */ + uint32_t writeVarint16(int16_t n, uint8_t* pkt); +}; + +/** + * Wraps a transport into a header one. + * + */ +class THeaderTransportFactory : public TTransportFactory { +public: + THeaderTransportFactory() = default; + + ~THeaderTransportFactory() override = default; + + /** + * Wraps the transport into a header one. + */ + std::shared_ptr getTransport(std::shared_ptr trans) override { + return std::shared_ptr(new THeaderTransport(trans)); + } +}; +} +} +} // apache::thrift::transport + +#endif // #ifndef THRIFT_TRANSPORT_THEADERTRANSPORT_H_ diff --git a/bsnes/thrift/thrift/transport/THttpClient.h b/bsnes/thrift/thrift/transport/THttpClient.h new file mode 100644 index 00000000..f0d7e8b2 --- /dev/null +++ b/bsnes/thrift/thrift/transport/THttpClient.h @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_THTTPCLIENT_H_ +#define _THRIFT_TRANSPORT_THTTPCLIENT_H_ 1 + +#include + +namespace apache { +namespace thrift { +namespace transport { + +/** + * @brief Client transport using HTTP. The path is an optional field that is + * not required by Thrift HTTP server or client. It can be used i.e. with HTTP + * redirection, load balancing or forwarding on the server. + */ +class THttpClient : public THttpTransport { +public: + /** + * @brief Constructor that wraps an existing transport, but also sets the + * host and path. The host and path are not used for the connection but are + * set in the HTTP header of the transport. + */ + THttpClient(std::shared_ptr transport, + std::string host = "localhost", + std::string path = "/service", + std::shared_ptr config = nullptr); + + /** + * @brief Constructor that will create a new socket transport using the host + * and port. + */ + THttpClient(std::string host, int port, + std::string path = "", + std::shared_ptr config = nullptr); + + ~THttpClient() override; + + void flush() override; + + void setPath(std::string path); + +protected: + std::string host_; + std::string path_; + + void parseHeader(char* header) override; + bool parseStatusLine(char* status) override; +}; +} +} +} // apache::thrift::transport + +#endif // #ifndef _THRIFT_TRANSPORT_THTTPCLIENT_H_ diff --git a/bsnes/thrift/thrift/transport/THttpServer.h b/bsnes/thrift/thrift/transport/THttpServer.h new file mode 100644 index 00000000..bc98986d --- /dev/null +++ b/bsnes/thrift/thrift/transport/THttpServer.h @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_THTTPSERVER_H_ +#define _THRIFT_TRANSPORT_THTTPSERVER_H_ 1 + +#include + +namespace apache { +namespace thrift { +namespace transport { + +class THttpServer : public THttpTransport { +public: + THttpServer(std::shared_ptr transport, std::shared_ptr config = nullptr); + + ~THttpServer() override; + + void flush() override; + +protected: + virtual std::string getHeader(uint32_t len); + void readHeaders(); + void parseHeader(char* header) override; + bool parseStatusLine(char* status) override; + std::string getTimeRFC1123(); +}; + +/** + * Wraps a transport into HTTP protocol + */ +class THttpServerTransportFactory : public TTransportFactory { +public: + THttpServerTransportFactory() = default; + + ~THttpServerTransportFactory() override = default; + + /** + * Wraps the transport into a buffered one. + */ + std::shared_ptr getTransport(std::shared_ptr trans) override { + return std::shared_ptr(new THttpServer(trans)); + } +}; +} +} +} // apache::thrift::transport + +#endif // #ifndef _THRIFT_TRANSPORT_THTTPSERVER_H_ diff --git a/bsnes/thrift/thrift/transport/THttpTransport.h b/bsnes/thrift/thrift/transport/THttpTransport.h new file mode 100644 index 00000000..5d2bd37f --- /dev/null +++ b/bsnes/thrift/thrift/transport/THttpTransport.h @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_THTTPTRANSPORT_H_ +#define _THRIFT_TRANSPORT_THTTPTRANSPORT_H_ 1 + +#include +#include + +namespace apache { +namespace thrift { +namespace transport { + +/** + * HTTP implementation of the thrift transport. This was irritating + * to write, but the alternatives in C++ land are daunting. Linking CURL + * requires 23 dynamic libraries last time I checked (WTF?!?). All we have + * here is a VERY basic HTTP/1.1 client which supports HTTP 100 Continue, + * chunked transfer encoding, keepalive, etc. Tested against Apache. + */ +class THttpTransport : public TVirtualTransport { +public: + THttpTransport(std::shared_ptr transport, std::shared_ptr config = nullptr); + + ~THttpTransport() override; + + void open() override { transport_->open(); } + + bool isOpen() const override { return transport_->isOpen(); } + + bool peek() override { return transport_->peek(); } + + void close() override { transport_->close(); } + + uint32_t read(uint8_t* buf, uint32_t len); + + uint32_t readEnd() override; + + void write(const uint8_t* buf, uint32_t len); + + void flush() override { + resetConsumedMessageSize(); + }; + + const std::string getOrigin() const override; + +protected: + std::shared_ptr transport_; + std::string origin_; + + TMemoryBuffer writeBuffer_; + TMemoryBuffer readBuffer_; + + bool readHeaders_; + bool chunked_; + bool chunkedDone_; + uint32_t chunkSize_; + uint32_t contentLength_; + + char* httpBuf_; + uint32_t httpPos_; + uint32_t httpBufLen_; + uint32_t httpBufSize_; + + virtual void init(); + + uint32_t readMoreData(); + char* readLine(); + + void readHeaders(); + virtual void parseHeader(char* header) = 0; + virtual bool parseStatusLine(char* status) = 0; + + uint32_t readChunked(); + void readChunkedFooters(); + uint32_t parseChunkSize(char* line); + + uint32_t readContent(uint32_t size); + + void refill(); + void shift(); + + static const char* CRLF; + static const int CRLF_LEN; +}; +} +} +} // apache::thrift::transport + +#endif // #ifndef _THRIFT_TRANSPORT_THTTPCLIENT_H_ diff --git a/bsnes/thrift/thrift/transport/TNonblockingSSLServerSocket.h b/bsnes/thrift/thrift/transport/TNonblockingSSLServerSocket.h new file mode 100644 index 00000000..a38bf126 --- /dev/null +++ b/bsnes/thrift/thrift/transport/TNonblockingSSLServerSocket.h @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_TNONBLOCKINGSSLSERVERSOCKET_H_ +#define _THRIFT_TRANSPORT_TNONBLOCKINGSSLSERVERSOCKET_H_ 1 + +#include + +namespace apache { +namespace thrift { +namespace transport { + +class TSSLSocketFactory; + +/** + * Nonblocking Server socket that accepts SSL connections. + */ +class TNonblockingSSLServerSocket : public TNonblockingServerSocket { +public: + /** + * Constructor. Binds to all interfaces. + * + * @param port Listening port + * @param factory SSL socket factory implementation + */ + TNonblockingSSLServerSocket(int port, std::shared_ptr factory); + + /** + * Constructor. Binds to the specified address. + * + * @param address Address to bind to + * @param port Listening port + * @param factory SSL socket factory implementation + */ + TNonblockingSSLServerSocket(const std::string& address, + int port, + std::shared_ptr factory); + + /** + * Constructor. Binds to all interfaces. + * + * @param port Listening port + * @param sendTimeout Socket send timeout + * @param recvTimeout Socket receive timeout + * @param factory SSL socket factory implementation + */ + TNonblockingSSLServerSocket(int port, + int sendTimeout, + int recvTimeout, + std::shared_ptr factory); + +protected: + std::shared_ptr createSocket(THRIFT_SOCKET socket) override; + std::shared_ptr factory_; +}; +} +} +} + +#endif diff --git a/bsnes/thrift/thrift/transport/TNonblockingServerSocket.h b/bsnes/thrift/thrift/transport/TNonblockingServerSocket.h new file mode 100644 index 00000000..1ed2b07f --- /dev/null +++ b/bsnes/thrift/thrift/transport/TNonblockingServerSocket.h @@ -0,0 +1,139 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_TNONBLOCKINGSERVERSOCKET_H_ +#define _THRIFT_TRANSPORT_TNONBLOCKINGSERVERSOCKET_H_ 1 + +#include +#include + +namespace apache { +namespace thrift { +namespace transport { + +class TSocket; + +/** + * Nonblocking Server socket implementation of TNonblockingServerTransport. Wrapper around a unix + * socket listen and accept calls. + * + */ +class TNonblockingServerSocket : public TNonblockingServerTransport { +public: + typedef std::function socket_func_t; + + const static int DEFAULT_BACKLOG = 1024; + + /** + * Constructor. + * + * @param port Port number to bind to + */ + TNonblockingServerSocket(int port); + + /** + * Constructor. + * + * @param port Port number to bind to + * @param sendTimeout Socket send timeout + * @param recvTimeout Socket receive timeout + */ + TNonblockingServerSocket(int port, int sendTimeout, int recvTimeout); + + /** + * Constructor. + * + * @param address Address to bind to + * @param port Port number to bind to + */ + TNonblockingServerSocket(const std::string& address, int port); + + /** + * Constructor used for unix sockets. + * + * @param path Pathname for unix socket. + */ + TNonblockingServerSocket(const std::string& path); + + ~TNonblockingServerSocket() override; + + void setSendTimeout(int sendTimeout); + void setRecvTimeout(int recvTimeout); + + void setAcceptBacklog(int accBacklog); + + void setRetryLimit(int retryLimit); + void setRetryDelay(int retryDelay); + + void setKeepAlive(bool keepAlive) { keepAlive_ = keepAlive; } + + void setTcpSendBuffer(int tcpSendBuffer); + void setTcpRecvBuffer(int tcpRecvBuffer); + + // listenCallback gets called just before listen, and after all Thrift + // setsockopt calls have been made. If you have custom setsockopt + // things that need to happen on the listening socket, this is the place to do it. + void setListenCallback(const socket_func_t& listenCallback) { listenCallback_ = listenCallback; } + + // acceptCallback gets called after each accept call, on the newly created socket. + // It is called after all Thrift setsockopt calls have been made. If you have + // custom setsockopt things that need to happen on the accepted + // socket, this is the place to do it. + void setAcceptCallback(const socket_func_t& acceptCallback) { acceptCallback_ = acceptCallback; } + + THRIFT_SOCKET getSocketFD() override { return serverSocket_; } + + int getPort() override; + + int getListenPort() override; + + void listen() override; + void close() override; + +protected: + std::shared_ptr acceptImpl() override; + virtual std::shared_ptr createSocket(THRIFT_SOCKET client); + +private: + int port_; + int listenPort_; + std::string address_; + std::string path_; + THRIFT_SOCKET serverSocket_; + int acceptBacklog_; + int sendTimeout_; + int recvTimeout_; + int retryLimit_; + int retryDelay_; + int tcpSendBuffer_; + int tcpRecvBuffer_; + bool keepAlive_; + bool listening_; + + socket_func_t listenCallback_; + socket_func_t acceptCallback_; + + void _setup_sockopts(); + void _setup_tcp_sockopts(); +}; +} +} +} // apache::thrift::transport + +#endif // #ifndef _THRIFT_TRANSPORT_TNONBLOCKINGSERVERSOCKET_H_ diff --git a/bsnes/thrift/thrift/transport/TNonblockingServerTransport.h b/bsnes/thrift/thrift/transport/TNonblockingServerTransport.h new file mode 100644 index 00000000..e8997d78 --- /dev/null +++ b/bsnes/thrift/thrift/transport/TNonblockingServerTransport.h @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_TNONBLOCKINGSERVERTRANSPORT_H_ +#define _THRIFT_TRANSPORT_TNONBLOCKINGSERVERTRANSPORT_H_ 1 + +#include +#include + +namespace apache { +namespace thrift { +namespace transport { + +/** + * Server transport framework. A server needs to have some facility for + * creating base transports to read/write from. The server is expected + * to keep track of TTransport children that it creates for purposes of + * controlling their lifetime. + */ +class TNonblockingServerTransport { +public: + virtual ~TNonblockingServerTransport() = default; + + /** + * Starts the server transport listening for new connections. Prior to this + * call most transports will not return anything when accept is called. + * + * @throws TTransportException if we were unable to listen + */ + virtual void listen() {} + + /** + * Gets a new dynamically allocated transport object and passes it to the + * caller. Note that it is the explicit duty of the caller to free the + * allocated object. The returned TTransport object must always be in the + * opened state. nullptr should never be returned, instead an Exception should + * always be thrown. + * + * @return A new TTransport object + * @throws TTransportException if there is an error + */ + std::shared_ptr accept() { + std::shared_ptr result = acceptImpl(); + if (!result) { + throw TTransportException("accept() may not return nullptr"); + } + return result; + } + + /** + * Utility method + * + * @return server socket file descriptor + * @throw TTransportException If an error occurs + */ + + virtual THRIFT_SOCKET getSocketFD() = 0; + + virtual int getPort() = 0; + + virtual int getListenPort() = 0; + + /** + * Closes this transport such that future calls to accept will do nothing. + */ + virtual void close() = 0; + +protected: + TNonblockingServerTransport() = default; + + /** + * Subclasses should implement this function for accept. + * + * @return A newly allocated TTransport object + * @throw TTransportException If an error occurs + */ + virtual std::shared_ptr acceptImpl() = 0; + +}; +} +} +} // apache::thrift::transport + +#endif // #ifndef _THRIFT_TRANSPORT_TNONBLOCKINGSERVERTRANSPORT_H_ diff --git a/bsnes/thrift/thrift/transport/TPipe.h b/bsnes/thrift/thrift/transport/TPipe.h new file mode 100644 index 00000000..7795151a --- /dev/null +++ b/bsnes/thrift/thrift/transport/TPipe.h @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_TPIPE_H_ +#define _THRIFT_TRANSPORT_TPIPE_H_ 1 + +#include +#include +#ifndef _WIN32 +#include +#endif +#ifdef _WIN32 +#include +#endif +#include +#ifdef _WIN32 +#include +#endif + +namespace apache { +namespace thrift { +namespace transport { + +/** + * Windows Pipes implementation of the TTransport interface. + * Don't destroy a TPipe at global scope, as that will cause a thread join + * during DLLMain. That also means that client objects using TPipe shouldn't be at global + * scope. + */ +#ifdef _WIN32 +class TPipeImpl; + +class TPipe : public TVirtualTransport { +public: + // Constructs a new pipe object. + TPipe(std::shared_ptr config = nullptr); + // Named pipe constructors - + explicit TPipe(HANDLE Pipe, std::shared_ptr config = nullptr); // HANDLE is a void* + explicit TPipe(TAutoHandle& Pipe, std::shared_ptr config = nullptr); // this ctor will clear out / move from Pipe + // need a const char * overload so string literals don't go to the HANDLE overload + explicit TPipe(const char* pipename, std::shared_ptr config = nullptr); + explicit TPipe(const std::string& pipename, std::shared_ptr config = nullptr); + // Anonymous pipe - + TPipe(HANDLE PipeRd, HANDLE PipeWrt, std::shared_ptr config = nullptr); + + // Destroys the pipe object, closing it if necessary. + virtual ~TPipe(); + + // Returns whether the pipe is open & valid. + bool isOpen() const override; + + // Checks whether more data is available in the pipe. + bool peek() override; + + // Creates and opens the named/anonymous pipe. + void open() override; + + // Shuts down communications on the pipe. + void close() override; + + // Reads from the pipe. + virtual uint32_t read(uint8_t* buf, uint32_t len); + + // Writes to the pipe. + virtual void write(const uint8_t* buf, uint32_t len); + + // Accessors + std::string getPipename(); + void setPipename(const std::string& pipename); + HANDLE getPipeHandle(); // doubles as the read handle for anon pipe + void setPipeHandle(HANDLE pipehandle); + HANDLE getWrtPipeHandle(); + void setWrtPipeHandle(HANDLE pipehandle); + long getConnTimeout(); + void setConnTimeout(long seconds); + + // this function is intended to be used in generic / template situations, + // so its name needs to be the same as TPipeServer's + HANDLE getNativeWaitHandle(); + +private: + std::shared_ptr impl_; + + std::string pipename_; + + long TimeoutSeconds_; + bool isAnonymous_; +}; + +#else +typedef TSocket TPipe; +#endif +} +} +} // apache::thrift::transport + +#endif // #ifndef _THRIFT_TRANSPORT_TPIPE_H_ diff --git a/bsnes/thrift/thrift/transport/TPipeServer.h b/bsnes/thrift/thrift/transport/TPipeServer.h new file mode 100644 index 00000000..67c5d51a --- /dev/null +++ b/bsnes/thrift/thrift/transport/TPipeServer.h @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_TSERVERWINPIPES_H_ +#define _THRIFT_TRANSPORT_TSERVERWINPIPES_H_ 1 + +#include +#include +#ifndef _WIN32 +#include +#endif +#ifdef _WIN32 +#include +#endif + +#define TPIPE_SERVER_MAX_CONNS_DEFAULT PIPE_UNLIMITED_INSTANCES + +// Windows - set security to allow non-elevated apps +// to access pipes created by elevated apps. +// Full access to everyone +const std::string DEFAULT_PIPE_SECURITY{"D:(A;;FA;;;WD)"}; + +namespace apache { +namespace thrift { +namespace transport { + +/** + * Windows Pipes implementation of TServerTransport. + * Don't destroy a TPipeServer at global scope, as that will cause a thread join + * during DLLMain. That also means that TServer's using TPipeServer shouldn't be at global + * scope. + */ +#ifdef _WIN32 +class TPipeServerImpl; +class TPipe; + +class TPipeServer : public TServerTransport { +public: + // Constructors + // Named Pipe - + TPipeServer(const std::string& pipename, uint32_t bufsize); + TPipeServer(const std::string& pipename, uint32_t bufsize, uint32_t maxconnections); + TPipeServer(const std::string& pipename, + uint32_t bufsize, + uint32_t maxconnections, + const std::string& securityDescriptor); + TPipeServer(const std::string& pipename); + // Anonymous pipe - + TPipeServer(int bufsize); + TPipeServer(); + + // Destructor + virtual ~TPipeServer(); + + bool isOpen() const override; + + // Standard transport callbacks + void interrupt() override; + void close() override; + void listen() override; + + // Accessors + std::string getPipename(); + void setPipename(const std::string& pipename); + int getBufferSize(); + void setBufferSize(int bufsize); + HANDLE getPipeHandle(); // Named Pipe R/W -or- Anonymous pipe Read handle + HANDLE getWrtPipeHandle(); + HANDLE getClientRdPipeHandle(); + HANDLE getClientWrtPipeHandle(); + bool getAnonymous(); + void setAnonymous(bool anon); + void setMaxConnections(uint32_t maxconnections); + void setSecurityDescriptor(const std::string& securityDescriptor); + + // this function is intended to be used in generic / template situations, + // so its name needs to be the same as TPipe's + HANDLE getNativeWaitHandle(); + +protected: + virtual std::shared_ptr acceptImpl(); + +private: + std::shared_ptr impl_; + + std::string pipename_; + std::string securityDescriptor_; + uint32_t bufsize_; + uint32_t maxconns_; + bool isAnonymous_; +}; +#else //_WIN32 +//*NIX named pipe implementation uses domain socket +typedef TServerSocket TPipeServer; +#endif +} +} +} // apache::thrift::transport + +#endif // #ifndef _THRIFT_TRANSPORT_TSERVERWINPIPES_H_ diff --git a/bsnes/thrift/thrift/transport/TSSLServerSocket.h b/bsnes/thrift/thrift/transport/TSSLServerSocket.h new file mode 100644 index 00000000..44df4327 --- /dev/null +++ b/bsnes/thrift/thrift/transport/TSSLServerSocket.h @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_TSSLSERVERSOCKET_H_ +#define _THRIFT_TRANSPORT_TSSLSERVERSOCKET_H_ 1 + +#include + +namespace apache { +namespace thrift { +namespace transport { + +class TSSLSocketFactory; + +/** + * Server socket that accepts SSL connections. + */ +class TSSLServerSocket : public TServerSocket { +public: + /** + * Constructor. Binds to all interfaces. + * + * @param port Listening port + * @param factory SSL socket factory implementation + */ + TSSLServerSocket(int port, std::shared_ptr factory); + + /** + * Constructor. Binds to the specified address. + * + * @param address Address to bind to + * @param port Listening port + * @param factory SSL socket factory implementation + */ + TSSLServerSocket(const std::string& address, + int port, + std::shared_ptr factory); + + /** + * Constructor. Binds to all interfaces. + * + * @param port Listening port + * @param sendTimeout Socket send timeout + * @param recvTimeout Socket receive timeout + * @param factory SSL socket factory implementation + */ + TSSLServerSocket(int port, + int sendTimeout, + int recvTimeout, + std::shared_ptr factory); + +protected: + std::shared_ptr createSocket(THRIFT_SOCKET socket) override; + std::shared_ptr factory_; +}; +} +} +} + +#endif diff --git a/bsnes/thrift/thrift/transport/TSSLSocket.h b/bsnes/thrift/thrift/transport/TSSLSocket.h new file mode 100644 index 00000000..5afc571f --- /dev/null +++ b/bsnes/thrift/thrift/transport/TSSLSocket.h @@ -0,0 +1,442 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_TSSLSOCKET_H_ +#define _THRIFT_TRANSPORT_TSSLSOCKET_H_ 1 + +// Put this first to avoid WIN32 build failure +#include + +#include +#include +#include + +namespace apache { +namespace thrift { +namespace transport { + +class AccessManager; +class SSLContext; + +enum SSLProtocol { + SSLTLS = 0, // Supports SSLv2 and SSLv3 handshake but only negotiates at TLSv1_0 or later. +//SSLv2 = 1, // HORRIBLY INSECURE! + SSLv3 = 2, // Supports SSLv3 only - also horribly insecure! + TLSv1_0 = 3, // Supports TLSv1_0 or later. + TLSv1_1 = 4, // Supports TLSv1_1 or later. + TLSv1_2 = 5, // Supports TLSv1_2 or later. + LATEST = TLSv1_2 +}; + +#define TSSL_EINTR 0 +#define TSSL_DATA 1 + +/** + * Initialize OpenSSL library. This function, or some other + * equivalent function to initialize OpenSSL, must be called before + * TSSLSocket is used. If you set TSSLSocketFactory to use manual + * OpenSSL initialization, you should call this function or otherwise + * ensure OpenSSL is initialized yourself. + */ +void initializeOpenSSL(); +/** + * Cleanup OpenSSL library. This function should be called to clean + * up OpenSSL after use of OpenSSL functionality is finished. If you + * set TSSLSocketFactory to use manual OpenSSL initialization, you + * should call this function yourself or ensure that whatever + * initialized OpenSSL cleans it up too. + */ +void cleanupOpenSSL(); + +/** + * OpenSSL implementation for SSL socket interface. + */ +class TSSLSocket : public TSocket { +public: + ~TSSLSocket() override; + /** + * TTransport interface. + */ + bool isOpen() const override; + bool peek() override; + void open() override; + void close() override; + bool hasPendingDataToRead() override; + uint32_t read(uint8_t* buf, uint32_t len) override; + void write(const uint8_t* buf, uint32_t len) override; + uint32_t write_partial(const uint8_t* buf, uint32_t len) override; + void flush() override; + /** + * Set whether to use client or server side SSL handshake protocol. + * + * @param flag Use server side handshake protocol if true. + */ + void server(bool flag) { server_ = flag; } + /** + * Determine whether the SSL socket is server or client mode. + */ + bool server() const { return server_; } + /** + * Set AccessManager. + * + * @param manager Instance of AccessManager + */ + virtual void access(std::shared_ptr manager) { access_ = manager; } + /** + * Set eventSafe flag if libevent is used. + */ + void setLibeventSafe() { eventSafe_ = true; } + /** + * Determines whether SSL Socket is libevent safe or not. + */ + bool isLibeventSafe() const { return eventSafe_; } + +protected: + /** + * Constructor. + */ + TSSLSocket(std::shared_ptr ctx, std::shared_ptr config = nullptr); + /** + * Constructor with an interrupt signal. + */ + TSSLSocket(std::shared_ptr ctx, std::shared_ptr interruptListener, + std::shared_ptr config = nullptr); + /** + * Constructor, create an instance of TSSLSocket given an existing socket. + * + * @param socket An existing socket + */ + TSSLSocket(std::shared_ptr ctx, THRIFT_SOCKET socket, std::shared_ptr config = nullptr); + /** + * Constructor, create an instance of TSSLSocket given an existing socket that can be interrupted. + * + * @param socket An existing socket + */ + TSSLSocket(std::shared_ptr ctx, THRIFT_SOCKET socket, std::shared_ptr interruptListener, + std::shared_ptr config = nullptr); + /** + * Constructor. + * + * @param host Remote host name + * @param port Remote port number + */ + TSSLSocket(std::shared_ptr ctx, std::string host, int port, std::shared_ptr config = nullptr); + /** + * Constructor with an interrupt signal. + * + * @param host Remote host name + * @param port Remote port number + */ + TSSLSocket(std::shared_ptr ctx, std::string host, int port, std::shared_ptr interruptListener, + std::shared_ptr config = nullptr); + /** + * Authorize peer access after SSL handshake completes. + */ + virtual void authorize(); + /** + * Initiate SSL handshake if not already initiated. + */ + void initializeHandshake(); + /** + * Initiate SSL handshake params. + */ + void initializeHandshakeParams(); + /** + * Check if SSL handshake is completed or not. + */ + bool checkHandshake(); + /** + * Waits for an socket or shutdown event. + * + * @throw TTransportException::INTERRUPTED if interrupted is signaled. + * + * @return TSSL_EINTR if EINTR happened on the underlying socket + * TSSL_DATA if data is available on the socket. + */ + unsigned int waitForEvent(bool wantRead); + + bool server_; + SSL* ssl_; + std::shared_ptr ctx_; + std::shared_ptr access_; + friend class TSSLSocketFactory; + +private: + bool handshakeCompleted_; + int readRetryCount_; + bool eventSafe_; + + void init(); +}; + +/** + * SSL socket factory. SSL sockets should be created via SSL factory. + * The factory will automatically initialize and cleanup openssl as long as + * there is a TSSLSocketFactory instantiated, and as long as the static + * boolean manualOpenSSLInitialization_ is set to false, the default. + * + * If you would like to initialize and cleanup openssl yourself, set + * manualOpenSSLInitialization_ to true and TSSLSocketFactory will no + * longer be responsible for openssl initialization and teardown. + * + * It is the responsibility of the code using TSSLSocketFactory to + * ensure that the factory lifetime exceeds the lifetime of any sockets + * it might create. If this is not guaranteed, a socket may call into + * openssl after the socket factory has cleaned up openssl! This + * guarantee is unnecessary if manualOpenSSLInitialization_ is true, + * however, since it would be up to the consuming application instead. + */ +class TSSLSocketFactory { +public: + /** + * Constructor/Destructor + * + * @param protocol The SSL/TLS protocol to use. + */ + TSSLSocketFactory(SSLProtocol protocol = SSLTLS); + virtual ~TSSLSocketFactory(); + /** + * Create an instance of TSSLSocket with a fresh new socket. + */ + virtual std::shared_ptr createSocket(); + /** + * Create an instance of TSSLSocket with a fresh new socket, which is interruptable. + */ + virtual std::shared_ptr createSocket(std::shared_ptr interruptListener); + /** + * Create an instance of TSSLSocket with the given socket. + * + * @param socket An existing socket. + */ + virtual std::shared_ptr createSocket(THRIFT_SOCKET socket); + /** + * Create an instance of TSSLSocket with the given socket which is interruptable. + * + * @param socket An existing socket. + */ + virtual std::shared_ptr createSocket(THRIFT_SOCKET socket, std::shared_ptr interruptListener); + /** + * Create an instance of TSSLSocket. + * + * @param host Remote host to be connected to + * @param port Remote port to be connected to + */ + virtual std::shared_ptr createSocket(const std::string& host, int port); + /** + * Create an instance of TSSLSocket. + * + * @param host Remote host to be connected to + * @param port Remote port to be connected to + */ + virtual std::shared_ptr createSocket(const std::string& host, int port, std::shared_ptr interruptListener); + /** + * Set ciphers to be used in SSL handshake process. + * + * @param ciphers A list of ciphers + */ + virtual void ciphers(const std::string& enable); + /** + * Enable/Disable authentication. + * + * @param required Require peer to present valid certificate if true + */ + virtual void authenticate(bool required); + /** + * Load server certificate. + * + * @param path Path to the certificate file + * @param format Certificate file format + */ + virtual void loadCertificate(const char* path, const char* format = "PEM"); + virtual void loadCertificateFromBuffer(const char* aCertificate, const char* format = "PEM"); + /** + * Load private key. + * + * @param path Path to the private key file + * @param format Private key file format + */ + virtual void loadPrivateKey(const char* path, const char* format = "PEM"); + virtual void loadPrivateKeyFromBuffer(const char* aPrivateKey, const char* format = "PEM"); + /** + * Load trusted certificates from specified file. + * + * @param path Path to trusted certificate file + */ + virtual void loadTrustedCertificates(const char* path, const char* capath = nullptr); + virtual void loadTrustedCertificatesFromBuffer(const char* aCertificate, const char* aChain = nullptr); + /** + * Default randomize method. + */ + virtual void randomize(); + /** + * Override default OpenSSL password callback with getPassword(). + */ + void overrideDefaultPasswordCallback(); + /** + * Set/Unset server mode. + * + * @param flag Server mode if true + */ + virtual void server(bool flag) { server_ = flag; } + /** + * Determine whether the socket is in server or client mode. + * + * @return true, if server mode, or, false, if client mode + */ + virtual bool server() const { return server_; } + /** + * Set AccessManager. + * + * @param manager The AccessManager instance + */ + virtual void access(std::shared_ptr manager) { access_ = manager; } + static void setManualOpenSSLInitialization(bool manualOpenSSLInitialization) { + manualOpenSSLInitialization_ = manualOpenSSLInitialization; + } + +protected: + std::shared_ptr ctx_; + + /** + * Override this method for custom password callback. It may be called + * multiple times at any time during a session as necessary. + * + * @param password Pass collected password to OpenSSL + * @param size Maximum length of password including NULL character + */ + virtual void getPassword(std::string& /* password */, int /* size */) {} + +private: + bool server_; + std::shared_ptr access_; + static concurrency::Mutex mutex_; + static uint64_t count_; + THRIFT_EXPORT static bool manualOpenSSLInitialization_; + void setup(std::shared_ptr ssl); + static int passwordCallback(char* password, int size, int, void* data); +}; + +/** + * SSL exception. + */ +class TSSLException : public TTransportException { +public: + TSSLException(const std::string& message) + : TTransportException(TTransportException::INTERNAL_ERROR, message) {} + + const char* what() const noexcept override { + if (message_.empty()) { + return "TSSLException"; + } else { + return message_.c_str(); + } + } +}; + +/** + * Wrap OpenSSL SSL_CTX into a class. + */ +class SSLContext { +public: + SSLContext(const SSLProtocol& protocol = SSLTLS); + virtual ~SSLContext(); + SSL* createSSL(); + SSL_CTX* get() { return ctx_; } + +private: + SSL_CTX* ctx_; +}; + +/** + * Callback interface for access control. It's meant to verify the remote host. + * It's constructed when application starts and set to TSSLSocketFactory + * instance. It's passed onto all TSSLSocket instances created by this factory + * object. + */ +class AccessManager { +public: + enum Decision { + DENY = -1, // deny access + SKIP = 0, // cannot make decision, move on to next (if any) + ALLOW = 1 // allow access + }; + /** + * Destructor + */ + virtual ~AccessManager() = default; + /** + * Determine whether the peer should be granted access or not. It's called + * once after the SSL handshake completes successfully, before peer certificate + * is examined. + * + * If a valid decision (ALLOW or DENY) is returned, the peer certificate is + * not to be verified. + * + * @param sa Peer IP address + * @return True if the peer is trusted, false otherwise + */ + virtual Decision verify(const sockaddr_storage& /* sa */) noexcept { return DENY; } + /** + * Determine whether the peer should be granted access or not. It's called + * every time a DNS subjectAltName/common name is extracted from peer's + * certificate. + * + * @param host Client mode: host name returned by TSocket::getHost() + * Server mode: host name returned by TSocket::getPeerHost() + * @param name SubjectAltName or common name extracted from peer certificate + * @param size Length of name + * @return True if the peer is trusted, false otherwise + * + * Note: The "name" parameter may be UTF8 encoded. + */ + virtual Decision verify(const std::string& /* host */, + const char* /* name */, + int /* size */) noexcept { + return DENY; + } + /** + * Determine whether the peer should be granted access or not. It's called + * every time an IP subjectAltName is extracted from peer's certificate. + * + * @param sa Peer IP address retrieved from the underlying socket + * @param data IP address extracted from certificate + * @param size Length of the IP address + * @return True if the peer is trusted, false otherwise + */ + virtual Decision verify(const sockaddr_storage& /* sa */, + const char* /* data */, + int /* size */) noexcept { + return DENY; + } +}; + +typedef AccessManager::Decision Decision; + +class DefaultClientAccessManager : public AccessManager { +public: + // AccessManager interface + Decision verify(const sockaddr_storage& sa) noexcept override; + Decision verify(const std::string& host, const char* name, int size) noexcept override; + Decision verify(const sockaddr_storage& sa, const char* data, int size) noexcept override; +}; +} +} +} + +#endif diff --git a/bsnes/thrift/thrift/transport/TServerSocket.h b/bsnes/thrift/thrift/transport/TServerSocket.h new file mode 100644 index 00000000..e4659a03 --- /dev/null +++ b/bsnes/thrift/thrift/transport/TServerSocket.h @@ -0,0 +1,174 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_TSERVERSOCKET_H_ +#define _THRIFT_TRANSPORT_TSERVERSOCKET_H_ 1 + +#include +#include +#include + +#include +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif + +namespace apache { +namespace thrift { +namespace transport { + +class TSocket; + +/** + * Server socket implementation of TServerTransport. Wrapper around a unix + * socket listen and accept calls. + * + */ +class TServerSocket : public TServerTransport { +public: + typedef std::function socket_func_t; + + const static int DEFAULT_BACKLOG = 1024; + + /** + * Constructor. + * + * @param port Port number to bind to + */ + TServerSocket(int port); + + /** + * Constructor. + * + * @param port Port number to bind to + * @param sendTimeout Socket send timeout + * @param recvTimeout Socket receive timeout + */ + TServerSocket(int port, int sendTimeout, int recvTimeout); + + /** + * Constructor. + * + * @param address Address to bind to + * @param port Port number to bind to + */ + TServerSocket(const std::string& address, int port); + + /** + * Constructor used for unix sockets. + * + * @param path Pathname for unix socket. + */ + TServerSocket(const std::string& path); + + ~TServerSocket() override; + + + bool isOpen() const override; + + void setSendTimeout(int sendTimeout); + void setRecvTimeout(int recvTimeout); + + void setAcceptTimeout(int accTimeout); + void setAcceptBacklog(int accBacklog); + + void setRetryLimit(int retryLimit); + void setRetryDelay(int retryDelay); + + void setKeepAlive(bool keepAlive) { keepAlive_ = keepAlive; } + + void setTcpSendBuffer(int tcpSendBuffer); + void setTcpRecvBuffer(int tcpRecvBuffer); + + // listenCallback gets called just before listen, and after all Thrift + // setsockopt calls have been made. If you have custom setsockopt + // things that need to happen on the listening socket, this is the place to do it. + void setListenCallback(const socket_func_t& listenCallback) { listenCallback_ = listenCallback; } + + // acceptCallback gets called after each accept call, on the newly created socket. + // It is called after all Thrift setsockopt calls have been made. If you have + // custom setsockopt things that need to happen on the accepted + // socket, this is the place to do it. + void setAcceptCallback(const socket_func_t& acceptCallback) { acceptCallback_ = acceptCallback; } + + // When enabled (the default), new children TSockets will be constructed so + // they can be interrupted by TServerTransport::interruptChildren(). + // This is more expensive in terms of system calls (poll + recv) however + // ensures a connected client cannot interfere with TServer::stop(). + // + // When disabled, TSocket children do not incur an additional poll() call. + // Server-side reads are more efficient, however a client can interfere with + // the server's ability to shutdown properly by staying connected. + // + // Must be called before listen(); mode cannot be switched after that. + // \throws std::logic_error if listen() has been called + void setInterruptableChildren(bool enable); + + THRIFT_SOCKET getSocketFD() override { return serverSocket_; } + + int getPort(); + + void listen() override; + void interrupt() override; + void interruptChildren() override; + void close() override; + +protected: + std::shared_ptr acceptImpl() override; + virtual std::shared_ptr createSocket(THRIFT_SOCKET client); + bool interruptableChildren_; + std::shared_ptr pChildInterruptSockReader_; // if interruptableChildren_ this is shared with child TSockets + +private: + void notify(THRIFT_SOCKET notifySock); + void _setup_sockopts(); + void _setup_unixdomain_sockopts(); + void _setup_tcp_sockopts(); + + int port_; + std::string address_; + std::string path_; + THRIFT_SOCKET serverSocket_; + int acceptBacklog_; + int sendTimeout_; + int recvTimeout_; + int accTimeout_; + int retryLimit_; + int retryDelay_; + int tcpSendBuffer_; + int tcpRecvBuffer_; + bool keepAlive_; + bool listening_; + + concurrency::Mutex rwMutex_; // thread-safe interrupt + THRIFT_SOCKET interruptSockWriter_; // is notified on interrupt() + THRIFT_SOCKET interruptSockReader_; // is used in select/poll with serverSocket_ for interruptability + THRIFT_SOCKET childInterruptSockWriter_; // is notified on interruptChildren() + + socket_func_t listenCallback_; + socket_func_t acceptCallback_; +}; +} +} +} // apache::thrift::transport + +#endif // #ifndef _THRIFT_TRANSPORT_TSERVERSOCKET_H_ diff --git a/bsnes/thrift/thrift/transport/TServerTransport.h b/bsnes/thrift/thrift/transport/TServerTransport.h new file mode 100644 index 00000000..0c566092 --- /dev/null +++ b/bsnes/thrift/thrift/transport/TServerTransport.h @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_TSERVERTRANSPORT_H_ +#define _THRIFT_TRANSPORT_TSERVERTRANSPORT_H_ 1 + +#include +#include + +namespace apache { +namespace thrift { +namespace transport { + +/** + * Server transport framework. A server needs to have some facility for + * creating base transports to read/write from. The server is expected + * to keep track of TTransport children that it creates for purposes of + * controlling their lifetime. + */ +class TServerTransport { +public: + virtual ~TServerTransport() = default; + + /** + * Whether this transport is open. + */ + virtual bool isOpen() const { return false; } + + /** + * Starts the server transport listening for new connections. Prior to this + * call most transports will not return anything when accept is called. + * + * @throws TTransportException if we were unable to listen + */ + virtual void listen() {} + + /** + * Gets a new dynamically allocated transport object and passes it to the + * caller. Note that it is the explicit duty of the caller to free the + * allocated object. The returned TTransport object must always be in the + * opened state. nullptr should never be returned, instead an Exception should + * always be thrown. + * + * @return A new TTransport object + * @throws TTransportException if there is an error + */ + std::shared_ptr accept() { + std::shared_ptr result = acceptImpl(); + if (!result) { + throw TTransportException("accept() may not return nullptr"); + } + return result; + } + + /** + * For "smart" TServerTransport implementations that work in a multi + * threaded context this can be used to break out of an accept() call. + * It is expected that the transport will throw a TTransportException + * with the INTERRUPTED error code. + * + * This will not make an attempt to interrupt any TTransport children. + */ + virtual void interrupt() {} + + /** + * This will interrupt the children created by the server transport. + * allowing them to break out of any blocking data reception call. + * It is expected that the children will throw a TTransportException + * with the INTERRUPTED error code. + */ + virtual void interruptChildren() {} + + /** + * Utility method + * + * @return server socket file descriptor + * @throw TTransportException If an error occurs + */ + + virtual THRIFT_SOCKET getSocketFD() { return -1; } + + /** + * Closes this transport such that future calls to accept will do nothing. + */ + virtual void close() = 0; + +protected: + TServerTransport() = default; + + /** + * Subclasses should implement this function for accept. + * + * @return A newly allocated TTransport object + * @throw TTransportException If an error occurs + */ + virtual std::shared_ptr acceptImpl() = 0; +}; +} +} +} // apache::thrift::transport + +#endif // #ifndef _THRIFT_TRANSPORT_TSERVERTRANSPORT_H_ diff --git a/bsnes/thrift/thrift/transport/TShortReadTransport.h b/bsnes/thrift/thrift/transport/TShortReadTransport.h new file mode 100644 index 00000000..c99e6a72 --- /dev/null +++ b/bsnes/thrift/thrift/transport/TShortReadTransport.h @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_TSHORTREADTRANSPORT_H_ +#define _THRIFT_TRANSPORT_TSHORTREADTRANSPORT_H_ 1 + +#include + +#include +#include + +namespace apache { +namespace thrift { +namespace transport { +namespace test { + +/** + * This class is only meant for testing. It wraps another transport. + * Calls to read are passed through with some probability. Otherwise, + * the read amount is randomly reduced before being passed through. + * + */ +class TShortReadTransport : public TVirtualTransport { +public: + TShortReadTransport(std::shared_ptr transport, double full_prob, + std::shared_ptr config = nullptr) + : TVirtualTransport(config), transport_(transport), fullProb_(full_prob) { + } + + bool isOpen() const override { return transport_->isOpen(); } + + bool peek() override { return transport_->peek(); } + + void open() override { transport_->open(); } + + void close() override { transport_->close(); } + + uint32_t read(uint8_t* buf, uint32_t len) { + checkReadBytesAvailable(len); + if (len == 0) { + return 0; + } + + if (rand() / (double)RAND_MAX >= fullProb_) { + len = 1 + rand() % len; + } + return transport_->read(buf, len); + } + + void write(const uint8_t* buf, uint32_t len) { transport_->write(buf, len); } + + void flush() override { + resetConsumedMessageSize(); + transport_->flush(); + } + + const uint8_t* borrow(uint8_t* buf, uint32_t* len) { return transport_->borrow(buf, len); } + + void consume(uint32_t len) { + countConsumedMessageBytes(len); + return transport_->consume(len); + } + + std::shared_ptr getUnderlyingTransport() { return transport_; } + +protected: + std::shared_ptr transport_; + double fullProb_; +}; +} +} +} +} // apache::thrift::transport::test + +#endif // #ifndef _THRIFT_TRANSPORT_TSHORTREADTRANSPORT_H_ diff --git a/bsnes/thrift/thrift/transport/TSimpleFileTransport.h b/bsnes/thrift/thrift/transport/TSimpleFileTransport.h new file mode 100644 index 00000000..24741b0f --- /dev/null +++ b/bsnes/thrift/thrift/transport/TSimpleFileTransport.h @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_TSIMPLEFILETRANSPORT_H_ +#define _THRIFT_TRANSPORT_TSIMPLEFILETRANSPORT_H_ 1 + +#include + +namespace apache { +namespace thrift { +namespace transport { + +/** + * Dead-simple wrapper around a file. + * + * Writeable files are opened with O_CREAT and O_APPEND + */ +class TSimpleFileTransport : public TFDTransport { +public: + TSimpleFileTransport(const std::string& path, bool read = true, bool write = false, + std::shared_ptr config = nullptr); +}; +} +} +} // apache::thrift::transport + +#endif // _THRIFT_TRANSPORT_TSIMPLEFILETRANSPORT_H_ diff --git a/bsnes/thrift/thrift/transport/TSocket.h b/bsnes/thrift/thrift/transport/TSocket.h new file mode 100644 index 00000000..8a224f2d --- /dev/null +++ b/bsnes/thrift/thrift/transport/TSocket.h @@ -0,0 +1,369 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_TSOCKET_H_ +#define _THRIFT_TRANSPORT_TSOCKET_H_ 1 + +#include + +#include +#include +#include +#include + +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif + +namespace apache { +namespace thrift { +namespace transport { + +/** + * TCP Socket implementation of the TTransport interface. + * + */ +class TSocket : public TVirtualTransport { +public: + /** + * Constructs a new socket. Note that this does NOT actually connect the + * socket. + * + */ + TSocket(std::shared_ptr config = nullptr); + + /** + * Constructs a new socket. Note that this does NOT actually connect the + * socket. + * + * @param host An IP address or hostname to connect to + * @param port The port to connect on + */ + TSocket(const std::string& host, int port, std::shared_ptr config = nullptr); + + /** + * Constructs a new Unix domain socket. + * Note that this does NOT actually connect the socket. + * + * @param path The Unix domain socket e.g. "/tmp/ThriftTest.binary.thrift" + * or a zero-prefixed string to create an abstract domain socket on Linux. + */ + TSocket(const std::string& path, std::shared_ptr config = nullptr); + + /** + * Destroyes the socket object, closing it if necessary. + */ + ~TSocket() override; + + /** + * Whether the socket is alive. + * + * @return Is the socket alive? + */ + bool isOpen() const override; + + /** + * Checks whether there is more data available in the socket to read. + * + * This call blocks until at least one byte is available or the socket is closed. + */ + bool peek() override; + + /** + * Creates and opens the UNIX socket. + * + * @throws TTransportException If the socket could not connect + */ + void open() override; + + /** + * Shuts down communications on the socket. + */ + void close() override; + + /** + * Determines whether there is pending data to read or not. + * + * This call does not block. + * \throws TTransportException of types: + * NOT_OPEN means the socket has been closed + * UNKNOWN means something unexpected happened + * \returns true if there is pending data to read, false otherwise + */ + virtual bool hasPendingDataToRead(); + + /** + * Reads from the underlying socket. + * \returns the number of bytes read or 0 indicates EOF + * \throws TTransportException of types: + * INTERRUPTED means the socket was interrupted + * out of a blocking call + * NOT_OPEN means the socket has been closed + * TIMED_OUT means the receive timeout expired + * UNKNOWN means something unexpected happened + */ + virtual uint32_t read(uint8_t* buf, uint32_t len); + + /** + * Writes to the underlying socket. Loops until done or fail. + */ + virtual void write(const uint8_t* buf, uint32_t len); + + /** + * Writes to the underlying socket. Does single send() and returns result. + */ + virtual uint32_t write_partial(const uint8_t* buf, uint32_t len); + + /** + * Get the host that the socket is connected to + * + * @return string host identifier + */ + std::string getHost(); + + /** + * Get the port that the socket is connected to + * + * @return int port number + */ + int getPort(); + + /** + * Get the Unix domain socket path that the socket is connected to + * + * @return std::string path + */ + std::string getPath(); + + /** + * Set the host that socket will connect to + * + * @param host host identifier + */ + void setHost(std::string host); + + /** + * Set the port that socket will connect to + * + * @param port port number + */ + void setPort(int port); + + /** + * Set the Unix domain socket path for the socket + * + * @param path std::string path + */ + void setPath(std::string path); + + /** + * Controls whether the linger option is set on the socket. + * + * @param on Whether SO_LINGER is on + * @param linger If linger is active, the number of seconds to linger for + */ + void setLinger(bool on, int linger); + + /** + * Whether to enable/disable Nagle's algorithm. + * + * @param noDelay Whether or not to disable the algorithm. + * @return + */ + void setNoDelay(bool noDelay); + + /** + * Set the connect timeout + */ + void setConnTimeout(int ms); + + /** + * Set the receive timeout + */ + void setRecvTimeout(int ms); + + /** + * Set the send timeout + */ + void setSendTimeout(int ms); + + /** + * Set the max number of recv retries in case of an THRIFT_EAGAIN + * error + */ + void setMaxRecvRetries(int maxRecvRetries); + + /** + * Set SO_KEEPALIVE + */ + void setKeepAlive(bool keepAlive); + + /** + * Get socket information formatted as a string + */ + std::string getSocketInfo() const; + + /** + * Returns the DNS name of the host to which the socket is connected + */ + std::string getPeerHost() const; + + /** + * Returns the address of the host to which the socket is connected + */ + std::string getPeerAddress() const; + + /** + * Returns the port of the host to which the socket is connected + **/ + int getPeerPort() const; + + /** + * Returns the underlying socket file descriptor. + */ + THRIFT_SOCKET getSocketFD() { return socket_; } + + /** + * (Re-)initialize a TSocket for the supplied descriptor. This is only + * intended for use by TNonblockingServer -- other use may result in + * unfortunate surprises. + * + * @param fd the descriptor for an already-connected socket + */ + void setSocketFD(THRIFT_SOCKET fd); + + /* + * Returns a cached copy of the peer address. + */ + sockaddr* getCachedAddress(socklen_t* len) const; + + /** + * Sets whether to use a low minimum TCP retransmission timeout. + */ + static void setUseLowMinRto(bool useLowMinRto); + + /** + * Gets whether to use a low minimum TCP retransmission timeout. + */ + static bool getUseLowMinRto(); + + /** + * Get the origin the socket is connected to + * + * @return string peer host identifier and port + */ + const std::string getOrigin() const override; + + /** + * Constructor to create socket from file descriptor. + */ + TSocket(THRIFT_SOCKET socket, std::shared_ptr config = nullptr); + + /** + * Constructor to create socket from file descriptor that + * can be interrupted safely. + */ + TSocket(THRIFT_SOCKET socket, std::shared_ptr interruptListener, + std::shared_ptr config = nullptr); + + /** + * Set a cache of the peer address (used when trivially available: e.g. + * accept() or connect()). Only caches IPV4 and IPV6; unset for others. + */ + void setCachedAddress(const sockaddr* addr, socklen_t len); + +protected: + /** connect, called by open */ + void openConnection(struct addrinfo* res); + + /** Host to connect to */ + std::string host_; + + /** Port number to connect on */ + int port_; + + /** UNIX domain socket path */ + std::string path_; + + /** Underlying socket handle */ + THRIFT_SOCKET socket_; + + /** Peer hostname */ + mutable std::string peerHost_; + + /** Peer address */ + mutable std::string peerAddress_; + + /** Peer port */ + mutable int peerPort_; + + /** + * A shared socket pointer that will interrupt a blocking read if data + * becomes available on it + */ + std::shared_ptr interruptListener_; + + /** Connect timeout in ms */ + int connTimeout_; + + /** Send timeout in ms */ + int sendTimeout_; + + /** Recv timeout in ms */ + int recvTimeout_; + + /** Keep alive on */ + bool keepAlive_; + + /** Linger on */ + bool lingerOn_; + + /** Linger val */ + int lingerVal_; + + /** Nodelay */ + bool noDelay_; + + /** Recv EGAIN retries */ + int maxRecvRetries_; + + /** Cached peer address */ + union { + sockaddr_in ipv4; + sockaddr_in6 ipv6; + } cachedPeerAddr_; + + /** Whether to use low minimum TCP retransmission timeout */ + static bool useLowMinRto_; + +private: + void unix_open(); + void local_open(); +}; +} +} +} // apache::thrift::transport + +#endif // #ifndef _THRIFT_TRANSPORT_TSOCKET_H_ diff --git a/bsnes/thrift/thrift/transport/TSocketPool.h b/bsnes/thrift/thrift/transport/TSocketPool.h new file mode 100644 index 00000000..97a2b906 --- /dev/null +++ b/bsnes/thrift/thrift/transport/TSocketPool.h @@ -0,0 +1,195 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_TSOCKETPOOL_H_ +#define _THRIFT_TRANSPORT_TSOCKETPOOL_H_ 1 + +#include +#include + +namespace apache { +namespace thrift { +namespace transport { + +/** + * Class to hold server information for TSocketPool + * + */ +class TSocketPoolServer { + +public: + /** + * Default constructor for server info + */ + TSocketPoolServer(); + + /** + * Constructor for TSocketPool server + */ + TSocketPoolServer(const std::string& host, int port); + + // Host name + std::string host_; + + // Port to connect on + int port_; + + // Socket for the server + THRIFT_SOCKET socket_; + + // Last time connecting to this server failed + time_t lastFailTime_; + + // Number of consecutive times connecting to this server failed + int consecutiveFailures_; +}; + +/** + * TCP Socket implementation of the TTransport interface. + * + */ +class TSocketPool : public TSocket { + +public: + /** + * Socket pool constructor + */ + TSocketPool(); + + /** + * Socket pool constructor + * + * @param hosts list of host names + * @param ports list of port names + */ + TSocketPool(const std::vector& hosts, const std::vector& ports); + + /** + * Socket pool constructor + * + * @param servers list of pairs of host name and port + */ + TSocketPool(const std::vector >& servers); + + /** + * Socket pool constructor + * + * @param servers list of TSocketPoolServers + */ + TSocketPool(const std::vector >& servers); + + /** + * Socket pool constructor + * + * @param host single host + * @param port single port + */ + TSocketPool(const std::string& host, int port); + + /** + * Destroyes the socket object, closing it if necessary. + */ + ~TSocketPool() override; + + /** + * Add a server to the pool + */ + void addServer(const std::string& host, int port); + + /** + * Add a server to the pool + */ + void addServer(std::shared_ptr& server); + + /** + * Set list of servers in this pool + */ + void setServers(const std::vector >& servers); + + /** + * Get list of servers in this pool + */ + void getServers(std::vector >& servers); + + /** + * Sets how many times to keep retrying a host in the connect function. + */ + void setNumRetries(int numRetries); + + /** + * Sets how long to wait until retrying a host if it was marked down + */ + void setRetryInterval(int retryInterval); + + /** + * Sets how many times to keep retrying a host before marking it as down. + */ + void setMaxConsecutiveFailures(int maxConsecutiveFailures); + + /** + * Turns randomization in connect order on or off. + */ + void setRandomize(bool randomize); + + /** + * Whether to always try the last server. + */ + void setAlwaysTryLast(bool alwaysTryLast); + + /** + * Creates and opens the UNIX socket. + */ + void open() override; + + /* + * Closes the UNIX socket + */ + void close() override; + +protected: + void setCurrentServer(const std::shared_ptr& server); + + /** List of servers to connect to */ + std::vector > servers_; + + /** Current server */ + std::shared_ptr currentServer_; + + /** How many times to retry each host in connect */ + int numRetries_; + + /** Retry interval in seconds, how long to not try a host if it has been + * marked as down. + */ + time_t retryInterval_; + + /** Max consecutive failures before marking a host down. */ + int maxConsecutiveFailures_; + + /** Try hosts in order? or Randomized? */ + bool randomize_; + + /** Always try last host, even if marked down? */ + bool alwaysTryLast_; +}; +} +} +} // apache::thrift::transport + +#endif // #ifndef _THRIFT_TRANSPORT_TSOCKETPOOL_H_ diff --git a/bsnes/thrift/thrift/transport/TSocketUtils.h b/bsnes/thrift/thrift/transport/TSocketUtils.h new file mode 100644 index 00000000..c9e0e57b --- /dev/null +++ b/bsnes/thrift/thrift/transport/TSocketUtils.h @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_SOCKETUTILS_H_ +#define _THRIFT_TRANSPORT_SOCKETUTILS_H_ 1 + +#include +#include +#include +#include + +#include +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif + +#include + +namespace apache { +namespace thrift { + +/** + * A helper to resolve hostnames to struct addrinfo's -- and not leak memory. + * + * Use like this: + * + * apache::thrift::AddressResolutionHelper addresses("localhost", "80"); + * + * for (auto addr : addresses.iterate()) { + * connect(sock, addr->ai_addr, addr->ai_addrlen); + * // ... + * } + */ +struct AddressResolutionHelper { + +private: + struct addrinfo_deleter { + void operator()(addrinfo* addr) { + ::freeaddrinfo(addr); // frees the whole list + } + }; + +public: + using PtrOwnedList = std::unique_ptr; + + struct Iter : std::iterator { + value_type ptr = nullptr; + + Iter() = default; + Iter(const addrinfo* head) : ptr(head) {} + + value_type operator*() const { return ptr; } + + bool operator==(const Iter& other) { return this->ptr == other.ptr; } + bool operator!=(const Iter& other) { return this->ptr != other.ptr; } + + operator bool() { return this->ptr != nullptr; } + bool operator!() { return this->ptr == nullptr; } + + Iter& operator++() { + if (ptr == nullptr) { + throw std::out_of_range("won't go pass end of linked list"); + } + ptr = ptr->ai_next; + return *this; + } + Iter operator++(int) { + Iter tmp(*this); + ++(*this); + return tmp; + } + }; + + struct gai_error : std::error_category { + virtual const char* name() const noexcept override { return "getaddrinfo"; } + virtual std::string message(int code) const override { return THRIFT_GAI_STRERROR(code); } + }; + +private: + PtrOwnedList gai_results; + + addrinfo* query(const std::string& host, const std::string& port, int socktype, int flags) { + addrinfo hints{}; + hints.ai_flags = flags; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = socktype; + + addrinfo* head; + int ret = ::getaddrinfo(host.empty() ? NULL : host.c_str(), port.c_str(), &hints, &head); + if (ret == 0) { + return head; +#ifdef _WIN32 + } else { + throw std::system_error{THRIFT_GET_SOCKET_ERROR, std::system_category()}; +#else + } else if (ret == EAI_SYSTEM) { + throw std::system_error{THRIFT_GET_SOCKET_ERROR, std::system_category()}; + } else { + throw std::system_error{ret, gai_error()}; +#endif + } + } + +public: + /** + * Constructor. May block. Throws errors. + * + * @param port Port number, or service name, as a string. + * @param socktype Socket type, SOCK_STREAM or SOCK_DGRAM. + * @param flags Standard getaddrinfo() flags. + */ + AddressResolutionHelper(const std::string& host, + const std::string& port, // pass "25" or "smtp" for port 25 + int socktype = SOCK_STREAM, + int flags = AI_V4MAPPED | AI_ADDRCONFIG) + : gai_results(query(host, port, socktype, flags)) {} + + AddressResolutionHelper() = default; + + /** + * Manual query. May block. Throws errors. + * + * @param port Port number, or service name, as a string. + * @param socktype Socket type, SOCK_STREAM or SOCK_DGRAM. + * @param flags Standard getaddrinfo() flags. + */ + AddressResolutionHelper& resolve(const std::string& host, + const std::string& port, // pass "25" or "smtp" for port 25 + int socktype = SOCK_STREAM, + int flags = AI_V4MAPPED | AI_ADDRCONFIG) { + gai_results.reset(query(host, port, socktype, flags)); + return *this; + } + + /** + * Return ForwardIterator to struct addrinfo* results. + */ + Iter iterate() const { return Iter{gai_results.get()}; } +}; + +} // namespace thrift +} // namespace apache + +#endif diff --git a/bsnes/thrift/thrift/transport/TTransport.h b/bsnes/thrift/thrift/transport/TTransport.h new file mode 100644 index 00000000..52b3a0a4 --- /dev/null +++ b/bsnes/thrift/thrift/transport/TTransport.h @@ -0,0 +1,357 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_TTRANSPORT_H_ +#define _THRIFT_TRANSPORT_TTRANSPORT_H_ 1 + +#include +#include +#include +#include +#include + +namespace apache { +namespace thrift { +namespace transport { + +/** + * Helper template to hoist readAll implementation out of TTransport + */ +template +uint32_t readAll(Transport_& trans, uint8_t* buf, uint32_t len) { + uint32_t have = 0; + uint32_t get = 0; + + while (have < len) { + get = trans.read(buf + have, len - have); + if (get <= 0) { + throw TTransportException(TTransportException::END_OF_FILE, "No more data to read."); + } + have += get; + } + + return have; +} + +/** + * Generic interface for a method of transporting data. A TTransport may be + * capable of either reading or writing, but not necessarily both. + * + */ +class TTransport { +public: + TTransport(std::shared_ptr config = nullptr) { + if(config == nullptr) { + configuration_ = std::shared_ptr (new TConfiguration()); + } else { + configuration_ = config; + } + resetConsumedMessageSize(); + } + + /** + * Virtual deconstructor. + */ + virtual ~TTransport() = default; + + /** + * Whether this transport is open. + */ + virtual bool isOpen() const { return false; } + + /** + * Tests whether there is more data to read or if the remote side is + * still open. By default this is true whenever the transport is open, + * but implementations should add logic to test for this condition where + * possible (i.e. on a socket). + * This is used by a server to check if it should listen for another + * request. + */ + virtual bool peek() { return isOpen(); } + + /** + * Opens the transport for communications. + * + * @return bool Whether the transport was successfully opened + * @throws TTransportException if opening failed + */ + virtual void open() { + throw TTransportException(TTransportException::NOT_OPEN, "Cannot open base TTransport."); + } + + /** + * Closes the transport. + */ + virtual void close() { + throw TTransportException(TTransportException::NOT_OPEN, "Cannot close base TTransport."); + } + + /** + * Attempt to read up to the specified number of bytes into the string. + * + * @param buf Reference to the location to write the data + * @param len How many bytes to read + * @return How many bytes were actually read + * @throws TTransportException If an error occurs + */ + uint32_t read(uint8_t* buf, uint32_t len) { + T_VIRTUAL_CALL(); + return read_virt(buf, len); + } + virtual uint32_t read_virt(uint8_t* /* buf */, uint32_t /* len */) { + throw TTransportException(TTransportException::NOT_OPEN, "Base TTransport cannot read."); + } + + /** + * Reads the given amount of data in its entirety no matter what. + * + * @param s Reference to location for read data + * @param len How many bytes to read + * @return How many bytes read, which must be equal to size + * @throws TTransportException If insufficient data was read + */ + uint32_t readAll(uint8_t* buf, uint32_t len) { + T_VIRTUAL_CALL(); + return readAll_virt(buf, len); + } + virtual uint32_t readAll_virt(uint8_t* buf, uint32_t len) { + return apache::thrift::transport::readAll(*this, buf, len); + } + + /** + * Called when read is completed. + * This can be over-ridden to perform a transport-specific action + * e.g. logging the request to a file + * + * @return number of bytes read if available, 0 otherwise. + */ + virtual uint32_t readEnd() { + // default behaviour is to do nothing + return 0; + } + + /** + * Writes the string in its entirety to the buffer. + * + * Note: You must call flush() to ensure the data is actually written, + * and available to be read back in the future. Destroying a TTransport + * object does not automatically flush pending data--if you destroy a + * TTransport object with written but unflushed data, that data may be + * discarded. + * + * @param buf The data to write out + * @throws TTransportException if an error occurs + */ + void write(const uint8_t* buf, uint32_t len) { + T_VIRTUAL_CALL(); + write_virt(buf, len); + } + virtual void write_virt(const uint8_t* /* buf */, uint32_t /* len */) { + throw TTransportException(TTransportException::NOT_OPEN, "Base TTransport cannot write."); + } + + /** + * Called when write is completed. + * This can be over-ridden to perform a transport-specific action + * at the end of a request. + * + * @return number of bytes written if available, 0 otherwise + */ + virtual uint32_t writeEnd() { + // default behaviour is to do nothing + return 0; + } + + /** + * Flushes any pending data to be written. Typically used with buffered + * transport mechanisms. + * + * @throws TTransportException if an error occurs + */ + virtual void flush() { + // default behaviour is to do nothing + } + + /** + * Attempts to return a pointer to \c len bytes, possibly copied into \c buf. + * Does not consume the bytes read (i.e.: a later read will return the same + * data). This method is meant to support protocols that need to read + * variable-length fields. They can attempt to borrow the maximum amount of + * data that they will need, then consume (see next method) what they + * actually use. Some transports will not support this method and others + * will fail occasionally, so protocols must be prepared to use read if + * borrow fails. + * + * @oaram buf A buffer where the data can be stored if needed. + * If borrow doesn't return buf, then the contents of + * buf after the call are undefined. This parameter may be + * nullptr to indicate that the caller is not supplying storage, + * but would like a pointer into an internal buffer, if + * available. + * @param len *len should initially contain the number of bytes to borrow. + * If borrow succeeds, *len will contain the number of bytes + * available in the returned pointer. This will be at least + * what was requested, but may be more if borrow returns + * a pointer to an internal buffer, rather than buf. + * If borrow fails, the contents of *len are undefined. + * @return If the borrow succeeds, return a pointer to the borrowed data. + * This might be equal to \c buf, or it might be a pointer into + * the transport's internal buffers. + * @throws TTransportException if an error occurs + */ + const uint8_t* borrow(uint8_t* buf, uint32_t* len) { + T_VIRTUAL_CALL(); + return borrow_virt(buf, len); + } + virtual const uint8_t* borrow_virt(uint8_t* /* buf */, uint32_t* /* len */) { return nullptr; } + + /** + * Remove len bytes from the transport. This should always follow a borrow + * of at least len bytes, and should always succeed. + * TODO(dreiss): Is there any transport that could borrow but fail to + * consume, or that would require a buffer to dump the consumed data? + * + * @param len How many bytes to consume + * @throws TTransportException If an error occurs + */ + void consume(uint32_t len) { + T_VIRTUAL_CALL(); + consume_virt(len); + } + virtual void consume_virt(uint32_t /* len */) { + throw TTransportException(TTransportException::NOT_OPEN, "Base TTransport cannot consume."); + } + + /** + * Returns the origin of the transports call. The value depends on the + * transport used. An IP based transport for example will return the + * IP address of the client making the request. + * If the transport doesn't know the origin Unknown is returned. + * + * The returned value can be used in a log message for example + */ + virtual const std::string getOrigin() const { return "Unknown"; } + + std::shared_ptr getConfiguration() { return configuration_; } + + void setConfiguration(std::shared_ptr config) { + if (config != nullptr) configuration_ = config; + } + + /** + * Updates RemainingMessageSize to reflect then known real message size (e.g. framed transport). + * Will throw if we already consumed too many bytes or if the new size is larger than allowed. + * + * @param size real message size + */ + void updateKnownMessageSize(long int size) + { + long int consumed = knownMessageSize_ - remainingMessageSize_; + resetConsumedMessageSize(size); + countConsumedMessageBytes(consumed); + } + + /** + * Throws if there are not enough bytes in the input stream to satisfy a read of numBytes bytes of data + * + * @param numBytes numBytes bytes of data + */ + void checkReadBytesAvailable(long int numBytes) + { + if (remainingMessageSize_ < numBytes) + throw TTransportException(TTransportException::END_OF_FILE, "MaxMessageSize reached"); + } + +protected: + std::shared_ptr configuration_; + long int remainingMessageSize_; + long int knownMessageSize_; + + inline long int getRemainingMessageSize() { return remainingMessageSize_; } + inline void setRemainingMessageSize(long int remainingMessageSize) { remainingMessageSize_ = remainingMessageSize; } + inline int getMaxMessageSize() { return configuration_->getMaxMessageSize(); } + inline long int getKnownMessageSize() { return knownMessageSize_; } + void setKnownMessageSize(long int knownMessageSize) { knownMessageSize_ = knownMessageSize; } + + /** + * Resets RemainingMessageSize to the configured maximum + * + * @param newSize configured size + */ + void resetConsumedMessageSize(long newSize = -1) + { + // full reset + if (newSize < 0) + { + knownMessageSize_ = getMaxMessageSize(); + remainingMessageSize_ = getMaxMessageSize(); + return; + } + + // update only: message size can shrink, but not grow + if (newSize > knownMessageSize_) + throw TTransportException(TTransportException::END_OF_FILE, "MaxMessageSize reached"); + + knownMessageSize_ = newSize; + remainingMessageSize_ = newSize; + } + + /** + * Consumes numBytes from the RemainingMessageSize. + * + * @param numBytes Consumes numBytes + */ + void countConsumedMessageBytes(long int numBytes) + { + if (remainingMessageSize_ >= numBytes) + { + remainingMessageSize_ -= numBytes; + } + else + { + remainingMessageSize_ = 0; + throw TTransportException(TTransportException::END_OF_FILE, "MaxMessageSize reached"); + } + } +}; + +/** + * Generic factory class to make an input and output transport out of a + * source transport. Commonly used inside servers to make input and output + * streams out of raw clients. + * + */ +class TTransportFactory { +public: + TTransportFactory() = default; + + virtual ~TTransportFactory() = default; + + /** + * Default implementation does nothing, just returns the transport given. + */ + virtual std::shared_ptr getTransport(std::shared_ptr trans) { + return trans; + } +}; +} +} +} // apache::thrift::transport + +#endif // #ifndef _THRIFT_TRANSPORT_TTRANSPORT_H_ diff --git a/bsnes/thrift/thrift/transport/TTransportException.h b/bsnes/thrift/thrift/transport/TTransportException.h new file mode 100644 index 00000000..dd5f361f --- /dev/null +++ b/bsnes/thrift/thrift/transport/TTransportException.h @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_TTRANSPORTEXCEPTION_H_ +#define _THRIFT_TRANSPORT_TTRANSPORTEXCEPTION_H_ 1 + +#include +#include +#include + +namespace apache { +namespace thrift { +namespace transport { + +/** + * Class to encapsulate all the possible types of transport errors that may + * occur in various transport systems. This provides a sort of generic + * wrapper around the vague UNIX E_ error codes that lets a common code + * base of error handling to be used for various types of transports, i.e. + * pipes etc. + * + */ +class TTransportException : public apache::thrift::TException { +public: + /** + * Error codes for the various types of exceptions. + */ + enum TTransportExceptionType { + UNKNOWN = 0, + NOT_OPEN = 1, + TIMED_OUT = 2, + END_OF_FILE = 3, + INTERRUPTED = 4, + BAD_ARGS = 5, + CORRUPTED_DATA = 6, + INTERNAL_ERROR = 7, + CLIENT_DISCONNECT = 8 + }; + + TTransportException() : apache::thrift::TException(), type_(UNKNOWN) {} + + TTransportException(TTransportExceptionType type) : apache::thrift::TException(), type_(type) {} + + TTransportException(const std::string& message) + : apache::thrift::TException(message), type_(UNKNOWN) {} + + TTransportException(TTransportExceptionType type, const std::string& message) + : apache::thrift::TException(message), type_(type) {} + + TTransportException(TTransportExceptionType type, const std::string& message, int errno_copy) + : apache::thrift::TException(message + ": " + TOutput::strerror_s(errno_copy)), type_(type) {} + + ~TTransportException() noexcept override = default; + + /** + * Returns an error code that provides information about the type of error + * that has occurred. + * + * @return Error code + */ + TTransportExceptionType getType() const noexcept { return type_; } + + const char* what() const noexcept override; + +protected: + /** Just like strerror_r but returns a C++ string object. */ + std::string strerror_s(int errno_copy); + + /** Error code */ + TTransportExceptionType type_; +}; + +/** + * Legacy code in transport implementations have overflow issues + * that need to be enforced. + */ +template To safe_numeric_cast(From i) { + try { + return boost::numeric_cast(i); + } + catch (const std::bad_cast& bc) { + throw TTransportException(TTransportException::CORRUPTED_DATA, + bc.what()); + } +} + +} +} +} // apache::thrift::transport + +#endif // #ifndef _THRIFT_TRANSPORT_TTRANSPORTEXCEPTION_H_ diff --git a/bsnes/thrift/thrift/transport/TTransportUtils.h b/bsnes/thrift/thrift/transport/TTransportUtils.h new file mode 100644 index 00000000..68c25f4c --- /dev/null +++ b/bsnes/thrift/thrift/transport/TTransportUtils.h @@ -0,0 +1,319 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_TTRANSPORTUTILS_H_ +#define _THRIFT_TRANSPORT_TTRANSPORTUTILS_H_ 1 + +#include +#include +#include +#include +#include +// Include the buffered transports that used to be defined here. +#include +#include + +namespace apache { +namespace thrift { +namespace transport { + +/** + * The null transport is a dummy transport that doesn't actually do anything. + * It's sort of an analogy to /dev/null, you can never read anything from it + * and it will let you write anything you want to it, though it won't actually + * go anywhere. + * + */ +class TNullTransport : public TVirtualTransport { +public: + TNullTransport() = default; + + ~TNullTransport() override = default; + + bool isOpen() const override { return true; } + + void open() override {} + + void write(const uint8_t* /* buf */, uint32_t /* len */) { return; } +}; + +/** + * TPipedTransport. This transport allows piping of a request from one + * transport to another either when readEnd() or writeEnd(). The typical + * use case for this is to log a request or a reply to disk. + * The underlying buffer expands to a keep a copy of the entire + * request/response. + * + */ +class TPipedTransport : virtual public TTransport { +public: + TPipedTransport(std::shared_ptr srcTrans, std::shared_ptr dstTrans, + std::shared_ptr config = nullptr) + : TTransport(config), + srcTrans_(srcTrans), + dstTrans_(dstTrans), + rBufSize_(512), + rPos_(0), + rLen_(0), + wBufSize_(512), + wLen_(0) { + + // default is to to pipe the request when readEnd() is called + pipeOnRead_ = true; + pipeOnWrite_ = false; + + rBuf_ = (uint8_t*)std::malloc(sizeof(uint8_t) * rBufSize_); + if (rBuf_ == nullptr) { + throw std::bad_alloc(); + } + wBuf_ = (uint8_t*)std::malloc(sizeof(uint8_t) * wBufSize_); + if (wBuf_ == nullptr) { + throw std::bad_alloc(); + } + } + + TPipedTransport(std::shared_ptr srcTrans, + std::shared_ptr dstTrans, + uint32_t sz, + std::shared_ptr config = nullptr) + : TTransport(config), + srcTrans_(srcTrans), + dstTrans_(dstTrans), + rBufSize_(512), + rPos_(0), + rLen_(0), + wBufSize_(sz), + wLen_(0) { + + rBuf_ = (uint8_t*)std::malloc(sizeof(uint8_t) * rBufSize_); + if (rBuf_ == nullptr) { + throw std::bad_alloc(); + } + wBuf_ = (uint8_t*)std::malloc(sizeof(uint8_t) * wBufSize_); + if (wBuf_ == nullptr) { + throw std::bad_alloc(); + } + } + + ~TPipedTransport() override { + std::free(rBuf_); + std::free(wBuf_); + } + + bool isOpen() const override { return srcTrans_->isOpen(); } + + bool peek() override { + if (rPos_ >= rLen_) { + // Double the size of the underlying buffer if it is full + if (rLen_ == rBufSize_) { + rBufSize_ *= 2; + auto * tmpBuf = (uint8_t*)std::realloc(rBuf_, sizeof(uint8_t) * rBufSize_); + if (tmpBuf == nullptr) { + throw std::bad_alloc(); + } + rBuf_ = tmpBuf; + } + + // try to fill up the buffer + rLen_ += srcTrans_->read(rBuf_ + rPos_, rBufSize_ - rPos_); + } + return (rLen_ > rPos_); + } + + void open() override { srcTrans_->open(); } + + void close() override { srcTrans_->close(); } + + void setPipeOnRead(bool pipeVal) { pipeOnRead_ = pipeVal; } + + void setPipeOnWrite(bool pipeVal) { pipeOnWrite_ = pipeVal; } + + uint32_t read(uint8_t* buf, uint32_t len); + + uint32_t readEnd() override { + + if (pipeOnRead_) { + dstTrans_->write(rBuf_, rPos_); + dstTrans_->flush(); + } + + srcTrans_->readEnd(); + + // If requests are being pipelined, copy down our read-ahead data, + // then reset our state. + int read_ahead = rLen_ - rPos_; + uint32_t bytes = rPos_; + memcpy(rBuf_, rBuf_ + rPos_, read_ahead); + rPos_ = 0; + rLen_ = read_ahead; + + return bytes; + } + + void write(const uint8_t* buf, uint32_t len); + + uint32_t writeEnd() override { + if (pipeOnWrite_) { + dstTrans_->write(wBuf_, wLen_); + dstTrans_->flush(); + } + return wLen_; + } + + void flush() override; + + std::shared_ptr getTargetTransport() { return dstTrans_; } + + /* + * Override TTransport *_virt() functions to invoke our implementations. + * We cannot use TVirtualTransport to provide these, since we need to inherit + * virtually from TTransport. + */ + uint32_t read_virt(uint8_t* buf, uint32_t len) override { return this->read(buf, len); } + void write_virt(const uint8_t* buf, uint32_t len) override { this->write(buf, len); } + +protected: + std::shared_ptr srcTrans_; + std::shared_ptr dstTrans_; + + uint8_t* rBuf_; + uint32_t rBufSize_; + uint32_t rPos_; + uint32_t rLen_; + + uint8_t* wBuf_; + uint32_t wBufSize_; + uint32_t wLen_; + + bool pipeOnRead_; + bool pipeOnWrite_; +}; + +/** + * Wraps a transport into a pipedTransport instance. + * + */ +class TPipedTransportFactory : public TTransportFactory { +public: + TPipedTransportFactory() = default; + TPipedTransportFactory(std::shared_ptr dstTrans) { + initializeTargetTransport(dstTrans); + } + ~TPipedTransportFactory() override = default; + + /** + * Wraps the base transport into a piped transport. + */ + std::shared_ptr getTransport(std::shared_ptr srcTrans) override { + return std::shared_ptr(new TPipedTransport(srcTrans, dstTrans_)); + } + + virtual void initializeTargetTransport(std::shared_ptr dstTrans) { + if (dstTrans_.get() == nullptr) { + dstTrans_ = dstTrans; + } else { + throw TException("Target transport already initialized"); + } + } + +protected: + std::shared_ptr dstTrans_; +}; + +/** + * TPipedFileTransport. This is just like a TTransport, except that + * it is a templatized class, so that clients who rely on a specific + * TTransport can still access the original transport. + * + */ +class TPipedFileReaderTransport : public TPipedTransport, public TFileReaderTransport { +public: + TPipedFileReaderTransport(std::shared_ptr srcTrans, + std::shared_ptr dstTrans, + std::shared_ptr config = nullptr); + + ~TPipedFileReaderTransport() override; + + // TTransport functions + bool isOpen() const override; + bool peek() override; + void open() override; + void close() override; + uint32_t read(uint8_t* buf, uint32_t len); + uint32_t readAll(uint8_t* buf, uint32_t len); + uint32_t readEnd() override; + void write(const uint8_t* buf, uint32_t len); + uint32_t writeEnd() override; + void flush() override; + + // TFileReaderTransport functions + int32_t getReadTimeout() override; + void setReadTimeout(int32_t readTimeout) override; + uint32_t getNumChunks() override; + uint32_t getCurChunk() override; + void seekToChunk(int32_t chunk) override; + void seekToEnd() override; + + /* + * Override TTransport *_virt() functions to invoke our implementations. + * We cannot use TVirtualTransport to provide these, since we need to inherit + * virtually from TTransport. + */ + uint32_t read_virt(uint8_t* buf, uint32_t len) override { return this->read(buf, len); } + uint32_t readAll_virt(uint8_t* buf, uint32_t len) override { return this->readAll(buf, len); } + void write_virt(const uint8_t* buf, uint32_t len) override { this->write(buf, len); } + +protected: + // shouldn't be used + TPipedFileReaderTransport(); + std::shared_ptr srcTrans_; +}; + +/** + * Creates a TPipedFileReaderTransport from a filepath and a destination transport + * + */ +class TPipedFileReaderTransportFactory : public TPipedTransportFactory { +public: + TPipedFileReaderTransportFactory() = default; + TPipedFileReaderTransportFactory(std::shared_ptr dstTrans) + : TPipedTransportFactory(dstTrans) {} + ~TPipedFileReaderTransportFactory() override = default; + + std::shared_ptr getTransport(std::shared_ptr srcTrans) override { + std::shared_ptr pFileReaderTransport + = std::dynamic_pointer_cast(srcTrans); + if (pFileReaderTransport.get() != nullptr) { + return getFileReaderTransport(pFileReaderTransport); + } else { + return std::shared_ptr(); + } + } + + std::shared_ptr getFileReaderTransport( + std::shared_ptr srcTrans) { + return std::shared_ptr( + new TPipedFileReaderTransport(srcTrans, dstTrans_)); + } +}; +} +} +} // apache::thrift::transport + +#endif // #ifndef _THRIFT_TRANSPORT_TTRANSPORTUTILS_H_ diff --git a/bsnes/thrift/thrift/transport/TVirtualTransport.h b/bsnes/thrift/thrift/transport/TVirtualTransport.h new file mode 100644 index 00000000..44bfa131 --- /dev/null +++ b/bsnes/thrift/thrift/transport/TVirtualTransport.h @@ -0,0 +1,140 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_TVIRTUALTRANSPORT_H_ +#define _THRIFT_TRANSPORT_TVIRTUALTRANSPORT_H_ 1 + +#include + +namespace apache { +namespace thrift { +namespace transport { + +/** + * Helper class that provides default implementations of TTransport methods. + * + * This class provides default implementations of read(), readAll(), write(), + * borrow() and consume(). + * + * In the TTransport base class, each of these methods simply invokes its + * virtual counterpart. This class overrides them to always perform the + * default behavior, without a virtual function call. + * + * The primary purpose of this class is to serve as a base class for + * TVirtualTransport, and prevent infinite recursion if one of its subclasses + * does not override the TTransport implementation of these methods. (Since + * TVirtualTransport::read_virt() calls read(), and TTransport::read() calls + * read_virt().) + */ +class TTransportDefaults : public TTransport { +public: + /* + * TTransport *_virt() methods provide reasonable default implementations. + * Invoke them non-virtually. + */ + uint32_t read(uint8_t* buf, uint32_t len) { return this->TTransport::read_virt(buf, len); } + uint32_t readAll(uint8_t* buf, uint32_t len) { return this->TTransport::readAll_virt(buf, len); } + void write(const uint8_t* buf, uint32_t len) { this->TTransport::write_virt(buf, len); } + const uint8_t* borrow(uint8_t* buf, uint32_t* len) { + return this->TTransport::borrow_virt(buf, len); + } + void consume(uint32_t len) { this->TTransport::consume_virt(len); } + +protected: + TTransportDefaults(std::shared_ptr config = nullptr) : TTransport(config) {} +}; + +/** + * Helper class to provide polymorphism for subclasses of TTransport. + * + * This class implements *_virt() methods of TTransport, to call the + * non-virtual versions of these functions in the proper subclass. + * + * To define your own transport class using TVirtualTransport: + * 1) Derive your subclass from TVirtualTransport + * e.g: class MyTransport : public TVirtualTransport { + * 2) Provide your own implementations of read(), readAll(), etc. + * These methods should be non-virtual. + * + * Transport implementations that need to use virtual inheritance when + * inheriting from TTransport cannot use TVirtualTransport. + * + * @author Chad Walters + */ +template +class TVirtualTransport : public Super_ { +public: + /* + * Implementations of the *_virt() functions, to call the subclass's + * non-virtual implementation function. + */ + uint32_t read_virt(uint8_t* buf, uint32_t len) override { + return static_cast(this)->read(buf, len); + } + + uint32_t readAll_virt(uint8_t* buf, uint32_t len) override { + return static_cast(this)->readAll(buf, len); + } + + void write_virt(const uint8_t* buf, uint32_t len) override { + static_cast(this)->write(buf, len); + } + + const uint8_t* borrow_virt(uint8_t* buf, uint32_t* len) override { + return static_cast(this)->borrow(buf, len); + } + + void consume_virt(uint32_t len) override { static_cast(this)->consume(len); } + + /* + * Provide a default readAll() implementation that invokes + * read() non-virtually. + * + * Note: subclasses that use TVirtualTransport to derive from another + * transport implementation (i.e., not TTransportDefaults) should beware that + * this may override any non-default readAll() implementation provided by + * the parent transport class. They may need to redefine readAll() to call + * the correct parent implementation, if desired. + */ + uint32_t readAll(uint8_t* buf, uint32_t len) { + auto* trans = static_cast(this); + return ::apache::thrift::transport::readAll(*trans, buf, len); + } + +protected: + TVirtualTransport() : Super_() {} + + /* + * Templatized constructors, to allow arguments to be passed to the Super_ + * constructor. Currently we only support 0, 1, or 2 arguments, but + * additional versions can be added as needed. + */ + template + TVirtualTransport(Arg_ const& arg) + : Super_(arg) {} + + template + TVirtualTransport(Arg1_ const& a1, Arg2_ const& a2) + : Super_(a1, a2) {} +}; +} +} +} // apache::thrift::transport + +#endif // #ifndef _THRIFT_TRANSPORT_TVIRTUALTRANSPORT_H_ diff --git a/bsnes/thrift/thrift/transport/TZlibTransport.h b/bsnes/thrift/thrift/transport/TZlibTransport.h new file mode 100644 index 00000000..85765e6b --- /dev/null +++ b/bsnes/thrift/thrift/transport/TZlibTransport.h @@ -0,0 +1,251 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_TZLIBTRANSPORT_H_ +#define _THRIFT_TRANSPORT_TZLIBTRANSPORT_H_ 1 + +#include +#include +#include +#include + +struct z_stream_s; + +namespace apache { +namespace thrift { +namespace transport { + +class TZlibTransportException : public TTransportException { +public: + TZlibTransportException(int status, const char* msg) + : TTransportException(TTransportException::INTERNAL_ERROR, errorMessage(status, msg)), + zlib_status_(status), + zlib_msg_(msg == nullptr ? "(null)" : msg) {} + + ~TZlibTransportException() noexcept override = default; + + int getZlibStatus() { return zlib_status_; } + std::string getZlibMessage() { return zlib_msg_; } + + static std::string errorMessage(int status, const char* msg) { + std::string rv = "zlib error: "; + if (msg) { + rv += msg; + } else { + rv += "(no message)"; + } + rv += " (status = "; + rv += to_string(status); + rv += ")"; + return rv; + } + + int zlib_status_; + std::string zlib_msg_; +}; + +/** + * This transport uses zlib to compress on write and decompress on read + * + * TODO(dreiss): Don't do an extra copy of the compressed data if + * the underlying transport is TBuffered or TMemory. + * + */ +class TZlibTransport : public TVirtualTransport { +public: + /** + * @param transport The transport to read compressed data from + * and write compressed data to. + * @param urbuf_size Uncompressed buffer size for reading. + * @param crbuf_size Compressed buffer size for reading. + * @param uwbuf_size Uncompressed buffer size for writing. + * @param cwbuf_size Compressed buffer size for writing. + * @param comp_level Compression level (0=none[fast], 6=default, 9=max[slow]). + */ + TZlibTransport(std::shared_ptr transport, + int urbuf_size = DEFAULT_URBUF_SIZE, + int crbuf_size = DEFAULT_CRBUF_SIZE, + int uwbuf_size = DEFAULT_UWBUF_SIZE, + int cwbuf_size = DEFAULT_CWBUF_SIZE, + int16_t comp_level = Z_DEFAULT_COMPRESSION, + std::shared_ptr config = nullptr) + : TVirtualTransport(config), + transport_(transport), + urpos_(0), + uwpos_(0), + input_ended_(false), + output_finished_(false), + urbuf_size_(urbuf_size), + crbuf_size_(crbuf_size), + uwbuf_size_(uwbuf_size), + cwbuf_size_(cwbuf_size), + urbuf_(nullptr), + crbuf_(nullptr), + uwbuf_(nullptr), + cwbuf_(nullptr), + rstream_(nullptr), + wstream_(nullptr), + comp_level_(comp_level) { + if (uwbuf_size_ < MIN_DIRECT_DEFLATE_SIZE) { + // Have to copy this into a local because of a linking issue. + int minimum = MIN_DIRECT_DEFLATE_SIZE; + throw TTransportException(TTransportException::BAD_ARGS, + "TZLibTransport: uncompressed write buffer must be at least" + + to_string(minimum) + "."); + } + + try { + urbuf_ = new uint8_t[urbuf_size]; + crbuf_ = new uint8_t[crbuf_size]; + uwbuf_ = new uint8_t[uwbuf_size]; + cwbuf_ = new uint8_t[cwbuf_size]; + + // Don't call this outside of the constructor. + initZlib(); + + } catch (...) { + delete[] urbuf_; + delete[] crbuf_; + delete[] uwbuf_; + delete[] cwbuf_; + throw; + } + } + + // Don't call this outside of the constructor. + void initZlib(); + + /** + * TZlibTransport destructor. + * + * Warning: Destroying a TZlibTransport object may discard any written but + * unflushed data. You must explicitly call flush() or finish() to ensure + * that data is actually written and flushed to the underlying transport. + */ + ~TZlibTransport() override; + + bool isOpen() const override; + bool peek() override; + + void open() override { transport_->open(); } + + void close() override { transport_->close(); } + + uint32_t read(uint8_t* buf, uint32_t len); + + void write(const uint8_t* buf, uint32_t len); + + void flush() override; + + /** + * Finalize the zlib stream. + * + * This causes zlib to flush any pending write data and write end-of-stream + * information, including the checksum. Once finish() has been called, no + * new data can be written to the stream. + */ + void finish(); + + const uint8_t* borrow(uint8_t* buf, uint32_t* len); + + void consume(uint32_t len); + + /** + * Verify the checksum at the end of the zlib stream. + * + * This may only be called after all data has been read. + * It verifies the checksum that was written by the finish() call. + */ + void verifyChecksum(); + + /** + * TODO(someone_smart): Choose smart defaults. + */ + static const int DEFAULT_URBUF_SIZE = 128; + static const int DEFAULT_CRBUF_SIZE = 1024; + static const int DEFAULT_UWBUF_SIZE = 128; + static const int DEFAULT_CWBUF_SIZE = 1024; + + std::shared_ptr getUnderlyingTransport() const { return transport_; } + +protected: + inline void checkZlibRv(int status, const char* msg); + inline void checkZlibRvNothrow(int status, const char* msg); + inline int readAvail() const; + void flushToTransport(int flush); + void flushToZlib(const uint8_t* buf, int len, int flush); + bool readFromZlib(); + +protected: + // Writes smaller than this are buffered up. + // Larger (or equal) writes are dumped straight to zlib. + static const uint32_t MIN_DIRECT_DEFLATE_SIZE = 32; + + std::shared_ptr transport_; + + int urpos_; + int uwpos_; + + /// True iff zlib has reached the end of the input stream. + bool input_ended_; + /// True iff we have finished the output stream. + bool output_finished_; + + uint32_t urbuf_size_; + uint32_t crbuf_size_; + uint32_t uwbuf_size_; + uint32_t cwbuf_size_; + + uint8_t* urbuf_; + uint8_t* crbuf_; + uint8_t* uwbuf_; + uint8_t* cwbuf_; + + struct z_stream_s* rstream_; + struct z_stream_s* wstream_; + + const int comp_level_; +}; + +/** + * Wraps a transport into a zlibbed one. + * + */ +class TZlibTransportFactory : public TTransportFactory { +public: + TZlibTransportFactory() = default; + + /** + * Wraps a transport factory into a zlibbed one. + */ + TZlibTransportFactory(std::shared_ptr transportFactory); + + ~TZlibTransportFactory() override = default; + + std::shared_ptr getTransport(std::shared_ptr trans) override; + +protected: + std::shared_ptr transportFactory_; +}; + +} +} +} // apache::thrift::transport + +#endif // #ifndef _THRIFT_TRANSPORT_TZLIBTRANSPORT_H_ diff --git a/bsnes/thrift/thrift/windows/GetTimeOfDay.h b/bsnes/thrift/thrift/windows/GetTimeOfDay.h new file mode 100644 index 00000000..762ac5e2 --- /dev/null +++ b/bsnes/thrift/thrift/windows/GetTimeOfDay.h @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_WINDOWS_GETTIMEOFDAY_H_ +#define _THRIFT_WINDOWS_GETTIMEOFDAY_H_ + +#if defined(_MSC_VER) && (_MSC_VER > 1200) +#pragma once +#endif // _MSC_VER + +#ifndef _WIN32 +#error This is a MSVC header only. +#endif + +#include +#include + +struct thrift_timespec { + int64_t tv_sec; + int64_t tv_nsec; +}; + +int thrift_gettimeofday(struct timeval* tv, struct timezone* tz); +int thrift_sleep(unsigned int seconds); +int thrift_usleep(unsigned int micro_seconds); +char* thrift_ctime_r(const time_t* _clock, char* _buf); + +#endif // _THRIFT_WINDOWS_GETTIMEOFDAY_H_ diff --git a/bsnes/thrift/thrift/windows/Operators.h b/bsnes/thrift/thrift/windows/Operators.h new file mode 100644 index 00000000..9b860968 --- /dev/null +++ b/bsnes/thrift/thrift/windows/Operators.h @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_WINDOWS_OPERATORS_H_ +#define _THRIFT_WINDOWS_OPERATORS_H_ + +#if defined(_MSC_VER) && (_MSC_VER > 1200) +#pragma once +#endif // _MSC_VER + +namespace apache { +namespace thrift { + +class TEnumIterator; + +inline bool operator==(const TEnumIterator&, const TEnumIterator&) { + // Not entirely sure what the test should be here. It is only to enable + // iterator debugging and is not used in release mode. + return true; +} +} +} // apache::thrift + +#endif // _THRIFT_WINDOWS_OPERATORS_H_ diff --git a/bsnes/thrift/thrift/windows/OverlappedSubmissionThread.h b/bsnes/thrift/thrift/windows/OverlappedSubmissionThread.h new file mode 100644 index 00000000..dd0c5c95 --- /dev/null +++ b/bsnes/thrift/thrift/windows/OverlappedSubmissionThread.h @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_WINDOWS_OverlappedSubmissionThread_H_ +#define _THRIFT_WINDOWS_OverlappedSubmissionThread_H_ 1 + +#ifndef _WIN32 +#error "OverlappedSubmissionThread.h is only usable on Windows" +#endif + +#include +#include +#include + +/* + *** Why does this class exist? + In short, because we want to enable something similar to a "select" loop, on Windows, with + named pipes. The core of the "select" loop is a call to WaitForMultipleObjects. So that means + we need a signalable object that indicates when data is available. + + A pipe handle doesn't do that. A pipe handle is signaled when a read or write completes, and if + no one has called read or write, then the pipe handle is useless in WaitForMultipleObjects. So + instead, we use overlapped I/O. With overlapped I/O, you call read, and associate an event with + the read. When the read finishes, the event is signaled. This means that when you create a pipe, + you start a read. When the customer calls read on your transport object, you wait for the last + read to finish, and then kick off another. + + There is one big caveat to this though. The thread that initiated the read must stay alive. If + the thread that initiated the read exits, then the read completes in an error state. To ensure + that the initiating thread stays alive, we create a singleton thread whose sole responsibility is + to manage this overlapped I/O requests. This introduces some overhead, but it is overhead that + is necessary for correct behavior. + + This thread currently supports connect, read, and cancel io. So far, I haven't needed to put any + writes on this thread, but if needed, it could be done. The client write buffer would need to be + copied to ensure that it doesn't get invalidated. + + *** How does one use this class? + Create a TOverlappedWorkItem, and fill in the action and "h", then call reset(). Your work item + is now ready to be submitted to the overlapped submission thread. Create a TAutoOverlapThread, + and call thread->addWorkItem with your work item. After addWorkItem completes, you may inspect + last_error and success. At some point in the future, call workItem.overlappedResults to wait + until the operation has completed. +*/ + +namespace apache { +namespace thrift { +namespace transport { + +struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) TOverlappedWorkItem : public SLIST_ENTRY { + TOverlappedWorkItem(); + + enum action_t { + UNKNOWN = 3000, + CONNECT, + READ, + CANCELIO, + STOP, + }; + + TAutoResetEvent doneSubmittingEvent; + action_t action; + HANDLE h; + uint8_t* buffer; + uint32_t buffer_len; + OVERLAPPED overlap; + + DWORD last_error; + BOOL success; + + void reset(uint8_t* buf, uint32_t len, HANDLE event); + uint32_t overlappedResults(bool signal_failure = true); + bool process(); +}; + +class TOverlappedSubmissionThread : boost::noncopyable { +public: + void addWorkItem(TOverlappedWorkItem* item); + + // singleton stuff +public: + static TOverlappedSubmissionThread* acquire_instance(); + static void release_instance(); + +private: + static TCriticalSection instanceGuard_; + static TOverlappedSubmissionThread* instance_; + static uint32_t instanceRefCount_; + + // thread details +private: + TOverlappedSubmissionThread(); + ~TOverlappedSubmissionThread(); + void run(); + static unsigned __stdcall thread_proc(void* addr); + +private: + DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) SLIST_HEADER workList_; + TOverlappedWorkItem stopItem_; + TAutoResetEvent workAvailableEvent_; + HANDLE thread_; +}; + +class TAutoOverlapThread : boost::noncopyable { +private: + TOverlappedSubmissionThread* p; + +public: + TAutoOverlapThread() : p(TOverlappedSubmissionThread::acquire_instance()) {} + ~TAutoOverlapThread() { TOverlappedSubmissionThread::release_instance(); } + TOverlappedSubmissionThread* operator->() { return p; } +}; +} +} +} // apache::thrift::transport + +#endif diff --git a/bsnes/thrift/thrift/windows/SocketPair.h b/bsnes/thrift/thrift/windows/SocketPair.h new file mode 100644 index 00000000..86bf4315 --- /dev/null +++ b/bsnes/thrift/thrift/windows/SocketPair.h @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_WINDOWS_SOCKETPAIR_H_ +#define _THRIFT_WINDOWS_SOCKETPAIR_H_ 1 + +#if defined(_MSC_VER) && (_MSC_VER > 1200) +#pragma once +#endif // _MSC_VER + +#ifndef _WIN32 +#error This is a MSVC header only. +#endif + +// Win32 +#include +#include + +int thrift_socketpair(int d, int type, int protocol, THRIFT_SOCKET sv[2]); + +#endif // _THRIFT_WINDOWS_SOCKETPAIR_H_ diff --git a/bsnes/thrift/thrift/windows/Sync.h b/bsnes/thrift/thrift/windows/Sync.h new file mode 100644 index 00000000..a296d7ec --- /dev/null +++ b/bsnes/thrift/thrift/windows/Sync.h @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_WINDOWS_Sync_H_ +#define _THRIFT_WINDOWS_Sync_H_ 1 + +#ifndef _WIN32 +#error "windows/Sync.h is only usable on Windows" +#endif + +#include +#include +#include + +/* + Lightweight synchronization objects that only make sense on Windows. For cross-platform + code, use the classes found in the concurrency namespace +*/ + +namespace apache { +namespace thrift { + +struct TCriticalSection : boost::noncopyable { + CRITICAL_SECTION cs; + TCriticalSection() { InitializeCriticalSection(&cs); } + ~TCriticalSection() { DeleteCriticalSection(&cs); } +}; + +class TAutoCrit : boost::noncopyable { +private: + CRITICAL_SECTION* cs_; + +public: + explicit TAutoCrit(TCriticalSection& cs) : cs_(&cs.cs) { EnterCriticalSection(cs_); } + ~TAutoCrit() { LeaveCriticalSection(cs_); } +}; + +struct TAutoResetEvent : boost::noncopyable { + HANDLE h; + + TAutoResetEvent() { + h = CreateEvent(nullptr, FALSE, FALSE, nullptr); + if (h == nullptr) { + GlobalOutput.perror("TAutoResetEvent unable to create event, GLE=", GetLastError()); + throw apache::thrift::concurrency::SystemResourceException("CreateEvent failed"); + } + } + ~TAutoResetEvent() { CloseHandle(h); } +}; + +struct TManualResetEvent : boost::noncopyable { + HANDLE h; + + TManualResetEvent() { + h = CreateEvent(nullptr, TRUE, FALSE, nullptr); + if (h == nullptr) { + GlobalOutput.perror("TManualResetEvent unable to create event, GLE=", GetLastError()); + throw apache::thrift::concurrency::SystemResourceException("CreateEvent failed"); + } + } + ~TManualResetEvent() { CloseHandle(h); } +}; + +struct TAutoHandle : boost::noncopyable { + HANDLE h; + explicit TAutoHandle(HANDLE h_ = INVALID_HANDLE_VALUE) : h(h_) {} + ~TAutoHandle() { + if (h != INVALID_HANDLE_VALUE) + CloseHandle(h); + } + + HANDLE release() { + HANDLE retval = h; + h = INVALID_HANDLE_VALUE; + return retval; + } + void reset(HANDLE h_ = INVALID_HANDLE_VALUE) { + if (h_ == h) + return; + if (h != INVALID_HANDLE_VALUE) + CloseHandle(h); + h = h_; + } +}; +} +} // apache::thrift + +#endif diff --git a/bsnes/thrift/thrift/windows/TWinsockSingleton.h b/bsnes/thrift/thrift/windows/TWinsockSingleton.h new file mode 100644 index 00000000..a30806b9 --- /dev/null +++ b/bsnes/thrift/thrift/windows/TWinsockSingleton.h @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_TRANSPORT_WINDOWS_TWINSOCKSINGLETON_H_ +#define _THRIFT_TRANSPORT_WINDOWS_TWINSOCKSINGLETON_H_ 1 + +#if defined(_MSC_VER) && (_MSC_VER > 1200) +#pragma once +#endif // _MSC_VER + +#ifndef _WIN32 +#error This is a MSVC header only. +#endif + +#include + +// boost +#include + +#include +#include + + +namespace apache { +namespace thrift { +namespace transport { + +/** + * Winsock2 must be intialised once only in order to create sockets. This class + * performs a one time initialisation when create is called. + */ +class TWinsockSingleton : private boost::noncopyable { + +public: + typedef std::shared_ptr instance_ptr; + +private: + TWinsockSingleton(void); + +public: + ~TWinsockSingleton(void); + +public: + static void create(void); + +private: + static void init(void); + +private: + static instance_ptr instance_ptr_; + static std::once_flag flags_; +}; +} +} +} // apache::thrift::transport + +#endif // _THRIFT_TRANSPORT_WINDOWS_TWINSOCKSINGLETON_H_ diff --git a/bsnes/thrift/thrift/windows/WinFcntl.h b/bsnes/thrift/thrift/windows/WinFcntl.h new file mode 100644 index 00000000..4816fc5e --- /dev/null +++ b/bsnes/thrift/thrift/windows/WinFcntl.h @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_WINDOWS_FCNTL_H_ +#define _THRIFT_WINDOWS_FCNTL_H_ 1 + +#if defined(_MSC_VER) && (_MSC_VER > 1200) +#pragma once +#endif // _MSC_VER + +#ifndef _WIN32 +#error This is a MSVC header only. +#endif + +#ifdef _WIN32_WCE +#include +#endif + +// Win32 +#include +#include + +extern "C" { +int thrift_fcntl(THRIFT_SOCKET fd, int cmd, int flags); +} + +#ifdef _WIN32_WCE +std::string thrift_wstr2str(std::wstring ws); +#endif + +#endif // _THRIFT_WINDOWS_FCNTL_H_ diff --git a/bsnes/thrift/thrift/windows/config.h b/bsnes/thrift/thrift/windows/config.h new file mode 100644 index 00000000..a218d908 --- /dev/null +++ b/bsnes/thrift/thrift/windows/config.h @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _THRIFT_WINDOWS_CONFIG_H_ +#define _THRIFT_WINDOWS_CONFIG_H_ 1 + +#if defined(_MSC_VER) && (_MSC_VER > 1200) +#pragma once +#endif // _MSC_VER + +#ifndef _WIN32 +#error "This is a Windows header only" +#endif + +// Something that defines PRId64 is required to build +#define HAVE_INTTYPES_H 1 + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0601 +#endif + +#if defined(_M_IX86) || defined(_M_X64) +#define ARITHMETIC_RIGHT_SHIFT 1 +#define SIGNED_RIGHT_SHIFT_IS 1 +#endif + +#ifndef __MINGW32__ +#pragma warning(disable : 4996) // Deprecated posix name. +#endif + +#define HAVE_GETTIMEOFDAY 1 +#define HAVE_SYS_STAT_H 1 + +#include + +#include +#include +#include +#include +#include +#include + +// windows +#include +#include +#ifndef __MINGW32__ + #ifdef _WIN32_WCE + #pragma comment(lib, "Ws2.lib") + #else + #pragma comment(lib, "Ws2_32.lib") + #pragma comment(lib, "gdi32.lib") // For static OpenSSL + #pragma comment(lib, "crypt32.lib") // For static OpenSSL + #pragma comment(lib, "user32.lib") // For static OpenSSL + #pragma comment(lib, "advapi32.lib") // For security APIs in TPipeServer + #pragma comment(lib, "Shlwapi.lib") // For StrStrIA in TPipeServer + #endif +#endif // __MINGW32__ + +#endif // _THRIFT_WINDOWS_CONFIG_H_ diff --git a/bsnes/thrift/thrift_32.lib b/bsnes/thrift/thrift_32.lib new file mode 100644 index 00000000..aa860ae3 Binary files /dev/null and b/bsnes/thrift/thrift_32.lib differ diff --git a/bsnes/thrift/thrift_64.lib b/bsnes/thrift/thrift_64.lib new file mode 100644 index 00000000..c455e472 Binary files /dev/null and b/bsnes/thrift/thrift_64.lib differ diff --git a/bsnes/thrift/thriftd_32.lib b/bsnes/thrift/thriftd_32.lib new file mode 100644 index 00000000..af6fb782 Binary files /dev/null and b/bsnes/thrift/thriftd_32.lib differ diff --git a/bsnes/thrift/thriftd_64.lib b/bsnes/thrift/thriftd_64.lib new file mode 100644 index 00000000..42c9c5fc Binary files /dev/null and b/bsnes/thrift/thriftd_64.lib differ diff --git a/bsnes/thrift/thriftnb_32.lib b/bsnes/thrift/thriftnb_32.lib new file mode 100644 index 00000000..9453bb6e Binary files /dev/null and b/bsnes/thrift/thriftnb_32.lib differ diff --git a/bsnes/thrift/thriftnb_64.lib b/bsnes/thrift/thriftnb_64.lib new file mode 100644 index 00000000..33c08c9d Binary files /dev/null and b/bsnes/thrift/thriftnb_64.lib differ diff --git a/bsnes/thrift/thriftnbd_32.lib b/bsnes/thrift/thriftnbd_32.lib new file mode 100644 index 00000000..f48b6b73 Binary files /dev/null and b/bsnes/thrift/thriftnbd_32.lib differ diff --git a/bsnes/thrift/thriftnbd_64.lib b/bsnes/thrift/thriftnbd_64.lib new file mode 100644 index 00000000..182c970c Binary files /dev/null and b/bsnes/thrift/thriftnbd_64.lib differ diff --git a/bsnes/ui-qt/application/application.cpp b/bsnes/ui-qt/application/application.cpp index f2276482..af49900d 100644 --- a/bsnes/ui-qt/application/application.cpp +++ b/bsnes/ui-qt/application/application.cpp @@ -159,7 +159,7 @@ int Application::main(int &argc, char **argv) { config().load(configFilename); mapper().bind(); init(); - SNES::system.init(&interface); + SNES::system.init(&intf); mainWindow->system_loadSpecial_superGameBoy->setVisible(SNES::supergameboy.opened()); parseArguments(); diff --git a/bsnes/ui-qt/base/main.cpp b/bsnes/ui-qt/base/main.cpp index 98f03c21..8d940df1 100644 --- a/bsnes/ui-qt/base/main.cpp +++ b/bsnes/ui-qt/base/main.cpp @@ -615,12 +615,12 @@ void MainWindow::recordMovieFromHere() { void MainWindow::saveScreenshot() { //tell SNES::Interface to save a screenshot at the next video_refresh() event - interface.saveScreenshot = true; + intf.saveScreenshot = true; } void MainWindow::saveSPC() { //tell the S-SMP core to save a SPC after the next note-on - interface.captureSPC(); + intf.captureSPC(); } void MainWindow::loadState() { diff --git a/bsnes/ui-qt/cartridge/cartridge.cpp b/bsnes/ui-qt/cartridge/cartridge.cpp index 5e6a31c1..08022971 100644 --- a/bsnes/ui-qt/cartridge/cartridge.cpp +++ b/bsnes/ui-qt/cartridge/cartridge.cpp @@ -115,6 +115,11 @@ bool Cartridge::loadNormal(const char *base) { application.currentRom = base; utility.modifySystemState(Utility::LoadCartridge); + + extern void init_dbg_server(); + // init remote debugger here + init_dbg_server(); + return true; } diff --git a/bsnes/ui-qt/debugger/debugger.cpp b/bsnes/ui-qt/debugger/debugger.cpp index bccee4a0..20b415e0 100644 --- a/bsnes/ui-qt/debugger/debugger.cpp +++ b/bsnes/ui-qt/debugger/debugger.cpp @@ -465,7 +465,7 @@ void Debugger::clear() { void Debugger::switchWindow() { // give focus to the main window if needed so that emulation can continue if(config().input.focusPolicy == Configuration::Input::FocusPolicyPauseEmulation) { - mainWindow->activateWindow(); + //mainWindow->activateWindow(); } } @@ -473,7 +473,7 @@ void Debugger::toggleRunStatus() { application.debug = !application.debug || application.debugrun; application.debugrun = false; if(!application.debug) { - mainWindow->activateWindow(); + //mainWindow->activateWindow(); } else { audio.clear(); } @@ -686,8 +686,8 @@ void Debugger::event() { audio.clear(); autoUpdate(); - show(); - activateWindow(); + showMinimized(); + //activateWindow(); } // update "auto refresh" tool windows diff --git a/bsnes/ui-qt/debugger/ppu/oam-data-model.cpp b/bsnes/ui-qt/debugger/ppu/oam-data-model.cpp index ceef528b..4714f8e8 100644 --- a/bsnes/ui-qt/debugger/ppu/oam-data-model.cpp +++ b/bsnes/ui-qt/debugger/ppu/oam-data-model.cpp @@ -36,7 +36,7 @@ OamDataModel::OamDataModel(QObject* parent) { assert(COLUMN_STRINGS.size() == N_COLUMNS); assert(FLIP_STRINGS.size() == 4); - assert(OBJECT_SIZE_TABLE == N_OAM_BASE_SIZES); + assert(OBJECT_SIZE_TABLE.size() == N_OAM_BASE_SIZES); for(OamObject& obj : mOamObjects) { obj.visible = true; diff --git a/bsnes/ui-qt/debugger/ppu/oam-data-model.moc.hpp b/bsnes/ui-qt/debugger/ppu/oam-data-model.moc.hpp index 1a778ce8..c2d6bb8a 100644 --- a/bsnes/ui-qt/debugger/ppu/oam-data-model.moc.hpp +++ b/bsnes/ui-qt/debugger/ppu/oam-data-model.moc.hpp @@ -1,3 +1,4 @@ +#undef small struct OamObject { signed xpos; diff --git a/bsnes/ui-qt/debugger/remote_debugger.cpp b/bsnes/ui-qt/debugger/remote_debugger.cpp new file mode 100644 index 00000000..ed631ce8 --- /dev/null +++ b/bsnes/ui-qt/debugger/remote_debugger.cpp @@ -0,0 +1,274 @@ +#include "gen-cpp/IdaClient.h" +#include "gen-cpp/BsnesDebugger.h" +#include +#include +#include +#include +#include +#include + +using namespace ::apache::thrift; +using namespace ::apache::thrift::protocol; +using namespace ::apache::thrift::transport; +using namespace ::apache::thrift::server; +using namespace ::apache::thrift::concurrency; + +#include "../ui-base.hpp" + +static ::std::shared_ptr client; +static ::std::shared_ptr srv; +static ::std::shared_ptr cli_transport; + +static ::std::mutex list_mutex; +::std::set visited; + +static void send_visited(bool is_step) { + const auto part = visited.size(); + + ::std::lock_guard<::std::mutex> lock(list_mutex); + + try { + if (client) { + client->add_visited(visited, is_step); + } + } + catch (...) { + + } + + visited.clear(); +} + +static void stop_client() { + try { + if (client) { + send_visited(false); + client->stop_event(); + } + cli_transport->close(); + } + catch (...) { + + } +} + +static void init_ida_client() { + ::std::shared_ptr socket(new TSocket("127.0.0.1", 9091)); + cli_transport = ::std::shared_ptr(new TFramedTransport(socket)); + ::std::shared_ptr protocol(new TBinaryProtocol(cli_transport)); + client = ::std::shared_ptr(new IdaClientClient(protocol)); + + while (true) { + try { + cli_transport->open(); + break; + } + catch (...) { + Sleep(10); + } + } + + atexit(stop_client); +} + +static void toggle_pause(bool enable) { + application.debug = enable; + application.debugrun = enable; + + if (enable) { + audio.clear(); + } +} + +class BsnesDebuggerHandler : virtual public BsnesDebuggerIf { + +public: + int32_t get_cpu_reg(const BsnesRegister::type reg) override { + switch (reg) { + case BsnesRegister::pc: + case BsnesRegister::a: + case BsnesRegister::x: + case BsnesRegister::y: + case BsnesRegister::s: + case BsnesRegister::d: + case BsnesRegister::db: + case BsnesRegister::p: + return SNES::cpu.getRegister((SNES::CPUDebugger::Register)reg); + case BsnesRegister::mflag: + return (SNES::cpu.usage[SNES::cpu.regs.pc] & SNES::CPUDebugger::UsageFlagM) ? 1 : 0; + case BsnesRegister::xflag: + return (SNES::cpu.usage[SNES::cpu.regs.pc] & SNES::CPUDebugger::UsageFlagX) ? 1 : 0; + case BsnesRegister::eflag: + return (SNES::cpu.usage[SNES::cpu.regs.pc] & SNES::CPUDebugger::UsageFlagE) ? 1 : 0; + } + } + + + void get_cpu_regs(BsnesRegisters& _return) override { + _return.pc = SNES::cpu.getRegister(SNES::CPUDebugger::Register::RegisterPC); + _return.a = SNES::cpu.getRegister(SNES::CPUDebugger::Register::RegisterA); + _return.x = SNES::cpu.getRegister(SNES::CPUDebugger::Register::RegisterX); + _return.y = SNES::cpu.getRegister(SNES::CPUDebugger::Register::RegisterY); + _return.s = SNES::cpu.getRegister(SNES::CPUDebugger::Register::RegisterS); + _return.d = SNES::cpu.getRegister(SNES::CPUDebugger::Register::RegisterD); + _return.db = SNES::cpu.getRegister(SNES::CPUDebugger::Register::RegisterDB); + _return.p = SNES::cpu.getRegister(SNES::CPUDebugger::Register::RegisterP); + + _return.mflag = (SNES::cpu.usage[SNES::cpu.regs.pc] & SNES::CPUDebugger::UsageFlagM) ? 1 : 0; + _return.xflag = (SNES::cpu.usage[SNES::cpu.regs.pc] & SNES::CPUDebugger::UsageFlagX) ? 1 : 0; + _return.eflag = (SNES::cpu.usage[SNES::cpu.regs.pc] & SNES::CPUDebugger::UsageFlagE) ? 1 : 0; + } + + + void set_cpu_reg(const BsnesRegister::type reg, const int32_t value) override { + switch (reg) { + case BsnesRegister::pc: + case BsnesRegister::a: + case BsnesRegister::x: + case BsnesRegister::y: + case BsnesRegister::s: + case BsnesRegister::d: + case BsnesRegister::db: + case BsnesRegister::p: + SNES::cpu.setRegister((SNES::CPUDebugger::Register)reg, value); + } + } + + void add_breakpoint(const DbgBreakpoint& bpt) override { + SNES::Debugger::Breakpoint add; + add.addr = bpt.bstart; + add.addr_end = bpt.bend; + add.mode = bpt.type; + add.source = (SNES::Debugger::Breakpoint::Source)bpt.src; + SNES::debugger.breakpoint.append(add); + } + + + void del_breakpoint(const DbgBreakpoint& bpt) override { + for (auto i = 0; i < SNES::debugger.breakpoint.size(); ++i) { + auto b = SNES::debugger.breakpoint[i]; + + if (b.source == (SNES::Debugger::Breakpoint::Source)bpt.src && b.addr == bpt.bstart && b.addr_end == bpt.bend && b.mode == bpt.type) { + SNES::debugger.breakpoint.remove(i); + break; + } + } + } + + + void read_memory(std::string& _return, const DbgMemorySource::type src, const int32_t address, const int32_t size) override { + _return.clear(); + + SNES::debugger.bus_access = true; + for (auto i = 0; i < size; ++i) { + _return += SNES::debugger.read((SNES::Debugger::MemorySource)src, address + i); + } + SNES::debugger.bus_access = false; + } + + + void write_memory(const DbgMemorySource::type src, const int32_t address, const std::string& data) override { + SNES::debugger.bus_access = true; + for (auto i = 0; i < data.size(); ++i) { + SNES::debugger.write((SNES::Debugger::MemorySource)src, address, data[i]); + } + SNES::debugger.bus_access = false; + } + + + void exit_emulation() override { + try { + if (client) { + send_visited(false); + client->stop_event(); + } + } + catch (...) { + + } + + application.app->exit(); + } + + + void pause() override { + step_into(); + } + + + void resume() override { + toggle_pause(false); + } + + + void start_emulation() override { + init_ida_client(); + + try { + if (client) { + client->start_event(); + visited.clear(); + client->pause_event(SNES::cpu.getRegister(SNES::CPUDebugger::RegisterPC)); + } + } + catch (...) { + + } + } + + + void step_into() override { + SNES::debugger.step_type = SNES::Debugger::StepType::StepInto; + application.debugrun = true; + + SNES::debugger.step_cpu = true; + } + + + void step_over() override { + SNES::debugger.step_type = SNES::Debugger::StepType::StepOver; + SNES::debugger.step_over_new = true; + SNES::debugger.call_count = 0; + application.debugrun = true; + + SNES::debugger.step_cpu = true; + } + +}; + +static void stop_server() { + srv->stop(); +} + +void init_dbg_server() { + ::std::shared_ptr handler(new BsnesDebuggerHandler()); + ::std::shared_ptr processor(new BsnesDebuggerProcessor(handler)); + ::std::shared_ptr serverTransport(new TNonblockingServerSocket(9090)); + ::std::shared_ptr transportFactory(new TFramedTransportFactory()); + ::std::shared_ptr protocolFactory(new TBinaryProtocolFactory()); + + srv = ::std::shared_ptr(new TNonblockingServer(processor, protocolFactory, serverTransport)); + ::std::shared_ptr tf(new ThreadFactory()); + ::std::shared_ptr thread = tf->newThread(srv); + thread->start(); + + atexit(stop_server); + + SNES::debugger.breakpoint.reset(); + + SNES::debugger.step_type = SNES::Debugger::StepType::StepInto; + application.debugrun = true; + SNES::debugger.step_cpu = true; +} + +void send_pause_event(bool is_step) { + try { + if (client) { + client->pause_event(SNES::cpu.getRegister(SNES::CPUDebugger::RegisterPC)); + send_visited(is_step); + } + } + catch (...) { + + } +} \ No newline at end of file diff --git a/bsnes/ui-qt/input/userinterface-general.cpp b/bsnes/ui-qt/input/userinterface-general.cpp index f1f6fefc..d63ee2e1 100644 --- a/bsnes/ui-qt/input/userinterface-general.cpp +++ b/bsnes/ui-qt/input/userinterface-general.cpp @@ -46,10 +46,10 @@ struct ToggleCheatSystem : HotkeyInput { struct CaptureScreenshot : HotkeyInput { void pressed() { //tell SNES::Interface to save a screenshot at the next video_refresh() event - interface.saveScreenshot = true; + intf.saveScreenshot = true; } - CaptureScreenshot() : HotkeyInput("Capture Screenshot", "input.userInterface.general.captureScreenshot") { + CaptureScreenshot() : HotkeyInput("Capture Screenshot", "input.userintf.general.captureScreenshot") { userInterfaceGeneral.attach(this); } } captureScreenshot; @@ -57,7 +57,7 @@ struct CaptureScreenshot : HotkeyInput { struct CaptureSPC : HotkeyInput { void pressed() { //tell the S-SMP core to save a SPC after the next note-on - interface.captureSPC(); + intf.captureSPC(); } CaptureSPC() : HotkeyInput("Capture SPC Dump", "input.userInterface.general.captureSPC") { diff --git a/bsnes/ui-qt/interface.cpp b/bsnes/ui-qt/interface.cpp index 722138f0..7432faba 100644 --- a/bsnes/ui-qt/interface.cpp +++ b/bsnes/ui-qt/interface.cpp @@ -1,4 +1,4 @@ -Interface interface; +Interface intf; void Interface::video_extras(uint16_t *data, unsigned width, unsigned height) { if (music.loaded()) music.render((uint16_t*)data, 1024, width, height); diff --git a/bsnes/ui-qt/interface.hpp b/bsnes/ui-qt/interface.hpp index 6c1f6080..de047ccc 100644 --- a/bsnes/ui-qt/interface.hpp +++ b/bsnes/ui-qt/interface.hpp @@ -15,4 +15,4 @@ class Interface : public SNES::Interface { unsigned framesExecuted; }; -extern Interface interface; +extern Interface intf; diff --git a/bsnes/ui-qt/main.cpp b/bsnes/ui-qt/main.cpp index d3ef63ae..fa66e115 100644 --- a/bsnes/ui-qt/main.cpp +++ b/bsnes/ui-qt/main.cpp @@ -38,3 +38,7 @@ const char defaultStylesheet[] = int main(int argc, char **argv) { return application.main(argc, argv); } + +#pragma comment(linker,"\"/manifestdependency:type='win32' \ +name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \ +processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") diff --git a/bsnes/ui-qt/resource/resource.rc b/bsnes/ui-qt/resource/resource.rc index 63dfef44..3a7b7db5 100644 --- a/bsnes/ui-qt/resource/resource.rc +++ b/bsnes/ui-qt/resource/resource.rc @@ -1,2 +1,2 @@ -1 24 "data/bsnes.Manifest" +//1 24 "data/bsnes.Manifest" IDI_ICON1 ICON DISCARDABLE "data/bsnes.ico" diff --git a/bsnes/ui-qt/utility/utility.cpp b/bsnes/ui-qt/utility/utility.cpp index 9c1863c3..28e07606 100644 --- a/bsnes/ui-qt/utility/utility.cpp +++ b/bsnes/ui-qt/utility/utility.cpp @@ -30,9 +30,9 @@ void Utility::updateSystemState() { text = "Power off"; } else if(application.pause == true || application.autopause == true) { text = "Paused"; - } else if(interface.framesUpdated == true) { - interface.framesUpdated = false; - text << interface.framesExecuted; + } else if(intf.framesUpdated == true) { + intf.framesUpdated = false; + text << intf.framesExecuted; text << " fps"; } else { //nothing to update diff --git a/bsnes/vstudio/bsnes/bsnes.sln b/bsnes/vstudio/bsnes/bsnes.sln new file mode 100644 index 00000000..f70260b3 --- /dev/null +++ b/bsnes/vstudio/bsnes/bsnes.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30517.126 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bsnes", "bsnes.vcxproj", "{42D864F9-AFDA-4EF7-99C3-218E982AA46E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "snesida", "..\..\Snesida\snesida.vcxproj", "{C89C7CCD-A6DA-4364-A7DA-8092983FB9A5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug-Accuracy|x64 = Debug-Accuracy|x64 + Release-Accuracy|x64 = Release-Accuracy|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {42D864F9-AFDA-4EF7-99C3-218E982AA46E}.Debug-Accuracy|x64.ActiveCfg = Debug-Accuracy|x64 + {42D864F9-AFDA-4EF7-99C3-218E982AA46E}.Debug-Accuracy|x64.Build.0 = Debug-Accuracy|x64 + {42D864F9-AFDA-4EF7-99C3-218E982AA46E}.Release-Accuracy|x64.ActiveCfg = Release-Accuracy|x64 + {42D864F9-AFDA-4EF7-99C3-218E982AA46E}.Release-Accuracy|x64.Build.0 = Release-Accuracy|x64 + {C89C7CCD-A6DA-4364-A7DA-8092983FB9A5}.Debug-Accuracy|x64.ActiveCfg = Debug|x64 + {C89C7CCD-A6DA-4364-A7DA-8092983FB9A5}.Debug-Accuracy|x64.Build.0 = Debug|x64 + {C89C7CCD-A6DA-4364-A7DA-8092983FB9A5}.Release-Accuracy|x64.ActiveCfg = Release|x64 + {C89C7CCD-A6DA-4364-A7DA-8092983FB9A5}.Release-Accuracy|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {79215649-444D-4FCC-97DD-3CD012E031FA} + EndGlobalSection +EndGlobal diff --git a/bsnes/vstudio/bsnes/bsnes.vcxproj b/bsnes/vstudio/bsnes/bsnes.vcxproj new file mode 100644 index 00000000..5ddd7ffc --- /dev/null +++ b/bsnes/vstudio/bsnes/bsnes.vcxproj @@ -0,0 +1,1610 @@ + + + + + Debug-Accuracy + x64 + + + Release-Accuracy + x64 + + + + 16.0 + Win32Proj + {42d864f9-afda-4ef7-99c3-218e982aa46e} + bsnes + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + false + Unicode + + + + + + + + + + + + + + + true + c:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Include;$(IncludePath) + $(ProjectName)-$(Configuration) + + + false + c:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Include;$(IncludePath) + $(ProjectName)-$(Configuration) + + + + Level3 + _CRT_SECURE_NO_WARNINGS;DEBUGGER;VIDEO_DIRECT3D;AUDIO_DIRECTSOUND;INPUT_DIRECTINPUT;PROFILE_ACCURACY;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(QTDIR)\include;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtWidgets;../../;../../snes/;../../ui-qt/debugger/tools/qhexedit2/;../../ui-qt/resource/;../../../common/;../../../common/nall/qt/;../../thrift/;../../thrift/libevent/include/;C:/local/boost_1_75_0/;%(AdditionalIncludeDirectories) + MultiThreadedDebug + 4267;4018;4244 + true + + + Console + true + c:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Lib\x64;$(QTDIR)\lib;%(AdditionalLibraryDirectories);../../thrift/;../../thrift/libevent/lib/ + D3d9.lib;Dsound.lib;Dinput8.lib;Dxguid.lib;thriftd_$(PlatformArchitecture).lib;thriftnbd_$(PlatformArchitecture).lib;event_$(PlatformArchitecture).lib;Iphlpapi.lib;Qt5Cored.lib;Qt5Guid.lib;Qt5Widgetsd.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + _CRT_SECURE_NO_WARNINGS;DEBUGGER;VIDEO_DIRECT3D;AUDIO_DIRECTSOUND;INPUT_DIRECTINPUT;PROFILE_ACCURACY;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(QTDIR)\include;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtWidgets;../../;../../snes/;../../ui-qt/debugger/tools/qhexedit2/;../../ui-qt/resource/;../../../common/;../../../common/nall/qt/;../../thrift/;../../thrift/libevent/include/;C:/local/boost_1_75_0/;%(AdditionalIncludeDirectories) + MultiThreaded + true + + + Console + true + c:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Lib\x64;$(QTDIR)\lib;%(AdditionalLibraryDirectories);../../thrift/;../../thrift/libevent/lib/ + D3d9.lib;Dsound.lib;Dinput8.lib;Dxguid.lib;thrift_$(PlatformArchitecture).lib;thriftnb_$(PlatformArchitecture).lib;event_$(PlatformArchitecture).lib;Iphlpapi.lib;Qt5Core.lib;Qt5Gui.lib;Qt5Widgets.lib;%(AdditionalDependencies) + true + true + + + + + + + + + + + + + + true + true + + + + true + true + + + true + true + + + true + true + + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + $(IntDir)/%(RelativeDir)/ + $(IntDir)/%(RelativeDir)/ + + + true + true + + + true + true + + + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + + true + true + + + true + true + + + true + true + + + + true + true + + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + + true + true + + + + true + true + + + true + true + + + + true + true + + + true + true + + + true + true + + + + true + true + + + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + + true + true + + + true + true + + + true + true + + + + true + true + + + true + true + + + $(IntDir)/%(RelativeDir)/ + $(IntDir)/%(RelativeDir)/ + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + $(IntDir)/%(RelativeDir)/ + $(IntDir)/%(RelativeDir)/ + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + + true + true + + + true + true + + + true + true + + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + $(IntDir)/%(RelativeDir)/ + $(IntDir)/%(RelativeDir)/ + + + true + true + + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + + true + true + + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + + true + true + + + true + true + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + true + + + true + true + + + + + + + + + + + + + + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + + + + + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + + + + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + + + + + + + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + + + %(RootDir)%(Directory)%(Filename);%(Outputs) + %(RootDir)%(Directory)%(Filename);%(Outputs) + Compiling %(Filename)%(Extension) using MOC + Compiling %(Filename)%(Extension) using MOC + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + $(QTDIR)\bin\moc.exe -i "%(FullPath)" -o "%(RootDir)%(Directory)%(Filename)" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Document + $(QTDIR)\bin\rcc.exe %(FullPath) -o %(RootDir)%(Directory)%(Filename).rcc + $(QTDIR)\bin\rcc.exe %(FullPath) -o %(RootDir)%(Directory)%(Filename).rcc + Compiling %(Filename)%(Extension) using RCC + Compiling %(Filename)%(Extension) using RCC + %(RootDir)%(Directory)%(Filename).rcc;%(Outputs) + %(RootDir)%(Directory)%(Filename).rcc;%(Outputs) + + + + + + + + + + ../../;%(AdditionalIncludeDirectories) + ../../;%(AdditionalIncludeDirectories) + + + + + + \ No newline at end of file diff --git a/bsnes/vstudio/bsnes/bsnes.vcxproj.filters b/bsnes/vstudio/bsnes/bsnes.vcxproj.filters new file mode 100644 index 00000000..74d524a0 --- /dev/null +++ b/bsnes/vstudio/bsnes/bsnes.vcxproj.filters @@ -0,0 +1,1886 @@ + + + + + {acd77031-02f8-49a2-bbf1-25c69facfcdd} + + + {70cea245-a73f-408e-b43d-4577fe26a4cb} + + + {626fcbc7-09f9-489b-928a-685320937ccf} + + + {fd4f25dc-2534-4e88-b17f-1a5b7bc84fe4} + + + {e8362c26-2292-4e08-bdaf-b31cb577811a} + + + {3c14ee14-c3b0-4c7e-bd61-7b01730c0919} + + + {18258502-b1ec-4df4-b32d-33b55955f64b} + + + {2c51348c-ac6a-4b5d-b515-46b912f63e58} + + + {cad0ee95-7364-428e-9699-bdb4a1754d6d} + + + {1798fb10-d931-4e41-92c9-64a3222c4ae0} + + + {3c91d563-1ab8-4df1-b7f2-6dfc2c0f3f40} + + + {f6bbb465-9106-4729-8e7f-8e527f5c0e11} + + + {48b91aa9-cf7f-490b-9d0e-516c34129c0e} + + + {57ac3a6e-4010-486a-ad41-1c195df9bd01} + + + {601b8ef2-a300-4eba-98d8-a15212df8613} + + + {d3974109-0028-4b92-ba84-6305f5a0b690} + + + {a8e9772a-0d1c-4ad6-8168-ac1a1d427c62} + + + {30b00000-dd79-49a1-a059-9852e52163ee} + + + {c23fc12a-cae5-4e7a-a5b4-e6a988bffcee} + + + {b87146bf-127f-4f16-87a9-280a1ab3a66c} + + + {eac77925-d76a-487f-b3f4-729f3292e12c} + + + {d65eebe3-05f6-47dd-b0ae-099836f3ffdc} + + + {1df7a165-809e-434d-bb91-052511536cb0} + + + {921bd4f7-a76a-464d-98de-d7c6f93092d3} + + + {03dc6de4-65e9-4e22-beea-9af350968971} + + + {14025810-8974-4e7e-a374-5d3ee2480fb5} + + + {8a2970cb-c9b4-41bb-8bc3-1c5e0535d6ae} + + + {86944617-8e1f-4081-9503-ee657549b12c} + + + {2d81073c-06f4-466f-ac20-c93bcc846eae} + + + {f74e47c9-7c62-4b46-b02f-3770ea8d4a6b} + + + {e1fc50dd-72ef-44ed-a758-b2b0c3251b6e} + + + {b7c5faf4-c3d3-4996-975e-b642d77b7914} + + + {9ed6318f-da0c-4318-9fee-c961c97d692f} + + + {d4737b51-2409-4e57-ba36-388847edffde} + + + {6efb6bad-0d4a-4fc8-a061-2460a8bce976} + + + {eccfcce6-b9e0-4494-8a7d-c3cbce288ac9} + + + {b6c6e828-c371-44bd-aec8-9a069688cd44} + + + {20a649d2-5a4a-4758-acd9-fd08fb8d11bd} + + + {13032fc1-0577-40e9-85d4-5d8124e1b272} + + + {9d11d620-3303-4198-994f-716bf436fd98} + + + {fb13c71f-7fd8-467e-b3f5-420327cc2177} + + + {b5c7f29c-6c51-40ef-b23a-978a09867680} + + + {0323c3ef-81d4-4d9e-ac2d-cc6aa83b0f9f} + + + {c96aed74-c04f-4566-b2c4-10a3953a46d6} + + + {e999255b-61d7-4c81-9716-ab98c20c14aa} + + + {e7649b04-a877-4884-96f3-d46b7d42eb80} + + + {db79c623-8c33-4cbe-bfe2-eb16bca18d39} + + + {e267b9c3-a579-41c4-a9e8-f2a4b93bf017} + + + {78c204cc-e5c6-40d5-b0c7-28d791f720bc} + + + {cea11459-df08-4fe2-bde7-681e1c5cd356} + + + {4acd9689-bae2-4dfc-b78e-e3e26062c437} + + + {14a6ff35-16ff-416e-9def-9fa53c24e93e} + + + {aabbaa14-6d0f-49b5-95b2-b0d2a211e04e} + + + {cea517a4-3e9b-4a80-91d6-a8fd24324268} + + + {1c3f4c6a-aaf3-4da7-94eb-dd9b5a16cb6b} + + + {e8734f1d-7789-4921-989b-109b58a52338} + + + {e8a6a10c-e33b-4850-86ba-a7d333ad182a} + + + {a484e997-e50e-4d33-b87d-637842768a7c} + + + {dd1d04c3-ef77-47f6-99a1-b70bb32e5300} + + + {659d386d-3ff2-43cf-8152-07392ace1eef} + + + {51f2c766-fbfc-484a-a5cb-fc2ea0a4555a} + + + {31fe7a10-ac1b-4a26-81f8-5fd3cc4bd301} + + + {0b954590-3027-4ad7-afb3-108e9309638a} + + + {0bc2e82d-9bd6-4ca2-bc86-1f9abe95374c} + + + {e85cc1cb-0950-4487-8830-7eaa8f9d45ee} + + + {9f9eb3a2-facd-4222-b484-cf428810ef1b} + + + {aff14859-0cd9-4a72-8cd8-285ea41b969b} + + + {537b06c8-1725-4703-a294-9ef3115bd1a9} + + + {fed788f7-d79e-4b83-841d-5a7b4c441ecb} + + + {9ca72061-358c-49ba-89ad-72ffc78fc2fb} + + + {f6a99ada-84ea-4699-b944-8884e825c808} + + + {24753958-aead-4c41-8f80-c64c05ad4cea} + + + {a4bbf361-2b35-43e1-a1b4-108f46279664} + + + {6e3a43c3-e7cd-44f4-af77-b18a5270847a} + + + {2348049f-6872-4199-b1ad-f3f2037cf557} + + + {042405c8-db97-4147-a10f-560369a56104} + + + {f79a6510-9483-4238-b730-d44cef56a0ec} + + + {2d800095-b254-4c2b-b25c-4e4d86fc37bf} + + + {57293206-a35e-4eed-aa5e-bf8f9d4cee61} + + + {804f84f4-c308-4acb-9e68-5ab1f4d343cb} + + + {8672c5f2-dea6-434c-a63b-6d9d94e3d355} + + + {9a51d029-9462-41e1-b091-9c49c3370918} + + + {3e82b754-3305-44c8-b27f-fcda6bf9f858} + + + {694c75c8-8ae1-43a0-a0f3-dadb9901b62a} + + + {d38a4f1f-0474-4d28-b567-1a79a16e1121} + + + {72b3d432-f56c-4d0b-a3e7-f87a4341e102} + + + {005cc49e-0588-4a77-85f1-fb968a8f815e} + + + {f13602a0-e01b-4429-8023-41efeb05d01b} + + + {77b15f02-9346-4292-a6a3-63dec9407187} + + + {6744e85c-04b5-4624-98da-31fc3f2c6e58} + + + {ec5dd2b6-5820-42b2-b598-e566ab91fac5} + + + {a42c83cd-678a-430a-92c5-75e7e3dd123d} + + + {17a483f6-7ea5-48b0-95b7-caf0b10a6f48} + + + {9cd0b4b9-18a4-4b7c-8e52-4499d88ff1c1} + + + {af5af218-a29b-496e-a765-dc3bd1f53e90} + + + {e235539e-3461-403c-ab3c-4fd343608101} + + + {d4a73649-d17c-4d29-88fb-7c3a153a2f58} + + + {43892867-6aa5-4686-9aaf-5a2c0129511a} + + + {60fe0955-d12b-4c0b-986c-e630fc82bffd} + + + {f8b7264f-ca84-4a7e-9d77-48cec5348288} + + + {e21f8e58-e334-4f8d-a2ba-927153365ab3} + + + {1a72ba3c-9d91-43c4-bdf9-ab9dd97a7a97} + + + {20c63d81-799b-4857-b334-55bc9a027dd7} + + + {fabff825-473b-48c8-8f64-b2fde98619d1} + + + {390e9dcd-7e41-4a8b-a005-8d259da51a8b} + + + {7e4a35b9-7b93-41fc-a22c-699b7a2e207f} + + + {70586847-48e9-42c2-8999-880771f61f52} + + + {eebd1030-6c40-480a-a594-cad9f5f85100} + + + {728a4f4b-668c-4d59-ad6a-ffd4c290a395} + + + + + snes\alt\cpu + + + snes\alt\cpu + + + snes\alt\cpu + + + snes\alt\cpu + + + snes\alt\cpu + + + snes\alt\cpu + + + snes\alt\dsp + + + snes\alt\dsp + + + snes\alt\dsp + + + snes\alt\ppu\debugger + + + snes\alt\ppu\memory + + + snes\alt\ppu\mmio + + + snes\alt\ppu\render + + + snes\alt\ppu\render + + + snes\alt\ppu\render + + + snes\alt\ppu\render + + + snes\alt\ppu\render + + + snes\alt\ppu\render + + + snes\alt\ppu\render + + + snes\alt\ppu\render + + + snes\alt\ppu + + + snes\alt\ppu + + + snes\audio + + + snes\cartridge + + + snes\cartridge + + + snes\cartridge + + + snes\cheat + + + snes\chip\bsx + + + snes\chip\bsx + + + snes\chip\bsx + + + snes\chip\bsx + + + snes\chip\bsx + + + snes\chip\cx4 + + + snes\chip\cx4 + + + snes\chip\cx4 + + + snes\chip\cx4 + + + snes\chip\cx4 + + + snes\chip\cx4 + + + snes\chip\cx4 + + + snes\chip\msu1 + + + snes\chip\msu1 + + + snes\chip\necdsp + + + snes\chip\necdsp + + + snes\chip\necdsp + + + snes\chip\necdsp + + + snes\chip\obc1 + + + snes\chip\obc1 + + + snes\chip\sa1 + + + snes\chip\sa1 + + + snes\chip\sa1\bus + + + snes\chip\sa1\debugger + + + snes\chip\sa1\dma + + + snes\chip\sa1\memory + + + snes\chip\sa1\mmio + + + snes\chip\sdd1 + + + snes\chip\sdd1 + + + snes\chip\sdd1 + + + snes\chip\serial + + + snes\chip\serial + + + snes\chip\spc7110 + + + snes\chip\spc7110 + + + snes\chip\spc7110 + + + snes\chip\srtc + + + snes\chip\srtc + + + snes\chip\st0018 + + + snes\chip\superfx + + + snes\chip\superfx + + + snes\chip\superfx\bus + + + snes\chip\superfx\core + + + snes\chip\superfx\core + + + snes\chip\superfx\core + + + snes\chip\superfx\debugger + + + snes\chip\superfx\disasm + + + snes\chip\superfx\memory + + + snes\chip\superfx\mmio + + + snes\chip\superfx\timing + + + snes\chip\supergameboy\debugger + + + snes\chip\supergameboy + + + snes\chip\supergameboy + + + snes\config + + + snes\cpu + + + snes\cpu + + + snes\cpu\core + + + snes\cpu\core + + + snes\cpu\core + + + snes\cpu\core + + + snes\cpu\core + + + snes\cpu\core + + + snes\cpu\core + + + snes\cpu\core + + + snes\cpu\core + + + snes\cpu\core\disassembler + + + snes\cpu\debugger + + + snes\cpu\debugger + + + snes\cpu\dma + + + snes\cpu\memory + + + snes\cpu\mmio + + + snes\cpu\timing + + + snes\cpu\timing + + + snes\cpu\timing + + + snes\debugger + + + snes\dsp\debugger + + + snes\dsp + + + snes\dsp + + + snes\dsp + + + snes\dsp + + + snes\dsp + + + snes\dsp + + + snes\dsp + + + snes\dsp + + + snes\dsp + + + snes\input + + + snes\memory + + + snes\memory + + + snes\ppu + + + snes\ppu + + + snes\ppu\background + + + snes\ppu\background + + + snes\ppu\counter + + + snes\ppu\debugger + + + snes\ppu\mmio + + + snes\ppu\screen + + + snes\ppu\sprite + + + snes\ppu\sprite + + + snes\ppu\window + + + snes\scheduler + + + snes\smp + + + snes\smp + + + snes\smp + + + snes\smp\core\disassembler + + + snes\smp\core + + + snes\smp\core + + + snes\smp\core + + + snes\smp\core + + + snes\smp\core + + + snes\smp\core + + + snes\smp\core + + + snes\smp\core + + + snes\smp\core + + + snes\smp\debugger + + + snes\smp\memory + + + snes\smp\mmio + + + snes\smp\timing + + + snes\system + + + snes\system + + + snes\system + + + snes\video + + + ruby + + + ruby + + + ruby + + + ruby\audio + + + ruby\input + + + ruby\video + + + ui-qt\application + + + ui-qt\application + + + ui-qt\application + + + ui-qt\base + + + ui-qt\base + + + ui-qt\base + + + ui-qt\base + + + ui-qt\base + + + ui-qt\base + + + ui-qt\base + + + ui-qt\cartridge + + + ui-qt\debugger\disassembler\processor + + + ui-qt\debugger\disassembler\processor + + + ui-qt\debugger\disassembler\processor + + + ui-qt\debugger\disassembler\processor + + + ui-qt\debugger\disassembler\processor + + + ui-qt\debugger\disassembler\symbols\adapters + + + ui-qt\debugger\disassembler\symbols\adapters + + + ui-qt\debugger\disassembler\symbols\adapters + + + ui-qt\debugger\disassembler\symbols + + + ui-qt\debugger\disassembler\symbols + + + ui-qt\debugger\disassembler + + + ui-qt\debugger\disassembler + + + ui-qt\debugger\ppu + + + ui-qt\debugger\ppu + + + ui-qt\debugger\ppu + + + ui-qt\debugger\ppu + + + ui-qt\debugger\ppu + + + ui-qt\debugger\ppu + + + ui-qt\debugger\ppu + + + ui-qt\debugger\ppu + + + ui-qt\debugger\ppu + + + ui-qt\debugger\ppu + + + ui-qt\debugger\ppu + + + ui-qt\debugger\tools\qhexedit2 + + + ui-qt\debugger\tools\qhexedit2 + + + ui-qt\debugger\tools + + + ui-qt\debugger\tools + + + ui-qt\debugger\tools + + + ui-qt\debugger + + + ui-qt\debugger + + + ui-qt\debugger + + + ui-qt\debugger + + + ui-qt\input + + + ui-qt\input + + + ui-qt\input + + + ui-qt\input + + + ui-qt\input + + + ui-qt\input + + + ui-qt\input + + + ui-qt\link + + + ui-qt\link + + + ui-qt\link + + + ui-qt\movie + + + ui-qt\platform + + + ui-qt\settings + + + ui-qt\settings + + + ui-qt\settings + + + ui-qt\settings + + + ui-qt\settings + + + ui-qt\settings + + + ui-qt\settings + + + ui-qt\state + + + ui-qt\tools + + + ui-qt\tools + + + ui-qt\tools + + + ui-qt\tools + + + ui-qt\tools + + + ui-qt\tools + + + ui-qt\tools + + + ui-qt\utility + + + ui-qt\utility + + + ui-qt\utility + + + ui-qt + + + ui-qt + + + ui-qt + + + common\zlib + + + common\zlib + + + common\zlib + + + common\zlib + + + common\zlib + + + common\zlib + + + libco + + + libco + + + libco + + + thrift + + + thrift + + + thrift + + + ui-qt\debugger + + + + + snes\alt\cpu + + + snes\alt\dsp + + + snes\alt\dsp + + + snes\alt\dsp + + + snes\alt\dsp + + + snes\alt\dsp + + + snes\alt\dsp + + + snes\alt\ppu\debugger + + + snes\alt\ppu\memory + + + snes\alt\ppu\mmio + + + snes\alt\ppu\render + + + snes\alt\ppu + + + snes\audio + + + snes\cartridge + + + snes\cheat + + + snes\cheat + + + snes\chip + + + snes\chip\bsx + + + snes\chip\cx4 + + + snes\chip\cx4 + + + snes\chip\msu1 + + + snes\chip\necdsp + + + snes\chip\necdsp + + + snes\chip\obc1 + + + snes\chip\sa1 + + + snes\chip\sa1\bus + + + snes\chip\sa1\debugger + + + snes\chip\sa1\dma + + + snes\chip\sa1\memory + + + snes\chip\sa1\mmio + + + snes\chip\sdd1 + + + snes\chip\sdd1 + + + snes\chip\serial + + + snes\chip\spc7110 + + + snes\chip\spc7110 + + + snes\chip\srtc + + + snes\chip\st0018 + + + snes\chip\superfx + + + snes\chip\superfx\bus + + + snes\chip\superfx\core + + + snes\chip\superfx\core + + + snes\chip\superfx\debugger + + + snes\chip\superfx\disasm + + + snes\chip\superfx\memory + + + snes\chip\superfx\mmio + + + snes\chip\superfx\timing + + + snes\chip\supergameboy\debugger + + + snes\chip\supergameboy + + + snes\config + + + snes\cpu + + + snes\cpu\core + + + snes\cpu\core + + + snes\cpu\core + + + snes\cpu\core\disassembler + + + snes\cpu\debugger + + + snes\cpu\debugger + + + snes\cpu\dma + + + snes\cpu\memory + + + snes\cpu\mmio + + + snes\cpu\timing + + + snes\debugger + + + snes\dsp\debugger + + + snes\dsp + + + snes\input + + + snes\interface + + + snes\memory + + + snes\memory + + + snes\ppu + + + snes\ppu\background + + + snes\ppu\counter + + + snes\ppu\counter + + + snes\ppu\debugger + + + snes\ppu\mmio + + + snes\ppu\screen + + + snes\ppu\sprite + + + snes\ppu\window + + + snes\scheduler + + + snes\smp + + + snes\smp\core\disassembler + + + snes\smp\core + + + snes\smp\core + + + snes\smp\core + + + snes\smp\debugger + + + snes\smp\memory + + + snes\smp\mmio + + + snes\smp\timing + + + snes\system + + + snes\video + + + snes + + + snes + + + snes + + + snes + + + ruby + + + ruby + + + ruby + + + ruby + + + ui-qt\cartridge + + + ui-qt\debugger\disassembler\processor + + + ui-qt\debugger\disassembler\processor + + + ui-qt\debugger\disassembler\processor + + + ui-qt\debugger\disassembler\processor + + + ui-qt\debugger\disassembler\processor + + + ui-qt\debugger\disassembler\symbols\adapters + + + ui-qt\debugger\disassembler\symbols\adapters + + + ui-qt\debugger\disassembler\symbols\adapters + + + ui-qt\debugger\disassembler\symbols\adapters + + + ui-qt\debugger\disassembler\symbols + + + ui-qt\debugger\disassembler + + + ui-qt\debugger\ppu + + + ui-qt\debugger\ppu + + + ui-qt\debugger\ppu + + + ui-qt\input + + + ui-qt\input + + + ui-qt\input + + + ui-qt\link + + + ui-qt\link + + + ui-qt\link + + + ui-qt\movie + + + ui-qt\state + + + ui-qt\utility + + + ui-qt + + + ui-qt + + + ui-qt + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall + + + common\nall\bps + + + common\nall\bps + + + common\nall\bps + + + common\nall\bps + + + common\nall\qt + + + common\nall\snes + + + common\nall\snes + + + common\nall\snes + + + common\nall\snes + + + common\nall\string + + + common\nall\string + + + common\nall\string + + + common\nall\string + + + common\nall\string + + + common\nall\string + + + common\nall\string + + + common\nall\string + + + common\nall\string + + + common\nall\string + + + common\nall\string + + + common\nall\string + + + common\nall\string + + + common\nall\string + + + common\nall\string + + + common\nall\string + + + common\nall\string + + + common\nall\string + + + common\zlib + + + common\zlib + + + common\zlib + + + common\zlib + + + common\zlib + + + common\zlib + + + common\zlib + + + common\zlib + + + libco + + + thrift + + + thrift + + + thrift + + + + + ui-qt\data\icons-16x16 + + + ui-qt\data\icons-16x16 + + + ui-qt\data\icons-16x16 + + + ui-qt\data\icons-16x16 + + + ui-qt\data\icons-16x16 + + + ui-qt\data\icons-16x16 + + + ui-qt\data\icons-16x16 + + + ui-qt\data\icons-16x16 + + + ui-qt\data\icons-16x16 + + + ui-qt\data\icons-16x16 + + + ui-qt\data\icons-16x16 + + + ui-qt\data\icons-16x16 + + + ui-qt\data\icons-16x16 + + + ui-qt\data\icons-16x16 + + + ui-qt\data\icons-16x16 + + + ui-qt\data\icons-16x16 + + + ui-qt\data\icons-16x16 + + + ui-qt\data\icons-16x16 + + + ui-qt\data + + + + + + ui-qt\data + + + ui-qt\data + + + + + ui-qt\debugger\tools\qhexedit2 + + + common\zlib + + + common\zlib + + + + + ui-qt\base + + + ui-qt\debugger + + + ui-qt\debugger\tools\qhexedit2 + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + mocs + + + resource + + + + + resource + + + \ No newline at end of file diff --git a/bsnes/vstudio/bsnes/bsnes.vcxproj.user b/bsnes/vstudio/bsnes/bsnes.vcxproj.user new file mode 100644 index 00000000..88a55094 --- /dev/null +++ b/bsnes/vstudio/bsnes/bsnes.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/common/nall/bps/patch.hpp b/common/nall/bps/patch.hpp index 85c4dcae..80491b9c 100644 --- a/common/nall/bps/patch.hpp +++ b/common/nall/bps/patch.hpp @@ -78,10 +78,11 @@ bool bpspatch::modify(const uint8_t *data, unsigned size) { modifyTargetSize = decode(); modifyMarkupSize = decode(); - char buffer[modifyMarkupSize + 1]; + char *buffer = new char[modifyMarkupSize + 1]; for(unsigned n = 0; n < modifyMarkupSize; n++) buffer[n] = modifyData[offset++]; buffer[modifyMarkupSize] = 0; - metadataString = (const char*)buffer; + metadataString.assign((const char*)buffer); + delete[] buffer; return true; } diff --git a/common/nall/platform.hpp b/common/nall/platform.hpp index 6212a8be..429a630e 100644 --- a/common/nall/platform.hpp +++ b/common/nall/platform.hpp @@ -22,7 +22,7 @@ #include #include #include - #undef interface + #define bsnesexport __declspec(dllexport) #else #include diff --git a/common/nall/utf8.hpp b/common/nall/utf8.hpp index f5597b85..4037bd94 100644 --- a/common/nall/utf8.hpp +++ b/common/nall/utf8.hpp @@ -13,7 +13,6 @@ #define _WIN32_WINNT 0x0501 #define NOMINMAX #include -#undef interface namespace nall { //UTF-8 to UTF-16