mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-10-01 02:35:48 -04:00
Merge pull request #2495 from csoler/v0.6-FriendServer
V0.6 friend server
This commit is contained in:
commit
b847caa11b
@ -55,6 +55,12 @@ retroshare_service {
|
||||
retroshare_service.target = retroshare_service
|
||||
}
|
||||
|
||||
retroshare_friendserver {
|
||||
SUBDIRS += retroshare_friendserver
|
||||
retroshare_friendserver.file = retroshare-friendserver/src/retroshare-friendserver.pro
|
||||
retroshare_friendserver.depends = libretroshare
|
||||
retroshare_friendserver.target = retroshare_friendserver
|
||||
}
|
||||
retroshare_plugins {
|
||||
SUBDIRS += plugins
|
||||
plugins.file = plugins/plugins.pro
|
||||
|
@ -54,7 +54,12 @@ namespace librs
|
||||
|
||||
return Sha1CheckSum(h);
|
||||
}
|
||||
|
||||
template<>
|
||||
HashStream& operator<<(HashStream& u,const std::pair<unsigned char *,uint32_t>& p)
|
||||
{
|
||||
EVP_DigestUpdate(u.mdctx,p.first,p.second) ;
|
||||
return u;
|
||||
}
|
||||
template<>
|
||||
HashStream& operator<<(HashStream& u,const std::string& s)
|
||||
{
|
||||
|
202
libretroshare/src/friend_server/fsclient.cc
Normal file
202
libretroshare/src/friend_server/fsclient.cc
Normal file
@ -0,0 +1,202 @@
|
||||
/*******************************************************************************
|
||||
* libretroshare/src/file_sharing: fsclient.cc *
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright 2021 by 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 "pqi/pqithreadstreamer.h"
|
||||
#include "retroshare/rspeers.h"
|
||||
|
||||
#include "fsclient.h"
|
||||
#include "pqi/pqifdbin.h"
|
||||
#include "pqi/pqiproxy.h"
|
||||
|
||||
bool FsClient::requestFriends(const std::string& address,uint16_t port,
|
||||
const std::string& proxy_address,uint16_t proxy_port,
|
||||
uint32_t reqs,std::map<std::string,bool>& friend_certificates)
|
||||
{
|
||||
// send our own certificate to publish and expects response frmo the server , decrypts it and reutnrs friend list
|
||||
|
||||
RsFriendServerClientPublishItem *pitem = new RsFriendServerClientPublishItem();
|
||||
|
||||
pitem->n_requested_friends = reqs;
|
||||
|
||||
std::string pgp_base64_string,pgp_base64_checksum,short_invite;
|
||||
rsPeers->GetPGPBase64StringAndCheckSum(rsPeers->getGPGOwnId(),pgp_base64_string,pgp_base64_checksum);
|
||||
|
||||
if(!rsPeers->getShortInvite(short_invite,RsPeerId(),RetroshareInviteFlags::RADIX_FORMAT | RetroshareInviteFlags::DNS))
|
||||
{
|
||||
RsErr() << "Cannot request own short invite! Something's very wrong." ;
|
||||
return false;
|
||||
}
|
||||
|
||||
pitem->pgp_public_key_b64 = pgp_base64_string;
|
||||
pitem->short_invite = short_invite;
|
||||
|
||||
std::list<RsItem*> response;
|
||||
sendItem(address,port,proxy_address,proxy_port,pitem,response);
|
||||
|
||||
// now decode the response
|
||||
|
||||
friend_certificates.clear();
|
||||
|
||||
for(auto item:response)
|
||||
{
|
||||
// auto *encrypted_response_item = dynamic_cast<RsFriendServerEncryptedServerResponseItem*>(item);
|
||||
|
||||
// if(!encrypted_response_item)
|
||||
// {
|
||||
// delete item;
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// For now, also handle unencrypted response items. Will be disabled in production
|
||||
|
||||
auto *response_item = dynamic_cast<RsFriendServerServerResponseItem*>(item);
|
||||
|
||||
if(response_item)
|
||||
handleServerResponse(response_item);
|
||||
|
||||
delete item;
|
||||
}
|
||||
return friend_certificates.size();
|
||||
}
|
||||
|
||||
void FsClient::handleServerResponse(RsFriendServerServerResponseItem *item)
|
||||
{
|
||||
std::cerr << "Received a response item from server: " << std::endl;
|
||||
std::cerr << *item << std::endl;
|
||||
|
||||
// for(const auto& it:response_item->friend_invites)
|
||||
// friend_certificates.insert(it);
|
||||
}
|
||||
|
||||
bool FsClient::sendItem(const std::string& server_address,uint16_t server_port,
|
||||
const std::string& proxy_address,uint16_t proxy_port,
|
||||
RsItem *item,std::list<RsItem*>& response)
|
||||
{
|
||||
// open a connection
|
||||
|
||||
RsDbg() << "Sending item to friend server at \"" << server_address << ":" << server_port << " through proxy " << proxy_address << ":" << proxy_port;
|
||||
|
||||
int CreateSocket = 0;
|
||||
char dataReceived[1024];
|
||||
struct sockaddr_in ipOfServer;
|
||||
|
||||
memset(dataReceived, '0' ,sizeof(dataReceived));
|
||||
|
||||
if((CreateSocket = socket(AF_INET, SOCK_STREAM, 0))< 0)
|
||||
{
|
||||
printf("Socket not created \n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ipOfServer.sin_family = AF_INET;
|
||||
ipOfServer.sin_port = htons(proxy_port);
|
||||
ipOfServer.sin_addr.s_addr = inet_addr(proxy_address.c_str());
|
||||
|
||||
if(connect(CreateSocket, (struct sockaddr *)&ipOfServer, sizeof(ipOfServer))<0)
|
||||
{
|
||||
printf("Connection to proxy failed due to port and ip problems, or proxy is not available\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now connect to the proxy
|
||||
|
||||
int ret=0;
|
||||
pqiproxyconnection proxy;
|
||||
proxy.setRemoteAddress(server_address);
|
||||
proxy.setRemotePort(server_port);
|
||||
|
||||
while(1 != (ret = proxy.proxy_negociate_connection(CreateSocket)))
|
||||
if(ret < 0)
|
||||
{
|
||||
RsErr() << "FriendServer client: Connection problem to the proxy!" ;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
|
||||
// Serialise the item and send it.
|
||||
|
||||
FsSerializer *fss = new FsSerializer;
|
||||
RsSerialiser *rss = new RsSerialiser(); // deleted by ~pqistreamer()
|
||||
rss->addSerialType(fss);
|
||||
|
||||
RsFdBinInterface *bio = new RsFdBinInterface(CreateSocket,true); // deleted by ~pqistreamer()
|
||||
|
||||
pqithreadstreamer p(this,rss,RsPeerId(),bio,BIN_FLAGS_READABLE | BIN_FLAGS_WRITEABLE | BIN_FLAGS_NO_CLOSE);
|
||||
p.start();
|
||||
|
||||
uint32_t ss;
|
||||
p.SendItem(item,ss);
|
||||
|
||||
RsDbg() << "Item sent. Waiting for response..." ;
|
||||
|
||||
// Now attempt to read and deserialize anything that comes back from that connexion until it gets closed by the server.
|
||||
|
||||
while(true)
|
||||
{
|
||||
p.tick(); // ticks bio
|
||||
|
||||
RsItem *item = GetItem();
|
||||
#ifdef DEBUG_FSCLIENT
|
||||
RsDbg() << "Ticking for response...";
|
||||
#endif
|
||||
if(item)
|
||||
{
|
||||
response.push_back(item);
|
||||
std::cerr << "Got a response item: " << std::endl;
|
||||
std::cerr << *item << std::endl;
|
||||
|
||||
RsDbg() << "End of transmission. " ;
|
||||
break;
|
||||
}
|
||||
else
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
}
|
||||
|
||||
RsDbg() << " Stopping/killing pqistreamer" ;
|
||||
p.fullstop();
|
||||
|
||||
RsDbg() << " Closing socket." ;
|
||||
close(CreateSocket);
|
||||
CreateSocket=0;
|
||||
|
||||
RsDbg() << " Exiting loop." ;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FsClient::RecvItem(RsItem *item)
|
||||
{
|
||||
mIncomingItems.push_back(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
RsItem *FsClient::GetItem()
|
||||
{
|
||||
if(mIncomingItems.empty())
|
||||
return nullptr;
|
||||
|
||||
RsItem *item = mIncomingItems.front();
|
||||
mIncomingItems.pop_front();
|
||||
|
||||
return item;
|
||||
}
|
54
libretroshare/src/friend_server/fsclient.h
Normal file
54
libretroshare/src/friend_server/fsclient.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*******************************************************************************
|
||||
* libretroshare/src/file_sharing: fsclient.h *
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright 2021 by 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 <string>
|
||||
#include "fsitem.h"
|
||||
#include "pqi/pqi_base.h"
|
||||
|
||||
// This class runs a client connection to the friend server. It opens a socket at each connection.
|
||||
|
||||
class FsClient: public PQInterface
|
||||
{
|
||||
public:
|
||||
FsClient() :PQInterface(RsPeerId()) {}
|
||||
|
||||
bool requestFriends(const std::string& address, uint16_t port,
|
||||
const std::string &proxy_address, uint16_t proxy_port,
|
||||
uint32_t reqs, std::map<std::string,bool>& friend_certificates);
|
||||
|
||||
protected:
|
||||
// Implements PQInterface
|
||||
|
||||
bool RecvItem(RsItem *item) override;
|
||||
int SendItem(RsItem *) override { RsErr() << "FsClient::SendItem() called although it should not." ; return 0;}
|
||||
RsItem *GetItem() override;
|
||||
|
||||
private:
|
||||
bool sendItem(const std::string &server_address, uint16_t server_port,
|
||||
const std::string &proxy_address, uint16_t proxy_port,
|
||||
RsItem *item, std::list<RsItem *> &response);
|
||||
|
||||
void handleServerResponse(RsFriendServerServerResponseItem *item);
|
||||
|
||||
std::list<RsItem*> mIncomingItems;
|
||||
};
|
||||
|
185
libretroshare/src/friend_server/fsitem.h
Normal file
185
libretroshare/src/friend_server/fsitem.h
Normal file
@ -0,0 +1,185 @@
|
||||
/*******************************************************************************
|
||||
* libretroshare/src/file_sharing: fsitem.h *
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright 2021 by 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 "serialiser/rsserial.h"
|
||||
#include "serialiser/rsserializer.h"
|
||||
|
||||
#include "rsitems/rsitem.h"
|
||||
#include "serialiser/rstlvbinary.h"
|
||||
#include "rsitems/rsserviceids.h"
|
||||
#include "rsitems/itempriorities.h"
|
||||
|
||||
const uint8_t RS_PKT_SUBTYPE_FS_CLIENT_PUBLISH = 0x01 ;
|
||||
const uint8_t RS_PKT_SUBTYPE_FS_CLIENT_REMOVE = 0x02 ;
|
||||
const uint8_t RS_PKT_SUBTYPE_FS_SERVER_RESPONSE = 0x03 ;
|
||||
const uint8_t RS_PKT_SUBTYPE_FS_SERVER_ENCRYPTED_RESPONSE = 0x04 ;
|
||||
const uint8_t RS_PKT_SUBTYPE_FS_SERVER_STATUS = 0x05 ;
|
||||
|
||||
class RsFriendServerItem: public RsItem
|
||||
{
|
||||
public:
|
||||
RsFriendServerItem(uint8_t item_subtype) : RsItem(RS_PKT_VERSION_SERVICE,RS_SERVICE_TYPE_FRIEND_SERVER,item_subtype)
|
||||
{
|
||||
setPriorityLevel(QOS_PRIORITY_DEFAULT) ;
|
||||
}
|
||||
virtual ~RsFriendServerItem() {}
|
||||
virtual void clear() override {}
|
||||
};
|
||||
|
||||
class RsFriendServerClientPublishItem: public RsFriendServerItem
|
||||
{
|
||||
public:
|
||||
RsFriendServerClientPublishItem() : RsFriendServerItem(RS_PKT_SUBTYPE_FS_CLIENT_PUBLISH) {}
|
||||
|
||||
void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) override
|
||||
{
|
||||
RS_SERIAL_PROCESS(n_requested_friends);
|
||||
RS_SERIAL_PROCESS(short_invite);
|
||||
RS_SERIAL_PROCESS(pgp_public_key_b64);
|
||||
}
|
||||
virtual void clear() override
|
||||
{
|
||||
pgp_public_key_b64.clear();
|
||||
short_invite.clear();
|
||||
n_requested_friends=0;
|
||||
}
|
||||
|
||||
// specific members for that item
|
||||
|
||||
uint32_t n_requested_friends;
|
||||
std::string short_invite;
|
||||
std::string pgp_public_key_b64;
|
||||
};
|
||||
|
||||
class RsFriendServerStatusItem: public RsFriendServerItem
|
||||
{
|
||||
public:
|
||||
RsFriendServerStatusItem() : RsFriendServerItem(RS_PKT_SUBTYPE_FS_SERVER_STATUS) {}
|
||||
|
||||
void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) override
|
||||
{
|
||||
RS_SERIAL_PROCESS(status);
|
||||
}
|
||||
|
||||
enum ConnectionStatus: uint8_t
|
||||
{
|
||||
UNKNOWN = 0x00,
|
||||
END_OF_TRANSMISSION = 0x01
|
||||
};
|
||||
|
||||
// specific members for that item
|
||||
|
||||
ConnectionStatus status;
|
||||
};
|
||||
|
||||
class RsFriendServerClientRemoveItem: public RsFriendServerItem
|
||||
{
|
||||
public:
|
||||
RsFriendServerClientRemoveItem() : RsFriendServerItem(RS_PKT_SUBTYPE_FS_CLIENT_REMOVE) {}
|
||||
|
||||
void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx)
|
||||
{
|
||||
RS_SERIAL_PROCESS(peer_id);
|
||||
RS_SERIAL_PROCESS(nonce);
|
||||
}
|
||||
|
||||
// Peer ID for the peer to remove.
|
||||
|
||||
RsPeerId peer_id;
|
||||
|
||||
// Nonce that was returned by the server after the last client request. Should match in order to proceed. This prevents
|
||||
// a malicious actor from removing peers from the server. Since the nonce is sent through Tor tunnels, it cannot be known by
|
||||
// anyone else than the client.
|
||||
|
||||
uint64_t nonce;
|
||||
};
|
||||
|
||||
class RsFriendServerEncryptedServerResponseItem: public RsFriendServerItem
|
||||
{
|
||||
public:
|
||||
RsFriendServerEncryptedServerResponseItem() : RsFriendServerItem(RS_PKT_SUBTYPE_FS_SERVER_ENCRYPTED_RESPONSE) {}
|
||||
|
||||
void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) override
|
||||
{
|
||||
RsTypeSerializer::RawMemoryWrapper prox(bin_data, bin_len);
|
||||
RsTypeSerializer::serial_process(j, ctx, prox, "data");
|
||||
}
|
||||
|
||||
virtual void clear() override
|
||||
{
|
||||
free(bin_data);
|
||||
bin_len = 0;
|
||||
bin_data = nullptr;
|
||||
}
|
||||
//
|
||||
|
||||
void *bin_data;
|
||||
uint32_t bin_len;
|
||||
};
|
||||
|
||||
class RsFriendServerServerResponseItem: public RsFriendServerItem
|
||||
{
|
||||
public:
|
||||
RsFriendServerServerResponseItem() : RsFriendServerItem(RS_PKT_SUBTYPE_FS_SERVER_RESPONSE) {}
|
||||
|
||||
void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) override
|
||||
{
|
||||
RS_SERIAL_PROCESS(nonce);
|
||||
RS_SERIAL_PROCESS(friend_invites);
|
||||
}
|
||||
|
||||
virtual void clear() override
|
||||
{
|
||||
friend_invites.clear();
|
||||
nonce = 0;
|
||||
}
|
||||
// specific members for that item
|
||||
|
||||
uint64_t nonce;
|
||||
std::map<std::string,bool> friend_invites;
|
||||
};
|
||||
|
||||
struct FsSerializer : RsServiceSerializer
|
||||
{
|
||||
FsSerializer(RsSerializationFlags flags = RsSerializationFlags::NONE): RsServiceSerializer(RS_SERVICE_TYPE_FRIEND_SERVER, flags) {}
|
||||
|
||||
virtual RsItem *create_item(uint16_t service_id,uint8_t item_sub_id) const
|
||||
{
|
||||
if(service_id != static_cast<uint16_t>(RsServiceType::FRIEND_SERVER))
|
||||
return nullptr;
|
||||
|
||||
switch(item_sub_id)
|
||||
{
|
||||
case RS_PKT_SUBTYPE_FS_CLIENT_REMOVE: return new RsFriendServerClientRemoveItem();
|
||||
case RS_PKT_SUBTYPE_FS_CLIENT_PUBLISH: return new RsFriendServerClientPublishItem();
|
||||
case RS_PKT_SUBTYPE_FS_SERVER_RESPONSE: return new RsFriendServerServerResponseItem();
|
||||
case RS_PKT_SUBTYPE_FS_SERVER_STATUS: return new RsFriendServerStatusItem();
|
||||
case RS_PKT_SUBTYPE_FS_SERVER_ENCRYPTED_RESPONSE: return new RsFriendServerEncryptedServerResponseItem();
|
||||
default:
|
||||
RsErr() << "Unknown subitem type " << item_sub_id << " in FsSerialiser" ;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
123
libretroshare/src/friend_server/fsmanager.cc
Normal file
123
libretroshare/src/friend_server/fsmanager.cc
Normal file
@ -0,0 +1,123 @@
|
||||
#include <cmath>
|
||||
#include "fsmanager.h"
|
||||
#include "fsclient.h"
|
||||
|
||||
RsFriendServer *rsFriendServer = nullptr;
|
||||
|
||||
static const rstime_t MIN_DELAY_BETWEEN_FS_REQUESTS = 30;
|
||||
static const rstime_t MAX_DELAY_BETWEEN_FS_REQUESTS = 3600;
|
||||
static const uint32_t DEFAULT_FRIENDS_TO_REQUEST = 10;
|
||||
|
||||
static const std::string DEFAULT_PROXY_ADDRESS = "127.0.0.1";
|
||||
static const uint16_t DEFAULT_FRIEND_SERVER_PORT = 2017;
|
||||
static const uint16_t DEFAULT_PROXY_PORT = 9050;
|
||||
|
||||
FriendServerManager::FriendServerManager()
|
||||
{
|
||||
mLastFriendReqestCampain = 0;
|
||||
mFriendsToRequest = DEFAULT_FRIENDS_TO_REQUEST;
|
||||
|
||||
mProxyAddress = DEFAULT_PROXY_ADDRESS;
|
||||
mProxyPort = DEFAULT_PROXY_PORT;
|
||||
mServerPort = DEFAULT_FRIEND_SERVER_PORT;
|
||||
}
|
||||
void FriendServerManager::startServer()
|
||||
{
|
||||
if(!isRunning())
|
||||
{
|
||||
std::cerr << "Starting Friend Server Manager." << std::endl;
|
||||
RsTickingThread::start() ;
|
||||
}
|
||||
}
|
||||
void FriendServerManager::stopServer()
|
||||
{
|
||||
if(isRunning() && !shouldStop())
|
||||
{
|
||||
std::cerr << "Stopping Friend Server Manager." << std::endl;
|
||||
RsTickingThread::askForStop() ;
|
||||
}
|
||||
}
|
||||
void FriendServerManager::checkServerAddress_async(const std::string& addr,uint16_t, const std::function<void (const std::string& address,bool result_status)>& callback)
|
||||
{
|
||||
#warning TODO
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
callback(addr,true);
|
||||
}
|
||||
|
||||
void FriendServerManager::setServerAddress(const std::string& addr,uint16_t port)
|
||||
{
|
||||
mServerAddress = addr;
|
||||
mServerPort = port;
|
||||
}
|
||||
void FriendServerManager::setProxyAddress(const std::string& addr,uint16_t port)
|
||||
{
|
||||
mProxyAddress = addr;
|
||||
mProxyPort = port;
|
||||
}
|
||||
void FriendServerManager::setFriendsToRequest(uint32_t n)
|
||||
{
|
||||
mFriendsToRequest = n;
|
||||
}
|
||||
|
||||
void FriendServerManager::threadTick()
|
||||
{
|
||||
std::cerr << "Ticking FriendServerManager..." << std::endl;
|
||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||
|
||||
if(mServerAddress.empty())
|
||||
{
|
||||
RsErr() << "No friend server address has been setup. This is probably a bug.";
|
||||
return;
|
||||
}
|
||||
// Check for requests. Compute how much to wait based on how many friends we have already
|
||||
|
||||
std::vector<RsPgpId> friends;
|
||||
rsPeers->getPgpFriendList(friends);
|
||||
|
||||
// log-scale interpolation of the delay between two requests.
|
||||
|
||||
if(mFriendsToRequest == 0 || mFriendsToRequest < friends.size())
|
||||
{
|
||||
RsErr() << "No friends to request! This is unexpected. Returning." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// This formula makes RS wait much longuer between two requests to the server when the number of friends is close the
|
||||
// wanted number
|
||||
// Delay for 0 friends: 30 secs.
|
||||
// Delay for 1 friends: 30 secs.
|
||||
// Delay for 2 friends: 32 secs.
|
||||
// Delay for 3 friends: 35 secs.
|
||||
// Delay for 4 friends: 44 secs.
|
||||
// Delay for 5 friends: 66 secs.
|
||||
// Delay for 6 friends: 121 secs.
|
||||
// Delay for 7 friends: 258 secs.
|
||||
// Delay for 8 friends: 603 secs.
|
||||
// Delay for 9 friends: 1466 secs.
|
||||
|
||||
RsDbg() << friends.size() << " friends already, " << mFriendsToRequest << " friends to request";
|
||||
|
||||
double s = (friends.size() < mFriendsToRequest)? ( (mFriendsToRequest - friends.size())/(double)mFriendsToRequest) : 1.0;
|
||||
rstime_t delay_for_request = MIN_DELAY_BETWEEN_FS_REQUESTS + (int)floor(exp(-1*s + log(MAX_DELAY_BETWEEN_FS_REQUESTS)*(1.0-s)));
|
||||
|
||||
std::cerr << "Delay for " << friends.size() << " friends: " << delay_for_request << " secs." << std::endl;
|
||||
|
||||
rstime_t now = time(nullptr);
|
||||
|
||||
if(mLastFriendReqestCampain + delay_for_request < now)
|
||||
{
|
||||
mLastFriendReqestCampain = now;
|
||||
|
||||
std::cerr << "Requesting new friends to friend server..." << std::endl;
|
||||
|
||||
std::map<std::string,bool> friend_certificates;
|
||||
FsClient().requestFriends(mServerAddress,mServerPort,mProxyAddress,mProxyPort,mFriendsToRequest,friend_certificates); // blocking call
|
||||
|
||||
std::cerr << "Got the following list of friend certificates:" << std::endl;
|
||||
|
||||
for(const auto& it:friend_certificates)
|
||||
std::cerr << it.first << " : " << it.second << std::endl;
|
||||
}
|
||||
}
|
||||
|
51
libretroshare/src/friend_server/fsmanager.h
Normal file
51
libretroshare/src/friend_server/fsmanager.h
Normal file
@ -0,0 +1,51 @@
|
||||
#include <map>
|
||||
|
||||
#include "util/rsthreads.h"
|
||||
#include "retroshare/rsfriendserver.h"
|
||||
#include "retroshare/rspeers.h"
|
||||
|
||||
struct FriendServerPeerInfo
|
||||
{
|
||||
enum FriendServerPeerStatus: uint8_t
|
||||
{
|
||||
UNKNOWN = 0x00,
|
||||
LOCALLY_ACCEPTED = 0x01,
|
||||
HAS_ACCEPTED_ME = 0x02,
|
||||
ALREADY_CONNECTED = 0x03
|
||||
};
|
||||
|
||||
uint32_t status ;
|
||||
rstime_t received_TS;
|
||||
};
|
||||
|
||||
class FriendServerManager: public RsFriendServer, public RsTickingThread
|
||||
{
|
||||
public:
|
||||
FriendServerManager();
|
||||
|
||||
virtual void startServer() override ;
|
||||
virtual void stopServer() override ;
|
||||
|
||||
virtual void checkServerAddress_async(const std::string& addr,uint16_t, const std::function<void (const std::string& address,bool result_status)>& callback) override ;
|
||||
virtual void setServerAddress(const std::string&,uint16_t) override ;
|
||||
virtual void setProxyAddress(const std::string&,uint16_t) override ;
|
||||
virtual void setFriendsToRequest(uint32_t) override ;
|
||||
|
||||
virtual uint32_t friendsToRequest() override { return mFriendsToRequest ; }
|
||||
virtual uint16_t friendsServerPort() override { return mServerPort ; }
|
||||
virtual std::string friendsServerAddress() override { return mServerAddress ; }
|
||||
protected:
|
||||
virtual void threadTick() override;
|
||||
|
||||
private:
|
||||
uint32_t mFriendsToRequest;
|
||||
rstime_t mLastFriendReqestCampain;
|
||||
|
||||
// encode the current list of friends obtained through the friendserver and their status
|
||||
|
||||
std::map<RsPeerId, FriendServerPeerInfo> mPeers;
|
||||
std::string mServerAddress ;
|
||||
uint16_t mServerPort;
|
||||
std::string mProxyAddress ;
|
||||
uint16_t mProxyPort;
|
||||
};
|
@ -391,6 +391,7 @@ HEADERS += pqi/authssl.h \
|
||||
pqi/pqissl.h \
|
||||
pqi/pqissllistener.h \
|
||||
pqi/pqisslpersongrp.h \
|
||||
pqi/pqiproxy.h \
|
||||
pqi/pqisslproxy.h \
|
||||
pqi/pqistore.h \
|
||||
pqi/pqistreamer.h \
|
||||
@ -559,6 +560,7 @@ SOURCES += pqi/authgpg.cc \
|
||||
pqi/pqissl.cc \
|
||||
pqi/pqissllistener.cc \
|
||||
pqi/pqisslpersongrp.cc \
|
||||
pqi/pqiproxy.cc \
|
||||
pqi/pqisslproxy.cc \
|
||||
pqi/pqistore.cc \
|
||||
pqi/pqistreamer.cc \
|
||||
@ -825,6 +827,22 @@ wikipoos {
|
||||
rsitems/rswikiitems.cc \
|
||||
}
|
||||
|
||||
# Friend server
|
||||
|
||||
rs_efs {
|
||||
DEFINES *= RS_EMBEDED_FRIEND_SERVER
|
||||
|
||||
HEADERS += friend_server/fsclient.h \
|
||||
friend_server/fsitem.h \
|
||||
friend_server/fsmanager.h \
|
||||
retroshare/rsfriendserver.h
|
||||
|
||||
SOURCES += friend_server/fsclient.cc \
|
||||
friend_server/fsmanager.cc
|
||||
}
|
||||
|
||||
# The Wire
|
||||
|
||||
gxsthewire {
|
||||
DEFINES *= RS_USE_WIRE
|
||||
|
||||
|
@ -1642,7 +1642,10 @@ bool OpenPGPSDKHandler::locked_syncPublicKeyring()
|
||||
#else
|
||||
if(-1 == stat64(_pubring_path.c_str(), &buf))
|
||||
#endif
|
||||
{
|
||||
RsErr() << "OpenPGPSDKHandler::syncDatabase(): can't stat file " << _pubring_path << ". Can't sync public keyring." ;
|
||||
buf.st_mtime = 0;
|
||||
}
|
||||
|
||||
if(_pubring_last_update_time < buf.st_mtime)
|
||||
{
|
||||
|
@ -357,12 +357,13 @@ bool PGPHandler::locked_syncTrustDatabase()
|
||||
librs::util::ConvertUtf8ToUtf16(_trustdb_path, wfullname);
|
||||
if(-1 == _wstati64(wfullname.c_str(), &buf))
|
||||
#else
|
||||
if(-1 == stat64(_trustdb_path.c_str(), &buf))
|
||||
if(-1 == stat64(_trustdb_path.c_str(), &buf))
|
||||
#endif
|
||||
{
|
||||
RsErr() << "PGPHandler::syncDatabase(): can't stat file " << _trustdb_path << ". Will force write it." ;
|
||||
_trustdb_changed = true ; // we force write of trust database if it does not exist.
|
||||
}
|
||||
{
|
||||
RsErr() << "PGPHandler::syncDatabase(): can't stat file " << _trustdb_path << ". Will force write it." ;
|
||||
_trustdb_changed = true ; // we force write of trust database if it does not exist.
|
||||
buf.st_mtime = 0;
|
||||
}
|
||||
|
||||
if(_trustdb_last_update_time < buf.st_mtime)
|
||||
{
|
||||
|
@ -21,6 +21,7 @@
|
||||
*******************************************************************************/
|
||||
#include <stdint.h>
|
||||
#include <util/radix64.h>
|
||||
#include <crypto/hashstream.h>
|
||||
#include "pgpkeyutil.h"
|
||||
|
||||
#include <iostream>
|
||||
@ -181,6 +182,59 @@ uint32_t PGPKeyManagement::compute24bitsCRC(unsigned char *octets, size_t len)
|
||||
return crc & 0xFFFFFFL;
|
||||
}
|
||||
|
||||
bool PGPKeyManagement::parsePGPPublicKey(const unsigned char *keydata, size_t keylen, PGPKeyInfo& info)
|
||||
{
|
||||
#ifdef DEBUG_PGPUTIL
|
||||
std::cerr << "Total size: " << keylen << std::endl;
|
||||
#endif
|
||||
unsigned char *data = (unsigned char*)keydata;
|
||||
|
||||
uint8_t packet_tag;
|
||||
uint32_t packet_length ;
|
||||
|
||||
PGPKeyParser::read_packetHeader(data,packet_tag,packet_length) ;
|
||||
|
||||
#ifdef DEBUG_PGPUTIL
|
||||
std::cerr << "Packet tag : " << (int)packet_tag << ", length=" << packet_length << std::endl;
|
||||
#endif
|
||||
if(packet_tag != PGPKeyParser::PGP_PACKET_TAG_PUBLIC_KEY)
|
||||
{
|
||||
std::cerr << "(EE) Parsing error in PGP public key. Expected a public key tag (6). Found " << (int)packet_tag << " instead." << std::endl;
|
||||
return false;
|
||||
}
|
||||
librs::crypto::HashStream H(librs::crypto::HashStream::SHA1);
|
||||
|
||||
H << (uint8_t)0x99; // RFC_4880
|
||||
|
||||
std::cerr << "Packet length = " << packet_length << std::endl;
|
||||
|
||||
H << (uint8_t)(packet_length >> 8);
|
||||
H << (uint8_t)(packet_length);
|
||||
H << std::make_pair(data,packet_length) ;
|
||||
|
||||
auto hash = H.hash();
|
||||
|
||||
memcpy(info.fingerprint, hash.toByteArray(),hash.SIZE_IN_BYTES);
|
||||
|
||||
data += packet_length;
|
||||
|
||||
// Read user ID.
|
||||
|
||||
PGPKeyParser::read_packetHeader(data,packet_tag,packet_length) ;
|
||||
|
||||
if(packet_tag != PGPKeyParser::PGP_PACKET_TAG_USER_ID)
|
||||
{
|
||||
std::cerr << "(EE) Parsing error in PGP public key. Expected a user ID key tag (13). Found " << (int)packet_tag << " instead." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
info.user_id.clear();
|
||||
|
||||
for(uint32_t i=0;i<packet_length;++i)
|
||||
info.user_id += (char)(data[i]);
|
||||
|
||||
return true ;
|
||||
}
|
||||
bool PGPKeyManagement::parseSignature(const unsigned char *signature, size_t sign_len, PGPSignatureInfo& info)
|
||||
{
|
||||
unsigned char *data = (unsigned char *)signature ;
|
||||
|
@ -81,6 +81,16 @@ public:
|
||||
uint8_t hash_algorithm ;
|
||||
};
|
||||
|
||||
class PGPKeyInfo
|
||||
{
|
||||
public:
|
||||
PGPKeyInfo() {}
|
||||
|
||||
std::string user_id;
|
||||
unsigned char fingerprint[20];
|
||||
};
|
||||
|
||||
|
||||
// This class handles GPG keys. For now we only clean them from signatures, but
|
||||
// in the future, we might cache them to avoid unnecessary calls to gpgme.
|
||||
//
|
||||
@ -107,6 +117,8 @@ class PGPKeyManagement
|
||||
static uint32_t compute24bitsCRC(unsigned char *data,size_t len) ;
|
||||
|
||||
static bool parseSignature(const unsigned char *signature, size_t sign_len, PGPSignatureInfo& info) ;
|
||||
|
||||
static bool parsePGPPublicKey(const unsigned char *keydata, size_t keylen, PGPKeyInfo& info);
|
||||
};
|
||||
|
||||
// This class handles the parsing of PGP packet headers under various (old and new) formats.
|
||||
@ -126,7 +138,7 @@ class PGPKeyParser
|
||||
static uint64_t read_KeyID(unsigned char *& data) ;
|
||||
static uint32_t read_125Size(unsigned char *& data) ;
|
||||
static uint32_t read_partialBodyLength(unsigned char *& data) ;
|
||||
static void read_packetHeader(unsigned char *& data,uint8_t& packet_tag,uint32_t& packet_length) ;
|
||||
static void read_packetHeader(unsigned char *&data, uint8_t& packet_tag, uint32_t& packet_length) ;
|
||||
|
||||
// These functions write, and indicate how many bytes where written.
|
||||
//
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <retroshare/rspeers.h>
|
||||
#include <util/radix64.h>
|
||||
#include <pgp/pgpkeyutil.h>
|
||||
#include <pgp/pgphandler.h>
|
||||
#include "rscertificate.h"
|
||||
#include "util/rsstring.h"
|
||||
#include "util/stacktrace.h"
|
||||
@ -619,6 +620,140 @@ bool RsCertificate::cleanRadix64(const std::string& instr,std::string& str,uint3
|
||||
return true ;
|
||||
}
|
||||
|
||||
bool RsCertificate::decodeRadix64ShortInvite(const std::string& rsInvite, RsPeerDetails& details, uint32_t& err_code)
|
||||
{
|
||||
err_code = 0;
|
||||
std::vector<uint8_t> bf = Radix64::decode(rsInvite);
|
||||
size_t size = bf.size();
|
||||
|
||||
unsigned char* buf = bf.data();
|
||||
size_t total_s = 0;
|
||||
bool CRC_ok = false ; // not checked yet
|
||||
|
||||
while(total_s < size)
|
||||
{
|
||||
RsShortInviteFieldType ptag = RsShortInviteFieldType(buf[0]);
|
||||
buf = &buf[1];
|
||||
|
||||
unsigned char *buf2 = buf;
|
||||
uint32_t s = 0;
|
||||
|
||||
try { s = PGPKeyParser::read_125Size(buf); }
|
||||
catch (...)
|
||||
{
|
||||
err_code = CERTIFICATE_PARSING_ERROR_SIZE_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
total_s += 1 + ( reinterpret_cast<size_t>(buf) - reinterpret_cast<size_t>(buf2) );
|
||||
|
||||
if(total_s > size)
|
||||
{
|
||||
err_code = CERTIFICATE_PARSING_ERROR_SIZE_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
Dbg3() << __PRETTY_FUNCTION__ << " Read ptag: "
|
||||
<< static_cast<uint32_t>(ptag)
|
||||
<< ", size " << s << ", total_s = " << total_s
|
||||
<< ", expected total = " << size << std::endl;
|
||||
|
||||
switch(ptag)
|
||||
{
|
||||
case RsShortInviteFieldType::SSL_ID:
|
||||
details.id = RsPeerId::fromBufferUnsafe(buf) ;
|
||||
break;
|
||||
|
||||
case RsShortInviteFieldType::PEER_NAME:
|
||||
details.name = std::string((char*)buf,s);
|
||||
break;
|
||||
|
||||
case RsShortInviteFieldType::PGP_FINGERPRINT:
|
||||
details.fpr = RsPgpFingerprint::fromBufferUnsafe(buf);
|
||||
details.gpg_id = PGPHandler::pgpIdFromFingerprint(details.fpr);
|
||||
break;
|
||||
|
||||
case RsShortInviteFieldType::LOCATOR:
|
||||
{
|
||||
std::string locatorStr((char*)buf,s);
|
||||
details.ipAddressList.push_back(locatorStr);
|
||||
}
|
||||
break;
|
||||
|
||||
case RsShortInviteFieldType::DNS_LOCATOR:
|
||||
details.extPort = (((int)buf[0]) << 8) + buf[1];
|
||||
details.dyndns = std::string((char*)&buf[2],s-2);
|
||||
break;
|
||||
|
||||
case RsShortInviteFieldType::LOC4_LOCATOR:
|
||||
{
|
||||
uint32_t t4Addr = (((uint32_t)buf[0]) << 24)+(((uint32_t)buf[1])<<16)+(((uint32_t)buf[2])<<8) + (uint32_t)buf[3];
|
||||
sockaddr_in tLocalAddr;
|
||||
tLocalAddr.sin_addr.s_addr = t4Addr;
|
||||
|
||||
details.localAddr = rs_inet_ntoa(tLocalAddr.sin_addr);
|
||||
details.localPort = (((uint32_t)buf[4])<<8) + (uint32_t)buf[5];
|
||||
}
|
||||
break;
|
||||
|
||||
case RsShortInviteFieldType::EXT4_LOCATOR:
|
||||
{
|
||||
uint32_t t4Addr = (((uint32_t)buf[0]) << 24)+(((uint32_t)buf[1])<<16)+(((uint32_t)buf[2])<<8) + (uint32_t)buf[3];
|
||||
sockaddr_in tExtAddr;
|
||||
tExtAddr.sin_addr.s_addr = t4Addr;
|
||||
|
||||
details.extAddr = rs_inet_ntoa(tExtAddr.sin_addr);
|
||||
details.extPort = (((uint32_t)buf[4])<<8) + (uint32_t)buf[5];
|
||||
}
|
||||
break;
|
||||
|
||||
case RsShortInviteFieldType::HIDDEN_LOCATOR:
|
||||
details.hiddenType = (((uint32_t)buf[0]) << 24)+(((uint32_t)buf[1])<<16)+(((uint32_t)buf[2])<<8) + (uint32_t)buf[3];
|
||||
details.hiddenNodePort = (((uint32_t)buf[4]) << 8)+ (uint32_t)buf[5];
|
||||
details.isHiddenNode = true;
|
||||
details.hiddenNodeAddress = std::string((char*)&buf[6],s-6);
|
||||
break;
|
||||
|
||||
case RsShortInviteFieldType::CHECKSUM:
|
||||
{
|
||||
if(s != 3 || total_s+3 != size) // make sure the checksum is the last section
|
||||
{
|
||||
err_code = CERTIFICATE_PARSING_ERROR_INVALID_CHECKSUM_SECTION;
|
||||
return false;
|
||||
}
|
||||
uint32_t computed_crc = PGPKeyManagement::compute24bitsCRC(bf.data(),size-5);
|
||||
uint32_t certificate_crc = static_cast<uint32_t>( buf[0] + (buf[1] << 8) + (buf[2] << 16) );
|
||||
|
||||
if(computed_crc != certificate_crc)
|
||||
{
|
||||
err_code = CERTIFICATE_PARSING_ERROR_CHECKSUM_ERROR;
|
||||
return false;
|
||||
}
|
||||
CRC_ok = true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
buf = &buf[s];
|
||||
total_s += s;
|
||||
}
|
||||
|
||||
if(details.id.isNull())
|
||||
{
|
||||
err_code = CERTIFICATE_PARSING_ERROR_MISSING_LOCATION_ID;
|
||||
return false;
|
||||
}
|
||||
if(!CRC_ok)
|
||||
{
|
||||
err_code = CERTIFICATE_PARSING_ERROR_CHECKSUM_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -36,6 +36,21 @@ struct RsPeerDetails;
|
||||
class RsCertificate
|
||||
{
|
||||
public:
|
||||
enum class RsShortInviteFieldType : uint8_t
|
||||
{
|
||||
SSL_ID = 0x00,
|
||||
PEER_NAME = 0x01,
|
||||
LOCATOR = 0x02,
|
||||
PGP_FINGERPRINT = 0x03,
|
||||
CHECKSUM = 0x04,
|
||||
|
||||
/* The following will be deprecated, and ported to LOCATOR when generic transport layer will be implemented */
|
||||
HIDDEN_LOCATOR = 0x90,
|
||||
DNS_LOCATOR = 0x91,
|
||||
EXT4_LOCATOR = 0x92, // external IPv4 address
|
||||
LOC4_LOCATOR = 0x93 // local IPv4 address
|
||||
};
|
||||
|
||||
typedef enum { RS_CERTIFICATE_OLD_FORMAT, RS_CERTIFICATE_RADIX, RS_CERTIFICATE_SHORT_RADIX } Format;
|
||||
|
||||
/**
|
||||
@ -64,6 +79,8 @@ public:
|
||||
|
||||
~RsCertificate();
|
||||
|
||||
static bool decodeRadix64ShortInvite(const std::string& short_invite_b64,RsPeerDetails& det,uint32_t& error_code);
|
||||
|
||||
/// Convert to certificate radix string
|
||||
std::string toStdString() const;
|
||||
|
||||
|
@ -280,7 +280,8 @@ public:
|
||||
* Sends data to a prescribed location (implementation dependent)
|
||||
*@param data what will be sent
|
||||
*@param len the size of data pointed to in memory
|
||||
*/
|
||||
*@returns total number of bytes actually sent
|
||||
*/
|
||||
virtual int senddata(void *data, int len) = 0;
|
||||
|
||||
/**
|
||||
|
@ -236,6 +236,7 @@ int RsFdBinInterface::readline(void *data, int len)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RsFdBinInterface::readdata(void *data, int len)
|
||||
{
|
||||
// read incoming bytes in the buffer
|
||||
|
469
libretroshare/src/pqi/pqiproxy.cc
Normal file
469
libretroshare/src/pqi/pqiproxy.cc
Normal file
@ -0,0 +1,469 @@
|
||||
#include "util/rsdebug.h"
|
||||
#include "util/rsnet.h"
|
||||
|
||||
#include "pqi/pqiproxy.h"
|
||||
|
||||
//#define PROXY_DEBUG 1
|
||||
|
||||
int pqiproxyconnection::proxy_negociate_connection(int sockfd)
|
||||
{
|
||||
int ret = 0;
|
||||
switch(mProxyState)
|
||||
{
|
||||
case PROXY_STATE_INIT:
|
||||
ret = Proxy_Send_Method(sockfd); // checks basic conn, sends Method when able.
|
||||
break;
|
||||
|
||||
case PROXY_STATE_WAITING_METHOD_RESPONSE:
|
||||
ret = Proxy_Send_Address(sockfd); // waits for Method Response, send Address when able.
|
||||
break;
|
||||
|
||||
case PROXY_STATE_WAITING_SOCKS_RESPONSE:
|
||||
ret = Proxy_Connection_Complete(sockfd); // wait for ACK.
|
||||
|
||||
if(ret < 1)
|
||||
break;
|
||||
|
||||
case PROXY_STATE_CONNECTION_COMPLETE:
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Basic_Connection_Complete() COMPLETED";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
|
||||
case PROXY_STATE_FAILED:
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Basic_Connection_Complete() FAILED";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(ret < 0)
|
||||
return -1;
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Basic_Connection_Complete() IN PROGRESS";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
// In Progress.
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int pqiproxyconnection::Proxy_Send_Method(int sockfd)
|
||||
{
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Send_Method() Basic complete, sending Method";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
/* send hello to proxy server */
|
||||
char method_hello_data[3] = { 0x05, 0x01, 0x00 }; // [ Ver | nMethods (1) | No Auth Method ]
|
||||
|
||||
int sent = send(sockfd, method_hello_data, 3, 0);
|
||||
if (sent != 3)
|
||||
{
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Send_Method() Send Failure";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Send_Method() Send Method Okay";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
mProxyState = PROXY_STATE_WAITING_METHOD_RESPONSE;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pqiproxyconnection::Proxy_Method_Response(int sockfd)
|
||||
{
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Method_Response()";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
/* get response from proxy server */
|
||||
|
||||
char method_response[2];
|
||||
|
||||
/*
|
||||
first it was:
|
||||
|
||||
int recvd = recv(sockfd, method_response, 2, MSG_WAITALL);
|
||||
|
||||
this does not work on windows, because the socket is in nonblocking mode
|
||||
the winsock reference says about the recv function and MSG_WAITALL:
|
||||
|
||||
"Note that if the underlying transport does not support MSG_WAITALL,
|
||||
or if the socket is in a non-blocking mode, then this call will fail with WSAEOPNOTSUPP."
|
||||
|
||||
now it is a two step process:
|
||||
|
||||
int recvd = recv(sockfd, method_response, 2, MSG_PEEK); // test how many bytes are in the input queue
|
||||
if (enaugh bytes available){
|
||||
recvd = recv(sockfd, method_response, 2, 0);
|
||||
}
|
||||
|
||||
this does not work on windows:
|
||||
if ((recvd == -1) && (errno == EAGAIN)) return TRY_AGAIN_LATER;
|
||||
|
||||
instead have to do:
|
||||
if ((recvd == -1) && (WSAGetLastError() == WSAEWOULDBLOCK)) return TRY_AGAIN_LATER;
|
||||
*/
|
||||
|
||||
// test how many bytes can be read from the queue
|
||||
int recvd = recv(sockfd, method_response, 2, MSG_PEEK);
|
||||
if (recvd != 2)
|
||||
{
|
||||
#ifdef WINDOWS_SYS
|
||||
if ((recvd == -1) && (WSAGetLastError() == WSAEWOULDBLOCK))
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Method_Response() waiting for more data (windows)";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if ((recvd == -1) && (errno == EAGAIN))
|
||||
{
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Method_Response() EAGAIN";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
else if (recvd == -1)
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Method_Response() recv error peek";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Method_Response() waiting for more data";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// read the bytes
|
||||
recvd = recv(sockfd, method_response, 2, 0);
|
||||
if (recvd != 2)
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Method_Response() recv error";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
// does it make sense?
|
||||
if (method_response[0] != 0x05)
|
||||
{
|
||||
|
||||
// Error.
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Method_Response() Error response[0] != 0x05. Is: ";
|
||||
std::cerr << (uint32_t) method_response[0];
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (method_response[1] != 0x00)
|
||||
{
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Method_Response() Error response[0] != 0x00. Is: ";
|
||||
std::cerr << (uint32_t) method_response[1];
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
// Error.
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Method_Response() Response Okay";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define MAX_SOCKS_REQUEST_LEN 262 // 4 + 1 + 255 + 2.
|
||||
|
||||
int pqiproxyconnection::Proxy_Send_Address(int sockfd)
|
||||
{
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Send_Address() Checking Method Response";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
// Check Method Response.
|
||||
int ret = Proxy_Method_Response(sockfd);
|
||||
if (ret != 1)
|
||||
{
|
||||
return ret; // Method Response not complete.
|
||||
}
|
||||
|
||||
char socks_request[MAX_SOCKS_REQUEST_LEN] = {
|
||||
0x05, // SOCKS VERSION.
|
||||
0x01, // CONNECT (Tor doesn't support BIND or UDP).
|
||||
0x00, // RESERVED.
|
||||
0x03, // ADDRESS TYPE (Domain Name)
|
||||
0x00, // Length of Domain name... the rest is variable so can't hard code it!
|
||||
};
|
||||
|
||||
/* get the length of the domain name, pack so we can't overflow uint8_t */
|
||||
uint8_t len = mDomainAddress.length();
|
||||
socks_request[4] = len;
|
||||
for(int i = 0; i < len; i++)
|
||||
socks_request[5 + i] = mDomainAddress[i];
|
||||
|
||||
/* now add the port, being careful with packing */
|
||||
uint16_t net_port = htons(mRemotePort);
|
||||
socks_request[5 + len] = ((uint8_t *) &net_port)[0];
|
||||
socks_request[5 + len + 1] = ((uint8_t *) &net_port)[1];
|
||||
|
||||
int pkt_len = 5 + len + 2;
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Send_Address() Sending String: ";
|
||||
for(int i = 0; i < pkt_len; i++)
|
||||
std::cerr << (uint32_t) socks_request[i];
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
int sent = send(sockfd, socks_request, pkt_len, 0);
|
||||
if (sent != pkt_len)
|
||||
{
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Send_Address() Send Error";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Send_Address() Sent Okay";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
mProxyState = PROXY_STATE_WAITING_SOCKS_RESPONSE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pqiproxyconnection::Proxy_Connection_Complete(int sockfd)
|
||||
{
|
||||
/* get response from proxy server */
|
||||
/* response is similar format to request - with variable length data */
|
||||
|
||||
char socks_response[MAX_SOCKS_REQUEST_LEN];
|
||||
|
||||
// test how many bytes can be read
|
||||
int recvd = recv(sockfd, socks_response, 5, MSG_PEEK);
|
||||
if (recvd != 5)
|
||||
{
|
||||
#ifdef WINDOWS_SYS
|
||||
if ((recvd == -1) && (WSAGetLastError() == WSAEWOULDBLOCK))
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() waiting for more data (windows)";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if ((recvd == -1) && (errno == EAGAIN))
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() EAGAIN";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
else if (recvd == -1)
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() recv error peek";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() waiting for more data";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// read the bytes
|
||||
recvd = recv(sockfd, socks_response, 5, 0);
|
||||
if (recvd != 5)
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() recv error";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
// error checking.
|
||||
if (socks_response[0] != 0x05)
|
||||
{
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR socks_response[0] != 0x05. is: ";
|
||||
std::cerr << (uint32_t) socks_response[0];
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
// error.
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (socks_response[1] != 0x00)
|
||||
{
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR socks_response[1] != 0x00. is: ";
|
||||
std::cerr << (uint32_t) socks_response[1];
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
// connection failed.
|
||||
return -1;
|
||||
}
|
||||
|
||||
int address_bytes = 0;
|
||||
switch(socks_response[3]) // Address Type.
|
||||
{
|
||||
case 0x01:
|
||||
// IPv4 4 address bytes.
|
||||
address_bytes = 4;
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() IPv4 Address Type";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
break;
|
||||
case 0x04:
|
||||
// IPv6 16 address bytes.
|
||||
address_bytes = 16;
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() IPv6 Address Type";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
break;
|
||||
case 0x03:
|
||||
// Variable address bytes - specified in next byte.
|
||||
address_bytes = 1 + socks_response[4];
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() Domain Address Type. len: " << address_bytes;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
// unknown error.
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR Unknown Address Type";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// test how many bytes can be read
|
||||
recvd = recv(sockfd, &(socks_response[5]), address_bytes + 1, MSG_PEEK); // address_bytes - 1 + 2...
|
||||
if (recvd != address_bytes + 1)
|
||||
{
|
||||
#ifdef WINDOWS_SYS
|
||||
if((recvd == -1) && (WSAGetLastError() == WSAEWOULDBLOCK))
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() waiting for more data(2) (windows)";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if ((recvd == -1) && (errno == EAGAIN))
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR EAGAIN at end.";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
// Waiting - shouldn't happen.
|
||||
return 0;
|
||||
}
|
||||
else if (recvd == -1)
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR recving(2)";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() waiting for more data(2)";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// read the bytes
|
||||
recvd = recv(sockfd, &(socks_response[5]), address_bytes + 1, 0); // address_bytes - 1 + 2...
|
||||
if (recvd != address_bytes + 1)
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() recv error (2)";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() Received String: ";
|
||||
for(int i = 0; i < 4 + address_bytes + 2; i++)
|
||||
std::cerr << (uint32_t) socks_response[i];
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
// should print address.
|
||||
// if we get here - connection is good!.
|
||||
mProxyState = PROXY_STATE_CONNECTION_COMPLETE;
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
72
libretroshare/src/pqi/pqiproxy.h
Normal file
72
libretroshare/src/pqi/pqiproxy.h
Normal file
@ -0,0 +1,72 @@
|
||||
/*******************************************************************************
|
||||
* libretroshare/src/pqi: pqiproxy.h *
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright 2004-2013 by Robert Fernie. *
|
||||
* Copyright 2004-2021 by 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 <string>
|
||||
|
||||
class pqiproxyconnection
|
||||
{
|
||||
public:
|
||||
enum ProxyState: uint8_t {
|
||||
PROXY_STATE_FAILED = 0x00,
|
||||
PROXY_STATE_INIT = 0x01,
|
||||
PROXY_STATE_WAITING_METHOD_RESPONSE = 0x02,
|
||||
PROXY_STATE_WAITING_SOCKS_RESPONSE = 0x03,
|
||||
PROXY_STATE_CONNECTION_COMPLETE = 0x04
|
||||
};
|
||||
|
||||
pqiproxyconnection() : mProxyState(PROXY_STATE_INIT) {}
|
||||
|
||||
/*!
|
||||
* \brief proxy_negotiate_connection
|
||||
* Negotiate the connection with the proxy that is connected with openned socket sockfd. The caller needs to
|
||||
* connect the socket *before* trying to call proxy_negotiate_connection(). The function must be called as many times as
|
||||
* necessary until it returns 1 (success) or -1 (error) in which case the socket needs to be closed.
|
||||
* \return
|
||||
* -1 : error. The socket must be closed as soon as possible.
|
||||
* 0 : in progress. The function needs to be called again asap.
|
||||
* 1 : proxy connection is fully negociated. Client can send data to the socket.
|
||||
*/
|
||||
int proxy_negociate_connection(int sockfd);
|
||||
|
||||
void setRemotePort(uint16_t v) { mRemotePort = v; }
|
||||
void setRemoteAddress(const std::string& s) { mDomainAddress = s; }
|
||||
|
||||
ProxyState proxyConnectionState() const { return mProxyState ; }
|
||||
|
||||
void proxy_init() { mProxyState = PROXY_STATE_INIT; }
|
||||
private:
|
||||
|
||||
ProxyState mProxyState;
|
||||
|
||||
std::string mDomainAddress;
|
||||
uint16_t mRemotePort;
|
||||
|
||||
// These are the internal steps in setting up the Proxy Connection.
|
||||
int Proxy_Send_Method(int sockfd);
|
||||
int Proxy_Method_Response(int sockfd);
|
||||
int Proxy_Send_Address(int sockfd);
|
||||
int Proxy_Connection_Complete(int sockfd);
|
||||
};
|
||||
|
@ -38,12 +38,6 @@ static struct RsLog::logInfo pqisslproxyzoneInfo = {RsLog::Default, "pqisslproxy
|
||||
// #define PROXY_DEBUG 1
|
||||
// #define PROXY_DEBUG_LOG 1
|
||||
|
||||
#define PROXY_STATE_FAILED 0
|
||||
#define PROXY_STATE_INIT 1
|
||||
#define PROXY_STATE_WAITING_METHOD_RESPONSE 2
|
||||
#define PROXY_STATE_WAITING_SOCKS_RESPONSE 3
|
||||
#define PROXY_STATE_CONNECTION_COMPLETE 4
|
||||
|
||||
pqisslproxy::pqisslproxy(pqissllistener *l, PQInterface *parent, p3LinkMgr *lm)
|
||||
:pqissl(l, parent, lm)
|
||||
{
|
||||
@ -74,7 +68,7 @@ int pqisslproxy::Initiate_Connection()
|
||||
rslog(RSL_DEBUG_BASIC, pqisslproxyzone,
|
||||
"pqisslproxy::Initiate_Connection() Connection to Proxy");
|
||||
/* init proxy state */
|
||||
mProxyState = PROXY_STATE_INIT;
|
||||
proxy_init();
|
||||
|
||||
/* call standard Init_Conn() */
|
||||
return pqissl::Initiate_Connection();
|
||||
@ -84,499 +78,31 @@ int pqisslproxy::Initiate_Connection()
|
||||
/********* VERY DIFFERENT **********/
|
||||
int pqisslproxy::Basic_Connection_Complete()
|
||||
{
|
||||
rslog(RSL_DEBUG_BASIC, pqisslproxyzone,
|
||||
"pqisslproxy::Basic_Connection_Complete()...");
|
||||
rslog(RSL_DEBUG_BASIC, pqisslproxyzone,
|
||||
"pqisslproxy::Basic_Connection_Complete()...");
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Basic_Connection_Complete() STATE: " << mProxyState;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "pqisslproxy::Basic_Connection_Complete() STATE: " << mProxyState;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
if (CheckConnectionTimeout())
|
||||
{
|
||||
// calls reset.
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
switch(mProxyState)
|
||||
{
|
||||
case PROXY_STATE_INIT:
|
||||
ret = Proxy_Send_Method(); // checks basic conn, sends Method when able.
|
||||
break;
|
||||
|
||||
case PROXY_STATE_WAITING_METHOD_RESPONSE:
|
||||
ret = Proxy_Send_Address(); // waits for Method Response, send Address when able.
|
||||
break;
|
||||
|
||||
case PROXY_STATE_WAITING_SOCKS_RESPONSE:
|
||||
ret = Proxy_Connection_Complete(); // wait for ACK.
|
||||
break;
|
||||
|
||||
case PROXY_STATE_CONNECTION_COMPLETE:
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Basic_Connection_Complete() COMPLETED";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
|
||||
case PROXY_STATE_FAILED:
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Basic_Connection_Complete() FAILED";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
reset_locked();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Basic_Connection_Complete() FAILED(2)";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
reset_locked();
|
||||
return -1; // FAILURE.
|
||||
}
|
||||
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Basic_Connection_Complete() IN PROGRESS";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
// In Progress.
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int pqisslproxy::Proxy_Send_Method()
|
||||
{
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Send_Method() Checking pqissl::Basic_Connection_Complete()";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
int ret = pqissl::Basic_Connection_Complete();
|
||||
if (ret != 1)
|
||||
{
|
||||
return ret; // basic connection not complete.
|
||||
}
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Send_Method() Basic complete, sending Method";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
/* send hello to proxy server */
|
||||
char method_hello_data[3] = { 0x05, 0x01, 0x00 }; // [ Ver | nMethods (1) | No Auth Method ]
|
||||
|
||||
int sent = send(sockfd, method_hello_data, 3, 0);
|
||||
if (sent != 3)
|
||||
{
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Send_Method() Send Failure";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Send_Method() Send Method Okay";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
mProxyState = PROXY_STATE_WAITING_METHOD_RESPONSE;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pqisslproxy::Proxy_Method_Response()
|
||||
{
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Method_Response()";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
/* get response from proxy server */
|
||||
|
||||
char method_response[2];
|
||||
|
||||
/*
|
||||
first it was:
|
||||
|
||||
int recvd = recv(sockfd, method_response, 2, MSG_WAITALL);
|
||||
|
||||
this does not work on windows, because the socket is in nonblocking mode
|
||||
the winsock reference says about the recv function and MSG_WAITALL:
|
||||
|
||||
"Note that if the underlying transport does not support MSG_WAITALL,
|
||||
or if the socket is in a non-blocking mode, then this call will fail with WSAEOPNOTSUPP."
|
||||
|
||||
now it is a two step process:
|
||||
|
||||
int recvd = recv(sockfd, method_response, 2, MSG_PEEK); // test how many bytes are in the input queue
|
||||
if (enaugh bytes available){
|
||||
recvd = recv(sockfd, method_response, 2, 0);
|
||||
}
|
||||
|
||||
this does not work on windows:
|
||||
if ((recvd == -1) && (errno == EAGAIN)) return TRY_AGAIN_LATER;
|
||||
|
||||
instead have to do:
|
||||
if ((recvd == -1) && (WSAGetLastError() == WSAEWOULDBLOCK)) return TRY_AGAIN_LATER;
|
||||
*/
|
||||
|
||||
// test how many bytes can be read from the queue
|
||||
int recvd = recv(sockfd, method_response, 2, MSG_PEEK);
|
||||
if (recvd != 2)
|
||||
{
|
||||
#ifdef WINDOWS_SYS
|
||||
if ((recvd == -1) && (WSAGetLastError() == WSAEWOULDBLOCK))
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Method_Response() waiting for more data (windows)";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if ((recvd == -1) && (errno == EAGAIN))
|
||||
{
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Method_Response() EAGAIN";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
else if (recvd == -1)
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Method_Response() recv error peek";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Method_Response() waiting for more data";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// read the bytes
|
||||
recvd = recv(sockfd, method_response, 2, 0);
|
||||
if (recvd != 2)
|
||||
if (CheckConnectionTimeout())
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Method_Response() recv error";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
// calls reset.
|
||||
return -1;
|
||||
}
|
||||
|
||||
// does it make sense?
|
||||
if (method_response[0] != 0x05)
|
||||
{
|
||||
int ret;
|
||||
|
||||
// Error.
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Method_Response() Error response[0] != 0x05. Is: ";
|
||||
std::cerr << (uint32_t) method_response[0];
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
if(proxyConnectionState() == PROXY_STATE_INIT && 1!=(ret=pqissl::Basic_Connection_Complete()))
|
||||
return ret; // basic connection not complete.
|
||||
|
||||
if (method_response[1] != 0x00)
|
||||
{
|
||||
ret = proxy_negociate_connection(sockfd);
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Method_Response() Error response[0] != 0x00. Is: ";
|
||||
std::cerr << (uint32_t) method_response[1];
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
// Error.
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Method_Response() Response Okay";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define MAX_SOCKS_REQUEST_LEN 262 // 4 + 1 + 255 + 2.
|
||||
|
||||
int pqisslproxy::Proxy_Send_Address()
|
||||
{
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Send_Address() Checking Method Response";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
// Check Method Response.
|
||||
int ret = Proxy_Method_Response();
|
||||
if (ret != 1)
|
||||
{
|
||||
return ret; // Method Response not complete.
|
||||
}
|
||||
|
||||
char socks_request[MAX_SOCKS_REQUEST_LEN] =
|
||||
{ 0x05, // SOCKS VERSION.
|
||||
0x01, // CONNECT (Tor doesn't support BIND or UDP).
|
||||
0x00, // RESERVED.
|
||||
0x03, // ADDRESS TYPE (Domain Name)
|
||||
0x00, // Length of Domain name... the rest is variable so can't hard code it!
|
||||
};
|
||||
|
||||
/* get the length of the domain name, pack so we can't overflow uint8_t */
|
||||
uint8_t len = mDomainAddress.length();
|
||||
socks_request[4] = len;
|
||||
for(int i = 0; i < len; i++)
|
||||
{
|
||||
socks_request[5 + i] = mDomainAddress[i];
|
||||
}
|
||||
|
||||
/* now add the port, being careful with packing */
|
||||
uint16_t net_port = htons(mRemotePort);
|
||||
socks_request[5 + len] = ((uint8_t *) &net_port)[0];
|
||||
socks_request[5 + len + 1] = ((uint8_t *) &net_port)[1];
|
||||
|
||||
int pkt_len = 5 + len + 2;
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Send_Address() Sending String: ";
|
||||
for(int i = 0; i < pkt_len; i++)
|
||||
std::cerr << (uint32_t) socks_request[i];
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
int sent = send(sockfd, socks_request, pkt_len, 0);
|
||||
if (sent != pkt_len)
|
||||
{
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Send_Address() Send Error";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Send_Address() Sent Okay";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
mProxyState = PROXY_STATE_WAITING_SOCKS_RESPONSE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pqisslproxy::Proxy_Connection_Complete()
|
||||
{
|
||||
/* get response from proxy server */
|
||||
/* response is similar format to request - with variable length data */
|
||||
|
||||
char socks_response[MAX_SOCKS_REQUEST_LEN];
|
||||
|
||||
// test how many bytes can be read
|
||||
int recvd = recv(sockfd, socks_response, 5, MSG_PEEK);
|
||||
if (recvd != 5)
|
||||
{
|
||||
#ifdef WINDOWS_SYS
|
||||
if ((recvd == -1) && (WSAGetLastError() == WSAEWOULDBLOCK))
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() waiting for more data (windows)";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if ((recvd == -1) && (errno == EAGAIN))
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() EAGAIN";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
else if (recvd == -1)
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() recv error peek";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() waiting for more data";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// read the bytes
|
||||
recvd = recv(sockfd, socks_response, 5, 0);
|
||||
if (recvd != 5)
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() recv error";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
// error checking.
|
||||
if (socks_response[0] != 0x05)
|
||||
{
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR socks_response[0] != 0x05. is: ";
|
||||
std::cerr << (uint32_t) socks_response[0];
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
// error.
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (socks_response[1] != 0x00)
|
||||
{
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR socks_response[1] != 0x00. is: ";
|
||||
std::cerr << (uint32_t) socks_response[1];
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
// connection failed.
|
||||
return -1;
|
||||
}
|
||||
|
||||
int address_bytes = 0;
|
||||
switch(socks_response[3]) // Address Type.
|
||||
{
|
||||
case 0x01:
|
||||
// IPv4 4 address bytes.
|
||||
address_bytes = 4;
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() IPv4 Address Type";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
break;
|
||||
case 0x04:
|
||||
// IPv6 16 address bytes.
|
||||
address_bytes = 16;
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() IPv6 Address Type";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
break;
|
||||
case 0x03:
|
||||
// Variable address bytes - specified in next byte.
|
||||
address_bytes = 1 + socks_response[4];
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() Domain Address Type. len: " << address_bytes;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
// unknown error.
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR Unknown Address Type";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// test how many bytes can be read
|
||||
recvd = recv(sockfd, &(socks_response[5]), address_bytes + 1, MSG_PEEK); // address_bytes - 1 + 2...
|
||||
if (recvd != address_bytes + 1)
|
||||
{
|
||||
#ifdef WINDOWS_SYS
|
||||
if((recvd == -1) && (WSAGetLastError() == WSAEWOULDBLOCK))
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() waiting for more data(2) (windows)";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if ((recvd == -1) && (errno == EAGAIN))
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR EAGAIN at end.";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
// Waiting - shouldn't happen.
|
||||
return 0;
|
||||
}
|
||||
else if (recvd == -1)
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR recving(2)";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() waiting for more data(2)";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// read the bytes
|
||||
recvd = recv(sockfd, &(socks_response[5]), address_bytes + 1, 0); // address_bytes - 1 + 2...
|
||||
if (recvd != address_bytes + 1)
|
||||
{
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() recv error (2)";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << "pqisslproxy::Proxy_Connection_Complete() Received String: ";
|
||||
for(int i = 0; i < 4 + address_bytes + 2; i++)
|
||||
std::cerr << (uint32_t) socks_response[i];
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
// should print address.
|
||||
// if we get here - connection is good!.
|
||||
mProxyState = PROXY_STATE_CONNECTION_COMPLETE;
|
||||
return 1;
|
||||
if(ret < 0)
|
||||
reset_locked();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool pqisslproxy::connect_parameter(uint32_t type, const std::string &value)
|
||||
@ -591,7 +117,7 @@ bool pqisslproxy::connect_parameter(uint32_t type, const std::string &value)
|
||||
rs_sprintf(out, "pqisslproxy::connect_parameter() Peer: %s DOMAIN_ADDRESS: %s", PeerId().toStdString().c_str(), value.c_str());
|
||||
rslog(RSL_WARNING, pqisslproxyzone, out);
|
||||
#endif
|
||||
mDomainAddress = value;
|
||||
setRemoteAddress(value);
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << out << std::endl;
|
||||
#endif
|
||||
@ -614,7 +140,7 @@ bool pqisslproxy::connect_parameter(uint32_t type, uint32_t value)
|
||||
#ifdef PROXY_DEBUG_LOG
|
||||
rslog(RSL_WARNING, pqisslproxyzone, out);
|
||||
#endif
|
||||
mRemotePort = value;
|
||||
setRemotePort(value);
|
||||
#ifdef PROXY_DEBUG
|
||||
std::cerr << out << std::endl;
|
||||
#endif
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
// operating system specific network header.
|
||||
#include "pqi/pqinetwork.h"
|
||||
#include "pqi/pqiproxy.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
@ -39,40 +40,27 @@
|
||||
* fns declared here are different -> all others are identical.
|
||||
*/
|
||||
|
||||
class pqisslproxy: public pqissl
|
||||
class pqisslproxy: public pqissl, public pqiproxyconnection
|
||||
{
|
||||
public:
|
||||
pqisslproxy(pqissllistener *l, PQInterface *parent, p3LinkMgr *lm);
|
||||
virtual ~pqisslproxy();
|
||||
pqisslproxy(pqissllistener *l, PQInterface *parent, p3LinkMgr *lm);
|
||||
virtual ~pqisslproxy();
|
||||
|
||||
// NetInterface. Is the same.
|
||||
// BinInterface. Is the same.
|
||||
// NetInterface. Is the same.
|
||||
// BinInterface. Is the same.
|
||||
|
||||
virtual bool connect_parameter(uint32_t type, const std::string &value);
|
||||
virtual bool connect_parameter(uint32_t type, uint32_t value);
|
||||
virtual bool connect_parameter(uint32_t type, const std::string &value);
|
||||
virtual bool connect_parameter(uint32_t type, uint32_t value);
|
||||
|
||||
protected:
|
||||
|
||||
//Initiate is the same - except it uses the Proxy Address rather than the Peer Address.
|
||||
// minor tweaks to setup data state.
|
||||
virtual int Initiate_Connection();
|
||||
//Initiate is the same - except it uses the Proxy Address rather than the Peer Address.
|
||||
// minor tweaks to setup data state.
|
||||
virtual int Initiate_Connection();
|
||||
|
||||
// The real overloading is done in Basic Connection Complete.
|
||||
// Instead of just checking for an open socket, we need to communicate with the SOCKS5 proxy.
|
||||
virtual int Basic_Connection_Complete();
|
||||
|
||||
// These are the internal steps in setting up the Proxy Connection.
|
||||
virtual int Proxy_Send_Method();
|
||||
virtual int Proxy_Method_Response();
|
||||
virtual int Proxy_Send_Address();
|
||||
virtual int Proxy_Connection_Complete();
|
||||
|
||||
private:
|
||||
|
||||
uint32_t mProxyState;
|
||||
|
||||
std::string mDomainAddress;
|
||||
uint16_t mRemotePort;
|
||||
// The real overloading is done in Basic Connection Complete.
|
||||
// Instead of just checking for an open socket, we need to communicate with the SOCKS5 proxy.
|
||||
virtual int Basic_Connection_Complete();
|
||||
};
|
||||
|
||||
#endif // MRK_PQI_SSL_PROXY_HEADER
|
||||
|
@ -357,6 +357,7 @@ int pqistreamer::status()
|
||||
// this method is overloaded by pqiqosstreamer
|
||||
void pqistreamer::locked_storeInOutputQueue(void *ptr,int,int)
|
||||
{
|
||||
RsDbg() << "Storing packet " << std::hex << ptr << std::dec << " in outqueue.";
|
||||
mOutPkts.push_back(ptr);
|
||||
}
|
||||
|
||||
@ -521,7 +522,7 @@ int pqistreamer::handleoutgoing_locked()
|
||||
{
|
||||
/* if we are not active - clear anything in the queues. */
|
||||
locked_clear_out_queue() ;
|
||||
#ifdef DEBUG_PACKET_SLICING
|
||||
#ifdef DEBUG_PACKET_SLICING
|
||||
std::cerr << "(II) Switching off packet slicing." << std::endl;
|
||||
#endif
|
||||
mAcceptsPacketSlicing = false ;
|
||||
@ -683,7 +684,7 @@ int pqistreamer::handleoutgoing_locked()
|
||||
outSentBytes_locked(mPkt_wpending_size); // this is the only time where we know exactly what was sent.
|
||||
|
||||
#ifdef DEBUG_TRANSFERS
|
||||
std::cerr << "pqistreamer::handleoutgoing_locked() Sent Packet len: " << mPkt_wpending_size << " @ " << RsUtil::AccurateTimeString();
|
||||
std::cerr << "pqistreamer::handleoutgoing_locked() Sent Packet len: " << mPkt_wpending_size << " @ " << getCurrentTS();
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
@ -693,7 +694,7 @@ int pqistreamer::handleoutgoing_locked()
|
||||
mPkt_wpending = NULL;
|
||||
mPkt_wpending_size = 0 ;
|
||||
|
||||
sent = true;
|
||||
sent = true;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_PQISTREAMER
|
||||
@ -802,11 +803,14 @@ start_packet_read:
|
||||
|
||||
if(!memcmp(block,PACKET_SLICING_PROBE_BYTES,8))
|
||||
{
|
||||
mAcceptsPacketSlicing = !DISABLE_PACKET_SLICING;
|
||||
mAcceptsPacketSlicing = !DISABLE_PACKET_SLICING;
|
||||
#ifdef DEBUG_PACKET_SLICING
|
||||
std::cerr << "(II) Enabling packet slicing!" << std::endl;
|
||||
#endif
|
||||
}
|
||||
mReading_state = reading_state_initial ; // restart at state 1.
|
||||
mFailed_read_attempts = 0 ;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
continue_packet:
|
||||
{
|
||||
@ -1430,8 +1434,12 @@ void *pqistreamer::locked_pop_out_data(uint32_t /*max_slice_size*/, uint32_t &si
|
||||
{
|
||||
res = *(mOutPkts.begin());
|
||||
mOutPkts.pop_front();
|
||||
|
||||
// In pqistreamer, we do not split outgoing packets. For now only pqiQoSStreamer supports packet slicing.
|
||||
size = getRsItemSize(res);
|
||||
|
||||
#ifdef DEBUG_TRANSFERS
|
||||
std::cerr << "pqistreamer::locked_pop_out_data() getting next pkt from mOutPkts queue";
|
||||
std::cerr << "pqistreamer::locked_pop_out_data() getting next pkt " << std::hex << res << std::dec << " from mOutPkts queue";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
@ -31,8 +31,8 @@ public:
|
||||
pqithreadstreamer(PQInterface *parent, RsSerialiser *rss, const RsPeerId& peerid, BinInterface *bio_in, int bio_flagsin);
|
||||
|
||||
// from pqistreamer
|
||||
virtual bool RecvItem(RsItem *item);
|
||||
virtual int tick();
|
||||
virtual bool RecvItem(RsItem *item) override;
|
||||
virtual int tick() override;
|
||||
|
||||
protected:
|
||||
void threadTick() override; /// @see RsTickingThread
|
||||
|
39
libretroshare/src/retroshare/rsfriendserver.h
Normal file
39
libretroshare/src/retroshare/rsfriendserver.h
Normal file
@ -0,0 +1,39 @@
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include "util/rstime.h"
|
||||
|
||||
// The Friend Server component of Retroshare automatically adds/removes some friends so that the
|
||||
//
|
||||
// The current strategy is:
|
||||
//
|
||||
// - if total nb of friends < S
|
||||
// request new friends to the FS
|
||||
// - if total nb of friends >= S
|
||||
// do not request anymore (and unpublish the key), but keep the friends already here
|
||||
//
|
||||
// Possible states:
|
||||
// - not started
|
||||
// - maintain friend list
|
||||
// - actively request friends
|
||||
//
|
||||
// The friend server internally keeps track of which friends have been added using the friend server.
|
||||
// It's important to keep the ones that are already connected because they may count on us.
|
||||
// Friends supplied by the FS who never connected for a few days should be removed automatically.
|
||||
|
||||
class RsFriendServer
|
||||
{
|
||||
public:
|
||||
virtual void startServer() =0;
|
||||
virtual void stopServer() =0;
|
||||
|
||||
virtual void checkServerAddress_async(const std::string& addr,uint16_t, const std::function<void (const std::string& address,bool result_status)>& callback) =0;
|
||||
virtual void setServerAddress(const std::string&,uint16_t) =0;
|
||||
virtual void setProxyAddress(const std::string&,uint16_t) =0;
|
||||
virtual void setFriendsToRequest(uint32_t) =0;
|
||||
|
||||
virtual uint32_t friendsToRequest() =0;
|
||||
virtual uint16_t friendsServerPort() =0;
|
||||
virtual std::string friendsServerAddress() =0;
|
||||
};
|
||||
|
||||
extern RsFriendServer *rsFriendServer;
|
@ -168,6 +168,15 @@ struct t_RsGenericIdType
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline Id_t operator^ (const Id_t& fp) const
|
||||
{
|
||||
Id_t ret;
|
||||
for(uint32_t i=0; i < ID_SIZE_IN_BYTES; ++i)
|
||||
ret.bytes[i] = bytes[i] ^ fp.bytes[i];
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
inline bool isNull() const
|
||||
{
|
||||
for(uint32_t i=0; i < SIZE_IN_BYTES; ++i)
|
||||
|
@ -54,7 +54,8 @@ enum class RsServiceType : uint16_t
|
||||
|
||||
BANLIST = 0x0101,
|
||||
STATUS = 0x0102,
|
||||
NXS = 0x0200,
|
||||
FRIEND_SERVER = 0x0103,
|
||||
NXS = 0x0200,
|
||||
GXSID = 0x0211,
|
||||
PHOTO = 0x0212,
|
||||
WIKI = 0x0213,
|
||||
@ -115,6 +116,8 @@ RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_DISTANT_CHAT =
|
||||
RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_GXS_TUNNEL = 0x0028;
|
||||
RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_BANLIST = 0x0101;
|
||||
RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_STATUS = 0x0102;
|
||||
RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_FRIEND_SERVER = 0x0103;
|
||||
|
||||
/// Rs Network Exchange Service
|
||||
RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_NXS = 0x0200;
|
||||
RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_GXS_TYPE_GXSID = 0x0211;
|
||||
|
@ -48,6 +48,7 @@
|
||||
|
||||
#include "pqi/authssl.h"
|
||||
|
||||
typedef RsCertificate::RsShortInviteFieldType RsShortInviteFieldType; // locally in this file to avoid renaming everything.
|
||||
|
||||
RsPeers *rsPeers = NULL;
|
||||
|
||||
@ -1162,22 +1163,6 @@ bool p3Peers::GetPGPBase64StringAndCheckSum(
|
||||
return true;
|
||||
}
|
||||
|
||||
enum class RsShortInviteFieldType : uint8_t
|
||||
{
|
||||
SSL_ID = 0x00,
|
||||
PEER_NAME = 0x01,
|
||||
LOCATOR = 0x02,
|
||||
PGP_FINGERPRINT = 0x03,
|
||||
CHECKSUM = 0x04,
|
||||
|
||||
/* The following will be deprecated, and ported to LOCATOR when generic
|
||||
* trasport layer will be implemented */
|
||||
HIDDEN_LOCATOR = 0x90,
|
||||
DNS_LOCATOR = 0x91,
|
||||
EXT4_LOCATOR = 0x92, // external IPv4 address
|
||||
LOC4_LOCATOR = 0x93 // local IPv4 address
|
||||
};
|
||||
|
||||
static void addPacketHeader(RsShortInviteFieldType ptag, size_t size, unsigned char *& buf, uint32_t& offset, uint32_t& buf_size)
|
||||
{
|
||||
// Check that the buffer has sufficient size. If not, increase it.
|
||||
@ -1373,136 +1358,23 @@ bool p3Peers::getShortInvite(std::string& invite, const RsPeerId& _sslId, Retros
|
||||
|
||||
bool p3Peers::parseShortInvite(const std::string& inviteStrUrl, RsPeerDetails& details, uint32_t &err_code )
|
||||
{
|
||||
if(inviteStrUrl.empty())
|
||||
{
|
||||
RsErr() << __PRETTY_FUNCTION__ << " can't parse empty invite"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
std::string rsInvite = inviteStrUrl;
|
||||
if(inviteStrUrl.empty())
|
||||
{
|
||||
RsErr() << __PRETTY_FUNCTION__ << " can't parse empty invite"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
std::string rsInvite = inviteStrUrl;
|
||||
|
||||
RsUrl inviteUrl(inviteStrUrl);
|
||||
RsUrl inviteUrl(inviteStrUrl);
|
||||
|
||||
if(inviteUrl.hasQueryK("rsInvite"))
|
||||
rsInvite = *inviteUrl.getQueryV("rsInvite");
|
||||
if(inviteUrl.hasQueryK("rsInvite"))
|
||||
rsInvite = *inviteUrl.getQueryV("rsInvite");
|
||||
|
||||
std::vector<uint8_t> bf = Radix64::decode(rsInvite);
|
||||
size_t size = bf.size();
|
||||
if(!RsCertificate::decodeRadix64ShortInvite(rsInvite, details, err_code))
|
||||
return false;
|
||||
|
||||
unsigned char* buf = bf.data();
|
||||
size_t total_s = 0;
|
||||
bool CRC_ok = false ; // not checked yet
|
||||
|
||||
while(total_s < size)
|
||||
{
|
||||
RsShortInviteFieldType ptag = RsShortInviteFieldType(buf[0]);
|
||||
buf = &buf[1];
|
||||
|
||||
unsigned char *buf2 = buf;
|
||||
uint32_t s = 0;
|
||||
|
||||
try { s = PGPKeyParser::read_125Size(buf); }
|
||||
catch (...)
|
||||
{
|
||||
err_code = CERTIFICATE_PARSING_ERROR_SIZE_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
total_s += 1 + ( reinterpret_cast<size_t>(buf) - reinterpret_cast<size_t>(buf2) );
|
||||
|
||||
if(total_s > size)
|
||||
{
|
||||
err_code = CERTIFICATE_PARSING_ERROR_SIZE_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
Dbg3() << __PRETTY_FUNCTION__ << " Read ptag: "
|
||||
<< static_cast<uint32_t>(ptag)
|
||||
<< ", size " << s << ", total_s = " << total_s
|
||||
<< ", expected total = " << size << std::endl;
|
||||
|
||||
switch(ptag)
|
||||
{
|
||||
case RsShortInviteFieldType::SSL_ID:
|
||||
details.id = RsPeerId::fromBufferUnsafe(buf) ;
|
||||
break;
|
||||
|
||||
case RsShortInviteFieldType::PEER_NAME:
|
||||
details.name = std::string((char*)buf,s);
|
||||
break;
|
||||
|
||||
case RsShortInviteFieldType::PGP_FINGERPRINT:
|
||||
details.fpr = RsPgpFingerprint::fromBufferUnsafe(buf);
|
||||
details.gpg_id = PGPHandler::pgpIdFromFingerprint(details.fpr);
|
||||
break;
|
||||
|
||||
case RsShortInviteFieldType::LOCATOR:
|
||||
{
|
||||
std::string locatorStr((char*)buf,s);
|
||||
details.ipAddressList.push_back(locatorStr);
|
||||
}
|
||||
break;
|
||||
|
||||
case RsShortInviteFieldType::DNS_LOCATOR:
|
||||
details.extPort = (((int)buf[0]) << 8) + buf[1];
|
||||
details.dyndns = std::string((char*)&buf[2],s-2);
|
||||
break;
|
||||
|
||||
case RsShortInviteFieldType::LOC4_LOCATOR:
|
||||
{
|
||||
uint32_t t4Addr = (((uint32_t)buf[0]) << 24)+(((uint32_t)buf[1])<<16)+(((uint32_t)buf[2])<<8) + (uint32_t)buf[3];
|
||||
sockaddr_in tLocalAddr;
|
||||
tLocalAddr.sin_addr.s_addr = t4Addr;
|
||||
|
||||
details.localAddr = rs_inet_ntoa(tLocalAddr.sin_addr);
|
||||
details.localPort = (((uint32_t)buf[4])<<8) + (uint32_t)buf[5];
|
||||
}
|
||||
break;
|
||||
|
||||
case RsShortInviteFieldType::EXT4_LOCATOR:
|
||||
{
|
||||
uint32_t t4Addr = (((uint32_t)buf[0]) << 24)+(((uint32_t)buf[1])<<16)+(((uint32_t)buf[2])<<8) + (uint32_t)buf[3];
|
||||
sockaddr_in tExtAddr;
|
||||
tExtAddr.sin_addr.s_addr = t4Addr;
|
||||
|
||||
details.extAddr = rs_inet_ntoa(tExtAddr.sin_addr);
|
||||
details.extPort = (((uint32_t)buf[4])<<8) + (uint32_t)buf[5];
|
||||
}
|
||||
break;
|
||||
|
||||
case RsShortInviteFieldType::HIDDEN_LOCATOR:
|
||||
details.hiddenType = (((uint32_t)buf[0]) << 24)+(((uint32_t)buf[1])<<16)+(((uint32_t)buf[2])<<8) + (uint32_t)buf[3];
|
||||
details.hiddenNodePort = (((uint32_t)buf[4]) << 8)+ (uint32_t)buf[5];
|
||||
details.isHiddenNode = true;
|
||||
details.hiddenNodeAddress = std::string((char*)&buf[6],s-6);
|
||||
break;
|
||||
|
||||
case RsShortInviteFieldType::CHECKSUM:
|
||||
{
|
||||
if(s != 3 || total_s+3 != size) // make sure the checksum is the last section
|
||||
{
|
||||
err_code = CERTIFICATE_PARSING_ERROR_INVALID_CHECKSUM_SECTION;
|
||||
return false;
|
||||
}
|
||||
uint32_t computed_crc = PGPKeyManagement::compute24bitsCRC(bf.data(),size-5);
|
||||
uint32_t certificate_crc = static_cast<uint32_t>( buf[0] + (buf[1] << 8) + (buf[2] << 16) );
|
||||
|
||||
if(computed_crc != certificate_crc)
|
||||
{
|
||||
err_code = CERTIFICATE_PARSING_ERROR_CHECKSUM_ERROR;
|
||||
return false;
|
||||
}
|
||||
CRC_ok = true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
buf = &buf[s];
|
||||
total_s += s;
|
||||
}
|
||||
|
||||
// now check if the PGP key is available. If so, add it in the PeerDetails:
|
||||
// Also check if the PGP key is available. If so, add it in the PeerDetails:
|
||||
|
||||
RsPeerDetails pgp_det ;
|
||||
if(getGPGDetails(PGPHandler::pgpIdFromFingerprint(details.fpr),pgp_det) && pgp_det.fpr == details.fpr)
|
||||
@ -1519,23 +1391,13 @@ bool p3Peers::parseShortInvite(const std::string& inviteStrUrl, RsPeerDetails& d
|
||||
else
|
||||
details.skip_pgp_signature_validation = true;
|
||||
|
||||
if(!CRC_ok)
|
||||
{
|
||||
err_code = CERTIFICATE_PARSING_ERROR_CHECKSUM_ERROR;
|
||||
return false;
|
||||
}
|
||||
if(details.gpg_id.isNull())
|
||||
{
|
||||
err_code = CERTIFICATE_PARSING_ERROR_MISSING_PGP_FINGERPRINT;
|
||||
return false;
|
||||
}
|
||||
if(details.id.isNull())
|
||||
{
|
||||
err_code = CERTIFICATE_PARSING_ERROR_MISSING_LOCATION_ID;
|
||||
return false;
|
||||
}
|
||||
err_code = CERTIFICATE_PARSING_ERROR_NO_ERROR;
|
||||
return true;
|
||||
err_code = CERTIFICATE_PARSING_ERROR_NO_ERROR;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool p3Peers::acceptInvite( const std::string& invite,
|
||||
|
@ -52,6 +52,10 @@
|
||||
#include "rsserver/rsloginhandler.h"
|
||||
#include "rsserver/rsaccounts.h"
|
||||
|
||||
#ifdef RS_EMBEDED_FRIEND_SERVER
|
||||
#include "friend_server/fsmanager.h"
|
||||
#endif
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
@ -1175,6 +1179,11 @@ int RsServer::StartupRetroShare()
|
||||
|
||||
serviceCtrl->setServiceServer(pqih) ;
|
||||
|
||||
#ifdef RS_EMBEDED_FRIEND_SERVER
|
||||
// setup friend server
|
||||
rsFriendServer = new FriendServerManager();
|
||||
#endif
|
||||
|
||||
/****** New Ft Server **** !!! */
|
||||
ftServer *ftserver = new ftServer(mPeerMgr, serviceCtrl);
|
||||
ftserver->setConfigDirectory(RsAccounts::AccountDirectory());
|
||||
@ -1936,6 +1945,12 @@ int RsServer::StartupRetroShare()
|
||||
|
||||
std::string RsInit::executablePath()
|
||||
{
|
||||
if(rsInitConfig->mainExecutablePath.empty())
|
||||
{
|
||||
RsErr() << "Main executable path not set! Plz call RsInit::InitRetroShare(conf) with conf.main_executable_path = argv[0]";
|
||||
assert(false);
|
||||
}
|
||||
|
||||
return rsInitConfig->mainExecutablePath;
|
||||
}
|
||||
bool RsInit::startAutoTor()
|
||||
|
@ -142,6 +142,8 @@ std::string TorManager::torDataDirectory() const
|
||||
|
||||
void TorManager::setTorDataDirectory(const std::string &path)
|
||||
{
|
||||
assert(RsDirUtil::checkCreateDirectory(std::string(path)));
|
||||
|
||||
d->dataDir = path;
|
||||
|
||||
if (!d->dataDir.empty() && !ByteArray(d->dataDir).endsWith('/'))
|
||||
|
414
retroshare-friendserver/src/friendserver.cc
Normal file
414
retroshare-friendserver/src/friendserver.cc
Normal file
@ -0,0 +1,414 @@
|
||||
#include "util/rsdebug.h"
|
||||
#include "util/rsprint.h"
|
||||
#include "util/rsdir.h"
|
||||
#include "util/rsbase64.h"
|
||||
#include "util/radix64.h"
|
||||
|
||||
#include "pgp/pgpkeyutil.h"
|
||||
#include "pgp/rscertificate.h"
|
||||
#include "pgp/openpgpsdkhandler.h"
|
||||
|
||||
#include "friendserver.h"
|
||||
#include "friend_server/fsitem.h"
|
||||
|
||||
static const rstime_t MAXIMUM_PEER_INACTIVE_DELAY = 600;
|
||||
static const rstime_t DELAY_BETWEEN_TWO_AUTOWASH = 60;
|
||||
static const rstime_t DELAY_BETWEEN_TWO_DEBUG_PRINT = 10;
|
||||
static const uint32_t MAXIMUM_PEERS_TO_REQUEST = 10;
|
||||
|
||||
void FriendServer::threadTick()
|
||||
{
|
||||
// Listen to the network interface, capture incoming data etc.
|
||||
|
||||
RsItem *item;
|
||||
|
||||
while(nullptr != (item = mni->GetItem()))
|
||||
{
|
||||
RsFriendServerItem *fsitem = dynamic_cast<RsFriendServerItem*>(item);
|
||||
|
||||
if(!fsitem)
|
||||
{
|
||||
RsErr() << "Received an item of the wrong type!" ;
|
||||
|
||||
continue;
|
||||
}
|
||||
std::cerr << "Received item: " << std::endl << *fsitem << std::endl;
|
||||
|
||||
switch(fsitem->PacketSubType())
|
||||
{
|
||||
case RS_PKT_SUBTYPE_FS_CLIENT_PUBLISH: handleClientPublish(dynamic_cast<RsFriendServerClientPublishItem*>(fsitem));
|
||||
break;
|
||||
case RS_PKT_SUBTYPE_FS_CLIENT_REMOVE: handleClientRemove(dynamic_cast<RsFriendServerClientRemoveItem*>(fsitem));
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
delete item;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
|
||||
static rstime_t last_autowash_TS = time(nullptr);
|
||||
rstime_t now = time(nullptr);
|
||||
|
||||
if(last_autowash_TS + DELAY_BETWEEN_TWO_AUTOWASH < now)
|
||||
{
|
||||
last_autowash_TS = now;
|
||||
autoWash();
|
||||
}
|
||||
|
||||
static rstime_t last_debugprint_TS = time(nullptr);
|
||||
|
||||
if(last_debugprint_TS + DELAY_BETWEEN_TWO_DEBUG_PRINT < now)
|
||||
{
|
||||
last_debugprint_TS = now;
|
||||
debugPrint();
|
||||
}
|
||||
}
|
||||
|
||||
void FriendServer::handleClientPublish(const RsFriendServerClientPublishItem *item)
|
||||
{
|
||||
// We always respond with exactly one item, be it an error item or a list of friends to connect to.
|
||||
|
||||
try
|
||||
{
|
||||
RsDbg() << "Received a client publish item from " << item->PeerId() << ":";
|
||||
RsDbg() << *item ;
|
||||
|
||||
// First of all, read PGP key and short invites, parse them, and check that they contain the same information
|
||||
|
||||
std::map<RsPeerId,PeerInfo>::iterator pi = handleIncomingClientData(item->pgp_public_key_b64,item->short_invite);
|
||||
|
||||
// No need to test for it==mCurrentClients.end() because it will be directly caught by the exception handling below even before.
|
||||
// Respond with a list of potential friends
|
||||
|
||||
RsDbg() << "Sending response item to " << item->PeerId() ;
|
||||
|
||||
RsFriendServerServerResponseItem *sr_item = new RsFriendServerServerResponseItem;
|
||||
|
||||
std::map<RsPeerId,RsPgpFingerprint> friends;
|
||||
sr_item->nonce = pi->second.last_nonce;
|
||||
sr_item->friend_invites = computeListOfFriendInvites(item->n_requested_friends,pi->first,friends);
|
||||
sr_item->PeerId(item->PeerId());
|
||||
|
||||
// Update the have_added_as_friend for the list of each peer. We do that before sending because sending destroys
|
||||
// the item.
|
||||
|
||||
for(const auto& pid:friends)
|
||||
{
|
||||
auto& p(mCurrentClientPeers[pid.first]);
|
||||
p.have_added_this_peer[computePeerDistance(p.pgp_fingerprint, pi->second.pgp_fingerprint)] = pi->first;
|
||||
}
|
||||
|
||||
// Now encrypt the item with the public PGP key of the destination. This prevents the wrong person to request for
|
||||
// someone else's data.
|
||||
#warning TODO
|
||||
|
||||
// Send the item.
|
||||
mni->SendItem(sr_item);
|
||||
|
||||
// Update the list of closest peers for all peers currently in the database.
|
||||
|
||||
updateClosestPeers(pi->first,pi->second.pgp_fingerprint);
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
RsErr() << "ERROR: " << e.what() ;
|
||||
|
||||
RsFriendServerStatusItem *status_item = new RsFriendServerStatusItem;
|
||||
status_item->status = RsFriendServerStatusItem::END_OF_TRANSMISSION;
|
||||
status_item->PeerId(item->PeerId());
|
||||
mni->SendItem(status_item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, bool> FriendServer::computeListOfFriendInvites(uint32_t nb_reqs_invites, const RsPeerId &pid, std::map<RsPeerId,RsPgpFingerprint>& friends)
|
||||
{
|
||||
// Strategy: we want to return the same set of friends for a given PGP profile key.
|
||||
// Still, using some closest distance strategy, the n-closest peers for profile A is not the
|
||||
// same set than the n-closest peers for profile B. We have multiple options:
|
||||
//
|
||||
// Option 1:
|
||||
//
|
||||
// (1) for each profile, keep the list of n-closest peers updated (when a new peer if added/removed all lists are updated)
|
||||
//
|
||||
// When a peer asks for k friends, read from (1), until the number of collected peers
|
||||
// reaches the requested value. Then when a peer receives a connection request, ask the friend server if the
|
||||
// peer has been sent your own cert.
|
||||
//
|
||||
// Option 2:
|
||||
//
|
||||
// (1) for each profile, keep the list of n-closest peers updated (when a new peer if added/removed all lists are updated)
|
||||
// (2) for each profile, keep the list of which peers have been sent this profile already
|
||||
//
|
||||
// When a peer asks for k friends, read from (2) first, then (1), until the number of collected peers
|
||||
// reaches the requested value.
|
||||
//
|
||||
// So we choose Option 2.
|
||||
|
||||
std::map<std::string,bool> res;
|
||||
|
||||
auto add_from = [&res,&friends,nb_reqs_invites,this](bool added,const std::map<PeerInfo::PeerDistance,RsPeerId>& lst) -> bool
|
||||
{
|
||||
for(const auto& pid:lst)
|
||||
{
|
||||
const auto p = mCurrentClientPeers.find(pid.second);
|
||||
res.insert(std::make_pair(p->second.short_certificate,added));
|
||||
friends.insert(std::make_pair(p->first,p->second.pgp_fingerprint));
|
||||
|
||||
if(res.size() >= nb_reqs_invites)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const auto& pinfo(mCurrentClientPeers[pid]);
|
||||
|
||||
// First add from peers who already added the current peer as friend, and leave if we already have enough
|
||||
|
||||
if(add_from(true,pinfo.have_added_this_peer))
|
||||
return res;
|
||||
|
||||
add_from(false,pinfo.closest_peers);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::map<RsPeerId,PeerInfo>::iterator FriendServer::handleIncomingClientData(const std::string& pgp_public_key_b64,const std::string& short_invite_b64)
|
||||
{
|
||||
// 1 - Check that the incoming data is sound.
|
||||
|
||||
RsDbg() << " Checking item data...";
|
||||
|
||||
std::string error_string;
|
||||
std::vector<uint8_t> key_binary_data ;
|
||||
|
||||
if(RsBase64::decode(pgp_public_key_b64,key_binary_data))
|
||||
throw std::runtime_error(" Cannot decode client pgp public key: \"" + pgp_public_key_b64 + "\". Wrong format??");
|
||||
|
||||
RsDbg() << " Parsing public key:" ;
|
||||
|
||||
PGPKeyInfo received_key_info;
|
||||
|
||||
if(!PGPKeyManagement::parsePGPPublicKey(key_binary_data.data(),key_binary_data.size(),received_key_info))
|
||||
throw std::runtime_error("Cannot parse received pgp public key.") ;
|
||||
|
||||
RsDbg() << " Issuer : \"" << received_key_info.user_id << "\"" ;
|
||||
RsDbg() << " Fingerprint: " << RsPgpFingerprint::fromBufferUnsafe(received_key_info.fingerprint) ;
|
||||
|
||||
RsDbg() << " Parsing short invite:" ;
|
||||
|
||||
RsPeerDetails shortInviteDetails;
|
||||
uint32_t errorCode = 0;
|
||||
|
||||
if(short_invite_b64.empty() || !RsCertificate::decodeRadix64ShortInvite(short_invite_b64, shortInviteDetails,errorCode ))
|
||||
throw std::runtime_error("Could not parse short certificate. Error = " + RsUtil::NumberToString(errorCode));
|
||||
|
||||
RsDbg() << " Fingerprint: " << shortInviteDetails.fpr ;
|
||||
RsDbg() << " Peer ID: " << shortInviteDetails.id ;
|
||||
|
||||
if(shortInviteDetails.fpr != RsPgpFingerprint::fromBufferUnsafe(received_key_info.fingerprint))
|
||||
throw std::runtime_error("Fingerpring from short invite and public key are different! Very unexpected! Message will be ignored.");
|
||||
|
||||
// 3 - if the key is not already here, add it to keyring.
|
||||
|
||||
{
|
||||
RsPgpFingerprint fpr_test;
|
||||
if(mPgpHandler->isPgpPubKeyAvailable(RsPgpId::fromBufferUnsafe(received_key_info.fingerprint+12)))
|
||||
RsDbg() << " PGP Key is already into keyring.";
|
||||
else
|
||||
{
|
||||
RsPgpId pgp_id;
|
||||
if(!mPgpHandler->LoadCertificateFromBinaryData(key_binary_data.data(),key_binary_data.size(), pgp_id, error_string))
|
||||
throw std::runtime_error("Cannot load client's pgp public key into keyring: " + error_string) ;
|
||||
|
||||
RsDbg() << " Public key added to keyring.";
|
||||
RsDbg() << " Sync-ing the PGP keyring on disk";
|
||||
|
||||
mPgpHandler->syncDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
// All good.
|
||||
|
||||
// Store/update the peer info
|
||||
|
||||
auto& pi(mCurrentClientPeers[shortInviteDetails.id]);
|
||||
|
||||
pi.short_certificate = short_invite_b64;
|
||||
pi.last_connection_TS = time(nullptr);
|
||||
pi.pgp_fingerprint = shortInviteDetails.fpr;
|
||||
|
||||
while(pi.last_nonce == 0) // reuse the same identifier (so it's not really a nonce, but it's kept secret whatsoever).
|
||||
pi.last_nonce = RsRandom::random_u64();
|
||||
|
||||
return mCurrentClientPeers.find(shortInviteDetails.id);
|
||||
}
|
||||
|
||||
|
||||
void FriendServer::handleClientRemove(const RsFriendServerClientRemoveItem *item)
|
||||
{
|
||||
RsDbg() << "Received a client remove item:" << *item ;
|
||||
|
||||
auto it = mCurrentClientPeers.find(item->peer_id);
|
||||
|
||||
if(it == mCurrentClientPeers.end())
|
||||
{
|
||||
RsErr() << " ERROR: Client " << item->peer_id << " is not known to the server." ;
|
||||
return;
|
||||
}
|
||||
|
||||
if(it->second.last_nonce != item->nonce)
|
||||
{
|
||||
RsErr() << " ERROR: Client supplied a nonce " << std::hex << item->nonce << std::dec << " that is not correct (expected "
|
||||
<< std::hex << it->second.last_nonce << std::dec << ")";
|
||||
return;
|
||||
}
|
||||
|
||||
RsDbg() << " Nonce is correct: " << std::hex << item->nonce << std::dec << ". Removing peer " << item->peer_id ;
|
||||
|
||||
removePeer(item->peer_id);
|
||||
}
|
||||
|
||||
void FriendServer::removePeer(const RsPeerId& peer_id)
|
||||
{
|
||||
auto it = mCurrentClientPeers.find(peer_id);
|
||||
|
||||
if(it != mCurrentClientPeers.end())
|
||||
mCurrentClientPeers.erase(it);
|
||||
|
||||
for(auto& it:mCurrentClientPeers)
|
||||
{
|
||||
// Also remove that peer from all n-closest lists
|
||||
|
||||
for(auto pit(it.second.closest_peers.begin());pit!=it.second.closest_peers.end();)
|
||||
if(pit->second == peer_id)
|
||||
{
|
||||
RsDbg() << " Removing from n-closest peers of peer " << pit->first ;
|
||||
|
||||
auto tmp(pit);
|
||||
++tmp;
|
||||
it.second.closest_peers.erase(pit);
|
||||
pit=tmp;
|
||||
}
|
||||
else
|
||||
++pit;
|
||||
|
||||
// Also remove that peer from peers that have accepted each peer
|
||||
|
||||
for(auto fit(it.second.have_added_this_peer.begin());fit!=it.second.have_added_this_peer.end();)
|
||||
if(fit->second == peer_id)
|
||||
{
|
||||
RsDbg() << " Removing from have_added_as_friend peers of peer " << fit->first ;
|
||||
|
||||
auto tmp(fit);
|
||||
++tmp;
|
||||
it.second.closest_peers.erase(fit);
|
||||
fit=tmp;
|
||||
}
|
||||
else
|
||||
++fit;
|
||||
}
|
||||
}
|
||||
|
||||
PeerInfo::PeerDistance FriendServer::computePeerDistance(const RsPgpFingerprint& p1,const RsPgpFingerprint& p2)
|
||||
{
|
||||
std::cerr << "Computing peer distance: p1=" << p1 << " p2=" << p2 << " p1^p2=" << (p1^p2) << " distance=" << ((p1^p2)^mRandomPeerBias) << std::endl;
|
||||
return (p1 ^ p2)^mRandomPeerBias;
|
||||
}
|
||||
FriendServer::FriendServer(const std::string& base_dir,const std::string& listening_address,uint16_t listening_port)
|
||||
: mListeningAddress(listening_address),mListeningPort(listening_port)
|
||||
{
|
||||
RsDbg() << "Creating friend server." ;
|
||||
mBaseDirectory = base_dir;
|
||||
|
||||
// Create a PGP Handler
|
||||
|
||||
std::string pgp_public_keyring_path = RsDirUtil::makePath(base_dir,"pgp_public_keyring") ;
|
||||
std::string pgp_lock_path = RsDirUtil::makePath(base_dir,"pgp_lock") ;
|
||||
|
||||
std::string pgp_private_keyring_path = RsDirUtil::makePath(base_dir,"pgp_private_keyring") ; // not used.
|
||||
std::string pgp_trustdb_path = RsDirUtil::makePath(base_dir,"pgp_trustdb") ; // not used.
|
||||
|
||||
mPgpHandler = new OpenPGPSDKHandler(pgp_public_keyring_path,pgp_private_keyring_path,pgp_trustdb_path,pgp_lock_path);
|
||||
|
||||
// Random bias. Should be cryptographically safe.
|
||||
|
||||
mRandomPeerBias = RsPgpFingerprint::random();
|
||||
}
|
||||
|
||||
void FriendServer::run()
|
||||
{
|
||||
// 1 - create network interface.
|
||||
|
||||
mni = new FsNetworkInterface(mListeningAddress,mListeningPort);
|
||||
mni->start();
|
||||
|
||||
while(!shouldStop()) { threadTick() ; }
|
||||
}
|
||||
|
||||
void FriendServer::autoWash()
|
||||
{
|
||||
rstime_t now = time(nullptr);
|
||||
RsDbg() << "autoWash..." ;
|
||||
|
||||
std::list<RsPeerId> to_remove;
|
||||
|
||||
for(std::map<RsPeerId,PeerInfo>::iterator it(mCurrentClientPeers.begin());it!=mCurrentClientPeers.end();++it)
|
||||
if(it->second.last_connection_TS + MAXIMUM_PEER_INACTIVE_DELAY < now)
|
||||
{
|
||||
RsDbg() << "Removing client peer " << it->first << " because it's inactive for more than " << MAXIMUM_PEER_INACTIVE_DELAY << " seconds." ;
|
||||
to_remove.push_back(it->first);
|
||||
}
|
||||
|
||||
for(auto peer_id:to_remove)
|
||||
removePeer(peer_id);
|
||||
|
||||
RsDbg() << "done." ;
|
||||
}
|
||||
|
||||
void FriendServer::updateClosestPeers(const RsPeerId& pid,const RsPgpFingerprint& fpr)
|
||||
{
|
||||
for(auto& it:mCurrentClientPeers)
|
||||
if(it.first != pid)
|
||||
{
|
||||
PeerInfo::PeerDistance d = computePeerDistance(fpr,it.second.pgp_fingerprint);
|
||||
|
||||
it.second.closest_peers.insert(std::make_pair(d,pid));
|
||||
|
||||
if(it.second.closest_peers.size() > MAXIMUM_PEERS_TO_REQUEST)
|
||||
it.second.closest_peers.erase(std::prev(it.second.closest_peers.end()));
|
||||
}
|
||||
}
|
||||
|
||||
void FriendServer::debugPrint()
|
||||
{
|
||||
RsDbg() << "========== FriendServer statistics ============";
|
||||
RsDbg() << " Base directory: "<< mBaseDirectory;
|
||||
RsDbg() << " Random peer bias: "<< mRandomPeerBias;
|
||||
RsDbg() << " Network interface: ";
|
||||
RsDbg() << " Max peers in n-closest list: " << MAXIMUM_PEERS_TO_REQUEST;
|
||||
RsDbg() << " Current active peers: " << mCurrentClientPeers.size() ;
|
||||
|
||||
rstime_t now = time(nullptr);
|
||||
|
||||
for(const auto& it:mCurrentClientPeers)
|
||||
{
|
||||
RsDbg() << " " << it.first << ": nonce=" << std::hex << it.second.last_nonce << std::dec << " fpr: " << it.second.pgp_fingerprint << ", last contact: " << now - it.second.last_connection_TS << " secs ago.";
|
||||
RsDbg() << " Closest peers:" ;
|
||||
|
||||
for(const auto& pit:it.second.closest_peers)
|
||||
RsDbg() << " " << pit.second << " distance=" << pit.first ;
|
||||
|
||||
RsDbg() << " Have added this peer:" ;
|
||||
|
||||
for(const auto& pit:it.second.have_added_this_peer)
|
||||
RsDbg() << " " << pit.second << " distance=" << pit.first ;
|
||||
}
|
||||
|
||||
RsDbg() << "===============================================";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
91
retroshare-friendserver/src/friendserver.h
Normal file
91
retroshare-friendserver/src/friendserver.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* RetroShare Friend Server
|
||||
* Copyright (C) 2021-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 Affero 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-FileCopyrightText: Retroshare Team <contact@retroshare.cc>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/rsthreads.h"
|
||||
#include "pqi/pqistreamer.h"
|
||||
#include "pgp/pgphandler.h"
|
||||
|
||||
#include "network.h"
|
||||
|
||||
class RsFriendServerClientRemoveItem;
|
||||
class RsFriendServerClientPublishItem;
|
||||
|
||||
struct PeerInfo
|
||||
{
|
||||
typedef RsPgpFingerprint PeerDistance;
|
||||
|
||||
RsPgpFingerprint pgp_fingerprint;
|
||||
std::string short_certificate;
|
||||
rstime_t last_connection_TS;
|
||||
uint64_t last_nonce;
|
||||
|
||||
std::map<PeerDistance,RsPeerId> closest_peers;
|
||||
std::map<PeerDistance,RsPeerId> have_added_this_peer;
|
||||
};
|
||||
|
||||
class FriendServer : public RsTickingThread
|
||||
{
|
||||
public:
|
||||
FriendServer(const std::string& base_directory,const std::string& listening_address,uint16_t listening_port);
|
||||
|
||||
private:
|
||||
// overloads RsTickingThread
|
||||
|
||||
virtual void threadTick() override;
|
||||
virtual void run() override;
|
||||
|
||||
// Own algorithmics
|
||||
|
||||
void handleClientRemove(const RsFriendServerClientRemoveItem *item);
|
||||
void handleClientPublish(const RsFriendServerClientPublishItem *item);
|
||||
|
||||
// Updates for each peer in the database, the list of closest peers w.r.t. some arbitrary distance.
|
||||
void updateClosestPeers(const RsPeerId& pid,const RsPgpFingerprint& fpr);
|
||||
|
||||
// removes a single peer from all lists.
|
||||
void removePeer(const RsPeerId& peer_id);
|
||||
|
||||
// Adds the incoming peer data to the list of current clients and returns the
|
||||
std::map<RsPeerId,PeerInfo>::iterator handleIncomingClientData(const std::string& pgp_public_key_b64,const std::string& short_invite_b64);
|
||||
|
||||
// Computes the appropriate list of short invites to send to a given peer.
|
||||
std::map<std::string, bool> computeListOfFriendInvites(uint32_t nb_reqs_invites, const RsPeerId &pid, std::map<RsPeerId,RsPgpFingerprint>& friends);
|
||||
|
||||
// Compute the distance between peers using the random bias (It's not really a distance though. I'm not sure about the triangular inequality).
|
||||
PeerInfo::PeerDistance computePeerDistance(const RsPgpFingerprint &p1, const RsPgpFingerprint &p2);
|
||||
|
||||
void autoWash();
|
||||
void debugPrint();
|
||||
|
||||
// Local members
|
||||
|
||||
FsNetworkInterface *mni;
|
||||
PGPHandler *mPgpHandler;
|
||||
|
||||
std::string mBaseDirectory;
|
||||
RsPgpFingerprint mRandomPeerBias;
|
||||
|
||||
std::map<RsPeerId, PeerInfo> mCurrentClientPeers;
|
||||
std::string mListeningAddress;
|
||||
uint16_t mListeningPort;
|
||||
};
|
298
retroshare-friendserver/src/network.cc
Normal file
298
retroshare-friendserver/src/network.cc
Normal file
@ -0,0 +1,298 @@
|
||||
/*
|
||||
* RetroShare Friend Server
|
||||
* Copyright (C) 2021-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 Affero 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-FileCopyrightText: Retroshare Team <contact@retroshare.cc>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "util/rsnet.h"
|
||||
#include "util/rsprint.h"
|
||||
#include "util/rsdebug.h"
|
||||
|
||||
#include "pqi/pqithreadstreamer.h"
|
||||
#include "pqi/pqifdbin.h"
|
||||
|
||||
#include "network.h"
|
||||
#include "friend_server/fsitem.h"
|
||||
|
||||
FsNetworkInterface::FsNetworkInterface(const std::string& listening_address,uint16_t listening_port)
|
||||
: PQInterface(RsPeerId()),mFsNiMtx(std::string("FsNetworkInterface")),mListeningAddress(listening_address),mListeningPort(listening_port)
|
||||
{
|
||||
RS_STACK_MUTEX(mFsNiMtx);
|
||||
|
||||
mClintListn = 0;
|
||||
mClintListn = socket(AF_INET, SOCK_STREAM, 0); // creating socket
|
||||
|
||||
int flags = fcntl(mClintListn, F_GETFL);
|
||||
fcntl(mClintListn, F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
struct sockaddr_in ipOfServer;
|
||||
memset(&ipOfServer, '0', sizeof(ipOfServer));
|
||||
|
||||
assert(mListeningPort > 1024);
|
||||
|
||||
ipOfServer.sin_family = AF_INET;
|
||||
ipOfServer.sin_port = htons(mListeningPort); // this is the port number of running server
|
||||
|
||||
int addr[4];
|
||||
if(sscanf(listening_address.c_str(),"%d.%d.%d.%d",&addr[0],&addr[1],&addr[2],&addr[3]) != 4)
|
||||
throw std::runtime_error("Cannot parse a proper IPv4 address in \""+listening_address+"\"");
|
||||
|
||||
for(int i=0;i<4;++i)
|
||||
if(addr[i] < 0 || addr[i] > 255)
|
||||
throw std::runtime_error("Cannot parse a proper IPv4 address in \""+listening_address+"\"");
|
||||
|
||||
ipOfServer.sin_addr.s_addr = htonl( (addr[0] << 24) + (addr[1] << 16) + (addr[2] << 8) + addr[3] );
|
||||
|
||||
if(bind(mClintListn, (struct sockaddr*)&ipOfServer , sizeof(ipOfServer)) < 0)
|
||||
{
|
||||
RsErr() << "Error while binding: errno=" << errno ;
|
||||
return;
|
||||
}
|
||||
|
||||
if(listen(mClintListn , 40) < 0)
|
||||
{
|
||||
RsErr() << "Error while calling listen: errno=" << errno ;
|
||||
return;
|
||||
}
|
||||
|
||||
RsDbg() << "Network interface now listening for TCP on " << sockaddr_storage_tostring( *(sockaddr_storage*)&ipOfServer) ;
|
||||
}
|
||||
|
||||
FsNetworkInterface::~FsNetworkInterface()
|
||||
{
|
||||
RS_STACK_MUTEX(mFsNiMtx);
|
||||
for(auto& it:mConnections)
|
||||
{
|
||||
delete it.second.pqi_thread;
|
||||
std::cerr << "Releasing socket " << it.second.socket << std::endl;
|
||||
close(it.second.socket);
|
||||
}
|
||||
std::cerr << "Releasing listening socket " << mClintListn << std::endl;
|
||||
close(mClintListn);
|
||||
}
|
||||
void FsNetworkInterface::threadTick()
|
||||
{
|
||||
// 1 - check for new connections
|
||||
|
||||
checkForNewConnections();
|
||||
|
||||
// 2 - tick all streamers
|
||||
|
||||
std::list<RsPeerId> to_close;
|
||||
|
||||
RS_STACK_MUTEX(mFsNiMtx);
|
||||
for(auto& it:mConnections)
|
||||
if(it.second.bio->isactive())
|
||||
it.second.pqi_thread->tick();
|
||||
else
|
||||
to_close.push_back(it.first);
|
||||
|
||||
for(const auto& pid:to_close)
|
||||
locked_closeConnection(pid);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
}
|
||||
|
||||
static RsPeerId makePeerId(int t)
|
||||
{
|
||||
unsigned char s[RsPeerId::SIZE_IN_BYTES];
|
||||
memset(s,0,sizeof(s));
|
||||
|
||||
*reinterpret_cast<int*>(&s) = t;
|
||||
return RsPeerId::fromBufferUnsafe(s);
|
||||
}
|
||||
bool FsNetworkInterface::checkForNewConnections()
|
||||
{
|
||||
// look for incoming data
|
||||
|
||||
struct sockaddr addr;
|
||||
socklen_t addr_len = sizeof(sockaddr);
|
||||
|
||||
int clintConnt = accept(mClintListn, &addr, &addr_len); // accept is a blocking call!
|
||||
|
||||
if(clintConnt < 0)
|
||||
{
|
||||
if(errno == EWOULDBLOCK)
|
||||
;//RsErr()<< "Incoming connection with nothing to read!" << std::endl;
|
||||
else
|
||||
RsErr()<< "Error when accepting connection." << std::endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
RsDbg() << "Got incoming connection from " << sockaddr_storage_tostring( *(sockaddr_storage*)&addr);
|
||||
|
||||
// Make the socket non blocking so that we can read from it and return if nothing comes
|
||||
|
||||
int flags = fcntl(clintConnt, F_GETFL);
|
||||
fcntl(clintConnt, F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
// Create connection info
|
||||
|
||||
ConnectionData c;
|
||||
c.socket = clintConnt;
|
||||
c.client_address = addr;
|
||||
|
||||
RsPeerId pid = makePeerId(clintConnt);
|
||||
|
||||
// Setup a pqistreamer to deserialize whatever comes from this connection
|
||||
|
||||
RsSerialiser *rss = new RsSerialiser ;
|
||||
rss->addSerialType(new FsSerializer) ;
|
||||
|
||||
RsFdBinInterface *bio = new RsFdBinInterface(clintConnt,true);
|
||||
|
||||
auto pqi = new pqithreadstreamer(this,rss, pid, bio,BIN_FLAGS_READABLE | BIN_FLAGS_WRITEABLE);
|
||||
|
||||
c.pqi_thread = pqi;
|
||||
c.bio = bio;
|
||||
|
||||
pqi->start();
|
||||
|
||||
RS_STACK_MUTEX(mFsNiMtx);
|
||||
mConnections[pid] = c;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FsNetworkInterface::RecvItem(RsItem *item)
|
||||
{
|
||||
RS_STACK_MUTEX(mFsNiMtx);
|
||||
|
||||
auto it = mConnections.find(item->PeerId());
|
||||
|
||||
if(it == mConnections.end())
|
||||
{
|
||||
RsErr() << "Receiving an item for peer ID " << item->PeerId() << " but no connection is known for that peer." << std::endl;
|
||||
delete item;
|
||||
return false;
|
||||
}
|
||||
|
||||
it->second.incoming_items.push_back(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
RsItem *FsNetworkInterface::GetItem()
|
||||
{
|
||||
RS_STACK_MUTEX(mFsNiMtx);
|
||||
|
||||
for(auto& it:mConnections)
|
||||
{
|
||||
if(!it.second.incoming_items.empty())
|
||||
{
|
||||
RsItem *item = it.second.incoming_items.front();
|
||||
it.second.incoming_items.pop_front();
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int FsNetworkInterface::SendItem(RsItem *item)
|
||||
{
|
||||
RS_STACK_MUTEX(mFsNiMtx);
|
||||
|
||||
const auto& it = mConnections.find(item->PeerId());
|
||||
|
||||
if(it == mConnections.end())
|
||||
{
|
||||
RsErr() << "Cannot send item to peer " << item->PeerId() << ": no pending sockets available." ;
|
||||
delete item;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t ss;
|
||||
return it->second.pqi_thread->SendItem(item,ss);
|
||||
}
|
||||
|
||||
void FsNetworkInterface::closeConnection(const RsPeerId& peer_id)
|
||||
{
|
||||
RS_STACK_MUTEX(mFsNiMtx);
|
||||
|
||||
locked_closeConnection(peer_id);
|
||||
}
|
||||
void FsNetworkInterface::locked_closeConnection(const RsPeerId& peer_id)
|
||||
{
|
||||
RsDbg() << "Closing connection to virtual peer " << peer_id ;
|
||||
|
||||
const auto& it = mConnections.find(peer_id);
|
||||
|
||||
if(it == mConnections.end())
|
||||
{
|
||||
RsErr() << " Cannot close connection to peer " << peer_id << ": no pending sockets available." ;
|
||||
return;
|
||||
}
|
||||
|
||||
if(!it->second.incoming_items.empty())
|
||||
{
|
||||
RsErr() << " Trying to close an incoming connection with incoming items still pending! The items will be lost:" << std::endl;
|
||||
|
||||
for(auto& item:it->second.incoming_items)
|
||||
{
|
||||
RsErr() << *item;
|
||||
delete item;
|
||||
}
|
||||
|
||||
it->second.incoming_items.clear();
|
||||
}
|
||||
// Close the socket and delete everything.
|
||||
|
||||
close(it->second.socket);
|
||||
it->second.pqi_thread->fullstop();
|
||||
it->second.bio->close();
|
||||
|
||||
delete it->second.pqi_thread;
|
||||
|
||||
mConnections.erase(it);
|
||||
}
|
||||
|
||||
void FsNetworkInterface::debugPrint()
|
||||
{
|
||||
RsDbg() << " " << mClintListn ; // listening socket
|
||||
RsDbg() << " Connections: " << mConnections.size() ;
|
||||
|
||||
for(auto& it:mConnections)
|
||||
RsDbg() << " " << it.first << ": from \"" << sockaddr_storage_tostring(*(sockaddr_storage*)(&it.second.client_address)) << "\", socket=" << it.second.socket ;
|
||||
|
||||
std::map<RsPeerId,ConnectionData> mConnections;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
86
retroshare-friendserver/src/network.h
Normal file
86
retroshare-friendserver/src/network.h
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* RetroShare Friend Server
|
||||
* Copyright (C) 2021-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 Affero 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-FileCopyrightText: Retroshare Team <contact@retroshare.cc>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/rsthreads.h"
|
||||
#include "pqi/pqi_base.h"
|
||||
#include "retroshare/rspeers.h"
|
||||
|
||||
class pqithreadstreamer;
|
||||
class RsFdBinInterface;
|
||||
|
||||
struct ConnectionData
|
||||
{
|
||||
sockaddr client_address;
|
||||
int socket;
|
||||
pqithreadstreamer *pqi_thread;
|
||||
RsFdBinInterface *bio;
|
||||
|
||||
std::list<RsItem*> incoming_items;
|
||||
};
|
||||
|
||||
// This class handles multiple connections to the server and supplies RsItem elements
|
||||
|
||||
class FsNetworkInterface: public RsTickingThread, public PQInterface
|
||||
{
|
||||
public:
|
||||
FsNetworkInterface(const std::string& listening_address,uint16_t listening_port) ;
|
||||
virtual ~FsNetworkInterface() ;
|
||||
|
||||
// basic functionality
|
||||
|
||||
void debugPrint();
|
||||
|
||||
// Implements PQInterface
|
||||
|
||||
bool RecvItem(RsItem *item) override;
|
||||
int SendItem(RsItem *item) override;
|
||||
RsItem *GetItem() override;
|
||||
|
||||
void closeConnection(const RsPeerId& peer_id);
|
||||
|
||||
// Implements RsTickingThread
|
||||
|
||||
void threadTick() override;
|
||||
|
||||
protected:
|
||||
bool checkForNewConnections();
|
||||
void locked_closeConnection(const RsPeerId& peer_id);
|
||||
|
||||
private:
|
||||
RsMutex mFsNiMtx;
|
||||
|
||||
void initListening();
|
||||
void stopListening();
|
||||
|
||||
int mClintListn ; // listening socket
|
||||
std::map<RsPeerId,ConnectionData> mConnections;
|
||||
|
||||
std::string mListeningAddress;
|
||||
uint16_t mListeningPort;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
106
retroshare-friendserver/src/retroshare-friendserver.cc
Normal file
106
retroshare-friendserver/src/retroshare-friendserver.cc
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* RetroShare Service
|
||||
* Copyright (C) 2021-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 Affero 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-FileCopyrightText: Retroshare Team <contact@retroshare.cc>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "util/stacktrace.h"
|
||||
#include "util/rsdir.h"
|
||||
#include "util/argstream.h"
|
||||
#include "util/rstime.h"
|
||||
#include "util/rsdebug.h"
|
||||
|
||||
#include "retroshare/rstor.h"
|
||||
#include "retroshare/rsinit.h"
|
||||
|
||||
#include "friendserver.h"
|
||||
|
||||
// debug
|
||||
#include "friend_server/fsitem.h"
|
||||
#include "friend_server/fsclient.h"
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
RsInfo() << "\n" <<
|
||||
"+================================================================+\n"
|
||||
"| o---o o |\n"
|
||||
"| \\ / - Retroshare Friend Server - / \\ |\n"
|
||||
"| o o---o |\n"
|
||||
"+================================================================+"
|
||||
<< std::endl << std::endl;
|
||||
|
||||
//RsControl::earlyInitNotificationSystem();
|
||||
|
||||
std::string base_directory = "FSData";
|
||||
|
||||
argstream as(argc,argv);
|
||||
|
||||
as >> parameter( 'c',"base-dir", base_directory, "set base directory to store data files (keys, etc)", false )
|
||||
>> help( 'h', "help", "Display this Help" );
|
||||
|
||||
as.defaultErrorHandling(true, true);
|
||||
|
||||
RsConfigOptions conf;
|
||||
conf.main_executable_path = argv[0];
|
||||
|
||||
RsInit::InitRsConfig();
|
||||
RsInit::InitRetroShare(conf);
|
||||
|
||||
// Create the base directory if needed
|
||||
|
||||
if(!RsDirUtil::checkCreateDirectory(base_directory))
|
||||
{
|
||||
RsErr() << "Cannot create base directory \"" << base_directory << "\". Check permissions, paths, etc." ;
|
||||
return 1;
|
||||
}
|
||||
// Create/start TorManager
|
||||
|
||||
RsTor::setTorDataDirectory(RsDirUtil::makePath(base_directory,"tor"));
|
||||
RsTor::setHiddenServiceDirectory(RsDirUtil::makePath(base_directory,"hidden_service"));
|
||||
|
||||
if(! RsTor::start() || RsTor::hasError())
|
||||
{
|
||||
RsErr() << "Tor cannot be started on your system: " << RsTor::errorMessage() ;
|
||||
return 1 ;
|
||||
}
|
||||
|
||||
std::string service_id;
|
||||
|
||||
while(RsTor::torStatus() != RsTorStatus::READY || RsTor::getHiddenServiceStatus(service_id) != RsTorHiddenServiceStatus::ONLINE)
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
std::string onion_address,service_target_address;
|
||||
uint16_t service_port,target_port;
|
||||
|
||||
RsTor::getHiddenServiceInfo(service_id,onion_address,service_port,service_target_address,target_port) ;
|
||||
|
||||
RsDbg() << "Tor properly started: " ;
|
||||
RsDbg() << " Hidden service address: " << onion_address << ":" << service_port;
|
||||
RsDbg() << " Target address : " << service_target_address << ":" << target_port;
|
||||
|
||||
// Now start the real thing.
|
||||
|
||||
FriendServer fs(base_directory,service_target_address,target_port);
|
||||
fs.start();
|
||||
|
||||
while(fs.isRunning())
|
||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
43
retroshare-friendserver/src/retroshare-friendserver.pro
Normal file
43
retroshare-friendserver/src/retroshare-friendserver.pro
Normal file
@ -0,0 +1,43 @@
|
||||
# RetroShare service qmake build script
|
||||
#
|
||||
# Copyright (C) 2021-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 Affero 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# SPDX-FileCopyrightText: Retroshare Team <contact@retroshare.cc>
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
!include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri")
|
||||
|
||||
TARGET = retroshare-friendserver
|
||||
|
||||
!include("../../libretroshare/src/use_libretroshare.pri"):error("Including")
|
||||
|
||||
SOURCES += retroshare-friendserver.cc \
|
||||
friendserver.cc \
|
||||
network.cc
|
||||
|
||||
HEADERS += friendserver.h \
|
||||
network.h \
|
||||
fsitem.h
|
||||
|
||||
################################# Linux ##########################################
|
||||
|
||||
unix {
|
||||
target.path = "$${RS_BIN_DIR}"
|
||||
INSTALLS += target
|
||||
}
|
||||
|
||||
################################### COMMON stuff ##################################
|
||||
|
171
retroshare-gui/src/gui/FriendServerControl.cpp
Normal file
171
retroshare-gui/src/gui/FriendServerControl.cpp
Normal file
@ -0,0 +1,171 @@
|
||||
/*******************************************************************************
|
||||
* gui/FriendServer.cpp *
|
||||
* *
|
||||
* 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 Affero 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 Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
#include <QTimer>
|
||||
#include <QMovie>
|
||||
#include <QTcpSocket>
|
||||
|
||||
#include "retroshare/rsfriendserver.h"
|
||||
#include "retroshare/rstor.h"
|
||||
|
||||
#include "util/qtthreadsutils.h"
|
||||
#include "gui/common/FilesDefs.h"
|
||||
|
||||
#include "FriendServerControl.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#define ICON_STATUS_UNKNOWN ":/images/ledoff1.png"
|
||||
#define ICON_STATUS_OK ":/images/ledon1.png"
|
||||
|
||||
/** Constructor */
|
||||
FriendServerControl::FriendServerControl(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
/* Invoke the Qt Designer generated object setup routine */
|
||||
setupUi(this);
|
||||
|
||||
if(!rsFriendServer)
|
||||
{
|
||||
setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
mConnectionCheckTimer = new QTimer;
|
||||
|
||||
// init values
|
||||
|
||||
torServerFriendsToRequest_SB->setValue(rsFriendServer->friendsToRequest());
|
||||
torServerAddress_LE->setText(QString::fromStdString(rsFriendServer->friendsServerAddress().c_str()));
|
||||
torServerPort_SB->setValue(rsFriendServer->friendsServerPort());
|
||||
|
||||
// connect slignals/slots
|
||||
|
||||
QObject::connect(friendServerOnOff_CB,SIGNAL(toggled(bool)),this,SLOT(onOnOffClick(bool)));
|
||||
QObject::connect(torServerFriendsToRequest_SB,SIGNAL(valueChanged(int)),this,SLOT(onFriendsToRequestChanged(int)));
|
||||
QObject::connect(torServerAddress_LE,SIGNAL(textChanged(const QString&)),this,SLOT(onOnionAddressEdit(const QString&)));
|
||||
|
||||
QObject::connect(mConnectionCheckTimer,SIGNAL(timeout()),this,SLOT(checkServerAddress()));
|
||||
|
||||
mCheckingServerMovie = new QMovie(":/images/loader/circleball-16.gif");
|
||||
serverStatusCheckResult_LB->setMovie(mCheckingServerMovie);
|
||||
|
||||
updateFriendServerStatusIcon(false);
|
||||
updateTorProxyInfo();
|
||||
}
|
||||
|
||||
void FriendServerControl::updateTorProxyInfo()
|
||||
{
|
||||
std::string friend_proxy_address;
|
||||
uint16_t friend_proxy_port;
|
||||
|
||||
RsTor::getProxyServerInfo(friend_proxy_address,friend_proxy_port);
|
||||
|
||||
torProxyPort_SB->setValue(friend_proxy_port);
|
||||
torProxyAddress_LE->setText(QString::fromStdString(friend_proxy_address));
|
||||
}
|
||||
|
||||
FriendServerControl::~FriendServerControl()
|
||||
{
|
||||
delete mCheckingServerMovie;
|
||||
delete mConnectionCheckTimer;
|
||||
}
|
||||
|
||||
void FriendServerControl::onOnOffClick(bool b)
|
||||
{
|
||||
if(b)
|
||||
rsFriendServer->startServer();
|
||||
else
|
||||
rsFriendServer->stopServer();
|
||||
}
|
||||
void FriendServerControl::onOnionPortEdit(int)
|
||||
{
|
||||
#warning TODO
|
||||
// // Setup timer to auto-check the friend server address
|
||||
//
|
||||
// mConnectionCheckTimer->setSingleShot(true);
|
||||
// mConnectionCheckTimer->setInterval(5000); // check in 5 secs unless something is changed in the mean time.
|
||||
//
|
||||
// mConnectionCheckTimer->start();
|
||||
//
|
||||
// if(mCheckingServerMovie->fileName() != QString(":/images/loader/circleball-16.gif" ))
|
||||
// {
|
||||
// mCheckingServerMovie->setFileName(":/images/loader/circleball-16.gif");
|
||||
// mCheckingServerMovie->start();
|
||||
// }
|
||||
rsFriendServer->setServerAddress(torServerAddress_LE->text().toStdString(),torServerPort_SB->value());
|
||||
rsFriendServer->setProxyAddress(torProxyAddress_LE->text().toStdString(),torProxyPort_SB->value());
|
||||
}
|
||||
|
||||
void FriendServerControl::onOnionAddressEdit(const QString&)
|
||||
{
|
||||
// Setup timer to auto-check the friend server address
|
||||
|
||||
// mConnectionCheckTimer->setSingleShot(true);
|
||||
// mConnectionCheckTimer->setInterval(5000); // check in 5 secs unless something is changed in the mean time.
|
||||
//
|
||||
// mConnectionCheckTimer->start();
|
||||
//
|
||||
// if(mCheckingServerMovie->fileName() != QString(":/images/loader/circleball-16.gif" ))
|
||||
// {
|
||||
// mCheckingServerMovie->setFileName(":/images/loader/circleball-16.gif");
|
||||
// mCheckingServerMovie->start();
|
||||
// }
|
||||
rsFriendServer->setServerAddress(torServerAddress_LE->text().toStdString(),torServerPort_SB->value());
|
||||
rsFriendServer->setProxyAddress(torProxyAddress_LE->text().toStdString(),torProxyPort_SB->value());
|
||||
}
|
||||
|
||||
void FriendServerControl::checkServerAddress()
|
||||
{
|
||||
rsFriendServer->checkServerAddress_async(torServerAddress_LE->text().toStdString(),torServerPort_SB->value(),
|
||||
[this](const std::string& address,bool test_result)
|
||||
{
|
||||
if(test_result)
|
||||
rsFriendServer->setServerAddress(address,1729);
|
||||
|
||||
RsQThreadUtils::postToObject( [=]() { updateFriendServerStatusIcon(test_result); },this);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void FriendServerControl::onNbFriendsToRequestsChanged(int n)
|
||||
{
|
||||
rsFriendServer->setFriendsToRequest(n);
|
||||
}
|
||||
|
||||
void FriendServerControl::updateFriendServerStatusIcon(bool ok)
|
||||
{
|
||||
mCheckingServerMovie->stop();
|
||||
|
||||
if(ok)
|
||||
{
|
||||
torServerStatus_LB->setToolTip(tr("Friend server is currently reachable.")) ;
|
||||
mCheckingServerMovie->setFileName(ICON_STATUS_OK);
|
||||
}
|
||||
else
|
||||
{
|
||||
torServerStatus_LB->setToolTip(tr("The proxy is not enabled or broken.\nAre all services up and running fine??\nAlso check your ports!")) ;
|
||||
mCheckingServerMovie->setFileName(ICON_STATUS_UNKNOWN);
|
||||
}
|
||||
mCheckingServerMovie->start();
|
||||
}
|
||||
|
||||
|
||||
|
48
retroshare-gui/src/gui/FriendServerControl.h
Normal file
48
retroshare-gui/src/gui/FriendServerControl.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*******************************************************************************
|
||||
* gui/NetworkView.h *
|
||||
* *
|
||||
* Copyright (c) 2008 Robert Fernie <retroshare.project@gmail.com> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero 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 Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QGraphicsScene>
|
||||
|
||||
#include "ui_FriendServerControl.h"
|
||||
|
||||
class FriendServerControl : public QWidget, public Ui::FriendServerControl
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FriendServerControl(QWidget *parent = 0);
|
||||
virtual ~FriendServerControl();
|
||||
|
||||
protected slots:
|
||||
void onOnOffClick(bool b);
|
||||
void onOnionAddressEdit(const QString&);
|
||||
void onOnionPortEdit(int);
|
||||
void onNbFriendsToRequestsChanged(int n);
|
||||
void updateTorProxyInfo();
|
||||
|
||||
private:
|
||||
void checkServerAddress();
|
||||
void updateFriendServerStatusIcon(bool ok);
|
||||
|
||||
QTimer *mConnectionCheckTimer;
|
||||
QMovie *mCheckingServerMovie;
|
||||
};
|
183
retroshare-gui/src/gui/FriendServerControl.ui
Normal file
183
retroshare-gui/src/gui/FriendServerControl.ui
Normal file
@ -0,0 +1,183 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FriendServerControl</class>
|
||||
<widget class="QWidget" name="FriendServerControl">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>620</width>
|
||||
<height>499</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="friendServerOnOff_CB">
|
||||
<property name="text">
|
||||
<string>On/Off</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Friends to request: </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="torServerFriendsToRequest_SB">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>15</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Server onion address:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="torServerAddress_LE">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>.onion</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="torServerPort_SB">
|
||||
<property name="minimum">
|
||||
<number>1025</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65536</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>2017</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="serverStatusCheckResult_LB">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="torServerStatus_LB">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Tor proxy address:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="torProxyAddress_LE">
|
||||
<property name="text">
|
||||
<string>127.0.0.1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="torProxyPort_SB">
|
||||
<property name="minimum">
|
||||
<number>1025</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65535</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>9050</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>380</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -44,6 +44,9 @@
|
||||
#include "NetworkView.h"
|
||||
#include "NetworkDialog.h"
|
||||
#include "gui/common/NewFriendList.h"
|
||||
#ifdef RS_EMBEDED_FRIEND_SERVER
|
||||
#include "gui/FriendServerControl.h"
|
||||
#endif
|
||||
#include "gui/Identity/IdDialog.h"
|
||||
/* Images for Newsfeed icons */
|
||||
//#define IMAGE_NEWSFEED ""
|
||||
@ -88,6 +91,9 @@ FriendsDialog::FriendsDialog(QWidget *parent) : MainPage(parent)
|
||||
ui.avatar->setFrameType(AvatarWidget::STATUS_FRAME);
|
||||
|
||||
ui.tabWidget->setTabPosition(QTabWidget::North);
|
||||
#ifdef RS_EMBEDED_FRIEND_SERVER
|
||||
ui.tabWidget->addTab(friendServerControl = new FriendServerControl(),QIcon(IMAGE_PEERS), tr("Friend Server"));
|
||||
#endif
|
||||
ui.tabWidget->addTab(networkView = new NetworkView(),QIcon(IMAGE_NETWORK2), tr("Network graph"));
|
||||
ui.tabWidget->addTab(networkDialog = new NetworkDialog(),QIcon(IMAGE_PEERS), tr("Keyring"));
|
||||
|
||||
|
@ -30,6 +30,7 @@ class NetworkDialog;
|
||||
class NetworkView;
|
||||
class IdDialog;
|
||||
class CirclesDialog;
|
||||
class FriendServerControl;
|
||||
|
||||
class FriendsDialog : public MainPage
|
||||
{
|
||||
@ -64,7 +65,8 @@ public:
|
||||
|
||||
NetworkDialog *networkDialog ;
|
||||
NetworkView *networkView ;
|
||||
|
||||
FriendServerControl *friendServerControl ;
|
||||
|
||||
IdDialog *idDialog;
|
||||
|
||||
private slots:
|
||||
|
@ -1085,6 +1085,13 @@ DEFINES *= CHANNELS_FRAME_CATCHER
|
||||
|
||||
}
|
||||
|
||||
# Embedded Friend Server
|
||||
|
||||
rs_efs {
|
||||
SOURCES += gui/FriendServerControl.cpp
|
||||
HEADERS += gui/FriendServerControl.h
|
||||
FORMS += gui/FriendServerControl.ui
|
||||
}
|
||||
|
||||
# BELOW IS GXS Unfinished Services.
|
||||
|
||||
|
@ -51,6 +51,11 @@ retroshare_plugins:CONFIG -= no_retroshare_plugins
|
||||
CONFIG *= retroshare_service
|
||||
no_retroshare_service:CONFIG -= retroshare_service
|
||||
|
||||
# To disable RetroShare FriendServer append the following assignation to
|
||||
# qmake command line "CONFIG+=no_rs_friendserver"
|
||||
CONFIG *= retroshare_friendserver
|
||||
no_rs_friendserver:CONFIG -= retroshare_friendserver
|
||||
|
||||
# To disable SQLCipher support append the following assignation to qmake
|
||||
# command line "CONFIG+=no_sqlcipher"
|
||||
CONFIG *= sqlcipher
|
||||
|
Loading…
Reference in New Issue
Block a user