Merge pull request #30 from thunder2/pr-2437-fixes

Pr 2437 fixes
This commit is contained in:
csoler 2021-12-23 11:49:28 +01:00 committed by GitHub
commit f14573bf4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 323 additions and 65 deletions

View File

@ -347,6 +347,7 @@ list(
util/rsurl.cc
util/folderiterator.cc
util/rsdir.cc
util/rsfile.cc
util/dnsresolver.cc
util/extaddrfinder.cc
util/rsdebug.cc

View File

@ -487,6 +487,7 @@ HEADERS += util/folderiterator.h \
util/rsmemory.h \
util/smallobject.h \
util/rsdir.h \
util/rsfile.h \
util/argstream.h \
util/rsdiscspace.h \
util/rsnet.h \
@ -641,6 +642,7 @@ SOURCES += util/folderiterator.cc \
util/rsexpr.cc \
util/smallobject.cc \
util/rsdir.cc \
util/rsfile.cc \
util/rsdiscspace.cc \
util/rsnet.cc \
util/rsnet_ss.cc \

View File

@ -21,10 +21,11 @@
******************************************************************************/
#include "util/rsprint.h"
#include "util/rsfile.h"
#include "pqi/pqifdbin.h"
RsFdBinInterface::RsFdBinInterface(int file_descriptor)
: mCLintConnt(file_descriptor),mIsActive(false)
RsFdBinInterface::RsFdBinInterface(int file_descriptor, bool is_socket)
: mCLintConnt(file_descriptor),mIsSocket(is_socket),mIsActive(false)
{
mTotalReadBytes=0;
mTotalInBufferBytes=0;
@ -53,8 +54,11 @@ void RsFdBinInterface::setSocket(int s)
#else
// On windows, there is no way to determine whether a socket is blocking or not, so we set it to non blocking whatsoever.
unsigned long int on = 1;
ioctlsocket(s, FIONBIO, &on);
if (mIsSocket) {
unix_fcntl_nonblock(s);
} else {
RsFileUtil::set_fd_nonblock(s);
}
#endif
mCLintConnt = s;
@ -82,8 +86,15 @@ int RsFdBinInterface::read_pending()
char inBuffer[1025];
memset(inBuffer,0,1025);
ssize_t readbytes = read(mCLintConnt, inBuffer, sizeof(inBuffer)); // Needs read instead of recv which is only for sockets.
// Sockets should be set to non blocking by the client process.
ssize_t readbytes;
#if WINDOWS_SYS
if (mIsSocket)
// Windows needs recv for sockets
readbytes = recv(mCLintConnt, inBuffer, sizeof(inBuffer), 0);
else
#endif
readbytes = read(mCLintConnt, inBuffer, sizeof(inBuffer)); // Needs read instead of recv which is only for sockets.
// Sockets should be set to non blocking by the client process.
if(readbytes == 0)
{
@ -95,7 +106,11 @@ int RsFdBinInterface::read_pending()
}
if(readbytes < 0)
{
if(errno != EWOULDBLOCK && errno != EAGAIN)
if(errno != 0 && errno != EWOULDBLOCK && errno != EAGAIN)
#ifdef WINDOWS_SYS
// A non blocking read to file descriptor gets ERROR_NO_DATA for empty data
if (mIsSocket == true || GetLastError() != ERROR_NO_DATA)
#endif
RsErr() << "read() failed. Errno=" << errno ;
return mTotalInBufferBytes;
@ -138,7 +153,14 @@ int RsFdBinInterface::write_pending()
return mTotalOutBufferBytes;
auto& p = out_buffer.front();
int written = write(mCLintConnt, p.first, p.second);
int written;
#if WINDOWS_SYS
if (mIsSocket)
// Windows needs send for sockets
written = send(mCLintConnt, (char*) p.first, p.second, 0);
else
#endif
written = write(mCLintConnt, p.first, p.second);
if(written < 0)
{

View File

@ -25,7 +25,7 @@
class RsFdBinInterface: public BinInterface
{
public:
RsFdBinInterface(int file_descriptor);
RsFdBinInterface(int file_descriptor, bool is_socket);
~RsFdBinInterface();
// Implements BinInterface methods
@ -70,6 +70,7 @@ private:
int write_pending();
int mCLintConnt;
bool mIsSocket;
bool mIsActive;
uint32_t mTotalReadBytes;
uint32_t mTotalInBufferBytes;

View File

@ -18,12 +18,12 @@
#include "rstcpsocket.h"
RsTcpSocket::RsTcpSocket(const std::string& tcp_address,uint16_t tcp_port)
:RsFdBinInterface(0),mState(DISCONNECTED),mConnectAddress(tcp_address),mConnectPort(tcp_port),mSocket(0)
:RsFdBinInterface(0, true),mState(DISCONNECTED),mConnectAddress(tcp_address),mConnectPort(tcp_port),mSocket(0)
{
}
RsTcpSocket::RsTcpSocket()
:RsFdBinInterface(0),mState(DISCONNECTED),mConnectAddress("0.0.0.0"),mConnectPort(0),mSocket(0)
:RsFdBinInterface(0, true),mState(DISCONNECTED),mConnectAddress("0.0.0.0"),mConnectPort(0),mSocket(0)
{
}

View File

@ -33,6 +33,7 @@
#pragma once
#include <functional>
#include <string>
/* Represents an asynchronous operation for reporting status
*

View File

@ -39,7 +39,7 @@ ByteArray quotedString(const ByteArray &string)
out.push_back('"');
for (uint i = 0; i < string.size(); ++i)
for (ByteArray::size_type i = 0; i < string.size(); ++i)
{
switch (string[i])
{
@ -67,7 +67,7 @@ ByteArray unquotedString(const ByteArray& string)
ByteArray out;
out.reserve(string.size() - 2);
for (uint i = 1; i < string.size(); ++i)
for (ByteArray::size_type i = 1; i < string.size(); ++i)
{
switch (string[i])
{
@ -89,9 +89,9 @@ std::list<ByteArray> splitQuotedStrings(const ByteArray &input, char separator)
{
std::list<ByteArray> out;
bool inquote = false;
uint start = 0;
ByteArray::size_type start = 0;
for (uint i = 0; i < input.size(); ++i)
for (ByteArray::size_type i = 0; i < input.size(); ++i)
{
switch (input[i])
{

View File

@ -68,6 +68,11 @@ TorControl::TorControl()
: mControlPort(0),mSocksPort(0),mStatus(NotConnected), mTorStatus(TorOffline),mHasOwnership(false)
{
mSocket = new TorControlSocket(this);
mControlPort = 0;
mSocksPort = 0;
mStatus = NotConnected;
mTorStatus = TorUnknown;
mHasOwnership = false;
}
static RsTorConnectivityStatus torConnectivityStatus(Tor::TorControl::Status t)

View File

@ -623,7 +623,7 @@ std::string TorManagerPrivate::torExecutablePath() const
return path;
#endif
#ifdef Q_OS_WIN
#ifdef WINDOWS_SYS
std::string filename("/tor/tor.exe");
#else
std::string filename("/tor");

View File

@ -35,11 +35,19 @@
#include <stdio.h>
#include "util/rsdir.h"
#include "util/rsfile.h"
#include "pqi/pqifdbin.h"
#include "TorProcess.h"
#include "CryptoKey.h"
#ifdef WINDOWS_SYS
#include "util/rsstring.h"
#include <fcntl.h>
#define pipe(fds) _pipe(fds, 1024, _O_BINARY)
#endif
using namespace Tor;
static const int INTERVAL_BETWEEN_CONTROL_PORT_READ_TRIES = 5; // try every 5 secs.
@ -110,7 +118,7 @@ std::string TorProcess::errorMessage() const
// 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)
int popen3(int fd[3],const std::vector<std::string>& args,TorProcessHandle& pid)
{
RsErr() << "Launching Tor in background..." ;
@ -123,42 +131,120 @@ int popen3(int fd[3],const char **const cmd,pid_t& pid)
for(int i=0; i<3; i++)
if(pipe(p[i]))
goto error;
// and fork
pid = fork();
if(-1 == pid)
goto error;
// in the parent?
if(pid)
{
// parent
fd[STDIN_FILENO] = p[STDIN_FILENO][1];
close(p[STDIN_FILENO][0]);
fd[STDOUT_FILENO] = p[STDOUT_FILENO][0];
close(p[STDOUT_FILENO][1]);
fd[STDERR_FILENO] = p[STDERR_FILENO][0];
close(p[STDERR_FILENO][1]);
// success
return 0;
#ifdef WINDOWS_SYS
// Set up members of the PROCESS_INFORMATION structure.
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
// Set up members of the STARTUPINFO structure.
// This structure specifies the STDIN and STDOUT handles for redirection.
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.hStdInput = (HANDLE) _get_osfhandle(p[STDIN_FILENO][0]);
si.hStdOutput = (HANDLE) _get_osfhandle(p[STDOUT_FILENO][1]);
si.hStdError = (HANDLE) _get_osfhandle(p[STDERR_FILENO][1]);
si.dwFlags |= STARTF_USESTDHANDLES;
if (si.hStdInput != INVALID_HANDLE_VALUE &&
si.hStdOutput != INVALID_HANDLE_VALUE &&
si.hStdError != INVALID_HANDLE_VALUE) {
// build commandline
std::string cmd;
for (std::vector<std::string>::const_iterator it = args.begin(); it != args.end(); ++it) {
if (it != args.begin()) {
cmd += " ";
}
cmd += *it;
}
std::wstring wcmd;
if (!librs::util::ConvertUtf8ToUtf16(cmd, wcmd)) {
goto error;
}
WINBOOL success = CreateProcess(nullptr,
(LPWSTR) wcmd.c_str(), // command line
nullptr, // process security attributes
nullptr, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
nullptr, // use parent's environment
nullptr, // use parent's current directory
&si, // STARTUPINFO pointer
&pi); // receives PROCESS_INFORMATION
if (success) {
pid = pi.hProcess;
CloseHandle(pi.hThread);
fd[STDIN_FILENO] = p[STDIN_FILENO][1];
close(p[STDIN_FILENO][0]);
fd[STDOUT_FILENO] = p[STDOUT_FILENO][0];
close(p[STDOUT_FILENO][1]);
fd[STDERR_FILENO] = p[STDERR_FILENO][0];
close(p[STDERR_FILENO][1]);
// success
return 0;
}
}
else
// fall through error
#else
{
RsErr() << "Launching sub-process..." ;
// child
dup2(p[STDIN_FILENO][0],STDIN_FILENO);
close(p[STDIN_FILENO][1]);
dup2(p[STDOUT_FILENO][1],STDOUT_FILENO);
close(p[STDOUT_FILENO][0]);
dup2(p[STDERR_FILENO][1],STDERR_FILENO);
close(p[STDERR_FILENO][0]);
const char *arguments[args.size()+1];
int n=0;
// here we try and run it
// We first pushed everything into a vector of strings to save the pointers obtained from string returning methods
// by the time the process is launched.
execv(*cmd,const_cast<char*const*>(cmd));
for(uint32_t i=0;i<args.size();++i)
arguments[n++]= args[i].data();
// if we are there, then we failed to launch our program
perror("Could not launch");
fprintf(stderr," \"%s\"\n",*cmd);
arguments[n] = nullptr;
// and fork
pid = fork();
if(-1 == pid)
goto error;
// in the parent?
if(pid)
{
// parent
fd[STDIN_FILENO] = p[STDIN_FILENO][1];
close(p[STDIN_FILENO][0]);
fd[STDOUT_FILENO] = p[STDOUT_FILENO][0];
close(p[STDOUT_FILENO][1]);
fd[STDERR_FILENO] = p[STDERR_FILENO][0];
close(p[STDERR_FILENO][1]);
// success
return 0;
}
else
{
RsErr() << "Launching sub-process..." ;
// child
dup2(p[STDIN_FILENO][0],STDIN_FILENO);
close(p[STDIN_FILENO][1]);
dup2(p[STDOUT_FILENO][1],STDOUT_FILENO);
close(p[STDOUT_FILENO][0]);
dup2(p[STDERR_FILENO][1],STDERR_FILENO);
close(p[STDERR_FILENO][0]);
// here we try and run it
execv(*arguments,const_cast<char*const*>(arguments));
// if we are there, then we failed to launch our program
perror("Could not launch");
fprintf(stderr," \"%s\"\n",*arguments);
}
}
#endif
error:
e = errno;
@ -250,31 +336,20 @@ void TorProcess::start()
for(auto s:mExtraSettings)
args.push_back(s);
const char *arguments[args.size()+1];
int n=0;
// We first pushed everything into a vector of strings to save the pointers obtained from string returning methods
// by the time the process is launched.
for(uint32_t i=0;i<args.size();++i)
arguments[n++]= args[i].data();
arguments[n] = nullptr;
int fd[3]; // File descriptors array
if(popen3(fd,arguments,mTorProcessId))
if(popen3(fd,args,mTorProcessId))
{
RsErr() << "Could not start Tor process. errno=" << errno ;
mState = Failed;
return; // stop the control thread
}
unix_fcntl_nonblock(fd[STDOUT_FILENO]);
unix_fcntl_nonblock(fd[STDERR_FILENO]);
RsFileUtil::set_fd_nonblock(fd[STDOUT_FILENO]);
RsFileUtil::set_fd_nonblock(fd[STDERR_FILENO]);
mStdOutFD = new RsFdBinInterface(fd[STDOUT_FILENO]);
mStdErrFD = new RsFdBinInterface(fd[STDERR_FILENO]);
mStdOutFD = new RsFdBinInterface(fd[STDOUT_FILENO], false);
mStdErrFD = new RsFdBinInterface(fd[STDERR_FILENO], false);
}
void TorProcess::tick()
@ -321,7 +396,11 @@ void TorProcess::stop()
while(mState == Starting)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
#ifdef WINDOWS_SYS
TerminateProcess (mTorProcessId, 0);
#else
kill(mTorProcessId,SIGTERM);
#endif
RsInfo() << "Tor process has been normally terminated. Exiting.";
@ -408,10 +487,12 @@ bool TorProcess::tryReadControlPort()
char *line = nullptr;
size_t tmp_buffsize = 0;
size_t size = getline(&line,&tmp_buffsize,file);
size_t size = RsFileUtil::rs_getline(&line,&tmp_buffsize,file);
ByteArray data = ByteArray((unsigned char*)line,size).trimmed();
free(line);
fclose(file);
int p;
if (data.startsWith("PORT=") && (p = data.lastIndexOf(':')) > 0) {
mControlHost = data.mid(5, p - 5).toString();

View File

@ -38,6 +38,12 @@
class RsFdBinInterface ;
#ifdef WINDOWS_SYS
#define TorProcessHandle HANDLE
#else
#define TorProcessHandle pid_t
#endif
namespace Tor
{
@ -114,7 +120,7 @@ private:
std::string controlPortFilePath() const;
bool ensureFilesExist();
pid_t mTorProcessId;
TorProcessHandle mTorProcessId;
time_t mLastTryReadControlPort ;
int mControlPortReadNbTries ;

View File

@ -0,0 +1,107 @@
/*******************************************************************************
* libretroshare/src/util: rsfile.cc *
* *
* libretroshare: retroshare core library *
* *
* Copyright (C) 2021 Retroshare Team <retroshare.project@gmail.com> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* This program 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 Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#include "util/rsfile.h"
#ifdef WINDOWS_SYS
#include <wtypes.h>
#include <io.h>
#include <namedpipeapi.h>
#include <errno.h>
#else
#include <fcntl.h>
#endif
int RsFileUtil::set_fd_nonblock(int fd)
{
int ret = 0;
/******************* OS SPECIFIC PART ******************/
#ifdef WINDOWS_SYS
DWORD mode = PIPE_NOWAIT;
WINBOOL result = SetNamedPipeHandleState((HANDLE) _get_osfhandle(fd), &mode, nullptr, nullptr);
if (!result) {
ret = -1;
}
#else // ie UNIX
int flags = fcntl(fd, F_GETFL);
ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
#endif
return ret;
}
ssize_t RsFileUtil::rs_getline(char **lineptr, size_t *n, FILE *stream)
{
/******************* OS SPECIFIC PART ******************/
#ifdef WINDOWS_SYS
if (lineptr == nullptr || n == nullptr || stream == nullptr) {
errno = EINVAL;
return -1;
}
if (*lineptr == nullptr || *n < 1) {
*n = BUFSIZ;
*lineptr = (char*) malloc(*n);
if (*lineptr == nullptr) {
*n = 0;
return -1;
}
}
char *ptr = *lineptr;
while (true) {
int c = fgetc(stream);
if (c == -1) {
if (feof(stream)) {
*ptr = '\0';
return (ssize_t) (ptr - *lineptr);
}
return -1;
}
*ptr = c;
++ptr;
if (c == '\n') {
*ptr = '\0';
return ptr - *lineptr;
}
if (ptr + 2 >= *lineptr + *n) {
size_t new_size = *n * 2;
ssize_t diff = ptr - *lineptr;
char *new_lineptr = (char*) realloc(*lineptr, new_size);
if (new_lineptr == nullptr) {
return -1;
}
*lineptr = new_lineptr;
*n = new_size;
ptr = new_lineptr + diff;
}
}
#else // ie UNIX
return getline(lineptr, n, stream);
#endif
}

View File

@ -0,0 +1,32 @@
/*******************************************************************************
* libretroshare/src/util: rsfile.h *
* *
* libretroshare: retroshare core library *
* *
* Copyright (C) 2021 Retroshare Team <retroshare.project@gmail.com> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* This program 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 Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#pragma once
#include <stdio.h>
namespace RsFileUtil {
int set_fd_nonblock(int fd);
ssize_t rs_getline(char **lineptr, size_t *n, FILE *stream);
}