diff --git a/libretroshare/src/pqi/pqifdbin.h b/libretroshare/src/pqi/pqifdbin.h index d88a470fa..5fa82df8e 100644 --- a/libretroshare/src/pqi/pqifdbin.h +++ b/libretroshare/src/pqi/pqifdbin.h @@ -48,6 +48,7 @@ public: int netstatus() override; int isactive() override; bool moretoread(uint32_t usec) override; + bool moretowrite(uint32_t usec) { return mTotalOutBufferBytes > 0 ; } bool cansend(uint32_t usec) override; int close() override; diff --git a/libretroshare/src/retroshare/rsinit.h b/libretroshare/src/retroshare/rsinit.h index c421755cc..ba2c33765 100644 --- a/libretroshare/src/retroshare/rsinit.h +++ b/libretroshare/src/retroshare/rsinit.h @@ -220,6 +220,7 @@ public: static void setAutoLogin(bool autoLogin); static bool RsClearAutoLogin() ; + static std::string executablePath() ; private: /** @brief Lock profile directory * param[in] accountDir account directory to lock diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index a49111021..cad6d3ae7 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -146,6 +146,7 @@ struct RsInitConfig {} RsFileHash main_executable_hash; + std::string mainExecutablePath; #ifdef WINDOWS_SYS bool portable; @@ -307,6 +308,7 @@ int RsInit::InitRetroShare(const RsConfigOptions& conf) rsInitConfig->optBaseDir = conf.optBaseDir; rsInitConfig->jsonApiPort = conf.jsonApiPort; rsInitConfig->jsonApiBindAddress = conf.jsonApiBindAddress; + rsInitConfig->mainExecutablePath = conf.main_executable_path; #ifdef PTW32_STATIC_LIB // for static PThreads under windows... we need to init the library... @@ -1932,6 +1934,10 @@ int RsServer::StartupRetroShare() return 1; } +std::string RsInit::executablePath() +{ + return rsInitConfig->mainExecutablePath; +} bool RsInit::startAutoTor() { std::cerr << "(II) node is an automated Tor node => launching Tor auto-configuration." << std::endl; diff --git a/libretroshare/src/tor/AddOnionCommand.cpp b/libretroshare/src/tor/AddOnionCommand.cpp index 9e8238c14..393f72541 100644 --- a/libretroshare/src/tor/AddOnionCommand.cpp +++ b/libretroshare/src/tor/AddOnionCommand.cpp @@ -65,7 +65,7 @@ ByteArray AddOnionCommand::build() out += " Port="; out += QByteArray::number(target.servicePort); out += ","; - out += target.targetAddress.toString().toLatin1(); + out += target.targetAddress; out += ":"; out += QByteArray::number(target.targetPort); } diff --git a/libretroshare/src/tor/HiddenService.cpp b/libretroshare/src/tor/HiddenService.cpp index 488f7db89..cb9adfa8a 100644 --- a/libretroshare/src/tor/HiddenService.cpp +++ b/libretroshare/src/tor/HiddenService.cpp @@ -83,7 +83,7 @@ void HiddenService::addTarget(const Target &target) m_targets.push_back(target); } -void HiddenService::addTarget(quint16 servicePort, QHostAddress targetAddress, quint16 targetPort) +void HiddenService::addTarget(quint16 servicePort, std::string targetAddress, quint16 targetPort) { Target t = { targetAddress, servicePort, targetPort }; m_targets.push_back(t); diff --git a/libretroshare/src/tor/HiddenService.h b/libretroshare/src/tor/HiddenService.h index b5c2b3281..2b69915f6 100644 --- a/libretroshare/src/tor/HiddenService.h +++ b/libretroshare/src/tor/HiddenService.h @@ -34,7 +34,6 @@ #define HIDDENSERVICE_H #include -#include #include "CryptoKey.h" #include "bytearray.h" @@ -63,7 +62,7 @@ class HiddenService : public QObject public: struct Target { - QHostAddress targetAddress; + std::string targetAddress; quint16 servicePort, targetPort; }; @@ -90,7 +89,7 @@ public: const std::list &targets() const { return m_targets; } void addTarget(const Target &target); - void addTarget(quint16 servicePort, QHostAddress targetAddress, quint16 targetPort); + void addTarget(quint16 servicePort, std::string targetAddress, quint16 targetPort); private slots: void servicePublished(); diff --git a/libretroshare/src/tor/TorControl.cpp b/libretroshare/src/tor/TorControl.cpp index 650232ab1..74fe41138 100644 --- a/libretroshare/src/tor/TorControl.cpp +++ b/libretroshare/src/tor/TorControl.cpp @@ -83,11 +83,11 @@ public: TorControl *q; TorControlSocket *socket; - QHostAddress torAddress; + std::string torAddress; std::string errorMessage; std::string torVersion; ByteArray authPassword; - QHostAddress socksAddress; + std::string socksAddress; QList services; quint16 controlPort, socksPort; TorControl::Status status; @@ -282,7 +282,7 @@ void TorControl::setAuthPassword(const ByteArray &password) d->authPassword = password; } -void TorControl::connect(const QHostAddress &address, quint16 port) +void TorControl::connect(const std::string &address, quint16 port) { if (status() > Connecting) { @@ -294,9 +294,9 @@ void TorControl::connect(const QHostAddress &address, quint16 port) d->controlPort = port; d->setTorStatus(TorUnknown); - bool b = d->socket->blockSignals(true); - d->socket->abort(); - d->socket->blockSignals(b); + //bool b = d->socket->blockSignals(true); + d->socket->fullstop(); + //d->socket->blockSignals(b); d->setStatus(Connecting); d->socket->connectToHost(address, port); @@ -304,8 +304,9 @@ void TorControl::connect(const QHostAddress &address, quint16 port) void TorControl::reconnect() { - Q_ASSERT(!d->torAddress.isNull() && d->controlPort); - if (d->torAddress.isNull() || !d->controlPort || status() >= Connecting) + assert(!d->torAddress.empty() && d->controlPort); + + if (d->torAddress.empty() || !d->controlPort || status() >= Connecting) return; d->setStatus(Connecting); @@ -332,7 +333,7 @@ void TorControlPrivate::authenticateReply() TorControlCommand *clientEvents = new TorControlCommand; connect(clientEvents, &TorControlCommand::replyLine, this, &TorControlPrivate::statusEvent); - socket->registerEvent("STATUS_CLIENT", clientEvents); + socket->registerEvent(ByteArray("STATUS_CLIENT"), clientEvents); getTorInfo(); publishServices(); @@ -400,11 +401,15 @@ void TorControlPrivate::protocolInfoReply() std::string cookieError; torCtrlDebug() << "torctrl: Using cookie authentication with file" << cookieFile << std::endl; - QFile file(cookieFile); - if (file.open(QIODevice::ReadOnly)) + FILE *f = fopen(cookieFile.c_str(),"r"); + + if(f) { - ByteArray cookie = file.readAll(); - file.close(); + std::string cookie; + char c; + while((c=getc(f))!=EOF) + cookie += c; + fclose(f); /* Simple test to avoid a vulnerability where any process listening on what we think is * the control port could trick us into sending the contents of an arbitrary file */ @@ -414,7 +419,7 @@ void TorControlPrivate::protocolInfoReply() cookieError = "Unexpected file size"; } else - cookieError = file.errorString(); + cookieError = "Cannot open file " + cookieFile + ". errno=" + RsUtil::NumberToString(errno); if (!cookieError.empty() || data.isNull()) { @@ -498,13 +503,13 @@ void TorControlPrivate::getTorInfoReply() for (const auto& add:listenAddresses) { ByteArray value = unquotedString(add); int sepp = value.indexOf(':'); - QHostAddress address(value.mid(0, sepp)); - quint16 port = (quint16)value.mid(sepp+1).toUInt(); + std::string address(value.mid(0, sepp).toString()); + quint16 port = (quint16)value.mid(sepp+1).toInt(); /* Use the first address that matches the one used for this control connection. If none do, * just use the first address and rely on the user to reconfigure if necessary (not a problem; * their setup is already very customized) */ - if (socksAddress.isNull() || address == socket->peerAddress()) { + if (socksAddress.empty() || address == socket->peerAddress()) { socksAddress = address; socksPort = port; if (address == socket->peerAddress()) @@ -515,8 +520,8 @@ void TorControlPrivate::getTorInfoReply() /* It is not immediately an error to have no SOCKS address; when DisableNetwork is set there won't be a * listener yet. To handle that situation, we'll try to read the socks address again when TorReady state * is reached. */ - if (!socksAddress.isNull()) { - torCtrlDebug() << "torctrl: SOCKS address is " << socksAddress.toString().toStdString() << ":" << socksPort << std::endl; + if (!socksAddress.empty()) { + torCtrlDebug() << "torctrl: SOCKS address is " << socksAddress << ":" << socksPort << std::endl; if(rsEvents) { @@ -601,8 +606,7 @@ void TorControlPrivate::publishServices() torCtrlDebug() << "torctrl: Configuring hidden service at" << service->dataPath() << std::endl; - QDir dir(service->dataPath()); - torConfig.append(qMakePair(ByteArray("HiddenServiceDir"), dir.absolutePath().toLocal8Bit())); + torConfig.push_back(std::make_pair("HiddenServiceDir", service->dataPath())); const std::list &targets = service->targets(); for (auto tit:targets) @@ -610,7 +614,7 @@ void TorControlPrivate::publishServices() std::string target = RsUtil::NumberToString(tit.servicePort) + " " +tit.targetAddress + ":" +RsUtil::NumberToString(tit.targetPort); - torConfig.append(qMakePair(ByteArray("HiddenServicePort"), target)); + torConfig.push_back(std::make_pair("HiddenServicePort", target)); } QObject::connect(command, &SetConfCommand::setConfSucceeded, service, &HiddenService::servicePublished); @@ -628,7 +632,7 @@ void TorControl::shutdown() return; } - d->socket->sendCommand("SIGNAL SHUTDOWN\r\n"); + d->socket->sendCommand(ByteArray("SIGNAL SHUTDOWN\r\n")); } void TorControl::shutdownSync() @@ -639,11 +643,10 @@ void TorControl::shutdownSync() } shutdown(); - while (d->socket->bytesToWrite()) - { - if (!d->socket->waitForBytesWritten(5000)) - return; - } + while (d->socket->moretowrite()) + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + d->socket->close(); } void TorControlPrivate::statusEvent(int code, const ByteArray &data) @@ -835,7 +838,7 @@ bool TorControl::hasOwnership() const void TorControl::takeOwnership() { d->hasOwnership = true; - d->socket->sendCommand("TAKEOWNERSHIP\r\n"); + d->socket->sendCommand(ByteArray("TAKEOWNERSHIP\r\n")); // Reset PID-based polling std::list > options; diff --git a/libretroshare/src/tor/TorControl.h b/libretroshare/src/tor/TorControl.h index d60b1430b..7380e240f 100644 --- a/libretroshare/src/tor/TorControl.h +++ b/libretroshare/src/tor/TorControl.h @@ -101,7 +101,7 @@ public: /* Connection */ bool isConnected() const { return status() == Connected; } - void connect(const QHostAddress &address, quint16 port); + void connect(const std::string &address, quint16 port); /* Ownership means that tor is managed by this socket, and we * can shut it down, own its configuration, etc. */ diff --git a/libretroshare/src/tor/TorControlSocket.cpp b/libretroshare/src/tor/TorControlSocket.cpp index 0311b7061..a3d465acc 100644 --- a/libretroshare/src/tor/TorControlSocket.cpp +++ b/libretroshare/src/tor/TorControlSocket.cpp @@ -49,6 +49,13 @@ TorControlSocket::~TorControlSocket() clear(); } +std::string TorControlSocket::peerAddress() const +{ + if(connectionState() == State::CONNECTED) + return connectAddress(); + else + return std::string(); +} void TorControlSocket::sendCommand(TorControlCommand *command, const ByteArray& data) { assert(data.endsWith(ByteArray("\r\n"))); @@ -78,10 +85,12 @@ void TorControlSocket::registerEvent(const ByteArray &event, TorControlCommand * void TorControlSocket::clear() { - qDeleteAll(commandQueue); + for(auto cmd:commandQueue) delete cmd; commandQueue.clear(); - qDeleteAll(eventCommands); + + for(auto cmd:eventCommands) delete cmd.second; eventCommands.clear(); + inDataReply = false; currentCommand = 0; } diff --git a/libretroshare/src/tor/TorControlSocket.h b/libretroshare/src/tor/TorControlSocket.h index f988cf2b3..a62feedf2 100644 --- a/libretroshare/src/tor/TorControlSocket.h +++ b/libretroshare/src/tor/TorControlSocket.h @@ -48,6 +48,7 @@ public: std::string errorMessage() const { return m_errorMessage; } + void connectToHost(const std::string& tcp_address,uint16_t tcp_port); void registerEvent(const ByteArray &event, TorControlCommand *handler); void sendCommand(const ByteArray& data) { sendCommand(0, data); } @@ -59,6 +60,7 @@ public: virtual int tick() override; + std::string peerAddress() const; //signals: void error(const std::string& message); diff --git a/libretroshare/src/tor/TorManager.cpp b/libretroshare/src/tor/TorManager.cpp index 7fb367960..a1aeb4bde 100644 --- a/libretroshare/src/tor/TorManager.cpp +++ b/libretroshare/src/tor/TorManager.cpp @@ -41,6 +41,9 @@ #include #endif +#include "util/rsdir.h" +#include "retroshare/rsinit.h" + #include #include "TorManager.h" @@ -136,10 +139,10 @@ std::string TorManager::torDataDirectory() const void TorManager::setTorDataDirectory(const std::string &path) { - d->dataDir = QDir::fromNativeSeparators(path); + d->dataDir = path; - if (!d->dataDir.isEmpty() && !d->dataDir.endsWith(QLatin1Char('/'))) - d->dataDir.append(QLatin1Char('/')); + if (!d->dataDir.empty() && !ByteArray(d->dataDir).endsWith('/')) + d->dataDir += '/'; } std::string TorManager::hiddenServiceDirectory() const @@ -148,7 +151,7 @@ std::string TorManager::hiddenServiceDirectory() const } void TorManager::setHiddenServiceDirectory(const std::string &path) { - d->hiddenServiceDir = QDir::fromNativeSeparators(path); + d->hiddenServiceDir = path; if (!d->hiddenServiceDir.empty() && !(d->hiddenServiceDir.back() == '/')) d->hiddenServiceDir += '/'; @@ -265,16 +268,15 @@ void TorManager::hiddenServiceHostnameChanged() if(!d->hiddenService) return ; - QFile outfile2(d->hiddenServiceDir + QLatin1String("/hostname")) ; - outfile2.open( QIODevice::WriteOnly | QIODevice::Text ); - QTextStream t(&outfile2); + std::string outfile2_name = RsDirUtil::makePath(d->hiddenServiceDir,"/hostname") ; + std::ofstream of(outfile2_name); std::string hostname(d->hiddenService->hostname()); - t << hostname << endl; - outfile2.close(); + of << hostname << std::endl; + of.close(); - std::cerr << "Hidden service hostname changed: " << hostname.toStdString() << std::endl; + std::cerr << "Hidden service hostname changed: " << hostname << std::endl; } bool TorManager::configurationNeeded() const @@ -282,14 +284,14 @@ bool TorManager::configurationNeeded() const return d->configNeeded; } -std::string TorManager::logMessages() const +const std::list& TorManager::logMessages() const { return d->logMessages; } bool TorManager::hasError() const { - return !d->errorMessage.isEmpty(); + return !d->errorMessage.empty(); } std::string TorManager::errorMessage() const @@ -299,7 +301,7 @@ std::string TorManager::errorMessage() const bool TorManager::start() { - if (!d->errorMessage.isEmpty()) { + if (!d->errorMessage.empty()) { d->errorMessage.clear(); //emit errorChanged(); // not needed because there's no error to handle @@ -346,9 +348,9 @@ bool TorManager::start() // Launch a bundled Tor instance std::string executable = d->torExecutablePath(); - std::cerr << "Executable path: " << executable.toStdString() << std::endl; + std::cerr << "Executable path: " << executable << std::endl; - if (executable.isEmpty()) { + if (executable.empty()) { d->setError("Cannot find tor executable"); return false; } @@ -361,20 +363,27 @@ bool TorManager::start() // QObject::connect(d->process, SIGNAL(logMessage(std::string)), d, SLOT(processLogMessage(std::string))); } - if (!QFile::exists(d->dataDir) && !d->createDataDir(d->dataDir)) { + if (!RsDirUtil::checkCreateDirectory(d->dataDir)) + { d->setError(std::string("Cannot write data location: ") + d->dataDir); return false; } - std::string defaultTorrc = d->dataDir + "default_torrc"; - if (!QFile::exists(defaultTorrc) && !d->createDefaultTorrc(defaultTorrc)) + std::string defaultTorrc = RsDirUtil::makePath(d->dataDir,"default_torrc"); + + if (!RsDirUtil::fileExists(defaultTorrc) && !d->createDefaultTorrc(defaultTorrc)) { - d->setError("Cannot write data files: ")+defaultTorrc); + d->setError("Cannot write data files: "+defaultTorrc); return false; } - QFile torrc(d->dataDir + "torrc"); - if (!torrc.exists() || torrc.size() == 0) { + std::string torrc = RsDirUtil::makePath(d->dataDir,"torrc"); + uint64_t file_size; + + bool torrc_exists = RsDirUtil::checkFile(torrc,file_size); + + if(!torrc_exists || torrc.size() == 0) + { d->configNeeded = true; if(rsEvents) @@ -387,9 +396,9 @@ bool TorManager::start() } std::cerr << "Starting Tor process:" << std::endl; - std::cerr << " Tor executable path: " << executable.toStdString() << std::endl; - std::cerr << " Tor data directory : " << d->dataDir.toStdString() << std::endl; - std::cerr << " Tor default torrc : " << defaultTorrc.toStdString() << std::endl; + std::cerr << " Tor executable path: " << executable << std::endl; + std::cerr << " Tor data directory : " << d->dataDir << std::endl; + std::cerr << " Tor default torrc : " << defaultTorrc << std::endl; d->process->setExecutable(executable); d->process->setDataDir(d->dataDir); @@ -435,8 +444,9 @@ bool TorManager::getHiddenServiceInfo(std::string& service_id,std::string& servi void TorManagerPrivate::processStateChanged(int state) { - std::cerr << Q_FUNC_INFO << "state: " << state << " passwd=\"" << std::string(process->controlPassword()).toStdString() << "\" " << process->controlHost().toString().toStdString() + RsInfo() << "state: " << state << " passwd=\"" << process->controlPassword().toString() << "\" " << process->controlHost().toString().toStdString() << ":" << process->controlPort() << std::endl; + if (state == TorProcess::Ready) { control->setAuthPassword(process->controlPassword()); control->connect(process->controlHost(), process->controlPort()); @@ -479,17 +489,21 @@ void TorManagerPrivate::getConfFinished() if (!command) return; - if (command->get("DisableNetwork").toInt() == 1 && !configNeeded) { - configNeeded = true; - //emit q->configurationNeededChanged(); + int n; - if(rsEvents) + for(auto str:command->get("DisableNetwork")) + if(RsUtil::StringToInt(str,n) && n==1 && !configNeeded) { - auto ev = std::make_shared(); - ev->mTorManagerEventType = RsTorManagerEventCode::CONFIGURATION_NEEDED; - rsEvents->sendEvent(ev); + configNeeded = true; + //emit q->configurationNeededChanged(); + + if(rsEvents) + { + auto ev = std::make_shared(); + ev->mTorManagerEventType = RsTorManagerEventCode::CONFIGURATION_NEEDED; + rsEvents->sendEvent(ev); + } } - } } std::string TorManagerPrivate::torExecutablePath() const @@ -509,34 +523,37 @@ std::string TorManagerPrivate::torExecutablePath() const std::string filename("/tor"); #endif - path = qApp->applicationDirPath(); + path = RsDirUtil::getDirectory(RsInit::executablePath()); + std::string tor_exe_path = RsDirUtil::makePath(path,filename); - if (QFile::exists(path + filename)) - return path + filename; + if (RsDirUtil::fileExists(tor_exe_path)) + return tor_exe_path; #ifdef BUNDLED_TOR_PATH path = BUNDLED_TOR_PATH; - if (QFile::exists(path + filename)) - return path + filename; + tor_exe_path = RsDirUtil::makePath(path,filename); + + if (RsDirUtil::fileExists(tor_exe_path)) + return tor_exe_path; #endif #ifdef __APPLE__ // on MacOS, try traditional brew installation path path = "/usr/local/opt/tor/bin" ; + tor_exe_path = RsDirUtil::makePath(path,filename); - if (QFile::exists(path + filename)) - return path + filename; + if (RsDirUtil::fileExists(tor_exe_path)) + return tor_exe_path; #endif // Try $PATH - return filename.mid(1); + return filename.substr(1); } bool TorManagerPrivate::createDataDir(const std::string &path) { - QDir dir(path); - return dir.mkpath("."); + return RsDirUtil::checkCreateDirectory(path); } bool TorManagerPrivate::createDefaultTorrc(const std::string &path) @@ -547,7 +564,7 @@ bool TorManagerPrivate::createDefaultTorrc(const std::string &path) // "DisableNetwork 1\n" // (cyril) I removed this because it prevents Tor to bootstrap. "__ReloadTorrcOnSIGHUP 0\n"; - FILE *f = fopen(path,"w"); + FILE *f = fopen(path.c_str(),"w"); if (!f) return false; diff --git a/libretroshare/src/tor/TorManager.h b/libretroshare/src/tor/TorManager.h index e70ca14b5..c396c2e5b 100644 --- a/libretroshare/src/tor/TorManager.h +++ b/libretroshare/src/tor/TorManager.h @@ -81,7 +81,7 @@ public: // True on first run or when the Tor configuration wizard needs to be shown bool configurationNeeded() const; - std::list logMessages() const; + const std::list& logMessages() const; bool hasError() const; std::string errorMessage() const; diff --git a/libretroshare/src/tor/TorProcess.cpp b/libretroshare/src/tor/TorProcess.cpp index 4d6806f29..907b9b78b 100644 --- a/libretroshare/src/tor/TorProcess.cpp +++ b/libretroshare/src/tor/TorProcess.cpp @@ -38,7 +38,7 @@ #include "util/rsdir.h" #include "pqi/pqifdbin.h" -#include "TorProcess_p.h" +#include "TorProcess.h" #include "CryptoKey.h" #include "SecureRNG.h" @@ -105,7 +105,7 @@ std::string TorProcess::errorMessage() const return mErrorMessage; } -// Does a fopen, but dup all file descriptors (STDIN STDOUT and STDERR) to the +// Does a popen, but dup all file descriptors (STDIN STDOUT and STDERR) to the // FDs supplied by the parent process int popen3(int fd[3],const char **const cmd,pid_t& pid) diff --git a/libretroshare/src/util/rsdir.cc b/libretroshare/src/util/rsdir.cc index 7e5f7dfab..897a481ee 100644 --- a/libretroshare/src/util/rsdir.cc +++ b/libretroshare/src/util/rsdir.cc @@ -93,6 +93,16 @@ std::string RsDirUtil::getFileName(const std::string& full_file_path) else return full_file_path.substr(n+1); } + +std::string RsDirUtil::getDirectory(const std::string& full_file_path) +{ + size_t n = full_file_path.find_last_of('/'); + + if(n == std::string::npos) + return std::string(); + else + return full_file_path.substr(0,n); +} std::string RsDirUtil::getTopDir(const std::string& dir) { std::string top; diff --git a/libretroshare/src/util/rsdir.h b/libretroshare/src/util/rsdir.h index 7ad06a711..457f4c26e 100644 --- a/libretroshare/src/util/rsdir.h +++ b/libretroshare/src/util/rsdir.h @@ -58,13 +58,20 @@ class RsStackFileLock namespace RsDirUtil { +// Returns the name of the directory on top of the given path (as opposed to the full path to that directory) std::string getTopDir(const std::string&); std::string getRootDir(const std::string&); std::string removeRootDir(const std::string& path); void removeTopDir(const std::string& dir, std::string &path); std::string removeRootDirs(const std::string& path, const std::string& root); + +// Returns the filename at the end of the path. An empty string is returned if the path is a directory path. std::string getFileName(const std::string& full_file_path); +// Returns the directory (full path) that contains the given path (filename or directory). +// If a directory is supplied, the same path is returned. +std::string getDirectory(const std::string& full_file_path); + // Renames file from to file to. Files should be on the same file system. // returns true if succeed, false otherwise. bool renameFile(const std::string& from,const std::string& to) ; diff --git a/libretroshare/src/util/rsprint.cc b/libretroshare/src/util/rsprint.cc index 4e547736a..5410ab0d0 100644 --- a/libretroshare/src/util/rsprint.cc +++ b/libretroshare/src/util/rsprint.cc @@ -22,6 +22,7 @@ #include "util/rsprint.h" #include "util/rsstring.h" +#include #include #include #include @@ -45,6 +46,13 @@ std::string RsUtil::NumberToString(uint64_t n,bool hex) return os.str(); } +bool RsUtil::StringToInt(const std::string& s,int& n) +{ + if(sscanf(s.c_str(),"%d",&n) == 1) + return true; + else + return false; +} std::string RsUtil::BinToHex(const std::string &bin) { return BinToHex(bin.c_str(), bin.length()); diff --git a/libretroshare/src/util/rsprint.h b/libretroshare/src/util/rsprint.h index dcaab6311..bdfcb942b 100644 --- a/libretroshare/src/util/rsprint.h +++ b/libretroshare/src/util/rsprint.h @@ -36,6 +36,10 @@ std::string BinToHex(const char *arr, const uint32_t len); std::string BinToHex(const unsigned char *arr, const uint32_t len, uint32_t max_len=0); bool HexToBin(const std::string& input,unsigned char *data, const uint32_t len); std::string NumberToString(uint64_t n, bool hex=false); + +// Returns in n the int that can be read in the string. Returns false when no int is fond. +bool StringToInt(const std::string& s,int& n); + std::string HashId(const std::string &id, bool reverse = false); std::vector BinToSha256(const std::vector &in);