- added support for multiple client threads to ApiServer

- added api client which reads the password from stdin. This allows to login from the webinterface and from the terminal at the same time.

git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@8103 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
electron128 2015-03-31 18:00:40 +00:00
parent 18e29c1e65
commit 73a6ca8af6
13 changed files with 884 additions and 461 deletions

View File

@ -6,12 +6,10 @@
#include <time.h>
#include <unistd.h>
#include <sstream>
#include <algorithm>
#include "json.h"
#include <retroshare/rsservicecontrol.h>
#ifdef FIXME
#include "rswall.h"
#endif
#include "JsonStream.h"
#include "StateTokenServer.h" // for the state token serialisers
@ -253,24 +251,11 @@ public:
FileSearchHandler mFileSearchHandler;
TransfersHandler mTransfersHandler;
};
#ifdef FIXME
class ApiServerWallModule
{
public:
ApiServerWallModule(ResourceRouter& router, const RsPlugInInterfaces& ifaces, RsWall::RsWall* wall):
mWallHandler(wall, ifaces.mIdentity)
{
router.addResourceHandler("wall", dynamic_cast<ResourceRouter*>(&mWallHandler),
&WallHandler::handleRequest);
}
WallHandler mWallHandler;
};
#endif
ApiServer::ApiServer():
mMtx("ApiServer mMtx"),
mStateTokenServer(),
mMainModules(0),
mWallModule(0)
mMainModules(0)
{
mRouter.addResourceHandler("statetokenservice", dynamic_cast<ResourceRouter*>(&mStateTokenServer),
&StateTokenServer::handleRequest);
@ -278,24 +263,22 @@ ApiServer::ApiServer():
ApiServer::~ApiServer()
{
RS_STACK_MUTEX(mMtx); // ********** LOCKED **********
for(std::vector<RequestId>::iterator vit = mRequests.begin(); vit != mRequests.end(); ++vit)
delete vit->task;
mRequests.clear();
if(mMainModules)
delete mMainModules;
if(mWallModule)
delete mWallModule;
}
void ApiServer::loadMainModules(const RsPlugInInterfaces &ifaces)
{
RS_STACK_MUTEX(mMtx); // ********** LOCKED **********
if(mMainModules == 0)
mMainModules = new ApiServerMainModules(mRouter, &mStateTokenServer, ifaces);
}
#ifdef FIXME
void ApiServer::loadWallModule(const RsPlugInInterfaces &ifaces, RsWall::RsWall* wall)
{
if(mWallModule == 0)
mWallModule = new ApiServerWallModule(mRouter, ifaces, wall);
}
#endif
std::string ApiServer::handleRequest(Request &request)
{
resource_api::JsonStream outstream;
@ -304,12 +287,22 @@ std::string ApiServer::handleRequest(Request &request)
StreamBase& data = outstream.getStreamToMember("data");
resource_api::Response resp(data, debugString);
ResponseTask* task = mRouter.handleRequest(request, resp);
ResponseTask* task = 0;
{
RS_STACK_MUTEX(mMtx); // ********** LOCKED **********
task = mRouter.handleRequest(request, resp);
}
time_t start = time(NULL);
while(task && task->doWork(request, resp))
bool morework = true;
while(task && morework)
{
usleep(10*1000);
{
RS_STACK_MUTEX(mMtx); // ********** LOCKED **********
morework = task->doWork(request, resp);
}
if(morework)
usleep(10*1000);
/*if(time(NULL) > (start+5))
{
std::cerr << "ApiServer::handleRequest() Error: task timed out" << std::endl;
@ -348,4 +341,53 @@ std::string ApiServer::handleRequest(Request &request)
return outstream.getJsonString();
}
ApiServer::RequestId ApiServer::handleRequest(Request &request, Response &response)
{
RequestId id;
ResponseTask* task = 0;
{
RS_STACK_MUTEX(mMtx); // ********** LOCKED **********
task = mRouter.handleRequest(request, response);
}
if(task == 0)
{
id.done = true;
return id;
}
id.done = false,
id.task = task;
id.request = &request;
id.response = &response;
{
RS_STACK_MUTEX(mMtx); // ********** LOCKED **********
mRequests.push_back(id);
}
return id;
}
bool ApiServer::isRequestDone(RequestId id)
{
if(id.done)
return true;
RS_STACK_MUTEX(mMtx); // ********** LOCKED **********
std::vector<RequestId>::iterator vit = std::find(mRequests.begin(), mRequests.end(), id);
// Request id not found, maybe the id is old and was removed from the list
if(vit == mRequests.end())
return true;
if(id.task->doWork(*id.request, *id.response))
return false;
// if we reach this point, the request is in the list and done
// remove the id from the list of valid ids
// delete the ResponseTask object
*vit = mRequests.back();
mRequests.pop_back();
delete id.task;
return true;
}
} // namespace resource_api

View File

@ -5,9 +5,6 @@
#include "ApiTypes.h"
#include "PeersHandler.h"
#include "IdentityHandler.h"
#ifdef FIXME
#include "WallHandler.h"
#endif
#include "ServiceControlHandler.h"
#include "StateTokenServer.h"
#include "FileSearchHandler.h"
@ -16,41 +13,57 @@
namespace resource_api{
class ApiServerMainModules;
class ApiServerWallModule;
// main entry point for all resource api calls
// main entry point for all resource_api calls
// general part of the api server
// should work with any http library or a different transport protocol (e.g. SSH)
// call chain is like this:
// Wt -> ApiServerWt -> ApiServer -> different handlers
// later i want to replace the parts with Wt with something else
// (Wt is a too large framework, a simple http server would be enough)
// maybe use libmicrohttpd
// the other use case for this api is a qt webkit view
// this works without html, the webkitview calls directly into our c++ code
// HTTP server -> ApiServer -> different handlers
// or
// GUI -> ApiServer -> different handlers
// multiple clients can use the same ApiServer instance at the same time
// general part of the api server
// should work with any http library or a different transport protocol
// ALL public methods in this class are thread safe
// this allows differen threads to send requests
class ApiServer
{
public:
ApiServer();
~ApiServer();
// it is currently hard to separate into http and non http stuff
// mainly because the http path is used in the api
// this has to change later
// for now let the http part make the request object
// and the general apiserver part makes the response
class RequestId{
public:
RequestId(): done(false), task(0), request(0), response(0){}
bool operator ==(const RequestId& r){
const RequestId& l = *this;
return (l.done==r.done)&&(l.task==r.task)&&(l.request==r.request)&&(l.response&&r.response);
}
private:
friend class ApiServer;
bool done; // this flag will be set to true, to signal the task id is valid and the task is done
// (in case there was no ResponseTask and task was zero)
ResponseTask* task; // null when the task id is invalid or when there was no task
Request* request;
Response* response;
};
// process the requestgiven by request and return the response as json string
// blocks until the request was processed
std::string handleRequest(Request& request);
// request and response must stay valid until isRequestDone returns true
// this method may do some work but it does not block
RequestId handleRequest(Request& request, Response& response);
// ticks the request
// returns true if the request is done or the id is invalid
// this method may do some work but it does not block
bool isRequestDone(RequestId id);
// load the main api modules
void loadMainModules(const RsPlugInInterfaces& ifaces);
// only after rswall was started!
#ifdef FIXME
void loadWallModule(const RsPlugInInterfaces& ifaces, RsWall::RsWall* wall);
#endif
// allows to add more handlers
// make sure the livetime of the handlers is longer than the api server
template <class T>
@ -61,25 +74,29 @@ public:
StateTokenServer* getStateTokenServer(){ return &mStateTokenServer; }
private:
RsMutex mMtx;
StateTokenServer mStateTokenServer; // goes first, as others may depend on it
// is always loaded, because it has no dependencies
// only pointers here, to load/unload modules at runtime
ApiServerMainModules* mMainModules; // loaded when RS is started
ApiServerWallModule* mWallModule; // only loaded in rssocialnet plugin
ResourceRouter mRouter;
std::vector<RequestId> mRequests;
};
// implementations
template <class T>
void ApiServer::addResourceHandler(std::string name, T* instance, ResponseTask* (T::*callback)(Request& req, Response& resp))
{
RS_STACK_MUTEX(mMtx); // ********** LOCKED **********
mRouter.addResourceHandler(name, instance, callback);
}
template <class T>
void ApiServer::addResourceHandler(std::string name, T* instance, void (T::*callback)(Request& req, Response& resp))
{
RS_STACK_MUTEX(mMtx); // ********** LOCKED **********
mRouter.addResourceHandler(name, instance, callback);
}

View File

@ -8,7 +8,8 @@
// for filestreamer
#include <retroshare/rsfiles.h>
#include "api/JsonStream.h"
#include "JsonStream.h"
#include "ApiServer.h"
#if MHD_VERSION < 0x00090000
// very old version, probably v0.4.x on old debian/ubuntu
@ -327,8 +328,8 @@ static void sendMessage(MHD_Connection *connection, unsigned int status, std::st
MHD_destroy_response(resp);
}
ApiServerMHD::ApiServerMHD():
mConfigOk(false), mDaemon(0)
ApiServerMHD::ApiServerMHD(ApiServer *server):
mConfigOk(false), mDaemon(0), mApiServer(server)
{
}
@ -394,7 +395,7 @@ bool ApiServerMHD::start()
MHD_OPTION_END);
if(mDaemon)
{
std::cerr << "ApiServerMHD::start() SUCCESS. Started server on port " << ntohs(mListenAddr.sin_port) << ". Serving files from \"" << mRootDir << "\" at /" << std::endl;
std::cerr << "ApiServerMHD::start() SUCCESS. Started server on port " << ntohs(mListenAddr.sin_port) << ". Serving files from \"" << mRootDir << "\" at " << STATIC_FILES_ENTRY_PATH << std::endl;
return true;
}
else
@ -480,7 +481,7 @@ int ApiServerMHD::accessHandlerCallback(MHD_Connection *connection,
if(strstr(url, API_ENTRY_PATH) == url)
{
// create a new handler and store it in con_cls
MHDHandlerBase* handler = new MHDApiHandler(&mApiServer);
MHDHandlerBase* handler = new MHDApiHandler(mApiServer);
*con_cls = (void*) handler;
return handler->handleRequest(connection, url, method, version, upload_data, upload_data_size);
}

View File

@ -11,14 +11,13 @@
#include <netinet/in.h>
#endif
#include "api/ApiServer.h"
namespace resource_api{
class ApiServer;
class ApiServerMHD
{
public:
ApiServerMHD();
ApiServerMHD(ApiServer* server);
~ApiServerMHD();
/**
* @brief configure the http server
@ -32,8 +31,6 @@ public:
bool start();
void stop();
ApiServer& getApiServer(){ return mApiServer; }
private:
// static callbacks for libmicrohttpd, they call the members below
static int static_acceptPolicyCallback(void* cls, const struct sockaddr * addr, socklen_t addrlen);
@ -46,7 +43,7 @@ private:
std::string mRootDir;
struct sockaddr_in mListenAddr;
MHD_Daemon* mDaemon;
ApiServer mApiServer;
ApiServer* mApiServer;
};
} // namespace resource_api

View File

@ -254,6 +254,7 @@ public:
class ResponseTask
{
public:
virtual ~ResponseTask(){}
// return true if function should get called again
// return false when finished
virtual bool doWork(Request& req, Response& resp) = 0;

View File

@ -46,6 +46,12 @@ std::string JsonStream::getJsonString()
return "";
}
void JsonStream::switchToDeserialisation()
{
deleteCurrentChild();
mSerialise = false;
}
//----------Stream Interface ---------------
@ -132,6 +138,7 @@ StreamBase& JsonStream::getStreamToMember()
if(checkDeserialisation() && arrayBoundsOk())
{
mChild->mValue = mArray[mArrayNextRead];
mChild->mSerialise = false;
mArrayNextRead++;
}
}

View File

@ -15,6 +15,11 @@ public:
void setJsonString(std::string jsonStr);
std::string getJsonString();
// it is possible to use this class as buffer
// first use as serialiser and fill with values
// then call this method to deserialise the values
void switchToDeserialisation();
//----------Stream Interface ---------------

View File

@ -51,6 +51,7 @@ ResponseTask* ResourceRouter::handleRequest(Request& req, Response& resp)
return vit->second->handleRequest(req, resp);
}
}
resp.setFail("ResourceRouter::handleRequest() Error: no handler for this path.");
return 0;
}

View File

@ -5,6 +5,7 @@
namespace resource_api
{
// a base class for routing requests to handler methods
// nothing is thread safe here
class ResourceRouter
{
public:
@ -23,6 +24,7 @@ private:
class HandlerBase
{
public:
virtual ~HandlerBase(){}
virtual ResponseTask* handleRequest(Request& req, Response& resp) = 0;
};
template <class T>

View File

@ -0,0 +1,310 @@
#include "TerminalApiClient.h"
#include <unistd.h>
#include <sstream>
#include <api/JsonStream.h>
// need two functions for non blocking read from stdin:
// int _kbhit() (returns a non zero value if a key was pressed)
// int _getch() (return the pressed key)
// these function are available on windows in conio.h
// they are not available on linux
#ifdef _WIN32
#include <conio.h>
#else // LINUX
/**
Linux (POSIX) implementation of _kbhit().
Morgan McGuire, morgan@cs.brown.edu
(modified to disable echo)
*/
#include <stdio.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <stropts.h>
int _kbhit() {
static const int STDIN = 0;
static bool initialized = false;
if (! initialized) {
// Use termios to turn off line buffering
termios term;
tcgetattr(STDIN, &term);
term.c_lflag &= ~ICANON;
term.c_lflag &= ~ECHO; // disable echo
tcsetattr(STDIN, TCSANOW, &term);
setbuf(stdin, NULL);
initialized = true;
}
int bytesWaiting;
ioctl(STDIN, FIONREAD, &bytesWaiting);
return bytesWaiting;
}
/*
Q: Is there a getch() (from conio) equivalent on Linux/UNIX?
A: No. But it's easy to emulate:
This code sets the terminal into non-canonical mode, thus disabling line buffering, reads a character from stdin and then restores the old terminal status. For more info on what else you can do with termios, see ``man termios''.
There's also a ``getch()'' function in the curses library, but it is /not/ equivalent to the DOS ``getch()'' and may only be used within real curses applications (ie: it only works in curses ``WINDOW''s).
http://cboard.cprogramming.com/faq-board/27714-faq-there-getch-conio-equivalent-linux-unix.html
*/
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
int _getch( ) {
struct termios oldt,
newt;
int ch;
tcgetattr( STDIN_FILENO, &oldt );
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newt );
ch = getchar();
tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
return ch;
}
#endif // LINUX
namespace resource_api {
TerminalApiClient::TerminalApiClient(ApiServer *api):
mApiServer(api)
{
start();
}
TerminalApiClient::~TerminalApiClient()
{
join();
}
void TerminalApiClient::run()
{
// values in milliseconds
const int MIN_WAIT_TIME = 20; // sleep time must be smaller or equal than the smallest period
const int IO_POLL_PERIOD = 20;
const int API_EVENT_POLL_PERIOD = 1000;
int last_io_poll = 0;
int last_event_api_poll = 0;
int last_char = 0;
std::string inbuf;
bool enter_was_pressed = false;
StateToken runstate_state_token;
std::string runstate;
std::vector<std::string> accounts;
StateToken password_state_token;
bool ask_for_password = false;
std::string key_name;
while(isRunning())
{
// assuming sleep_time >> work_time
// so we don't have to check the absolute time, just sleep every cycle
usleep(MIN_WAIT_TIME * 1000);
last_io_poll += MIN_WAIT_TIME;
last_event_api_poll += MIN_WAIT_TIME;
if(last_io_poll >= IO_POLL_PERIOD)
{
last_io_poll = 0;
last_char = 0;
if(_kbhit())
{
enter_was_pressed = false;
last_char = _getch();
if(last_char > 127)
std::cout << "Warning: non ASCII characters probably won't work." << std::endl;
if(last_char >= ' ')// space is the first printable ascii character
inbuf += (char) last_char;
if(last_char == '\r' || last_char == '\n')
enter_was_pressed = true;
else
enter_was_pressed = false;
// send echo
if(ask_for_password)
std::cout << "*";
else
std::cout << (char) last_char;
//std::cout << "you pressed key " << (char) last_char << " as integer: " << last_char << std::endl;
}
}
if(last_event_api_poll >= API_EVENT_POLL_PERIOD)
{
last_event_api_poll = 0;
if(!runstate_state_token.isNull() && !isTokenValid(runstate_state_token))
runstate_state_token = StateToken(); // must get new state with new token
if(!password_state_token.isNull() && !isTokenValid(password_state_token))
password_state_token = StateToken();
}
bool edge = false;
if(runstate_state_token.isNull())
{
edge = true;
JsonStream reqs;
JsonStream resps;
Request req(reqs);
std::stringstream ss;
Response resp(resps, ss);
req.mPath.push("runstate");
req.mPath.push("control");
reqs.switchToDeserialisation();
ApiServer::RequestId id = mApiServer->handleRequest(req, resp);
waitForResponse(id);
resps.switchToDeserialisation();
resps << makeKeyValueReference("runstate", runstate);
runstate_state_token = resp.mStateToken;
}
if(password_state_token.isNull())
{
edge = true;
JsonStream reqs;
JsonStream resps;
Request req(reqs);
std::stringstream ss;
Response resp(resps, ss);
req.mPath.push("password");
req.mPath.push("control");
reqs.switchToDeserialisation();
ApiServer::RequestId id = mApiServer->handleRequest(req, resp);
waitForResponse(id);
resps.switchToDeserialisation();
resps << makeKeyValueReference("want_password", ask_for_password);
resps << makeKeyValueReference("key_name", key_name);
password_state_token = resp.mStateToken;
}
if(!ask_for_password && edge && runstate == "waiting_account_select")
{
JsonStream reqs;
JsonStream resps;
Request req(reqs);
std::stringstream ss;
Response resp(resps, ss);
req.mPath.push("locations");
req.mPath.push("control");
reqs.switchToDeserialisation();
ApiServer::RequestId id = mApiServer->handleRequest(req, resp);
waitForResponse(id);
resps.switchToDeserialisation();
std::cout << "Type a number to select an account" << std::endl;
if(!resps.hasMore())
std::cout << "Error: No Accounts. Use the Qt-GUI or the webinterface to create an account." << std::endl;
int i = 0;
accounts.clear();
while(resps.hasMore())
{
std::string id;
std::string name;
std::string location;
resps.getStreamToMember()
<< makeKeyValueReference("id", id)
<< makeKeyValueReference("name", name)
<< makeKeyValueReference("location", location);
std::cout << "[" << i << "] " << name << "(" << location << ")" << std::endl;
accounts.push_back(id);
}
}
if(!ask_for_password && runstate == "waiting_account_select"
&& last_char >= '0' && last_char <= '9'
&& (last_char-'0') < accounts.size())
{
std::string acc = accounts[last_char-'0'];
JsonStream reqs;
JsonStream resps;
Request req(reqs);
std::stringstream ss;
Response resp(resps, ss);
req.mPath.push("login");
req.mPath.push("control");
reqs << makeKeyValueReference("id", acc);
reqs.switchToDeserialisation();
ApiServer::RequestId id = mApiServer->handleRequest(req, resp);
waitForResponse(id);
inbuf.clear();
}
if(edge && ask_for_password)
{
std::cout << "Enter the password for key " << key_name << std::endl;
}
if(ask_for_password && enter_was_pressed && !inbuf.empty())
{
std::cout << "TerminalApiClient: got a password" << std::endl;
JsonStream reqs;
JsonStream resps;
Request req(reqs);
std::stringstream ss;
Response resp(resps, ss);
req.mPath.push("password");
req.mPath.push("control");
reqs << makeKeyValueReference("password", inbuf);
reqs.switchToDeserialisation();
ApiServer::RequestId id = mApiServer->handleRequest(req, resp);
waitForResponse(id);
inbuf.clear();
}
}
}
void TerminalApiClient::waitForResponse(ApiServer::RequestId id)
{
while(!mApiServer->isRequestDone(id))
usleep(20*1000);
}
bool TerminalApiClient::isTokenValid(StateToken runstate_state_token)
{
JsonStream reqs;
JsonStream resps;
Request req(reqs);
std::stringstream ss;
Response resp(resps, ss);
req.mPath.push("statetokenservice");
req.mStream << runstate_state_token;
reqs.switchToDeserialisation();
ApiServer::RequestId id = mApiServer->handleRequest(req, resp);
waitForResponse(id);
resps.switchToDeserialisation();
if(resps.hasMore())
return false;
else
return true;
}
} // namespace resource_api

View File

@ -0,0 +1,27 @@
#pragma once
#include <api/ApiServer.h>
#include <util/rsthreads.h>
namespace resource_api {
// allows basic control from stdin/stdout
// - account selection
// - login
// - shutdown
class TerminalApiClient: private RsThread{
public:
// zero setup: create an instance of this class and destroy it when not needed anymore
// no need to call start or stop or something
// parameter api must not be null
TerminalApiClient(ApiServer* api);
~TerminalApiClient();
protected:
// from RsThread
virtual void run(); /* called once the thread is started. Should be overloaded by subclasses. */
private:
void waitForResponse(ApiServer::RequestId id);
bool isTokenValid(StateToken st);
ApiServer* mApiServer;
};
} // namespace resource_api

View File

@ -1,380 +1,386 @@
TEMPLATE = app
TARGET = retroshare-nogui
CONFIG += bitdht
#CONFIG += introserver
#CONFIG += sshserver
# webinterface, requires libmicrohttpd
#CONFIG += webui
CONFIG -= qt xml gui
# if you are linking against the libretroshare with gxs.
# this option links against the required sqlite library.
CONFIG += gxs
#CONFIG += debug
debug {
QMAKE_CFLAGS -= -O2
QMAKE_CFLAGS += -O0
QMAKE_CFLAGS += -g
QMAKE_CXXFLAGS -= -O2
QMAKE_CXXFLAGS += -O0
QMAKE_CXXFLAGS += -g
}
################################# Linux ##########################################
linux-* {
#CONFIG += version_detail_bash_script
QMAKE_CXXFLAGS *= -D_FILE_OFFSET_BITS=64
LIBS += ../../libretroshare/src/lib/libretroshare.a
LIBS += ../../openpgpsdk/src/lib/libops.a -lbz2
LIBS += -lssl -lupnp -lixml -lgnome-keyring
LIBS *= -lcrypto -ldl -lz -lpthread
LIBS *= -rdynamic
gxs {
SQLCIPHER_OK = $$system(pkg-config --exists sqlcipher && echo yes)
isEmpty(SQLCIPHER_OK) {
# We need a explicit path here, to force using the home version of sqlite3 that really encrypts the database.
exists(../../../lib/sqlcipher/.libs/libsqlcipher.a) {
LIBS += ../../../lib/sqlcipher/.libs/libsqlcipher.a
DEPENDPATH += ../../../lib/sqlcipher/src/
INCLUDEPATH += ../../../lib/sqlcipher/src/
} else {
message(libsqlcipher.a not found. Compilation will not use SQLCIPHER. Database will be unencrypted.)
DEFINES *= NO_SQLCIPHER
LIBS *= -lsqlite3
}
} else {
LIBS *= -lsqlcipher
}
}
}
linux-g++ {
OBJECTS_DIR = temp/linux-g++/obj
}
linux-g++-64 {
OBJECTS_DIR = temp/linux-g++-64/obj
}
#################### Cross compilation for windows under Linux ###################
win32-x-g++ {
OBJECTS_DIR = temp/win32-x-g++/obj
LIBS += ../../../../lib/win32-x-g++/libretroshare.a
LIBS += ../../../../lib/win32-x-g++/libssl.a
LIBS += ../../../../lib/win32-x-g++/libcrypto.a
LIBS += ../../../../lib/win32-x-g++/libminiupnpc.a
LIBS += ../../../../lib/win32-x-g++/libz.a
LIBS += -L${HOME}/.wine/drive_c/pthreads/lib -lpthreadGCE2
LIBS += -lws2_32 -luuid -lole32 -liphlpapi -lcrypt32 -gdi32
LIBS += -lole32 -lwinmm
RC_FILE = gui/images/retroshare_win.rc
DEFINES *= WIN32
}
#################################### Windows #####################################
win32 {
CONFIG += console
OBJECTS_DIR = temp/obj
RCC_DIR = temp/qrc
UI_DIR = temp/ui
MOC_DIR = temp/moc
PRE_TARGETDEPS *= ../../libretroshare/src/lib/libretroshare.a
PRE_TARGETDEPS *= ../../openpgpsdk/src/lib/libops.a
LIBS_DIR = $$PWD/../../../libs
LIBS += ../../libretroshare/src/lib/libretroshare.a
LIBS += ../../openpgpsdk/src/lib/libops.a -lbz2
LIBS += -L"$$LIBS_DIR/lib"
LIBS += -lssl -lcrypto -lpthread -lminiupnpc -lz
# added after bitdht
# LIBS += -lcrypto -lws2_32 -lgdi32
LIBS += -luuid -lole32 -liphlpapi -lcrypt32
LIBS += -lole32 -lwinmm
PROTOCPATH=$$LIBS_DIR/bin/
RC_FILE = resources/retroshare_win.rc
DEFINES *= WINDOWS_SYS _USE_32BIT_TIME_T
DEPENDPATH += $$LIBS_DIR/include
INCLUDEPATH += $$LIBS_DIR/include
gxs {
LIBS += ../../supportlibs/pegmarkdown/lib/libpegmarkdown.a
LIBS += -lsqlcipher
}
}
##################################### MacOS ######################################
macx {
# ENABLE THIS OPTION FOR Univeral Binary BUILD.
# CONFIG += ppc x86
LIBS += -Wl,-search_paths_first
LIBS += ../../libretroshare/src/lib/libretroshare.a
LIBS += ../../openpgpsdk/src/lib/libops.a -lbz2
LIBS += -lssl -lcrypto -lz
LIBS += ../../../miniupnpc-1.0/libminiupnpc.a
LIBS += -framework CoreFoundation
LIBS += -framework Security
gxs {
# We need a explicit path here, to force using the home version of sqlite3 that really encrypts the database.
# LIBS += ../../../lib/sqlcipher/.libs/libsqlcipher.a
LIBS += ../../../lib/libsqlcipher.a
}
sshserver {
LIBS += -L../../../lib
#LIBS += -L../../../lib/libssh-0.6.0
}
QMAKE_CXXFLAGS *= -Dfseeko64=fseeko -Dftello64=ftello -Dstat64=stat -Dstatvfs64=statvfs -Dfopen64=fopen
}
##################################### FreeBSD ######################################
freebsd-* {
INCLUDEPATH *= /usr/local/include/gpgme
LIBS *= ../../libretroshare/src/lib/libretroshare.a
LIBS *= -lssl
LIBS *= -lgpgme
LIBS *= -lupnp
LIBS *= -lgnome-keyring
PRE_TARGETDEPS *= ../../libretroshare/src/lib/libretroshare.a
}
##################################### OpenBSD ######################################
openbsd-* {
INCLUDEPATH *= /usr/local/include
QMAKE_CXXFLAGS *= -Dfseeko64=fseeko -Dftello64=ftello -Dstat64=stat -Dstatvfs64=statvfs -Dfopen64=fopen
LIBS *= ../../libretroshare/src/lib/libretroshare.a
LIBS *= ../../openpgpsdk/src/lib/libops.a -lbz2
LIBS *= -lssl -lcrypto
LIBS *= -lgpgme
LIBS *= -lupnp
LIBS *= -lgnome-keyring
PRE_TARGETDEPS *= ../../libretroshare/src/lib/libretroshare.a
PRE_TARGETDEPS *= ../../openpgpsdk/src/lib/libops.a
LIBS *= -rdynamic
}
############################## Common stuff ######################################
# bitdht config
bitdht {
LIBS += ../../libbitdht/src/lib/libbitdht.a
}
DEPENDPATH += . ../../libretroshare/src
INCLUDEPATH += . ../../libretroshare/src
# Input
HEADERS += notifytxt.h
SOURCES += notifytxt.cc \
retroshare.cc
introserver {
HEADERS += introserver.h
SOURCES += introserver.cc
DEFINES *= RS_INTRO_SERVER
}
webui {
DEFINES *= ENABLE_WEBUI
LIBS += ../../libresapi/src/lib/libresapi.a -lmicrohttpd
INCLUDEPATH += ../../libresapi/src
}
sshserver {
# This Requires libssh-0.5.* to compile.
# Please use this path below.
# (You can modify it locally if required - but dont commit it!)
#LIBSSH_DIR = ../../../lib/libssh-0.5.2
LIBSSH_DIR = ../../../libssh-0.6.0rc1
#
# Use the following commend to generate a Server RSA Key.
# Key should be in current directory - when run/
# ssh-keygen -t rsa -f rs_ssh_host_rsa_key
#
# You can connect from a standard ssh, eg: ssh -p 7022 127.0.0.1
#
# The Menu system is available from the command-line (-T) and SSH (-S)
# if it get covered by debug gunk, just press <return> to refresh.
#
# ./retroshare-nogui -h provides some more instructions.
#
win32 {
DEFINES *= LIBSSH_STATIC
}
DEPENDPATH += $$LIBSSH_DIR/include/
INCLUDEPATH += $$LIBSSH_DIR/include/
win32 {
LIBS += -lssh
LIBS += -lssh_threads
} else {
SSH_OK = $$system(pkg-config --atleast-version 0.5.4 libssh && echo yes)
isEmpty(SSH_OK) {
exists($$LIBSSH_DIR/build/src/libssh.a):exists($$LIBSSH_DIR/build/src/threads/libssh_threads.a) {
LIBS += $$LIBSSH_DIR/build/src/libssh.a
LIBS += $$LIBSSH_DIR/build/src/threads/libssh_threads.a
}
else {
! exists($$LIBSSH_DIR/build/src/libssh.a):message($$LIBSSH_DIR/build/src/libssh.a does not exist)
! exists($$LIBSSH_DIR/build/src/threads/libssh_threads.a):message($$LIBSSH_DIR/build/src/threads/libssh_threads.a does not exist)
message(You need to download and compile libssh)
message(See http://sourceforge.net/p/retroshare/code/6163/tree/trunk/)
}
} else {
LIBS += -lssh
LIBS += -lssh_threads
}
}
HEADERS += ssh/rssshd.h
SOURCES += ssh/rssshd.cc
# For the Menu System
HEADERS += menu/menu.h \
menu/menus.h \
menu/stdiocomms.h \
SOURCES += menu/menu.cc \
menu/menus.cc \
menu/stdiocomms.cc \
# For the RPC System
HEADERS += rpc/rpc.h \
rpc/rpcserver.h \
rpc/rpcsetup.h \
rpc/rpcecho.h \
rpcsystem.h \
SOURCES += rpc/rpc.cc \
rpc/rpcserver.cc \
rpc/rpcsetup.cc \
rpc/rpcecho.cc \
# Actual protocol files to go here...
#HEADERS += rpc/proto/rpcecho.h \
#SOURCES += rpc/proto/rpcecho.cc \
DEFINES *= RS_SSH_SERVER
# Include Protobuf classes.
CONFIG += protorpc
}
protorpc {
# Proto Services
PROTOS = core.proto peers.proto system.proto chat.proto search.proto files.proto stream.proto
DESTPATH = $$PWD/rpc/proto/gencc
PROTOPATH = $$PWD/../../rsctrl/src/definition
CMD = echo Building protobuf files
for(pf, PROTOS):CMD += && $${PROTOCPATH}protoc --cpp_out=$${DESTPATH} --proto_path=$${PROTOPATH} $${PROTOPATH}/$${pf}
protobuf_gen.commands = $${CMD}
QMAKE_EXTRA_TARGETS += protobuf_gen
PRE_TARGETDEPS += protobuf_gen
HEADERS += rpc/proto/rpcprotopeers.h \
rpc/proto/rpcprotosystem.h \
rpc/proto/rpcprotochat.h \
rpc/proto/rpcprotosearch.h \
rpc/proto/rpcprotofiles.h \
rpc/proto/rpcprotostream.h \
rpc/proto/rpcprotoutils.h \
SOURCES += rpc/proto/rpcprotopeers.cc \
rpc/proto/rpcprotosystem.cc \
rpc/proto/rpcprotochat.cc \
rpc/proto/rpcprotosearch.cc \
rpc/proto/rpcprotofiles.cc \
rpc/proto/rpcprotostream.cc \
rpc/proto/rpcprotoutils.cc \
# Offical Generated Code (protobuf 2.4.1)
HEADERS += rpc/proto/gencc/core.pb.h \
rpc/proto/gencc/peers.pb.h \
rpc/proto/gencc/system.pb.h \
rpc/proto/gencc/chat.pb.h \
rpc/proto/gencc/search.pb.h \
rpc/proto/gencc/files.pb.h \
rpc/proto/gencc/stream.pb.h \
SOURCES += rpc/proto/gencc/core.pb.cc \
rpc/proto/gencc/peers.pb.cc \
rpc/proto/gencc/system.pb.cc \
rpc/proto/gencc/chat.pb.cc \
rpc/proto/gencc/search.pb.cc \
rpc/proto/gencc/files.pb.cc \
rpc/proto/gencc/stream.pb.cc \
# Generated ProtoBuf Code the RPC System
# If you are developing, or have a different version of protobuf
# you can use these ones (run make inside rsctrl/src/ to generate)
#HEADERS += ../../rsctrl/src/gencc/core.pb.h \
# ../../rsctrl/src/gencc/peers.pb.h \
# ../../rsctrl/src/gencc/system.pb.h \
# ../../rsctrl/src/gencc/chat.pb.h \
# ../../rsctrl/src/gencc/search.pb.h \
# ../../rsctrl/src/gencc/files.pb.h \
# ../../rsctrl/src/gencc/stream.pb.h \
#SOURCES += ../../rsctrl/src/gencc/core.pb.cc \
# ../../rsctrl/src/gencc/peers.pb.cc \
# ../../rsctrl/src/gencc/system.pb.cc \
# ../../rsctrl/src/gencc/chat.pb.cc \
# ../../rsctrl/src/gencc/search.pb.cc \
# ../../rsctrl/src/gencc/files.pb.cc \
# ../../rsctrl/src/gencc/stream.pb.cc \
DEPENDPATH *= rpc/proto/gencc
INCLUDEPATH *= rpc/proto/gencc
!win32 {
# unrecognized option
QMAKE_CFLAGS += -pthread
QMAKE_CXXFLAGS += -pthread
}
LIBS += -lprotobuf -lpthread
win32 {
DEPENDPATH += $$LIBS_DIR/include/protobuf
INCLUDEPATH += $$LIBS_DIR/include/protobuf
}
macx {
PROTOPATH = ../../../protobuf-2.4.1
INCLUDEPATH += $${PROTOPATH}/src
}
}
win32 {
# must be added after ssh
LIBS += -lcrypto -lws2_32 -lgdi32
}
TEMPLATE = app
TARGET = retroshare-nogui
CONFIG += bitdht
#CONFIG += introserver
#CONFIG += sshserver
# webinterface, requires libmicrohttpd
#CONFIG += webui
CONFIG -= qt xml gui
# if you are linking against the libretroshare with gxs.
# this option links against the required sqlite library.
CONFIG += gxs
#CONFIG += debug
debug {
QMAKE_CFLAGS -= -O2
QMAKE_CFLAGS += -O0
QMAKE_CFLAGS += -g
QMAKE_CXXFLAGS -= -O2
QMAKE_CXXFLAGS += -O0
QMAKE_CXXFLAGS += -g
}
################################# Linux ##########################################
linux-* {
#CONFIG += version_detail_bash_script
QMAKE_CXXFLAGS *= -D_FILE_OFFSET_BITS=64
LIBS += ../../libretroshare/src/lib/libretroshare.a
LIBS += ../../openpgpsdk/src/lib/libops.a -lbz2
LIBS += -lssl -lupnp -lixml -lgnome-keyring
LIBS *= -lcrypto -ldl -lz -lpthread
LIBS *= -rdynamic
gxs {
SQLCIPHER_OK = $$system(pkg-config --exists sqlcipher && echo yes)
isEmpty(SQLCIPHER_OK) {
# We need a explicit path here, to force using the home version of sqlite3 that really encrypts the database.
exists(../../../lib/sqlcipher/.libs/libsqlcipher.a) {
LIBS += ../../../lib/sqlcipher/.libs/libsqlcipher.a
DEPENDPATH += ../../../lib/sqlcipher/src/
INCLUDEPATH += ../../../lib/sqlcipher/src/
} else {
message(libsqlcipher.a not found. Compilation will not use SQLCIPHER. Database will be unencrypted.)
DEFINES *= NO_SQLCIPHER
LIBS *= -lsqlite3
}
} else {
LIBS *= -lsqlcipher
}
}
}
linux-g++ {
OBJECTS_DIR = temp/linux-g++/obj
}
linux-g++-64 {
OBJECTS_DIR = temp/linux-g++-64/obj
}
#################### Cross compilation for windows under Linux ###################
win32-x-g++ {
OBJECTS_DIR = temp/win32-x-g++/obj
LIBS += ../../../../lib/win32-x-g++/libretroshare.a
LIBS += ../../../../lib/win32-x-g++/libssl.a
LIBS += ../../../../lib/win32-x-g++/libcrypto.a
LIBS += ../../../../lib/win32-x-g++/libminiupnpc.a
LIBS += ../../../../lib/win32-x-g++/libz.a
LIBS += -L${HOME}/.wine/drive_c/pthreads/lib -lpthreadGCE2
LIBS += -lws2_32 -luuid -lole32 -liphlpapi -lcrypt32 -gdi32
LIBS += -lole32 -lwinmm
RC_FILE = gui/images/retroshare_win.rc
DEFINES *= WIN32
}
#################################### Windows #####################################
win32 {
CONFIG += console
OBJECTS_DIR = temp/obj
RCC_DIR = temp/qrc
UI_DIR = temp/ui
MOC_DIR = temp/moc
PRE_TARGETDEPS *= ../../libretroshare/src/lib/libretroshare.a
PRE_TARGETDEPS *= ../../openpgpsdk/src/lib/libops.a
LIBS_DIR = $$PWD/../../../libs
LIBS += ../../libretroshare/src/lib/libretroshare.a
LIBS += ../../openpgpsdk/src/lib/libops.a -lbz2
LIBS += -L"$$LIBS_DIR/lib"
LIBS += -lssl -lcrypto -lpthread -lminiupnpc -lz
# added after bitdht
# LIBS += -lcrypto -lws2_32 -lgdi32
LIBS += -luuid -lole32 -liphlpapi -lcrypt32
LIBS += -lole32 -lwinmm
PROTOCPATH=$$LIBS_DIR/bin/
RC_FILE = resources/retroshare_win.rc
DEFINES *= WINDOWS_SYS _USE_32BIT_TIME_T
DEPENDPATH += $$LIBS_DIR/include
INCLUDEPATH += $$LIBS_DIR/include
gxs {
LIBS += ../../supportlibs/pegmarkdown/lib/libpegmarkdown.a
LIBS += -lsqlcipher
}
}
##################################### MacOS ######################################
macx {
# ENABLE THIS OPTION FOR Univeral Binary BUILD.
# CONFIG += ppc x86
LIBS += -Wl,-search_paths_first
LIBS += ../../libretroshare/src/lib/libretroshare.a
LIBS += ../../openpgpsdk/src/lib/libops.a -lbz2
LIBS += -lssl -lcrypto -lz
LIBS += ../../../miniupnpc-1.0/libminiupnpc.a
LIBS += -framework CoreFoundation
LIBS += -framework Security
gxs {
# We need a explicit path here, to force using the home version of sqlite3 that really encrypts the database.
# LIBS += ../../../lib/sqlcipher/.libs/libsqlcipher.a
LIBS += ../../../lib/libsqlcipher.a
}
sshserver {
LIBS += -L../../../lib
#LIBS += -L../../../lib/libssh-0.6.0
}
QMAKE_CXXFLAGS *= -Dfseeko64=fseeko -Dftello64=ftello -Dstat64=stat -Dstatvfs64=statvfs -Dfopen64=fopen
}
##################################### FreeBSD ######################################
freebsd-* {
INCLUDEPATH *= /usr/local/include/gpgme
LIBS *= ../../libretroshare/src/lib/libretroshare.a
LIBS *= -lssl
LIBS *= -lgpgme
LIBS *= -lupnp
LIBS *= -lgnome-keyring
PRE_TARGETDEPS *= ../../libretroshare/src/lib/libretroshare.a
}
##################################### OpenBSD ######################################
openbsd-* {
INCLUDEPATH *= /usr/local/include
QMAKE_CXXFLAGS *= -Dfseeko64=fseeko -Dftello64=ftello -Dstat64=stat -Dstatvfs64=statvfs -Dfopen64=fopen
LIBS *= ../../libretroshare/src/lib/libretroshare.a
LIBS *= ../../openpgpsdk/src/lib/libops.a -lbz2
LIBS *= -lssl -lcrypto
LIBS *= -lgpgme
LIBS *= -lupnp
LIBS *= -lgnome-keyring
PRE_TARGETDEPS *= ../../libretroshare/src/lib/libretroshare.a
PRE_TARGETDEPS *= ../../openpgpsdk/src/lib/libops.a
LIBS *= -rdynamic
}
############################## Common stuff ######################################
# bitdht config
bitdht {
LIBS += ../../libbitdht/src/lib/libbitdht.a
}
DEPENDPATH += . ../../libretroshare/src
INCLUDEPATH += . ../../libretroshare/src
# Input
HEADERS += notifytxt.h
SOURCES += notifytxt.cc \
retroshare.cc
introserver {
HEADERS += introserver.h
SOURCES += introserver.cc
DEFINES *= RS_INTRO_SERVER
}
webui {
DEFINES *= ENABLE_WEBUI
PRE_TARGETDEPS *= ../../libresapi/src/lib/libresapi.a
LIBS += ../../libresapi/src/lib/libresapi.a -lmicrohttpd
DEPENDPATH += ../../libresapi/src
INCLUDEPATH += ../../libresapi/src
HEADERS += \
TerminalApiClient.h
SOURCES += \
TerminalApiClient.cpp
}
sshserver {
# This Requires libssh-0.5.* to compile.
# Please use this path below.
# (You can modify it locally if required - but dont commit it!)
#LIBSSH_DIR = ../../../lib/libssh-0.5.2
LIBSSH_DIR = ../../../libssh-0.6.0rc1
#
# Use the following commend to generate a Server RSA Key.
# Key should be in current directory - when run/
# ssh-keygen -t rsa -f rs_ssh_host_rsa_key
#
# You can connect from a standard ssh, eg: ssh -p 7022 127.0.0.1
#
# The Menu system is available from the command-line (-T) and SSH (-S)
# if it get covered by debug gunk, just press <return> to refresh.
#
# ./retroshare-nogui -h provides some more instructions.
#
win32 {
DEFINES *= LIBSSH_STATIC
}
DEPENDPATH += $$LIBSSH_DIR/include/
INCLUDEPATH += $$LIBSSH_DIR/include/
win32 {
LIBS += -lssh
LIBS += -lssh_threads
} else {
SSH_OK = $$system(pkg-config --atleast-version 0.5.4 libssh && echo yes)
isEmpty(SSH_OK) {
exists($$LIBSSH_DIR/build/src/libssh.a):exists($$LIBSSH_DIR/build/src/threads/libssh_threads.a) {
LIBS += $$LIBSSH_DIR/build/src/libssh.a
LIBS += $$LIBSSH_DIR/build/src/threads/libssh_threads.a
}
else {
! exists($$LIBSSH_DIR/build/src/libssh.a):message($$LIBSSH_DIR/build/src/libssh.a does not exist)
! exists($$LIBSSH_DIR/build/src/threads/libssh_threads.a):message($$LIBSSH_DIR/build/src/threads/libssh_threads.a does not exist)
message(You need to download and compile libssh)
message(See http://sourceforge.net/p/retroshare/code/6163/tree/trunk/)
}
} else {
LIBS += -lssh
LIBS += -lssh_threads
}
}
HEADERS += ssh/rssshd.h
SOURCES += ssh/rssshd.cc
# For the Menu System
HEADERS += menu/menu.h \
menu/menus.h \
menu/stdiocomms.h \
SOURCES += menu/menu.cc \
menu/menus.cc \
menu/stdiocomms.cc \
# For the RPC System
HEADERS += rpc/rpc.h \
rpc/rpcserver.h \
rpc/rpcsetup.h \
rpc/rpcecho.h \
rpcsystem.h \
SOURCES += rpc/rpc.cc \
rpc/rpcserver.cc \
rpc/rpcsetup.cc \
rpc/rpcecho.cc \
# Actual protocol files to go here...
#HEADERS += rpc/proto/rpcecho.h \
#SOURCES += rpc/proto/rpcecho.cc \
DEFINES *= RS_SSH_SERVER
# Include Protobuf classes.
CONFIG += protorpc
}
protorpc {
# Proto Services
PROTOS = core.proto peers.proto system.proto chat.proto search.proto files.proto stream.proto
DESTPATH = $$PWD/rpc/proto/gencc
PROTOPATH = $$PWD/../../rsctrl/src/definition
CMD = echo Building protobuf files
for(pf, PROTOS):CMD += && $${PROTOCPATH}protoc --cpp_out=$${DESTPATH} --proto_path=$${PROTOPATH} $${PROTOPATH}/$${pf}
protobuf_gen.commands = $${CMD}
QMAKE_EXTRA_TARGETS += protobuf_gen
PRE_TARGETDEPS += protobuf_gen
HEADERS += rpc/proto/rpcprotopeers.h \
rpc/proto/rpcprotosystem.h \
rpc/proto/rpcprotochat.h \
rpc/proto/rpcprotosearch.h \
rpc/proto/rpcprotofiles.h \
rpc/proto/rpcprotostream.h \
rpc/proto/rpcprotoutils.h \
SOURCES += rpc/proto/rpcprotopeers.cc \
rpc/proto/rpcprotosystem.cc \
rpc/proto/rpcprotochat.cc \
rpc/proto/rpcprotosearch.cc \
rpc/proto/rpcprotofiles.cc \
rpc/proto/rpcprotostream.cc \
rpc/proto/rpcprotoutils.cc \
# Offical Generated Code (protobuf 2.4.1)
HEADERS += rpc/proto/gencc/core.pb.h \
rpc/proto/gencc/peers.pb.h \
rpc/proto/gencc/system.pb.h \
rpc/proto/gencc/chat.pb.h \
rpc/proto/gencc/search.pb.h \
rpc/proto/gencc/files.pb.h \
rpc/proto/gencc/stream.pb.h \
SOURCES += rpc/proto/gencc/core.pb.cc \
rpc/proto/gencc/peers.pb.cc \
rpc/proto/gencc/system.pb.cc \
rpc/proto/gencc/chat.pb.cc \
rpc/proto/gencc/search.pb.cc \
rpc/proto/gencc/files.pb.cc \
rpc/proto/gencc/stream.pb.cc \
# Generated ProtoBuf Code the RPC System
# If you are developing, or have a different version of protobuf
# you can use these ones (run make inside rsctrl/src/ to generate)
#HEADERS += ../../rsctrl/src/gencc/core.pb.h \
# ../../rsctrl/src/gencc/peers.pb.h \
# ../../rsctrl/src/gencc/system.pb.h \
# ../../rsctrl/src/gencc/chat.pb.h \
# ../../rsctrl/src/gencc/search.pb.h \
# ../../rsctrl/src/gencc/files.pb.h \
# ../../rsctrl/src/gencc/stream.pb.h \
#SOURCES += ../../rsctrl/src/gencc/core.pb.cc \
# ../../rsctrl/src/gencc/peers.pb.cc \
# ../../rsctrl/src/gencc/system.pb.cc \
# ../../rsctrl/src/gencc/chat.pb.cc \
# ../../rsctrl/src/gencc/search.pb.cc \
# ../../rsctrl/src/gencc/files.pb.cc \
# ../../rsctrl/src/gencc/stream.pb.cc \
DEPENDPATH *= rpc/proto/gencc
INCLUDEPATH *= rpc/proto/gencc
!win32 {
# unrecognized option
QMAKE_CFLAGS += -pthread
QMAKE_CXXFLAGS += -pthread
}
LIBS += -lprotobuf -lpthread
win32 {
DEPENDPATH += $$LIBS_DIR/include/protobuf
INCLUDEPATH += $$LIBS_DIR/include/protobuf
}
macx {
PROTOPATH = ../../../protobuf-2.4.1
INCLUDEPATH += $${PROTOPATH}/src
}
}
win32 {
# must be added after ssh
LIBS += -lcrypto -lws2_32 -lgdi32
}

View File

@ -58,6 +58,7 @@ void generatePasswordHash() ;
#include <stdarg.h>
#include "api/ApiServerMHD.h"
#include "api/RsControlModule.h"
#include "TerminalApiClient.h"
#endif
/* Basic instructions for running libretroshare as background thread.
@ -92,29 +93,35 @@ int main(int argc, char **argv)
std::cerr << args.usage() << std::endl;
}
resource_api::ApiServer api;
resource_api::RsControlModule ctrl_mod(argc, argv, api.getStateTokenServer(), &api, true);
api.addResourceHandler("control", dynamic_cast<resource_api::ResourceRouter*>(&ctrl_mod), &resource_api::RsControlModule::handleRequest);
resource_api::ApiServerMHD* httpd = 0;
if(httpPort != 0)
{
resource_api::ApiServerMHD httpd;
if(!httpd.configure(docroot, httpPort, listenAddress, allowAllIps))
httpd = new resource_api::ApiServerMHD(&api);
if(!httpd->configure(docroot, httpPort, listenAddress, allowAllIps))
{
std::cerr << "Failed to configure the http server. Check your parameters." << std::endl;
return 1;
}
resource_api::RsControlModule ctrl_mod(argc, argv, httpd.getApiServer().getStateTokenServer(), &httpd.getApiServer(), true);
httpd.getApiServer().addResourceHandler("control", dynamic_cast<resource_api::ResourceRouter*>(&ctrl_mod), &resource_api::RsControlModule::handleRequest);
httpd.start();
while(ctrl_mod.processShouldExit() == false)
{
usleep(20*1000);
}
httpd.stop();
return 0;
httpd->start();
}
resource_api::TerminalApiClient tac(&api);
while(ctrl_mod.processShouldExit() == false)
{
usleep(20*1000);
}
if(httpd)
{
httpd->stop();
delete httpd;
}
return 0;
#endif
/* Retroshare startup is configured using an RsInit object.