From bb10b6b4007a3e91b30d16f27caaeb8c86b65e0c Mon Sep 17 00:00:00 2001 From: drbob Date: Mon, 20 Aug 2012 14:59:41 +0000 Subject: [PATCH] Added first version of RPC system for external control of retroshare-nogui. The protocol message format is as follows: [HEADER: 16 bytes: 4 x Network Order uint32_t][ VARIABLE LENGTH BODY ] [ MAGIC_CODE ] [ MSG_ID ] [ REQ_ID ] [ BODY_SIZE ] [ ........ BODY ......... ] MagicCode = 0x137f0001 ... this will be incremented for new versions of the protocol. MsgID = Corresponds to the format of the Body. ReqID = Generated by Requester, Returned in Response, make sure its unique. (undefined behaviour for duplicates) BodySize = Byte Length of Body. The Body will consist of a protobuf encoded message. For the moment, the RPC server just ECHOs the request back to the sender - for testing purposes. Usage: * Create SSH connection to retroshare-nogui. * Create Request Message(s), and send over SSH channel - You can send as meny requests as you want. * They will processed, and responses sent back (potentially in an arbitary order). Specific Changes here: * Modified rssshd to support arbitary recv/send applications. (interface is RpcComms). * Added rpc directory, with server, setup and echo service. * Modified Menu System to use the new interface to rssshd * Wrote new matching interface for Terminal Usage. - NOTE: Strange BUG in Terminal version.... causes stderr to disappear. TODO. * Added -C commandline option to switch on RPC system. This is the first version - so I expect there will be bugs. Please report for a prompt fix! git-svn-id: http://svn.code.sf.net/p/retroshare/code/branches/v0.5-gxs-b1@5444 b45a01b8-16f6-495d-af2f-9b41ad6348cc --- retroshare-nogui/src/menu/menu.cc | 99 +++++++- retroshare-nogui/src/menu/menu.h | 56 ++++- retroshare-nogui/src/menu/menus.cc | 22 ++ retroshare-nogui/src/menu/menus.h | 22 ++ retroshare-nogui/src/menu/stdiocomms.cc | 171 +++++++++++++ retroshare-nogui/src/menu/stdiocomms.h | 57 +++++ retroshare-nogui/src/retroshare-nogui.pro | 28 ++- retroshare-nogui/src/retroshare.cc | 54 +++- retroshare-nogui/src/rpc/rpc.cc | 289 ++++++++++++++++++++++ retroshare-nogui/src/rpc/rpc.h | 71 ++++++ retroshare-nogui/src/rpc/rpcecho.cc | 40 +++ retroshare-nogui/src/rpc/rpcecho.h | 38 +++ retroshare-nogui/src/rpc/rpcserver.cc | 227 +++++++++++++++++ retroshare-nogui/src/rpc/rpcserver.h | 110 ++++++++ retroshare-nogui/src/rpc/rpcsetup.cc | 43 ++++ retroshare-nogui/src/rpc/rpcsetup.h | 34 +++ retroshare-nogui/src/rpcsystem.h | 61 +++++ retroshare-nogui/src/rstermserver.h | 13 - retroshare-nogui/src/ssh/rssshd.cc | 202 +++++++++++++-- retroshare-nogui/src/ssh/rssshd.h | 47 ++-- 20 files changed, 1612 insertions(+), 72 deletions(-) create mode 100644 retroshare-nogui/src/menu/stdiocomms.cc create mode 100644 retroshare-nogui/src/menu/stdiocomms.h create mode 100644 retroshare-nogui/src/rpc/rpc.cc create mode 100644 retroshare-nogui/src/rpc/rpc.h create mode 100644 retroshare-nogui/src/rpc/rpcecho.cc create mode 100644 retroshare-nogui/src/rpc/rpcecho.h create mode 100644 retroshare-nogui/src/rpc/rpcserver.cc create mode 100644 retroshare-nogui/src/rpc/rpcserver.h create mode 100644 retroshare-nogui/src/rpc/rpcsetup.cc create mode 100644 retroshare-nogui/src/rpc/rpcsetup.h create mode 100644 retroshare-nogui/src/rpcsystem.h delete mode 100644 retroshare-nogui/src/rstermserver.h diff --git a/retroshare-nogui/src/menu/menu.cc b/retroshare-nogui/src/menu/menu.cc index 504558837..bfe55e048 100644 --- a/retroshare-nogui/src/menu/menu.cc +++ b/retroshare-nogui/src/menu/menu.cc @@ -1,3 +1,25 @@ +/* + * RetroShare External Interface. + * + * Copyright 2012-2012 by Robert Fernie. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ #include "menu/menu.h" #include @@ -8,6 +30,8 @@ #include "util/rsstring.h" +#define MENU_DEBUG 1 + /********************************************************** * Menu Base Interface. */ @@ -18,29 +42,89 @@ void MenuInterface::reset() mBase->reset(); mCurrentMenu = mBase; mInputRequired = false; + mUpdateTime = 0; } -int MenuInterface::tick(bool haveInput, char keypress, std::string &output) + + +int MenuInterface::tick() { - if (!haveInput) +#ifdef MENU_DEBUG + std::cerr << "MenuInterface::tick()"; + std::cerr << std::endl; +#endif // MENU_DEBUG + + /* try to read a char */ + bool haveInput = false; + uint8_t keypress; + std::string output; + + int read = mComms->recv(&keypress, 1); +#ifdef MENU_DEBUG + std::cerr << "MenuInterface::tick() read " << read << " bytes"; + std::cerr << std::endl; +#endif // MENU_DEBUG + + if (read == 0) { + haveInput = false; /* make a harmless key */ keypress = ' '; } - - if ((mInputRequired) && (!haveInput)) + else if (read == 1) { - return 1; + haveInput = true; + } + else + { + /* error, NON BLOCKING is handled by recv returning 0 */ + mComms->error("Bad Input"); + return -1; + } + + + /**** Main logic bit ****/ + /**** slow down the updates / refresh ****/ + + time_t now = time(NULL); +#define UPDATE_TIME 5 + if (!haveInput) + { + // If Input is Required, + if (mInputRequired) + { + std::cerr << "MenuInterface::tick() No Input & Required-No Output"; + std::cerr << std::endl; + return 0; + } + + // Output will just almost the same, so occasionally. + if (now < mUpdateTime + UPDATE_TIME) + { + std::cerr << "MenuInterface::tick() No Input-Slow Update"; + std::cerr << std::endl; + return 0; + } + + std::cerr << "MenuInterface::tick() No Input - but doing update."; + std::cerr << std::endl; } uint32_t rt = process(keypress, mDrawFlags, output); mInputRequired = (rt == MENU_PROCESS_NEEDDATA); + mUpdateTime = now; if (rt == MENU_PROCESS_QUIT) { return -1; } - return 1; + + if (output.size() > 0) + { + mComms->send(output); + } + + return (haveInput); } @@ -168,6 +252,9 @@ uint32_t MenuInterface::process(char key, uint32_t drawFlags, std::string &buffe return MENU_PROCESS_NONE; } + + + uint32_t MenuInterface::drawHeader(uint32_t drawFlags, std::string &buffer) { buffer += "=======================================================\r\n"; diff --git a/retroshare-nogui/src/menu/menu.h b/retroshare-nogui/src/menu/menu.h index 4d10c762a..0feaec1b5 100644 --- a/retroshare-nogui/src/menu/menu.h +++ b/retroshare-nogui/src/menu/menu.h @@ -1,3 +1,28 @@ +/* + * RetroShare External Interface. + * + * Copyright 2012-2012 by Robert Fernie. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ + + + #ifndef RSNOGUI_MENU_H #define RSNOGUI_MENU_H @@ -7,7 +32,7 @@ #include #include -#include "rstermserver.h" // generic processing command. +#include "rpcsystem.h" // generic processing command. #define MENU_PROCESS_MASK 0x0fff @@ -172,7 +197,7 @@ protected: }; - +#if 0 class MenuInterface: public RsTermServer { public: @@ -193,5 +218,32 @@ private: bool mInputRequired; }; +#endif + + +class MenuInterface: public RpcSystem +{ +public: + + MenuInterface(RpcComms *c, Menu *b, uint32_t drawFlags) + :mComms(c), mCurrentMenu(b), mBase(b), mDrawFlags(drawFlags), mInputRequired(false) { return; } + + uint32_t process(char key, uint32_t drawFlags, std::string &buffer); + uint32_t drawHeader(uint32_t drawFlags, std::string &buffer); + + // RsSystem Interface. + virtual void reset(); + virtual int tick(); + + +private: + RpcComms *mComms; + Menu *mCurrentMenu; + Menu *mBase; + uint32_t mDrawFlags; + bool mInputRequired; + time_t mUpdateTime; +}; + #endif diff --git a/retroshare-nogui/src/menu/menus.cc b/retroshare-nogui/src/menu/menus.cc index f783abc66..1613228be 100644 --- a/retroshare-nogui/src/menu/menus.cc +++ b/retroshare-nogui/src/menu/menus.cc @@ -1,3 +1,25 @@ +/* + * RetroShare External Interface. + * + * Copyright 2012-2012 by Robert Fernie. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ #include #include diff --git a/retroshare-nogui/src/menu/menus.h b/retroshare-nogui/src/menu/menus.h index 44806a013..b276eda57 100644 --- a/retroshare-nogui/src/menu/menus.h +++ b/retroshare-nogui/src/menu/menus.h @@ -1,3 +1,25 @@ +/* + * RetroShare External Interface. + * + * Copyright 2012-2012 by Robert Fernie. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ #include "menu/menu.h" #include diff --git a/retroshare-nogui/src/menu/stdiocomms.cc b/retroshare-nogui/src/menu/stdiocomms.cc new file mode 100644 index 000000000..08d1abb76 --- /dev/null +++ b/retroshare-nogui/src/menu/stdiocomms.cc @@ -0,0 +1,171 @@ +/* + * RetroShare External Interface. + * + * Copyright 2012-2012 by Robert Fernie. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ + +#include "menu/stdiocomms.h" + +#include +#include +#include +#include +#include + + +StdioComms::StdioComms(int infd, int outfd) + :mIn(infd), mOut(outfd) +{ +#if 1 +// THIS Code is strange... +// It seems to mess up stderr. +// But if you redirect it -> is comes out fine. Very Weird. +// HELP!!! + + std::cerr << "StdioComms() STDERR msg 0"; + std::cerr << std::endl; + const int fcflags = fcntl(mIn,F_GETFL); + if (fcflags < 0) + { + std::cerr << "StdioComms() ERROR getting fcntl FLAGS"; + std::cerr << std::endl; + exit(1); + } + if (fcntl(mIn,F_SETFL,fcflags | O_NONBLOCK) <0) + { + std::cerr << "StdioComms() ERROR setting fcntl FLAGS"; + std::cerr << std::endl; + exit(1); + } + std::cerr << "StdioComms() STDERR msg 1"; + std::cerr << std::endl; +#endif +} + + +int StdioComms::isOkay() +{ + return 1; +} + + +int StdioComms::error(std::string msg) +{ + std::cerr << "StdioComms::error(" << msg << ")"; + std::cerr << std::endl; + return 1; +} + + + +int StdioComms::recv_ready() +{ + /* should be proper poll / select! - but we don't use this at the moment */ + return 1; +} + + +int StdioComms::recv(uint8_t *buffer, int bytes) +{ + int size = read(mIn, buffer, bytes); + std::cerr << "StdioComms::recv() returned: " << size; + std::cerr << std::endl; + + if (size == -1) + { + std::cerr << "StdioComms::recv() ERROR: " << errno; + std::cerr << std::endl; + if (errno == EAGAIN) + { + return 0; // OKAY; + } + } + + return size; +} + + +int StdioComms::recv(std::string &buffer, int bytes) +{ + uint8_t tmpbuffer[bytes]; + int size = read(mIn, tmpbuffer, bytes); + for(int i = 0; i < size; i++) + { + buffer += tmpbuffer[i]; + } + return size; +} + + // these make it easier... +int StdioComms::recv_blocking(uint8_t *buffer, int bytes) +{ + int totalread = 0; + while(totalread < bytes) + { + int size = read(mIn, &(buffer[totalread]), bytes - totalread); + if (size < 0) + { + if (totalread) + break; // partial read. + else + return size; // error. + } + totalread += size; + usleep(1000); // minisleep - so we don't 100% CPU. + std::cerr << "StdioComms::recv_blocking() read so far: " << size; + std::cerr << " / " << totalread; + std::cerr << std::endl; + } + return totalread; +} + + +int StdioComms::recv_blocking(std::string &buffer, int bytes) +{ + uint8_t tmpbuffer[bytes]; + int size = recv_blocking(tmpbuffer, bytes); + + if (size < 0) + return size; // error. + + for(int i = 0; i < size; i++) + buffer += tmpbuffer[i]; + + return size; +} + + +int StdioComms::send(uint8_t *buffer, int bytes) +{ + write(mOut, buffer, bytes); + return bytes; +} + + +int StdioComms::send(const std::string &output) +{ + if (output.size() > 0) + { + write(mOut, output.c_str(), output.size()); + } + return output.size(); +} + + diff --git a/retroshare-nogui/src/menu/stdiocomms.h b/retroshare-nogui/src/menu/stdiocomms.h new file mode 100644 index 000000000..bad510d6c --- /dev/null +++ b/retroshare-nogui/src/menu/stdiocomms.h @@ -0,0 +1,57 @@ +/* + * RetroShare External Interface. + * + * Copyright 2012-2012 by Robert Fernie. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ + + + +#ifndef RS_STDIO_COMMS_H +#define RS_STDIO_COMMS_H + +#include "rpcsystem.h" + + + +class StdioComms: public RpcComms +{ +public: + StdioComms(int infd, int outfd); + + virtual int isOkay(); + virtual int error(std::string msg); + + virtual int recv_ready(); + virtual int recv(uint8_t *buffer, int bytes); + virtual int recv(std::string &buffer, int bytes); + + // these make it easier... + virtual int recv_blocking(uint8_t *buffer, int bytes); + virtual int recv_blocking(std::string &buffer, int bytes); + + virtual int send(uint8_t *buffer, int bytes); + virtual int send(const std::string &buffer); + +private: + int mIn, mOut; +}; + +#endif + diff --git a/retroshare-nogui/src/retroshare-nogui.pro b/retroshare-nogui/src/retroshare-nogui.pro index 0833bab5c..28621ebe0 100644 --- a/retroshare-nogui/src/retroshare-nogui.pro +++ b/retroshare-nogui/src/retroshare-nogui.pro @@ -142,18 +142,38 @@ sshserver { # INCLUDEPATH += ../../../lib/libssh-0.5.2/include/ -# LIBS += ../../../lib/libssh-0.5.2/build/src/libssh.a -# LIBS += ../../../lib/libssh-0.5.2/build/src/threads/libssh_threads.a -LIBS *= -lssh + LIBS += ../../../lib/libssh-0.5.2/build/src/libssh.a + LIBS += ../../../lib/libssh-0.5.2/build/src/threads/libssh_threads.a + #LIBS += -lssh + #LIBS += -lssh_threads HEADERS += ssh/rssshd.h SOURCES += ssh/rssshd.cc + # For the Menu System HEADERS += menu/menu.h \ menu/menus.h \ - rstermserver.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 } diff --git a/retroshare-nogui/src/retroshare.cc b/retroshare-nogui/src/retroshare.cc index 917511cce..b741966c6 100644 --- a/retroshare-nogui/src/retroshare.cc +++ b/retroshare-nogui/src/retroshare.cc @@ -44,7 +44,9 @@ #include "ssh/rssshd.h" #include "menu/menus.h" -#include "menu/menutest.h" +#include "menu/stdiocomms.h" + +#include "rpc/rpcsetup.h" #endif @@ -94,6 +96,7 @@ int main(int argc, char **argv) // set user/password for SSH. -L "user:pwdhash" // accept RSA Key Auth. -K "RsaPubKeyFile" // Terminal mode. -T + bool enableRpc = false; bool enableSsh = false; bool enableSshHtml = false; bool enableSshPwd = false; @@ -105,10 +108,14 @@ int main(int argc, char **argv) std::string sshRsaFile = ""; std::string sshPortStr = "7022"; - while((c = getopt(argc, argv,"hTL:P:K:GS::")) != -1) + while((c = getopt(argc, argv,"ChTL:P:K:GS::")) != -1) { switch(c) { + case 'C': + enableRpc = true; + strictCheck = false; + break; case 'S': enableSsh = true; if (optarg) @@ -153,6 +160,7 @@ int main(int argc, char **argv) std::cerr << "\t-S [port] Enable SSH Server, optionally specify port" << std::endl; std::cerr << "\t-L Specify SSH login user (default:user)" << std::endl; std::cerr << "\t-P Enable SSH login via Password" << std::endl; + std::cerr << "\t-C Enable RPC Protocol (requires -S too)" << std::endl; //std::cerr << "\t-K [rsapubkeyfile] Enable SSH login via RSA key" << std::endl; //std::cerr << "\t NB: Two Factor Auth, specify both -P & -K" << std::endl; std::cerr << std::endl; @@ -247,6 +255,13 @@ int main(int argc, char **argv) exit(1); } + if (enableRpc && (!enableSsh)) + { + std::cerr << "ERROR: RPC Mode (-C) requires SSH Server (-S) enabled"; + std::cerr << std::endl; + exit(1); + } + /* parse -S, -L & -K parameters */ if (enableSshRsa) @@ -364,26 +379,39 @@ int main(int argc, char **argv) #ifdef RS_SSH_SERVER uint32_t baseDrawFlags = 0; if (enableSshHtml) + { baseDrawFlags = MENU_DRAW_FLAGS_HTML; + } if (enableSsh) { - /* create menu system for SSH */ - Menu *baseMenu = CreateMenuStructure(notify); - MenuInterface *menuInterface = new MenuInterface(baseMenu, baseDrawFlags | MENU_DRAW_FLAGS_ECHO); - ssh->setTermServer(menuInterface); + if (enableRpc) + { + /* Build RPC Server */ + RpcMediator *med = CreateRpcSystem(ssh); + ssh->setRpcSystem(med); + ssh->setSleepPeriods(0.01, 0.1); + } + else + { + /* create menu system for SSH */ + Menu *baseMenu = CreateMenuStructure(notify); + MenuInterface *menuInterface = new MenuInterface(ssh, baseMenu, baseDrawFlags | MENU_DRAW_FLAGS_ECHO); + ssh->setRpcSystem(menuInterface); + ssh->setSleepPeriods(0.2, 1); + } ssh->start(); } - //MenuTest *menuTerminal = NULL; - RsConsole *menuTerminal = NULL; + MenuInterface *terminalMenu = NULL; if (enableTerminal) { /* Terminal Version */ + RpcComms *stdioComms = new StdioComms(fileno(stdin), fileno(stdout)); Menu *baseMenu = CreateMenuStructure(notify); - MenuInterface *menuInterface = new MenuInterface(baseMenu, baseDrawFlags | MENU_DRAW_FLAGS_NOQUIT); - menuTerminal = new RsConsole(menuInterface, fileno(stdin), fileno(stdout)); + terminalMenu = new MenuInterface(stdioComms, baseMenu, baseDrawFlags | MENU_DRAW_FLAGS_NOQUIT); + //menuTerminal = new RsConsole(menuInterface, fileno(stdin), fileno(stdout)); } @@ -400,9 +428,9 @@ int main(int argc, char **argv) int rt = 0; #ifdef RS_SSH_SERVER - if (menuTerminal) + if (terminalMenu) { - rt = menuTerminal->tick(); + rt = terminalMenu->tick(); } #endif @@ -417,6 +445,8 @@ int main(int argc, char **argv) #endif } + usleep(1000); + } return 1; } diff --git a/retroshare-nogui/src/rpc/rpc.cc b/retroshare-nogui/src/rpc/rpc.cc new file mode 100644 index 000000000..368baf22e --- /dev/null +++ b/retroshare-nogui/src/rpc/rpc.cc @@ -0,0 +1,289 @@ +/* + * RetroShare External Interface. + * + * Copyright 2012-2012 by Robert Fernie. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ + +#include "rpc/rpc.h" +#include "rpc/rpcserver.h" + +// This one is inside libretroshare (BAD)!!! +#include "serialiser/rsbaseserial.h" + +#include + +const uint32_t kMsgHeaderSize = 16; +const uint32_t kMsgMagicCode = 0x137f0001; // Arbitary + 0x0001 + +RpcMediator::RpcMediator(RpcComms *c) + :mComms(c), mServer(NULL) +{ + return; +} + +void RpcMediator::reset() +{ + mServer->reset(); +} + + +int RpcMediator::tick() +{ + bool worked = false; + if (recv()) + { + worked = true; + } + + if (mServer->checkPending()) + { + worked = true; + } + + if (worked) + return 1; + else + return 0; + return 0; +} + + +int RpcMediator::recv() +{ + int recvd = 0; + while(recv_msg()) + { + recvd = 1; + } + return recvd; +} + + +int RpcMediator::recv_msg() +{ + /* nothing in here needs a Mutex... */ + + if (!mComms->recv_ready()) + { + return 0; + } + + std::cerr << "RpcMediator::recv_msg() Data Ready"; + std::cerr << std::endl; + + /* read in data */ + uint8_t buffer[kMsgHeaderSize]; + uint32_t bufsize = kMsgHeaderSize; + uint32_t msg_id; + uint32_t req_id; + uint32_t msg_size; + std::string msg_body; + + std::cerr << "RpcMediator::recv_msg() get Header: " << bufsize; + std::cerr << " bytes" << std::endl; + + int read = mComms->recv_blocking(buffer, bufsize); + if (read != bufsize) + { + /* error */ + std::cerr << "RpcMediator::recv_msg() Error Reading Header: " << bufsize; + std::cerr << " bytes" << std::endl; + + mComms->error("Failed to Recv Header"); + return 0; + } + + if (!MsgPacker::deserialiseHeader(msg_id, req_id, msg_size, buffer, bufsize)) + { + /* error */ + std::cerr << "RpcMediator::recv_msg() Error Deserialising Header"; + std::cerr << std::endl; + + mComms->error("Failed to Deserialise Header"); + return 0; + } + + std::cerr << "RpcMediator::recv_msg() MsgId: " << msg_id; + std::cerr << " ReqId: " << req_id; + std::cerr << std::endl; + + std::cerr << "RpcMediator::recv_msg() get Body: " << msg_size; + std::cerr << " bytes" << std::endl; + + /* grab real size */ + read = mComms->recv_blocking(msg_body, msg_size); + if (read != msg_size) + { + /* error */ + std::cerr << "RpcMediator::recv_msg() Error Reading Body: " << bufsize; + std::cerr << " bytes" << std::endl; + + mComms->error("Failed to Recv MsgBody"); + return 0; + } + mServer->processMsg(msg_id, req_id, msg_body); + + return 1; +} + + +int RpcMediator::send(uint32_t msg_id, uint32_t req_id, const std::string &msg) + +{ + std::cerr << "RpcMediator::send(" << msg_id << "," << req_id << ", len("; + std::cerr << msg.size() << "))"; + std::cerr << std::endl; + + uint8_t buffer[kMsgHeaderSize]; + uint32_t bufsize = kMsgHeaderSize; + uint32_t msg_size = msg.size(); + + bool okay = MsgPacker::serialiseHeader(msg_id, req_id, msg_size, buffer, bufsize); + if (!okay) + { + std::cerr << "RpcMediator::send() SerialiseHeader Failed"; + std::cerr << std::endl; + /* error */ + return 0; + } + + if (!mComms->send(buffer, bufsize)) + { + std::cerr << "RpcMediator::send() Send Header Failed"; + std::cerr << std::endl; + /* error */ + mComms->error("Failed to Send Header"); + return 0; + } + + /* now send the body */ + if (!mComms->send(msg)) + { + std::cerr << "RpcMediator::send() Send Body Failed"; + std::cerr << std::endl; + /* error */ + mComms->error("Failed to Send Msg"); + return 0; + } + return 1; +} + + + + +/* Msg Packing */ +int MsgPacker::headersize() +{ + return kMsgHeaderSize; +} + +#if 0 +int MsgPacker::msgsize(Message *msg) +{ + /* */ + return 0; +} + +int MsgPacker::pktsize(Message *msg) +{ + /* */ + return headersize() + msgsize(); +} +#endif + +bool MsgPacker::serialiseHeader(uint32_t msg_id, uint32_t req_id, uint32_t msg_size, uint8_t *buffer, uint32_t bufsize) +{ + /* check size */ + if (bufsize < kMsgHeaderSize) + { + return false; + } + + /* pack the data (using libretroshare serialiser for now */ + void *data = buffer; + uint32_t offset = 0; + uint32_t size = bufsize; + + bool ok = true; + + /* 4 x uint32_t for header */ + ok &= setRawUInt32(data, size, &offset, kMsgMagicCode); + ok &= setRawUInt32(data, size, &offset, msg_id); + ok &= setRawUInt32(data, size, &offset, req_id); + ok &= setRawUInt32(data, size, &offset, msg_size); + + return ok; +} + + +bool MsgPacker::deserialiseHeader(uint32_t &msg_id, uint32_t &req_id, uint32_t &msg_size, uint8_t *buffer, uint32_t bufsize) +{ + /* check size */ + if (bufsize < kMsgHeaderSize) + { + return false; + } + + /* pack the data (using libretroshare serialiser for now */ + void *data = buffer; + uint32_t offset = 0; + uint32_t size = bufsize; + uint32_t magic_code; + + bool ok = true; + + /* 4 x uint32_t for header */ + ok &= getRawUInt32(data, size, &offset, &magic_code); + if (!ok) + { + std::cerr << "Failed to deserialise uint32_t(0)"; + std::cerr << std::endl; + } + ok &= getRawUInt32(data, size, &offset, &msg_id); + if (!ok) + { + std::cerr << "Failed to deserialise uint32_t(1)"; + std::cerr << std::endl; + } + ok &= getRawUInt32(data, size, &offset, &req_id); + if (!ok) + { + std::cerr << "Failed to deserialise uint32_t(2)"; + std::cerr << std::endl; + } + ok &= getRawUInt32(data, size, &offset, &msg_size); + if (!ok) + { + std::cerr << "Failed to deserialise uint32_t(3)"; + std::cerr << std::endl; + } + + ok &= (magic_code == kMsgMagicCode); + if (!ok) + { + std::cerr << "Failed to Match MagicCode"; + std::cerr << std::endl; + } + + return ok; +} + + + diff --git a/retroshare-nogui/src/rpc/rpc.h b/retroshare-nogui/src/rpc/rpc.h new file mode 100644 index 000000000..ff1817cd1 --- /dev/null +++ b/retroshare-nogui/src/rpc/rpc.h @@ -0,0 +1,71 @@ +/* + * RetroShare External Interface. + * + * Copyright 2012-2012 by Robert Fernie. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ + +#ifndef RPC_MEDIATOR_H +#define RPC_MEDIATOR_H + +/* + * Interface between RpcServer and RpcComms. + */ + +#include +#include + +#include "rpcsystem.h" + +class RpcServer; + +class RpcMediator: public RpcSystem +{ +public: + + RpcMediator(RpcComms *c); + void setRpcServer(RpcServer *s) { mServer = s; } /* Must only be called during setup */ + + // Overloaded from RpcSystem. +virtual void reset(); +virtual int tick(); + + int recv(); + int recv_msg(); + int send(uint32_t msg_id, uint32_t req_id, const std::string &msg); + +private: + RpcComms *mComms; + RpcServer *mServer; + +}; + + +/* Msg Packing */ +class MsgPacker +{ +public: + static int headersize(); + static bool serialiseHeader(uint32_t msg_id, uint32_t req_id, uint32_t msg_size, uint8_t *buffer, uint32_t bufsize); + static bool deserialiseHeader(uint32_t &msg_id, uint32_t &req_id, uint32_t &msg_size, uint8_t *buffer, uint32_t bufsize); +}; + + + +#endif /* RPC_MEDIATOR_H */ diff --git a/retroshare-nogui/src/rpc/rpcecho.cc b/retroshare-nogui/src/rpc/rpcecho.cc new file mode 100644 index 000000000..ff01ccaf8 --- /dev/null +++ b/retroshare-nogui/src/rpc/rpcecho.cc @@ -0,0 +1,40 @@ +/* + * RetroShare External Interface. + * + * Copyright 2012-2012 by Robert Fernie. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ + +#include "rpc/rpcecho.h" + +RpcEcho::RpcEcho(uint32_t serviceId) +:RpcQueueService(serviceId) +{ + return; +} + +int RpcEcho::processMsg(uint32_t msg_id, uint32_t req_id, const std::string &msg) +{ + /* */ + queueResponse(msg_id, req_id, msg); + return 1; +} + + + diff --git a/retroshare-nogui/src/rpc/rpcecho.h b/retroshare-nogui/src/rpc/rpcecho.h new file mode 100644 index 000000000..a72871382 --- /dev/null +++ b/retroshare-nogui/src/rpc/rpcecho.h @@ -0,0 +1,38 @@ +/* + * RetroShare External Interface. + * + * Copyright 2012-2012 by Robert Fernie. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ + + +#ifndef RS_RPC_ECHO_H +#define RS_RPC_ECHO_H + +#include "rpc/rpcserver.h" + +class RpcEcho: public RpcQueueService +{ +public: + RpcEcho(uint32_t serviceId); + virtual int processMsg(uint32_t msgId, uint32_t req_id, const std::string &msg); +}; + + +#endif /* RS_RPC_ECHO_H */ diff --git a/retroshare-nogui/src/rpc/rpcserver.cc b/retroshare-nogui/src/rpc/rpcserver.cc new file mode 100644 index 000000000..3392eaffa --- /dev/null +++ b/retroshare-nogui/src/rpc/rpcserver.cc @@ -0,0 +1,227 @@ +/* + * RetroShare External Interface. + * + * Copyright 2012-2012 by Robert Fernie. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ + +#include "rpc/rpcserver.h" + +#include "rpc/rpc.h" + +#include + +RpcServer::RpcServer(RpcMediator *med) + :mMediator(med), mRpcMtx("RpcMtx") +{ + +} + +void RpcServer::reset() +{ + std::cerr << "RpcServer::reset()" << std::endl; + { + RsStackMutex stack(mRpcMtx); /********** LOCKED MUTEX ***************/ + + std::list::iterator it; + for(it = mAllServices.begin(); it != mAllServices.end(); it++) + { + /* in mutex, but should be okay */ + (*it)->reset(); + } + + // clear existing queue. + mRpcQueue.clear(); + } + + return; +} + + +int RpcServer::addService(RpcService *service) +{ + RsStackMutex stack(mRpcMtx); /********** LOCKED MUTEX ***************/ + + mAllServices.push_back(service); + + return 1; +} + + +int RpcServer::processMsg(uint32_t msg_id, uint32_t req_id, const std::string &msg) +{ + std::cerr << "RpcServer::processMsg(" << msg_id << "," << req_id; + std::cerr << ", len(" << msg.size() << "))" << std::endl; + { + RsStackMutex stack(mRpcMtx); /********** LOCKED MUTEX ***************/ + + std::list::iterator it; + for(it = mAllServices.begin(); it != mAllServices.end(); it++) + { + int rt = (*it)->processMsg(msg_id, req_id, msg); + if (!rt) + continue; + + /* remember request */ + queueRequest_locked(msg_id, req_id, (*it)); + return 1; + } + } + + std::cerr << "RpcServer::processMsg() No service to accepted it - discard"; + std::cerr << std::endl; + return 0; +} + +int RpcServer::queueRequest_locked(uint32_t /* msgId */, uint32_t req_id, RpcService *service) +{ + std::cerr << "RpcServer::queueRequest_locked() req_id: " << req_id; + std::cerr << std::endl; + + RpcQueuedObj obj; + obj.mReqId = req_id; + obj.mService = service; + + mRpcQueue.push_back(obj); + + return 1; +} + + +bool RpcServer::checkPending() +{ + std::list msgsToSend; + bool someRemaining = false; + bool someToSend = false; + + { + RsStackMutex stack(mRpcMtx); /********** LOCKED MUTEX ***************/ + + std::list::iterator it; + for(it = mRpcQueue.begin(); it != mRpcQueue.end();) + { + uint32_t out_msg_id = 0; + uint32_t out_req_id = it->mReqId; + std::string out_msg; + if (it->mService->getResponse(out_msg_id, out_req_id, out_msg)) + { + std::cerr << "RpcServer::checkPending() Response: ("; + std::cerr << out_msg_id << "," << out_req_id; + std::cerr << ", len(" << out_msg.size() << "))"; + std::cerr << std::endl; + + /* store and send after queue is processed */ + RpcQueuedMsg msg; + msg.mMsgId = out_msg_id; + msg.mReqId = out_req_id; + msg.mMsg = out_msg; + + msgsToSend.push_back(msg); + + it = mRpcQueue.erase(it); + someToSend = true; + } + else + { + it++; + someRemaining = true; + } + } + } + + if (someToSend) + { + sendQueuedMsgs(msgsToSend); + } + + return someRemaining; +} + +bool RpcServer::sendQueuedMsgs(std::list &msgs) +{ + /* No need for lock, as mOut is the only accessed item - and that has own protection */ + + std::cerr << "RpcServer::sendQueuedMsg() " << msgs.size() << " to send"; + std::cerr << std::endl; + + std::list::iterator it; + for (it = msgs.begin(); it != msgs.end(); it++) + { + mMediator->send(it->mMsgId, it->mReqId, it->mMsg); + } + return true; +} + + + + + + + +RpcQueueService::RpcQueueService(uint32_t serviceId) +:RpcService(serviceId), mQueueMtx("RpcQueueService") +{ + return; +} + + +void RpcQueueService::reset() +{ + RsStackMutex stack(mQueueMtx); /********** LOCKED MUTEX ***************/ + + // clear existing queue. + mResponses.clear(); + return; +} + +int RpcQueueService::getResponse(uint32_t &msg_id, uint32_t &req_id, std::string &msg) +{ + RsStackMutex stack(mQueueMtx); /********** LOCKED MUTEX ***************/ + + std::map::iterator it; + + it = mResponses.find(req_id); + if (it == mResponses.end()) + { + return 0; + } + + msg_id = it->second.mMsgId; + msg = it->second.mMsg; + + mResponses.erase(it); + + return 1; +} + +int RpcQueueService::queueResponse(uint32_t msg_id, uint32_t req_id, const std::string &msg) +{ + RsStackMutex stack(mQueueMtx); /********** LOCKED MUTEX ***************/ + + RpcQueuedMsg qmsg; + qmsg.mMsgId = msg_id; + qmsg.mReqId = req_id; + qmsg.mMsg = msg; + + mResponses[req_id] = qmsg; + + return 1; +} + + diff --git a/retroshare-nogui/src/rpc/rpcserver.h b/retroshare-nogui/src/rpc/rpcserver.h new file mode 100644 index 000000000..061ad7842 --- /dev/null +++ b/retroshare-nogui/src/rpc/rpcserver.h @@ -0,0 +1,110 @@ +/* + * RetroShare External Interface. + * + * Copyright 2012-2012 by Robert Fernie. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ + + +#ifndef RS_RPC_SERVER_H +#define RS_RPC_SERVER_H + +#include +#include +#include +#include + +#include "util/rsthreads.h" + +/*** This can be overloaded for plugins + * Also allows a natural seperation of the full interface into sections. + */ + +class RpcQueuedMsg +{ +public: + uint32_t mMsgId; + uint32_t mReqId; + std::string mMsg; +}; + + +class RpcService +{ +public: + RpcService(uint32_t /* serviceId */ ) { return; } + virtual void reset() { return; } + virtual int msgsAccepted(std::list & /* msgIds */) { return 0; } /* not used at the moment */ + virtual int processMsg(uint32_t msgId, uint32_t req_id, const std::string &msg) = 0; /* returns 0 - not handled, > 0, accepted */ + virtual int getResponse(uint32_t &msgId, uint32_t &req_id, std::string &msg) = 0; /* 0 - not ready, > 0 heres the response */ +}; + + +/* Implements a Queue for quick implementation of Instant Response Services */ +class RpcQueueService: public RpcService +{ +public: + RpcQueueService(uint32_t serviceId); +virtual void reset(); +virtual int getResponse(uint32_t &msgId, uint32_t &req_id, std::string &msg); + +protected: + int queueResponse(uint32_t msgId, uint32_t req_id, const std::string &msg); +private: + RsMutex mQueueMtx; + std::map mResponses; +}; + + +/* For Tracking responses */ +class RpcQueuedObj +{ +public: + uint32_t mReqId; + RpcService *mService; +}; + + +class RpcMediator; + +class RpcServer +{ + +public: + RpcServer(RpcMediator *med); + int addService(RpcService *service); + int processMsg(uint32_t msgId, uint32_t req_id, const std::string &msg); + bool checkPending(); + + void reset(); + +private: + bool sendQueuedMsgs(std::list &msgs); + int queueRequest_locked(uint32_t msgId, uint32_t req_id, RpcService *service); + + RpcMediator *mMediator; + + RsMutex mRpcMtx; + + std::list mRpcQueue; + std::list mAllServices; +}; + + +#endif /* RS_RPC_SERVER_H */ diff --git a/retroshare-nogui/src/rpc/rpcsetup.cc b/retroshare-nogui/src/rpc/rpcsetup.cc new file mode 100644 index 000000000..38b8a9c5b --- /dev/null +++ b/retroshare-nogui/src/rpc/rpcsetup.cc @@ -0,0 +1,43 @@ +/* + * RetroShare External Interface. + * + * Copyright 2012-2012 by Robert Fernie. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ + +#include "rpc/rpcsetup.h" +#include "rpc/rpcserver.h" + +#include "rpc/rpcecho.h" + + +RpcMediator *CreateRpcSystem(RpcComms *comms) +{ + RpcMediator *med = new RpcMediator(comms); + RpcServer *server = new RpcServer(med); + + /* add services */ + RpcEcho *echo = new RpcEcho(1); + server->addService(echo); + + med->setRpcServer(server); + + return med; +} + diff --git a/retroshare-nogui/src/rpc/rpcsetup.h b/retroshare-nogui/src/rpc/rpcsetup.h new file mode 100644 index 000000000..4d847f089 --- /dev/null +++ b/retroshare-nogui/src/rpc/rpcsetup.h @@ -0,0 +1,34 @@ +/* + * RetroShare External Interface. + * + * Copyright 2012-2012 by Robert Fernie. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ + + +#ifndef RPC_SETUP_H +#define RPC_SETUP_H + + +#include "rpc/rpc.h" + +RpcMediator *CreateRpcSystem(RpcComms *comms); + +#endif + diff --git a/retroshare-nogui/src/rpcsystem.h b/retroshare-nogui/src/rpcsystem.h new file mode 100644 index 000000000..db81d5702 --- /dev/null +++ b/retroshare-nogui/src/rpcsystem.h @@ -0,0 +1,61 @@ +/* + * RetroShare External Interface. + * + * Copyright 2012-2012 by Robert Fernie. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ + + +#ifndef RS_RPC_SYSTEM_H +#define RS_RPC_SYSTEM_H + +#include +#include + +class RpcComms +{ +public: + virtual int isOkay() = 0; + virtual int error(std::string msg) = 0; + + virtual int recv_ready() = 0; + virtual int recv(uint8_t *buffer, int bytes) = 0; + virtual int recv(std::string &buffer, int bytes) = 0; + + // these make it easier... + virtual int recv_blocking(uint8_t *buffer, int bytes) = 0; + virtual int recv_blocking(std::string &buffer, int bytes) = 0; + + virtual int send(uint8_t *buffer, int bytes) = 0; + virtual int send(const std::string &buffer) = 0; + + virtual int setSleepPeriods(float /* busy */, float /* idle */) { return 0; } +}; + + +class RpcSystem +{ +public: + /* this must be regularly ticked to update the display */ + virtual void reset() = 0; + virtual int tick() = 0; +}; + + +#endif // RS_RPC_SERVER_H diff --git a/retroshare-nogui/src/rstermserver.h b/retroshare-nogui/src/rstermserver.h deleted file mode 100644 index 2658e8c93..000000000 --- a/retroshare-nogui/src/rstermserver.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef RS_TERM_SERVER_H -#define RS_TERM_SERVER_H - -class RsTermServer -{ -public: - /* this must be regularly ticked to update the display */ - virtual void reset() = 0; - virtual int tick(bool haveInput, char keypress, std::string &output) = 0; -}; - - -#endif // RS_TERM_SERVER_H diff --git a/retroshare-nogui/src/ssh/rssshd.cc b/retroshare-nogui/src/ssh/rssshd.cc index b75c32e89..195d85af0 100644 --- a/retroshare-nogui/src/ssh/rssshd.cc +++ b/retroshare-nogui/src/ssh/rssshd.cc @@ -26,6 +26,8 @@ clients must be made or how a client should react. #define RSSSHD_STATE_NULL 0 #define RSSSHD_STATE_INIT_OK 1 +#define RSSSHD_STATE_CONNECTED 2 +#define RSSSHD_STATE_ERROR 3 RsSshd *rsSshd = NULL; // External Reference Variable. @@ -54,8 +56,9 @@ RsSshd::RsSshd(std::string portStr) mState = RSSSHD_STATE_NULL; mBindState = 0; - mTermServer = NULL; + mRpcSystem = NULL; + setSleepPeriods(0.01, 0.1); return; } @@ -104,6 +107,7 @@ void RsSshd::run() std::cerr << "RsSshd::run() setup mSession => interactive"; std::cerr << std::endl; + mState = RSSSHD_STATE_CONNECTED; interactive(); } else @@ -195,7 +199,7 @@ int RsSshd::interactive() std::cerr << "RsSshd::interactive()"; std::cerr << std::endl; - doTermServer(); + doRpcSystem(); //doEcho(); return 1; } @@ -318,7 +322,36 @@ int RsSshd::setupShell() return 1; } +// CLEANUP +int RsSshd::cleanupSession() +{ + std::cerr << "RsSshd::cleanupSession()"; + std::cerr << std::endl; + ssh_disconnect(mSession); + ssh_free(mSession); + return 1; +} + + +int RsSshd::cleanupAll() +{ + std::cerr << "RsSshd::cleanupAll()"; + std::cerr << std::endl; + + cleanupSession(); + if (mBindState) + { + ssh_bind_free(mBind); + mBindState = 0; + } + ssh_finalize(); + return 1; +} + + + +// Various Operating Modes. int RsSshd::doEcho() { std::cerr << "RsSshd::doEcho()"; @@ -354,13 +387,14 @@ int RsSshd::doEcho() } -int RsSshd::setTermServer(RsTermServer *s) +int RsSshd::setRpcSystem(RpcSystem *s) { - mTermServer = s; + mRpcSystem = s; return 1; } +#if 0 int RsSshd::doTermServer() { @@ -422,33 +456,161 @@ int RsSshd::doTermServer() return 1; } +#endif -int RsSshd::cleanupSession() + +int RsSshd::doRpcSystem() { - std::cerr << "RsSshd::cleanupSession()"; + std::cerr << "RsSshd::doRpcSystem()"; std::cerr << std::endl; - ssh_disconnect(mSession); - ssh_free(mSession); - return 1; + if (!mRpcSystem) + { + std::cerr << "RsSshd::doRpcSystem() ERROR Not Set"; + std::cerr << std::endl; + return 0; + } + + mRpcSystem->reset(); // clear everything for new user. + + bool okay = true; + while(okay) + { + int rt = mRpcSystem->tick(); + if (rt) + { + // Working - so small sleep, + usleep(mBusyUSleep); + } + else + { + // No work cycle, longer break. + usleep(mIdleUSleep); + } + + if (rt < 0) + { + okay = false; // exit. + } + + if (!isOkay()) + { + okay = false; + } + } + + std::cerr << "RsSshd::doRpcSystem() Finished"; + std::cerr << std::endl; + + return 1; +} + +// RpcComms Interface.... +int RsSshd::isOkay() +{ + return (mState == RSSSHD_STATE_CONNECTED); } -int RsSshd::cleanupAll() +int RsSshd::error(std::string msg) { - std::cerr << "RsSshd::cleanupAll()"; + std::cerr << "RsSshd::error(" << msg << ")"; std::cerr << std::endl; - cleanupSession(); - if (mBindState) - { - ssh_bind_free(mBind); - mBindState = 0; - } - ssh_finalize(); - return 1; + mState = RSSSHD_STATE_ERROR; + return 1; } + +int RsSshd::recv_ready() +{ + int bytes = ssh_channel_poll(mChannel, 0); + return bytes; +} + + +int RsSshd::recv(uint8_t *buffer, int bytes) +{ +#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,5,0) + int size = ssh_channel_read_nonblocking(mChannel, buffer, bytes, 0); +#else + int size = channel_read_nonblocking(mChannel, buffer, bytes, 0); +#endif + return size; +} + + +int RsSshd::recv(std::string &buffer, int bytes) +{ + char input[bytes]; +#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,5,0) + int size = ssh_channel_read_nonblocking(mChannel, input, bytes, 0); +#else + int size = channel_read_nonblocking(mChannel, input, bytes, 0); +#endif + for(int i = 0; i < size; i++) + { + buffer += input[i]; + } + return size; +} + + +int RsSshd::recv_blocking(uint8_t *buffer, int bytes) +{ +#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,5,0) + int size = ssh_channel_read(mChannel, buffer, bytes, 0); +#else + int size = channel_read(mChannel, buffer, bytes, 0); +#endif + return size; +} + + +int RsSshd::recv_blocking(std::string &buffer, int bytes) +{ + char input[bytes]; +#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,5,0) + int size = ssh_channel_read(mChannel, input, bytes, 0); +#else + int size = channel_read(mChannel, input, bytes, 0); +#endif + for(int i = 0; i < size; i++) + { + buffer += input[i]; + } + return size; +} + +int RsSshd::send(uint8_t *buffer, int bytes) +{ +#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,5,0) + ssh_channel_write(mChannel, buffer, bytes); +#else + channel_write(mChannel, buffer, bytes); +#endif + return 1; +} + +int RsSshd::send(const std::string &buffer) +{ +#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,5,0) + ssh_channel_write(mChannel, buffer.c_str(), buffer.size()); +#else + channel_write(mChannel, buffer.c_str(), buffer.size()); +#endif + return 1; +} + +int RsSshd::setSleepPeriods(float busy, float idle) +{ + mBusyUSleep = busy * 1000000; + mIdleUSleep = idle * 1000000; + return 1; +} + + + /***********************************************************************************/ /* PASSWORDS */ /***********************************************************************************/ @@ -682,7 +844,7 @@ int CheckPasswordHash(std::string pwdHashRadix64, std::string password) char *buf = NULL; size_t len = 1024; Radix64::decode(pwdHashRadix64, buf, len); - for(int i = 0; (i < len) && (i < 1024); i++) + for(unsigned int i = 0; (i < len) && (i < 1024); i++) { output[i] = buf[i]; } diff --git a/retroshare-nogui/src/ssh/rssshd.h b/retroshare-nogui/src/ssh/rssshd.h index ef2be2709..2f0a87d36 100644 --- a/retroshare-nogui/src/ssh/rssshd.h +++ b/retroshare-nogui/src/ssh/rssshd.h @@ -34,7 +34,7 @@ clients must be made or how a client should react. #include #include -#include "rstermserver.h" +#include "rpcsystem.h" #ifndef KEYS_FOLDER #ifdef _WIN32 @@ -66,24 +66,36 @@ int CheckPasswordHash(std::string pwdHashRadix64, std::string password); int GeneratePasswordHash(std::string saltBin, std::string password, std::string &pwdHashRadix64); int GenerateSalt(std::string &saltBin); -class RsSshd: public RsThread +class RsSshd: public RsThread, public RpcComms { public: -int adduserpwdhash(std::string username, std::string hash); -#ifdef ALLOW_CLEARPWDS -int adduser(std::string username, std::string password); -#endif // ALLOW_CLEARPWDS - - - -virtual void run(); /* overloaded from RsThread => called once the thread is started */ - // NB: This must be called EARLY before all the threads are launched. static RsSshd *InitRsSshd(std::string portstr, std::string rsakeyfile); - // Terminal Handling! -int setTermServer(RsTermServer *s); + + // Interface. +int setRpcSystem(RpcSystem *s); +int adduserpwdhash(std::string username, std::string hash); + + // RsThreads Interface. + virtual void run(); /* called once the thread is started */ + + // RsComms Interface. + virtual int isOkay(); + virtual int error(std::string msg); + + virtual int recv_ready(); + + virtual int recv(uint8_t *buffer, int bytes); + virtual int recv(std::string &buffer, int bytes); + virtual int recv_blocking(uint8_t *buffer, int bytes); + virtual int recv_blocking(std::string &buffer, int bytes); + + virtual int send(uint8_t *buffer, int bytes); + virtual int send(const std::string &buffer); + + virtual int setSleepPeriods(float busy, float idle); private: RsSshd(std::string portStr); /* private constructor => so can only create with */ @@ -102,7 +114,8 @@ int setupShell(); int doEcho(); // Terminal Handling! -int doTermServer(); +//int doTermServer(); +int doRpcSystem(); int cleanupSession(); int cleanupAll(); @@ -117,6 +130,9 @@ int auth_password_basic(char *name, char *pwd); // DATA. RsMutex mSshMtx; + + uint32_t mBusyUSleep; + uint32_t mIdleUSleep; uint32_t mState; uint32_t mBindState; @@ -126,7 +142,8 @@ int auth_password_basic(char *name, char *pwd); ssh_bind mBind; ssh_channel mChannel; - RsTermServer *mTermServer; + RpcSystem *mRpcSystem; + #ifdef ALLOW_CLEARPWDS std::map mPasswords; #endif // ALLOW_CLEARPWDS