mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-08-06 13:24:16 -04:00
Add I2P BOB support to libretroashare and RetroShare GUI
This commit is contained in:
parent
9ff81b9e93
commit
a3ee85a30d
31 changed files with 4150 additions and 959 deletions
1118
libretroshare/src/services/autoproxy/p3i2pbob.cc
Normal file
1118
libretroshare/src/services/autoproxy/p3i2pbob.cc
Normal file
File diff suppressed because it is too large
Load diff
248
libretroshare/src/services/autoproxy/p3i2pbob.h
Normal file
248
libretroshare/src/services/autoproxy/p3i2pbob.h
Normal file
|
@ -0,0 +1,248 @@
|
|||
#ifndef P3I2PBOB_H
|
||||
#define P3I2PBOB_H
|
||||
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "services/autoproxy/rsautoproxymonitor.h"
|
||||
#include "util/rsthreads.h"
|
||||
#include "pqi/p3cfgmgr.h"
|
||||
|
||||
/*
|
||||
* This class implements I2P BOB (BASIC OPEN BRIDGE) communication to allow RS
|
||||
* to automatically remote control I2P to setup the needed tunnel.
|
||||
* BOB is a simple text-based interface: https://geti2p.net/en/docs/api/bob
|
||||
*
|
||||
* Note 1:
|
||||
* One tunnel is enough even for hidden locations since it can be used
|
||||
* bidirectional. (In contrast to what RS I2P users had to set up manually.)
|
||||
*
|
||||
* Note 2:
|
||||
* BOB tunnels are no SOCKS tunnel. Therefore pqissli2pbob implements a simplified
|
||||
* proxy specially for BOB tunnels.
|
||||
*
|
||||
* Note 3:
|
||||
* BOB needs a unique name as an ID for each tunnel.
|
||||
* We use 'RetroShare-' + 8 base32 characters.
|
||||
*
|
||||
* Design:
|
||||
* The service uses three state machines to manage its task:
|
||||
* int stateMachineBOB();
|
||||
* mBOBState
|
||||
* int stateMachineController();
|
||||
* mState
|
||||
* mTask
|
||||
*
|
||||
* stateMachineBOB:
|
||||
* This state machine manages the low level communication with BOB. It basically has a linked
|
||||
* list (currently a implemented as a std::map) that contains a command and the next
|
||||
* state.
|
||||
* Each high level operation (start up / shut down / get keys) is represented by a
|
||||
* chain of states. E.g. the chain to retrieve new keys:
|
||||
* mCommands[bobState::setnickN] = {setnick, bobState::newkeysN};
|
||||
* mCommands[bobState::newkeysN] = {newkeys, bobState::getkeys};
|
||||
* mCommands[bobState::getkeys] = {getkeys, bobState::clear};
|
||||
* mCommands[bobState::clear] = {clear, bobState::quit};
|
||||
* mCommands[bobState::quit] = {quit, bobState::cleared};
|
||||
*
|
||||
* stateMachineController:
|
||||
* This state machone manages the high level tasks.
|
||||
* It is controlled by mState and mTask.
|
||||
*
|
||||
* mTast:
|
||||
* Tracks the high level operation (like start up).
|
||||
* It will keep its value even when a task is done to track
|
||||
* the requested BOB state.
|
||||
* When other operations are performed like a conection check
|
||||
* the last task gets backed up and is later restored again
|
||||
*
|
||||
* mState:
|
||||
* This state lives only for one operation an manages the communication
|
||||
* with the BOB instance. This is basically connecting, starting BOB
|
||||
* protocol and disconnecting
|
||||
*
|
||||
* How a task looks like:
|
||||
* 1) RS sets task using the ticket system
|
||||
* 2) stateMachineController connects to BOBs control port, sets mBobState to a lists head
|
||||
* 3) stateMachineBOB processes command chain
|
||||
* 4) stateMachineBOB is done and sets mBobState to cleared signaling that the connection
|
||||
* is cleared and can be closed
|
||||
* 5) stateMachineController disconnects from BOBs control port and updates mState
|
||||
*/
|
||||
|
||||
///
|
||||
/// \brief The controllerState enum
|
||||
/// States for the controller to keep track of what he is currently doing
|
||||
enum controllerState {
|
||||
csIdel,
|
||||
csDoConnect,
|
||||
csConnected,
|
||||
csWaitForBob,
|
||||
csDoDisconnect,
|
||||
csDisconnected,
|
||||
csError
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief The controllerTask enum
|
||||
/// This state tracks the controllers tast (e.g. setup a BOB tunnel or shut down
|
||||
/// an existing one).
|
||||
enum controllerTask {
|
||||
ctIdle,
|
||||
ctRunSetUp,
|
||||
ctRunShutDown,
|
||||
ctRunGetKeys,
|
||||
ctRunCheck
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief The bobState enum
|
||||
/// One state for each message
|
||||
///
|
||||
enum bobState {
|
||||
bsCleared,
|
||||
bsSetnickC, // chain head for only client tunnel
|
||||
bsSetnickN, // chain head for getting new (server) keys
|
||||
bsSetnickS, // chain head for client and server tunnel
|
||||
bsGetnick,
|
||||
bsNewkeysC, // part of chain for only client tunnel
|
||||
bsNewkeysN, // part of chain for getting new (server) keys
|
||||
bsGetkeys,
|
||||
bsSetkeys,
|
||||
bsInhost,
|
||||
bsOuthost,
|
||||
bsInport,
|
||||
bsOutport,
|
||||
bsInlength,
|
||||
bsOutlength,
|
||||
bsInvariance,
|
||||
bsOutvariance,
|
||||
bsInquantity,
|
||||
bsOutquantity,
|
||||
bsQuiet,
|
||||
bsStart,
|
||||
bsStop,
|
||||
bsClear,
|
||||
bsList, // chain head for 'list' command
|
||||
bsQuit
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief The bobStateInfo struct
|
||||
/// State machine with commands
|
||||
/// \todo This could be replaced by a linked list instead of a map
|
||||
struct bobStateInfo {
|
||||
std::string command;
|
||||
bobState nextState;
|
||||
};
|
||||
|
||||
struct bobSettings {
|
||||
bool enableBob; ///< This field is used by the pqi subsystem to determinine whether SOCKS proxy or BOB is used for I2P connections
|
||||
std::string keys; ///< (optional) server keys
|
||||
std::string addr; ///< (optional) hidden service addr. in base32 form
|
||||
|
||||
int8_t inLength;
|
||||
int8_t inQuantity;
|
||||
int8_t inVariance;
|
||||
|
||||
int8_t outLength;
|
||||
int8_t outQuantity;
|
||||
int8_t outVariance;
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief The bobStates struct
|
||||
/// This container struct is used to pass all states.
|
||||
/// Additionally, the tunnel name is included to to show it in the GUI.
|
||||
/// The advantage of a struct is that it can be forward declared.
|
||||
struct bobStates {
|
||||
bobState bs;
|
||||
controllerState cs;
|
||||
controllerTask ct;
|
||||
|
||||
std::string tunnelName;
|
||||
};
|
||||
|
||||
class p3PeerMgr;
|
||||
|
||||
class p3I2pBob : public RsTickingThread, public p3Config, public autoProxyService
|
||||
{
|
||||
public:
|
||||
p3I2pBob(p3PeerMgr *peerMgr);
|
||||
|
||||
// autoProxyService interface
|
||||
public:
|
||||
bool isEnabled();
|
||||
bool initialSetup(std::string &addr, uint16_t &);
|
||||
void processTaskAsync(taskTicket *ticket);
|
||||
void processTaskSync(taskTicket *ticket);
|
||||
|
||||
static std::string keyToBase32Addr(const std::string &key);
|
||||
|
||||
// RsTickingThread interface
|
||||
public:
|
||||
void data_tick();
|
||||
|
||||
private:
|
||||
int stateMachineBOB();
|
||||
int stateMachineBOB_locked_failure(const std::string &answer, const bobStateInfo ¤tState);
|
||||
|
||||
int stateMachineController();
|
||||
int stateMachineController_locked_idle();
|
||||
int stateMachineController_locked_connected();
|
||||
int stateMachineController_locked_disconnected();
|
||||
int stateMachineController_locked_error();
|
||||
|
||||
// p3Config interface
|
||||
protected:
|
||||
RsSerialiser *setupSerialiser();
|
||||
bool saveList(bool &cleanup, std::list<RsItem *> &lst);
|
||||
bool loadList(std::list<RsItem *> &load);
|
||||
|
||||
private:
|
||||
// helpers
|
||||
void getBOBSettings(bobSettings *settings);
|
||||
void setBOBSettings(const bobSettings *settings);
|
||||
void getStates(bobStates *bs);
|
||||
|
||||
std::string executeCommand(const std::string &command);
|
||||
bool connectI2P();
|
||||
bool disconnectI2P();
|
||||
|
||||
void finalizeSettings_locked();
|
||||
void updateSettings_locked();
|
||||
|
||||
std::string recv();
|
||||
|
||||
// states for state machines
|
||||
controllerState mState;
|
||||
controllerTask mTask;
|
||||
// used to store old state when in error state
|
||||
// mStateOld is also used as a flag when an error occured in BOB protocol
|
||||
controllerState mStateOld;
|
||||
// mTaskOld is used to keep the previous task (start up / shut down) when requesting keys or checking the connection
|
||||
controllerTask mTaskOld;
|
||||
bobSettings mSetting;
|
||||
bobState mBOBState;
|
||||
|
||||
// used variables
|
||||
p3PeerMgr *mPeerMgr;
|
||||
bool mConfigLoaded;
|
||||
int mSocket;
|
||||
time_t mLastProxyCheck;
|
||||
sockaddr_storage mI2PProxyAddr;
|
||||
std::map<bobState, bobStateInfo> mCommands;
|
||||
std::string mErrorMsg;
|
||||
std::string mTunnelName;
|
||||
|
||||
std::queue<taskTicket *> mPending;
|
||||
taskTicket *mProcessing;
|
||||
|
||||
// mutex
|
||||
RsMutex mLock;
|
||||
};
|
||||
|
||||
#endif // P3I2PBOB_H
|
305
libretroshare/src/services/autoproxy/rsautoproxymonitor.cc
Normal file
305
libretroshare/src/services/autoproxy/rsautoproxymonitor.cc
Normal file
|
@ -0,0 +1,305 @@
|
|||
#include "rsautoproxymonitor.h"
|
||||
|
||||
rsAutoProxyMonitor *rsAutoProxyMonitor::mInstance = NULL;
|
||||
|
||||
rsAutoProxyMonitor::rsAutoProxyMonitor()
|
||||
: mRSShutDown(false), mLock("rs auto proxy monitor")
|
||||
{
|
||||
mProxies.clear();
|
||||
}
|
||||
|
||||
rsAutoProxyMonitor *rsAutoProxyMonitor::instance()
|
||||
{
|
||||
if (mInstance == NULL)
|
||||
mInstance = new rsAutoProxyMonitor();
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
void rsAutoProxyMonitor::addProxy(autoProxyType::autoProxyType_enum type, autoProxyService *service)
|
||||
{
|
||||
RS_STACK_MUTEX(mLock);
|
||||
if (mProxies.find(type) != mProxies.end())
|
||||
std::cerr << "sAutoProxyMonitor::addProxy type " << type << " already added - OVERWRITING" << std::endl;
|
||||
|
||||
mProxies[type] = service;
|
||||
}
|
||||
|
||||
void rsAutoProxyMonitor::startAll()
|
||||
{
|
||||
// create ticket
|
||||
taskTicket *tt = getTicket();
|
||||
tt->cb = this;
|
||||
tt->task = autoProxyTask::start;
|
||||
|
||||
{
|
||||
std::map<autoProxyType::autoProxyType_enum, autoProxyService*>::const_iterator it;
|
||||
|
||||
// fill types
|
||||
RS_STACK_MUTEX(mLock);
|
||||
for (it = mProxies.begin(); it != mProxies.end(); ++it)
|
||||
if (it->second->isEnabled())
|
||||
tt->types.push_back(it->first);
|
||||
}
|
||||
|
||||
task(tt);
|
||||
}
|
||||
|
||||
void rsAutoProxyMonitor::stopAll()
|
||||
{
|
||||
// create ticket
|
||||
taskTicket *tt = getTicket();
|
||||
tt->cb = this;
|
||||
tt->task = autoProxyTask::stop;
|
||||
|
||||
{
|
||||
std::map<autoProxyType::autoProxyType_enum, autoProxyService*>::const_iterator it;
|
||||
|
||||
// fill types
|
||||
RS_STACK_MUTEX(mLock);
|
||||
for (it = mProxies.begin(); it != mProxies.end(); ++it)
|
||||
if (it->second->isEnabled())
|
||||
tt->types.push_back(it->first);
|
||||
}
|
||||
|
||||
task(tt);
|
||||
}
|
||||
|
||||
void rsAutoProxyMonitor::stopAllRSShutdown()
|
||||
{
|
||||
{
|
||||
RS_STACK_MUTEX(mLock);
|
||||
mRSShutDown = true;
|
||||
|
||||
// remove disabled services
|
||||
std::vector<autoProxyType::autoProxyType_enum> toRemove;
|
||||
std::map<autoProxyType::autoProxyType_enum, autoProxyService*>::const_iterator it;
|
||||
for (it = mProxies.begin(); it != mProxies.end(); ++it) {
|
||||
if (!it->second->isEnabled()) {
|
||||
toRemove.push_back(it->first);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<autoProxyType::autoProxyType_enum>::const_iterator it2;
|
||||
for (it2 = toRemove.begin(); it2 != toRemove.end(); ++it2) {
|
||||
mProxies.erase(*it2);
|
||||
}
|
||||
}
|
||||
|
||||
// stop all remaining
|
||||
stopAll();
|
||||
|
||||
// wait for shutdown of all services
|
||||
uint32_t t = 0, timeout = 15;
|
||||
do {
|
||||
#ifndef WINDOWS_SYS
|
||||
usleep(1000 * 1000);
|
||||
#else
|
||||
Sleep(1000);
|
||||
#endif
|
||||
RS_STACK_MUTEX(mLock);
|
||||
std::cout << "(II) waiting for auto proxy service(s) to shut down " << t << "/" << timeout << " (remaining: " << mProxies.size() << ")" << std::endl;
|
||||
if (mProxies.empty())
|
||||
break;
|
||||
t++;
|
||||
} while (t < timeout );
|
||||
}
|
||||
|
||||
bool rsAutoProxyMonitor::isEnabled(autoProxyType::autoProxyType_enum t)
|
||||
{
|
||||
autoProxyService *s = lookUpService(t);
|
||||
if (s == NULL)
|
||||
return false;
|
||||
|
||||
return s->isEnabled();
|
||||
}
|
||||
|
||||
bool rsAutoProxyMonitor::initialSetup(autoProxyType::autoProxyType_enum t, std::string &addr, uint16_t &port)
|
||||
{
|
||||
autoProxyService *s = lookUpService(t);
|
||||
if (s == NULL)
|
||||
return false;
|
||||
|
||||
return s->initialSetup(addr, port);
|
||||
}
|
||||
|
||||
void rsAutoProxyMonitor::task(taskTicket *ticket)
|
||||
{
|
||||
// sanity checks
|
||||
if (!ticket->async && ticket->types.size() > 1) {
|
||||
std::cerr << "(WW) rsAutoProxyMonitor::task synchronous call to multiple services. This can cause problems!" << std::endl;
|
||||
}
|
||||
if (ticket->async && !ticket->cb && ticket->data) {
|
||||
std::cerr << "(WW) rsAutoProxyMonitor::task asynchronous call with data but no callback. This will likely causes memory leak!" << std::endl;
|
||||
}
|
||||
if (ticket->types.size() > 1 && ticket->data) {
|
||||
std::cerr << "(WW) rsAutoProxyMonitor::task call with data to multiple services. This will likely causes memory leak!" << std::endl;
|
||||
}
|
||||
|
||||
std::vector<autoProxyType::autoProxyType_enum>::const_iterator it;
|
||||
|
||||
for (it = ticket->types.begin(); it != ticket->types.end(); ++it) {
|
||||
autoProxyService* s = lookUpService(*it);
|
||||
if (s == NULL)
|
||||
continue;
|
||||
|
||||
if (ticket->async) {
|
||||
// copy ticket
|
||||
taskTicket *tt = new taskTicket();
|
||||
*tt = *ticket;
|
||||
tt->types.clear();
|
||||
tt->types.push_back(*it);
|
||||
s->processTaskAsync(tt);
|
||||
} else {
|
||||
s->processTaskSync(ticket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rsAutoProxyMonitor::taskAsync(autoProxyType::autoProxyType_enum type, autoProxyTask::autoProxyTask_enum task, autoProxyCallback *cb, void *data)
|
||||
{
|
||||
std::vector<autoProxyType::autoProxyType_enum> types;
|
||||
types.push_back(type);
|
||||
taskAsync(types, task, cb, data);
|
||||
}
|
||||
|
||||
void rsAutoProxyMonitor::taskAsync(std::vector<autoProxyType::autoProxyType_enum> types, autoProxyTask::autoProxyTask_enum task, autoProxyCallback *cb, void *data)
|
||||
{
|
||||
if (!isAsyncTask(task)) {
|
||||
// Usually the services will reject this ticket.
|
||||
// Just print a warning - maybe there is some special case where this is a good idea.
|
||||
std::cerr << "(WW) rsAutoProxyMonitor::taskAsync called with a synchronous task!" << std::endl;
|
||||
}
|
||||
|
||||
taskTicket *tt = getTicket();
|
||||
tt->task = task;
|
||||
tt->types = types;
|
||||
if (cb)
|
||||
tt->cb = cb;
|
||||
if (data)
|
||||
tt->data = data;
|
||||
|
||||
instance()->task(tt);
|
||||
// tickets were copied, clean up
|
||||
delete tt;
|
||||
}
|
||||
|
||||
void rsAutoProxyMonitor::taskSync(autoProxyType::autoProxyType_enum type, autoProxyTask::autoProxyTask_enum task, void *data)
|
||||
{
|
||||
std::vector<autoProxyType::autoProxyType_enum> types;
|
||||
types.push_back(type);
|
||||
taskSync(types, task, data);
|
||||
}
|
||||
|
||||
void rsAutoProxyMonitor::taskSync(std::vector<autoProxyType::autoProxyType_enum> types, autoProxyTask::autoProxyTask_enum task, void *data)
|
||||
{
|
||||
if (isAsyncTask(task)) {
|
||||
// Usually the services will reject this ticket.
|
||||
// Just print a warning - maybe there is some special case where this is a good idea.
|
||||
std::cerr << "(WW) rsAutoProxyMonitor::taskSync called with an asynchronous task!" << std::endl;
|
||||
}
|
||||
|
||||
taskTicket *tt = getTicket();
|
||||
tt->async = false;
|
||||
tt->task = task;
|
||||
tt->types = types;
|
||||
if (data)
|
||||
tt->data = data;
|
||||
|
||||
instance()->task(tt);
|
||||
// call done, clean up
|
||||
delete tt;
|
||||
}
|
||||
|
||||
void rsAutoProxyMonitor::taskError(taskTicket *t)
|
||||
{
|
||||
taskDone(t, autoProxyStatus::error);
|
||||
}
|
||||
|
||||
void rsAutoProxyMonitor::taskDone(taskTicket *t, autoProxyStatus::autoProxyStatus_enum status)
|
||||
{
|
||||
bool cleanUp = false;
|
||||
|
||||
t->result = status;
|
||||
if (t->cb) {
|
||||
t->cb->taskFinished(t);
|
||||
if (t != NULL) {
|
||||
// callack did not clean up properly
|
||||
std::cerr << "(WW) rsAutoProxyMonitor::taskFinish callback did not clean up!" << std::endl;
|
||||
cleanUp = true;
|
||||
}
|
||||
} else if (t->async){
|
||||
// async and no callback
|
||||
// we must take care of deleting
|
||||
cleanUp = true;
|
||||
if(t->data)
|
||||
std::cerr << "(WW) rsAutoProxyMonitor::taskFinish async call with data attached but no callback set!" << std::endl;
|
||||
}
|
||||
|
||||
if (cleanUp) {
|
||||
if (t->data) {
|
||||
std::cerr << "(WW) rsAutoProxyMonitor::taskFinish will try to delete void pointer!" << std::endl;
|
||||
#pragma GCC diagnostic ignored "-Wdelete-incomplete"
|
||||
delete t->data;
|
||||
#pragma GCC diagnostic pop
|
||||
t->data = NULL;
|
||||
}
|
||||
delete t;
|
||||
t = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
taskTicket *rsAutoProxyMonitor::getTicket()
|
||||
{
|
||||
taskTicket *tt = new taskTicket();
|
||||
tt->cb = NULL;
|
||||
tt->data = NULL;
|
||||
tt->async = true;
|
||||
tt->result = autoProxyStatus::undefined;
|
||||
return tt;
|
||||
}
|
||||
|
||||
void rsAutoProxyMonitor::taskFinished(taskTicket *&ticket)
|
||||
{
|
||||
{
|
||||
RS_STACK_MUTEX(mLock);
|
||||
if (mRSShutDown && ticket->task == autoProxyTask::stop) {
|
||||
mProxies.erase(ticket->types.front());
|
||||
}
|
||||
}
|
||||
|
||||
// clean up
|
||||
if (ticket->data) {
|
||||
std::cerr << "rsAutoProxyMonitor::taskFinished data set. Will try to delete void pointer" << std::endl;
|
||||
#pragma GCC diagnostic ignored "-Wdelete-incomplete"
|
||||
delete ticket->data;
|
||||
#pragma GCC diagnostic pop
|
||||
ticket->data = NULL;
|
||||
}
|
||||
delete ticket;
|
||||
ticket = NULL;
|
||||
}
|
||||
|
||||
autoProxyService *rsAutoProxyMonitor::lookUpService(autoProxyType::autoProxyType_enum t)
|
||||
{
|
||||
RS_STACK_MUTEX(mLock);
|
||||
std::map<autoProxyType::autoProxyType_enum, autoProxyService*>::const_iterator itService;
|
||||
if ((itService = mProxies.find(t)) != mProxies.end()) {
|
||||
return itService->second;
|
||||
}
|
||||
std::cerr << "sAutoProxyMonitor::lookUpService no service for type " << t << " found!" << std::endl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool rsAutoProxyMonitor::isAsyncTask(autoProxyTask::autoProxyTask_enum t)
|
||||
{
|
||||
switch (t) {
|
||||
case autoProxyTask::start:
|
||||
case autoProxyTask::stop:
|
||||
case autoProxyTask::receiveKey:
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
216
libretroshare/src/services/autoproxy/rsautoproxymonitor.h
Normal file
216
libretroshare/src/services/autoproxy/rsautoproxymonitor.h
Normal file
|
@ -0,0 +1,216 @@
|
|||
#ifndef RSAUTOPROXYMONITOR_H
|
||||
#define RSAUTOPROXYMONITOR_H
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <util/rsthreads.h>
|
||||
|
||||
class autoProxyCallback;
|
||||
|
||||
namespace autoProxyType {
|
||||
enum autoProxyType_enum {
|
||||
I2PBOB
|
||||
};
|
||||
}
|
||||
|
||||
namespace autoProxyTask {
|
||||
enum autoProxyTask_enum {
|
||||
/* async tasks */
|
||||
start, ///< start up proxy
|
||||
stop, ///< shut down proxy
|
||||
receiveKey, ///< renew proxy key (if any)
|
||||
proxyStatusCheck, ///< use to check if the proxy is still running
|
||||
/* sync tasks */
|
||||
status, ///< get status from auto proxy
|
||||
getSettings, ///< get setting from auto proxy
|
||||
setSettings, ///< set setting of auto proxy
|
||||
reloadConfig, ///< signal config reload/rebuild
|
||||
getErrorInfo ///< get error information from auto proxy
|
||||
};
|
||||
}
|
||||
|
||||
namespace autoProxyStatus {
|
||||
enum autoProxyStatus_enum {
|
||||
undefined, ///< undefined - usually not yet set
|
||||
disabled, ///< used when a task cannot be done (e.g. a disabled service cannot be startet or stopped)
|
||||
offline, ///< proxy is not set up
|
||||
online, ///< proxy is set up
|
||||
ok, ///< generic ok
|
||||
error ///< generic error
|
||||
};
|
||||
}
|
||||
|
||||
struct taskTicket {
|
||||
///
|
||||
/// \brief types auto proxy service types that should get the ticket
|
||||
///
|
||||
std::vector<autoProxyType::autoProxyType_enum> types;
|
||||
|
||||
///
|
||||
/// \brief task the task to satisfy
|
||||
///
|
||||
autoProxyTask::autoProxyTask_enum task;
|
||||
|
||||
///
|
||||
/// \brief cb (optional) callback that gets called once the task is done
|
||||
///
|
||||
autoProxyCallback *cb;
|
||||
|
||||
///
|
||||
/// \brief result (optional) result
|
||||
///
|
||||
autoProxyStatus::autoProxyStatus_enum result;
|
||||
|
||||
///
|
||||
/// \brief data (optional) service dependent data
|
||||
///
|
||||
/// Needs to be allocated and freed by caller!
|
||||
///
|
||||
void *data;
|
||||
|
||||
///
|
||||
/// \brief async is the call Asynchronous
|
||||
///
|
||||
/// Will create a copy of the ticket for each
|
||||
/// service and delete the original ticket.
|
||||
///
|
||||
bool async;
|
||||
};
|
||||
|
||||
class autoProxyCallback {
|
||||
public:
|
||||
///
|
||||
/// \brief taskFinished called when a task is finished
|
||||
/// \param ticket
|
||||
///
|
||||
/// Remove everything: ticket and attached data if any!
|
||||
///
|
||||
virtual void taskFinished(taskTicket *&ticket) = 0;
|
||||
};
|
||||
|
||||
class autoProxyService {
|
||||
public:
|
||||
///
|
||||
/// \brief isEnabled must be provided to directly get a result without going through the ticket system
|
||||
/// \return whether the auto proxy service is enabled or not
|
||||
///
|
||||
virtual bool isEnabled() = 0;
|
||||
|
||||
///
|
||||
/// \brief initialSetup used when creating a node
|
||||
/// \param addr new address for the hidden service
|
||||
/// \param port new port for the hidden service
|
||||
/// \return true on success
|
||||
///
|
||||
/// This function is used to do an initial setup when creating a new hidden node.
|
||||
/// Nothing has been set up at this point to the auto proxy service must take care
|
||||
/// of everything (e.g. starting (and stoping) of needed threads)
|
||||
///
|
||||
virtual bool initialSetup(std::string &addr, uint16_t &port) = 0;
|
||||
|
||||
///
|
||||
/// \brief processTaskAsync adds a ticket to the auto proxies task list
|
||||
/// \param ticket
|
||||
///
|
||||
/// Don't call the callback in this function as this can cause dead locks!
|
||||
///
|
||||
virtual void processTaskAsync(taskTicket *ticket) = 0;
|
||||
|
||||
///
|
||||
/// \brief processTaskSync taskTicket must be satisfied immediately
|
||||
/// \param ticket
|
||||
///
|
||||
virtual void processTaskSync(taskTicket *ticket) = 0;
|
||||
};
|
||||
|
||||
class rsAutoProxyMonitor : autoProxyCallback
|
||||
{
|
||||
public:
|
||||
static rsAutoProxyMonitor *instance();
|
||||
|
||||
///
|
||||
/// \brief addProxy adds a new auto proxy service to the monitor
|
||||
/// \param type type of the new auto proxy service
|
||||
/// \param service pointer to the service
|
||||
///
|
||||
void addProxy(autoProxyType::autoProxyType_enum type, autoProxyService *service);
|
||||
|
||||
// global functions
|
||||
void startAll();
|
||||
void stopAll();
|
||||
void stopAllRSShutdown();
|
||||
bool isEnabled(autoProxyType::autoProxyType_enum t);
|
||||
// use this when creating a new node
|
||||
bool initialSetup(autoProxyType::autoProxyType_enum t, std::string &addr, uint16_t &port);
|
||||
|
||||
///
|
||||
/// \brief task Sends a task to all requested services
|
||||
/// \param ticket Ticket containing required information
|
||||
///
|
||||
/// There are two kind of tasks: asyn and sync.
|
||||
/// All tasks that involve communication with the target program (e.g. I2P or Tor) are asynchronous.
|
||||
/// All other task are synchronous (e.g. getting settings)
|
||||
///
|
||||
///
|
||||
/// Synchronous:
|
||||
/// When you want to get the settings from a service you can call task() with a ticket only listing
|
||||
/// one service and data pointing to the service's settings class/struct. Set async to false so
|
||||
/// that the service gets your original ticket. Ther service will process the request (get settings)
|
||||
/// immediately and when the call to task() is done you can access the settings from your ticket.
|
||||
///
|
||||
/// When additionally a call back is set the service will also call it. This can cause deadlocks!
|
||||
///
|
||||
///
|
||||
/// Asynchronous:
|
||||
/// When you want to start up all services or request new keys for all services you can call task() with a list
|
||||
/// of services and set async to true. When each service has fullfilled the resquest he will
|
||||
/// use the callback. The original caller ticket will be copied and each call to the callback
|
||||
/// will use its copy of the original ticket. The attached data is not copied so each service gets
|
||||
/// the same pointer!
|
||||
///
|
||||
///
|
||||
/// Note:
|
||||
/// Services should not delet or allocate anything unless no call back is provided and it is an
|
||||
/// async call. In that case the service should delete the ticket and the attacked data.
|
||||
/// Otherwise the caller must take care of cleaning up.
|
||||
/// This class provides two wrappers to take care of this that should be used: taskError and taskDone
|
||||
///
|
||||
/// Note2:
|
||||
/// This function is private so that each user must use the wrappers taskAsync and taskSync that include
|
||||
/// more sanity checks
|
||||
///
|
||||
private:
|
||||
void task(taskTicket *ticket);
|
||||
|
||||
public:
|
||||
static void taskAsync(autoProxyType::autoProxyType_enum type, autoProxyTask::autoProxyTask_enum task, autoProxyCallback *cb = NULL, void *data = NULL);
|
||||
static void taskAsync(std::vector<autoProxyType::autoProxyType_enum> types, autoProxyTask::autoProxyTask_enum task, autoProxyCallback *cb = NULL, void *data = NULL);
|
||||
static void taskSync (autoProxyType::autoProxyType_enum type, autoProxyTask::autoProxyTask_enum task, void *data = NULL);
|
||||
static void taskSync (std::vector<autoProxyType::autoProxyType_enum> types, autoProxyTask::autoProxyTask_enum task, void *data = NULL);
|
||||
|
||||
// usefull helpers
|
||||
static void taskError(taskTicket *t);
|
||||
static void taskDone(taskTicket *t, autoProxyStatus::autoProxyStatus_enum status);
|
||||
static taskTicket *getTicket();
|
||||
|
||||
// autoProxyCallback interface
|
||||
public:
|
||||
void taskFinished(taskTicket *&ticket);
|
||||
|
||||
private:
|
||||
rsAutoProxyMonitor();
|
||||
|
||||
autoProxyService *lookUpService(autoProxyType::autoProxyType_enum t);
|
||||
static bool isAsyncTask(autoProxyTask::autoProxyTask_enum t);
|
||||
|
||||
std::map<autoProxyType::autoProxyType_enum, autoProxyService*> mProxies;
|
||||
bool mRSShutDown;
|
||||
RsMutex mLock;
|
||||
|
||||
static rsAutoProxyMonitor *mInstance;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // RSAUTOPROXYMONITOR_H
|
Loading…
Add table
Add a link
Reference in a new issue